diff options
Diffstat (limited to 'Documentation/cdrom/sbpcd')
-rw-r--r-- | Documentation/cdrom/sbpcd | 1057 |
1 files changed, 1057 insertions, 0 deletions
diff --git a/Documentation/cdrom/sbpcd b/Documentation/cdrom/sbpcd new file mode 100644 index 000000000000..d1825dffca34 --- /dev/null +++ b/Documentation/cdrom/sbpcd @@ -0,0 +1,1057 @@ +This README belongs to release 4.2 or newer of the SoundBlaster Pro +(Matsushita, Kotobuki, Panasonic, CreativeLabs, Longshine and Teac) +CD-ROM driver for Linux. + +sbpcd really, really is NOT for ANY IDE/ATAPI drive! +Not even if you have an "original" SoundBlaster card with an IDE interface! +So, you'd better have a look into README.ide if your port address is 0x1F0, +0x170, 0x1E8, 0x168 or similar. +I get tons of mails from IDE/ATAPI drive users - I really can't continue +any more to answer them all. So, if your drive/interface information sheets +mention "IDE" (primary, secondary, tertiary, quaternary) and the DOS driver +invoking line within your CONFIG.SYS is using an address below 0x230: +DON'T ROB MY LAST NERVE - jumper your interface to address 0x170 and IRQ 15 +(that is the "secondary IDE" configuration), set your drive to "master" and +use ide-cd as your driver. If you do not have a second IDE hard disk, use the +LILO commands + hdb=noprobe hdc=cdrom +and get lucky. +To make it fully clear to you: if you mail me about IDE/ATAPI drive problems, +my answer is above, and I simply will discard your mail, hoping to stop the +flood and to find time to lead my 12-year old son towards happy computing. + +The driver is able to drive the whole family of "traditional" AT-style (that +is NOT the new "Enhanced IDE" or "ATAPI" drive standard) Matsushita, +Kotobuki, Panasonic drives, sometimes labelled as "CreativeLabs". The +well-known drives are CR-521, CR-522, CR-523, CR-562, CR-563. +CR-574 is an IDE/ATAPI drive. + +The Longshine LCS-7260 is a double-speed drive which uses the "old" +Matsushita command set. It is supported - with help by Serge Robyns. +Vertos ("Elitegroup Computer Systems", ECS) has a similar drive - support +has started; get in contact if you have such a "Vertos 100" or "ECS-AT" +drive. + +There exists an "IBM External ISA CD-ROM Drive" which in fact is a CR-563 +with a special controller board. This drive is supported (the interface is +of the "LaserMate" type), and it is possibly the best buy today (cheaper than +an internal drive, and you can use it as an internal, too - e.g. plug it into +a soundcard). + +CreativeLabs has a new drive "CD200" and a similar drive "CD200F". The latter +is made by Funai and sometimes named "E2550UA", newer models may be named +"MK4015". The CD200F drives should fully work. +CD200 drives without "F" are still giving problems: drive detection and +playing audio should work, data access will result in errors. I need qualified +feedback about the bugs within the data functions or a drive (I never saw a +CD200). + +The quad-speed Teac CD-55A drive is supported, but still does not reach "full +speed". The data rate already reaches 500 kB/sec if you set SBP_BUFFER_FRAMES +to 64 (it is not recommended to do that for normal "file access" usage, but it +can speed up things a lot if you use something like "dd" to read from the +drive; I use it for verifying self-written CDs this way). +The drive itself is able to deliver 600 kB/sec, so this needs +work; with the normal setup, the performance currently is not even as good as +double-speed. + +This driver is NOT for Mitsumi or Sony or Aztech or Philips or XXX drives, +and again: this driver is in no way usable for any IDE/ATAPI drive. If you +think your drive should work and it doesn't: send me the DOS driver for your +beast (gzipped + uuencoded) and your CONFIG.SYS if you want to ask me for help, +and include an original log message excerpt, and try to give all information +a complete idiot needs to understand your hassle already with your first +mail. And if you want to say "as I have mailed you before", be sure that I +don't remember your "case" by such remarks; at the moment, I have some +hundreds of open correspondences about Linux CDROM questions (hope to reduce if +the IDE/ATAPI user questions disappear). + + +This driver will work with the soundcard interfaces (SB Pro, SB 16, Galaxy, +SoundFX, Mozart, MAD16 ...) and with the "no-sound" cards (Panasonic CI-101P, +LaserMate, WDH-7001C, Longshine LCS-6853, Teac ...). + +It works with the "configurable" interface "Sequoia S-1000", too, which is +used on the Spea Media FX and Ensonic Soundscape sound cards. You have to +specify the type "SBPRO 2" and the true CDROM port address with it, not the +"configuration port" address. + +If you have a sound card which needs a "configuration driver" instead of +jumpers for interface types and addresses (like Mozart cards) - those +drivers get invoked before the DOS CDROM driver in your CONFIG.SYS, typical +names are "cdsetup.sys" and "mztinit.sys" - let the sound driver do the +CDROM port configuration (the leading comments in linux/drivers/sound/mad16.c +are just for you!). Hannu Savolainen's mad16.c code is able to set up my +Mozart card - I simply had to add + #define MAD16_CONF 0x06 + #define MAD16_CDSEL 0x03 +to configure the CDROM interface for type "Panasonic" (LaserMate) and address +0x340. + +The interface type has to get configured in linux/drivers/cdrom/sbpcd.h, +because the register layout is different between the "SoundBlaster" and the +"LaserMate" type. + +I got a report that the Teac interface card "I/F E117098" is of type +"SoundBlaster" (i.e. you have to set SBPRO to 1) even with the addresses +0x300 and above. This is unusual, and it can't get covered by the auto +probing scheme. +The Teac 16-bit interface cards (like P/N E950228-00A, default address 0x2C0) +need the SBPRO 3 setup. + +If auto-probing found the drive, the address is correct. The reported type +may be wrong. A "mount" will give success only if the interface type is set +right. Playing audio should work with a wrong set interface type, too. + +With some Teac and some CD200 drives I have seen interface cards which seem +to lack the "drive select" lines; always drive 0 gets addressed. To avoid +"mirror drives" (four drives detected where you only have one) with such +interface cards, set MAX_DRIVES to 1 and jumper your drive to ID 0 (if +possible). + + +Up to 4 drives per interface card, and up to 4 interface cards are supported. +All supported drive families can be mixed, but the CR-521 drives are +hard-wired to drive ID 0. The drives have to use different drive IDs, and each +drive has to get a unique minor number (0...3), corresponding indirectly to +its drive ID. +The drive IDs may be selected freely from 0 to 3 - they do not have to be in +consecutive order. + +As Don Carroll, don@ds9.us.dell.com or FIDO 1:382/14, told me, it is possible +to change old drives to any ID, too. He writes in this sense: + "In order to be able to use more than one single speed drive + (they do not have the ID jumpers) you must add a DIP switch + and two resistors. The pads are already on the board next to + the power connector. You will see the silkscreen for the + switch if you remove the top cover. + 1 2 3 4 + ID 0 = x F F x O = "on" + ID 1 = x O F x F = "off" + ID 2 = x F O x x = "don't care" + ID 3 = x O O x + Next to the switch are the positions for R76 (7k) and R78 + (12k). I had to play around with the resistor values - ID 3 + did not work with other values. If the values are not good, + ID 3 behaves like ID 0." + +To use more than 4 drives, you simply need a second controller card at a +different address and a second cable. + +The driver supports reading of data from the CD and playing of audio tracks. +The audio part should run with WorkMan, xcdplayer, with the "non-X11" products +CDplayer and WorkBone - tell me if it is not compatible with other software. +The only accepted measure for correctness with the audio functions is the +"cdtester" utility (appended) - most audio player programmers seem to be +better musicians than programmers. ;-) + +With the CR-56x and the CD200 drives, the reading of audio frames is possible. +This is implemented by an IOCTL function which reads READ_AUDIO frames of +2352 bytes at once (configurable with the "READ_AUDIO" define, default is 0). +Reading the same frame a second time gives different data; the frame data +start at a different position, but all read bytes are valid, and we always +read 98 consecutive chunks (of 24 Bytes) as a frame. Reading more than 1 frame +at once possibly misses some chunks at each frame boundary. This lack has to +get corrected by external, "higher level" software which reads the same frame +again and tries to find and eliminate overlapping chunks (24-byte-pieces). + +The transfer rate with reading audio (1-frame-pieces) currently is very slow. +This can be better reading bigger chunks, but the "missing" chunks possibly +occur at the beginning of each single frame. +The software interface possibly may change a bit the day the SCSI driver +supports it too. + +With all but the CR-52x drives, MultiSession is supported. +Photo CDs work (the "old" drives like CR-521 can access only the first +session of a photoCD). +At ftp.gwdg.de:/pub/linux/hpcdtoppm/ you will find Hadmut Danisch's package to +convert photo CD image files and Gerd Knorr's viewing utility. + +The transfer rate will reach 150 kB/sec with CR-52x drives, 300 kB/sec with +CR-56x drives, and currently not more than 500 kB/sec (usually less than +250 kB/sec) with the Teac quad speed drives. +XA (PhotoCD) disks with "old" drives give only 50 kB/sec. + +This release consists of +- this README file +- the driver file linux/drivers/cdrom/sbpcd.c +- the stub files linux/drivers/cdrom/sbpcd[234].c +- the header file linux/drivers/cdrom/sbpcd.h. + + +To install: +----------- + +1. Setup your hardware parameters. Though the driver does "auto-probing" at a + lot of (not all possible!) addresses, this step is recommended for + everyday use. You should let sbpcd auto-probe once and use the reported + address if a drive got found. The reported type may be incorrect; it is + correct if you can mount a data CD. There is no choice for you with the + type; only one is right, the others are deadly wrong. + + a. Go into /usr/src/linux/drivers/cdrom/sbpcd.h and configure it for your + hardware (near the beginning): + a1. Set it up for the appropriate type of interface board. + "Original" CreativeLabs sound cards need "SBPRO 1". + Most "compatible" sound cards (almost all "non-CreativeLabs" cards) + need "SBPRO 0". + The "no-sound" board from OmniCd needs the "SBPRO 1" setup. + The Teac 8-bit "no-sound" boards need the "SBPRO 1" setup. + The Teac 16-bit "no-sound" boards need the "SBPRO 3" setup. + All other "no-sound" boards need the "SBPRO 0" setup. + The Spea Media FX and Ensoniq SoundScape cards need "SBPRO 2". + sbpcd.c holds some examples in its auto-probe list. + If you configure "SBPRO" wrong, the playing of audio CDs will work, + but you will not be able to mount a data CD. + a2. Tell the address of your CDROM_PORT (not of the sound port). + a3. If 4 drives get found, but you have only one, set MAX_DRIVES to 1. + a4. Set DISTRIBUTION to 0. + b. Additionally for 2.a1 and 2.a2, the setup may be done during + boot time (via the "kernel command line" or "LILO option"): + sbpcd=0x320,LaserMate + or + sbpcd=0x230,SoundBlaster + or + sbpcd=0x338,SoundScape + or + sbpcd=0x2C0,Teac16bit + This is especially useful if you install a fresh distribution. + If the second parameter is a number, it gets taken as the type + setting; 0 is "LaserMate", 1 is "SoundBlaster", 2 is "SoundScape", + 3 is "Teac16bit". + So, for example + sbpcd=0x230,1 + is equivalent to + sbpcd=0x230,SoundBlaster + +2. "cd /usr/src/linux" and do a "make config" and select "y" for Matsushita + CD-ROM support and for ISO9660 FileSystem support. If you do not have a + second, third, or fourth controller installed, do not say "y" to the + secondary Matsushita CD-ROM questions. + +3. Then make the kernel image ("make zlilo" or similar). + +4. Make the device file(s). This step usually already has been done by the + MAKEDEV script. + The driver uses MAJOR 25, so, if necessary, do + mknod /dev/sbpcd b 25 0 (if you have only one drive) + and/or + mknod /dev/sbpcd0 b 25 0 + mknod /dev/sbpcd1 b 25 1 + mknod /dev/sbpcd2 b 25 2 + mknod /dev/sbpcd3 b 25 3 + to make the node(s). + + The "first found" drive gets MINOR 0 (regardless of its jumpered ID), the + "next found" (at the same cable) gets MINOR 1, ... + + For a second interface board, you have to make nodes like + mknod /dev/sbpcd4 b 26 0 + mknod /dev/sbpcd5 b 26 1 + and so on. Use the MAJORs 26, 27, 28. + + If you further make a link like + ln -s sbpcd /dev/cdrom + you can use the name /dev/cdrom, too. + +5. Reboot with the new kernel. + +You should now be able to do + mkdir /CD +and + mount -rt iso9660 /dev/sbpcd /CD +or + mount -rt iso9660 -o block=2048 /dev/sbpcd /CD +and see the contents of your CD in the /CD directory. +To use audio CDs, a mounting is not recommended (and it would fail if the +first track is not a data track). + + +Using sbpcd as a "loadable module": +----------------------------------- + +If you do NOT select "Matsushita/Panasonic CDROM driver support" during the +"make config" of your kernel, you can build the "loadable module" sbpcd.o. + +If sbpcd gets used as a module, the support of more than one interface +card (i.e. drives 4...15) is disabled. + +You can specify interface address and type with the "insmod" command like: + # insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x340,0 +or + # insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x230,1 +or + # insmod /usr/src/linux/modules/sbpcd.o sbpcd=0x338,2 +where the last number represents the SBPRO setting (no strings allowed here). + + +Things of interest: +------------------- + +The driver is configured to try the LaserMate type of interface at I/O port +0x0340 first. If this is not appropriate, sbpcd.h should get changed +(you will find the right place - just at the beginning). + +No DMA and no IRQ is used. + +To reduce or increase the amount of kernel messages, edit sbpcd.c and play +with the "DBG_xxx" switches (initialization of the variable "sbpcd_debug"). +Don't forget to reflect on what you do; enabling all DBG_xxx switches at once +may crash your system, and each message line is accompanied by a delay. + +The driver uses the "variable BLOCK_SIZE" feature. To use it, you have to +specify "block=2048" as a mount option. Doing this will disable the direct +execution of a binary from the CD; you have to copy it to a device with the +standard BLOCK_SIZE (1024) first. So, do not use this if your system is +directly "running from the CDROM" (like some of Yggdrasil's installation +variants). There are CDs on the market (like the German "unifix" Linux +distribution) which MUST get handled with a block_size of 1024. Generally, +one can say all the CDs which hold files of the name YMTRANS.TBL are defective; +do not use block=2048 with those. + +Within sbpcd.h, you will find some "#define"s (e.g. EJECT and JUKEBOX). With +these, you can configure the driver for some special things. +You can use the appended program "cdtester" to set the auto-eject feature +during runtime. Jeff Tranter's "eject" utility can do this, too (and more) +for you. + +There is an ioctl CDROMMULTISESSION to obtain with a user program if +the CD is an XA disk and - if it is - where the last session starts. The +"cdtester" program illustrates how to call it. + + +Auto-probing at boot time: +-------------------------- + +The driver does auto-probing at many well-known interface card addresses, +but not all: +Some probings can cause a hang if an NE2000 ethernet card gets touched, because +SBPCD's auto-probing happens before the initialization of the net drivers. +Those "hazardous" addresses are excluded from auto-probing; the "kernel +command line" feature has to be used during installation if you have your +drive at those addresses. The "module" version is allowed to probe at those +addresses, too. + +The auto-probing looks first at the configured address resp. the address +submitted by the kernel command line. With this, it is possible to use this +driver within installation boot floppies, and for any non-standard address, +too. + +Auto-probing will make an assumption about the interface type ("SBPRO" or not), +based upon the address. That assumption may be wrong (initialization will be +o.k., but you will get I/O errors during mount). In that case, use the "kernel +command line" feature and specify address & type at boot time to find out the +right setup. + +For everyday use, address and type should get configured within sbpcd.h. That +will stop the auto-probing due to success with the first try. + +The kernel command "sbpcd=0" suppresses each auto-probing and causes +the driver not to find any drive; it is meant for people who love sbpcd +so much that they do not want to miss it, even if they miss the drives. ;-) + +If you configure "#define CDROM_PORT 0" in sbpcd.h, the auto-probing is +initially disabled and needs an explicit kernel command to get activated. +Once activated, it does not stop before success or end-of-list. This may be +useful within "universal" CDROM installation boot floppies (but using the +loadable module would be better because it allows an "extended" auto-probing +without fearing NE2000 cards). + +To shorten the auto-probing list to a single entry, set DISTRIBUTION 0 within +sbpcd.h. + + +Setting up address and interface type: +-------------------------------------- + +If your I/O port address is not 0x340, you have to look for the #defines near +the beginning of sbpcd.h and configure them: set SBPRO to 0 or 1 or 2, and +change CDROM_PORT to the address of your CDROM I/O port. + +Almost all of the "SoundBlaster compatible" cards behave like the no-sound +interfaces, i.e. need SBPRO 0! + +With "original" SB Pro cards, an initial setting of CD_volume through the +sound card's MIXER register gets done. +If you are using a "compatible" sound card of types "LaserMate" or "SPEA", +you can set SOUND_BASE (in sbpcd.h) to get it done with your card, too... + + +Using audio CDs: +---------------- + +Workman, WorkBone, xcdplayer, cdplayer and the nice little tool "cdplay" (see +README.aztcd from the Aztech driver package) should work. + +The program CDplayer likes to talk to "/dev/mcd" only, xcdplayer wants +"/dev/rsr0", workman loves "/dev/sr0" or "/dev/cdrom" - so, make the +appropriate links to use them without the need to supply parameters. + + +Copying audio tracks: +--------------------- + +The following program will copy track 1 (or a piece of it) from an audio CD +into the file "track01": + +/*=================== begin program ========================================*/ +/* + * read an audio track from a CD + * + * (c) 1994 Eberhard Moenkeberg <emoenke@gwdg.de> + * may be used & enhanced freely + * + * Due to non-existent sync bytes at the beginning of each audio frame (or due + * to a firmware bug within all known drives?), it is currently a kind of + * fortune if two consecutive frames fit together. + * Usually, they overlap, or a little piece is missing. This happens in units + * of 24-byte chunks. It has to get fixed by higher-level software (reading + * until an overlap occurs, and then eliminate the overlapping chunks). + * ftp.gwdg.de:/pub/linux/misc/cdda2wav-sbpcd.*.tar.gz holds an example of + * such an algorithm. + * This example program further is missing to obtain the SubChannel data + * which belong to each frame. + * + * This is only an example of the low-level access routine. The read data are + * pure 16-bit CDDA values; they have to get converted to make sound out of + * them. + * It is no fun to listen to it without prior overlap/underlap correction! + */ +#include <stdio.h> +#include <sys/ioctl.h> +#include <linux/cdrom.h> + +static struct cdrom_tochdr hdr; +static struct cdrom_tocentry entry[101]; +static struct cdrom_read_audio arg; +static u_char buffer[CD_FRAMESIZE_RAW]; +static int datafile, drive; +static int i, j, limit, track, err; +static char filename[32]; + +main(int argc, char *argv[]) +{ +/* + * open /dev/cdrom + */ + drive=open("/dev/cdrom", 0); + if (drive<0) + { + fprintf(stderr, "can't open drive.\n"); + exit (-1); + } +/* + * get TocHeader + */ + fprintf(stdout, "getting TocHeader...\n"); + err=ioctl(drive, CDROMREADTOCHDR, &hdr); + if (err!=0) + { + fprintf(stderr, "can't get TocHeader (error %d).\n", err); + exit (-1); + } + else + fprintf(stdout, "TocHeader: %d %d\n", hdr.cdth_trk0, hdr.cdth_trk1); +/* + * get and display all TocEntries + */ + fprintf(stdout, "getting TocEntries...\n"); + for (i=1;i<=hdr.cdth_trk1+1;i++) + { + if (i!=hdr.cdth_trk1+1) entry[i].cdte_track = i; + else entry[i].cdte_track = CDROM_LEADOUT; + entry[i].cdte_format = CDROM_LBA; + err=ioctl(drive, CDROMREADTOCENTRY, &entry[i]); + if (err!=0) + { + fprintf(stderr, "can't get TocEntry #%d (error %d).\n", i, err); + exit (-1); + } + else + { + fprintf(stdout, "TocEntry #%d: %1X %1X %06X %02X\n", + entry[i].cdte_track, + entry[i].cdte_adr, + entry[i].cdte_ctrl, + entry[i].cdte_addr.lba, + entry[i].cdte_datamode); + } + } + fprintf(stdout, "got all TocEntries.\n"); +/* + * ask for track number (not implemented here) + */ +track=1; +#if 0 /* just read a little piece (4 seconds) */ +entry[track+1].cdte_addr.lba=entry[track].cdte_addr.lba+300; +#endif +/* + * read track into file + */ + sprintf(filename, "track%02d\0", track); + datafile=creat(filename, 0755); + if (datafile<0) + { + fprintf(stderr, "can't open datafile %s.\n", filename); + exit (-1); + } + arg.addr.lba=entry[track].cdte_addr.lba; + arg.addr_format=CDROM_LBA; /* CDROM_MSF would be possible here, too. */ + arg.nframes=1; + arg.buf=&buffer[0]; + limit=entry[track+1].cdte_addr.lba; + for (;arg.addr.lba<limit;arg.addr.lba++) + { + err=ioctl(drive, CDROMREADAUDIO, &arg); + if (err!=0) + { + fprintf(stderr, "can't read abs. frame #%d (error %d).\n", + arg.addr.lba, err); + } + j=write(datafile, &buffer[0], CD_FRAMESIZE_RAW); + if (j!=CD_FRAMESIZE_RAW) + { + fprintf(stderr,"I/O error (datafile) at rel. frame %d\n", + arg.addr.lba-entry[track].cdte_addr.lba); + } + arg.addr.lba++; + } +} +/*===================== end program ========================================*/ + +At ftp.gwdg.de:/pub/linux/misc/cdda2wav-sbpcd.*.tar.gz is an adapted version of +Heiko Eissfeldt's digital-audio to .WAV converter (the original is there, too). +This is preliminary, as Heiko himself will care about it. + + +Known problems: +--------------- + +Currently, the detection of disk change or removal is actively disabled. + +Most attempts to read the UPC/EAN code result in a stream of zeroes. All my +drives are mostly telling there is no UPC/EAN code on disk or there is, but it +is an all-zero number. I guess now almost no CD holds such a number. + +Bug reports, comments, wishes, donations (technical information is a donation, +too :-) etc. to emoenke@gwdg.de. + +SnailMail address, preferable for CD editors if they want to submit a free +"cooperation" copy: + Eberhard Moenkeberg + Reinholdstr. 14 + D-37083 Goettingen + Germany +--- + + +Appendix -- the "cdtester" utility: + +/* + * cdtester.c -- test the audio functions of a CD driver + * + * (c) 1995 Eberhard Moenkeberg <emoenke@gwdg.de> + * published under the GPL + * + * made under heavy use of the "Tiny Audio CD Player" + * from Werner Zimmermann <zimmerma@rz.fht-esslingen.de> + * (see linux/drivers/block/README.aztcd) + */ +#undef AZT_PRIVATE_IOCTLS /* not supported by every CDROM driver */ +#define SBP_PRIVATE_IOCTLS /* not supported by every CDROM driver */ + +#include <stdio.h> +#include <stdio.h> +#include <malloc.h> +#include <sys/ioctl.h> +#include <linux/cdrom.h> + +#ifdef AZT_PRIVATE_IOCTLS +#include <linux/../../drivers/cdrom/aztcd.h> +#endif AZT_PRIVATE_IOCTLS +#ifdef SBP_PRIVATE_IOCTLS +#include <linux/../../drivers/cdrom/sbpcd.h> +#include <linux/fs.h> +#endif SBP_PRIVATE_IOCTLS + +struct cdrom_tochdr hdr; +struct cdrom_tochdr tocHdr; +struct cdrom_tocentry TocEntry[101]; +struct cdrom_tocentry entry; +struct cdrom_multisession ms_info; +struct cdrom_read_audio read_audio; +struct cdrom_ti ti; +struct cdrom_subchnl subchnl; +struct cdrom_msf msf; +struct cdrom_volctrl volctrl; +#ifdef AZT_PRIVATE_IOCTLS +union +{ + struct cdrom_msf msf; + unsigned char buf[CD_FRAMESIZE_RAW]; +} azt; +#endif AZT_PRIVATE_IOCTLS +int i, i1, i2, i3, j, k; +unsigned char sequence=0; +unsigned char command[80]; +unsigned char first=1, last=1; +char *default_device="/dev/cdrom"; +char dev[20]; +char filename[20]; +int drive; +int datafile; +int rc; + +void help(void) +{ + printf("Available Commands:\n"); + printf("STOP s EJECT e QUIT q\n"); + printf("PLAY TRACK t PAUSE p RESUME r\n"); + printf("NEXT TRACK n REPEAT LAST l HELP h\n"); + printf("SUBCHANNEL_Q c TRACK INFO i PLAY AT a\n"); + printf("READ d READ RAW w READ AUDIO A\n"); + printf("MS-INFO M TOC T START S\n"); + printf("SET EJECTSW X DEVICE D DEBUG Y\n"); + printf("AUDIO_BUFSIZ Z RESET R SET VOLUME v\n"); + printf("GET VOLUME V\n"); +} + +/* + * convert MSF number (3 bytes only) to Logical_Block_Address + */ +int msf2lba(u_char *msf) +{ + int i; + + i=(msf[0] * CD_SECS + msf[1]) * CD_FRAMES + msf[2] - CD_BLOCK_OFFSET; + if (i<0) return (0); + return (i); +} +/* + * convert logical_block_address to m-s-f_number (3 bytes only) + */ +void lba2msf(int lba, unsigned char *msf) +{ + lba += CD_BLOCK_OFFSET; + msf[0] = lba / (CD_SECS*CD_FRAMES); + lba %= CD_SECS*CD_FRAMES; + msf[1] = lba / CD_FRAMES; + msf[2] = lba % CD_FRAMES; +} + +int init_drive(char *dev) +{ + unsigned char msf_ent[3]; + + /* + * open the device + */ + drive=open(dev,0); + if (drive<0) return (-1); + /* + * get TocHeader + */ + printf("getting TocHeader...\n"); + rc=ioctl(drive,CDROMREADTOCHDR,&hdr); + if (rc!=0) + { + printf("can't get TocHeader (error %d).\n",rc); + return (-2); + } + else + first=hdr.cdth_trk0; + last=hdr.cdth_trk1; + printf("TocHeader: %d %d\n",hdr.cdth_trk0,hdr.cdth_trk1); + /* + * get and display all TocEntries + */ + printf("getting TocEntries...\n"); + for (i=1;i<=hdr.cdth_trk1+1;i++) + { + if (i!=hdr.cdth_trk1+1) TocEntry[i].cdte_track = i; + else TocEntry[i].cdte_track = CDROM_LEADOUT; + TocEntry[i].cdte_format = CDROM_LBA; + rc=ioctl(drive,CDROMREADTOCENTRY,&TocEntry[i]); + if (rc!=0) + { + printf("can't get TocEntry #%d (error %d).\n",i,rc); + } + else + { + lba2msf(TocEntry[i].cdte_addr.lba,&msf_ent[0]); + if (TocEntry[i].cdte_track==CDROM_LEADOUT) + { + printf("TocEntry #%02X: %1X %1X %02d:%02d:%02d (lba: 0x%06X) %02X\n", + TocEntry[i].cdte_track, + TocEntry[i].cdte_adr, + TocEntry[i].cdte_ctrl, + msf_ent[0], + msf_ent[1], + msf_ent[2], + TocEntry[i].cdte_addr.lba, + TocEntry[i].cdte_datamode); + } + else + { + printf("TocEntry #%02d: %1X %1X %02d:%02d:%02d (lba: 0x%06X) %02X\n", + TocEntry[i].cdte_track, + TocEntry[i].cdte_adr, + TocEntry[i].cdte_ctrl, + msf_ent[0], + msf_ent[1], + msf_ent[2], + TocEntry[i].cdte_addr.lba, + TocEntry[i].cdte_datamode); + } + } + } + return (hdr.cdth_trk1); /* number of tracks */ +} + +void display(int size,unsigned char *buffer) +{ + k=0; + getchar(); + for (i=0;i<(size+1)/16;i++) + { + printf("%4d:",i*16); + for (j=0;j<16;j++) + { + printf(" %02X",buffer[i*16+j]); + } + printf(" "); + for (j=0;j<16;j++) + { + if (isalnum(buffer[i*16+j])) + printf("%c",buffer[i*16+j]); + else + printf("."); + } + printf("\n"); + k++; + if (k>=20) + { + printf("press ENTER to continue\n"); + getchar(); + k=0; + } + } +} + +main(int argc, char *argv[]) +{ + printf("\nTesting tool for a CDROM driver's audio functions V0.1\n"); + printf("(C) 1995 Eberhard Moenkeberg <emoenke@gwdg.de>\n"); + printf("initializing...\n"); + + rc=init_drive(default_device); + if (rc<0) printf("could not open %s (rc=%d).\n",default_device,rc); + help(); + while (1) + { + printf("Give a one-letter command (h = help): "); + scanf("%s",command); + command[1]=0; + switch (command[0]) + { + case 'D': + printf("device name (f.e. /dev/sbpcd3): ? "); + scanf("%s",&dev); + close(drive); + rc=init_drive(dev); + if (rc<0) printf("could not open %s (rc %d).\n",dev,rc); + break; + case 'e': + rc=ioctl(drive,CDROMEJECT); + if (rc<0) printf("CDROMEJECT: rc=%d.\n",rc); + break; + case 'p': + rc=ioctl(drive,CDROMPAUSE); + if (rc<0) printf("CDROMPAUSE: rc=%d.\n",rc); + break; + case 'r': + rc=ioctl(drive,CDROMRESUME); + if (rc<0) printf("CDROMRESUME: rc=%d.\n",rc); + break; + case 's': + rc=ioctl(drive,CDROMSTOP); + if (rc<0) printf("CDROMSTOP: rc=%d.\n",rc); + break; + case 'S': + rc=ioctl(drive,CDROMSTART); + if (rc<0) printf("CDROMSTART: rc=%d.\n",rc); + break; + case 't': + rc=ioctl(drive,CDROMREADTOCHDR,&tocHdr); + if (rc<0) + { + printf("CDROMREADTOCHDR: rc=%d.\n",rc); + break; + } + first=tocHdr.cdth_trk0; + last= tocHdr.cdth_trk1; + if ((first==0)||(first>last)) + { + printf ("--got invalid TOC data.\n"); + } + else + { + printf("--enter track number(first=%d, last=%d): ",first,last); + scanf("%d",&i1); + ti.cdti_trk0=i1; + if (ti.cdti_trk0<first) ti.cdti_trk0=first; + if (ti.cdti_trk0>last) ti.cdti_trk0=last; + ti.cdti_ind0=0; + ti.cdti_trk1=last; + ti.cdti_ind1=0; + rc=ioctl(drive,CDROMSTOP); + rc=ioctl(drive,CDROMPLAYTRKIND,&ti); + if (rc<0) printf("CDROMPLAYTRKIND: rc=%d.\n",rc); + } + break; + case 'n': + rc=ioctl(drive,CDROMSTOP); + if (++ti.cdti_trk0>last) ti.cdti_trk0=last; + ti.cdti_ind0=0; + ti.cdti_trk1=last; + ti.cdti_ind1=0; + rc=ioctl(drive,CDROMPLAYTRKIND,&ti); + if (rc<0) printf("CDROMPLAYTRKIND: rc=%d.\n",rc); + break; + case 'l': + rc=ioctl(drive,CDROMSTOP); + if (--ti.cdti_trk0<first) ti.cdti_trk0=first; + ti.cdti_ind0=0; + ti.cdti_trk1=last; + ti.cdti_ind1=0; + rc=ioctl(drive,CDROMPLAYTRKIND,&ti); + if (rc<0) printf("CDROMPLAYTRKIND: rc=%d.\n",rc); + break; + case 'c': + subchnl.cdsc_format=CDROM_MSF; + rc=ioctl(drive,CDROMSUBCHNL,&subchnl); + if (rc<0) printf("CDROMSUBCHNL: rc=%d.\n",rc); + else + { + printf("AudioStatus:%s Track:%d Mode:%d MSF=%02d:%02d:%02d\n", + subchnl.cdsc_audiostatus==CDROM_AUDIO_PLAY ? "PLAYING":"NOT PLAYING", + subchnl.cdsc_trk,subchnl.cdsc_adr, + subchnl.cdsc_absaddr.msf.minute, + subchnl.cdsc_absaddr.msf.second, + subchnl.cdsc_absaddr.msf.frame); + } + break; + case 'i': + printf("Track No.: "); + scanf("%d",&i1); + entry.cdte_track=i1; + if (entry.cdte_track<first) entry.cdte_track=first; + if (entry.cdte_track>last) entry.cdte_track=last; + entry.cdte_format=CDROM_MSF; + rc=ioctl(drive,CDROMREADTOCENTRY,&entry); + if (rc<0) printf("CDROMREADTOCENTRY: rc=%d.\n",rc); + else + { + printf("Mode %d Track, starts at %02d:%02d:%02d\n", + entry.cdte_adr, + entry.cdte_addr.msf.minute, + entry.cdte_addr.msf.second, + entry.cdte_addr.msf.frame); + } + break; + case 'a': + printf("Address (min:sec:frm) "); + scanf("%d:%d:%d",&i1,&i2,&i3); + msf.cdmsf_min0=i1; + msf.cdmsf_sec0=i2; + msf.cdmsf_frame0=i3; + if (msf.cdmsf_sec0>59) msf.cdmsf_sec0=59; + if (msf.cdmsf_frame0>74) msf.cdmsf_frame0=74; + lba2msf(TocEntry[last+1].cdte_addr.lba-1,&msf.cdmsf_min1); + rc=ioctl(drive,CDROMSTOP); + rc=ioctl(drive,CDROMPLAYMSF,&msf); + if (rc<0) printf("CDROMPLAYMSF: rc=%d.\n",rc); + break; + case 'V': + rc=ioctl(drive,CDROMVOLREAD,&volctrl); + if (rc<0) printf("CDROMVOLCTRL: rc=%d.\n",rc); + printf("Volume: channel 0 (left) %d, channel 1 (right) %d\n",volctrl.channel0,volctrl.channel1); + break; + case 'R': + rc=ioctl(drive,CDROMRESET); + if (rc<0) printf("CDROMRESET: rc=%d.\n",rc); + break; +#ifdef AZT_PRIVATE_IOCTLS /*not supported by every CDROM driver*/ + case 'd': + printf("Address (min:sec:frm) "); + scanf("%d:%d:%d",&i1,&i2,&i3); + azt.msf.cdmsf_min0=i1; + azt.msf.cdmsf_sec0=i2; + azt.msf.cdmsf_frame0=i3; + if (azt.msf.cdmsf_sec0>59) azt.msf.cdmsf_sec0=59; + if (azt.msf.cdmsf_frame0>74) azt.msf.cdmsf_frame0=74; + rc=ioctl(drive,CDROMREADMODE1,&azt.msf); + if (rc<0) printf("CDROMREADMODE1: rc=%d.\n",rc); + else display(CD_FRAMESIZE,azt.buf); + break; + case 'w': + printf("Address (min:sec:frame) "); + scanf("%d:%d:%d",&i1,&i2,&i3); + azt.msf.cdmsf_min0=i1; + azt.msf.cdmsf_sec0=i2; + azt.msf.cdmsf_frame0=i3; + if (azt.msf.cdmsf_sec0>59) azt.msf.cdmsf_sec0=59; + if (azt.msf.cdmsf_frame0>74) azt.msf.cdmsf_frame0=74; + rc=ioctl(drive,CDROMREADMODE2,&azt.msf); + if (rc<0) printf("CDROMREADMODE2: rc=%d.\n",rc); + else display(CD_FRAMESIZE_RAW,azt.buf); /* currently only 2336 */ + break; +#endif + case 'v': + printf("--Channel 0 (Left) (0-255): "); + scanf("%d",&i1); + volctrl.channel0=i1; + printf("--Channel 1 (Right) (0-255): "); + scanf("%d",&i1); + volctrl.channel1=i1; + volctrl.channel2=0; + volctrl.channel3=0; + rc=ioctl(drive,CDROMVOLCTRL,&volctrl); + if (rc<0) printf("CDROMVOLCTRL: rc=%d.\n",rc); + break; + case 'q': + close(drive); + exit(0); + case 'h': + help(); + break; + case 'T': /* display TOC entry - without involving the driver */ + scanf("%d",&i); + if ((i<hdr.cdth_trk0)||(i>hdr.cdth_trk1)) + printf("invalid track number.\n"); + else + printf("TocEntry %02d: adr=%01X ctrl=%01X msf=%02d:%02d:%02d mode=%02X\n", + TocEntry[i].cdte_track, + TocEntry[i].cdte_adr, + TocEntry[i].cdte_ctrl, + TocEntry[i].cdte_addr.msf.minute, + TocEntry[i].cdte_addr.msf.second, + TocEntry[i].cdte_addr.msf.frame, + TocEntry[i].cdte_datamode); + break; + case 'A': /* read audio data into file */ + printf("Address (min:sec:frm) ? "); + scanf("%d:%d:%d",&i1,&i2,&i3); + read_audio.addr.msf.minute=i1; + read_audio.addr.msf.second=i2; + read_audio.addr.msf.frame=i3; + read_audio.addr_format=CDROM_MSF; + printf("# of frames ? "); + scanf("%d",&i1); + read_audio.nframes=i1; + k=read_audio.nframes*CD_FRAMESIZE_RAW; + read_audio.buf=malloc(k); + if (read_audio.buf==NULL) + { + printf("can't malloc %d bytes.\n",k); + break; + } + sprintf(filename,"audio_%02d%02d%02d_%02d.%02d\0", + read_audio.addr.msf.minute, + read_audio.addr.msf.second, + read_audio.addr.msf.frame, + read_audio.nframes, + ++sequence); + datafile=creat(filename, 0755); + if (datafile<0) + { + printf("can't open datafile %s.\n",filename); + break; + } + rc=ioctl(drive,CDROMREADAUDIO,&read_audio); + if (rc!=0) + { + printf("CDROMREADAUDIO: rc=%d.\n",rc); + } + else + { + rc=write(datafile,&read_audio.buf,k); + if (rc!=k) printf("datafile I/O error (%d).\n",rc); + } + close(datafile); + break; + case 'X': /* set EJECT_SW (0: disable, 1: enable auto-ejecting) */ + scanf("%d",&i); + rc=ioctl(drive,CDROMEJECT_SW,i); + if (rc!=0) + printf("CDROMEJECT_SW: rc=%d.\n",rc); + else + printf("EJECT_SW set to %d\n",i); + break; + case 'M': /* get the multisession redirection info */ + ms_info.addr_format=CDROM_LBA; + rc=ioctl(drive,CDROMMULTISESSION,&ms_info); + if (rc!=0) + { + printf("CDROMMULTISESSION(lba): rc=%d.\n",rc); + } + else + { + if (ms_info.xa_flag) printf("MultiSession offset (lba): %d (0x%06X)\n",ms_info.addr.lba,ms_info.addr.lba); + else + { + printf("this CD is not an XA disk.\n"); + break; + } + } + ms_info.addr_format=CDROM_MSF; + rc=ioctl(drive,CDROMMULTISESSION,&ms_info); + if (rc!=0) + { + printf("CDROMMULTISESSION(msf): rc=%d.\n",rc); + } + else + { + if (ms_info.xa_flag) + printf("MultiSession offset (msf): %02d:%02d:%02d (0x%02X%02X%02X)\n", + ms_info.addr.msf.minute, + ms_info.addr.msf.second, + ms_info.addr.msf.frame, + ms_info.addr.msf.minute, + ms_info.addr.msf.second, + ms_info.addr.msf.frame); + else printf("this CD is not an XA disk.\n"); + } + break; +#ifdef SBP_PRIVATE_IOCTLS + case 'Y': /* set the driver's message level */ +#if 0 /* not implemented yet */ + printf("enter switch name (f.e. DBG_CMD): "); + scanf("%s",&dbg_switch); + j=get_dbg_num(dbg_switch); +#else + printf("enter DDIOCSDBG switch number: "); + scanf("%d",&j); +#endif + printf("enter 0 for \"off\", 1 for \"on\": "); + scanf("%d",&i); + if (i==0) j|=0x80; + printf("calling \"ioctl(drive,DDIOCSDBG,%d)\"\n",j); + rc=ioctl(drive,DDIOCSDBG,j); + printf("DDIOCSDBG: rc=%d.\n",rc); + break; + case 'Z': /* set the audio buffer size */ + printf("# frames wanted: ? "); + scanf("%d",&j); + rc=ioctl(drive,CDROMAUDIOBUFSIZ,j); + printf("%d frames granted.\n",rc); + break; +#endif SBP_PRIVATE_IOCTLS + default: + printf("unknown command: \"%s\".\n",command); + break; + } + } +} +/*==========================================================================*/ + |