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