4 * Hacked version of the linux cdrom.c kernel module - everything except the
5 * DVD handling ripped out and the rest rewritten to use raw SCSI commands
6 * on BSD/OS 4.2 (but should work with earlier versions as well).
14 #include <sys/ioctl.h>
15 #include </sys/dev/scsi/scsi.h>
16 #include </sys/dev/scsi/scsi_ioctl.h>
21 * Now get rid of the override/intercept macro so we can call the real ioctl()
26 #define CMD_READ_10 0x28
27 #define CMD_READ_TOC_PMA_ATIP 0x43
28 #define CMD_READ_CD 0xbe
29 #define CMD_START_STOP_UNIT 0x1b
31 #define CMD_SEND_KEY 0xa3
32 #define CMD_REPORT_KEY 0xa4
33 #define CMD_READ_DVD_STRUCTURE 0xad
35 #define copy_key(dest,src) memcpy((dest), (src), sizeof(dvd_key))
36 #define copy_chal(dest,src) memcpy((dest), (src), sizeof(dvd_challenge))
38 /* Define the Cdrom Generic Command structure */
46 scsi_user_sense_t
*sus
;
49 static int scsi_cmd(int, cgc_t
*);
50 static int cdrom_ioctl(int, u_long
, void *);
51 static int cdrom_tray_move(int, int);
52 static void cdrom_count_tracks(int, tracktype
*);
53 static int dvd_ioctl(int, u_long
, void *);
56 void dvd_cdrom_debug(int flag
)
62 * This is the published entry point. Actually applications should simply
63 * include <dvd.h> and not refer to this at all.
65 int dvd_cdrom_ioctl(int fd
, unsigned long cmd
, void *arg
)
71 return(dvd_ioctl(fd
, cmd
, arg
));
73 case CDROMREADTOCENTRY
:
79 case CDROM_DRIVE_STATUS
:
80 case CDROM_DISC_STATUS
:
81 return(cdrom_ioctl(fd
, cmd
, arg
));
83 return(ioctl(fd
, cmd
, arg
));
87 static void setup_report_key(cgc_t
*cgc
, u_int agid
, u_int type
)
90 cgc
->cdb
[0] = CMD_REPORT_KEY
;
91 cgc
->cdb
[10] = type
| (agid
<< 6);
107 cgc
->cdb
[9] = cgc
->buflen
;
111 static void setup_send_key(cgc_t
*cgc
, u_int agid
, u_int type
)
114 cgc
->cdb
[0] = CMD_SEND_KEY
;
115 cgc
->cdb
[10] = type
| (agid
<< 6);
128 cgc
->cdb
[9] = cgc
->buflen
;
132 static void cgc_init(cgc_t
*cgc
, void *buf
, int len
, int type
)
135 memset(cgc
, 0, sizeof (*cgc
));
138 cgc
->buf
= (u_char
*)buf
;
141 cgc
->timeout
= 5; /* 5 second timeout */
144 static int dvd_do_auth(int fd
, dvd_authinfo
*ai
)
149 rpc_state_t rpc_state
;
151 memset(buf
, 0, sizeof(buf
));
152 cgc_init(&cgc
, buf
, 0, SUC_READ
);
156 case DVD_LU_SEND_AGID
: /* LU data send */
157 setup_report_key(&cgc
, ai
->lsa
.agid
, 0);
158 if (ret
= scsi_cmd(fd
, &cgc
))
160 ai
->lsa
.agid
= buf
[7] >> 6;
162 case DVD_LU_SEND_KEY1
:
163 setup_report_key(&cgc
, ai
->lsk
.agid
, 2);
164 if (ret
= scsi_cmd(fd
, &cgc
))
166 copy_key(ai
->lsk
.key
, &buf
[4]);
168 case DVD_LU_SEND_CHALLENGE
:
169 setup_report_key(&cgc
, ai
->lsc
.agid
, 1);
170 if (ret
= scsi_cmd(fd
, &cgc
))
172 copy_chal(ai
->lsc
.chal
, &buf
[4]);
174 case DVD_LU_SEND_TITLE_KEY
: /* Post-auth key */
175 setup_report_key(&cgc
, ai
->lstk
.agid
, 4);
176 cgc
.cdb
[5] = ai
->lstk
.lba
;
177 cgc
.cdb
[4] = ai
->lstk
.lba
>> 8;
178 cgc
.cdb
[3] = ai
->lstk
.lba
>> 16;
179 cgc
.cdb
[2] = ai
->lstk
.lba
>> 24;
180 if (ret
= scsi_cmd(fd
, &cgc
))
182 ai
->lstk
.cpm
= (buf
[4] >> 7) & 1;
183 ai
->lstk
.cp_sec
= (buf
[4] >> 6) & 1;
184 ai
->lstk
.cgms
= (buf
[4] >> 4) & 3;
185 copy_key(ai
->lstk
.title_key
, &buf
[5]);
187 case DVD_LU_SEND_ASF
:
188 setup_report_key(&cgc
, ai
->lsasf
.agid
, 5);
189 if (ret
= scsi_cmd(fd
, &cgc
))
191 ai
->lsasf
.asf
= buf
[7] & 1;
193 case DVD_HOST_SEND_CHALLENGE
: /* LU data receive (LU changes state) */
194 setup_send_key(&cgc
, ai
->hsc
.agid
, 1);
196 copy_chal(&buf
[4], ai
->hsc
.chal
);
197 if (ret
= scsi_cmd(fd
, &cgc
))
199 ai
->type
= DVD_LU_SEND_KEY1
;
201 case DVD_HOST_SEND_KEY2
:
202 setup_send_key(&cgc
, ai
->hsk
.agid
, 3);
204 copy_key(&buf
[4], ai
->hsk
.key
);
205 if (ret
= scsi_cmd(fd
, &cgc
))
207 ai
->type
= DVD_AUTH_FAILURE
;
210 ai
->type
= DVD_AUTH_ESTABLISHED
;
212 case DVD_INVALIDATE_AGID
:
213 setup_report_key(&cgc
, ai
->lsa
.agid
, 0x3f);
214 if (ret
= scsi_cmd(fd
, &cgc
))
217 case DVD_LU_SEND_RPC_STATE
: /* Get region settings */
218 setup_report_key(&cgc
, 0, 8);
219 memset(&rpc_state
, 0, sizeof(rpc_state_t
));
220 cgc
.buf
= (char *) &rpc_state
;
221 if (ret
= scsi_cmd(fd
, &cgc
))
224 ai
->lrpcs
.rpc_scheme
= 0;
228 ai
->lrpcs
.type
= rpc_state
.type_code
;
229 ai
->lrpcs
.vra
= rpc_state
.vra
;
230 ai
->lrpcs
.ucca
= rpc_state
.ucca
;
231 ai
->lrpcs
.region_mask
= rpc_state
.region_mask
;
232 ai
->lrpcs
.rpc_scheme
= rpc_state
.rpc_scheme
;
235 case DVD_HOST_SEND_RPC_STATE
: /* Set region settings */
236 setup_send_key(&cgc
, 0, 6);
238 buf
[4] = ai
->hrpcs
.pdrc
;
239 if (ret
= scsi_cmd(fd
, &cgc
))
248 static int dvd_read_physical(int fd
, dvd_struct
*s
)
251 u_char buf
[4 + 4 * 20], *base
;
252 struct dvd_layer
*layer
;
255 cgc_init(&cgc
, buf
, sizeof(buf
), SUC_READ
);
256 cgc
.cdb
[0] = CMD_READ_DVD_STRUCTURE
;
257 cgc
.cdb
[6] = s
->physical
.layer_num
;
258 cgc
.cdb
[7] = s
->type
;
259 cgc
.cdb
[9] = cgc
.buflen
& 0xff;
261 if (ret
= scsi_cmd(fd
, &cgc
))
265 layer
= &s
->physical
.layer
[0];
267 /* place the data... really ugly, but at least we won't have to
268 worry about endianess in userspace or here. */
269 for (i
= 0; i
< 4; ++i
, base
+= 20, ++layer
)
271 memset(layer
, 0, sizeof(*layer
));
272 layer
->book_version
= base
[0] & 0xf;
273 layer
->book_type
= base
[0] >> 4;
274 layer
->min_rate
= base
[1] & 0xf;
275 layer
->disc_size
= base
[1] >> 4;
276 layer
->layer_type
= base
[2] & 0xf;
277 layer
->track_path
= (base
[2] >> 4) & 1;
278 layer
->nlayers
= (base
[2] >> 5) & 3;
279 layer
->track_density
= base
[3] & 0xf;
280 layer
->linear_density
= base
[3] >> 4;
281 layer
->start_sector
= base
[5] << 16 | base
[6] << 8 | base
[7];
282 layer
->end_sector
= base
[9] << 16 | base
[10] << 8 | base
[11];
283 layer
->end_sector_l0
= base
[13] << 16 | base
[14] << 8 | base
[15];
284 layer
->bca
= base
[16] >> 7;
289 static int dvd_read_copyright(int fd
, dvd_struct
*s
)
295 cgc_init(&cgc
, buf
, sizeof(buf
), SUC_READ
);
296 cgc
.cdb
[0] = CMD_READ_DVD_STRUCTURE
;
297 cgc
.cdb
[6] = s
->copyright
.layer_num
;
298 cgc
.cdb
[7] = s
->type
;
299 cgc
.cdb
[8] = cgc
.buflen
>> 8;
300 cgc
.cdb
[9] = cgc
.buflen
& 0xff;
302 if (ret
= scsi_cmd(fd
, &cgc
))
304 s
->copyright
.cpst
= buf
[4];
305 s
->copyright
.rmi
= buf
[5];
309 static int dvd_read_disckey(int fd
, dvd_struct
*s
)
315 size
= sizeof(s
->disckey
.value
) + 4;
317 if ((buf
= (u_char
*) malloc(size
)) == NULL
)
320 cgc_init(&cgc
, buf
, size
, SUC_READ
);
321 cgc
.cdb
[0] = CMD_READ_DVD_STRUCTURE
;
322 cgc
.cdb
[7] = s
->type
;
323 cgc
.cdb
[8] = size
>> 8;
324 cgc
.cdb
[9] = size
& 0xff;
325 cgc
.cdb
[10] = s
->disckey
.agid
<< 6;
327 if (!(ret
= scsi_cmd(fd
, &cgc
)))
328 memcpy(s
->disckey
.value
, &buf
[4], sizeof(s
->disckey
.value
));
333 static int dvd_read_bca(int fd
, dvd_struct
*s
)
339 cgc_init(&cgc
, buf
, sizeof(buf
), SUC_READ
);
340 cgc
.cdb
[0] = CMD_READ_DVD_STRUCTURE
;
341 cgc
.cdb
[7] = s
->type
;
342 cgc
.cdb
[9] = cgc
.buflen
= 0xff;
344 if (ret
= scsi_cmd(fd
, &cgc
))
346 s
->bca
.len
= buf
[0] << 8 | buf
[1];
347 if (s
->bca
.len
< 12 || s
->bca
.len
> 188)
349 memcpy(s
->bca
.value
, &buf
[4], s
->bca
.len
);
353 static int dvd_read_manufact(int fd
, dvd_struct
*s
)
359 size
= sizeof(s
->manufact
.value
) + 4;
361 if ((buf
= (u_char
*) malloc(size
)) == NULL
)
364 cgc_init(&cgc
, buf
, size
, SUC_READ
);
365 cgc
.cdb
[0] = CMD_READ_DVD_STRUCTURE
;
366 cgc
.cdb
[7] = s
->type
;
367 cgc
.cdb
[8] = size
>> 8;
368 cgc
.cdb
[9] = size
& 0xff;
370 if (ret
= scsi_cmd(fd
, &cgc
))
375 s
->manufact
.len
= buf
[0] << 8 | buf
[1];
376 if (s
->manufact
.len
< 0 || s
->manufact
.len
> 2048)
379 memcpy(s
->manufact
.value
, &buf
[4], s
->manufact
.len
);
384 static int dvd_read_struct(int fd
, dvd_struct
*s
)
388 case DVD_STRUCT_PHYSICAL
:
389 return dvd_read_physical(fd
, s
);
390 case DVD_STRUCT_COPYRIGHT
:
391 return dvd_read_copyright(fd
, s
);
392 case DVD_STRUCT_DISCKEY
:
393 return dvd_read_disckey(fd
, s
);
395 return dvd_read_bca(fd
, s
);
396 case DVD_STRUCT_MANUFACT
:
397 return dvd_read_manufact(fd
, s
);
403 static u_char scsi_cdblen
[8] = {6, 10, 10, 12, 12, 12, 10, 10};
405 static int scsi_cmd(int fd
, cgc_t
*cgc
)
407 int i
, scsistatus
, cdblen
;
409 struct scsi_user_cdb suc
;
412 if (cgc
->rw
!= SUC_READ
&& cgc
->rw
!= SUC_WRITE
)
415 suc
.suc_flags
= cgc
->rw
;
416 cdblen
= scsi_cdblen
[(cgc
->cdb
[0] >> 5) & 7];
417 suc
.suc_cdblen
= cdblen
;
418 bcopy(cgc
->cdb
, suc
.suc_cdb
, cdblen
);
419 suc
.suc_data
= cgc
->buf
;
420 suc
.suc_datalen
= cgc
->buflen
;
421 suc
.suc_timeout
= cgc
->timeout
;
422 if (ioctl(fd
, SCSIRAWCDB
, &suc
) == -1)
424 scsistatus
= suc
.suc_sus
.sus_status
;
427 * If the device returns a scsi sense error and debugging is enabled print
428 * some hopefully useful information on stderr.
430 if (scsistatus
&& debug
)
432 cp
= suc
.suc_sus
.sus_sense
;
433 fprintf(stderr
,"scsistatus = %x cdb =",
435 for (i
= 0; i
< cdblen
; i
++)
436 fprintf(stderr
, " %x", cgc
->cdb
[i
]);
437 fprintf(stderr
, "\nsense =");
438 for (i
= 0; i
< 16; i
++)
439 fprintf(stderr
, " %x", cp
[i
]);
440 fprintf(stderr
, "\n");
443 bcopy(&suc
.suc_sus
, cgc
->sus
, sizeof (struct scsi_user_sense
));
445 return(EIO
); /* generic i/o error for unsuccessful status */
450 * The entry point for the DVDioctls for BSD/OS.
452 static int dvd_ioctl(int fd
, u_long cmd
, void *arg
)
458 case DVD_READ_STRUCT
:
459 ret
= dvd_read_struct(fd
, (dvd_struct
*)arg
);
462 return(ret
? -1 : 0);
464 ret
= dvd_do_auth(fd
, (dvd_authinfo
*)arg
);
467 return(ret
? -1 : 0);
475 * The entry point for the CDROMioctls for BSD/OS
477 static int cdrom_read_block(int, cgc_t
*, int, int, int, int);
478 static int cdrom_read_cd(int, cgc_t
*, int, int, int );
479 int cdrom_blocksize(int, int );
482 int msf_to_lba(char m
, char s
, char f
)
484 return (((m
* CD_SECS
) + s
) * CD_FRAMES
+ f
) - CD_MSF_OFFSET
;
487 cdrom_ioctl(int fd
, u_long cmd
, void *arg
)
498 struct cdrom_msf
*msf
;
499 int blocksize
= 0, format
= 0, lba
;
504 blocksize
= CD_FRAMESIZE_RAW
;
507 blocksize
= CD_FRAMESIZE
;
511 blocksize
= CD_FRAMESIZE_RAW0
;
514 msf
= (struct cdrom_msf
*)arg
;
515 lba
= msf_to_lba(msf
->cdmsf_min0
,msf
->cdmsf_sec0
,
521 cgc_init(&cgc
, arg
, blocksize
, SUC_READ
);
522 ret
= cdrom_read_block(fd
, &cgc
, lba
, 1, format
, blocksize
);
526 * SCSI-II devices are not required to support CMD_READ_CD (which specifies
527 * the blocksize to read) so try switching the block size with a mode select,
528 * doing the normal read sector command and then changing the sector size back
531 * If the program dies before changing the blocksize back sdopen()
532 * in the kernel will fail opens with a message that looks something like:
534 * "sr1: blksize 2336 not multiple of 512: cannot use"
536 * At that point the drive has to be power cycled (or reset in some other way).
538 if (ret
= cdrom_blocksize(fd
, blocksize
))
540 ret
= cdrom_read_cd(fd
, &cgc
, lba
, blocksize
, 1);
541 ret
|= cdrom_blocksize(fd
, 2048);
545 case CDROMREADTOCHDR
:
547 struct cdrom_tochdr
*tochdr
= (struct cdrom_tochdr
*) arg
;
550 cgc_init(&cgc
, buffer
, sizeof (buffer
), SUC_READ
);
551 cgc
.cdb
[0] = CMD_READ_TOC_PMA_ATIP
;
552 cgc
.cdb
[1] = 0x2; /* MSF */
553 cgc
.cdb
[8] = 12; /* LSB of length */
555 ret
= scsi_cmd(fd
, &cgc
);
558 tochdr
->cdth_trk0
= buffer
[2];
559 tochdr
->cdth_trk1
= buffer
[3];
563 case CDROMREADTOCENTRY
:
565 struct cdrom_tocentry
*tocentry
= (struct cdrom_tocentry
*) arg
;
568 cgc_init(&cgc
, buffer
, sizeof (buffer
), SUC_READ
);
569 cgc
.cdb
[0] = CMD_READ_TOC_PMA_ATIP
;
570 cgc
.cdb
[1] = (tocentry
->cdte_format
== CDROM_MSF
) ? 0x02 : 0;
571 cgc
.cdb
[6] = tocentry
->cdte_track
;
572 cgc
.cdb
[8] = 12; /* LSB of length */
574 ret
= scsi_cmd(fd
, &cgc
);
578 tocentry
->cdte_ctrl
= buffer
[5] & 0xf;
579 tocentry
->cdte_adr
= buffer
[5] >> 4;
580 tocentry
->cdte_datamode
= (tocentry
->cdte_ctrl
& 0x04) ? 1 : 0;
581 if (tocentry
->cdte_format
== CDROM_MSF
)
583 tocentry
->cdte_addr
.msf
.minute
= buffer
[9];
584 tocentry
->cdte_addr
.msf
.second
= buffer
[10];
585 tocentry
->cdte_addr
.msf
.frame
= buffer
[11];
588 tocentry
->cdte_addr
.lba
= (((((buffer
[8] << 8)
594 case CDROMEJECT
: /* NO-OP for now */
595 ret
= cdrom_tray_move(fd
, 1);
598 ret
= cdrom_tray_move(fd
, 0);
601 * This sucks but emulates the expected behaviour. Instead of the return
602 * value being the actual status a success/fail indicator should have been
603 * returned and the 3rd arg to the ioctl should have been an 'int *' to update
604 * with the actual status. Both the drive and disc status ioctl calls are
605 * similarily braindamaged.
607 case CDROM_DRIVE_STATUS
:
608 return(CDS_NO_INFO
); /* XXX */
609 case CDROM_DISC_STATUS
:
614 cdrom_count_tracks(fd
, &tracks
);
616 return(tracks
.error
);
617 if (tracks
.audio
> 0)
619 cnt
= tracks
.data
+ tracks
.cdi
+ tracks
.xa
;
635 return(ret
? -1 : 0);
638 static int cdrom_read_cd(int fd
, cgc_t
*cgc
, int lba
, int blocksize
, int nblocks
)
641 memset(&cgc
->cdb
, 0, sizeof(cgc
->cdb
));
642 cgc
->cdb
[0] = CMD_READ_10
;
643 cgc
->cdb
[2] = (lba
>> 24) & 0xff;
644 cgc
->cdb
[3] = (lba
>> 16) & 0xff;
645 cgc
->cdb
[4] = (lba
>> 8) & 0xff;
646 cgc
->cdb
[5] = lba
& 0xff;
647 cgc
->cdb
[6] = (nblocks
>> 16) & 0xff;
648 cgc
->cdb
[7] = (nblocks
>> 8) & 0xff;
649 cgc
->cdb
[8] = nblocks
& 0xff;
650 cgc
->buflen
= blocksize
* nblocks
;
651 return(scsi_cmd(fd
, cgc
));
654 static int cdrom_read_block(int fd
, cgc_t
*cgc
,
655 int lba
, int nblocks
, int format
, int blksize
)
658 memset(&cgc
->cdb
, 0, sizeof(cgc
->cdb
));
659 cgc
->cdb
[0] = CMD_READ_CD
;
660 /* expected sector size - cdda,mode1,etc. */
661 cgc
->cdb
[1] = format
<< 2;
662 /* starting address */
663 cgc
->cdb
[2] = (lba
>> 24) & 0xff;
664 cgc
->cdb
[3] = (lba
>> 16) & 0xff;
665 cgc
->cdb
[4] = (lba
>> 8) & 0xff;
666 cgc
->cdb
[5] = lba
& 0xff;
667 /* number of blocks */
668 cgc
->cdb
[6] = (nblocks
>> 16) & 0xff;
669 cgc
->cdb
[7] = (nblocks
>> 8) & 0xff;
670 cgc
->cdb
[8] = nblocks
& 0xff;
671 cgc
->buflen
= blksize
* nblocks
;
673 /* set the header info returned */
676 case CD_FRAMESIZE_RAW0
:
679 case CD_FRAMESIZE_RAW1
:
682 case CD_FRAMESIZE_RAW
:
688 return(scsi_cmd(fd
, cgc
));
691 static void cdrom_count_tracks(int fd
, tracktype
*tracks
)
693 struct cdrom_tochdr header
;
694 struct cdrom_tocentry entry
;
697 memset(tracks
, 0, sizeof (*tracks
));
698 ret
= cdrom_ioctl(fd
, CDROMREADTOCHDR
, &header
);
700 * This whole business is a crock anyhow so we don't bother distinguishing
701 * between no media, drive not ready, etc and on any error just say we have
706 tracks
->error
= CDS_NO_INFO
;
710 entry
.cdte_format
= CDROM_MSF
;
711 for (i
= header
.cdth_trk0
; i
<= header
.cdth_trk1
; i
++)
713 entry
.cdte_track
= i
;
714 if (cdrom_ioctl(fd
, CDROMREADTOCENTRY
, &entry
))
716 tracks
->error
= CDS_NO_INFO
;
719 if (entry
.cdte_ctrl
& CDROM_DATA_TRACK
)
721 if (entry
.cdte_format
== 0x10)
723 else if (entry
.cdte_format
== 0x20)
734 static int cdrom_tray_move(int fd
, int flag
)
738 cgc_init(&cgc
, NULL
, 0, SUC_READ
);
739 cgc
.cdb
[0] = CMD_START_STOP_UNIT
;
740 cgc
.cdb
[1] = 1; /* immediate */
741 cgc
.cdb
[4] = flag
? 0x2 : 0x3; /* eject : close */
742 return(scsi_cmd(fd
, &cgc
));
746 * Required when we need to use READ_10 to issue other than 2048 block
749 int cdrom_blocksize(int fd
, int size
)
752 struct modesel_head mh
;
754 memset(&mh
, 0, sizeof(mh
));
755 mh
.block_desc_length
= 0x08;
756 mh
.block_length_med
= (size
>> 8) & 0xff;
757 mh
.block_length_lo
= size
& 0xff;
759 memset(&cgc
, 0, sizeof(cgc
));
763 cgc
.buflen
= sizeof(mh
);
764 cgc
.buf
= (u_char
*) &mh
;
766 mh
.block_desc_length
= 0x08;
767 mh
.block_length_med
= (size
>> 8) & 0xff;
768 mh
.block_length_lo
= size
& 0xff;
769 return(scsi_cmd(fd
, &cgc
));