1 /* @(#)ioctl.c	1.39 10/12/19 Copyright 1998,1999,2000 Heiko Eissfeldt, Copyright 2006-2010 J. Schilling */
2 #include "config.h"
3 #ifndef lint
4 static	UConst char sccsid[] =
5 "@(#)ioctl.c	1.39 10/12/19 Copyright 1998,1999,2000 Heiko Eissfeldt, Copyright 2006-2010 J. Schilling";
6 
7 #endif
8 /*
9  * Copyright (C) 1999 Heiko Eissfeldt heiko@colossus.escape.de
10  * Copyright (c) 2006-2010 J. Schilling
11  *
12  * Ioctl interface module for cdrom drive access
13  *
14  * Solaris ATAPI cdrom drives are untested!
15  *
16  */
17 /*
18  * The contents of this file are subject to the terms of the
19  * Common Development and Distribution License, Version 1.0 only
20  * (the "License").  You may not use this file except in compliance
21  * with the License.
22  *
23  * See the file CDDL.Schily.txt in this distribution for details.
24  * A copy of the CDDL is also available via the Internet at
25  * http://www.opensource.org/licenses/cddl1.txt
26  *
27  * When distributing Covered Code, include this CDDL HEADER in each
28  * file and include the License file CDDL.Schily.txt from this distribution.
29  */
30 
31 #include "config.h"
32 #include <schily/stdio.h>
33 #include <schily/standard.h>
34 #include <schily/stdlib.h>
35 #include <schily/unistd.h>
36 #include <schily/string.h>
37 #include <schily/errno.h>
38 #include <schily/signal.h>
39 #include <schily/fcntl.h>
40 #include <schily/assert.h>
41 #include <schily/ioctl.h>
42 #include <schily/stat.h>
43 #include <schily/schily.h>
44 #include <schily/nlsdefs.h>
45 #include <schily/device.h>
46 
47 #include <scg/scsitransp.h>
48 
49 #include "mycdrom.h"
50 #include "lowlevel.h"
51 /* some include file locations have changed with newer kernels */
52 #if defined(__linux__)
53 # if LINUX_VERSION_CODE > 0x10300 + 97
54 #  if LINUX_VERSION_CODE < 0x200ff
55 #   include <linux/sbpcd.h>
56 #   include <linux/ucdrom.h>
57 #  endif
58 #  if !defined(CDROM_SELECT_SPEED)
59 #   include <linux/ucdrom.h>
60 #  endif
61 # endif
62 #endif
63 
64 #include "mytype.h"
65 #include "byteorder.h"
66 #include "interface.h"
67 #include "toc.h"
68 #include "cdda2wav.h"
69 #include "ioctl.h"
70 #include "global.h"
71 #include "exitcodes.h"
72 
73 #include <schily/utypes.h>
74 #include <cdrecord.h>
75 
76 #if defined(HAVE_IOCTL_INTERFACE)
77 #if  !defined(sun) && !defined(__sun) && \
78 		!((defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) && \
79 				(__FreeBSD_version >= 501112))
80 static struct cdrom_read_audio arg;
81 #endif
82 
83 #if ((defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) && \
84 				__FreeBSD_version >= 400014) || \
85 					defined(__DragonFly__)
86 static unsigned sector_size;
87 #endif
88 
89 static int err;
90 
91 static void	EnableCdda_cooked	__PR((SCSI *scgp, int fAudioMode,
92 							unsigned uSectorsize));
93 /* ARGSUSED */
94 static void
EnableCdda_cooked(scgp,fAudioMode,uSectorsize)95 EnableCdda_cooked(scgp, fAudioMode, uSectorsize)
96 	SCSI		*scgp;
97 	int		fAudioMode;
98 	unsigned	uSectorsize;
99 {
100 #if	((defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) && \
101 				__FreeBSD_version >= 400014) || \
102 					defined(__DragonFly__)
103 	if (scgp && scgp->verbose)
104 		fprintf(stderr, _("EnableCdda_cooked (CDRIOCSETBLOCKSIZE)...\n"));
105 
106 	if (fAudioMode) {
107 		if (ioctl(global.cooked_fd, CDRIOCGETBLOCKSIZE,
108 							&sector_size) == -1)
109 			sector_size = CD_FRAMESIZE;
110 		ioctl(global.cooked_fd, CDRIOCSETBLOCKSIZE, &uSectorsize);
111 	} else
112 		ioctl(global.cooked_fd, CDRIOCSETBLOCKSIZE, &sector_size);
113 #else
114 #if	defined	CDIOCSETCDDA
115 	if (scgp && scgp->verbose) {
116 		fprintf(stderr, _("EnableCdda_cooked (CDIOCSETCDDA)...\n"));
117 		if (uSectorsize != CD_FRAMESIZE_RAW)
118 			fprintf(stderr, _("non audio sector size is ignored.\n"));
119 	}
120 
121 	ioctl(global.cooked_fd, CDIOCSETCDDA, &fAudioMode);
122 #else
123 	fprintf(stderr,
124 		_("EnableCdda_cooked (CDIOCSETCDDA) is not available...\n"));
125 #endif
126 #endif
127 
128 }
129 
130 
131 static unsigned ReadToc_cooked __PR((SCSI *x));
132 
133 /* read the table of contents (toc) via the ioctl interface */
134 static unsigned
ReadToc_cooked(x)135 ReadToc_cooked(x)
136 	SCSI	*x;
137 {
138 	unsigned	i;
139 	unsigned	tracks;
140 	struct cdrom_tochdr	hdr;
141 	struct cdrom_tocentry	entry[100];
142 	struct cdrom_tocentry	entryMSF[100];
143 
144 	if (x && x->verbose) {
145 		fprintf(stderr, _("ReadToc_cooked (CDROMREADTOCHDR)...\n"));
146 	}
147 
148 	/*
149 	 * get TocHeader to find out how many entries there are
150 	 */
151 	err = ioctl(global.cooked_fd, CDROMREADTOCHDR, &hdr);
152 	if (err != 0) {
153 		/*
154 		 * error handling
155 		 */
156 		if (err == -1) {
157 			if (errno == EPERM) {
158 				fprintf(stderr,
159 				_("Please run this program setuid root.\n"));
160 			}
161 			errmsg(_("Cooked: Error in read TOC.\n"));
162 			exit(DEVICE_ERROR);
163 		} else {
164 			errmsgno(EX_BAD,
165 				_("Can't get TocHeader (error %d).\n"), err);
166 			exit(MEDIA_ERROR);
167 		}
168 	}
169 	/*
170 	 * get all TocEntries
171 	 */
172 	for (i = 0; i < hdr.cdth_trk1; i++) {
173 		entryMSF[i].cdte_track = 1+i;
174 		entryMSF[i].cdte_format = CDROM_MSF;
175 		err = ioctl(global.cooked_fd, CDROMREADTOCENTRY, &entryMSF[i]);
176 		if (err != 0) {
177 			/*
178 			 * error handling
179 			 */
180 			errmsg(("Can't get TocEntry #%d msf (error %d).\n"),
181 				i+1, err);
182 			exit(MEDIA_ERROR);
183 		}
184 	}
185 	entryMSF[i].cdte_track = CDROM_LEADOUT;
186 	entryMSF[i].cdte_format = CDROM_MSF;
187 	err = ioctl(global.cooked_fd, CDROMREADTOCENTRY, &entryMSF[i]);
188 	if (err != 0) {
189 		/*
190 		 * error handling
191 		 */
192 		errmsg(_("Can't get TocEntry LEADOUT msf (error %d).\n"),
193 			err);
194 		exit(MEDIA_ERROR);
195 	}
196 	tracks = hdr.cdth_trk1+1;
197 #ifdef nonono
198 	for (i = 0; i < tracks; i++) {
199 		toc[i].bFlags = (entry[i].cdte_adr << 4) | (entry[i].cdte_ctrl & 0x0f);
200 		toc[i].bTrack = entry[i].cdte_track;
201 		toc[i].mins = entry[i].cdte_addr.msf.minute;
202 		toc[i].secs = entry[i].cdte_addr.msf.second;
203 		toc[i].frms = entry[i].cdte_addr.msf.frame;
204 	}
205 #endif
206 	/*
207 	 * get all TocEntries now in lba format
208 	 */
209 	for (i = 0; i < hdr.cdth_trk1; i++) {
210 		entry[i].cdte_track = 1+i;
211 		entry[i].cdte_format = CDROM_LBA;
212 		err = ioctl(global.cooked_fd, CDROMREADTOCENTRY, &entry[i]);
213 		if (err != 0) {
214 			/*
215 			 * error handling
216 			 */
217 			errmsg(_("Can't get TocEntry #%d lba (error %d).\n"),
218 				i+1, err);
219 			exit(MEDIA_ERROR);
220 		}
221 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
222 		entry[i].cdte_addr.lba = be32_to_cpu(entry[i].cdte_addr.lba);
223 #endif
224 	}
225 	entry[i].cdte_track = CDROM_LEADOUT;
226 	entry[i].cdte_format = CDROM_LBA;
227 	err = ioctl(global.cooked_fd, CDROMREADTOCENTRY, &entry[i]);
228 	if (err != 0) {
229 		/*
230 		 * error handling
231 		 */
232 		errmsg(_("Can't get TocEntry LEADOUT lba (error %d).\n"),
233 			err);
234 		exit(MEDIA_ERROR);
235 	}
236 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
237 	entry[i].cdte_addr.lba = be32_to_cpu(entry[i].cdte_addr.lba);
238 #endif
239 
240 	for (i = 0; i < tracks; i++) {
241 		toc_entry(i+1,
242 			(entry[i].cdte_adr << 4) | (entry[i].cdte_ctrl & 0x0f),
243 			entry[i].cdte_track,
244 			NULL /* ISRC */,
245 			entry[i].cdte_addr.lba,
246 			entryMSF[i].cdte_addr.msf.minute,
247 			entryMSF[i].cdte_addr.msf.second,
248 			entryMSF[i].cdte_addr.msf.frame);
249 	}
250 	bufferTOC[0] = '\0';
251 	bufferTOC[1] = '\0';
252 	return (--tracks);	/* without lead-out */
253 }
254 
255 static void	trash_cache_cooked __PR((UINT4 *p, unsigned lSector,
256 						unsigned SectorBurstVal));
257 
258 static void
trash_cache_cooked(p,lSector,SectorBurstVal)259 trash_cache_cooked(p, lSector, SectorBurstVal)
260 	UINT4	*p;
261 	unsigned	lSector;
262 	unsigned	SectorBurstVal;
263 {
264 	/*
265 	 * trash the cache
266 	 */
267 
268 #if	defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
269 						defined(__DragonFly__)
270 #if	(defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) && \
271 						__FreeBSD_version >= 501112
272 	pread(global.cooked_fd, (void *) &p[0], 3*CD_FRAMESIZE_RAW,
273 		find_an_off_sector(lSector, SectorBurstVal)*CD_FRAMESIZE_RAW);
274 #else
275 	static struct cdrom_read_audio	arg2;
276 
277 	arg2.address.lba = find_an_off_sector(lSector, SectorBurstVal);
278 	arg2.addr_format = CDROM_LBA;
279 	arg2.nframes = 3;
280 	arg2.buffer = (unsigned char *) &p[0];
281 
282 	ioctl(global.cooked_fd, CDROMREADAUDIO, &arg2);
283 #endif
284 #endif
285 #if	defined __linux__
286 	static struct cdrom_read_audio	arg2;
287 
288 	arg2.addr.lba = find_an_off_sector(lSector, SectorBurstVal);
289 	arg2.addr_format = CDROM_LBA;
290 	arg2.nframes = 3;
291 	arg2.buf = (unsigned char *) &p[0];
292 
293 	ioctl(global.cooked_fd, CDROMREADAUDIO, &arg2);
294 #endif
295 #if	defined __sun || \
296 		(defined HAVE_SYS_CDIO_H && defined CDROM_DA_NO_SUBCODE)
297 	struct cdrom_cdda	suncdda;
298 
299 	suncdda.cdda_addr = lSector;
300 	suncdda.cdda_length = SectorBurstVal*CD_FRAMESIZE_RAW;
301 	suncdda.cdda_data = (char *) &p[0];
302 	suncdda.cdda_subcode = CDROM_DA_NO_SUBCODE;
303 
304 	ioctl(global.cooked_fd, CDROMCDDA, &suncdda);
305 #endif
306 }
307 
308 static void ReadCdRomData_cooked __PR((SCSI *x, UINT4 *p, unsigned lSector,
309 						unsigned SectorBurstVal));
310 /*
311  * read 'SectorBurst' adjacent sectors of data sectors
312  * to Buffer '*p' beginning at sector 'lSector'
313  */
314 static void
ReadCdRomData_cooked(x,p,lSector,SectorBurstVal)315 ReadCdRomData_cooked(x, p, lSector, SectorBurstVal)
316 	SCSI		*x;
317 	UINT4		*p;
318 	unsigned	lSector;
319 	unsigned	SectorBurstVal;
320 {
321 	int		retval;
322 
323 	if (x && x->verbose) {
324 		fprintf(stderr, _("ReadCdRomData_cooked (lseek & read)...\n"));
325 	}
326 
327 	if ((retval = lseek(global.cooked_fd, lSector*CD_FRAMESIZE, SEEK_SET))
328 				!= (int)lSector*CD_FRAMESIZE) {
329 		errmsg(_("Cannot seek sector.\n"));
330 	}
331 	if ((retval = read(global.cooked_fd, p, SectorBurstVal*CD_FRAMESIZE))
332 				!= (int)SectorBurstVal*CD_FRAMESIZE) {
333 		errmsg(_("Cannot read sector.\n"));
334 	}
335 }
336 
337 static int	ReadCdRom_cooked __PR((SCSI *x, UINT4 *p, unsigned lSector,
338 						unsigned SectorBurstVal));
339 /*
340  * read 'SectorBurst' adjacent sectors of audio sectors
341  * to Buffer '*p' beginning at sector 'lSector'
342  */
343 static int
ReadCdRom_cooked(x,p,lSector,SectorBurstVal)344 ReadCdRom_cooked(x, p, lSector, SectorBurstVal)
345 	SCSI		*x;
346 	UINT4		*p;
347 	unsigned	lSector;
348 	unsigned	SectorBurstVal;
349 {
350 	int	retry_count = 0;
351 static int	nothing_read = 1;
352 
353 /* read 2352 bytes audio data */
354 #if	defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
355 						defined(__DragonFly__)
356 #if	(defined(__FreeBSD__) || defined(__FreeBSD_kernel__)) && \
357 						__FreeBSD_version >= 501112
358 	if (x && x->verbose) {
359 		fprintf(stderr, _("ReadCdRom_cooked (pread)...\n"));
360 	}
361 
362 	do {
363 		err = 0;
364 		if (pread(global.cooked_fd, (void *) &p[0],
365 				SectorBurstVal*CD_FRAMESIZE_RAW,
366 				lSector*CD_FRAMESIZE_RAW) == -1) {
367 			err = -1;
368 		}
369 #else
370 	arg.address.lba = lSector;
371 	arg.addr_format = CDROM_LBA;
372 	arg.nframes = SectorBurstVal;
373 	arg.buffer = (unsigned char *) &p[0];
374 
375 	if (x && x->verbose) {
376 		fprintf(stderr, _("ReadCdRom_cooked (CDROMREADAUDIO)...\n"));
377 	}
378 
379 	do {
380 		err = ioctl(global.cooked_fd, CDROMREADAUDIO, &arg);
381 #endif
382 #endif
383 #if	defined __linux__
384 	arg.addr.lba = lSector;
385 	arg.addr_format = CDROM_LBA;
386 	arg.nframes = SectorBurstVal;
387 	arg.buf = (unsigned char *) &p[0];
388 
389 	if (x && x->verbose) {
390 		fprintf(stderr, _("ReadCdRom_cooked (CDROMREADAUDIO)...\n"));
391 	}
392 
393 	do {
394 		err = ioctl(global.cooked_fd, CDROMREADAUDIO, &arg);
395 #endif
396 #if	defined __sun || \
397 		(defined HAVE_SYS_CDIO_H && defined CDROM_DA_NO_SUBCODE)
398 	struct cdrom_cdda	suncdda;
399 
400 	suncdda.cdda_addr = lSector;
401 	suncdda.cdda_length = SectorBurstVal*CD_FRAMESIZE_RAW;
402 	suncdda.cdda_data = (char *) &p[0];
403 	suncdda.cdda_subcode = CDROM_DA_NO_SUBCODE;
404 
405 	if (x && x->verbose) {
406 		fprintf(stderr, _("ReadCdRom_cooked (CDROMCDDA)...\n"));
407 	}
408 
409 	do {
410 		err = ioctl(global.cooked_fd, CDROMCDDA, &suncdda);
411 #endif
412 		retry_count++;
413 
414 		if (err) {
415 			trash_cache_cooked(p, lSector, SectorBurstVal);
416 		}
417 
418 	} while ((err) && (retry_count < 30));
419 
420 	if (err != 0) {
421 		if (x->silent == 0) {
422 			/*
423 			 * error handling
424 			 */
425 			if (err == -1) {
426 				if (nothing_read &&
427 				    (errno == EINVAL || errno == EIO)) {
428 					fprintf(stderr,
429 						_("Sorry, this driver and/or drive does not support cdda reading.\n"));
430 				}
431 				errmsg(_("Cooked: Error read cdda sector %u + %u, buffer %p + %x\n"),
432 					lSector, SectorBurstVal, p,
433 					global.shmsize);
434 			} else {
435 				errmsgno(EX_BAD,
436 					_("Can't read frame #%u (error %d).\n"),
437 					lSector, err);
438 			}
439 		}
440 		return (SectorBurstVal - 1);
441 	} else {
442 		nothing_read = 0;
443 	}
444 
445 	return (SectorBurstVal);
446 }
447 
448 static int	StopPlay_cooked	__PR((SCSI *x));
449 static int
450 StopPlay_cooked(x)
451 	SCSI	*x;
452 {
453 	if (x && x->verbose) {
454 		fprintf(stderr, _("StopPlay_cooked (CDROMSTOP)...\n"));
455 	}
456 
457 	return (ioctl(global.cooked_fd, CDROMSTOP, 0) ? 0 : -1);
458 }
459 
460 static int	Play_at_cooked __PR((SCSI *x, unsigned int from_sector,
461 							unsigned int sectors));
462 static int
463 Play_at_cooked(x, from_sector, sectors)
464 	SCSI	*x;
465 	unsigned int	from_sector;
466 	unsigned int	sectors;
467 {
468 	struct cdrom_msf	cmsf;
469 	int			retval;
470 
471 	if (x && x->verbose) {
472 		fprintf(stderr,
473 		_("Play_at_cooked (CDROMSTART & CDROMPLAYMSF)... (%u-%u)"),
474 			from_sector, from_sector+sectors-1);
475 		fprintf(stderr, "\n");
476 	}
477 
478 	cmsf.cdmsf_min0 = (from_sector + 150) / (60*75);
479 	cmsf.cdmsf_sec0 = ((from_sector + 150) / 75) % 60;
480 	cmsf.cdmsf_frame0 = (from_sector + 150) % 75;
481 	cmsf.cdmsf_min1 = (from_sector + 150 + sectors) / (60*75);
482 	cmsf.cdmsf_sec1 = ((from_sector + 150 + sectors) / 75) % 60;
483 	cmsf.cdmsf_frame1 = (from_sector + 150 + sectors) % 75;
484 
485 #if	0
486 	/*
487 	 * makes index scanning under FreeBSD too slow
488 	 */
489 	if ((retval = ioctl(global.cooked_fd, CDROMSTART, 0)) != 0) {
490 		errmsg(_("Cannot do ioctl(%d, CDROMSTART, 0).\n"),
491 			global.cooked_fd);
492 	}
493 #endif
494 	if ((retval = ioctl(global.cooked_fd, CDROMPLAYMSF, &cmsf)) != 0) {
495 		errmsg(_("Cannot do ioctl(%d, CDROMPLAYMSF, ...).\n"),
496 			global.cooked_fd);
497 	}
498 	return (retval);
499 }
500 
501 #if	defined	PROTOTYPES
502 static subq_chnl	*ReadSubQ_cooked __PR((SCSI *x,
503 						unsigned char sq_format,
504 						unsigned char track))
505 #else
506 /*
507  * request sub-q-channel information. This function may cause confusion
508  * for a drive, when called in the sampling process.
509  */
510 static subq_chnl *
511 ReadSubQ_cooked(x, sq_format, track)
512 	SCSI	*x;
513 	unsigned char	sq_format;
514 	unsigned char	track;
515 #endif
516 {
517 	struct cdrom_subchnl		sub_ch;
518 
519 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
520 	struct cd_sub_channel_info	sub_ch_info;
521 
522 	if (x && x->verbose) {
523 		fprintf(stderr,
524 		_("ReadSubQ_cooked (CDROM_GET_MCN or CDROMSUBCHNL)...\n"));
525 	}
526 
527 	sub_ch.address_format = CD_MSF_FORMAT;
528 	sub_ch.track = track;
529 	sub_ch.data_len = sizeof (struct cd_sub_channel_info);
530 	sub_ch.data = &sub_ch_info;
531 
532 	switch (sq_format) {
533 
534 	case GET_CATALOGNUMBER:
535 		sub_ch.data_format = CD_MEDIA_CATALOG;
536 #else
537 	if (x && x->verbose) {
538 		fprintf(stderr,
539 		_("ReadSubQ_cooked (CDROM_GET_MCN or CDROMSUBCHNL)...\n"));
540 	}
541 
542 	switch (sq_format) {
543 
544 	case GET_CATALOGNUMBER:
545 #endif
546 #if	defined CDROM_GET_MCN
547 		if (!(err = ioctl(global.cooked_fd, CDROM_GET_MCN,
548 					(struct cdrom_mcn *) SubQbuffer))) {
549 			subq_chnl *SQp = (subq_chnl *) SubQbuffer;
550 			subq_catalog *SQPp = (subq_catalog *) &SQp->data;
551 
552 			memmove(SQPp->media_catalog_number, SQp,
553 					sizeof (SQPp->media_catalog_number));
554 			SQPp->zero = 0;
555 			SQPp->mc_valid = 0x80;
556 			break;
557 	} else
558 #endif
559 	{
560 		return (NULL);
561 	}
562 
563 	case GET_POSITIONDATA:
564 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
565 		sub_ch.data_format = CD_CURRENT_POSITION;
566 #endif
567 #if defined(__linux__)
568 		sub_ch.cdsc_format = CDROM_MSF;
569 #endif
570 		if (!(err = ioctl(global.cooked_fd, CDROMSUBCHNL, &sub_ch))) {
571 			/*
572 			 * copy to SubQbuffer
573 			 */
574 			subq_chnl *SQp = (subq_chnl *) (SubQbuffer);
575 			subq_position *SQPp = (subq_position *) SQp->data;
576 			SQp->audio_status 	= sub_ch.cdsc_audiostatus;
577 			SQp->format 		= sub_ch.cdsc_format;
578 			SQp->control_adr	= (sub_ch.cdsc_adr << 4) |
579 						    (sub_ch.cdsc_ctrl & 0x0f);
580 			SQp->track 		= sub_ch.cdsc_trk;
581 			SQp->index 		= sub_ch.cdsc_ind;
582 			SQPp->abs_min 	= sub_ch.cdsc_absaddr.msf.minute;
583 			SQPp->abs_sec 	= sub_ch.cdsc_absaddr.msf.second;
584 			SQPp->abs_frame 	= sub_ch.cdsc_absaddr.msf.frame;
585 			SQPp->trel_min 	= sub_ch.cdsc_reladdr.msf.minute;
586 			SQPp->trel_sec 	= sub_ch.cdsc_reladdr.msf.second;
587 			SQPp->trel_frame 	= sub_ch.cdsc_reladdr.msf.frame;
588 		} else {
589 			if (err == -1) {
590 				if (errno == EPERM)
591 					fprintf(stderr,
592 					_("Please run this program setuid root.\n"));
593 				errmsg(_("Cooked: Error in read subq.\n"));
594 				exit(DEVICE_ERROR);
595 			} else {
596 				errmsgno(EX_BAD,
597 				_("Can't read sub q channel (error %d).\n"),
598 					err);
599 				exit(DEVICE_ERROR);
600 			}
601 		}
602 		break;
603 
604 	default:
605 		return (NULL);
606 	} /* switch */
607 
608 	return ((subq_chnl *)(SubQbuffer));
609 }
610 
611 /*
612  * Speed control
613  */
614 static void	SpeedSelect_cooked	__PR((SCSI *x, unsigned speed));
615 /* ARGSUSED */
616 static void
617 SpeedSelect_cooked(x, speed)
618 	SCSI		*x;
619 	unsigned	speed;
620 {
621 	if (x && x->verbose) {
622 		fprintf(stderr,
623 			_("SpeedSelect_cooked (CDROM_SELECT_SPEED)...\n"));
624 	}
625 
626 #ifdef CDROM_SELECT_SPEED
627 	/*
628 	 * CAUTION!!!!! Non standard ioctl parameter types here!!!!
629 	 */
630 	if ((err = ioctl(global.cooked_fd, CDROM_SELECT_SPEED, speed))) {
631 		if (err == -1) {
632 			if (errno == EPERM) {
633 				fprintf(stderr,
634 				_("Please run this program setuid root.\n"));
635 			}
636 			errmsg(_("Cooked: Error in speed select.\n"));
637 			/* exit(err); */
638 		} else {
639 			errmsgno(EX_BAD,
640 				_("Can't set speed %d (error %d).\n"),
641 				speed, err);
642 			exit(DEVICE_ERROR);
643 		}
644 	}
645 #endif
646 }
647 
648 /*
649  * set function pointers to use the ioctl routines
650  */
651 void
652 SetupCookedIoctl(pdev_name)
653 	char	*pdev_name;
654 {
655 #if (HAVE_ST_RDEV == 1)
656 	struct stat	statstruct;
657 
658 	if (fstat(global.cooked_fd, &statstruct)) {
659 		errmsg(_("Cannot stat cd %d (%s).\n"),
660 				global.cooked_fd, pdev_name);
661 		exit(STAT_ERROR);
662 	}
663 #if	defined __linux__
664 	switch (major(statstruct.st_rdev)) {
665 
666 	case CDU31A_CDROM_MAJOR:	/* sony cdu-31a/33a */
667 		global.nsectors = 13;
668 		if (global.nsectors >= 14) {
669 			global.overlap = 10;
670 		}
671 		break;
672 
673 	case MATSUSHITA_CDROM_MAJOR:	/* sbpcd 1 */
674 	case MATSUSHITA_CDROM2_MAJOR:	/* sbpcd 2 */
675 	case MATSUSHITA_CDROM3_MAJOR:	/* sbpcd 3 */
676 	case MATSUSHITA_CDROM4_MAJOR:	/* sbpcd 4 */
677 		/*
678 		 * some are more compatible than others
679 		 */
680 		global.nsectors = 13;
681 		break;
682 
683 	default:
684 		global.nsectors = 8;
685 		break;
686 	}
687 
688 	err = ioctl(global.cooked_fd, CDROMAUDIOBUFSIZ, global.nsectors);
689 
690 	switch (major(statstruct.st_rdev)) {
691 
692 	case MATSUSHITA_CDROM_MAJOR:	/* sbpcd 1 */
693 	case MATSUSHITA_CDROM2_MAJOR:	/* sbpcd 2 */
694 	case MATSUSHITA_CDROM3_MAJOR:	/* sbpcd 3 */
695 	case MATSUSHITA_CDROM4_MAJOR:	/* sbpcd 4 */
696 
697 		if (err == -1) {
698 			errmsg(_("Error doing ioctl(CDROMAUDIOBUFSIZ).\n"));
699 		}
700 	}
701 #endif
702 #endif
703 	EnableCdda = EnableCdda_cooked;
704 	ReadCdRom = ReadCdRom_cooked;
705 	ReadCdRomData = (int (*) __PR((SCSI *,
706 				unsigned char *,
707 				unsigned, unsigned))) ReadCdRomData_cooked;
708 	doReadToc = ReadToc_cooked;
709 	ReadTocText = (void (*) __PR((SCSI *)))NULL;
710 	ReadSubQ = ReadSubQ_cooked;
711 	ReadSubChannels = (subq_chnl * (*) __PR((SCSI *, unsigned)))NULL;
712 	SelectSpeed = SpeedSelect_cooked;
713 	Play_at = Play_at_cooked;
714 	StopPlay = StopPlay_cooked;
715 	trash_cache = trash_cache_cooked;
716 	ReadLastAudio = (unsigned (*) __PR((SCSI *)))NULL;
717 }
718 #endif
719