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