1 /*
2 * libdi - CD Audio Device Interface Library
3 *
4 * Copyright (C) 1993-2004 Ti Kan
5 * E-mail: xmcd@amb.org
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 /*
23 * Pioneer vendor-unique support
24 *
25 * The name "Pioneer" is a trademark of Pioneer Corporation, and is
26 * used here for identification purposes only.
27 */
28 #ifndef lint
29 static char *_vu_pion_c_ident_ = "@(#)vu_pion.c 6.36 04/01/14";
30 #endif
31
32 #include "common_d/appenv.h"
33 #include "common_d/util.h"
34 #include "libdi_d/libdi.h"
35 #include "libdi_d/scsipt.h"
36
37 #ifdef VENDOR_PIONEER
38
39 extern appdata_t app_data;
40 extern di_client_t *di_clinfo;
41 extern vu_tbl_t scsipt_vutbl[];
42 extern byte_t cdb[];
43 extern di_dev_t *devp;
44
45 /*
46 * pion_playaudio
47 * Play audio function: send vendor-unique play audio command
48 * to the drive.
49 *
50 * Args:
51 * addr_fmt - Flags indicating which address formats are passed in
52 * If ADDR_BLK, then:
53 * start_addr - The logical block starting address
54 * end_addr - The logical block ending address
55 * If ADD_MSF, then:
56 * start_msf - Pointer to the starting MSF address structure
57 * end_msf - Pointer to the ending MSF address structure
58 * If ADDR_TRKIDX, then:
59 * trk - The starting track number
60 * idx - The starting index number
61 * If ADDR_OPTEND, then the ending address, if specified, can be
62 * ignored if possible.
63 *
64 * Return:
65 * TRUE - success
66 * FALSE - failure
67 */
68 /*ARGSUSED*/
69 bool_t
pion_playaudio(byte_t addr_fmt,sword32_t start_addr,sword32_t end_addr,msf_t * start_msf,msf_t * end_msf,byte_t trk,byte_t idx)70 pion_playaudio(
71 byte_t addr_fmt,
72 sword32_t start_addr,
73 sword32_t end_addr,
74 msf_t *start_msf,
75 msf_t *end_msf,
76 byte_t trk,
77 byte_t idx
78 )
79 {
80 bool_t ret = FALSE;
81
82 if (!ret && addr_fmt & ADDR_MSF) {
83 /* Position laser head at desired location
84 * and start play.
85 */
86 SCSICDB_RESET(cdb);
87 cdb[0] = OP_VP_AUDSRCH;
88 cdb[1] = 0x19;
89 cdb[3] = (byte_t) util_ltobcd(start_msf->min);
90 cdb[4] = (byte_t) util_ltobcd(start_msf->sec);
91 cdb[5] = (byte_t) util_ltobcd(start_msf->frame);
92 cdb[9] = 0x40;
93
94 ret = pthru_send(devp, DI_ROLE_MAIN, cdb, 10, NULL, 0, NULL, 0,
95 OP_NODATA, 10, TRUE);
96
97 #if 0 /* Apparently the DRM-600A doesn't need the "Audio Play" command */
98 if (ret && !(addr_fmt & ADDR_OPTEND)) {
99 /* Specify end location and start play */
100 SCSICDB_RESET(cdb);
101 cdb[0] = OP_VP_AUDPLAY;
102 cdb[1] = 0x19;
103 cdb[3] = (byte_t) util_ltobcd(end_msf->min);
104 cdb[4] = (byte_t) util_ltobcd(end_msf->sec);
105 cdb[5] = (byte_t) util_ltobcd(end_msf->frame);
106 cdb[9] = 0x40;
107
108 ret = pthru_send(devp, DI_ROLE_MAIN, cdb, 10,
109 NULL, 0, NULL, 0,
110 OP_NODATA, 10, TRUE);
111 }
112 #endif
113 }
114
115 if (!ret && addr_fmt & ADDR_BLK) {
116 /* Position laser head at desired location
117 * and start play.
118 */
119 SCSICDB_RESET(cdb);
120 cdb[0] = OP_VP_AUDSRCH;
121 cdb[1] = 0x19;
122 cdb[2] = ((word32_t) start_addr & 0xff000000) >> 24;
123 cdb[3] = ((word32_t) start_addr & 0x00ff0000) >> 16;
124 cdb[4] = ((word32_t) start_addr & 0x0000ff00) >> 8;
125 cdb[5] = ((word32_t) start_addr & 0x000000ff);
126 cdb[9] = 0x00;
127
128 ret = pthru_send(devp, DI_ROLE_MAIN, cdb, 10, NULL, 0, NULL, 0,
129 OP_NODATA, 10, TRUE);
130
131 #if 0 /* Apparently the DRM-600A doesn't need the "Audio Play" command */
132 if (ret && !(addr_fmt & ADDR_OPTEND)) {
133 /* Specify end location and start play */
134 SCSICDB_RESET(cdb);
135 cdb[0] = OP_VP_AUDPLAY;
136 cdb[1] = 0x19;
137 cdb[2] = ((word32_t) end_addr & 0xff000000) >> 24;
138 cdb[3] = ((word32_t) end_addr & 0x00ff0000) >> 16;
139 cdb[4] = ((word32_t) end_addr & 0x0000ff00) >> 8;
140 cdb[5] = ((word32_t) end_addr & 0x000000ff);
141 cdb[9] = 0x00;
142
143 ret = pthru_send(devp, DI_ROLE_MAIN, cdb, 10,
144 NULL, 0, NULL, 0,
145 OP_NODATA, 10, TRUE);
146 }
147 #endif
148 }
149
150 return (ret);
151 }
152
153
154 /*
155 * pion_pause_resume
156 * Pause/resume function: send vendor-unique commands to implement
157 * the pause and resume capability.
158 *
159 * Args:
160 * resume - TRUE: resume, FALSE: pause
161 *
162 * Return:
163 * TRUE - success
164 * FALSE - failure
165 */
166 bool_t
pion_pause_resume(bool_t resume)167 pion_pause_resume(bool_t resume)
168 {
169 SCSICDB_RESET(cdb);
170 cdb[0] = OP_VP_PAUSE;
171 cdb[1] = resume ? 0x00 : 0x10;
172
173 return (
174 pthru_send(devp, DI_ROLE_MAIN, cdb, 10,
175 NULL, 0, NULL, 0, OP_NODATA, 5, TRUE)
176 );
177 }
178
179
180 /*
181 * pion_get_playstatus
182 * Send vendor-unique command to obtain current audio playback
183 * status.
184 *
185 * Args:
186 * sp - Pointer to the caller-supplied cdstat_t return structure
187 *
188 * Return:
189 * TRUE - success
190 * FALSE - failure
191 */
192 bool_t
pion_get_playstatus(cdstat_t * sp)193 pion_get_playstatus(cdstat_t *sp)
194 {
195 byte_t buf[sizeof(psubq_data_t)];
196 bool_t stopped;
197 paudstat_data_t *a;
198 psubq_data_t *d;
199
200
201 (void) memset(buf, 0, sizeof(buf));
202
203 /* Send Pioneer Read Audio Status command */
204 SCSICDB_RESET(cdb);
205 cdb[0] = OP_VP_AUDSTAT;
206 cdb[8] = SZ_VP_AUDSTAT;
207
208 if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10, buf, SZ_VP_AUDSTAT,
209 NULL, 0, OP_DATAIN, 5, TRUE))
210 return FALSE;
211
212 DBGDUMP(DBG_DEVIO)("pion: Read Audio Status data bytes",
213 buf, SZ_VP_AUDSTAT);
214
215 a = (paudstat_data_t *)(void *) buf;
216
217 stopped = FALSE;
218
219 /* Translate Pioneer audio status to cdstat_t status */
220 switch (a->status) {
221 case PAUD_PLAYING:
222 case PAUD_MUTEPLAY:
223 sp->status = CDSTAT_PLAYING;
224 break;
225
226 case PAUD_PAUSED:
227 sp->status = CDSTAT_PAUSED;
228 break;
229
230 case PAUD_COMPLETED:
231 sp->status = CDSTAT_COMPLETED;
232 stopped = TRUE;
233 break;
234
235 case PAUD_ERROR:
236 sp->status = CDSTAT_FAILED;
237 stopped = TRUE;
238 break;
239
240 case PAUD_NOSTATUS:
241 sp->status = CDSTAT_NOSTATUS;
242 stopped = TRUE;
243 break;
244 }
245
246 if (stopped) {
247 sp->abs_addr.min = (byte_t) util_bcdtol(a->abs_min);
248 sp->abs_addr.sec = (byte_t) util_bcdtol(a->abs_sec);
249 sp->abs_addr.frame = (byte_t) util_bcdtol(a->abs_frame);
250 util_msftoblk(
251 sp->abs_addr.min, sp->abs_addr.sec, sp->abs_addr.frame,
252 &sp->abs_addr.addr, MSF_OFFSET
253 );
254
255 return TRUE;
256 }
257
258 (void) memset(buf, 0, sizeof(buf));
259
260 /* Send Pioneer Read Subcode Q command */
261 SCSICDB_RESET(cdb);
262 cdb[0] = OP_VP_RDSUBQ;
263 cdb[8] = SZ_VP_RDSUBQ;
264
265 if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10, buf, SZ_VP_RDSUBQ,
266 NULL, 0, OP_DATAIN, 5, TRUE))
267 return FALSE;
268
269 DBGDUMP(DBG_DEVIO)("pion: Read Subcode Q data bytes",
270 buf, SZ_VP_RDSUBQ);
271
272 d = (psubq_data_t *)(void *) buf;
273
274 sp->track = (int) util_bcdtol((word32_t) d->trkno);
275 sp->index = (int) util_bcdtol((word32_t) d->idxno);
276
277 sp->abs_addr.min = (byte_t) util_bcdtol(d->abs_min);
278 sp->abs_addr.sec = (byte_t) util_bcdtol(d->abs_sec);
279 sp->abs_addr.frame = (byte_t) util_bcdtol(d->abs_frame);
280 sp->rel_addr.min = (byte_t) util_bcdtol(d->rel_min);
281 sp->rel_addr.sec = (byte_t) util_bcdtol(d->rel_sec);
282 sp->rel_addr.frame = (byte_t) util_bcdtol(d->rel_frame);
283 util_msftoblk(
284 sp->abs_addr.min, sp->abs_addr.sec, sp->abs_addr.frame,
285 &sp->abs_addr.addr, MSF_OFFSET
286 );
287 util_msftoblk(
288 sp->rel_addr.min, sp->rel_addr.sec, sp->rel_addr.frame,
289 &sp->rel_addr.addr, 0
290 );
291
292 return TRUE;
293 }
294
295
296 /*
297 * pion_get_toc
298 * Send vendor-unique command to obtain the disc table-of-contents
299 *
300 * Args:
301 * s - Pointer to the curstat_t structure, which contains the TOC
302 * table to be updated.
303 *
304 * Return:
305 * TRUE - success
306 * FALSE - failure
307 */
308 bool_t
pion_get_toc(curstat_t * s)309 pion_get_toc(curstat_t *s)
310 {
311 int i,
312 j;
313 byte_t buf[SZ_VP_RDTOC];
314 pinfo_00_t *t0;
315 pinfo_01_t *t1;
316 pinfo_02_t *t2;
317
318
319 (void) memset(buf, 0, sizeof(buf));
320
321 /* Find number of tracks */
322 SCSICDB_RESET(cdb);
323 cdb[0] = OP_VP_RDTOC;
324 cdb[5] = 0x00;
325 cdb[7] = (SZ_VP_RDTOC & 0xff00) >> 8;
326 cdb[8] = (SZ_VP_RDTOC & 0x00ff);
327 cdb[9] = 0x00;
328
329 if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10, buf, SZ_VP_RDTOC, NULL, 0,
330 OP_DATAIN, 5, TRUE))
331 return FALSE;
332
333 DBGDUMP(DBG_DEVIO)("pion: Read TOC data bytes", buf, SZ_VP_RDTOC);
334
335 t0 = (pinfo_00_t *) buf;
336 s->first_trk = (byte_t) util_bcdtol(t0->first_trk);
337 s->last_trk = (byte_t) util_bcdtol(t0->last_trk);
338
339 /* Get the starting position of each track */
340 for (i = 0, j = (int) s->first_trk; j <= (int) s->last_trk; i++, j++) {
341 (void) memset(buf, 0, sizeof(buf));
342
343 SCSICDB_RESET(cdb);
344 cdb[0] = OP_VP_RDTOC;
345 cdb[5] = (byte_t) util_ltobcd(j);
346 cdb[7] = (SZ_VP_RDTOC & 0xff00) >> 8;
347 cdb[8] = (SZ_VP_RDTOC & 0x00ff);
348 cdb[9] = 0x02 << 6;
349
350 if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10, buf, SZ_VP_RDTOC,
351 NULL, 0, OP_DATAIN, 5, TRUE))
352 return FALSE;
353
354 DBGDUMP(DBG_DEVIO)("pion: Read TOC data bytes",
355 buf, SZ_VP_RDTOC);
356
357 t2 = (pinfo_02_t *)(void *) buf;
358
359 s->trkinfo[i].trkno = j;
360 s->trkinfo[i].min = (byte_t) util_bcdtol(t2->min);
361 s->trkinfo[i].sec = (byte_t) util_bcdtol(t2->sec);
362 s->trkinfo[i].frame = (byte_t) util_bcdtol(t2->frame);
363 util_msftoblk(
364 s->trkinfo[i].min,
365 s->trkinfo[i].sec,
366 s->trkinfo[i].frame,
367 &s->trkinfo[i].addr,
368 MSF_OFFSET
369 );
370 }
371 s->tot_trks = (byte_t) i;
372
373 (void) memset(buf, 0, sizeof(buf));
374
375 /* Get the lead out track position */
376 SCSICDB_RESET(cdb);
377 cdb[0] = OP_VP_RDTOC;
378 cdb[5] = 0x00;
379 cdb[7] = (SZ_VP_RDTOC & 0xff00) >> 8;
380 cdb[8] = (SZ_VP_RDTOC & 0x00ff);
381 cdb[9] = 0x01 << 6;
382
383 if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10, buf, SZ_VP_RDTOC, NULL, 0,
384 OP_DATAIN, 5, TRUE))
385 return FALSE;
386
387 DBGDUMP(DBG_DEVIO)("pion: Read TOC data bytes", buf, SZ_VP_RDTOC);
388
389 t1 = (pinfo_01_t *) buf;
390
391 s->trkinfo[i].trkno = LEAD_OUT_TRACK;
392 s->discpos_tot.min = s->trkinfo[i].min = (byte_t) util_bcdtol(t1->min);
393 s->discpos_tot.sec = s->trkinfo[i].sec = (byte_t) util_bcdtol(t1->sec);
394 s->discpos_tot.frame = s->trkinfo[i].frame =
395 (byte_t) util_bcdtol(t1->frame);
396 util_msftoblk(
397 s->trkinfo[i].min,
398 s->trkinfo[i].sec,
399 s->trkinfo[i].frame,
400 &s->trkinfo[i].addr,
401 MSF_OFFSET
402 );
403 s->discpos_tot.addr = s->trkinfo[i].addr;
404
405 return TRUE;
406 }
407
408
409 /*
410 * pion_eject
411 * Send vendor-unique command to eject the caddy
412 *
413 * Args:
414 * Nothing.
415 *
416 * Return:
417 * TRUE - success
418 * FALSE - failure
419 */
420 bool_t
pion_eject(void)421 pion_eject(void)
422 {
423 SCSICDB_RESET(cdb);
424 cdb[0] = OP_VP_EJECT;
425 cdb[1] = 0x01; /* Set immediate bit */
426
427 return (
428 pthru_send(devp, DI_ROLE_MAIN, cdb, 10,
429 NULL, 0, NULL, 0, OP_NODATA, 20, TRUE)
430 );
431 }
432
433
434 /*
435 * pion_init
436 * Initialize the vendor-unique support module
437 *
438 * Args:
439 * Nothing.
440 *
441 * Return:
442 * Nothing.
443 */
444 void
pion_init(void)445 pion_init(void)
446 {
447 /* Register vendor_unique module entry points */
448 scsipt_vutbl[VENDOR_PIONEER].vendor = "Pioneer";
449 scsipt_vutbl[VENDOR_PIONEER].playaudio = pion_playaudio;
450 scsipt_vutbl[VENDOR_PIONEER].pause_resume = pion_pause_resume;
451 scsipt_vutbl[VENDOR_PIONEER].start_stop = NULL;
452 scsipt_vutbl[VENDOR_PIONEER].get_playstatus = pion_get_playstatus;
453 scsipt_vutbl[VENDOR_PIONEER].volume = NULL;
454 scsipt_vutbl[VENDOR_PIONEER].route = NULL;
455 scsipt_vutbl[VENDOR_PIONEER].mute = NULL;
456 scsipt_vutbl[VENDOR_PIONEER].get_toc = pion_get_toc;
457 scsipt_vutbl[VENDOR_PIONEER].eject = pion_eject;
458 scsipt_vutbl[VENDOR_PIONEER].start = NULL;
459 scsipt_vutbl[VENDOR_PIONEER].halt = NULL;
460 }
461
462
463 #endif /* VENDOR_PIONEER */
464
465