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  *   Hitachi vendor-unique support
24  *
25  *   The name "Hitachi" is a trademark of Hitachi Corporation, and is
26  *   used here for identification purposes only.
27  */
28 #ifndef lint
29 static char *_vu_hita_c_ident_ = "@(#)vu_hita.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_HITACHI
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		hita_paused,			/* Currently paused */
46 			hita_playing,			/* Currently playing */
47 			hita_audio_muted;		/* Audio is muted */
48 STATIC sword32_t	hita_pause_addr;		/* Pause addr */
49 STATIC msf_t		hita_sav_end;			/* Save addr */
50 
51 
52 /*
53  * Internal functions
54  */
55 
56 /*
57  * hita_do_pause
58  *	Send a vendor-unique Pause command to the drive
59  *
60  * Args:
61  *	ret_addr - Pointer to a buffer where the paused address will be
62  *		   written to.  If NULL, no pause address info will
63  *		   returned.
64  *
65  * Return:
66  *	TRUE - success
67  *	FALSE - failure
68  */
69 STATIC bool_t
hita_do_pause(hmsf_t * ret_addr)70 hita_do_pause(hmsf_t *ret_addr)
71 {
72 	hmsf_t	pause_addr;
73 	bool_t	ret;
74 
75 	SCSICDB_RESET(cdb);
76 	cdb[0] = OP_VH_PAUSE;
77 
78 	if ((ret = pthru_send(devp, DI_ROLE_MAIN, cdb, 12,
79 			      (byte_t *) AD_VH_PAUSE(&pause_addr),
80 			      SZ_VH_PAUSE, NULL, 0,
81 			      OP_DATAIN, 5, TRUE)) == TRUE) {
82 		DBGDUMP(DBG_DEVIO)("hita: Pause address",
83 			(byte_t *) &pause_addr, sizeof(hmsf_t));
84 
85 		if (ret_addr != NULL)
86 			*ret_addr = pause_addr;	/* structure copy */
87 	}
88 	return (ret);
89 }
90 
91 
92 /*
93  * Public functions
94  */
95 
96 /*
97  * hita_playaudio
98  *	Play audio function: send vendor-unique play audio command
99  *	to the drive.
100  *
101  * Args:
102  *	addr_fmt - Flags indicating which address formats are passed in
103  *	If ADDR_BLK, then:
104  *	    start_addr - The logical block starting address
105  *	    end_addr - The logical block ending address
106  *	If ADD_MSF, then:
107  *	    start_msf - Pointer to the starting MSF address structure
108  *	    end_msf - Pointer to the ending MSF address structure
109  *	If ADDR_TRKIDX, then:
110  *	    trk - The starting track number
111  *	    idx - The starting index number
112  *	If ADDR_OPTEND, then the ending address, if specified, can be
113  *	ignored if possible.
114  *
115  * Return:
116  *	TRUE - success
117  *	FALSE - failure
118  */
119 /*ARGSUSED*/
120 bool_t
hita_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)121 hita_playaudio(
122 	byte_t		addr_fmt,
123 	sword32_t	start_addr,
124 	sword32_t	end_addr,
125 	msf_t		*start_msf,
126 	msf_t		*end_msf,
127 	byte_t		trk,
128 	byte_t		idx
129 )
130 {
131 	msf_t		istart_msf,
132 			iend_msf;
133 	bool_t		ret = FALSE;
134 
135 	if (!ret && (addr_fmt & ADDR_BLK) && !(addr_fmt & ADDR_MSF)) {
136 		/* Convert block address to MSF format */
137 		util_blktomsf(
138 			start_addr,
139 			&istart_msf.min, &istart_msf.sec, &istart_msf.frame,
140 			MSF_OFFSET
141 		);
142 
143 		util_blktomsf(
144 			end_addr,
145 			&iend_msf.min, &iend_msf.sec, &iend_msf.frame,
146 			MSF_OFFSET
147 		);
148 
149 		/* Let the ADDR_MSF code handle the request */
150 		start_msf = &istart_msf;
151 		end_msf = &iend_msf;
152 		addr_fmt |= ADDR_MSF;
153 		ret = FALSE;
154 	}
155 
156 	if (!ret && (addr_fmt & ADDR_MSF)) {
157 		hita_sav_end.min = (byte_t) end_msf->min;
158 		hita_sav_end.sec = (byte_t) end_msf->sec;
159 		hita_sav_end.frame = (byte_t) end_msf->frame;
160 
161 		/* Send a pause command to cease any current audio playback,
162 		 * then send the actual play audio command.
163 		 */
164 		if ((ret = hita_do_pause(NULL)) == TRUE) {
165 			SCSICDB_RESET(cdb);
166 			cdb[0] = OP_VH_AUDPLAY;
167 			cdb[1] = hita_audio_muted ? 0x07 : 0x01;
168 			cdb[2] = start_msf->min;
169 			cdb[3] = start_msf->sec;
170 			cdb[4] = start_msf->frame;
171 			cdb[7] = end_msf->min;
172 			cdb[8] = end_msf->sec;
173 			cdb[9] = end_msf->frame;
174 
175 			ret = pthru_send(devp, DI_ROLE_MAIN, cdb, 12,
176 					 NULL, 0, NULL, 0,
177 					 OP_NODATA, 10, TRUE);
178 		}
179 	}
180 
181 	if (ret) {
182 		hita_paused = FALSE;
183 		hita_playing = TRUE;
184 	}
185 
186 	return (ret);
187 }
188 
189 
190 /*
191  * hita_pause_resume
192  *	Pause/resume function: send vendor-unique commands to implement
193  *	the pause and resume capability.
194  *
195  * Args:
196  *	resume - TRUE: resume, FALSE: pause
197  *
198  * Return:
199  *	TRUE - success
200  *	FALSE - failure
201  */
202 bool_t
hita_pause_resume(bool_t resume)203 hita_pause_resume(bool_t resume)
204 {
205 	hmsf_t		*a;
206 	bool_t		ret = FALSE;
207 
208 	a = (hmsf_t *) &hita_pause_addr;
209 
210         if (resume) {
211 		if (!hita_paused)
212 			return TRUE;
213 
214 		SCSICDB_RESET(cdb);
215 		cdb[0] = OP_VH_AUDPLAY;
216 		cdb[1] = hita_audio_muted ? 0x07 : 0x01;
217 		cdb[2] = a->min;
218 		cdb[3] = a->sec;
219 		cdb[4] = a->frame;
220 		cdb[7] = hita_sav_end.min;
221 		cdb[8] = hita_sav_end.sec;
222 		cdb[9] = hita_sav_end.frame;
223 
224 		ret = pthru_send(devp, DI_ROLE_MAIN, cdb, 12, NULL, 0, NULL, 0,
225 				 OP_NODATA, 10, TRUE);
226         }
227         else {
228 		if (hita_paused)
229 			return TRUE;
230 
231 		ret = hita_do_pause(a);
232 	}
233 
234 	if (ret) {
235 		hita_paused = !resume;
236 		hita_playing = !hita_paused;
237 	}
238 
239 	return (ret);
240 }
241 
242 
243 /*
244  * hita_start_stop
245  *	Start/stop function: When playing audio, the Hitachi drive must
246  *	first be paused before sending a Start/Stop Unit command to
247  *	stop it.
248  *
249  * Args:
250  *	start - TRUE: start unit, FALSE: stop unit
251  *	loej - TRUE: eject caddy, FALSE: do not eject
252  *
253  * Return:
254  *	TRUE - success
255  *	FALSE - failure
256  */
257 bool_t
hita_start_stop(bool_t start,bool_t loej)258 hita_start_stop(bool_t start, bool_t loej)
259 {
260 	if (!start && hita_playing && !hita_do_pause(NULL))
261 		return FALSE;
262 
263 	hita_paused = FALSE;
264 
265 	return (scsipt_start_stop(devp, DI_ROLE_MAIN, start, loej, TRUE));
266 }
267 
268 
269 /*
270  * hita_get_playstatus
271  *	Send vendor-unique command to obtain current audio playback
272  *	status.
273  *
274  * Args:
275  *	sp - Pointer to the caller-supplied cdstat_t return structure
276  *
277  * Return:
278  *	TRUE - success
279  *	FALSE - failure
280  */
281 bool_t
hita_get_playstatus(cdstat_t * sp)282 hita_get_playstatus(cdstat_t *sp)
283 {
284 	byte_t		buf[SZ_VH_RDSTAT];
285 	haudstat_t	*d;
286 
287 
288 	(void) memset(buf, 0, sizeof(buf));
289 
290 	SCSICDB_RESET(cdb);
291 	cdb[0] = OP_VH_RDSTAT;
292 
293 	if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 12,
294 			AD_VH_RDSTAT(buf), SZ_VH_RDSTAT,
295 			NULL, 0, OP_DATAIN, 5, TRUE))
296 		return FALSE;
297 
298 	DBGDUMP(DBG_DEVIO)("hita: Read Status data bytes", buf, SZ_VH_RDSTAT);
299 
300 	d = (haudstat_t *)(void *) buf;
301 
302 	sp->track = (int) d->trkno;
303 	sp->index = 1;		/* Fudge */
304 
305 	/* Make up audio status */
306 	if (hita_paused)
307 		sp->status = CDSTAT_PAUSED;
308 	else if (d->playing)
309 		sp->status = CDSTAT_PLAYING;
310 	else {
311 		sp->status = CDSTAT_COMPLETED;
312 		hita_playing = FALSE;
313 	}
314 
315 	sp->abs_addr.min = (byte_t) d->abs_addr.min;
316 	sp->abs_addr.sec = (byte_t) d->abs_addr.sec;
317 	sp->abs_addr.frame = (byte_t) d->abs_addr.frame;
318 	sp->rel_addr.min = (byte_t) d->rel_addr.min;
319 	sp->rel_addr.sec = (byte_t) d->rel_addr.sec;
320 	sp->rel_addr.frame = (byte_t) d->rel_addr.frame;
321 	util_msftoblk(
322 		sp->abs_addr.min, sp->abs_addr.sec, sp->abs_addr.frame,
323 		&sp->abs_addr.addr, MSF_OFFSET
324 	);
325 	util_msftoblk(
326 		sp->rel_addr.min, sp->rel_addr.sec, sp->rel_addr.frame,
327 		&sp->rel_addr.addr, 0
328 	);
329 
330 	return TRUE;
331 }
332 
333 
334 /*
335  * hita_get_toc
336  *	Send vendor-unique command to obtain the disc table-of-contents
337  *
338  * Args:
339  *	s - Pointer to the curstat_t structure, which contains the TOC
340  *	    table to be updated.
341  *
342  * Return:
343  *	TRUE - success
344  *	FALSE - failure
345  */
346 bool_t
hita_get_toc(curstat_t * s)347 hita_get_toc(curstat_t *s)
348 {
349 	int		i,
350 			j;
351 	size_t		xfer_len;
352 	byte_t		buf[SZ_VH_RDXINFO];
353 	hxdiscinfo_t	*p;
354 	hxmsf_t		*a;
355 
356 
357 	if (hita_playing)
358 		return FALSE;	/* Drive is busy */
359 
360 	(void) memset(buf, 0, sizeof(buf));
361 
362 	/* Read the TOC header first */
363 	SCSICDB_RESET(cdb);
364 	cdb[0] = OP_VH_RDXINFO;
365 	cdb[10] = SZ_VH_XTOCHDR;
366 
367 	if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 12,
368 			AD_VH_RDXINFO(buf), SZ_VH_XTOCHDR,
369 			NULL, 0, OP_DATAIN, 5, TRUE))
370 		return FALSE;
371 
372 	p = (hxdiscinfo_t *)(void *) buf;
373 
374 	s->first_trk = (byte_t) p->first_trk;
375 	s->last_trk = (byte_t) p->last_trk;
376 
377 	xfer_len = SZ_VH_XTOCHDR +
378 		   ((int) (p->last_trk - p->first_trk + 2) * SZ_VH_XTOCENT);
379 
380 	if (xfer_len > SZ_VH_RDXINFO)
381 		xfer_len = SZ_VH_RDXINFO;
382 
383 	/* Read the appropriate number of bytes of the entire TOC */
384 	SCSICDB_RESET(cdb);
385 	cdb[0] = OP_VH_RDXINFO;
386 	cdb[9] = (xfer_len & 0xff00) >> 8;
387 	cdb[10] = xfer_len & 0x00ff;
388 
389 	if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 12,
390 			AD_VH_RDXINFO(buf), xfer_len,
391 			NULL, 0, OP_DATAIN, 5, TRUE))
392 		return FALSE;
393 
394 	DBGDUMP(DBG_DEVIO)("hita: Read Extended Disc Info data bytes",
395 		buf, xfer_len);
396 
397 	/* Get the starting position of each track */
398 	for (i = 0, j = (int) s->first_trk; j <= (int) s->last_trk; i++, j++) {
399 		a = (hxmsf_t *)(void *) &p->xmsfdata[(i+1) * SZ_VH_XTOCENT];
400 		s->trkinfo[i].trkno = j;
401 		s->trkinfo[i].min = (byte_t) a->min;
402 		s->trkinfo[i].sec = (byte_t) a->sec;
403 		s->trkinfo[i].frame = (byte_t) a->frame;
404 		util_msftoblk(
405 			s->trkinfo[i].min,
406 			s->trkinfo[i].sec,
407 			s->trkinfo[i].frame,
408 			&s->trkinfo[i].addr,
409 			MSF_OFFSET
410 		);
411 		s->trkinfo[i].type = (a->trktype == 0) ? TYP_AUDIO : TYP_DATA;
412 	}
413 	s->tot_trks = (byte_t) i;
414 
415 	/* Get the lead-out track position */
416 	a = (hxmsf_t *)(void *) &p->xmsfdata[0];
417 	s->trkinfo[i].trkno = LEAD_OUT_TRACK;
418 	s->discpos_tot.min = s->trkinfo[i].min = (byte_t) a->min;
419 	s->discpos_tot.sec = s->trkinfo[i].sec = (byte_t) a->sec;
420 	s->discpos_tot.frame = s->trkinfo[i].frame = (byte_t) a->frame;
421 	util_msftoblk(
422 		s->trkinfo[i].min,
423 		s->trkinfo[i].sec,
424 		s->trkinfo[i].frame,
425 		&s->trkinfo[i].addr,
426 		MSF_OFFSET
427 	);
428 	s->discpos_tot.addr = s->trkinfo[i].addr;
429 
430 	return TRUE;
431 }
432 
433 
434 /*
435  * hita_mute
436  *	Send vendor-unique command to mute/unmute the audio
437  *
438  * Args:
439  *	mute - TRUE: mute audio, FALSE: un-mute audio
440  *
441  * Return:
442  *	TRUE - success
443  *	FALSE - failure
444  */
445 bool_t
hita_mute(bool_t mute)446 hita_mute(bool_t mute)
447 {
448 	curstat_t	*s = di_clinfo->curstat_addr();
449 
450 	if (mute == hita_audio_muted)
451 		return TRUE;
452 
453 	if (hita_playing) {
454 		/* Pause the playback first */
455         	if (!hita_do_pause(NULL))
456 			return FALSE;
457 
458 		SCSICDB_RESET(cdb);
459 		cdb[0] = OP_VH_AUDPLAY;
460 		cdb[1] = mute ? 0x07 : 0x01;
461 		cdb[2] = s->curpos_tot.min;
462 		cdb[3] = s->curpos_tot.sec;
463 		cdb[4] = s->curpos_tot.frame;
464 		cdb[7] = hita_sav_end.min;
465 		cdb[8] = hita_sav_end.sec;
466 		cdb[9] = hita_sav_end.frame;
467 
468 		if (!pthru_send(devp, DI_ROLE_MAIN, cdb, 12, NULL, 0, NULL, 0,
469 				OP_NODATA, 10, TRUE))
470 			return FALSE;
471 	}
472 
473 	hita_audio_muted = mute;
474 
475 	return TRUE;
476 }
477 
478 
479 /*
480  * hita_eject
481  *	Send vendor-unique command to eject the caddy
482  *
483  * Args:
484  *	Nothing.
485  *
486  * Return:
487  *	TRUE - success
488  *	FALSE - failure
489  */
490 bool_t
hita_eject(void)491 hita_eject(void)
492 {
493 	/* If audio playback is in progress, pause the playback first */
494 	if (hita_playing && !hita_do_pause(NULL))
495 		return FALSE;
496 
497 	hita_playing = hita_paused = FALSE;
498 
499 	/* Eject the caddy */
500 	SCSICDB_RESET(cdb);
501 	cdb[0] = OP_VH_EJECT;
502 	cdb[10] = 0x01;
503 	return (
504 		pthru_send(devp, DI_ROLE_MAIN, cdb, 12,
505 			   NULL, 0, NULL, 0, OP_NODATA, 20, TRUE)
506 	);
507 }
508 
509 
510 /*
511  * hita_init
512  *	Initialize the vendor-unique support module
513  *
514  * Args:
515  *	Nothing.
516  *
517  * Return:
518  *	Nothing.
519  */
520 void
hita_init(void)521 hita_init(void)
522 {
523 	/* Register vendor_unique module entry points */
524 	scsipt_vutbl[VENDOR_HITACHI].vendor = "Hitachi";
525 	scsipt_vutbl[VENDOR_HITACHI].playaudio = hita_playaudio;
526 	scsipt_vutbl[VENDOR_HITACHI].pause_resume = hita_pause_resume;
527 	scsipt_vutbl[VENDOR_HITACHI].start_stop = hita_start_stop;
528 	scsipt_vutbl[VENDOR_HITACHI].get_playstatus = hita_get_playstatus;
529 	scsipt_vutbl[VENDOR_HITACHI].volume = NULL;
530 	scsipt_vutbl[VENDOR_HITACHI].route = NULL;
531 	scsipt_vutbl[VENDOR_HITACHI].mute = hita_mute;
532 	scsipt_vutbl[VENDOR_HITACHI].get_toc = hita_get_toc;
533 	scsipt_vutbl[VENDOR_HITACHI].eject = hita_eject;
534 	scsipt_vutbl[VENDOR_HITACHI].start = NULL;
535 	scsipt_vutbl[VENDOR_HITACHI].halt = NULL;
536 }
537 
538 
539 #endif	/* VENDOR_HITACHI */
540 
541