FreeBSD/Linux Kernel Cross Reference
sys/scsi/rz_audio.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: rz_audio.c,v $
29 * Revision 2.7 93/08/03 12:33:55 mrt
30 * Return the device back to the default data-mode at close.
31 * Otherwise things get messy when we change CDs.
32 * MOved zero_ior() elsewhere.
33 * [93/07/29 23:33:56 af]
34 *
35 * Added Toshiba drives.
36 * [93/04/13 22:48:05 af]
37 *
38 * Revision 2.6 93/05/15 19:42:03 mrt
39 * machparam.h -> machspl.h
40 *
41 * Revision 2.5 93/05/10 21:22:22 rvb
42 * Added Toshiba drives.
43 * [93/04/13 22:48:05 af]
44 *
45 * Revision 2.4 93/03/26 18:03:33 mrt
46 * Tested NEC driver. Tested Sony driver.
47 * [93/03/22 af]
48 *
49 * Rewritten a lot. Do not even try (some) SCSI-2 commands on those
50 * drivers that aren't even SCSI-1 compliant. Use instead a list of
51 * vendor-specific work-arounds.
52 * [93/03/22 af]
53 *
54 * Functionality is now complete for RRD42.
55 * [93/03/17 af]
56 *
57 * Revision 2.3 93/03/11 14:08:33 danner
58 * Forward decl. Replaced gimmeabreak with panic.
59 *
60 * Revision 2.2 93/03/09 12:26:46 danner
61 * Created.
62 * [93/03/09 af]
63 *
64 */
65 /*
66 * File: rz_audio.c
67 * Author: Alessandro Forin, Carnegie Mellon University
68 * Date: 3/93
69 *
70 * Top layer of the SCSI driver: interface with the MI.
71 * This file contains operations specific to audio CD-ROM devices.
72 * Unlike many others, it sits on top of the rz.c module.
73 */
74
75 #include <mach/std_types.h>
76 #include <kern/strings.h>
77 #include <machine/machspl.h> /* spl definitions */
78 #include <vm/vm_kern.h>
79 #include <device/ds_routines.h>
80
81 #include <scsi/compat_30.h>
82 #include <scsi/scsi.h>
83 #include <scsi/scsi2.h>
84 #include <scsi/scsi_defs.h>
85 #include <scsi/rz.h>
86
87 #define private static
88
89 /* some data is two BCD digits in one byte */
90 #define bcd_to_decimal(b) (((b)&0xf) + 10 * (((b) >> 4) & 0xf))
91 #define decimal_to_bcd(b) ((((b) / 10) << 4) | ((b) % 10))
92
93 /*
94 * Regular use of a CD-ROM is for data, and is handled
95 * by the default set of operations. Ours is for funtime..
96 */
97
98 extern char *sccdrom_name();
99 int cd_strategy();
100 void cd_start();
101
102 private scsi_devsw_t scsi_audio = {
103 sccdrom_name, 0, 0, 0, cd_strategy, cd_start, 0, 0
104 };
105
106 private char unsupported[] = "Device does not support it.";
107
108 /*
109 * Unfortunately, none of the vendors appear to
110 * abide by the SCSI-2 standard and many of them
111 * violate or stretch even the SCSI-1 one.
112 * Therefore, we keep a red-list here of the worse
113 * offendors and how to deal with them.
114 * The user is notified of the problem and invited
115 * to solicit his vendor to upgrade the firmware.
116 * [They had plenty of time to do so]
117 */
118 typedef struct red_list {
119 char *vendor;
120 char *product;
121 char *rev;
122 /*
123 * The standard MANDATES [par 13.1.6] the play_audio command
124 * at least as a way to discover if the device
125 * supports audio operations at all. This is the only way
126 * we need to use it.
127 */
128 scsi_ret_t (*can_play_audio)( target_info_t *, char *, io_req_t);
129 /*
130 * The standard defines the use of start_stop_unit to
131 * cause the drive to eject the disk.
132 */
133 scsi_ret_t (*eject)( target_info_t *, char *, io_req_t );
134 /*
135 * The standard defines read_subchannel as a way to
136 * get the current playing position.
137 */
138 scsi_ret_t (*current_position)( target_info_t *, char *, io_req_t );
139 /*
140 * The standard defines read_table_of_content to get
141 * the listing of audio tracks available.
142 */
143 scsi_ret_t (*read_toc)( target_info_t *, char *, io_req_t );
144 /*
145 * The standard defines read_subchannel as the way to
146 * report the current audio status (playing/stopped/...).
147 */
148 scsi_ret_t (*get_status)( target_info_t *, char *, io_req_t );
149 /*
150 * The standard defines two ways to issue a play command,
151 * depending on the type of addressing used.
152 */
153 scsi_ret_t (*play_msf)( target_info_t *, char *, io_req_t );
154 scsi_ret_t (*play_ti)( target_info_t *, char *, io_req_t );
155 /*
156 * The standard defines the pause_resume command to
157 * suspend or resume playback of audio data.
158 */
159 scsi_ret_t (*pause_resume)( target_info_t *, char *, io_req_t );
160 /*
161 * The standard defines the audio page among the
162 * mode selection options as a way to control
163 * both volume and connectivity of the channels
164 */
165 scsi_ret_t (*volume_control)( target_info_t *, char *, io_req_t );
166 } red_list_t;
167
168 #define if_it_can_do(some_cmd) \
169 if (tgt->dev_info.cdrom.violates_standards && \
170 tgt->dev_info.cdrom.violates_standards->some_cmd) \
171 rc = (*tgt->dev_info.cdrom.violates_standards->some_cmd) \
172 (tgt,cmd,ior); \
173 else
174
175 /*
176 * So now that you know what they should have implemented :-),
177 * check at the end of the file what the naughty boys did instead.
178 */
179 /* private red_list_t audio_replacements[]; / * at end */
180
181 /*
182 * Forward decls
183 */
184 private void decode_status( char *buf, unsigned char audio_status );
185 void zero_ior( io_req_t );
186
187 /*
188 * Open routine. Does some checking, sets up
189 * the replacement pointer.
190 */
191 io_return_t
192 cd_open(
193 int dev,
194 dev_mode_t mode,
195 io_req_t req)
196 {
197 scsi_softc_t *sc = 0;
198 target_info_t *tgt;
199 int ret;
200 scsi_ret_t rc;
201 io_req_t ior = 0;
202 vm_offset_t mem = 0;
203 extern boolean_t rz_check();
204
205 if (!rz_check(dev, &sc, &tgt)) {
206 /*
207 * Probe it again: might have installed a new device
208 */
209 if (!sc || !scsi_probe(sc, &tgt, rzslave(dev), ior))
210 return D_NO_SUCH_DEVICE;
211 bzero(&tgt->dev_info, sizeof(tgt->dev_info));
212 }
213
214 /*
215 * Check this is indeded a CD-ROM
216 */
217 if (tgt->dev_ops != &scsi_devsw[SCSI_CDROM]) {
218 rz_close(dev);
219 return D_NO_SUCH_DEVICE;
220 }
221
222 /*
223 * Switch to audio ops, unless some wrong
224 */
225 tgt->dev_ops = &scsi_audio;
226
227 /*
228 * Bring unit online
229 */
230 ret = rz_open(dev, mode, req);
231 if (ret) goto bad;
232
233 /* Pessimistic */
234 ret = D_INVALID_OPERATION;
235
236 /*
237 * Check if this device is on the red list
238 */
239 {
240 scsi2_inquiry_data_t *inq;
241 private void check_red_list();
242
243 scsi_inquiry(tgt, SCSI_INQ_STD_DATA);
244 inq = (scsi2_inquiry_data_t*)tgt->cmd_ptr;
245
246 check_red_list( tgt, inq );
247
248 }
249
250 /*
251 * Allocate dynamic data
252 */
253 if (kmem_alloc(kernel_map, &mem, PAGE_SIZE) != KERN_SUCCESS)
254 return D_NO_MEMORY;
255 tgt->dev_info.cdrom.result = (void *)mem;
256 tgt->dev_info.cdrom.result_available = FALSE;
257
258 /*
259 * See if this CDROM can play audio data
260 */
261 io_req_alloc(ior,0);
262 zero_ior( ior );
263
264 {
265 char *cmd = 0;
266 if_it_can_do(can_play_audio)
267 rc = scsi_play_audio( tgt, 0, 0, FALSE, ior);
268 }
269
270 if (rc != SCSI_RET_SUCCESS) goto bad;
271
272 io_req_free(ior);
273 return D_SUCCESS;
274
275 bad:
276 if (ior) io_req_free(ior);
277 if (mem) kmem_free(kernel_map, mem, PAGE_SIZE);
278 tgt->dev_ops = &scsi_devsw[SCSI_CDROM];
279 return ret;
280 }
281
282 /*
283 * Close routine.
284 */
285 io_return_t
286 cd_close(
287 int dev)
288 {
289 scsi_softc_t *sc;
290 target_info_t *tgt;
291 vm_offset_t mem;
292
293 if (!rz_check(dev, &sc, &tgt))
294 return D_NO_SUCH_DEVICE;
295 if (!tgt || (tgt->dev_ops != &scsi_audio))
296 return D_NO_SUCH_DEVICE;
297
298 /*
299 * Cleanup state
300 */
301 mem = (vm_offset_t) tgt->dev_info.cdrom.result;
302 tgt->dev_info.cdrom.result = (void *)0;
303 tgt->dev_info.cdrom.result_available = FALSE;
304
305 (void) kmem_free(kernel_map, mem, PAGE_SIZE);
306
307 (void) rz_close(dev);
308
309 tgt->dev_ops = &scsi_devsw[SCSI_CDROM];
310 return D_SUCCESS;
311 }
312
313 /*
314 * Write routine. It is passed an ASCII string
315 * with the command to be executed.
316 */
317 io_return_t
318 cd_write(
319 int dev,
320 io_req_t ior)
321 {
322 register kern_return_t rc;
323 boolean_t wait = FALSE;
324 io_return_t ret;
325 int count;
326 register char *data;
327 vm_offset_t addr;
328
329 data = ior->io_data;
330 count = ior->io_count;
331 if (count == 0)
332 return D_SUCCESS;
333
334 if (!(ior->io_op & IO_INBAND)) {
335 /*
336 * Copy out-of-line data into kernel address space.
337 * Since data is copied as page list, it will be
338 * accessible.
339 */
340 vm_map_copy_t copy = (vm_map_copy_t) data;
341 kern_return_t kr;
342
343 kr = vm_map_copyout(device_io_map, &addr, copy);
344 if (kr != KERN_SUCCESS)
345 return kr;
346 data = (char *) addr;
347 }
348
349 if (scsi_debug) printf("Got command '%s'\n", data);
350
351 ret = cd_command( dev, data, count, ior);
352
353 if (!(ior->io_op & IO_INBAND))
354 (void) vm_deallocate(device_io_map, addr, ior->io_count);
355 return D_SUCCESS;
356 }
357
358 /*
359 * Read routine. Returns an ASCII string with the results
360 * of the last command executed.
361 */
362 io_return_t
363 cd_read(
364 int dev,
365 io_req_t ior)
366 {
367 target_info_t *tgt;
368 kern_return_t rc;
369 natural_t count;
370
371 /*
372 * Allocate memory for read buffer.
373 */
374 count = (natural_t)ior->io_count;
375 if (count > PAGE_SIZE)
376 return D_INVALID_SIZE; /* sanity */
377
378 rc = device_read_alloc(ior, count);
379 if (rc != KERN_SUCCESS)
380 return rc;
381
382 if (scsi_debug) printf("Got read req for %d bytes\n", count);
383
384 /*
385 * See if last cmd left some to say
386 */
387 tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)];
388 if (tgt->dev_info.cdrom.result_available) {
389 int len;
390
391 tgt->dev_info.cdrom.result_available = FALSE;
392 len = strlen(tgt->dev_info.cdrom.result)+1;
393
394 if (count > len)
395 count = len;
396 bcopy(tgt->dev_info.cdrom.result, ior->io_data, count);
397
398 } else {
399 # define noway "No results pending"
400 count = (count > sizeof(noway)) ? sizeof(noway) : count;
401 bcopy(noway, ior->io_data, count);
402 }
403
404 ior->io_residual = ior->io_count - count;
405 return D_SUCCESS;
406 }
407
408 /*
409 * This does all the work
410 */
411 io_return_t
412 cd_command(
413 int dev,
414 char *cmd,
415 int count,
416 io_req_t req)
417 {
418 target_info_t *tgt;
419 io_req_t ior;
420 io_return_t ret = D_INVALID_OPERATION;
421 scsi_ret_t rc;
422 char *buf;
423
424 tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)];
425
426 buf = tgt->dev_info.cdrom.result;
427 tgt->dev_info.cdrom.result_available = FALSE;
428
429 io_req_alloc(ior,0);
430 zero_ior( ior );
431
432 switch (cmd[0]) {
433
434 case 'E':
435 /* "Eject" */
436 /* too many dont support it. Sigh */
437 tgt->flags |= TGT_OPTIONAL_CMD;
438 (void) scsi_medium_removal( tgt, TRUE, ior);
439 tgt->flags &= ~TGT_OPTIONAL_CMD;
440
441 zero_ior( ior );
442
443 if_it_can_do(eject)
444 rc = scsi_start_unit(tgt, SCSI_CMD_SS_EJECT, ior);
445 break;
446
447 case 'G':
448 switch (cmd[4]) {
449
450 case 'P':
451 /* "Get Position MSF|ABS" */
452 if_it_can_do(current_position) {
453 rc = scsi_read_subchannel(tgt,
454 cmd[13] == 'M',
455 SCSI_CMD_RS_FMT_CURPOS,
456 0,
457 ior);
458 if (rc == SCSI_RET_SUCCESS) {
459 cdrom_chan_curpos_t *st;
460 st = (cdrom_chan_curpos_t *)tgt->cmd_ptr;
461 if (cmd[13] == 'M')
462 sprintf(buf, "MSF Position %d %d %d %d %d %d",
463 (integer_t)st->subQ.absolute_address.msf.minute,
464 (integer_t)st->subQ.absolute_address.msf.second,
465 (integer_t)st->subQ.absolute_address.msf.frame,
466 (integer_t)st->subQ.relative_address.msf.minute,
467 (integer_t)st->subQ.relative_address.msf.second,
468 (integer_t)st->subQ.relative_address.msf.frame);
469 else
470 sprintf(buf, "ABS Position %d %d", (integer_t)
471 (st->subQ.absolute_address.lba.lba1<<24)+
472 (st->subQ.absolute_address.lba.lba2<<16)+
473 (st->subQ.absolute_address.lba.lba3<< 8)+
474 st->subQ.absolute_address.lba.lba4,
475 (integer_t)
476 (st->subQ.relative_address.lba.lba1<<24)+
477 (st->subQ.relative_address.lba.lba2<<16)+
478 (st->subQ.relative_address.lba.lba3<< 8)+
479 st->subQ.relative_address.lba.lba4);
480 tgt->dev_info.cdrom.result_available = TRUE;
481 }
482 }
483 break;
484
485 case 'T':
486 /* "Get TH" */
487 if_it_can_do(read_toc) {
488 rc = scsi_read_toc(tgt, TRUE, 1, PAGE_SIZE, ior);
489 if (rc == SCSI_RET_SUCCESS) {
490 cdrom_toc_t *toc = (cdrom_toc_t *)tgt->cmd_ptr;
491 sprintf(buf, "toc header: %d %d %d",
492 (toc->len1 << 8) + toc->len2,
493 toc->first_track,
494 toc->last_track);
495 tgt->dev_info.cdrom.result_available = TRUE;
496 }
497 }
498 break;
499
500 case 'S':
501 /* "Get Status" */
502 if_it_can_do(get_status) {
503 rc = scsi_read_subchannel(tgt,
504 TRUE,
505 SCSI_CMD_RS_FMT_CURPOS,
506 0,
507 ior);
508 if (rc == SCSI_RET_SUCCESS) {
509 cdrom_chan_curpos_t *st;
510 st = (cdrom_chan_curpos_t *)tgt->cmd_ptr;
511 decode_status(buf, st->audio_status);
512 tgt->dev_info.cdrom.result_available = TRUE;
513 }
514 }
515 break;
516 }
517 break;
518
519 case 'P':
520 switch (cmd[5]) {
521 case 'A':
522 /* "Play A startM startS startF endM endS endF" */
523 if_it_can_do(play_msf) {
524
525 int sm, ss, sf, em, es, ef;
526
527 sscanf(&cmd[7], "%d %d %d %d %d %d",
528 &sm, &ss, &sf, &em, &es, &ef);
529
530 rc = scsi_play_audio_msf(tgt,
531 sm, ss, sf,
532 em, es, ef,
533 ior);
534 }
535 break;
536
537 case 'T':
538 /* "Play TI startT startI endT endI" */
539 if_it_can_do(play_ti) {
540
541 int st, si, et, ei;
542
543 sscanf(&cmd[8], "%d %d %d %d",
544 &st, &si, &et, &ei);
545
546 rc = scsi_play_audio_track_index(tgt,
547 st, si, et, ei, ior);
548 }
549 break;
550 }
551 break;
552
553 case 'R':
554 /* "Resume" */
555 if_it_can_do(pause_resume)
556 rc = scsi_pause_resume(tgt, FALSE, ior);
557 break;
558
559 case 'S':
560 switch (cmd[2]) {
561
562 case 'a':
563 /* "Start" */
564 rc = scsi_start_unit(tgt, SCSI_CMD_SS_START, ior);
565 break;
566
567 case 'o':
568 /* "Stop" */
569 if_it_can_do(pause_resume)
570 rc = scsi_pause_resume(tgt, TRUE, ior);
571 break;
572
573 case 't':
574 /* "Set V chan0vol chan1vol chan2vol chan3vol" */
575 if_it_can_do(volume_control) {
576
577 int v0, v1, v2, v3;
578 cdrom_audio_page_t au, *aup;
579
580 rc = scsi_mode_sense(tgt,
581 SCSI_CD_AUDIO_PAGE,
582 sizeof(au),
583 ior);
584 if (rc == SCSI_RET_SUCCESS) {
585
586 sscanf(&cmd[6], "%d %d %d %d",
587 &v0, &v1, &v2, &v3);
588
589 aup = (cdrom_audio_page_t *) tgt->cmd_ptr;
590 au = *aup;
591 /* au.h.bdesc ... */
592 au.vol0 = v0;
593 au.vol1 = v1;
594 au.vol2 = v2;
595 au.vol3 = v3;
596 au.imm = 1;
597 au.aprv = 0;
598
599 zero_ior( ior );
600
601 rc = scsi2_mode_select(tgt, FALSE,
602 &au, sizeof(au), ior);
603 }
604 }
605 break;
606 }
607 break;
608
609 case 'T':
610 /* "Toc MSF|ABS trackno" */
611 if_it_can_do(read_toc) {
612
613 int t, m;
614
615 sscanf(&cmd[8], "%d", &t);
616 rc = scsi_read_toc( tgt, cmd[4]=='M', t, PAGE_SIZE, ior);
617
618 if (rc == SCSI_RET_SUCCESS) {
619
620 cdrom_toc_t *toc = (cdrom_toc_t *)tgt->cmd_ptr;
621
622 sprintf(buf, "TOC from track %d:\n", t);
623 m = (toc->len1 << 8) + toc->len2;
624 m -= 4; /* header */
625 for (t = 0; m > 0; t++, m -= sizeof(struct cdrom_toc_desc)) {
626 buf += strlen(buf);
627 if (cmd[4] == 'M')
628 sprintf(buf, "%d %d %d %d %d %d\n",
629 toc->descs[t].control,
630 toc->descs[t].adr,
631 toc->descs[t].trackno,
632 (integer_t)toc->descs[t].absolute_address.msf.minute,
633 (integer_t)toc->descs[t].absolute_address.msf.second,
634 (integer_t)toc->descs[t].absolute_address.msf.frame);
635 else
636 sprintf(buf, "%d %d %d %d\n",
637 toc->descs[t].control,
638 toc->descs[t].adr,
639 toc->descs[t].trackno,
640 (toc->descs[t].absolute_address.lba.lba1<<24)+
641 (toc->descs[t].absolute_address.lba.lba2<<16)+
642 (toc->descs[t].absolute_address.lba.lba3<<8)+
643 toc->descs[t].absolute_address.lba.lba4);
644 }
645 tgt->dev_info.cdrom.result_available = TRUE;
646 }
647 }
648 break;
649 }
650
651 if (rc == SCSI_RET_SUCCESS)
652 ret = D_SUCCESS;
653
654 /* We are stateless, but.. */
655 if (rc == SCSI_RET_NEED_SENSE) {
656 zero_ior( ior );
657 tgt->ior = ior;
658 scsi_request_sense(tgt, ior, 0);
659 iowait(ior);
660 if (scsi_check_sense_data(tgt, tgt->cmd_ptr))
661 scsi_print_sense_data(tgt->cmd_ptr);
662 }
663
664 io_req_free(ior);
665 return ret;
666 }
667
668 private char st_invalid [] = "Drive would not say";
669 private char st_playing [] = "Playing";
670 private char st_paused [] = "Suspended";
671 private char st_complete[] = "Done playing";
672 private char st_error [] = "Stopped in error";
673 private char st_nothing [] = "Idle";
674
675 private void
676 decode_status(
677 char *buf,
678 unsigned char audio_status)
679 {
680 switch (audio_status) {
681 case SCSI_CDST_INVALID:
682 sprintf(buf, st_invalid); break;
683 case SCSI_CDST_PLAYING:
684 sprintf(buf, st_playing); break;
685 case SCSI_CDST_PAUSED:
686 sprintf(buf, st_paused); break;
687 case SCSI_CDST_COMPLETED:
688 sprintf(buf, st_complete); break;
689 case SCSI_CDST_ERROR:
690 sprintf(buf, st_error); break;
691 case SCSI_CDST_NO_STATUS:
692 sprintf(buf, st_nothing); break;
693 }
694 }
695
696 /* some vendor specific use this instead */
697 private void
698 decode_status_1(
699 char *buf,
700 unsigned char audio_status)
701 {
702 switch (audio_status) {
703 case 0: sprintf(buf, st_playing ); break;
704 case 1:
705 case 2: sprintf(buf, st_paused ); break;
706 case 3: sprintf(buf, st_complete ); break;
707 default:
708 sprintf(buf, "Unknown status" ); break;
709 }
710 }
711
712
713 private void
714 curse_the_vendor(
715 red_list_t *list,
716 boolean_t not_really)
717 {
718 if (not_really) return;
719
720 printf("%s\n%s\n%s\n%s\n",
721 "The CDROM you use is not fully SCSI-2 compliant.",
722 "We invite You to contact Your vendor and ask",
723 "that they provide You with a firmware upgrade.",
724 "Here is a list of some known deficiencies");
725
726 printf("Vendor: %s Product: %s.. Revision: %s..\n",
727 list->vendor, list->product, list->rev);
728
729 #define check(x,y,z) \
730 if (list->x) printf("Command code x%x %s not supported\n", y, z);
731
732 check(can_play_audio, SCSI_CMD_PLAY_AUDIO, "PLAY_AUDIO");
733 check(eject, SCSI_CMD_START_STOP_UNIT,
734 "START_STOP_UNIT, flag EJECT(0x2) in byte 5");
735 check(current_position, SCSI_CMD_READ_SUBCH, "READ_SUBCHANNEL");
736 check(read_toc, SCSI_CMD_READ_TOC, "READ_TOC");
737 /* check(get_status, ...); duplicate of current_position */
738 check(play_msf, SCSI_CMD_PLAY_AUDIO_MSF, "PLAY_AUDIO_MSF");
739 check(play_ti, SCSI_CMD_PLAY_AUDIO_TI, "PLAY_AUDIO_TRACK_INDEX");
740 check(pause_resume, SCSI_CMD_PAUSE_RESUME, "PAUSE_RESUME");
741 check(volume_control, SCSI_CMD_MODE_SELECT,
742 "MODE_SELECT, AUDIO page(0xe)");
743
744 #undef check
745 printf("Will work around these problems...\n");
746 }
747
748 /*
749 * Ancillaries
750 */
751 cd_strategy(ior)
752 register io_req_t ior;
753 {
754 return rz_simpleq_strategy( ior, cd_start);
755 }
756
757 void cd_start( tgt, done)
758 target_info_t *tgt;
759 boolean_t done;
760 {
761 io_req_t ior;
762
763 ior = tgt->ior;
764 if (done && ior) {
765 tgt->ior = 0;
766 iodone(ior);
767 return;
768 }
769 panic("cd start"); /* uhu? */
770 }
771
772 /*
773 * When the hardware cannot
774 */
775 private scsi_ret_t
776 op_not_supported(
777 target_info_t *tgt,
778 char *cmd,
779 io_req_t ior)
780 {
781 /*
782 * The command is not implemented, no way around it
783 */
784 sprintf(tgt->dev_info.cdrom.result, unsupported);
785 tgt->dev_info.cdrom.result_available = TRUE;
786 return SCSI_RET_SUCCESS;
787 }
788
789 /****************************************/
790 /* Vendor Specific Operations */
791 /****************************************/
792
793 /* DEC RRD42 */
794
795 #define SCSI_CMD_DEC_SET_ADDRESS_FORMAT 0xc0
796 # define scsi_cmd_saf_fmt scsi_cmd_xfer_len_2
797
798 #define SCSI_CMD_DEC_PLAYBACK_STATUS 0xc4
799 typedef struct {
800 unsigned char xxx;
801 BITFIELD_2(unsigned char,
802 is_msf: 1,
803 xxx1: 7);
804 unsigned char data_len1;
805 unsigned char data_len0;
806 unsigned char audio_status;
807 BITFIELD_2(unsigned char,
808 control : 4,
809 xxx2 : 4);
810 cdrom_addr_t address;
811 BITFIELD_2(unsigned char,
812 chan0_select : 4,
813 xxx3 : 4);
814 unsigned char chan0_volume;
815 BITFIELD_2(unsigned char,
816 chan1_select : 4,
817 xxx4 : 4);
818 unsigned char chan1_volume;
819 BITFIELD_2(unsigned char,
820 chan2_select : 4,
821 xxx5 : 4);
822 unsigned char chan2_volume;
823 BITFIELD_2(unsigned char,
824 chan3_select : 4,
825 xxx6 : 4);
826 unsigned char chan3_volume;
827 } dec_playback_status_t;
828
829 #define SCSI_CMD_DEC_PLAYBACK_CONTROL 0xc9
830 typedef struct {
831 unsigned char xxx0;
832 BITFIELD_2(unsigned char,
833 fmt : 1,
834 xxx1 : 7);
835 unsigned char xxx[8];
836 BITFIELD_2(unsigned char,
837 chan0_select : 4,
838 xxx3 : 4);
839 unsigned char chan0_volume;
840 BITFIELD_2(unsigned char,
841 chan1_select : 4,
842 xxx4 : 4);
843 unsigned char chan1_volume;
844 BITFIELD_2(unsigned char,
845 chan2_select : 4,
846 xxx5 : 4);
847 unsigned char chan2_volume;
848 BITFIELD_2(unsigned char,
849 chan3_select : 4,
850 xxx6 : 4);
851 unsigned char chan3_volume;
852 } dec_playback_control_t;
853
854
855 #if 0
856
857 private scsi_ret_t
858 rrd42_status(
859 target_info_t *tgt,
860 char *cmd,
861 io_req_t ior)
862 {
863 scsi_ret_t rc;
864 char *buf = tgt->dev_info.cdrom.result;
865 scsi_command_group_2 c;
866 dec_playback_status_t *st;
867
868 /* We might have to specify addressing fmt */
869 if (cmd[4] == 'P') {
870 scsi_command_group_2 saf;
871
872 bzero(&saf, sizeof(saf));
873 saf.scsi_cmd_code = SCSI_CMD_DEC_SET_ADDRESS_FORMAT;
874 saf.scsi_cmd_saf_fmt = (cmd[13] == 'A') ? 0 : 1;
875
876 rc = cdrom_vendor_specific(tgt, &saf, 0, 0, 0, ior);
877
878 if (rc != SCSI_RET_SUCCESS) return rc;
879
880 zero_ior( ior );
881 }
882
883 bzero(&c, sizeof(c));
884 c.scsi_cmd_code = SCSI_CMD_DEC_PLAYBACK_STATUS;
885 c.scsi_cmd_xfer_len_2 = sizeof(*st);
886 rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*st), ior);
887
888 if (rc != SCSI_RET_SUCCESS) return rc;
889
890 st = (dec_playback_status_t *) tgt->cmd_ptr;
891
892 if (cmd[4] == 'S')
893 decode_status( buf, st->audio_status+0x11 );
894 else {
895 if (st->is_msf)
896 sprintf(buf, "MSF Position %d %d %d",
897 (integer_t)st->address.msf.minute,
898 (integer_t)st->address.msf.second,
899 (integer_t)st->address.msf.frame);
900 else
901 sprintf(buf, "ABS Position %d", (integer_t)
902 (st->address.lba.lba1<<24)+
903 (st->address.lba.lba2<<16)+
904 (st->address.lba.lba3<< 8)+
905 st->address.lba.lba4);
906 }
907 tgt->dev_info.cdrom.result_available = TRUE;
908 return rc;
909 }
910 #endif
911
912 private scsi_ret_t
913 rrd42_set_volume(
914 target_info_t *tgt,
915 char *cmd,
916 io_req_t ior)
917 {
918 scsi_command_group_2 c;
919 dec_playback_control_t req;
920 int v0, v1, v2, v3;
921
922 sscanf(&cmd[6], "%d %d %d %d", &v0, &v1, &v2, &v3);
923
924 bzero(&c, sizeof(c));
925 c.scsi_cmd_code = SCSI_CMD_DEC_PLAYBACK_CONTROL;
926 c.scsi_cmd_xfer_len_2 = sizeof(req);
927 bzero(&req, sizeof(req));
928 if (v0) {
929 req.chan0_select = 1;
930 req.chan0_volume = v0;
931 }
932 if (v1) {
933 req.chan1_select = 2;
934 req.chan1_volume = v1;
935 }
936 if (v2) {
937 req.chan2_select = 4;
938 req.chan2_volume = v2;
939 }
940 if (v3) {
941 req.chan3_select = 8;
942 req.chan3_volume = v3;
943 }
944 return cdrom_vendor_specific(tgt, &c, &req, sizeof(req), 0, ior);
945 }
946
947 /* NEC CD-ROM */
948
949 #define SCSI_CMD_NEC_READ_TOC 0xde
950 typedef struct {
951 unsigned char xxx[9];
952 unsigned char first_track;
953 unsigned char xxx1[9];
954 unsigned char last_track;
955 unsigned char xxx2[9];
956 unsigned char lead_out_addr[3];
957 struct {
958 BITFIELD_2(unsigned char,
959 adr : 4,
960 ctrl : 4);
961 unsigned char xxx3[6];
962 unsigned char address[3];
963 } track_info[1]; /* VARSIZE */
964 } nec_toc_data_t;
965
966 #define SCSI_CMD_NEC_SEEK_TRK 0xd8
967 #define SCSI_CMD_NEC_PLAY_AUDIO 0xd9
968 #define SCSI_CMD_NEC_PAUSE 0xda
969 #define SCSI_CMD_NEC_EJECT 0xdc
970
971 #define SCSI_CMD_NEC_READ_SUBCH_Q 0xdd
972 typedef struct {
973 unsigned char audio_status; /* see decode_status_1 */
974 BITFIELD_2(unsigned char,
975 ctrl : 4,
976 xxx1 : 4);
977 unsigned char trackno;
978 unsigned char indexno;
979 unsigned char relative_address[3];
980 unsigned char absolute_address[3];
981 } nec_subch_data_t;
982
983 /*
984 * Reserved bits in byte1
985 */
986 #define NEC_LR_PLAY_MODE 0x01 /* RelAdr bit overload */
987 #define NEC_LR_STEREO 0x02 /* mono/stereo */
988
989 /*
990 * Vendor specific bits in the control byte.
991 * NEC uses them to specify the addressing mode
992 */
993 #define NEC_CTRL_A_ABS 0x00 /* XXX not sure about this */
994 #define NEC_CTRL_A_MSF 0x40 /* min/sec/frame */
995 #define NEC_CTRL_A_TI 0x80 /* track/index */
996 #define NEC_CTRL_A_CURRENT 0xc0 /* same as last specified */
997
998 private scsi_ret_t
999 nec_eject(
1000 target_info_t *tgt,
1001 char *cmd,
1002 io_req_t ior)
1003 {
1004 scsi_command_group_2 c;
1005
1006 bzero(&c, sizeof(c));
1007 c.scsi_cmd_code = SCSI_CMD_NEC_EJECT;
1008
1009 return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior);
1010 }
1011
1012 private scsi_ret_t
1013 nec_subchannel(
1014 target_info_t *tgt,
1015 char *cmd,
1016 io_req_t ior)
1017 {
1018 scsi_command_group_2 c;
1019 nec_subch_data_t *st;
1020 char *buf = tgt->dev_info.cdrom.result;
1021 scsi_ret_t rc;
1022
1023 bzero(&c, sizeof(c));
1024 c.scsi_cmd_code = SCSI_CMD_NEC_READ_SUBCH_Q;
1025 c.scsi_cmd_lun_and_relbit = sizeof(*st); /* Sic! */
1026
1027 rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*st), ior);
1028 if (rc != SCSI_RET_SUCCESS) return rc;
1029
1030 st = (nec_subch_data_t *) tgt->cmd_ptr;
1031
1032 /* Status or Position ? */
1033
1034 if (cmd[4] == 'S') {
1035 decode_status_1( buf, st->audio_status);
1036 } else {
1037
1038 /* XXX can it do ABS addressing e.g. 'logical' ? */
1039
1040 sprintf(buf, "MSF Position %d %d %d %d %d %d",
1041 (integer_t)bcd_to_decimal(st->absolute_address[0]), /* min */
1042 (integer_t)bcd_to_decimal(st->absolute_address[1]), /* sec */
1043 (integer_t)bcd_to_decimal(st->absolute_address[2]), /* frm */
1044 (integer_t)bcd_to_decimal(st->relative_address[0]), /* min */
1045 (integer_t)bcd_to_decimal(st->relative_address[1]), /* sec */
1046 (integer_t)bcd_to_decimal(st->relative_address[2])); /* frm */
1047 }
1048
1049 tgt->dev_info.cdrom.result_available = TRUE;
1050 return SCSI_RET_SUCCESS;
1051 }
1052
1053 private scsi_ret_t
1054 nec_read_toc(
1055 target_info_t *tgt,
1056 char *cmd,
1057 io_req_t ior)
1058 {
1059 scsi_command_group_2 c;
1060 nec_toc_data_t *t;
1061 char *buf = tgt->dev_info.cdrom.result;
1062 scsi_ret_t rc;
1063 int first, last, i;
1064
1065 bzero(&c, sizeof(c));
1066 c.scsi_cmd_code = SCSI_CMD_NEC_READ_TOC;
1067 c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE|NEC_LR_STEREO;
1068
1069 rc = cdrom_vendor_specific(tgt, &c, 0, 0, 512/*XXX*/, ior);
1070 if (rc != SCSI_RET_SUCCESS) return rc;
1071
1072 t = (nec_toc_data_t *) tgt->cmd_ptr;
1073
1074 first = bcd_to_decimal(t->first_track);
1075 last = bcd_to_decimal(t->last_track);
1076
1077 /*
1078 * "Get TH" wants summary, "TOC MSF|ABS from_track" wants all
1079 */
1080 if (cmd[0] == 'G') {
1081 sprintf(buf, "toc header: %d %d %d",
1082 sizeof(*t) + sizeof(t->track_info) * (last - first - 1),
1083 first, last);
1084 goto out;
1085 }
1086
1087 /*
1088 * The whole shebang
1089 */
1090 sscanf(&cmd[8], "%d", &i);
1091 sprintf(buf, "TOC from track %d:\n", i);
1092
1093 last -= first;
1094 i -= first;
1095 while ((i >= 0) && (i <= last)) {
1096 buf += strlen(buf);
1097 if (cmd[4] == 'M')
1098 sprintf(buf, "%d %d %d %d %d %d\n",
1099 t->track_info[i].ctrl,
1100 t->track_info[i].adr,
1101 first + i,
1102 bcd_to_decimal(t->track_info[i].address[0]),
1103 bcd_to_decimal(t->track_info[i].address[1]),
1104 bcd_to_decimal(t->track_info[i].address[2]));
1105 else
1106 /* THIS IS WRONG */
1107 sprintf(buf, "%d %d %d %d\n",
1108 t->track_info[i].ctrl,
1109 t->track_info[i].adr,
1110 first + i,
1111 bcd_to_decimal(t->track_info[i].address[0]) * 10000 +
1112 bcd_to_decimal(t->track_info[i].address[1]) * 100 +
1113 bcd_to_decimal(t->track_info[i].address[2]));
1114 i++;
1115 }
1116 /* To know how long the last track is */
1117 buf += strlen(buf);
1118 if (cmd[4] == 'M')
1119 sprintf(buf, "%d %d %d %d %d %d\n",
1120 0, 1, 0xaa /* User expects this */,
1121 bcd_to_decimal(t->lead_out_addr[0]),
1122 bcd_to_decimal(t->lead_out_addr[1]),
1123 bcd_to_decimal(t->lead_out_addr[2]));
1124 else
1125 /* THIS IS WRONG */
1126 sprintf(buf, "%d %d %d %d\n",
1127 0, 1, 0xaa /* User expects this */,
1128 bcd_to_decimal(t->lead_out_addr[0]) * 10000 +
1129 bcd_to_decimal(t->lead_out_addr[1]) * 100 +
1130 bcd_to_decimal(t->lead_out_addr[2]));
1131 out:
1132 tgt->dev_info.cdrom.result_available = TRUE;
1133 return SCSI_RET_SUCCESS;
1134 }
1135
1136
1137 private scsi_ret_t
1138 nec_play(
1139 target_info_t *tgt,
1140 char *cmd,
1141 io_req_t ior)
1142 {
1143 scsi_command_group_2 c;
1144 int sm, ss, sf, em, es, ef;
1145 int st, si, et, ei;
1146 scsi_ret_t rc;
1147
1148 /*
1149 * Seek to desired position
1150 */
1151 bzero(&c, sizeof(c));
1152 c.scsi_cmd_code = SCSI_CMD_NEC_SEEK_TRK;
1153 c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE;
1154
1155 /*
1156 * Play_msf or Play_ti
1157 */
1158 if (cmd[5] == 'A') {
1159 /* "Play A startM startS startF endM endS endF" */
1160
1161 sscanf(&cmd[7], "%d %d %d %d %d %d",
1162 &sm, &ss, &sf, &em, &es, &ef);
1163
1164 c.scsi_cmd_lba1 = decimal_to_bcd(sm);
1165 c.scsi_cmd_lba2 = decimal_to_bcd(ss);
1166 c.scsi_cmd_lba3 = decimal_to_bcd(sf);
1167 c.scsi_cmd_ctrl_byte = NEC_CTRL_A_MSF;
1168
1169 } else {
1170 /* "Play TI startT startI endT endI" */
1171
1172 sscanf(&cmd[8], "%d %d %d %d", &st, &si, &et, &ei);
1173
1174 c.scsi_cmd_lba1 = decimal_to_bcd(st);
1175 c.scsi_cmd_lba2 = decimal_to_bcd(si);
1176 c.scsi_cmd_lba3 = 0;
1177 c.scsi_cmd_ctrl_byte = NEC_CTRL_A_TI;
1178
1179 }
1180
1181 rc = cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior);
1182 if (rc != SCSI_RET_SUCCESS) return rc;
1183
1184 /*
1185 * Now ask it to play until..
1186 */
1187 zero_ior( ior );
1188
1189 bzero(&c, sizeof(c));
1190 c.scsi_cmd_code = SCSI_CMD_NEC_PLAY_AUDIO;
1191 c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE|NEC_LR_STEREO;
1192
1193 if (cmd[5] == 'A') {
1194 c.scsi_cmd_lba1 = decimal_to_bcd(em);
1195 c.scsi_cmd_lba2 = decimal_to_bcd(es);
1196 c.scsi_cmd_lba3 = decimal_to_bcd(ef);
1197 c.scsi_cmd_ctrl_byte = NEC_CTRL_A_MSF;
1198 } else {
1199 c.scsi_cmd_lba1 = decimal_to_bcd(et);
1200 c.scsi_cmd_lba2 = decimal_to_bcd(ei);
1201 c.scsi_cmd_lba3 = 0;
1202 c.scsi_cmd_ctrl_byte = NEC_CTRL_A_TI;
1203 }
1204
1205 return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior);
1206 }
1207
1208 private scsi_ret_t
1209 nec_pause_resume(
1210 target_info_t *tgt,
1211 char *cmd,
1212 io_req_t ior)
1213 {
1214 scsi_command_group_2 c;
1215
1216 bzero(&c, sizeof(c));
1217 /*
1218 * "Resume" or "Stop"
1219 */
1220 if (cmd[0] == 'R') {
1221 c.scsi_cmd_code = SCSI_CMD_NEC_PLAY_AUDIO;
1222 c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE|NEC_LR_STEREO;
1223 c.scsi_cmd_ctrl_byte = NEC_CTRL_A_CURRENT;
1224 } else {
1225 c.scsi_cmd_code = SCSI_CMD_NEC_PAUSE;
1226 }
1227
1228 return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior);
1229 }
1230
1231 /* TOSHIBA CD-ROM DRIVE:XM 3232 */
1232
1233 #define SCSI_CMD_TOSHIBA_SEEK_TRK 0xc0
1234 #define SCSI_CMD_TOSHIBA_PLAY_AUDIO 0xc1
1235 #define SCSI_CMD_TOSHIBA_PAUSE_AUDIO 0xc2
1236 #define SCSI_CMD_TOSHIBA_EJECT 0xc4
1237
1238 #define SCSI_CMD_TOSHIBA_READ_SUBCH_Q 0xc6
1239 typedef nec_subch_data_t toshiba_subch_data_t;
1240 /* audio status -> decode_status_1 */
1241
1242 #define SCSI_CMD_TOSHIBA_READ_TOC_ENTRY 0xc7
1243 typedef struct {
1244 unsigned char first_track;
1245 unsigned char last_track;
1246 unsigned char xxx[2];
1247 } toshiba_toc_header_t;
1248 typedef struct {
1249 unsigned char address[4];
1250 } toshiba_toc_data_t;
1251
1252
1253 private scsi_ret_t
1254 toshiba_eject(
1255 target_info_t *tgt,
1256 char *cmd,
1257 io_req_t ior)
1258 {
1259 scsi_command_group_2 c;
1260
1261 bzero(&c, sizeof(c));
1262 c.scsi_cmd_code = SCSI_CMD_TOSHIBA_EJECT;
1263
1264 return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior);
1265 }
1266
1267 private scsi_ret_t
1268 toshiba_subchannel(
1269 target_info_t *tgt,
1270 char *cmd,
1271 io_req_t ior)
1272 {
1273 scsi_command_group_2 c;
1274 toshiba_subch_data_t *st;
1275 char *buf = tgt->dev_info.cdrom.result;
1276 scsi_ret_t rc;
1277
1278 bzero(&c, sizeof(c));
1279 c.scsi_cmd_code = SCSI_CMD_TOSHIBA_READ_SUBCH_Q;
1280 c.scsi_cmd_lun_and_relbit = sizeof(*st); /* Sic! */
1281
1282 rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*st), ior);
1283 if (rc != SCSI_RET_SUCCESS) return rc;
1284
1285 st = (toshiba_subch_data_t *) tgt->cmd_ptr;
1286
1287 /* Status or Position ? */
1288
1289 if (cmd[4] == 'S') {
1290 decode_status_1( buf, st->audio_status);
1291 } else {
1292
1293 /* XXX can it do ABS addressing e.g. 'logical' ? */
1294
1295 sprintf(buf, "MSF Position %d %d %d %d %d %d",
1296 (integer_t)bcd_to_decimal(st->absolute_address[0]), /* min */
1297 (integer_t)bcd_to_decimal(st->absolute_address[1]), /* sec */
1298 (integer_t)bcd_to_decimal(st->absolute_address[2]), /* frm */
1299 (integer_t)bcd_to_decimal(st->relative_address[0]), /* min */
1300 (integer_t)bcd_to_decimal(st->relative_address[1]), /* sec */
1301 (integer_t)bcd_to_decimal(st->relative_address[2])); /* frm */
1302 }
1303
1304 tgt->dev_info.cdrom.result_available = TRUE;
1305 return SCSI_RET_SUCCESS;
1306 }
1307
1308 private scsi_ret_t
1309 toshiba_read_toc(
1310 target_info_t *tgt,
1311 char *cmd,
1312 io_req_t ior)
1313 {
1314 scsi_command_group_2 c;
1315 toshiba_toc_data_t *t;
1316 toshiba_toc_header_t *th;
1317 char *buf = tgt->dev_info.cdrom.result;
1318 scsi_ret_t rc;
1319 int first, last, i;
1320
1321 /* TOC header first */
1322 bzero(&c, sizeof(c));
1323 c.scsi_cmd_code = SCSI_CMD_TOSHIBA_READ_TOC_ENTRY;
1324 c.scsi_cmd_lun_and_relbit = 0;
1325 c.scsi_cmd_lba1 = 0;
1326
1327 rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*th), ior);
1328 if (rc != SCSI_RET_SUCCESS) return rc;
1329
1330 th = (toshiba_toc_header_t *) tgt->cmd_ptr;
1331
1332 first = bcd_to_decimal(th->first_track);
1333 last = bcd_to_decimal(th->last_track);
1334
1335 /*
1336 * "Get TH" wants summary, "TOC MSF|ABS from_track" wants all
1337 */
1338 if (cmd[0] == 'G') {
1339 sprintf(buf, "toc header: %d %d %d",
1340 sizeof(*th) + sizeof(*t) * (last - first + 1),
1341 first, last);
1342 goto out;
1343 }
1344
1345 /*
1346 * The whole shebang
1347 */
1348 sscanf(&cmd[8], "%d", &i);
1349 sprintf(buf, "TOC from track %d:\n", i);
1350
1351 while (i <= last) {
1352 bzero(&c, sizeof(c));
1353
1354 c.scsi_cmd_code = SCSI_CMD_TOSHIBA_READ_TOC_ENTRY;
1355 c.scsi_cmd_lun_and_relbit = 2;
1356 c.scsi_cmd_lba1 = decimal_to_bcd(i);
1357
1358 zero_ior( ior );
1359 rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*t), ior);
1360 if (rc != SCSI_RET_SUCCESS) break;
1361
1362 t = (toshiba_toc_data_t *) tgt->cmd_ptr;
1363
1364 buf += strlen(buf);
1365 if (cmd[4] == 'M')
1366 sprintf(buf, "0 0 %d %d %d %d\n",
1367 i,
1368 bcd_to_decimal(t->address[0]),
1369 bcd_to_decimal(t->address[1]),
1370 bcd_to_decimal(t->address[2]));
1371 else
1372 /* THIS IS WRONG */
1373 sprintf(buf, "0 0 %d %d\n",
1374 i,
1375 bcd_to_decimal(t->address[0]) * 10000 +
1376 bcd_to_decimal(t->address[1]) * 100 +
1377 bcd_to_decimal(t->address[2]));
1378 i++;
1379 }
1380
1381 /* Must simulate the lead-out track */
1382 bzero(&c, sizeof(c));
1383
1384 c.scsi_cmd_code = SCSI_CMD_TOSHIBA_READ_TOC_ENTRY;
1385 c.scsi_cmd_lun_and_relbit = 1;
1386 c.scsi_cmd_lba1 = 0;
1387
1388 zero_ior( ior );
1389 rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(*t), ior);
1390 if (rc != SCSI_RET_SUCCESS) goto out;
1391
1392 t = (toshiba_toc_data_t *) tgt->cmd_ptr;
1393
1394 buf += strlen(buf);
1395 if (cmd[4] == 'M')
1396 sprintf(buf, "0 0 %d %d %d %d\n",
1397 i,
1398 bcd_to_decimal(t->address[0]),
1399 bcd_to_decimal(t->address[1]),
1400 bcd_to_decimal(t->address[2]));
1401 else
1402 /* THIS IS WRONG */
1403 sprintf(buf, "0 0 %d %d\n",
1404 i,
1405 bcd_to_decimal(t->address[0]) * 10000 +
1406 bcd_to_decimal(t->address[1]) * 100 +
1407 bcd_to_decimal(t->address[2]));
1408 i++;
1409
1410 out:
1411 tgt->dev_info.cdrom.result_available = TRUE;
1412 return SCSI_RET_SUCCESS;
1413 }
1414
1415
1416 private scsi_ret_t
1417 toshiba_play(
1418 target_info_t *tgt,
1419 char *cmd,
1420 io_req_t ior)
1421 {
1422 scsi_command_group_2 c;
1423 int sm, ss, sf, em, es, ef;
1424 int st, si, et, ei;
1425 scsi_ret_t rc;
1426
1427 /*
1428 * Seek to desired position
1429 */
1430 bzero(&c, sizeof(c));
1431 c.scsi_cmd_code = SCSI_CMD_TOSHIBA_SEEK_TRK;
1432
1433 /*
1434 * Play_msf or Play_ti
1435 */
1436 if (cmd[5] == 'A') {
1437 /* "Play A startM startS startF endM endS endF" */
1438
1439 sscanf(&cmd[7], "%d %d %d %d %d %d",
1440 &sm, &ss, &sf, &em, &es, &ef);
1441
1442 c.scsi_cmd_lba1 = decimal_to_bcd(sm);
1443 c.scsi_cmd_lba2 = decimal_to_bcd(ss);
1444 c.scsi_cmd_lba3 = decimal_to_bcd(sf);
1445 c.scsi_cmd_ctrl_byte = NEC_CTRL_A_MSF;
1446
1447 } else {
1448 /* "Play TI startT startI endT endI" */
1449
1450 sscanf(&cmd[8], "%d %d %d %d", &st, &si, &et, &ei);
1451
1452 c.scsi_cmd_lba1 = decimal_to_bcd(st);
1453 c.scsi_cmd_lba2 = decimal_to_bcd(si);
1454 c.scsi_cmd_lba3 = 0;
1455 c.scsi_cmd_ctrl_byte = NEC_CTRL_A_TI;
1456
1457 }
1458
1459 rc = cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior);
1460 if (rc != SCSI_RET_SUCCESS) return rc;
1461
1462 /*
1463 * Now ask it to play until..
1464 */
1465 zero_ior( ior );
1466
1467 bzero(&c, sizeof(c));
1468 c.scsi_cmd_code = SCSI_CMD_TOSHIBA_PLAY_AUDIO;
1469 c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE|NEC_LR_STEREO;
1470
1471 if (cmd[5] == 'A') {
1472 c.scsi_cmd_lba1 = decimal_to_bcd(em);
1473 c.scsi_cmd_lba2 = decimal_to_bcd(es);
1474 c.scsi_cmd_lba3 = decimal_to_bcd(ef);
1475 c.scsi_cmd_ctrl_byte = NEC_CTRL_A_MSF;
1476 } else {
1477 c.scsi_cmd_lba1 = decimal_to_bcd(et);
1478 c.scsi_cmd_lba2 = decimal_to_bcd(ei);
1479 c.scsi_cmd_lba3 = 0;
1480 c.scsi_cmd_ctrl_byte = NEC_CTRL_A_TI;
1481 }
1482
1483 return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior);
1484 }
1485
1486 private scsi_ret_t
1487 toshiba_pause_resume(
1488 target_info_t *tgt,
1489 char *cmd,
1490 io_req_t ior)
1491 {
1492 scsi_command_group_2 c;
1493
1494 bzero(&c, sizeof(c));
1495 /*
1496 * "Resume" or "Stop"
1497 */
1498 if (cmd[0] == 'R') {
1499 /* ???? would have to remember last cmd ???? */
1500 /* broken ! */
1501 c.scsi_cmd_code = SCSI_CMD_TOSHIBA_PLAY_AUDIO;
1502 c.scsi_cmd_lun_and_relbit = NEC_LR_PLAY_MODE|NEC_LR_STEREO;
1503 c.scsi_cmd_ctrl_byte = NEC_CTRL_A_CURRENT;
1504 } else {
1505 c.scsi_cmd_code = SCSI_CMD_TOSHIBA_PAUSE_AUDIO;
1506 }
1507
1508 return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior);
1509 }
1510
1511
1512 #if 0
1513 /* I have info on these drives, but no drive to test */
1514
1515 /* PIONEER DRM-600 */
1516
1517 #define SCSI_CMD_PIONEER_EJECT 0xc0
1518
1519 #define SCSI_CMD_PIONEER_READ_TOC 0xc1
1520 typedef struct {
1521 unsigned char first_track;
1522 unsigned char last_track;
1523 unsigned char xxx[2];
1524 } pioneer_toc_hdr_t;
1525 typedef struct {
1526 unsigned char ctrl;
1527 unsigned char address[3];
1528 } pioneer_toc_info_t;
1529
1530 #define SCSI_CMD_PIONEER_READ_SUBCH 0xc2
1531 typedef struct {
1532 BITFIELD_2(unsigned char,
1533 ctrl : 4,
1534 xxx1 : 4);
1535 unsigned char trackno;
1536 unsigned char indexno;
1537 unsigned char relative_address[3];
1538 unsigned char absolute_address[3];
1539 } pioneer_subch_data_t;
1540
1541 #define SCSI_CMD_PIONEER_SEEK_TRK 0xc8
1542 #define SCSI_CMD_PIONEER_PLAY_AUDIO 0xc9
1543 #define SCSI_CMD_PIONEER_PAUSE 0xca
1544
1545 #define SCSI_CMD_PIONEER_AUDIO_STATUS 0xcc
1546 typedef struct {
1547 unsigned char audio_status;
1548 unsigned char xxx[5];
1549 } pioneer_status_t;
1550
1551 /*
1552 * Reserved bits in byte1
1553 */
1554 #define PIONEER_LR_END_ADDR 0x10
1555 #define PIONEER_LR_PAUSE 0x10
1556 #define PIONEER_LR_RESUME 0x00
1557
1558 /*
1559 * Vendor specific bits in the control byte.
1560 */
1561 #define PIONEER_CTRL_TH 0x00 /* TOC header */
1562 #define PIONEER_CTRL_TE 0x80 /* one TOC entry */
1563 #define PIONEER_CTRL_LO 0x40 /* lead-out track info */
1564
1565 #define PIONEER_CTRL_A_MSF 0x40 /* min/sec/frame addr */
1566
1567 private scsi_ret_t
1568 pioneer_eject(
1569 target_info_t *tgt,
1570 char *cmd,
1571 io_req_t ior)
1572 {
1573 scsi_command_group_2 c;
1574
1575 bzero(&c, sizeof(c));
1576 c.scsi_cmd_code = SCSI_CMD_PIONEER_EJECT;
1577
1578 return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior);
1579 }
1580
1581 private scsi_ret_t
1582 pioneer_position(
1583 target_info_t *tgt,
1584 char *cmd,
1585 io_req_t ior)
1586 {
1587 scsi_command_group_2 c;
1588 scsi_ret_t rc;
1589 char *buf = tgt->dev_info.cdrom.result;
1590 pioneer_subch_data_t *st;
1591
1592 bzero(&c, sizeof(c));
1593 c.scsi_cmd_code = SCSI_CMD_PIONEER_READ_SUBCH;
1594 c.scsi_cmd_xfer_len_2 = sizeof(pioneer_subch_data_t); /* 9 bytes */
1595
1596 rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(pioneer_subch_data_t), ior);
1597 if (rc != SCSI_RET_SUCCESS) return rc;
1598
1599 st = (pioneer_subch_data_t *) tgt->cmd_ptr;
1600
1601 /* XXX can it do ABS addressing e.g. 'logical' ? */
1602
1603 sprintf(buf, "MSF Position %d %d %d %d %d %d",
1604 (integer_t)bcd_to_decimal(st->absolute_address[0]), /* min */
1605 (integer_t)bcd_to_decimal(st->absolute_address[1]), /* sec */
1606 (integer_t)bcd_to_decimal(st->absolute_address[2]), /* frm */
1607 (integer_t)bcd_to_decimal(st->relative_address[0]), /* min */
1608 (integer_t)bcd_to_decimal(st->relative_address[1]), /* sec */
1609 (integer_t)bcd_to_decimal(st->relative_address[2])); /* frm */
1610
1611 tgt->dev_info.cdrom.result_available = TRUE;
1612 return SCSI_RET_SUCCESS;
1613 }
1614
1615 private scsi_ret_t
1616 pioneer_toc(
1617 target_info_t *tgt,
1618 char *cmd,
1619 io_req_t ior)
1620 {
1621 scsi_command_group_2 c;
1622 pioneer_toc_hdr_t *th;
1623 pioneer_toc_info_t *t;
1624 char *buf = tgt->dev_info.cdrom.result;
1625 scsi_ret_t rc;
1626 int first, last, i;
1627
1628 /* Read header first */
1629 bzero(&c, sizeof(c));
1630 c.scsi_cmd_code = SCSI_CMD_PIONEER_READ_TOC;
1631 c.scsi_cmd_xfer_len_2 = sizeof(pioneer_toc_hdr_t);
1632 c.scsi_cmd_ctrl_byte = PIONEER_CTRL_TH;
1633
1634 rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(pioneer_toc_hdr_t), ior);
1635 if (rc != SCSI_RET_SUCCESS) return rc;
1636
1637 th = (pioneer_toc_hdr_t *)tgt->cmd_ptr;
1638 first = bcd_to_decimal(th->first_track);
1639 last = bcd_to_decimal(th->last_track);
1640
1641 /*
1642 * "Get TH" wants summary, "TOC MSF|ABS from_track" wants all
1643 */
1644 if (cmd[0] == 'G') {
1645 sprintf(buf, "toc header: %d %d %d", 0, first, last);
1646 goto out;
1647 }
1648
1649 /*
1650 * Must do it one track at a time
1651 */
1652 sscanf(&cmd[8], "%d", &i);
1653 sprintf(buf, "TOC from track %d:\n", i);
1654
1655 for ( ; i <= last; i++) {
1656 zero_ior(ior);
1657 bzero(&c, sizeof(c));
1658 c.scsi_cmd_code = SCSI_CMD_PIONEER_READ_TOC;
1659 c.scsi_cmd_lba4 = decimal_to_bcd(i);
1660 c.scsi_cmd_xfer_len_2 = sizeof(pioneer_toc_info_t);
1661 c.scsi_cmd_ctrl_byte = PIONEER_CTRL_TE;
1662
1663 rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(pioneer_toc_info_t), ior);
1664 if (rc != SCSI_RET_SUCCESS) break;
1665
1666 t = (pioneer_toc_info_t *)tgt->cmd_ptr;
1667
1668 buf += strlen(buf);
1669 if (cmd[4] == 'M')
1670 sprintf(buf, "%d %d %d %d %d %d\n",
1671 t->ctrl, 0, i,
1672 bcd_to_decimal(t->address[0]),
1673 bcd_to_decimal(t->address[1]),
1674 bcd_to_decimal(t->address[2]));
1675 else
1676 /* THIS IS WRONG */
1677 sprintf(buf, "%d %d %d %d\n",
1678 t->ctrl, 0, i,
1679 bcd_to_decimal(t->address[0]) * 10000 +
1680 bcd_to_decimal(t->address[1]) * 100 +
1681 bcd_to_decimal(t->address[2]));
1682 }
1683 /* To know how long the last track is */
1684 zero_ior(ior);
1685 bzero(&c, sizeof(c));
1686 c.scsi_cmd_code = SCSI_CMD_PIONEER_READ_TOC;
1687 c.scsi_cmd_xfer_len_2 = sizeof(pioneer_toc_info_t);
1688 c.scsi_cmd_ctrl_byte = PIONEER_CTRL_LO;
1689
1690 rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(pioneer_toc_info_t), ior);
1691 if (rc != SCSI_RET_SUCCESS) return rc;
1692
1693 buf += strlen(buf);
1694 t = (pioneer_toc_info_t *)tgt->cmd_ptr;
1695 if (cmd[4] == 'M')
1696 sprintf(buf, "%d %d %d %d %d %d\n",
1697 t->ctrl, 0, 0xaa /* User expects this */,
1698 bcd_to_decimal(t->address[0]),
1699 bcd_to_decimal(t->address[1]),
1700 bcd_to_decimal(t->address[2]));
1701 else
1702 /* THIS IS WRONG */
1703 sprintf(buf, "%d %d %d %d\n",
1704 t->ctrl, 0, 0xaa /* User expects this */,
1705 bcd_to_decimal(t->address[0]) * 10000 +
1706 bcd_to_decimal(t->address[1]) * 100 +
1707 bcd_to_decimal(t->address[2]));
1708
1709 out:
1710 tgt->dev_info.cdrom.result_available = TRUE;
1711 return SCSI_RET_SUCCESS;
1712 }
1713
1714 private scsi_ret_t
1715 pioneer_status(
1716 target_info_t *tgt,
1717 char *cmd,
1718 io_req_t ior)
1719 {
1720 scsi_command_group_2 c;
1721 pioneer_status_t *st;
1722 char *buf = tgt->dev_info.cdrom.result;
1723 scsi_ret_t rc;
1724
1725 bzero(&c, sizeof(c));
1726 c.scsi_cmd_code = SCSI_CMD_PIONEER_AUDIO_STATUS;
1727 c.scsi_cmd_xfer_len_2 = sizeof(pioneer_status_t); /* 6 bytes */
1728
1729 rc = cdrom_vendor_specific(tgt, &c, 0, 0, sizeof(pioneer_status_t), ior);
1730 if (rc != SCSI_RET_SUCCESS) return rc;
1731
1732 st = (pioneer_status_t*) tgt->cmd_ptr;
1733 decode_status_1( buf, st->audio_status);
1734
1735 tgt->dev_info.cdrom.result_available = TRUE;
1736 return SCSI_RET_SUCCESS;
1737 }
1738
1739 private scsi_ret_t
1740 pioneer_play(
1741 target_info_t *tgt,
1742 char *cmd,
1743 io_req_t ior)
1744 {
1745 scsi_command_group_2 c;
1746 int sm, ss, sf, em, es, ef;
1747 int st, si, et, ei;
1748 scsi_ret_t rc;
1749
1750 /*
1751 * Seek to desired position
1752 */
1753 bzero(&c, sizeof(c));
1754 c.scsi_cmd_code = SCSI_CMD_PIONEER_SEEK_TRK;
1755 /*
1756 * Play_msf or Play_ti
1757 */
1758 if (cmd[5] == 'A') {
1759 /* "Play A startM startS startF endM endS endF" */
1760
1761 sscanf(&cmd[7], "%d %d %d %d %d %d",
1762 &sm, &ss, &sf, &em, &es, &ef);
1763
1764 c.scsi_cmd_lba2 = decimal_to_bcd(sm);
1765 c.scsi_cmd_lba3 = decimal_to_bcd(ss);
1766 c.scsi_cmd_lba4 = decimal_to_bcd(sf);
1767 c.scsi_cmd_ctrl_byte = PIONEER_CTRL_A_MSF;
1768
1769 } else {
1770 /* "Play TI startT startI endT endI" */
1771
1772 sscanf(&cmd[8], "%d %d %d %d", &st, &si, &et, &ei);
1773
1774 c.scsi_cmd_lba3 = decimal_to_bcd(st);
1775 c.scsi_cmd_lba4 = decimal_to_bcd(si);
1776 c.scsi_cmd_ctrl_byte = 0x80; /* Pure speculation!! */
1777
1778 }
1779
1780 rc = cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior);
1781 if (rc != SCSI_RET_SUCCESS) return rc;
1782
1783 /*
1784 * Now ask it to play until..
1785 */
1786 zero_ior( ior );
1787
1788 bzero(&c, sizeof(c));
1789 c.scsi_cmd_code = SCSI_CMD_PIONEER_PLAY_AUDIO;
1790 c.scsi_cmd_lun_and_relbit = PIONEER_LR_END_ADDR;
1791
1792 if (cmd[5] == 'A') {
1793 c.scsi_cmd_lba2 = decimal_to_bcd(em);
1794 c.scsi_cmd_lba3 = decimal_to_bcd(es);
1795 c.scsi_cmd_lba4 = decimal_to_bcd(ef);
1796 c.scsi_cmd_ctrl_byte = PIONEER_CTRL_A_MSF;
1797 } else {
1798 c.scsi_cmd_lba3 = decimal_to_bcd(et);
1799 c.scsi_cmd_lba4 = decimal_to_bcd(ei);
1800 c.scsi_cmd_ctrl_byte = 0x80; /* Pure speculation! */
1801 }
1802
1803 return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior);
1804 }
1805
1806 private scsi_ret_t
1807 pioneer_pause_resume(
1808 target_info_t *tgt,
1809 char *cmd,
1810 io_req_t ior)
1811 {
1812 scsi_command_group_2 c;
1813
1814 bzero(&c, sizeof(c));
1815 c.scsi_cmd_code = SCSI_CMD_PIONEER_PAUSE;
1816 /*
1817 * "Resume" or "Stop"
1818 */
1819 if (cmd[0] == 'S')
1820 c.scsi_cmd_lun_and_relbit = PIONEER_LR_PAUSE;
1821 else
1822 c.scsi_cmd_lun_and_relbit = PIONEER_LR_RESUME;
1823
1824 return cdrom_vendor_specific(tgt, &c, 0, 0, 0, ior);
1825 }
1826
1827 /* DENON DRD-253 */
1828
1829 #define SCSI_CMD_DENON_PLAY_AUDIO 0x22
1830 #define SCSI_CMD_DENON_EJECT 0xe6
1831 #define SCSI_CMD_DENON_PAUSE_AUDIO 0xe7
1832 #define SCSI_CMD_DENON_READ_TOC 0xe9
1833 #define SCSI_CMD_DENON_READ_SUBCH 0xeb
1834
1835
1836 /* HITACHI 1750 */
1837
1838 #define SCSI_CMD_HITACHI_PLAY_AUDIO_MSF 0xe0
1839 #define SCSI_CMD_HITACHI_PAUSE_AUDIO 0xe1
1840 #define SCSI_CMD_HITACHI_EJECT 0xe4
1841 #define SCSI_CMD_HITACHI_READ_SUBCH 0xe5
1842 #define SCSI_CMD_HITACHI_READ_TOC 0xe8
1843
1844 #endif
1845
1846 /*
1847 * Tabulate all of the above
1848 */
1849 private red_list_t cdrom_exceptions[] = {
1850
1851 #if 0
1852 For documentation purposes, here are some SCSI-2 compliant drives:
1853
1854 Vendor Product Rev Comments
1855
1856 "SONY " "CD-ROMCDU-541 " "2.6a" The NeXT drive
1857 #endif
1858
1859 /* vendor, product, rev */
1860 /* can_play_audio */
1861 /* eject */
1862 /* current_position */
1863 /* read_toc */
1864 /* get_status */
1865 /* play_msf */
1866 /* play_ti */
1867 /* pause_resume */
1868 /* volume_control */
1869
1870 /* We have seen a "RRD42(C)DEC " "4.5d" */
1871 { "DEC ", "RRD42", "",
1872 0, 0, 0, 0, 0, 0, 0, 0, rrd42_set_volume },
1873
1874 /* We have seen a "CD-ROM DRIVE:84 " "1.0 " */
1875 { "NEC ", "CD-ROM DRIVE:84", "",
1876 op_not_supported, nec_eject, nec_subchannel, nec_read_toc,
1877 nec_subchannel, nec_play, nec_play, nec_pause_resume,
1878 op_not_supported },
1879
1880 /* We have seen a "CD-ROM DRIVE:XM " "3232" */
1881 { "TOSHIBA ", "CD-ROM DRIVE:XM", "32",
1882 op_not_supported, toshiba_eject, toshiba_subchannel, toshiba_read_toc,
1883 toshiba_subchannel, toshiba_play, toshiba_play, toshiba_pause_resume,
1884 op_not_supported },
1885
1886 { "TOSHIBA ", "CD-ROM DRIVE:XM", "33",
1887 op_not_supported, toshiba_eject, toshiba_subchannel, toshiba_read_toc,
1888 toshiba_subchannel, toshiba_play, toshiba_play, toshiba_pause_resume,
1889 op_not_supported },
1890
1891 #if 0
1892 { "PIONEER ", "???????DRM-6", "",
1893 op_not_supported, pioneer_eject, pioneer_position, pioneer_toc,
1894 pioneer_status, pioneer_play, pioneer_play, pioneer_pause_resume,
1895 op_not_supported },
1896
1897 { "DENON ", "DRD 25X", "", ...},
1898 { "HITACHI ", "CDR 1750S", "", ...},
1899 { "HITACHI ", "CDR 1650S", "", ...},
1900 { "HITACHI ", "CDR 3650", "", ...},
1901
1902 #endif
1903
1904 /* Zero terminate this list */
1905 { 0, }
1906 };
1907
1908 private void
1909 check_red_list(
1910 target_info_t *tgt,
1911 scsi2_inquiry_data_t *inq)
1912
1913 {
1914 red_list_t *list;
1915
1916 for (list = &cdrom_exceptions[0]; list->vendor; list++) {
1917
1918 /*
1919 * Prefix-Match all strings
1920 */
1921 if ((strncmp(list->vendor, (const char *)inq->vendor_id,
1922 strlen(list->vendor)) == 0) &&
1923 (strncmp(list->product, (const char *)inq->product_id,
1924 strlen(list->product)) == 0) &&
1925 (strncmp(list->rev, (const char *)inq->product_rev,
1926 strlen(list->rev)) == 0)) {
1927 /*
1928 * One of them..
1929 */
1930 if (tgt->dev_info.cdrom.violates_standards != list) {
1931 tgt->dev_info.cdrom.violates_standards = list;
1932 curse_the_vendor( list, TRUE );
1933 }
1934 return;
1935 }
1936 }
1937 }
Cache object: 6fca613f7515a7f23f64b47999bb0e53
|