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  *   NEC vendor-unique support
24  *
25  *   The name "NEC" is a trademark of NEC Corporation, and is used here
26  *   for identification purposes only.
27  */
28 #ifndef lint
29 static char *_vu_nec_c_ident_ = "@(#)vu_nec.c	6.41 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_NEC
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		nec_audio_muted;	/* Is audio muted? */
46 
47 
48 /*
49  * nec_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
nec_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 nec_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_VN_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_VN_AUDPLAY;
104 			cdb[1] = nec_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,
111 					 cdb, 10, 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_VN_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_VN_AUDPLAY;
136 			cdb[1] = nec_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,
144 					 cdb, 10, NULL, 0, NULL, 0,
145 					 OP_NODATA, 10, TRUE);
146 		}
147 	}
148 
149 	return (ret);
150 }
151 
152 
153 /*
154  * nec_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
nec_pause_resume(bool_t resume)166 nec_pause_resume(bool_t resume)
167 {
168 	SCSICDB_RESET(cdb);
169 
170 	if (resume) {
171 		cdb[0] = OP_VN_AUDPLAY;
172 		cdb[1] = nec_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_VN_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  * nec_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
nec_get_playstatus(cdstat_t * sp)204 nec_get_playstatus(cdstat_t *sp)
205 {
206 	byte_t		buf[sizeof(nsubq_data_t)];
207 	nsubq_data_t	*d;
208 
209 
210 	(void) memset(buf, 0, sizeof(buf));
211 
212 	SCSICDB_RESET(cdb);
213 	cdb[0] = OP_VN_RDSUBQ;
214 	cdb[1] = SZ_VN_RDSUBQ & 0x1f;
215 
216 	if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10, buf, SZ_VN_RDSUBQ,
217 			NULL, 0, OP_DATAIN, 5, TRUE))
218 		return FALSE;
219 
220 	DBGDUMP(DBG_DEVIO)("nec: Read Subchannel data bytes",
221 		buf, SZ_VN_RDSUBQ);
222 
223 	d = (nsubq_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 NEC audio status to SCSI-2 audio status */
244 	switch (d->audio_status) {
245 	case NAUD_PLAYING:
246 		sp->status = CDSTAT_PLAYING;
247 		break;
248 
249 	case NAUD_PAUSED:
250 	case NAUD_SRCH_PAUSED:
251 		sp->status = CDSTAT_PAUSED;
252 		break;
253 
254 	case NAUD_COMPLETED:
255 		sp->status = CDSTAT_COMPLETED;
256 		break;
257 	}
258 
259 	return TRUE;
260 }
261 
262 
263 /*
264  * nec_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
nec_get_toc(curstat_t * s)276 nec_get_toc(curstat_t *s)
277 {
278 	int		i,
279 			j;
280 	byte_t		buf[SZ_VN_RDTOC];
281 	ninfo_00_t	*t0;
282 	ninfo_01_t	*t1;
283 	ninfo_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_VN_RDTOC;
291 	cdb[1] = 0x00;
292 
293 	if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10, buf, SZ_VN_RDTOC, NULL, 0,
294 			OP_DATAIN, 5, TRUE))
295 		return FALSE;
296 
297 	DBGDUMP(DBG_DEVIO)("nec: Read TOC data bytes", buf, SZ_VN_RDTOC);
298 
299 	t0 = (ninfo_00_t *) buf;
300 	s->first_trk = (byte_t) util_bcdtol(t0->first_trk);
301 	s->last_trk = (byte_t) util_bcdtol(t0->last_trk);
302 
303 	/* Get the starting position of each track */
304 	for (i = 0, j = (int) s->first_trk; j <= (int) s->last_trk; i++, j++) {
305 		(void) memset(buf, 0, sizeof(buf));
306 
307 		SCSICDB_RESET(cdb);
308 		cdb[0] = OP_VN_RDTOC;
309 		cdb[1] = 0x02;
310 		cdb[2] = (byte_t) util_ltobcd(j);
311 
312 		if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10, buf, SZ_VN_RDTOC,
313 				NULL, 0, OP_DATAIN, 5, TRUE))
314 			return FALSE;
315 
316 		DBGDUMP(DBG_DEVIO)("nec: Read TOC data bytes",
317 			buf, SZ_VN_RDTOC);
318 
319 		t2 = (ninfo_02_t *) buf;
320 
321 		s->trkinfo[i].trkno = j;
322 		s->trkinfo[i].min = (byte_t) util_bcdtol(t2->min);
323 		s->trkinfo[i].sec = (byte_t) util_bcdtol(t2->sec);
324 		s->trkinfo[i].frame = (byte_t) util_bcdtol(t2->frame);
325 		util_msftoblk(
326 			s->trkinfo[i].min,
327 			s->trkinfo[i].sec,
328 			s->trkinfo[i].frame,
329 			&s->trkinfo[i].addr,
330 			MSF_OFFSET
331 		);
332 	}
333 	s->tot_trks = (byte_t) i;
334 
335 	(void) memset(buf, 0, sizeof(buf));
336 
337 	/* Get the lead out track position */
338 	SCSICDB_RESET(cdb);
339 	cdb[0] = OP_VN_RDTOC;
340 	cdb[1] = 0x01;
341 
342 	if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10, buf, SZ_VN_RDTOC, NULL, 0,
343 			OP_DATAIN, 5, TRUE))
344 		return FALSE;
345 
346 	DBGDUMP(DBG_DEVIO)("nec: Read TOC data bytes", buf, SZ_VN_RDTOC);
347 
348 	t1 = (ninfo_01_t *) buf;
349 
350 	s->trkinfo[i].trkno = LEAD_OUT_TRACK;
351 	s->discpos_tot.min = s->trkinfo[i].min = (byte_t) util_bcdtol(t1->min);
352 	s->discpos_tot.sec = s->trkinfo[i].sec = (byte_t) util_bcdtol(t1->sec);
353 	s->discpos_tot.frame = s->trkinfo[i].frame =
354 		(byte_t) util_bcdtol(t1->frame);
355 	util_msftoblk(
356 		s->trkinfo[i].min,
357 		s->trkinfo[i].sec,
358 		s->trkinfo[i].frame,
359 		&s->trkinfo[i].addr,
360 		MSF_OFFSET
361 	);
362 	s->discpos_tot.addr = s->trkinfo[i].addr;
363 
364 	return TRUE;
365 }
366 
367 
368 /*
369  * nec_mute
370  *	Send vendor-unique command to mute/unmute the audio
371  *
372  * Args:
373  *	mute - TRUE: mute audio, FALSE: unmute audio
374  *
375  * Return:
376  *	TRUE - success
377  *	FALSE - failure
378  */
379 bool_t
nec_mute(bool_t mute)380 nec_mute(bool_t mute)
381 {
382 	curstat_t	*s = di_clinfo->curstat_addr();
383 
384 	if (nec_audio_muted != mute) {
385 		switch (s->mode) {
386 		case MOD_BUSY:
387 		case MOD_NODISC:
388 		case MOD_STOP:
389 		case MOD_PAUSE:
390 			break;
391 
392 		default:
393 			SCSICDB_RESET(cdb);
394 			cdb[0] = OP_VN_AUDPLAY;
395 			cdb[1] = mute ? 0x00 : 0x03;
396 			cdb[9] = 0xc0;
397 
398 			if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 10,
399 					NULL, 0, NULL, 0, OP_NODATA, 5, TRUE))
400 				return FALSE;
401 			break;
402 		}
403 
404 		nec_audio_muted = mute;
405 	}
406 
407 	return TRUE;
408 }
409 
410 
411 /*
412  * nec_eject
413  *	Send vendor-unique command to eject the caddy
414  *
415  * Args:
416  *	Nothing.
417  *
418  * Return:
419  *	TRUE - success
420  *	FALSE - failure
421  */
422 bool_t
nec_eject(void)423 nec_eject(void)
424 {
425 	SCSICDB_RESET(cdb);
426 	cdb[0] = OP_VN_EJECT;
427 	cdb[1] = 0x01;	/* Set immediate bit */
428 
429 	return (
430 		pthru_send(devp, DI_ROLE_MAIN, cdb, 10,
431 			   NULL, 0, NULL, 0, OP_NODATA, 5, TRUE)
432 	);
433 }
434 
435 
436 /*
437  * nec_init
438  *	Initialize the vendor-unique support module
439  *
440  * Args:
441  *	Nothing.
442  *
443  * Return:
444  *	Nothing.
445  */
446 void
nec_init(void)447 nec_init(void)
448 {
449 	/* Register vendor_unique module entry points */
450 	scsipt_vutbl[VENDOR_NEC].vendor = "NEC";
451 	scsipt_vutbl[VENDOR_NEC].playaudio = nec_playaudio;
452 	scsipt_vutbl[VENDOR_NEC].pause_resume = nec_pause_resume;
453 	scsipt_vutbl[VENDOR_NEC].start_stop = NULL;
454 	scsipt_vutbl[VENDOR_NEC].get_playstatus = nec_get_playstatus;
455 	scsipt_vutbl[VENDOR_NEC].volume = NULL;
456 	scsipt_vutbl[VENDOR_NEC].route = NULL;
457 	scsipt_vutbl[VENDOR_NEC].mute = nec_mute;
458 	scsipt_vutbl[VENDOR_NEC].get_toc = nec_get_toc;
459 	scsipt_vutbl[VENDOR_NEC].eject = nec_eject;
460 	scsipt_vutbl[VENDOR_NEC].start = NULL;
461 	scsipt_vutbl[VENDOR_NEC].halt = NULL;
462 }
463 
464 
465 #endif	/* VENDOR_NEC */
466 
467