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