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  *   Toshiba vendor-unique support
24  *
25  *   The name "Toshiba" is a trademark of Toshiba Corporation, and is
26  *   used here for identification purposes only.
27  */
28 #ifndef lint
29 static char *_vu_tosh_c_ident_ = "@(#)vu_tosh.c	6.40 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_TOSHIBA
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 bool_t		tosh_audio_muted;	/* Is audio muted? */
46 
47 
48 /*
49  * tosh_playaudio
50  *	Play audio function: send vendor-unique play audio command
51  *	to the drive.
52  *
53  * Args:
54  *	addr_fmt - Flags indicating which address formats are passed in
55  *	If ADDR_BLK, then:
56  *	    start_addr - The logical block starting address
57  *	    end_addr - The logical block ending address
58  *	If ADD_MSF, then:
59  *	    start_msf - Pointer to the starting MSF address structure
60  *	    end_msf - Pointer to the ending MSF address structure
61  *	If ADDR_TRKIDX, then:
62  *	    trk - The starting track number
63  *	    idx - The starting index number
64  *	If ADDR_OPTEND, then the ending address, if specified, can be
65  *	ignored if possible.
66  *
67  * Return:
68  *	TRUE - success
69  *	FALSE - failure
70  */
71 /*ARGSUSED*/
72 bool_t
tosh_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)73 tosh_playaudio(
74 	byte_t		addr_fmt,
75 	sword32_t	start_addr,
76 	sword32_t	end_addr,
77 	msf_t		*start_msf,
78 	msf_t		*end_msf,
79 	byte_t		trk,
80 	byte_t		idx
81 )
82 {
83 	bool_t		ret = FALSE;
84 
85 	if (!ret && addr_fmt & ADDR_MSF) {
86 		/* Position laser head at desired location
87 		 * and start play.
88 		 */
89 		SCSICDB_RESET(cdb);
90 		cdb[0] = OP_VT_AUDSRCH;
91 		cdb[1] = 0x01;
92 		cdb[2] = (byte_t) util_ltobcd(start_msf->min);
93 		cdb[3] = (byte_t) util_ltobcd(start_msf->sec);
94 		cdb[4] = (byte_t) util_ltobcd(start_msf->frame);
95 		cdb[9] = 0x40;
96 
97 		ret = pthru_send(devp, DI_ROLE_MAIN, cdb, 10, NULL, 0, NULL, 0,
98 				 OP_NODATA, 10, TRUE);
99 
100 		if (ret && !(addr_fmt & ADDR_OPTEND)) {
101 			/* Specify end location, muting, and start play */
102 			SCSICDB_RESET(cdb);
103 			cdb[0] = OP_VT_AUDPLAY;
104 			cdb[1] = tosh_audio_muted ? 0x00 : 0x03;
105 			cdb[2] = (byte_t) util_ltobcd(end_msf->min);
106 			cdb[3] = (byte_t) util_ltobcd(end_msf->sec);
107 			cdb[4] = (byte_t) util_ltobcd(end_msf->frame);
108 			cdb[9] = 0x40;
109 
110 			ret = pthru_send(devp, DI_ROLE_MAIN, cdb, 10,
111 					 NULL, 0, NULL, 0,
112 					 OP_NODATA, 10, TRUE);
113 		}
114 	}
115 
116 	if (!ret && addr_fmt & ADDR_BLK) {
117 		/* Position laser head at desired location
118 		 * and start play.
119 		 */
120 		SCSICDB_RESET(cdb);
121 		cdb[0] = OP_VT_AUDSRCH;
122 		cdb[1] = 0x01;
123 		cdb[2] = ((word32_t) start_addr & 0xff000000) >> 24;
124 		cdb[3] = ((word32_t) start_addr & 0x00ff0000) >> 16;
125 		cdb[4] = ((word32_t) start_addr & 0x0000ff00) >> 8;
126 		cdb[5] = ((word32_t) start_addr & 0x000000ff);
127 		cdb[9] = 0x00;
128 
129 		ret = pthru_send(devp, DI_ROLE_MAIN, cdb, 10, NULL, 0, NULL, 0,
130 				 OP_NODATA, 10, TRUE);
131 
132 		if (ret && !(addr_fmt & ADDR_OPTEND)) {
133 			/* Specify end location, muting, and start play */
134 			SCSICDB_RESET(cdb);
135 			cdb[0] = OP_VT_AUDPLAY;
136 			cdb[1] = tosh_audio_muted ? 0x00 : 0x03;
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 	}
148 
149 	return (ret);
150 }
151 
152 
153 /*
154  * tosh_pause_resume
155  *	Pause/resume function: send vendor-unique commands to implement
156  *	the pause and resume capability.
157  *
158  * Args:
159  *	resume - TRUE: resume, FALSE: pause
160  *
161  * Return:
162  *	TRUE - success
163  *	FALSE - failure
164  */
165 bool_t
tosh_pause_resume(bool_t resume)166 tosh_pause_resume(bool_t resume)
167 {
168 	SCSICDB_RESET(cdb);
169 
170 	if (resume) {
171 		cdb[0] = OP_VT_AUDPLAY;
172 		cdb[1] = tosh_audio_muted ? 0x00 : 0x03;
173 		cdb[9] = 0xc0;
174 
175 		return (
176 			pthru_send(devp, DI_ROLE_MAIN, cdb, 10,
177 				   NULL, 0, NULL, 0, OP_NODATA, 5, TRUE)
178 		);
179 	}
180 	else {
181 		cdb[0] = OP_VT_STILL;
182 
183 		return (
184 			pthru_send(devp, DI_ROLE_MAIN, cdb, 10,
185 				   NULL, 0, NULL, 0, OP_NODATA, 5, TRUE)
186 		);
187 	}
188 }
189 
190 
191 /*
192  * tosh_get_playstatus
193  *	Send vendor-unique command to obtain current audio playback
194  *	status.
195  *
196  * Args:
197  *	sp - Pointer to the caller-supplied cdstat_t return structure
198  *
199  * Return:
200  *	TRUE - success
201  *	FALSE - failure
202  */
203 bool_t
tosh_get_playstatus(cdstat_t * sp)204 tosh_get_playstatus(cdstat_t *sp)
205 {
206 	byte_t		buf[sizeof(tsubq_data_t)];
207 	tsubq_data_t	*d;
208 
209 
210 	(void) memset(buf, 0, sizeof(buf));
211 
212 	SCSICDB_RESET(cdb);
213 	cdb[0] = OP_VT_RDSUBQ;
214 	cdb[1] = SZ_VT_RDSUBQ & 0x1f;
215 
216 	if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10, buf, SZ_VT_RDSUBQ,
217 			NULL, 0, OP_DATAIN, 5, TRUE))
218 		return FALSE;
219 
220 	DBGDUMP(DBG_DEVIO)("tosh: Read Subchannel data bytes",
221 		buf, SZ_VT_RDSUBQ);
222 
223 	d = (tsubq_data_t *)(void *) buf;
224 
225 	sp->track = (int) util_bcdtol((word32_t) d->trkno);
226 	sp->index = (int) util_bcdtol((word32_t) d->idxno);
227 
228 	sp->abs_addr.min = (byte_t) util_bcdtol(d->abs_min);
229 	sp->abs_addr.sec = (byte_t) util_bcdtol(d->abs_sec);
230 	sp->abs_addr.frame = (byte_t) util_bcdtol(d->abs_frame);
231 	sp->rel_addr.min = (byte_t) util_bcdtol(d->rel_min);
232 	sp->rel_addr.sec = (byte_t) util_bcdtol(d->rel_sec);
233 	sp->rel_addr.frame = (byte_t) util_bcdtol(d->rel_frame);
234 	util_msftoblk(
235 		sp->abs_addr.min, sp->abs_addr.sec, sp->abs_addr.frame,
236 		&sp->abs_addr.addr, MSF_OFFSET
237 	);
238 	util_msftoblk(
239 		sp->rel_addr.min, sp->rel_addr.sec, sp->rel_addr.frame,
240 		&sp->rel_addr.addr, 0
241 	);
242 
243 	/* Translate Toshiba audio status to SCSI-2 audio status */
244 	switch (d->audio_status) {
245 	case TAUD_PLAYING:
246 		sp->status = CDSTAT_PLAYING;
247 		break;
248 
249 	case TAUD_SRCH_PAUSED:
250 	case TAUD_PAUSED:
251 		sp->status = CDSTAT_PAUSED;
252 		break;
253 
254 	case TAUD_OTHER:
255 		sp->status = CDSTAT_COMPLETED;
256 		break;
257 	}
258 
259 	return TRUE;
260 }
261 
262 
263 /*
264  * tosh_get_toc
265  *	Send vendor-unique command to obtain the disc table-of-contents
266  *
267  * Args:
268  *	s - Pointer to the curstat_t structure, which contains the TOC
269  *	    table to be updated.
270  *
271  * Return:
272  *	TRUE - success
273  *	FALSE - failure
274  */
275 bool_t
tosh_get_toc(curstat_t * s)276 tosh_get_toc(curstat_t *s)
277 {
278 	int		i,
279 			j;
280 	byte_t		buf[SZ_VT_RDINFO];
281 	tinfo_00_t	*t0;
282 	tinfo_01_t	*t1;
283 	tinfo_02_t	*t2;
284 
285 
286 	(void) memset(buf, 0, sizeof(buf));
287 
288 	/* Find number of tracks */
289 	SCSICDB_RESET(cdb);
290 	cdb[0] = OP_VT_RDINFO;
291 	cdb[1] = 0x00;
292 
293 	if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10, buf, SZ_VT_RDINFO,
294 			NULL, 0, OP_DATAIN, 5, TRUE))
295 		return FALSE;
296 
297 	DBGDUMP(DBG_DEVIO)("tosh: Read Disc Info data bytes",
298 		buf, SZ_VT_RDINFO);
299 
300 	t0 = (tinfo_00_t *) buf;
301 	s->first_trk = (byte_t) util_bcdtol(t0->first_trk);
302 	s->last_trk = (byte_t) util_bcdtol(t0->last_trk);
303 
304 	/* Get the starting position of each track */
305 	for (i = 0, j = (int) s->first_trk; j <= (int) s->last_trk; i++, j++) {
306 		(void) memset(buf, 0, sizeof(buf));
307 
308 		SCSICDB_RESET(cdb);
309 		cdb[0] = OP_VT_RDINFO;
310 		cdb[1] = 0x02;
311 		cdb[2] = (byte_t) util_ltobcd(j);
312 
313 		if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10,
314 				buf, SZ_VT_RDINFO, NULL, 0,
315 				OP_DATAIN, 5, TRUE))
316 			return FALSE;
317 
318 		DBGDUMP(DBG_DEVIO)("tosh: Read Disc Info data bytes",
319 			buf, SZ_VT_RDINFO);
320 
321 		t2 = (tinfo_02_t *) buf;
322 
323 		s->trkinfo[i].trkno = j;
324 		s->trkinfo[i].min = (byte_t) util_bcdtol(t2->min);
325 		s->trkinfo[i].sec = (byte_t) util_bcdtol(t2->sec);
326 		s->trkinfo[i].frame = (byte_t) util_bcdtol(t2->frame);
327 		util_msftoblk(
328 			s->trkinfo[i].min,
329 			s->trkinfo[i].sec,
330 			s->trkinfo[i].frame,
331 			&s->trkinfo[i].addr,
332 			MSF_OFFSET
333 		);
334 	}
335 	s->tot_trks = (byte_t) i;
336 
337 	(void) memset(buf, 0, sizeof(buf));
338 
339 	/* Get the lead out track position */
340 	SCSICDB_RESET(cdb);
341 	cdb[0] = OP_VT_RDINFO;
342 	cdb[1] = 0x01;
343 
344 	if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10, buf, SZ_VT_RDINFO,
345 			NULL, 0, OP_DATAIN, 5, TRUE))
346 		return FALSE;
347 
348 	DBGDUMP(DBG_DEVIO)("tosh: Read Disc Info data bytes",
349 		buf, SZ_VT_RDINFO);
350 
351 	t1 = (tinfo_01_t *) buf;
352 
353 	s->trkinfo[i].trkno = LEAD_OUT_TRACK;
354 	s->discpos_tot.min = s->trkinfo[i].min = (byte_t) util_bcdtol(t1->min);
355 	s->discpos_tot.sec = s->trkinfo[i].sec = (byte_t) util_bcdtol(t1->sec);
356 	s->discpos_tot.frame = s->trkinfo[i].frame =
357 		(byte_t) util_bcdtol(t1->frame);
358 	util_msftoblk(
359 		s->trkinfo[i].min,
360 		s->trkinfo[i].sec,
361 		s->trkinfo[i].frame,
362 		&s->trkinfo[i].addr,
363 		MSF_OFFSET
364 	);
365 	s->discpos_tot.addr = s->trkinfo[i].addr;
366 
367 	return TRUE;
368 }
369 
370 
371 /*
372  * tosh_mute
373  *	Send vendor-unique command to mute/unmute the audio
374  *
375  * Args:
376  *	mute - TRUE: mute audio, FALSE: unmute audio
377  *
378  * Return:
379  *	TRUE - success
380  *	FALSE - failure
381  */
382 bool_t
tosh_mute(bool_t mute)383 tosh_mute(bool_t mute)
384 {
385 	curstat_t	*s = di_clinfo->curstat_addr();
386 
387 	if (tosh_audio_muted != mute) {
388 		switch (s->mode) {
389 		case MOD_BUSY:
390 		case MOD_NODISC:
391 		case MOD_STOP:
392 		case MOD_PAUSE:
393 			break;
394 
395 		default:
396 			SCSICDB_RESET(cdb);
397 			cdb[0] = OP_VT_AUDPLAY;
398 			cdb[1] = mute ? 0x00 : 0x03;
399 			cdb[9] = 0xc0;
400 
401 			if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10,
402 					NULL, 0, NULL, 0, OP_NODATA, 5, TRUE))
403 				return FALSE;
404 			break;
405 		}
406 
407 		tosh_audio_muted = mute;
408 	}
409 
410 	return TRUE;
411 }
412 
413 
414 /*
415  * tosh_eject
416  *	Send vendor-unique command to eject the caddy
417  *
418  * Args:
419  *	Nothing.
420  *
421  * Return:
422  *	TRUE - success
423  *	FALSE - failure
424  */
425 bool_t
tosh_eject(void)426 tosh_eject(void)
427 {
428 	SCSICDB_RESET(cdb);
429 	cdb[0] = OP_VT_EJECT;
430 	cdb[1] = 0x01;	/* Set immediate bit */
431 
432 	return (pthru_send(devp, DI_ROLE_MAIN, cdb, 10, NULL, 0, NULL, 0,
433 			   OP_NODATA, 20, TRUE));
434 }
435 
436 
437 /*
438  * tosh_init
439  *	Initialize the vendor-unique support module
440  *
441  * Args:
442  *	Nothing.
443  *
444  * Return:
445  *	Nothing.
446  */
447 void
tosh_init(void)448 tosh_init(void)
449 {
450 	/* Register vendor_unique module entry points */
451 	scsipt_vutbl[VENDOR_TOSHIBA].vendor = "Toshiba";
452 	scsipt_vutbl[VENDOR_TOSHIBA].playaudio = tosh_playaudio;
453 	scsipt_vutbl[VENDOR_TOSHIBA].pause_resume = tosh_pause_resume;
454 	scsipt_vutbl[VENDOR_TOSHIBA].start_stop = NULL;
455 	scsipt_vutbl[VENDOR_TOSHIBA].get_playstatus = tosh_get_playstatus;
456 	scsipt_vutbl[VENDOR_TOSHIBA].volume = NULL;
457 	scsipt_vutbl[VENDOR_TOSHIBA].route = NULL;
458 	scsipt_vutbl[VENDOR_TOSHIBA].mute = tosh_mute;
459 	scsipt_vutbl[VENDOR_TOSHIBA].get_toc = tosh_get_toc;
460 	scsipt_vutbl[VENDOR_TOSHIBA].eject = tosh_eject;
461 	scsipt_vutbl[VENDOR_TOSHIBA].start = NULL;
462 	scsipt_vutbl[VENDOR_TOSHIBA].halt = NULL;
463 }
464 
465 
466 #endif	/* VENDOR_TOSHIBA */
467 
468