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