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 * Sony vendor-unique support
24 *
25 * The name "Sony" is a trademark of Sony Corporation, and is used
26 * here for identification purposes only.
27 */
28 #ifndef lint
29 static char *_vu_sony_c_ident_ = "@(#)vu_sony.c 6.46 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_SONY
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 STATIC byte_t sony_route_left, /* left ch routing control */
46 sony_route_right; /* Right ch routing control */
47
48
49 /*
50 * sony_route_val
51 * Return the channel routing control value used in the
52 * Sony Playback Status command.
53 *
54 * Args:
55 * route_mode - The channel routing mode value.
56 * channel - The channel number desired (0=left 1=right).
57 *
58 * Return:
59 * The routing control value.
60 */
61 STATIC byte_t
sony_route_val(int route_mode,int channel)62 sony_route_val(int route_mode, int channel)
63 {
64 switch (channel) {
65 case 0:
66 switch (route_mode) {
67 case 0:
68 return 0x1;
69 case 1:
70 return 0x2;
71 case 2:
72 return 0x1;
73 case 3:
74 return 0x2;
75 case 4:
76 return 0x3;
77 default:
78 /* Invalid value */
79 return 0x0;
80 }
81 /*NOTREACHED*/
82
83 case 1:
84 switch (route_mode) {
85 case 0:
86 return 0x2;
87 case 1:
88 return 0x1;
89 case 2:
90 return 0x1;
91 case 3:
92 return 0x2;
93 case 4:
94 return 0x3;
95 default:
96 /* Invalid value */
97 return 0x0;
98 }
99 /*NOTREACHED*/
100
101 default:
102 /* Invalid value */
103 return 0x0;
104 }
105 }
106
107
108 /*
109 * sony_playaudio
110 * Play audio function: send vendor-unique play audio command
111 * to the drive.
112 *
113 * Args:
114 * addr_fmt - Flags indicating which address formats are passed in
115 * If ADDR_BLK, then:
116 * start_addr - The logical block starting address
117 * end_addr - The logical block ending address
118 * If ADD_MSF, then:
119 * start_msf - Pointer to the starting MSF address structure
120 * end_msf - Pointer to the ending MSF address structure
121 * If ADDR_TRKIDX, then:
122 * trk - The starting track number
123 * idx - The starting index number
124 * If ADDR_OPTEND, then the ending address, if specified, can be
125 * ignored if possible.
126 *
127 * Return:
128 * TRUE - success
129 * FALSE - failure
130 */
131 /*ARGSUSED*/
132 bool_t
sony_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)133 sony_playaudio(
134 byte_t addr_fmt,
135 sword32_t start_addr,
136 sword32_t end_addr,
137 msf_t *start_msf,
138 msf_t *end_msf,
139 byte_t trk,
140 byte_t idx
141 )
142 {
143 msf_t istart_msf,
144 iend_msf;
145 bool_t ret = FALSE;
146
147 if (!ret && (addr_fmt & ADDR_BLK) && !(addr_fmt & ADDR_MSF)) {
148 /* Convert block address to MSF format */
149 util_blktomsf(
150 start_addr,
151 &istart_msf.min, &istart_msf.sec, &istart_msf.frame,
152 MSF_OFFSET
153 );
154
155 util_blktomsf(
156 end_addr,
157 &iend_msf.min, &iend_msf.sec, &iend_msf.frame,
158 MSF_OFFSET
159 );
160
161 /* Let the ADDR_MSF code handle the request */
162 start_msf = &istart_msf;
163 end_msf = &iend_msf;
164 addr_fmt |= ADDR_MSF;
165 ret = FALSE;
166 }
167
168 if (!ret && addr_fmt & ADDR_MSF) {
169 SCSICDB_RESET(cdb);
170 cdb[0] = OP_VS_PLAYMSF;
171 cdb[3] = start_msf->min;
172 cdb[4] = start_msf->sec;
173 cdb[5] = start_msf->frame;
174 cdb[6] = end_msf->min;
175 cdb[7] = end_msf->sec;
176 cdb[8] = end_msf->frame;
177
178 ret = pthru_send(devp, DI_ROLE_MAIN, cdb, 10, NULL, 0, NULL, 0,
179 OP_NODATA, 10, TRUE);
180 }
181
182 return (ret);
183 }
184
185
186 /*
187 * sony_pause_resume
188 * Pause/resume function: send vendor-unique commands to implement
189 * the pause and resume capability.
190 *
191 * Args:
192 * resume - TRUE: resume, FALSE: pause
193 *
194 * Return:
195 * TRUE - success
196 * FALSE - failure
197 */
198 bool_t
sony_pause_resume(bool_t resume)199 sony_pause_resume(bool_t resume)
200 {
201 SCSICDB_RESET(cdb);
202 cdb[0] = OP_VS_PAUSE;
203 cdb[1] = resume ? 0x00 : 0x10;
204
205 return(pthru_send(devp, DI_ROLE_MAIN, cdb, 10, NULL, 0, NULL, 0,
206 OP_NODATA, 5, TRUE));
207 }
208
209
210 /*
211 * sony_get_playstatus
212 * Send vendor-unique command to obtain current audio playback
213 * status.
214 *
215 * Args:
216 * sp - Pointer to the caller-supplied cdstat_t return structure
217 *
218 * Return:
219 * TRUE - success
220 * FALSE - failure
221 */
222 bool_t
sony_get_playstatus(cdstat_t * sp)223 sony_get_playstatus(cdstat_t *sp)
224 {
225 byte_t dbuf[sizeof(sstat_data_t)],
226 qbuf[sizeof(ssubq_data_t)];
227 sstat_data_t *d;
228 ssubq_data_t *q;
229
230
231 /*
232 * Send Sony Playback Status command
233 */
234
235 (void) memset(dbuf, 0, sizeof(dbuf));
236
237 SCSICDB_RESET(cdb);
238 cdb[0] = OP_VS_PLAYSTAT;
239 cdb[8] = SZ_VS_PLAYSTAT;
240
241 if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10, dbuf, SZ_VS_PLAYSTAT,
242 NULL, 0, OP_DATAIN, 5, TRUE))
243 return FALSE;
244
245 DBGDUMP(DBG_DEVIO)("sony: Playback Status data bytes",
246 dbuf, SZ_VS_PLAYSTAT);
247
248 d = (sstat_data_t *)(void *) dbuf;
249
250 /* Translate Sony audio status to cdstat_t status */
251 switch (d->audio_status) {
252 case SAUD_PLAYING:
253 case SAUD_MUTED:
254 sp->status = CDSTAT_PLAYING;
255 break;
256
257 case SAUD_PAUSED:
258 sp->status = CDSTAT_PAUSED;
259 break;
260
261 case SAUD_COMPLETED:
262 sp->status = CDSTAT_COMPLETED;
263 break;
264
265 case SAUD_ERROR:
266 sp->status = CDSTAT_FAILED;
267 break;
268
269 case SAUD_NOTREQ:
270 sp->status = CDSTAT_NOSTATUS;
271 break;
272 }
273
274 /*
275 * Send Sony Read Subchannel command
276 */
277
278 (void) memset(qbuf, 0, sizeof(qbuf));
279
280 SCSICDB_RESET(cdb);
281 cdb[0] = OP_VS_RDSUBQ;
282 cdb[2] = 0x40;
283 cdb[8] = SZ_VS_RDSUBQ;
284
285 if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10, qbuf, SZ_VS_RDSUBQ,
286 NULL, 0, OP_DATAIN, 5, TRUE))
287 return FALSE;
288
289 DBGDUMP(DBG_DEVIO)("sony: Read Subchannel data bytes",
290 qbuf, SZ_VS_RDSUBQ);
291
292 q = (ssubq_data_t *)(void *) qbuf;
293
294 sp->track = (int) q->trkno;
295 sp->index = (int) q->idxno;
296
297 sp->abs_addr.min = (byte_t) q->abs_min;
298 sp->abs_addr.sec = (byte_t) q->abs_sec;
299 sp->abs_addr.frame = (byte_t) q->abs_frame;
300 sp->rel_addr.min = (byte_t) q->rel_min;
301 sp->rel_addr.sec = (byte_t) q->rel_sec;
302 sp->rel_addr.frame = (byte_t) q->rel_frame;
303 util_msftoblk(
304 sp->abs_addr.min, sp->abs_addr.sec, sp->abs_addr.frame,
305 &sp->abs_addr.addr, MSF_OFFSET
306 );
307 util_msftoblk(
308 sp->rel_addr.min, sp->rel_addr.sec, sp->rel_addr.frame,
309 &sp->rel_addr.addr, 0
310 );
311
312 return TRUE;
313 }
314
315
316 /*
317 * sony_get_toc
318 * Send vendor-unique command to obtain the disc table-of-contents
319 *
320 * Args:
321 * s - Pointer to the curstat_t structure, which contains the TOC
322 * table to be updated.
323 *
324 * Return:
325 * TRUE - success
326 * FALSE - failure
327 */
328 bool_t
sony_get_toc(curstat_t * s)329 sony_get_toc(curstat_t *s)
330 {
331 int i,
332 j,
333 xfer_len;
334 byte_t buf[sizeof(stoc_data_t)];
335 stoc_data_t *d;
336 stoc_ent_t *e;
337
338 (void) memset(buf, 0, sizeof(buf));
339
340 /* Read TOC header to find the number of tracks */
341 for (i = 1; i < MAXTRACK - 1; i++) {
342 SCSICDB_RESET(cdb);
343 cdb[0] = OP_VS_RDTOC;
344 cdb[5] = (byte_t) i;
345 cdb[8] = SZ_VS_TOCHDR;
346
347 if (pthru_send(devp, DI_ROLE_MAIN, cdb, 10, buf, SZ_VS_TOCHDR,
348 NULL, 0, OP_DATAIN, 5, TRUE))
349 break;
350 }
351 if (i == MAXTRACK - 1)
352 return FALSE;
353
354 d = (stoc_data_t *)(void *) buf;
355
356 s->first_trk = (byte_t) d->first_trk;
357 s->last_trk = (byte_t) d->last_trk;
358
359 xfer_len = SZ_VS_TOCHDR +
360 ((int) (d->last_trk - d->first_trk + 2) * SZ_VS_TOCENT);
361
362 if (xfer_len > SZ_VS_RDTOC)
363 xfer_len = SZ_VS_RDTOC;
364
365 SCSICDB_RESET(cdb);
366 cdb[0] = OP_VS_RDTOC;
367 cdb[5] = (byte_t) s->first_trk;
368 cdb[7] = (xfer_len & 0xff00) >> 8;
369 cdb[8] = (xfer_len & 0x00ff);
370
371 if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10, buf, xfer_len, NULL, 0,
372 OP_DATAIN, 5, TRUE))
373 return FALSE;
374
375 DBGDUMP(DBG_DEVIO)("sony: Read TOC data bytes", buf, SZ_VS_RDTOC);
376
377 /* Get the starting position of each track */
378 for (i = 0, j = (int) s->first_trk; j <= (int) s->last_trk; i++, j++) {
379 e = (stoc_ent_t *)(void *) &d->trkdata[i * SZ_VS_TOCENT];
380 s->trkinfo[i].trkno = j;
381 s->trkinfo[i].min = (byte_t) e->min;
382 s->trkinfo[i].sec = (byte_t) e->sec;
383 s->trkinfo[i].frame = (byte_t) e->frame;
384 util_msftoblk(
385 s->trkinfo[i].min,
386 s->trkinfo[i].sec,
387 s->trkinfo[i].frame,
388 &s->trkinfo[i].addr,
389 MSF_OFFSET
390 );
391 s->trkinfo[i].type = (e->trktype == 0) ? TYP_AUDIO : TYP_DATA;
392 }
393 s->tot_trks = (byte_t) i;
394
395 /* Get the lead-out track position */
396 e = (stoc_ent_t *)(void *) &d->trkdata[i * SZ_VS_TOCENT];
397 s->trkinfo[i].trkno = LEAD_OUT_TRACK;
398 s->discpos_tot.min = s->trkinfo[i].min = (byte_t) e->min;
399 s->discpos_tot.sec = s->trkinfo[i].sec = (byte_t) e->sec;
400 s->discpos_tot.frame = s->trkinfo[i].frame = (byte_t) e->frame;
401 util_msftoblk(
402 s->trkinfo[i].min,
403 s->trkinfo[i].sec,
404 s->trkinfo[i].frame,
405 &s->trkinfo[i].addr,
406 MSF_OFFSET
407 );
408 s->discpos_tot.addr = s->trkinfo[i].addr;
409 return TRUE;
410 }
411
412
413 /*
414 * sony_volume
415 * Send vendor-unique command to query/control the playback volume.
416 *
417 * Args:
418 * vol - Volume level to set to
419 * s - Pointer to the curstat_t structure
420 * query - This call is to query the current volume setting rather
421 * than to set it.
422 *
423 * Return:
424 * The current volume value.
425 */
426 int
sony_volume(int vol,curstat_t * s,bool_t query)427 sony_volume(int vol, curstat_t *s, bool_t query)
428 {
429 int vol1,
430 vol2;
431 byte_t buf[sizeof(sstat_data_t)];
432 sstat_data_t *d;
433
434 (void) memset(buf, 0, sizeof(buf));
435
436 SCSICDB_RESET(cdb);
437 cdb[0] = OP_VS_PLAYSTAT;
438 cdb[8] = SZ_VS_PLAYSTAT;
439
440 if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10, buf, SZ_VS_PLAYSTAT,
441 NULL, 0, OP_DATAIN, 5, TRUE))
442 return -1;
443
444 DBGDUMP(DBG_DEVIO)("sony: Playback Status data bytes",
445 buf, SZ_VS_PLAYSTAT);
446
447 d = (sstat_data_t *)(void *) buf;
448
449 if (query) {
450 vol1 = util_untaper_vol(util_unscale_vol((int) d->vol0));
451 vol2 = util_untaper_vol(util_unscale_vol((int) d->vol1));
452 sony_route_left = (byte_t) d->sel0;
453 sony_route_right = (byte_t) d->sel1;
454
455 if (vol1 == vol2) {
456 s->level_left = s->level_right = 100;
457 vol = vol1;
458 }
459 else if (vol1 > vol2) {
460 s->level_left = 100;
461 s->level_right = (byte_t) ((vol2 * 100) / vol1);
462 vol = vol1;
463 }
464 else {
465 s->level_left = (byte_t) ((vol1 * 100) / vol2);
466 s->level_right = 100;
467 vol = vol2;
468 }
469
470 return (vol);
471 }
472 else {
473 (void) memset(buf, 0, 10);
474
475 d->vol0 = (byte_t) util_scale_vol(
476 util_taper_vol(vol * (int) s->level_left / 100)
477 );
478 d->vol1 = (byte_t) util_scale_vol(
479 util_taper_vol(vol * (int) s->level_right / 100)
480 );
481 d->sel0 = sony_route_left;
482 d->sel1 = sony_route_right;
483
484 DBGDUMP(DBG_DEVIO)("sony: Playback Control data bytes",
485 buf, SZ_VS_PLAYSTAT);
486
487 SCSICDB_RESET(cdb);
488 cdb[0] = OP_VS_PLAYCTL;
489 cdb[8] = SZ_VS_PLAYSTAT;
490
491 if (pthru_send(devp, DI_ROLE_MAIN, cdb, 10,
492 buf, SZ_VS_PLAYSTAT, NULL, 0,
493 OP_DATAOUT, 5, TRUE)) {
494 /* Success */
495 return (vol);
496 }
497 else if (d->vol0 != d->vol1) {
498 /* Set the balance to the center
499 * and retry.
500 */
501 d->vol0 = d->vol1 = util_scale_vol(
502 util_taper_vol(vol)
503 );
504
505 DBGDUMP(DBG_DEVIO)("sony: Playback Control data bytes",
506 buf, SZ_VS_PLAYSTAT);
507
508 SCSICDB_RESET(cdb);
509 cdb[0] = OP_VS_PLAYCTL;
510 cdb[8] = SZ_VS_PLAYSTAT;
511
512 if (pthru_send(devp, DI_ROLE_MAIN, cdb, 10,
513 buf, SZ_VS_PLAYSTAT,
514 NULL, 0, OP_DATAOUT, 5, TRUE)) {
515 /* Success: Warp balance control */
516 s->level_left = s->level_right = 100;
517 return (vol);
518 }
519
520 /* Still failed: just drop through */
521 }
522 }
523
524 return -1;
525 }
526
527
528 /*
529 * sony_route
530 * Configure channel routing via Sony Vendor-unique commands.
531 *
532 * Args:
533 * s - Pointer to the curstat_t structure
534 *
535 * Return:
536 * TRUE - success
537 * FALSE - failure
538 */
539 bool_t
sony_route(curstat_t * s)540 sony_route(curstat_t *s)
541 {
542 byte_t val0,
543 val1;
544
545 val0 = sony_route_val(app_data.ch_route, 0);
546 val1 = sony_route_val(app_data.ch_route, 1);
547
548 if (val0 == sony_route_left && val1 == sony_route_right)
549 /* No change: just return */
550 return TRUE;
551
552 sony_route_left = val0;
553 sony_route_right = val1;
554
555 /* Sony channel routing is done with the volume control */
556 (void) sony_volume(s->level, s, FALSE);
557
558 return TRUE;
559 }
560
561
562 /*
563 * sony_init
564 * Initialize the vendor-unique support module
565 *
566 * Args:
567 * Nothing.
568 *
569 * Return:
570 * Nothing.
571 */
572 void
sony_init(void)573 sony_init(void)
574 {
575 /* Register vendor_unique module entry points */
576 scsipt_vutbl[VENDOR_SONY].vendor = "Sony";
577 scsipt_vutbl[VENDOR_SONY].playaudio = sony_playaudio;
578 scsipt_vutbl[VENDOR_SONY].pause_resume = sony_pause_resume;
579 scsipt_vutbl[VENDOR_SONY].start_stop = NULL;
580 scsipt_vutbl[VENDOR_SONY].get_playstatus = sony_get_playstatus;
581 scsipt_vutbl[VENDOR_SONY].volume = sony_volume;
582 scsipt_vutbl[VENDOR_SONY].route = sony_route;
583 scsipt_vutbl[VENDOR_SONY].mute = NULL;
584 scsipt_vutbl[VENDOR_SONY].get_toc = sony_get_toc;
585 scsipt_vutbl[VENDOR_SONY].eject = NULL;
586 scsipt_vutbl[VENDOR_SONY].start = sony_start;
587 scsipt_vutbl[VENDOR_SONY].halt = NULL;
588 }
589
590
591 /*
592 * sony_start
593 * Start the vendor-unique support module. In the case of the Sony,
594 * we want to set the drive's CD addressing to MSF mode. Some Sony
595 * drives use the Mode Select command (page 0x8) to do this while
596 * others use a special vendor-unique "Set Address Format" command.
597 * We determine which to use by overloading the meaning of the
598 * app_data.msen_dbd configuration parameter.
599 *
600 * Args:
601 * Nothing.
602 *
603 * Return:
604 * Nothing.
605 */
606 void
sony_start(void)607 sony_start(void)
608 {
609 byte_t buf[SZ_VS_CDPARM];
610 mode_sense_6_data_t *ms_data;
611 blk_desc_t *bdesc;
612 cdparm_pg_t *parm_pg;
613
614 if (app_data.msen_dbd) {
615 /* Send "Set Address Format" command */
616 SCSICDB_RESET(cdb);
617 cdb[0] = OP_VS_SETADDRFMT;
618 cdb[8] = 0x01;
619
620 (void) pthru_send(devp, DI_ROLE_MAIN, cdb, 10,
621 NULL, 0, NULL, 0, OP_NODATA, 5, TRUE);
622 }
623 else {
624 /* Do Mode Sense command, CD-ROM parameters page */
625 if (!scsipt_modesense(devp, DI_ROLE_MAIN, buf, 0, PG_VS_CDPARM,
626 SZ_VS_CDPARM))
627 return; /* Error */
628
629 ms_data = (mode_sense_6_data_t *)(void *) buf;
630 bdesc = (blk_desc_t *)(void *) ms_data->data;
631 parm_pg = (cdparm_pg_t *)(void *)
632 &ms_data->data[ms_data->bdescr_len];
633
634 if (parm_pg->pg_code != PG_VS_CDPARM)
635 return; /* Error */
636
637 ms_data->data_len = 0;
638 if (ms_data->bdescr_len > 0)
639 bdesc->num_blks = 0;
640
641 /* Set the drive up for MSF address mode */
642 parm_pg->lbamsf = 1;
643
644 (void) scsipt_modesel(devp, DI_ROLE_MAIN, buf,
645 PG_VS_CDPARM, SZ_VS_CDPARM);
646 }
647 }
648
649
650 #endif /* VENDOR_SONY */
651
652