2 * This file has been modified for the cdrkit suite.
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
13 /* @(#)ioctl.c 1.22 06/02/19 Copyright 1998,1999,2000 Heiko Eissfeldt, Copyright 2006 J. Schilling */
15 * CopyPolicy: GNU Public License 2 applies
16 * Copyright (C) 1999 Heiko Eissfeldt heiko@colossus.escape.de
18 * Ioctl interface module for cdrom drive access
20 * Solaris ATAPI cdrom drives are untested!
34 #include <sys/ioctl.h>
39 #include <usal/scsitransp.h>
43 /* some include file locations have changed with newer kernels */
44 #if defined (__linux__)
45 # if LINUX_VERSION_CODE > 0x10300 + 97
46 # if LINUX_VERSION_CODE < 0x200ff
47 # include <linux/sbpcd.h>
48 # include <linux/ucdrom.h>
50 # if !defined(CDROM_SELECT_SPEED)
51 # include <linux/ucdrom.h>
57 #include "byteorder.h"
58 #include "interface.h"
63 #include "exitcodes.h"
68 #if defined (HAVE_IOCTL_INTERFACE)
69 #if !defined(sun) && !defined(__sun) && !(defined(__FreeBSD__) && (__FreeBSD_version >= 501112))
70 static struct cdrom_read_audio arg;
73 #if (defined(__FreeBSD__) && __FreeBSD_version >= 400014) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
74 static unsigned sector_size;
79 static void EnableCdda_cooked(SCSI *usalp, int fAudioMode, unsigned uSectorsize);
81 static void EnableCdda_cooked(SCSI *usalp, int fAudioMode, unsigned uSectorsize)
83 #if (defined(__FreeBSD__) && __FreeBSD_version >= 400014) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
84 if (usalp && usalp->verbose)
85 fprintf(stderr, "EnableCdda_cooked (CDRIOCSETBLOCKSIZE)...\n");
88 if (ioctl(global.cooked_fd, CDRIOCGETBLOCKSIZE, §or_size) ==-1)
89 sector_size = CD_FRAMESIZE;
90 ioctl(global.cooked_fd, CDRIOCSETBLOCKSIZE, &uSectorsize);
92 ioctl(global.cooked_fd, CDRIOCSETBLOCKSIZE, §or_size);
94 #if defined CDIOCSETCDDA
95 if (usalp && usalp->verbose) {
96 fprintf(stderr, "EnableCdda_cooked (CDIOCSETCDDA)...\n");
97 if (uSectorsize != CD_FRAMESIZE_RAW)
98 fprintf(stderr, "non audio sector size is ignored.\n");
101 ioctl(global.cooked_fd, CDIOCSETCDDA, &fAudioMode);
103 fprintf(stderr, "EnableCdda_cooked (CDIOCSETCDDA) is not available...\n");
110 static unsigned ReadToc_cooked(SCSI *x);
112 /* read the table of contents (toc) via the ioctl interface */
113 static unsigned ReadToc_cooked(SCSI *x)
117 struct cdrom_tochdr hdr;
118 struct cdrom_tocentry entry[100];
119 struct cdrom_tocentry entryMSF[100];
121 if (x && x->verbose) {
122 fprintf(stderr, "ReadToc_cooked (CDROMREADTOCHDR)...\n");
125 /* get TocHeader to find out how many entries there are */
126 err = ioctl( global.cooked_fd, CDROMREADTOCHDR, &hdr );
131 fprintf( stderr, "Please run this program setuid root.\n");
132 perror("cooked: Read TOC ");
133 exit( DEVICE_ERROR );
135 fprintf( stderr, "can't get TocHeader (error %d).\n", err );
139 /* get all TocEntries */
140 for ( i = 0; i < hdr.cdth_trk1; i++ ) {
141 entryMSF[i].cdte_track = 1+i;
142 entryMSF[i].cdte_format = CDROM_MSF;
143 err = ioctl( global.cooked_fd, CDROMREADTOCENTRY, &entryMSF[i] );
146 fprintf( stderr, "can't get TocEntry #%d msf (error %d).\n", i+1, err );
150 entryMSF[i].cdte_track = CDROM_LEADOUT;
151 entryMSF[i].cdte_format = CDROM_MSF;
152 err = ioctl( global.cooked_fd, CDROMREADTOCENTRY, &entryMSF[i] );
155 fprintf( stderr, "can't get TocEntry LEADOUT msf (error %d).\n", err );
158 tracks = hdr.cdth_trk1+1;
160 for (i = 0; i < tracks; i++) {
161 toc[i].bFlags = (entry[i].cdte_adr << 4) | (entry[i].cdte_ctrl & 0x0f);
162 toc[i].bTrack = entry[i].cdte_track;
163 toc[i].mins = entry[i].cdte_addr.msf.minute;
164 toc[i].secs = entry[i].cdte_addr.msf.second;
165 toc[i].frms = entry[i].cdte_addr.msf.frame;
168 /* get all TocEntries now in lba format */
169 for ( i = 0; i < hdr.cdth_trk1; i++ ) {
170 entry[i].cdte_track = 1+i;
171 entry[i].cdte_format = CDROM_LBA;
172 err = ioctl( global.cooked_fd, CDROMREADTOCENTRY, &entry[i] );
175 fprintf( stderr, "can't get TocEntry #%d lba (error %d).\n", i+1, err );
178 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
179 entry[i].cdte_addr.lba = be32_to_cpu(entry[i].cdte_addr.lba);
182 entry[i].cdte_track = CDROM_LEADOUT;
183 entry[i].cdte_format = CDROM_LBA;
184 err = ioctl( global.cooked_fd, CDROMREADTOCENTRY, &entry[i] );
187 fprintf( stderr, "can't get TocEntry LEADOUT lba (error %d).\n", err );
190 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
191 entry[i].cdte_addr.lba = be32_to_cpu(entry[i].cdte_addr.lba);
194 for (i = 0; i < tracks; i++) {
196 (entry[i].cdte_adr << 4) | (entry[i].cdte_ctrl & 0x0f),
199 entry[i].cdte_addr.lba,
200 entryMSF[i].cdte_addr.msf.minute,
201 entryMSF[i].cdte_addr.msf.second,
202 entryMSF[i].cdte_addr.msf.frame);
206 return --tracks; /* without lead-out */
209 static void trash_cache_cooked(UINT4 *p, unsigned lSector,
210 unsigned SectorBurstVal);
212 static void trash_cache_cooked(UINT4 *p, unsigned lSector,
213 unsigned SectorBurstVal)
215 /* trash the cache */
217 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
218 #if defined(__FreeBSD__) && __FreeBSD_version >= 501112
219 pread(global.cooked_fd, (void *) &p[0], 3*CD_FRAMESIZE_RAW,
220 find_an_off_sector(lSector, SectorBurstVal)*CD_FRAMESIZE_RAW);
222 static struct cdrom_read_audio arg2;
224 arg2.address.lba = find_an_off_sector(lSector, SectorBurstVal);
225 arg2.addr_format = CDROM_LBA;
227 arg2.buffer = (unsigned char *) &p[0];
229 ioctl(global.cooked_fd, CDROMREADAUDIO, &arg2);
232 #if defined __linux__
233 static struct cdrom_read_audio arg2;
235 arg2.addr.lba = find_an_off_sector(lSector, SectorBurstVal);
236 arg2.addr_format = CDROM_LBA;
238 arg2.buf = (unsigned char *) &p[0];
240 ioctl(global.cooked_fd, CDROMREADAUDIO, &arg2);
242 #if defined __sun || (defined HAVE_SYS_CDIO_H && defined CDROM_DA_NO_SUBCODE)
243 struct cdrom_cdda suncdda;
245 suncdda.cdda_addr = lSector;
246 suncdda.cdda_length = SectorBurstVal*CD_FRAMESIZE_RAW;
247 suncdda.cdda_data = (char *) &p[0];
248 suncdda.cdda_subcode = CDROM_DA_NO_SUBCODE;
250 ioctl(global.cooked_fd, CDROMCDDA, &suncdda);
254 static void ReadCdRomData_cooked(SCSI *x, UINT4 *p, unsigned lSector,
255 unsigned SectorBurstVal);
256 /* read 'SectorBurst' adjacent sectors of data sectors
257 * to Buffer '*p' beginning at sector 'lSector'
259 static void ReadCdRomData_cooked(SCSI *x, UINT4 *p, unsigned lSector,
260 unsigned SectorBurstVal)
264 if (x && x->verbose) {
265 fprintf(stderr, "ReadCdRomData_cooked (lseek & read)...\n");
268 if ((retval = lseek(global.cooked_fd, lSector*CD_FRAMESIZE, SEEK_SET))
269 != (int)lSector*CD_FRAMESIZE) { perror("cannot seek sector"); }
270 if ((retval = read(global.cooked_fd, p, SectorBurstVal*CD_FRAMESIZE))
271 != (int)SectorBurstVal*CD_FRAMESIZE) { perror("cannot read sector"); }
276 static int ReadCdRom_cooked(SCSI *x, UINT4 *p, unsigned lSector,
277 unsigned SectorBurstVal);
278 /* read 'SectorBurst' adjacent sectors of audio sectors
279 * to Buffer '*p' beginning at sector 'lSector'
281 static int ReadCdRom_cooked(SCSI *x, UINT4 *p, unsigned lSector,
282 unsigned SectorBurstVal)
285 static int nothing_read = 1;
287 /* read 2352 bytes audio data */
288 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
289 #if defined(__FreeBSD__) && __FreeBSD_version >= 501112
290 if (x && x->verbose) {
291 fprintf(stderr, "ReadCdRom_cooked (pread)...\n");
296 if (pread(global.cooked_fd, (void *) &p[0], SectorBurstVal*CD_FRAMESIZE_RAW,
297 lSector*CD_FRAMESIZE_RAW) == -1)
300 arg.address.lba = lSector;
301 arg.addr_format = CDROM_LBA;
302 arg.nframes = SectorBurstVal;
303 arg.buffer = (unsigned char *) &p[0];
305 if (x && x->verbose) {
306 fprintf(stderr, "ReadCdRom_cooked (CDROMREADAUDIO)...\n");
310 err = ioctl(global.cooked_fd, CDROMREADAUDIO, &arg);
313 #if defined __linux__
314 arg.addr.lba = lSector;
315 arg.addr_format = CDROM_LBA;
316 arg.nframes = SectorBurstVal;
317 arg.buf = (unsigned char *) &p[0];
319 if (x && x->verbose) {
320 fprintf(stderr, "ReadCdRom_cooked (CDROMREADAUDIO)...\n");
324 err = ioctl(global.cooked_fd, CDROMREADAUDIO, &arg);
326 #if defined __sun || (defined HAVE_SYS_CDIO_H && defined CDROM_DA_NO_SUBCODE)
327 struct cdrom_cdda suncdda;
329 suncdda.cdda_addr = lSector;
330 suncdda.cdda_length = SectorBurstVal*CD_FRAMESIZE_RAW;
331 suncdda.cdda_data = (char *) &p[0];
332 suncdda.cdda_subcode = CDROM_DA_NO_SUBCODE;
334 if (x && x->verbose) {
335 fprintf(stderr, "ReadCdRom_cooked (CDROMCDDA)...\n");
339 err = ioctl(global.cooked_fd, CDROMCDDA, &suncdda);
344 trash_cache_cooked(p, lSector, SectorBurstVal);
347 } while ((err) && (retry_count < 30));
349 if (x->silent == 0) {
352 if (nothing_read && (errno == EINVAL || errno == EIO))
353 fprintf( stderr, "Sorry, this driver and/or drive does not support cdda reading.\n");
354 perror("cooked: Read cdda ");
355 fprintf(stderr, " sector %u + %u, buffer %p + %x\n", lSector, SectorBurstVal, p, global.shmsize);
357 fprintf(stderr, "can't read frame #%u (error %d).\n",
361 return SectorBurstVal - 1;
366 return SectorBurstVal;
369 static int StopPlay_cooked(SCSI *x);
370 static int StopPlay_cooked(SCSI *x)
372 if (x && x->verbose) {
373 fprintf(stderr, "StopPlay_cooked (CDROMSTOP)...\n");
376 return ioctl( global.cooked_fd, CDROMSTOP, 0 ) ? 0 : -1;
379 static int Play_at_cooked(SCSI *x, unsigned int from_sector,
380 unsigned int sectors);
381 static int Play_at_cooked(SCSI *x, unsigned int from_sector,
382 unsigned int sectors)
384 struct cdrom_msf cmsf;
387 if (x && x->verbose) {
388 fprintf(stderr, "Play_at_cooked (CDROMSTART & CDROMPLAYMSF)... (%u-%u)",
389 from_sector, from_sector+sectors-1);
391 fprintf(stderr, "\n");
394 cmsf.cdmsf_min0 = (from_sector + 150) / (60*75);
395 cmsf.cdmsf_sec0 = ((from_sector + 150) / 75) % 60;
396 cmsf.cdmsf_frame0 = (from_sector + 150) % 75;
397 cmsf.cdmsf_min1 = (from_sector + 150 + sectors) / (60*75);
398 cmsf.cdmsf_sec1 = ((from_sector + 150 + sectors) / 75) % 60;
399 cmsf.cdmsf_frame1 = (from_sector + 150 + sectors) % 75;
402 /* makes index scanning under FreeBSD too slow */
403 if (( retval = ioctl( global.cooked_fd, CDROMSTART, 0 )) != 0){
407 if (( retval = ioctl( global.cooked_fd, CDROMPLAYMSF, &cmsf )) != 0){
413 /* request sub-q-channel information. This function may cause confusion
414 * for a drive, when called in the sampling process.
416 static subq_chnl *ReadSubQ_cooked(SCSI *x, unsigned char sq_format,
419 struct cdrom_subchnl sub_ch;
421 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
422 struct cd_sub_channel_info sub_ch_info;
424 if (x && x->verbose) {
425 fprintf(stderr, "ReadSubQ_cooked (CDROM_GET_MCN or CDROMSUBCHNL)...\n");
428 sub_ch.address_format = CD_MSF_FORMAT;
429 sub_ch.track = track;
430 sub_ch.data_len = sizeof(struct cd_sub_channel_info);
431 sub_ch.data = &sub_ch_info;
434 case GET_CATALOGNUMBER:
435 sub_ch.data_format = CD_MEDIA_CATALOG;
437 if (x && x->verbose) {
438 fprintf(stderr, "ReadSubQ_cooked (CDROM_GET_MCN or CDROMSUBCHNL)...\n");
442 case GET_CATALOGNUMBER:
444 #if defined CDROM_GET_MCN
445 if (!(err = ioctl(global.cooked_fd, CDROM_GET_MCN, (struct cdrom_mcn *) SubQbuffer))) {
446 subq_chnl *SQp = (subq_chnl *) SubQbuffer;
447 subq_catalog *SQPp = (subq_catalog *) &SQp->data;
449 memmove(SQPp->media_catalog_number, SQp, sizeof (SQPp->media_catalog_number));
451 SQPp->mc_valid = 0x80;
458 case GET_POSITIONDATA:
459 #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
460 sub_ch.data_format = CD_CURRENT_POSITION;
462 #if defined (__linux__)
463 sub_ch.cdsc_format = CDROM_MSF;
465 if (!(err = ioctl(global.cooked_fd, CDROMSUBCHNL, &sub_ch))) {
466 /* copy to SubQbuffer */
467 subq_chnl *SQp = (subq_chnl *) (SubQbuffer);
468 subq_position *SQPp = (subq_position *) SQp->data;
469 SQp->audio_status = sub_ch.cdsc_audiostatus;
470 SQp->format = sub_ch.cdsc_format;
471 SQp->control_adr = (sub_ch.cdsc_adr << 4) | (sub_ch.cdsc_ctrl & 0x0f);
472 SQp->track = sub_ch.cdsc_trk;
473 SQp->index = sub_ch.cdsc_ind;
474 SQPp->abs_min = sub_ch.cdsc_absaddr.msf.minute;
475 SQPp->abs_sec = sub_ch.cdsc_absaddr.msf.second;
476 SQPp->abs_frame = sub_ch.cdsc_absaddr.msf.frame;
477 SQPp->trel_min = sub_ch.cdsc_reladdr.msf.minute;
478 SQPp->trel_sec = sub_ch.cdsc_reladdr.msf.second;
479 SQPp->trel_frame = sub_ch.cdsc_reladdr.msf.frame;
483 fprintf( stderr, "Please run this program setuid root.\n");
484 perror("cooked: Read subq ");
485 exit( DEVICE_ERROR );
487 fprintf(stderr, "can't read sub q channel (error %d).\n", err);
488 exit( DEVICE_ERROR );
495 return (subq_chnl *)(SubQbuffer);
499 static void SpeedSelect_cooked(SCSI *x, unsigned speed);
501 static void SpeedSelect_cooked(SCSI *x, unsigned speed)
503 if (x && x->verbose) {
504 fprintf(stderr, "SpeedSelect_cooked (CDROM_SELECT_SPEED)...\n");
507 #ifdef CDROM_SELECT_SPEED
508 /* CAUTION!!!!! Non standard ioctl parameter types here!!!! */
509 if ((err = ioctl(global.cooked_fd, CDROM_SELECT_SPEED, speed))) {
512 fprintf( stderr, "Please run this program setuid root.\n");
513 perror("cooked: Speed select ");
516 fprintf(stderr, "can't set speed %d (error %d).\n", speed, err);
517 exit( DEVICE_ERROR );
523 /* set function pointers to use the ioctl routines */
524 void SetupCookedIoctl(char *pdev_name)
526 #if (HAVE_ST_RDEV == 1)
527 struct stat statstruct;
529 if (fstat(global.cooked_fd, &statstruct)) {
530 fprintf(stderr, "cannot stat cd %d (%s)\n",global.cooked_fd, pdev_name);
533 #if defined __linux__
534 switch (major(statstruct.st_rdev)) {
535 case CDU31A_CDROM_MAJOR: /* sony cdu-31a/33a */
536 global.nsectors = 13;
537 if (global.nsectors >= 14) {
541 case MATSUSHITA_CDROM_MAJOR: /* sbpcd 1 */
542 case MATSUSHITA_CDROM2_MAJOR: /* sbpcd 2 */
543 case MATSUSHITA_CDROM3_MAJOR: /* sbpcd 3 */
544 case MATSUSHITA_CDROM4_MAJOR: /* sbpcd 4 */
545 /* some are more compatible than others */
546 global.nsectors = 13;
552 err = ioctl(global.cooked_fd, CDROMAUDIOBUFSIZ, global.nsectors);
554 switch (major(statstruct.st_rdev)) {
555 case MATSUSHITA_CDROM_MAJOR: /* sbpcd 1 */
556 case MATSUSHITA_CDROM2_MAJOR: /* sbpcd 2 */
557 case MATSUSHITA_CDROM3_MAJOR: /* sbpcd 3 */
558 case MATSUSHITA_CDROM4_MAJOR: /* sbpcd 4 */
560 perror("ioctl(CDROMAUDIOBUFSIZ)");
565 EnableCdda = EnableCdda_cooked;
566 ReadCdRom = ReadCdRom_cooked;
567 ReadCdRomData = (int (*)(SCSI *, unsigned char *, unsigned, unsigned)) ReadCdRomData_cooked;
568 doReadToc = ReadToc_cooked;
570 ReadSubQ = ReadSubQ_cooked;
571 ReadSubChannels = NULL;
572 SelectSpeed = SpeedSelect_cooked;
573 Play_at = Play_at_cooked;
574 StopPlay = StopPlay_cooked;
575 trash_cache = trash_cache_cooked;
576 ReadLastAudio = NULL;