1 /*
2 * libdi - scsipt SCSI Device Interface Library
3 *
4 * Copyright (C) 1993-2004 Ti Kan
5 * E-mail: xmcd@amb.org
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 #ifndef lint
22 static char *_cdsim_c_ident_ = "@(#)cdsim.c 6.33 04/03/11";
23 #endif
24
25 #include "common_d/appenv.h"
26 #include "common_d/util.h"
27 #include "libdi_d/libdi.h"
28 #include "libdi_d/scsipt.h"
29
30 #ifdef DEMO_ONLY
31
32 #ifndef CDSIM_VERS
33 #define CDSIM_VERS "2.00" /* CD-ROM simulator version */
34 #endif
35
36 extern appdata_t app_data;
37 extern FILE *errfp;
38
39 STATIC simstat_t cdsim_stat;
40 STATIC time_t cdsim_start_time,
41 cdsim_pause_time,
42 cdsim_pause_elapsed,
43 cdsim_prev_pause,
44 cdsim_elapsed,
45 cdsim_now;
46
47 STATIC inquiry_data_t cdsim_inqdata;
48 STATIC byte_t cdsim_tocdata1[SZ_RDTOC],
49 cdsim_tocdata2[SZ_RDTOC];
50
51 STATIC int cdsim_sfd,
52 cdsim_rfd;
53
54
55 /*
56 * cdsim_sendpkt
57 * Write a CD simulator packet down the pipe
58 *
59 * Args:
60 * name - The text string describing the caller module
61 * fd - Pipe file descriptor
62 * s - Pointer to the packet data
63 *
64 * Return:
65 * TRUE - pipe write successful
66 * FALSE - pipe write failed
67 */
68 bool_t
cdsim_sendpkt(char * name,int fd,simpkt_t * s)69 cdsim_sendpkt(char *name, int fd, simpkt_t *s)
70 {
71 byte_t *p = (byte_t *) s;
72 int i,
73 ret;
74
75 if (fd < 0)
76 return FALSE;
77
78 /* Brand packet with magic number */
79 s->magic = CDSIM_MAGIC;
80
81 /* Send a packet */
82 i = CDSIM_PKTSZ;
83 while ((ret = write(fd, p, i)) < i) {
84 if (ret < 0 && errno != EBADF) {
85 (void) fprintf(errfp,
86 "%s: packet write error (errno=%d)\n",
87 name, errno);
88 return FALSE;
89 }
90
91 if (ret == 0) {
92 /* avoid hogging CPU */
93 util_delayms(1000);
94 }
95 else {
96 i -= ret;
97 p += ret;
98 }
99 }
100
101 return TRUE;
102 }
103
104
105 /*
106 * cdsim_getpkt
107 * Read a CD simulator packet from the pipe
108 *
109 * Args:
110 * name - The text string describing the caller module
111 * fd - Pipe file descriptor
112 * s - Pointer to the packet data
113 *
114 * Return:
115 * TRUE - pipe read successful
116 * FALSE - pipe read failed
117 */
118 bool_t
cdsim_getpkt(char * name,int fd,simpkt_t * r)119 cdsim_getpkt(char *name, int fd, simpkt_t *r)
120 {
121 byte_t *p = (byte_t *) r;
122 int i,
123 ret;
124
125 if (fd < 0)
126 return FALSE;
127
128 /* Get a packet */
129 i = CDSIM_PKTSZ;
130 while ((ret = read(fd, p, i)) < i) {
131 if (ret < 0 && errno != EBADF) {
132 (void) fprintf(errfp,
133 "%s: packet read error (errno=%d)\n",
134 name, errno);
135 return FALSE;
136 }
137
138 if (ret == 0) {
139 /* avoid hogging CPU */
140 util_delayms(1000);
141 }
142 else {
143 i -= ret;
144 p += ret;
145 }
146 }
147
148 /* Check packet for magic number */
149 if (r->magic != CDSIM_MAGIC) {
150 (void) fprintf(errfp, "%s: bad packet magic number.\n", name);
151 return FALSE;
152 }
153
154 return TRUE;
155 }
156
157
158 /*
159 * cdsim_sig
160 * CD simulator process signal handler
161 *
162 * Args:
163 * sig - The signal number
164 *
165 * Return:
166 * Nothing.
167 */
168 /*ARGSUSED*/
169 STATIC void
cdsim_sig(int sig)170 cdsim_sig(int sig)
171 {
172 (void) fprintf(errfp, "CD-ROM simulator pid=%d exiting.\n",
173 (int) getpid());
174 (void) close(cdsim_sfd);
175 (void) close(cdsim_rfd);
176 _exit(0);
177 }
178
179
180 /*
181 * cdsim_s_test
182 * Test Unit Ready command simulation function
183 *
184 * Args:
185 * r - Pointer to the command packet
186 * s - Pointer to the response packet
187 *
188 * Return:
189 * Command completion status code
190 */
191 /*ARGSUSED*/
192 STATIC byte_t
cdsim_s_test(simpkt_t * r,simpkt_t * s)193 cdsim_s_test(simpkt_t *r, simpkt_t *s)
194 {
195 if (cdsim_stat.status == CDSIM_NODISC)
196 return CDSIM_COMPERR;
197 else
198 return CDSIM_COMPOK;
199 }
200
201
202 /*
203 * cdsim_s_inquir
204 * Inquiry command simulation function
205 *
206 * Args:
207 * r - Pointer to the command packet
208 * s - Pointer to the response packet
209 *
210 * Return:
211 * Command completion status code
212 */
213 STATIC byte_t
cdsim_s_inquir(simpkt_t * r,simpkt_t * s)214 cdsim_s_inquir(simpkt_t *r, simpkt_t *s)
215 {
216 s->len = (r->len > CDSIM_INQSZ) ? CDSIM_INQSZ : r->len;
217
218 /* Copy inquiry data into packet */
219 (void) memcpy(s->data, (byte_t *) &cdsim_inqdata, s->len);
220
221 return CDSIM_COMPOK;
222 }
223
224
225 /*
226 * cdsim_s_mselect
227 * Mode Select (6) command simulation function
228 *
229 * Args:
230 * r - Pointer to the command packet
231 * s - Pointer to the response packet
232 *
233 * Return:
234 * Command completion status code
235 */
236 /*ARGSUSED*/
237 STATIC byte_t
cdsim_s_mselect(simpkt_t * r,simpkt_t * s)238 cdsim_s_mselect(simpkt_t *r, simpkt_t *s)
239 {
240 return CDSIM_COMPOK;
241 }
242
243
244 /*
245 * cdsim_m_mselect
246 * Mode Select (10) command simulation function
247 *
248 * Args:
249 * r - Pointer to the command packet
250 * s - Pointer to the response packet
251 *
252 * Return:
253 * Command completion status code
254 */
255 /*ARGSUSED*/
256 STATIC byte_t
cdsim_m_mselect(simpkt_t * r,simpkt_t * s)257 cdsim_m_mselect(simpkt_t *r, simpkt_t *s)
258 {
259 return CDSIM_COMPOK;
260 }
261
262
263 /*
264 * cdsim_s_msense
265 * Mode Sense (6) command simulation function
266 *
267 * Args:
268 * r - Pointer to the command packet
269 * s - Pointer to the response packet
270 *
271 * Return:
272 * Command completion status code
273 */
274 /*ARGSUSED*/
275 STATIC byte_t
cdsim_s_msense(simpkt_t * r,simpkt_t * s)276 cdsim_s_msense(simpkt_t *r, simpkt_t *s)
277 {
278 return CDSIM_COMPOK;
279 }
280
281
282 /*
283 * cdsim_m_msense
284 * Mode Sense (10) command simulation function
285 *
286 * Args:
287 * r - Pointer to the command packet
288 * s - Pointer to the response packet
289 *
290 * Return:
291 * Command completion status code
292 */
293 /*ARGSUSED*/
294 STATIC byte_t
cdsim_m_msense(simpkt_t * r,simpkt_t * s)295 cdsim_m_msense(simpkt_t *r, simpkt_t *s)
296 {
297 return CDSIM_COMPOK;
298 }
299
300
301 /*
302 * cdsim_s_start
303 * Start/Stop Unit command simulation function
304 *
305 * Args:
306 * r - Pointer to the command packet
307 * s - Pointer to the response packet
308 *
309 * Return:
310 * Command completion status code
311 */
312 /*ARGSUSED*/
313 STATIC byte_t
cdsim_s_start(simpkt_t * r,simpkt_t * s)314 cdsim_s_start(simpkt_t *r, simpkt_t *s)
315 {
316 cdsim_start_time = 0;
317 cdsim_elapsed = 0;
318 cdsim_pause_time = 0;
319 cdsim_pause_elapsed = 0;
320 cdsim_prev_pause = 0;
321
322 if (r->cdb[4] & 0x01) {
323 /* Start unit */
324 if (r->cdb[4] & 0x02) {
325 /* Load disc */
326 cdsim_stat.status = CDSIM_STOPPED;
327 return CDSIM_COMPOK;
328 }
329 else if (cdsim_stat.status == CDSIM_NODISC)
330 return CDSIM_COMPERR;
331 }
332 else {
333 /* Stop unit */
334 if (cdsim_stat.status == CDSIM_NODISC)
335 return CDSIM_COMPERR;
336 else if (r->cdb[4] & 0x02) {
337 /* Eject disc */
338 if (cdsim_stat.caddylock)
339 return CDSIM_COMPERR;
340 else {
341 cdsim_stat.status = CDSIM_NODISC;
342 return CDSIM_COMPOK;
343 }
344 }
345 else {
346 /* Stop disc */
347 cdsim_stat.status = CDSIM_STOPPED;
348 return CDSIM_COMPOK;
349 }
350 }
351 return CDSIM_COMPOK;
352 }
353
354
355 /*
356 * cdsim_s_prevent
357 * Prevent/Allow Medium Removal command simulation function
358 *
359 * Args:
360 * r - Pointer to the command packet
361 * s - Pointer to the response packet
362 *
363 * Return:
364 * Command completion status code
365 */
366 /*ARGSUSED*/
367 STATIC byte_t
cdsim_s_prevent(simpkt_t * r,simpkt_t * s)368 cdsim_s_prevent(simpkt_t *r, simpkt_t *s)
369 {
370 if (r->cdb[4] & 0x01)
371 cdsim_stat.caddylock = TRUE;
372 else
373 cdsim_stat.caddylock = FALSE;
374
375 return CDSIM_COMPOK;
376 }
377
378
379 /*
380 * cdsim_m_rdsubq
381 * Read Subchannel command simulation function
382 *
383 * Args:
384 * r - Pointer to the command packet
385 * s - Pointer to the response packet
386 *
387 * Return:
388 * Command completion status code
389 */
390 STATIC byte_t
cdsim_m_rdsubq(simpkt_t * r,simpkt_t * s)391 cdsim_m_rdsubq(simpkt_t *r, simpkt_t *s)
392 {
393 subq_hdr_t *h = (subq_hdr_t *)(void *) s->data;
394 subq_01_t *s1 = (subq_01_t *)(void *)
395 (s->data + sizeof(subq_hdr_t));
396
397 /* Subchannel formats */
398 switch (r->cdb[3]) {
399 case SUB_CURPOS:
400 h->subch_len = 15;
401
402 s1->fmt_code = SUB_CURPOS;
403 s1->preemph = 0;
404 s1->copyallow = 0;
405 s1->trktype = 0;
406 s1->audioch = 0;
407 s1->adr = 0;
408
409 s1->trkno = cdsim_stat.trkno;
410 s1->idxno = cdsim_stat.idxno;
411
412 if (r->cdb[1] & 0x02) {
413 util_blktomsf(
414 cdsim_stat.absaddr,
415 &s1->abs_addr.msf.min,
416 &s1->abs_addr.msf.sec,
417 &s1->abs_addr.msf.frame,
418 MSF_OFFSET
419 );
420
421 util_blktomsf(
422 cdsim_stat.reladdr,
423 &s1->rel_addr.msf.min,
424 &s1->rel_addr.msf.sec,
425 &s1->rel_addr.msf.frame,
426 0
427 );
428 }
429 else {
430 s1->abs_addr.logical = util_bswap32(cdsim_stat.absaddr);
431 s1->rel_addr.logical = util_bswap32(cdsim_stat.reladdr);
432 }
433
434 s->len = sizeof(subq_hdr_t) + sizeof(subq_01_t);
435
436 break;
437
438 default:
439 /* The other formats are not implemented */
440 return CDSIM_COMPERR;
441 }
442
443 switch (cdsim_stat.status) {
444 case CDSIM_PLAYING:
445 h->audio_status = AUDIO_PLAYING;
446 break;
447
448 case CDSIM_PAUSED:
449 h->audio_status = AUDIO_PAUSED;
450 break;
451
452 default:
453 h->audio_status = AUDIO_COMPLETED;
454 break;
455 }
456
457 return CDSIM_COMPOK;
458 }
459
460
461 /*
462 * cdsim_m_rdtoc
463 * Read TOC command simulation function
464 *
465 * Args:
466 * r - Pointer to the command packet
467 * s - Pointer to the response packet
468 *
469 * Return:
470 * Command completion status code
471 */
472 STATIC byte_t
cdsim_m_rdtoc(simpkt_t * r,simpkt_t * s)473 cdsim_m_rdtoc(simpkt_t *r, simpkt_t *s)
474 {
475 byte_t *startoff,
476 fmt;
477
478 fmt = (r->cdb[2] & 0x0f);
479
480 switch (fmt) {
481 case 0:
482 /* Read track TOC */
483 break;
484 case 1: /* Session info */
485 case 2: /* Full TOC */
486 case 3: /* PMA */
487 case 4: /* ATIP */
488 case 5: /* CD-TEXT */
489 /* These are not supported */
490 return CDSIM_PARMERR;
491 }
492
493 if (r->cdb[1] & 0x02)
494 startoff = cdsim_tocdata2 + sizeof(toc_hdr_t);
495 else
496 startoff = cdsim_tocdata1 + sizeof(toc_hdr_t);
497
498 s->len = (r->len > SZ_RDTOC) ? SZ_RDTOC : r->len;
499
500 if (r->cdb[6] > 1) {
501 int skip;
502
503 skip = ((int) r->cdb[6] - 1) *
504 sizeof(toc_trk_descr_t);
505 s->len -= skip;
506 startoff += skip;
507 }
508
509 /* Copy TOC data into packet */
510
511 /* Header info */
512 (void) memcpy(s->data, cdsim_tocdata1, sizeof(toc_hdr_t));
513
514 /* TOC data */
515 (void) memcpy(s->data + sizeof(toc_hdr_t), startoff, s->len);
516
517 return CDSIM_COMPOK;
518 }
519
520
521 /*
522 * cdsim_m_play
523 * Play Audio (10) command simulation function
524 *
525 * Args:
526 * r - Pointer to the command packet
527 * s - Pointer to the response packet
528 *
529 * Return:
530 * Command completion status code
531 */
532 /*ARGSUSED*/
533 STATIC byte_t
cdsim_m_play(simpkt_t * r,simpkt_t * s)534 cdsim_m_play(simpkt_t *r, simpkt_t *s)
535 {
536 cdsim_stat.startaddr = (r->cdb[2] << 24) | (r->cdb[3] << 16) |
537 (r->cdb[4] << 8) | r->cdb[5];
538 cdsim_stat.endaddr = cdsim_stat.startaddr +
539 ((r->cdb[7] << 8) | r->cdb[8]);
540
541 if (cdsim_stat.endaddr <= cdsim_stat.startaddr)
542 return CDSIM_PARMERR;
543
544 cdsim_start_time = cdsim_now;
545 cdsim_elapsed = 0;
546 cdsim_pause_time = 0;
547 cdsim_pause_elapsed = 0;
548 cdsim_prev_pause = 0;
549
550 cdsim_stat.status = CDSIM_PLAYING;
551
552 return CDSIM_COMPOK;
553 }
554
555
556 /*
557 * cdsim_m_playmsf
558 * Play Audio MSF command simulation function
559 *
560 * Args:
561 * r - Pointer to the command packet
562 * s - Pointer to the response packet
563 *
564 * Return:
565 * Command completion status code
566 */
567 /*ARGSUSED*/
568 STATIC byte_t
cdsim_m_playmsf(simpkt_t * r,simpkt_t * s)569 cdsim_m_playmsf(simpkt_t *r, simpkt_t *s)
570 {
571 util_msftoblk(
572 r->cdb[3],
573 r->cdb[4],
574 r->cdb[5],
575 &cdsim_stat.startaddr,
576 MSF_OFFSET
577 );
578 util_msftoblk(
579 r->cdb[6],
580 r->cdb[7],
581 r->cdb[8],
582 &cdsim_stat.endaddr,
583 MSF_OFFSET
584 );
585
586 if (cdsim_stat.endaddr <= cdsim_stat.startaddr)
587 return CDSIM_PARMERR;
588
589 cdsim_start_time = cdsim_now;
590 cdsim_elapsed = 0;
591 cdsim_pause_time = 0;
592 cdsim_pause_elapsed = 0;
593 cdsim_prev_pause = 0;
594
595 cdsim_stat.status = CDSIM_PLAYING;
596
597 return CDSIM_COMPOK;
598 }
599
600
601 /*
602 * cdsim_m_playti
603 * Play Audio Track/index command simulation function
604 *
605 * Args:
606 * r - Pointer to the command packet
607 * s - Pointer to the response packet
608 *
609 * Return:
610 * Command completion status code
611 */
612 /*ARGSUSED*/
613 STATIC byte_t
cdsim_m_playti(simpkt_t * r,simpkt_t * s)614 cdsim_m_playti(simpkt_t *r, simpkt_t *s)
615 {
616 int strk = (int) r->cdb[4],
617 sidx = (int) r->cdb[5],
618 etrk = (int) r->cdb[7],
619 eidx = (int) r->cdb[8];
620
621 if (sidx > (int) cdsim_stat.trk[strk - 1].nidxs) {
622 strk++;
623 sidx = 1;
624 }
625
626 if (strk > (int) cdsim_stat.ntrks || etrk > (int) cdsim_stat.ntrks)
627 return CDSIM_PARMERR;
628
629 if (eidx > (int) cdsim_stat.trk[strk - 1].nidxs)
630 eidx = (int) cdsim_stat.trk[strk - 1].nidxs;
631
632 cdsim_stat.startaddr = cdsim_stat.trk[strk - 1].iaddr[sidx - 1];
633 cdsim_stat.endaddr = cdsim_stat.trk[etrk].iaddr[eidx - 1];
634
635 if (cdsim_stat.endaddr <= cdsim_stat.startaddr)
636 return CDSIM_PARMERR;
637
638 cdsim_start_time = cdsim_now;
639 cdsim_elapsed = 0;
640 cdsim_pause_time = 0;
641 cdsim_pause_elapsed = 0;
642 cdsim_prev_pause = 0;
643
644 cdsim_stat.status = CDSIM_PLAYING;
645
646 return CDSIM_COMPOK;
647 }
648
649
650 /*
651 * cdsim_m_pause
652 * Pause/Resume command simulation function
653 *
654 * Args:
655 * r - Pointer to the command packet
656 * s - Pointer to the response packet
657 *
658 * Return:
659 * Command completion status code
660 */
661 /*ARGSUSED*/
662 STATIC byte_t
cdsim_m_pause(simpkt_t * r,simpkt_t * s)663 cdsim_m_pause(simpkt_t *r, simpkt_t *s)
664 {
665 if (cdsim_stat.status == CDSIM_PAUSED && r->cdb[8] & 0x01) {
666 /* Resume */
667 cdsim_stat.status = CDSIM_PLAYING;
668 cdsim_prev_pause += cdsim_pause_elapsed;
669 cdsim_pause_elapsed = 0;
670
671 return CDSIM_COMPOK;
672 }
673 else {
674 cdsim_stat.status = CDSIM_PAUSED;
675 cdsim_pause_time = time(NULL);
676 return CDSIM_COMPOK;
677 }
678 }
679
680
681 /*
682 * cdsim_l_play
683 * Play Audio (12) command simulation function
684 *
685 * Args:
686 * r - Pointer to the command packet
687 * s - Pointer to the response packet
688 *
689 * Return:
690 * Command completion status code
691 */
692 /*ARGSUSED*/
693 STATIC byte_t
cdsim_l_play(simpkt_t * r,simpkt_t * s)694 cdsim_l_play(simpkt_t *r, simpkt_t *s)
695 {
696 cdsim_stat.startaddr = (r->cdb[2] << 24) | (r->cdb[3] << 16) |
697 (r->cdb[4] << 8) | r->cdb[5];
698 cdsim_stat.endaddr = cdsim_stat.startaddr +
699 ((r->cdb[6] << 24) | (r->cdb[7] << 16) |
700 (r->cdb[8] << 8) | r->cdb[9]);
701
702 if (cdsim_stat.endaddr <= cdsim_stat.startaddr)
703 return CDSIM_PARMERR;
704
705 cdsim_start_time = cdsim_now;
706 cdsim_elapsed = 0;
707 cdsim_pause_time = 0;
708 cdsim_pause_elapsed = 0;
709 cdsim_prev_pause = 0;
710
711 cdsim_stat.status = CDSIM_PLAYING;
712
713 return CDSIM_COMPOK;
714 }
715
716
717 /*
718 * cdsim_l_readcd
719 * MMC Read CD (12) command simulation function
720 *
721 * Args:
722 * r - Pointer to the command packet
723 * s - Pointer to the response packet
724 *
725 * Return:
726 * Command completion status code
727 */
728 /*ARGSUSED*/
729 STATIC byte_t
cdsim_l_readcd(simpkt_t * r,simpkt_t * s)730 cdsim_l_readcd(simpkt_t *r, simpkt_t *s)
731 {
732 int i;
733 byte_t *p;
734 char c;
735
736 cdsim_stat.startaddr = (r->cdb[2] << 24) | (r->cdb[3] << 16) |
737 (r->cdb[4] << 8) | r->cdb[5];
738 cdsim_stat.endaddr = cdsim_stat.startaddr +
739 ((r->cdb[6] << 16) | (r->cdb[7] << 8) | r->cdb[8]);
740
741 if (cdsim_stat.endaddr <= cdsim_stat.startaddr)
742 return CDSIM_PARMERR;
743
744 cdsim_start_time = cdsim_now;
745 cdsim_elapsed = 0;
746 cdsim_pause_time = 0;
747 cdsim_pause_elapsed = 0;
748 cdsim_prev_pause = 0;
749
750 cdsim_stat.status = CDSIM_PLAYING;
751
752 /* Write printable ASCII character pattern into buffer */
753 c = (byte_t) 0x20;
754 for (i = 0, p = s->data; i < sizeof(s->data); i++, p++) {
755 *p = c;
756 if (++c == 0x7f)
757 c = 0x20;
758 }
759
760 return CDSIM_COMPOK;
761 }
762
763
764 /*
765 * cdsim_svccmd
766 * Service a command
767 *
768 * Args:
769 * r - Pointer to the command packet
770 * s - Pointer to the response packet
771 *
772 * Return:
773 * TRUE - success
774 * FALSE - failure
775 */
776 STATIC bool_t
cdsim_svccmd(simpkt_t * r,simpkt_t * s)777 cdsim_svccmd(simpkt_t *r, simpkt_t *s)
778 {
779 (void) memset(s, 0, CDSIM_PKTSZ);
780
781 DBGPRN(DBG_DEVIO)(errfp, "\ncdsim: pktid=%d cdbsz=%d len=%d dir=%d",
782 r->pktid, r->cdbsz, r->len, r->dir);
783
784 DBGDUMP(DBG_DEVIO)("cdsim: SCSI CDB bytes",
785 (byte_t *) r->cdb, (int) r->cdbsz);
786
787 /* Set return packet id */
788 s->pktid = r->pktid;
789
790 /* Copy CDB */
791 s->cdbsz = r->cdbsz;
792 (void) memcpy(s->cdb, r->cdb, r->cdbsz);
793
794 /* Truncate if necessary */
795 if (s->len > CDSIM_MAX_DATALEN)
796 s->len = CDSIM_MAX_DATALEN;
797
798 /* Direction flag */
799 s->dir = r->dir;
800
801 /* Interpret CDB and service the command */
802 switch (r->cdb[0]) {
803 case OP_S_TEST:
804 /* Test unit ready */
805 s->retcode = cdsim_s_test(r, s);
806 break;
807
808 case OP_S_INQUIR:
809 /* Inquiry */
810 s->retcode = cdsim_s_inquir(r, s);
811 break;
812
813 case OP_S_MSELECT:
814 /* Mode select (6) */
815 s->retcode = cdsim_s_mselect(r, s);
816 break;
817
818 case OP_M_MSELECT:
819 /* Mode select (10) */
820 s->retcode = cdsim_m_mselect(r, s);
821 break;
822
823 case OP_S_MSENSE:
824 /* Mode sense (6) */
825 s->retcode = cdsim_s_msense(r, s);
826 break;
827
828 case OP_M_MSENSE:
829 /* Mode sense (10) */
830 s->retcode = cdsim_m_msense(r, s);
831 break;
832
833 case OP_S_START:
834 /* Start/stop unit */
835 s->retcode = cdsim_s_start(r, s);
836 break;
837
838 case OP_S_PREVENT:
839 /* Prevent/allow medium removal */
840 s->retcode = cdsim_s_prevent(r, s);
841 break;
842
843 case OP_M_RDSUBQ:
844 /* Read subchannel */
845 s->retcode = cdsim_m_rdsubq(r, s);
846 break;
847
848 case OP_M_RDTOC:
849 /* Read TOC */
850 s->retcode = cdsim_m_rdtoc(r, s);
851 break;
852
853 case OP_M_PLAY:
854 /* Play audio (10) */
855 s->retcode = cdsim_m_play(r, s);
856 break;
857
858 case OP_M_PLAYMSF:
859 /* Play audio MSF */
860 s->retcode = cdsim_m_playmsf(r, s);
861 break;
862
863 case OP_M_PLAYTI:
864 /* Play audio track/index */
865 s->retcode = cdsim_m_playti(r, s);
866 break;
867
868 case OP_M_PAUSE:
869 /* Pause/resume */
870 s->retcode = cdsim_m_pause(r, s);
871 break;
872
873 case OP_L_PLAY:
874 /* Play audio (12) */
875 s->retcode = cdsim_l_play(r, s);
876 break;
877
878 case OP_L_READCD:
879 /* MMC Read CD (12) */
880 s->retcode = cdsim_l_readcd(r, s);
881 break;
882
883 default:
884 /* Command not implemented */
885 s->retcode = CDSIM_NOTSUPP;
886 break;
887 }
888
889 return (cdsim_sendpkt("cdsim", cdsim_rfd, s));
890 }
891
892
893 /*
894 * cdsim_init
895 * Initialize the CD-simulator subsystem
896 *
897 * Args:
898 * Nothing.
899 *
900 * Return:
901 * Nothing.
902 */
903 STATIC void
cdsim_init(void)904 cdsim_init(void)
905 {
906 int i,
907 j;
908 toc_hdr_t *h1 = (toc_hdr_t *)(void *) cdsim_tocdata1,
909 *h2 = (toc_hdr_t *)(void *) cdsim_tocdata2;
910 toc_trk_descr_t *t1,
911 *t2;
912
913 /* Initialize internal states */
914 cdsim_stat.status = CDSIM_STOPPED;
915 cdsim_stat.ntrks = CDSIM_NTRKS;
916 cdsim_stat.absaddr = 0;
917 cdsim_stat.reladdr = 0;
918 cdsim_stat.startaddr = 0;
919 cdsim_stat.endaddr = 0;
920 cdsim_stat.caddylock = 0;
921
922 /* Addresses for each simulated track and index */
923 for (i = 0; i < CDSIM_NTRKS; i++) {
924 if (i == 0)
925 cdsim_stat.trk[i].addr = 0;
926 else
927 cdsim_stat.trk[i].addr = (i * CDSIM_TRKLEN) - 150;
928
929 cdsim_stat.trk[i].nidxs = CDSIM_NIDXS;
930
931 for (j = 0; j < (int) cdsim_stat.trk[i].nidxs; j++) {
932 cdsim_stat.trk[i].iaddr[j] = (j * CDSIM_IDXLEN) +
933 cdsim_stat.trk[i].addr;
934 }
935 }
936
937 /* Simulated lead-out track */
938 cdsim_stat.trk[i].addr = (i * CDSIM_TRKLEN) - 150;
939 cdsim_stat.trk[i].nidxs = 0;
940 for (j = 0; j < CDSIM_NIDXS; j++)
941 cdsim_stat.trk[i].iaddr[j] = cdsim_stat.trk[i].addr;
942
943 /* Initialize inquiry data */
944 cdsim_inqdata.type = DEV_ROM;
945 cdsim_inqdata.pqual = 0;
946 cdsim_inqdata.qualif = 0;
947 cdsim_inqdata.rmb = 1;
948 cdsim_inqdata.ver = 2;
949 cdsim_inqdata.len = 38;
950 (void) strncpy((char *) cdsim_inqdata.vendor, "XMCD ", 8);
951 (void) strncpy((char *) cdsim_inqdata.prod, "CD-ROM SIMULATOR", 16);
952 (void) strncpy((char *) cdsim_inqdata.revnum, CDSIM_VERS, 4);
953
954 /* Initialize TOC data */
955 h1->data_len = h2->data_len = util_bswap16(
956 ((CDSIM_NTRKS + 1) * sizeof(toc_trk_descr_t)) + 2
957 );
958
959 h1->first_trk = h2->first_trk = 1;
960 h1->last_trk = h2->last_trk = CDSIM_NTRKS;
961
962 t1 = (toc_trk_descr_t *)(void *) (cdsim_tocdata1 + sizeof(toc_hdr_t));
963 t2 = (toc_trk_descr_t *)(void *) (cdsim_tocdata2 + sizeof(toc_hdr_t));
964
965 for (i = 0; i < CDSIM_NTRKS; i++) {
966 t1->preemph = t2->preemph = 0;
967 t1->copyallow = t2->copyallow = 0;
968 t1->trktype = t2->trktype = 0;
969 t1->audioch = t2->audioch = 0;
970 t1->adr = t2->adr = 0;
971 t1->trkno = t2->trkno = i + 1;
972 t1->abs_addr.logical = util_bswap32(cdsim_stat.trk[i].addr);
973 util_blktomsf(
974 cdsim_stat.trk[i].addr,
975 &t2->abs_addr.msf.min,
976 &t2->abs_addr.msf.sec,
977 &t2->abs_addr.msf.frame,
978 MSF_OFFSET
979 );
980
981 t1 = (toc_trk_descr_t *)(void *)
982 ((byte_t *)(void *) t1 + sizeof(toc_trk_descr_t));
983 t2 = (toc_trk_descr_t *)(void *)
984 ((byte_t *)(void *) t2 + sizeof(toc_trk_descr_t));
985 }
986
987 /* Lead-out track */
988 t1->preemph = t2->preemph = 0;
989 t1->copyallow = t2->copyallow = 0;
990 t1->trktype = t2->trktype = 0;
991 t1->audioch = t2->audioch = 0;
992 t1->adr = t2->adr = 0;
993 t1->trkno = t2->trkno = LEAD_OUT_TRACK;
994 t1->abs_addr.logical = util_bswap32(cdsim_stat.trk[i].addr);
995 util_blktomsf(
996 cdsim_stat.trk[i].addr,
997 &t2->abs_addr.msf.min,
998 &t2->abs_addr.msf.sec,
999 &t2->abs_addr.msf.frame,
1000 MSF_OFFSET
1001 );
1002 }
1003
1004
1005 /*
1006 * cdsim_main
1007 * The CD simulator main function
1008 *
1009 * Args:
1010 * sfd - The packet send file descriptor
1011 * rfd - The packet recv file descriptor
1012 *
1013 * Return:
1014 * Nothing.
1015 */
1016 void
cdsim_main(int sfd,int rfd)1017 cdsim_main(int sfd, int rfd)
1018 {
1019 int i,
1020 j;
1021 simpkt_t spkt,
1022 rpkt;
1023
1024 (void) fprintf(errfp,
1025 "CD-ROM simulator version %s (pid=%d) starting...\n",
1026 CDSIM_VERS, (int) getpid());
1027
1028 /* Install signal handlers */
1029 (void) util_signal(SIGINT, cdsim_sig);
1030 (void) util_signal(SIGTERM, cdsim_sig);
1031 (void) util_signal(SIGHUP, cdsim_sig);
1032
1033 cdsim_sfd = sfd;
1034 cdsim_rfd = rfd;
1035
1036 /* Initialize CD-ROM simulator */
1037 cdsim_init();
1038
1039 /* Main simulation service loop */
1040 for (;;) {
1041 /* Get SCSI request */
1042 if (!cdsim_getpkt("cdsim", cdsim_sfd, &rpkt))
1043 continue;
1044
1045 cdsim_now = time(NULL);
1046
1047 /* Update status */
1048 switch (cdsim_stat.status) {
1049 case CDSIM_PLAYING:
1050 cdsim_elapsed = cdsim_now - cdsim_start_time -
1051 cdsim_pause_elapsed - cdsim_prev_pause;
1052
1053 cdsim_stat.absaddr = cdsim_elapsed * FRAME_PER_SEC +
1054 cdsim_stat.startaddr;
1055
1056 cdsim_stat.trkno = 0;
1057 for (i = 0; i < (int) cdsim_stat.ntrks; i++) {
1058 if (cdsim_stat.trk[i].addr > cdsim_stat.absaddr)
1059 break;
1060 cdsim_stat.trkno++;
1061 }
1062
1063 cdsim_stat.idxno = 0;
1064 for (j = 0; j < (int) cdsim_stat.trk[i-1].nidxs; j++) {
1065 if (cdsim_stat.trk[i-1].iaddr[j] >
1066 cdsim_stat.absaddr)
1067 break;
1068 cdsim_stat.idxno++;
1069 }
1070
1071 cdsim_stat.reladdr = cdsim_stat.absaddr -
1072 cdsim_stat.trk[i-1].addr;
1073
1074 if (cdsim_stat.absaddr > cdsim_stat.endaddr) {
1075 cdsim_stat.status = CDSIM_STOPPED;
1076 cdsim_elapsed = 0;
1077 cdsim_start_time = 0;
1078 cdsim_pause_time = 0;
1079 cdsim_prev_pause = 0;
1080 cdsim_pause_elapsed = 0;
1081 }
1082 break;
1083
1084 case CDSIM_PAUSED:
1085 cdsim_pause_elapsed = cdsim_now - cdsim_pause_time;
1086 break;
1087 }
1088
1089 /* Process SCSI request */
1090 (void) cdsim_svccmd(&rpkt, &spkt);
1091 }
1092 }
1093
1094 #endif /* DEMO_ONLY */
1095
1096