/* * sbpcd.c CD-ROM device driver for the whole family of traditional, * non-ATAPI IDE-style Matsushita/Panasonic CR-5xx drives. * Works with SoundBlaster compatible cards and with "no-sound" * interface cards like Lasermate, Panasonic CI-101P, Teac, ... * Also for the Longshine LCS-7260 drive. * Also for the IBM "External ISA CD-Rom" drive. * Also for the CreativeLabs CD200 drive. * Also for the TEAC CD-55A drive. * Also for the ECS-AT "Vertos 100" drive. * Not for Sanyo drives (but for the H94A, sjcd is there...). * Not for any other Funai drives than the CD200 types (sometimes * labelled E2550UA or MK4015 or 2800F). */ #define VERSION "v4.63 Andrew J. Kroll Wed Jul 26 04:24:10 EDT 2000" /* Copyright (C) 1993, 1994, 1995 Eberhard Moenkeberg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * You should have received a copy of the GNU General Public License * (for example /usr/src/linux/COPYING); if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * If you change this software, you should mail a .diff file with some * description lines to emoenke@gwdg.de. I want to know about it. * * If you are the editor of a Linux CD, you should enable sbpcd.c within * your boot floppy kernel and send me one of your CDs for free. * * If you would like to port the driver to an other operating system (f.e. * FreeBSD or NetBSD) or use it as an information source, you shall not be * restricted by the GPL under the following conditions: * a) the source code of your work is freely available * b) my part of the work gets mentioned at all places where your * authorship gets mentioned * c) I receive a copy of your code together with a full installation * package of your operating system for free. * * * VERSION HISTORY * * 0.1 initial release, April/May 93, after mcd.c (Martin Harriss) * * 0.2 thek "repeat:"-loop in do_sbpcd_request did not check for * end-of-request_queue (resulting in kernel panic). * Flow control seems stable, but throughput is not better. * * 0.3 interrupt locking totally eliminated (maybe "inb" and "outb" * are still locking) - 0.2 made keyboard-type-ahead losses. * check_sbpcd_media_change added (to use by isofs/inode.c) * - but it detects almost nothing. * * 0.4 use MAJOR 25 definitely. * Almost total re-design to support double-speed drives and * "naked" (no sound) interface cards ("LaserMate" interface type). * Flow control should be exact now. * Don't occupy the SbPro IRQ line (not needed either); will * live together with Hannu Savolainen's sndkit now. * Speeded up data transfer to 150 kB/sec, with help from Kai * Makisara, the "provider" of the "mt" tape utility. * Give "SpinUp" command if necessary. * First steps to support up to 4 drives (but currently only one). * Implemented audio capabilities - workman should work, xcdplayer * gives some problems. * This version is still consuming too much CPU time, and * sleeping still has to be worked on. * During "long" implied seeks, it seems possible that a * ReadStatus command gets ignored. That gives the message * "ResponseStatus timed out" (happens about 6 times here during * a "ls -alR" of the YGGDRASIL LGX-Beta CD). Such a case is * handled without data error, but it should get done better. * * 0.5 Free CPU during waits (again with help from Kai Makisara). * Made it work together with the LILO/kernel setup standard. * Included auto-probing code, as suggested by YGGDRASIL. * Formal redesign to add DDI debugging. * There are still flaws in IOCTL (workman with double speed drive). * * 1.0 Added support for all drive IDs (0...3, no longer only 0) * and up to 4 drives on one controller. * Added "#define MANY_SESSION" for "old" multi session CDs. * * 1.1 Do SpinUp for new drives, too. * Revised for clean compile under "old" kernels (0.99pl9). * * 1.2 Found the "workman with double-speed drive" bug: use the driver's * audio_state, not what the drive is reporting with ReadSubQ. * * 1.3 Minor cleanups. * Refinements regarding Workman. * * 1.4 Read XA disks (PhotoCDs) with "old" drives, too (but only the first * session - no chance to fully access a "multi-session" CD). * This currently still is too slow (50 kB/sec) - but possibly * the old drives won't do it faster. * Implemented "door (un)lock" for new drives (still does not work * as wanted - no lock possible after an unlock). * Added some debugging printout for the UPC/EAN code - but my drives * return only zeroes. Is there no UPC/EAN code written? * * 1.5 Laborate with UPC/EAN code (not better yet). * Adapt to kernel 1.1.8 change (have to explicitly include * now). * * 1.6 Trying to read audio frames as data. Impossible with the current * drive firmware levels, as it seems. Awaiting any hint. ;-) * Changed "door unlock": repeat it until success. * Changed CDROMSTOP routine (stop somewhat "softer" so that Workman * won't get confused). * Added a third interface type: Sequoia S-1000, as used with the SPEA * Media FX sound card. This interface (usable for Sony and Mitsumi * drives, too) needs a special configuration setup and behaves like a * LaserMate type after that. Still experimental - I do not have such * an interface. * Use the "variable BLOCK_SIZE" feature (2048). But it does only work * if you give the mount option "block=2048". * The media_check routine is currently disabled; now that it gets * called as it should I fear it must get synchronized for not to * disturb the normal driver's activity. * * 2.0 Version number bumped - two reasons: * - reading audio tracks as data works now with CR-562 and CR-563. We * currently do it by an IOCTL (yet has to get standardized), one frame * at a time; that is pretty slow. But it works. * - we are maintaining now up to 4 interfaces (each up to 4 drives): * did it the easy way - a different MAJOR (25, 26, ...) and a different * copy of the driver (sbpcd.c, sbpcd2.c, sbpcd3.c, sbpcd4.c - only * distinguished by the value of SBPCD_ISSUE and the driver's name), * and a common sbpcd.h file. * Bettered the "ReadCapacity error" problem with old CR-52x drives (the * drives sometimes need a manual "eject/insert" before work): just * reset the drive and do again. Needs lots of resets here and sometimes * that does not cure, so this can't be the solution. * * 2.1 Found bug with multisession CDs (accessing frame 16). * "read audio" works now with address type CDROM_MSF, too. * Bigger audio frame buffer: allows reading max. 4 frames at time; this * gives a significant speedup, but reading more than one frame at once * gives missing chunks at each single frame boundary. * * 2.2 Kernel interface cleanups: timers, init, setup, media check. * * 2.3 Let "door lock" and "eject" live together. * Implemented "close tray" (done automatically during open). * * 2.4 Use different names for device registering. * * 2.5 Added "#if EJECT" code (default: enabled) to automatically eject * the tray during last call to "sbpcd_release". * Added "#if JUKEBOX" code (default: disabled) to automatically eject * the tray during call to "sbpcd_open" if no disk is in. * Turn on the CD volume of "compatible" sound cards, too; just define * SOUND_BASE (in sbpcd.h) accordingly (default: disabled). * * 2.6 Nothing new. * * 2.7 Added CDROMEJECT_SW ioctl to set the "EJECT" behavior on the fly: * 0 disables, 1 enables auto-ejecting. Useful to keep the tray in * during shutdown. * * 2.8 Added first support (still BETA, I need feedback or a drive) for * the Longshine LCS-7260 drives. They appear as double-speed drives * using the "old" command scheme, extended by tray control and door * lock functions. * Found (and fixed preliminary) a flaw with some multisession CDs: we * have to re-direct not only the accesses to frame 16 (the isofs * routines drive it up to max. 100), but also those to the continuation * (repetition) frames (as far as they exist - currently set fix as * 16..20). * Changed default of the "JUKEBOX" define. If you use this default, * your tray will eject if you try to mount without a disk in. Next * mount command will insert the tray - so, just fill in a disk. ;-) * * 2.9 Fulfilled the Longshine LCS-7260 support; with great help and * experiments by Serge Robyns. * First attempts to support the TEAC CD-55A drives; but still not * usable yet. * Implemented the CDROMMULTISESSION ioctl; this is an attempt to handle * multi session CDs more "transparent" (redirection handling has to be * done within the isofs routines, and only for the special purpose of * obtaining the "right" volume descriptor; accesses to the raw device * should not get redirected). * * 3.0 Just a "normal" increment, with some provisions to do it better. ;-) * Introduced "#define READ_AUDIO" to specify the maximum number of * audio frames to grab with one request. This defines a buffer size * within kernel space; a value of 0 will reserve no such space and * disable the CDROMREADAUDIO ioctl. A value of 75 enables the reading * of a whole second with one command, but will use a buffer of more * than 172 kB. * Started CD200 support. Drive detection should work, but nothing * more. * * 3.1 Working to support the CD200 and the Teac CD-55A drives. * AT-BUS style device numbering no longer used: use SCSI style now. * So, the first "found" device has MINOR 0, regardless of the * jumpered drive ID. This implies modifications to the /dev/sbpcd* * entries for some people, but will help the DAU (german TLA, english: * "newbie", maybe ;-) to install his "first" system from a CD. * * 3.2 Still testing with CD200 and CD-55A drives. * * 3.3 Working with CD200 support. * * 3.4 Auto-probing stops if an address of 0 is seen (to be entered with * the kernel command line). * Made the driver "loadable". If used as a module, "audio copy" is * disabled, and the internal read ahead data buffer has a reduced size * of 4 kB; so, throughput may be reduced a little bit with slow CPUs. * * 3.5 Provisions to handle weird photoCDs which have an interrupted * "formatting" immediately after the last frames of some files: simply * never "read ahead" with MultiSession CDs. By this, CPU usage may be * increased with those CDs, and there may be a loss in speed. * Re-structured the messaging system. * The "loadable" version no longer has a limited READ_AUDIO buffer * size. * Removed "MANY_SESSION" handling for "old" multi session CDs. * Added "private" IOCTLs CDROMRESET and CDROMVOLREAD. * Started again to support the TEAC CD-55A drives, now that I found * the money for "my own" drive. ;-) * The TEAC CD-55A support is fairly working now. * I have measured that the drive "delivers" at 600 kB/sec (even with * bigger requests than the drive's 64 kB buffer can satisfy), but * the "real" rate does not exceed 520 kB/sec at the moment. * Caused by the various changes to build in TEAC support, the timed * loops are de-optimized at the moment (less throughput with CR-52x * drives, and the TEAC will give speed only with SBP_BUFFER_FRAMES 64). * * 3.6 Fixed TEAC data read problems with SbPro interfaces. * Initial size of the READ_AUDIO buffer is 0. Can get set to any size * during runtime. * * 3.7 Introduced MAX_DRIVES for some poor interface cards (seen with TEAC * drives) which allow only one drive (ID 0); this avoids repetitive * detection under IDs 1..3. * Elongated cmd_out_T response waiting; necessary for photo CDs with * a lot of sessions. * Bettered the sbpcd_open() behavior with TEAC drives. * * 3.8 Elongated max_latency for CR-56x drives. * * 3.9 Finally fixed the long-known SoundScape/SPEA/Sequoia S-1000 interface * configuration bug. * Now Corey, Heiko, Ken, Leo, Vadim/Eric & Werner are invited to copy * the config_spea() routine into their drivers. ;-) * * 4.0 No "big step" - normal version increment. * Adapted the benefits from 1.3.33. * Fiddled with CDROMREADAUDIO flaws. * Avoid ReadCapacity command with CD200 drives (the MKE 1.01 version * seems not to support it). * Fulfilled "read audio" for CD200 drives, with help of Pete Heist * (heistp@rpi.edu). * * 4.1 Use loglevel KERN_INFO with printk(). * Added support for "Vertos 100" drive ("ECS-AT") - it is very similar * to the Longshine LCS-7260. Give feedback if you can - I never saw * such a drive, and I have no specs. * * 4.2 Support for Teac 16-bit interface cards. Can't get auto-detected, * so you have to jumper your card to 0x2C0. Still not 100% - come * in contact if you can give qualified feedback. * Use loglevel KERN_NOTICE with printk(). If you get annoyed by a * flood of unwanted messages and the accompanied delay, try to read * my documentation. Especially the Linux CDROM drivers have to do an * important job for the newcomers, so the "distributed" version has * to fit some special needs. Since generations, the flood of messages * is user-configurable (even at runtime), but to get aware of this, one * needs a special mental quality: the ability to read. * * 4.3 CD200F does not like to receive a command while the drive is * reading the ToC; still trying to solve it. * Removed some redundant verify_area calls (yes, Heiko Eissfeldt * is visiting all the Linux CDROM drivers ;-). * * 4.4 Adapted one idea from tiensivu@pilot.msu.edu's "stripping-down" * experiments: "KLOGD_PAUSE". * Inhibited "play audio" attempts with data CDs. Provisions for a * "data-safe" handling of "mixed" (data plus audio) Cds. * * 4.5 Meanwhile Gonzalo Tornaria (GTL) built a * special end_request routine: we seem to have to take care for not * to have two processes working at the request list. My understanding * was and is that ll_rw_blk should not call do_sbpcd_request as long * as there is still one call active (the first call will care for all * outstanding I/Os, and if a second call happens, that is a bug in * ll_rw_blk.c). * "Check media change" without touching any drive. * * 4.6 Use a semaphore to synchronize multi-activity; elaborated by Rob * Riggs . At the moment, we simply block "read" * against "ioctl" and vice versa. This could be refined further, but * I guess with almost no performance increase. * Experiments to speed up the CD-55A; again with help of Rob Riggs * (to be true, he gave both, idea & code. ;-) * * 4.61 Ported to Uniform CD-ROM driver by * Heiko Eissfeldt with additional * changes by Erik Andersen * * 4.62 Fix a bug where playing audio left the drive in an unusable state. * Heiko Eissfeldt * * November 1999 -- Make kernel-parameter implementation work with 2.3.x * Removed init_module & cleanup_module in favor of * module_init & module_exit. * Torben Mathiasen * * 4.63 Bug fixes for audio annoyances, new legacy CDROM maintainer. * Annoying things fixed: * TOC reread on automated disk changes * TOC reread on manual cd changes * Play IOCTL tries to play CD before it's actually ready... sometimes. * CD_AUDIO_COMPLETED state so workman (and other playes) can repeat play. * Andrew J. Kroll Wed Jul 26 04:24:10 EDT 2000 * * 4.64 Fix module parameters - were being completely ignored. * Can also specify max_drives=N as a setup int to get rid of * "ghost" drives on crap hardware (aren't they all?) Paul Gortmaker * * TODO * implement "read all subchannel data" (96 bytes per frame) * remove alot of the virtual status bits and deal with hardware status * move the change of cd for audio to a better place * add debug levels to insmod parameters (trivial) * * special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine * elaborated speed-up experiments (and the fabulous results!), for * the "push" towards load-free wait loops, and for the extensive mail * thread which brought additional hints and bug fixes. * */ /* * Trying to merge requests breaks this driver horribly (as in it goes * boom and apparently has done so since 2.3.41). As it is a legacy * driver for a horribly slow double speed CD on a hideous interface * designed for polled operation, I won't lose any sleep in simply * disallowing merging. Paul G. 02/2001 * * Thu May 30 14:14:47 CEST 2002: * * I have presumably found the reson for the above - there was a bogous * end_request substitute, which was manipulating the request queues * incorrectly. If someone has access to the actual hardware, and it's * still operations - well please free to test it. * * Marcin Dalecki */ /* * Add bio/kdev_t changes for 2.5.x required to make it work again. * Still room for improvement in the request handling here if anyone * actually cares. Bring your own chainsaw. Paul G. 02/2002 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sbpcd.h" #define MAJOR_NR MATSUSHITA_CDROM_MAJOR #include /*==========================================================================*/ #if SBPCD_DIS_IRQ # define SBPCD_CLI cli() # define SBPCD_STI sti() #else # define SBPCD_CLI # define SBPCD_STI #endif /*==========================================================================*/ /* * auto-probing address list * inspired by Adam J. Richter from Yggdrasil * * still not good enough - can cause a hang. * example: a NE 2000 ethernet card at 300 will cause a hang probing 310. * if that happens, reboot and use the LILO (kernel) command line. * The possibly conflicting ethernet card addresses get NOT probed * by default - to minimize the hang possibilities. * * The SB Pro addresses get "mirrored" at 0x6xx and some more locations - to * avoid a type error, the 0x2xx-addresses must get checked before 0x6xx. * * send mail to emoenke@gwdg.de if your interface card is not FULLY * represented here. */ static int sbpcd[] = { CDROM_PORT, SBPRO, /* probe with user's setup first */ #if DISTRIBUTION 0x230, 1, /* Soundblaster Pro and 16 (default) */ #if 0 0x300, 0, /* CI-101P (default), WDH-7001C (default), Galaxy (default), Reveal (one default) */ 0x250, 1, /* OmniCD default, Soundblaster Pro and 16 */ 0x2C0, 3, /* Teac 16-bit cards */ 0x260, 1, /* OmniCD */ 0x320, 0, /* Lasermate, CI-101P, WDH-7001C, Galaxy, Reveal (other default), Longshine LCS-6853 (default) */ 0x338, 0, /* Reveal Sound Wave 32 card model #SC600 */ 0x340, 0, /* Mozart sound card (default), Lasermate, CI-101P */ 0x360, 0, /* Lasermate, CI-101P */ 0x270, 1, /* Soundblaster 16 */ 0x670, 0, /* "sound card #9" */ 0x690, 0, /* "sound card #9" */ 0x338, 2, /* SPEA Media FX, Ensonic SoundScape (default) */ 0x328, 2, /* SPEA Media FX */ 0x348, 2, /* SPEA Media FX */ 0x634, 0, /* some newer sound cards */ 0x638, 0, /* some newer sound cards */ 0x230, 1, /* some newer sound cards */ /* due to incomplete address decoding of the SbPro card, these must be last */ 0x630, 0, /* "sound card #9" (default) */ 0x650, 0, /* "sound card #9" */ #ifdef MODULE /* * some "hazardous" locations (no harm with the loadable version) * (will stop the bus if a NE2000 ethernet card resides at offset -0x10) */ 0x330, 0, /* Lasermate, CI-101P, WDH-7001C */ 0x350, 0, /* Lasermate, CI-101P */ 0x358, 2, /* SPEA Media FX */ 0x370, 0, /* Lasermate, CI-101P */ 0x290, 1, /* Soundblaster 16 */ 0x310, 0, /* Lasermate, CI-101P, WDH-7001C */ #endif /* MODULE */ #endif #endif /* DISTRIBUTION */ }; /* * Protects access to global structures etc. */ static __cacheline_aligned DEFINE_SPINLOCK(sbpcd_lock); static struct request_queue *sbpcd_queue; /* You can only set the first pair, from old MODULE_PARM code. */ static int sbpcd_set(const char *val, struct kernel_param *kp) { get_options((char *)val, 2, (int *)sbpcd); return 0; } module_param_call(sbpcd, sbpcd_set, NULL, NULL, 0); #define NUM_PROBE (sizeof(sbpcd) / sizeof(int)) /*==========================================================================*/ #define INLINE inline /*==========================================================================*/ /* * the forward references: */ static void sbp_sleep(u_int); static void mark_timeout_delay(u_long); static void mark_timeout_data(u_long); #if 0 static void mark_timeout_audio(u_long); #endif static void sbp_read_cmd(struct request *req); static int sbp_data(struct request *req); static int cmd_out(void); static int DiskInfo(void); /*==========================================================================*/ /* * pattern for printk selection: * * (1<99) msgnum=0; sprintf(buf, MSG_LEVEL "%s-%d [%02d]: ", major_name, current_drive - D_S, msgnum); va_start(args, fmt); vsprintf(&buf[18], fmt, args); va_end(args); printk(buf); #if KLOGD_PAUSE sbp_sleep(KLOGD_PAUSE); /* else messages get lost */ #endif /* KLOGD_PAUSE */ return; } /*==========================================================================*/ /* * DDI interface: runtime trace bit pattern maintenance */ static int sbpcd_dbg_ioctl(unsigned long arg, int level) { switch(arg) { case 0: /* OFF */ sbpcd_debug = DBG_INF; break; default: if (arg>=128) sbpcd_debug &= ~(1<<(arg-128)); else sbpcd_debug |= (1<>4)); } /*==========================================================================*/ static INLINE u_char byt2bcd(u_char i) { return (((i/10)<<4)+i%10); } /*==========================================================================*/ static INLINE u_char bcd2bin(u_char bcd) { return ((bcd>>4)*10+(bcd&0x0F)); } /*==========================================================================*/ static INLINE int msf2blk(int msfx) { MSF msf; int i; msf.n=msfx; i=(msf.c[2] * CD_SECS + msf.c[1]) * CD_FRAMES + msf.c[0] - CD_MSF_OFFSET; if (i<0) return (0); return (i); } /*==========================================================================*/ /* * convert m-s-f_number (3 bytes only) to logical_block_address */ static INLINE int msf2lba(u_char *msf) { int i; i=(msf[0] * CD_SECS + msf[1]) * CD_FRAMES + msf[2] - CD_MSF_OFFSET; if (i<0) return (0); return (i); } /*==========================================================================*/ /* evaluate cc_ReadError code */ static int sta2err(int sta) { if (famT_drive) { if (sta==0x00) return (0); if (sta==0x01) return (-604); /* CRC error */ if (sta==0x02) return (-602); /* drive not ready */ if (sta==0x03) return (-607); /* unknown media */ if (sta==0x04) return (-612); /* general failure */ if (sta==0x05) return (0); if (sta==0x06) return (-ERR_DISKCHANGE); /* disk change */ if (sta==0x0b) return (-612); /* general failure */ if (sta==0xff) return (-612); /* general failure */ return (0); } else { if (sta<=2) return (sta); if (sta==0x05) return (-604); /* CRC error */ if (sta==0x06) return (-606); /* seek error */ if (sta==0x0d) return (-606); /* seek error */ if (sta==0x0e) return (-603); /* unknown command */ if (sta==0x14) return (-603); /* unknown command */ if (sta==0x0c) return (-611); /* read fault */ if (sta==0x0f) return (-611); /* read fault */ if (sta==0x10) return (-611); /* read fault */ if (sta>=0x16) return (-612); /* general failure */ if (sta==0x11) return (-ERR_DISKCHANGE); /* disk change (LCS: removed) */ if (famL_drive) if (sta==0x12) return (-ERR_DISKCHANGE); /* disk change (inserted) */ return (-602); /* drive not ready */ } } /*==========================================================================*/ static INLINE void clr_cmdbuf(void) { int i; for (i=0;i<10;i++) drvcmd[i]=0; cmd_type=0; } /*==========================================================================*/ static void flush_status(void) { int i; sbp_sleep(15*HZ/10); for (i=maxtim_data;i!=0;i--) inb(CDi_status); } /*====================================================================*/ /* * CDi status loop for Teac CD-55A (Rob Riggs) * * This is needed because for some strange reason * the CD-55A can take a real long time to give a * status response. This seems to happen after we * issue a READ command where a long seek is involved. * * I tried to ensure that we get max throughput with * minimal busy waiting. We busy wait at first, then * "switch gears" and start sleeping. We sleep for * longer periods of time the longer we wait. * */ static int CDi_stat_loop_T(void) { int i, gear=1; u_long timeout_1, timeout_2, timeout_3, timeout_4; timeout_1 = jiffies + HZ / 50; /* sbp_sleep(0) for a short period */ timeout_2 = jiffies + HZ / 5; /* nap for no more than 200ms */ timeout_3 = jiffies + 5 * HZ; /* sleep for up to 5s */ timeout_4 = jiffies + 45 * HZ; /* long sleep for up to 45s. */ do { i = inb(CDi_status); if (!(i&s_not_data_ready)) return (i); if (!(i&s_not_result_ready)) return (i); switch(gear) { case 4: sbp_sleep(HZ); if (time_after(jiffies, timeout_4)) gear++; msg(DBG_TEA, "CDi_stat_loop_T: long sleep active.\n"); break; case 3: sbp_sleep(HZ/10); if (time_after(jiffies, timeout_3)) gear++; break; case 2: sbp_sleep(HZ/100); if (time_after(jiffies, timeout_2)) gear++; break; case 1: sbp_sleep(0); if (time_after(jiffies, timeout_1)) gear++; } } while (gear < 5); return -1; } /*==========================================================================*/ static int CDi_stat_loop(void) { int i,j; for(timeout = jiffies + 10*HZ, i=maxtim_data; time_before(jiffies, timeout); ) { for ( ;i!=0;i--) { j=inb(CDi_status); if (!(j&s_not_data_ready)) return (j); if (!(j&s_not_result_ready)) return (j); if (fam0L_drive) if (j&s_attention) return (j); } sbp_sleep(1); i = 1; } msg(DBG_LCS,"CDi_stat_loop failed in line %d\n", __LINE__); return (-1); } /*==========================================================================*/ #if 00000 /*==========================================================================*/ static int tst_DataReady(void) { int i; i=inb(CDi_status); if (i&s_not_data_ready) return (0); return (1); } /*==========================================================================*/ static int tst_ResultReady(void) { int i; i=inb(CDi_status); if (i&s_not_result_ready) return (0); return (1); } /*==========================================================================*/ static int tst_Attention(void) { int i; i=inb(CDi_status); if (i&s_attention) return (1); return (0); } /*==========================================================================*/ #endif /*==========================================================================*/ static int ResponseInfo(void) { int i,j,st=0; u_long timeout; for (i=0,timeout=jiffies+HZ;i0) msg(DBG_INF,"ResponseInfo: got %d trailing bytes.\n",j); #endif /* 000 */ for (j=0;j0) return (-j); else return (i); } /*==========================================================================*/ static void EvaluateStatus(int st) { current_drive->status_bits=0; if (fam1_drive) current_drive->status_bits=st|p_success; else if (fam0_drive) { if (st&p_caddin_old) current_drive->status_bits |= p_door_closed|p_caddy_in; if (st&p_spinning) current_drive->status_bits |= p_spinning; if (st&p_check) current_drive->status_bits |= p_check; if (st&p_success_old) current_drive->status_bits |= p_success; if (st&p_busy_old) current_drive->status_bits |= p_busy_new; if (st&p_disk_ok) current_drive->status_bits |= p_disk_ok; } else if (famLV_drive) { current_drive->status_bits |= p_success; if (st&p_caddin_old) current_drive->status_bits |= p_disk_ok|p_caddy_in; if (st&p_spinning) current_drive->status_bits |= p_spinning; if (st&p_check) current_drive->status_bits |= p_check; if (st&p_busy_old) current_drive->status_bits |= p_busy_new; if (st&p_lcs_door_closed) current_drive->status_bits |= p_door_closed; if (st&p_lcs_door_locked) current_drive->status_bits |= p_door_locked; } else if (fam2_drive) { current_drive->status_bits |= p_success; if (st&p2_check) current_drive->status_bits |= p1_check; if (st&p2_door_closed) current_drive->status_bits |= p1_door_closed; if (st&p2_disk_in) current_drive->status_bits |= p1_disk_in; if (st&p2_busy1) current_drive->status_bits |= p1_busy; if (st&p2_busy2) current_drive->status_bits |= p1_busy; if (st&p2_spinning) current_drive->status_bits |= p1_spinning; if (st&p2_door_locked) current_drive->status_bits |= p1_door_locked; if (st&p2_disk_ok) current_drive->status_bits |= p1_disk_ok; } else if (famT_drive) { return; /* still needs to get coded */ current_drive->status_bits |= p_success; if (st&p2_check) current_drive->status_bits |= p1_check; if (st&p2_door_closed) current_drive->status_bits |= p1_door_closed; if (st&p2_disk_in) current_drive->status_bits |= p1_disk_in; if (st&p2_busy1) current_drive->status_bits |= p1_busy; if (st&p2_busy2) current_drive->status_bits |= p1_busy; if (st&p2_spinning) current_drive->status_bits |= p1_spinning; if (st&p2_door_locked) current_drive->status_bits |= p1_door_locked; if (st&p2_disk_ok) current_drive->status_bits |= p1_disk_ok; } return; } /*==========================================================================*/ static int cmd_out_T(void); static int get_state_T(void) { int i; clr_cmdbuf(); current_drive->n_bytes=1; drvcmd[0]=CMDT_STATUS; i=cmd_out_T(); if (i>=0) i=infobuf[0]; else { msg(DBG_TEA,"get_state_T error %d\n", i); return (i); } if (i>=0) /* 2: closed, disk in */ current_drive->status_bits=p1_door_closed|p1_disk_in|p1_spinning|p1_disk_ok; else if (current_drive->error_state==6) { /* 3: closed, disk in, changed ("06 xx xx") */ current_drive->status_bits=p1_door_closed|p1_disk_in; current_drive->CD_changed=0xFF; current_drive->diskstate_flags &= ~toc_bit; } else if ((current_drive->error_state!=2)||(current_drive->b3!=0x3A)||(current_drive->b4==0x00)) { /* 1: closed, no disk ("xx yy zz"or "02 3A 00") */ current_drive->status_bits=p1_door_closed; current_drive->open_count=0; } else if (current_drive->b4==0x01) { /* 0: open ("02 3A 01") */ current_drive->status_bits=0; current_drive->open_count=0; } else { /* 1: closed, no disk ("02 3A xx") */ current_drive->status_bits=p1_door_closed; current_drive->open_count=0; } return (current_drive->status_bits); } /*==========================================================================*/ static int ResponseStatus(void) { int i,j; u_long timeout; msg(DBG_STA,"doing ResponseStatus...\n"); if (famT_drive) return (get_state_T()); if (flags_cmd_out & f_respo3) timeout = jiffies; else if (flags_cmd_out & f_respo2) timeout = jiffies + 16*HZ; else timeout = jiffies + 4*HZ; j=maxtim_8; do { for ( ;j!=0;j--) { i=inb(CDi_status); if (!(i&s_not_result_ready)) break; } if ((j!=0)||time_after(jiffies, timeout)) break; sbp_sleep(1); j = 1; } while (1); if (j==0) { if ((flags_cmd_out & f_respo3) == 0) msg(DBG_STA,"ResponseStatus: timeout.\n"); current_drive->status_bits=0; return (-401); } i=inb(CDi_info); msg(DBG_STA,"ResponseStatus: response %02X.\n", i); EvaluateStatus(i); msg(DBG_STA,"status_bits=%02X, i=%02X\n",current_drive->status_bits,i); return (current_drive->status_bits); } /*==========================================================================*/ static void cc_ReadStatus(void) { int i; msg(DBG_STA,"giving cc_ReadStatus command\n"); if (famT_drive) return; SBPCD_CLI; if (fam0LV_drive) OUT(CDo_command,CMD0_STATUS); else if (fam1_drive) OUT(CDo_command,CMD1_STATUS); else if (fam2_drive) OUT(CDo_command,CMD2_STATUS); if (!fam0LV_drive) for (i=0;i<6;i++) OUT(CDo_command,0); SBPCD_STI; } /*==========================================================================*/ static int cc_ReadError(void) { int i; clr_cmdbuf(); msg(DBG_ERR,"giving cc_ReadError command.\n"); if (fam1_drive) { drvcmd[0]=CMD1_READ_ERR; response_count=8; flags_cmd_out=f_putcmd|f_ResponseStatus; } else if (fam0LV_drive) { drvcmd[0]=CMD0_READ_ERR; response_count=6; if (famLV_drive) flags_cmd_out=f_putcmd; else flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus; } else if (fam2_drive) { drvcmd[0]=CMD2_READ_ERR; response_count=6; flags_cmd_out=f_putcmd; } else if (famT_drive) { response_count=5; drvcmd[0]=CMDT_READ_ERR; } i=cmd_out(); current_drive->error_byte=0; msg(DBG_ERR,"cc_ReadError: cmd_out(CMDx_READ_ERR) returns %d (%02X)\n",i,i); if (i<0) return (i); if (fam0V_drive) i=1; else i=2; current_drive->error_byte=infobuf[i]; msg(DBG_ERR,"cc_ReadError: infobuf[%d] is %d (%02X)\n",i,current_drive->error_byte,current_drive->error_byte); i=sta2err(infobuf[i]); if (i==-ERR_DISKCHANGE) { current_drive->CD_changed=0xFF; current_drive->diskstate_flags &= ~toc_bit; } return (i); } /*==========================================================================*/ static int cc_DriveReset(void); static int cmd_out_T(void) { #undef CMDT_TRIES #define CMDT_TRIES 1000 #define TEST_FALSE_FF 1 int i, j, l=0, m, ntries; unsigned long flags; current_drive->error_state=0; current_drive->b3=0; current_drive->b4=0; current_drive->f_drv_error=0; for (i=0;i<10;i++) sprintf(&msgbuf[i*3]," %02X",drvcmd[i]); msgbuf[i*3]=0; msg(DBG_CMD,"cmd_out_T:%s\n",msgbuf); OUT(CDo_sel_i_d,0); OUT(CDo_enable,current_drive->drv_sel); i=inb(CDi_status); do_16bit=0; if ((f_16bit)&&(!(i&0x80))) { do_16bit=1; msg(DBG_TEA,"cmd_out_T: do_16bit set.\n"); } if (!(i&s_not_result_ready)) do { j=inb(CDi_info); i=inb(CDi_status); sbp_sleep(0); msg(DBG_TEA,"cmd_out_T: spurious !s_not_result_ready. (%02X)\n", j); } while (!(i&s_not_result_ready)); save_flags(flags); cli(); for (i=0;i<10;i++) OUT(CDo_command,drvcmd[i]); restore_flags(flags); for (ntries=CMDT_TRIES;ntries>0;ntries--) { if (drvcmd[0]==CMDT_READ_VER) sbp_sleep(HZ); /* fixme */ #if 01 OUT(CDo_sel_i_d,1); #endif /* 01 */ if (teac==2) { if ((i=CDi_stat_loop_T()) == -1) break; } else { #if 0 OUT(CDo_sel_i_d,1); #endif /* 0 */ i=inb(CDi_status); } if (!(i&s_not_data_ready)) /* f.e. CMDT_DISKINFO */ { OUT(CDo_sel_i_d,1); if (drvcmd[0]==CMDT_READ) return (0); /* handled elsewhere */ if (drvcmd[0]==CMDT_DISKINFO) { l=0; do { if (do_16bit) { i=inw(CDi_data); infobuf[l++]=i&0x0ff; infobuf[l++]=i>>8; #if TEST_FALSE_FF if ((l==2)&&(infobuf[0]==0x0ff)) { infobuf[0]=infobuf[1]; l=1; msg(DBG_TEA,"cmd_out_T: do_16bit: false first byte!\n"); } #endif /* TEST_FALSE_FF */ } else infobuf[l++]=inb(CDi_data); i=inb(CDi_status); } while (!(i&s_not_data_ready)); for (j=0;j1) msg(DBG_TEA,"cmd_out_T READ_ERR recursion (%02X): %d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", drvcmd[0], recursion); clr_cmdbuf(); drvcmd[0]=CMDT_READ_ERR; j=cmd_out_T(); /* !!! recursive here !!! */ --recursion; sbp_sleep(1); } while (j<0); current_drive->error_state=infobuf[2]; current_drive->b3=infobuf[3]; current_drive->b4=infobuf[4]; if (current_drive->f_drv_error) { current_drive->f_drv_error=0; cc_DriveReset(); current_drive->error_state=2; } return (-current_drive->error_state-400); } if (drvcmd[0]==CMDT_READ) return (0); /* handled elsewhere */ if ((teac==0)||(ntries<(CMDT_TRIES-5))) sbp_sleep(HZ/10); else sbp_sleep(HZ/100); if (ntries>(CMDT_TRIES-50)) continue; msg(DBG_TEA,"cmd_out_T: next CMDT_TRIES (%02X): %d.\n", drvcmd[0], ntries-1); } current_drive->f_drv_error=1; cc_DriveReset(); current_drive->error_state=2; return (-99); } /*==========================================================================*/ static int cmd_out(void) { int i=0; if (famT_drive) return(cmd_out_T()); if (flags_cmd_out&f_putcmd) { unsigned long flags; for (i=0;i<7;i++) sprintf(&msgbuf[i*3], " %02X", drvcmd[i]); msgbuf[i*3]=0; msg(DBG_CMD,"cmd_out:%s\n", msgbuf); save_flags(flags); cli(); for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]); restore_flags(flags); } if (response_count!=0) { if (cmd_type!=0) { if (sbpro_type==1) OUT(CDo_sel_i_d,1); msg(DBG_INF,"misleaded to try ResponseData.\n"); if (sbpro_type==1) OUT(CDo_sel_i_d,0); return (-22); } else i=ResponseInfo(); if (i<0) return (i); } if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to CDi_stat_loop.\n"); if (flags_cmd_out&f_lopsta) { i=CDi_stat_loop(); if ((i<0)||!(i&s_attention)) return (-8); } if (!(flags_cmd_out&f_getsta)) goto LOC_229; LOC_228: if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cc_ReadStatus.\n"); cc_ReadStatus(); LOC_229: if (flags_cmd_out&f_ResponseStatus) { if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to ResponseStatus.\n"); i=ResponseStatus(); /* builds status_bits, returns orig. status or p_busy_new */ if (i<0) return (i); if (flags_cmd_out&(f_bit1|f_wait_if_busy)) { if (!st_check) { if ((flags_cmd_out&f_bit1)&&(i&p_success)) goto LOC_232; if ((!(flags_cmd_out&f_wait_if_busy))||(!st_busy)) goto LOC_228; } } } LOC_232: if (!(flags_cmd_out&f_obey_p_check)) return (0); if (!st_check) return (0); if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cc_ReadError.\n"); i=cc_ReadError(); if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cmd_out OK.\n"); msg(DBG_000,"cmd_out: cc_ReadError=%d\n", i); return (i); } /*==========================================================================*/ static int cc_Seek(u_int pos, char f_blk_msf) { int i; clr_cmdbuf(); if (f_blk_msf>1) return (-3); if (fam0V_drive) { drvcmd[0]=CMD0_SEEK; if (f_blk_msf==1) pos=msf2blk(pos); drvcmd[2]=(pos>>16)&0x00FF; drvcmd[3]=(pos>>8)&0x00FF; drvcmd[4]=pos&0x00FF; if (fam0_drive) flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta | f_ResponseStatus | f_obey_p_check | f_bit1; else flags_cmd_out = f_putcmd; } else if (fam1L_drive) { drvcmd[0]=CMD1_SEEK; /* same as CMD1_ and CMDL_ */ if (f_blk_msf==0) pos=blk2msf(pos); drvcmd[1]=(pos>>16)&0x00FF; drvcmd[2]=(pos>>8)&0x00FF; drvcmd[3]=pos&0x00FF; if (famL_drive) flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; else flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; } else if (fam2_drive) { drvcmd[0]=CMD2_SEEK; if (f_blk_msf==0) pos=blk2msf(pos); drvcmd[2]=(pos>>24)&0x00FF; drvcmd[3]=(pos>>16)&0x00FF; drvcmd[4]=(pos>>8)&0x00FF; drvcmd[5]=pos&0x00FF; flags_cmd_out=f_putcmd|f_ResponseStatus; } else if (famT_drive) { drvcmd[0]=CMDT_SEEK; if (f_blk_msf==1) pos=msf2blk(pos); drvcmd[2]=(pos>>24)&0x00FF; drvcmd[3]=(pos>>16)&0x00FF; drvcmd[4]=(pos>>8)&0x00FF; drvcmd[5]=pos&0x00FF; current_drive->n_bytes=1; } response_count=0; i=cmd_out(); return (i); } /*==========================================================================*/ static int cc_SpinUp(void) { int i; msg(DBG_SPI,"SpinUp.\n"); current_drive->in_SpinUp = 1; clr_cmdbuf(); if (fam0LV_drive) { drvcmd[0]=CMD0_SPINUP; if (fam0L_drive) flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta| f_ResponseStatus|f_obey_p_check|f_bit1; else flags_cmd_out=f_putcmd; } else if (fam1_drive) { drvcmd[0]=CMD1_SPINUP; flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; } else if (fam2_drive) { drvcmd[0]=CMD2_TRAY_CTL; drvcmd[4]=0x01; /* "spinup" */ flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; } else if (famT_drive) { drvcmd[0]=CMDT_TRAY_CTL; drvcmd[4]=0x03; /* "insert", it hopefully spins the drive up */ } response_count=0; i=cmd_out(); current_drive->in_SpinUp = 0; return (i); } /*==========================================================================*/ static int cc_SpinDown(void) { int i; if (fam0_drive) return (0); clr_cmdbuf(); response_count=0; if (fam1_drive) { drvcmd[0]=CMD1_SPINDOWN; flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; } else if (fam2_drive) { drvcmd[0]=CMD2_TRAY_CTL; drvcmd[4]=0x02; /* "eject" */ flags_cmd_out=f_putcmd|f_ResponseStatus; } else if (famL_drive) { drvcmd[0]=CMDL_SPINDOWN; drvcmd[1]=1; flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; } else if (famV_drive) { drvcmd[0]=CMDV_SPINDOWN; flags_cmd_out=f_putcmd; } else if (famT_drive) { drvcmd[0]=CMDT_TRAY_CTL; drvcmd[4]=0x02; /* "eject" */ } i=cmd_out(); return (i); } /*==========================================================================*/ static int cc_get_mode_T(void) { int i; clr_cmdbuf(); response_count=10; drvcmd[0]=CMDT_GETMODE; drvcmd[4]=response_count; i=cmd_out_T(); return (i); } /*==========================================================================*/ static int cc_set_mode_T(void) { int i; clr_cmdbuf(); response_count=1; drvcmd[0]=CMDT_SETMODE; drvcmd[1]=current_drive->speed_byte; drvcmd[2]=current_drive->frmsiz>>8; drvcmd[3]=current_drive->frmsiz&0x0FF; drvcmd[4]=current_drive->f_XA; /* 1: XA */ drvcmd[5]=current_drive->type_byte; /* 0, 1, 3 */ drvcmd[6]=current_drive->mode_xb_6; drvcmd[7]=current_drive->mode_yb_7|current_drive->volume_control; drvcmd[8]=current_drive->mode_xb_8; drvcmd[9]=current_drive->delay; i=cmd_out_T(); return (i); } /*==========================================================================*/ static int cc_prep_mode_T(void) { int i, j; i=cc_get_mode_T(); if (i<0) return (i); for (i=0;i<10;i++) sprintf(&msgbuf[i*3], " %02X", infobuf[i]); msgbuf[i*3]=0; msg(DBG_TEA,"CMDT_GETMODE:%s\n", msgbuf); current_drive->speed_byte=0x02; /* 0x02: auto quad, 0x82: quad, 0x81: double, 0x80: single */ current_drive->frmsiz=make16(infobuf[2],infobuf[3]); current_drive->f_XA=infobuf[4]; if (current_drive->f_XA==0) current_drive->type_byte=0; else current_drive->type_byte=1; current_drive->mode_xb_6=infobuf[6]; current_drive->mode_yb_7=1; current_drive->mode_xb_8=infobuf[8]; current_drive->delay=0; /* 0, 1, 2, 3 */ j=cc_set_mode_T(); i=cc_get_mode_T(); for (i=0;i<10;i++) sprintf(&msgbuf[i*3], " %02X", infobuf[i]); msgbuf[i*3]=0; msg(DBG_TEA,"CMDT_GETMODE:%s\n", msgbuf); return (j); } /*==========================================================================*/ static int cc_SetSpeed(u_char speed, u_char x1, u_char x2) { int i; if (fam0LV_drive) return (0); clr_cmdbuf(); response_count=0; if (fam1_drive) { drvcmd[0]=CMD1_SETMODE; drvcmd[1]=0x03; drvcmd[2]=speed; drvcmd[3]=x1; drvcmd[4]=x2; flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; } else if (fam2_drive) { drvcmd[0]=CMD2_SETSPEED; if (speed&speed_auto) { drvcmd[2]=0xFF; drvcmd[3]=0xFF; } else { drvcmd[2]=0; drvcmd[3]=150; } flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; } else if (famT_drive) { return (0); } i=cmd_out(); return (i); } /*==========================================================================*/ static int cc_SetVolume(void) { int i; u_char channel0,channel1,volume0,volume1; u_char control0,value0,control1,value1; current_drive->diskstate_flags &= ~volume_bit; clr_cmdbuf(); channel0=current_drive->vol_chan0; volume0=current_drive->vol_ctrl0; channel1=control1=current_drive->vol_chan1; volume1=value1=current_drive->vol_ctrl1; control0=value0=0; if (famV_drive) return (0); if (((current_drive->drv_options&audio_mono)!=0)&&(current_drive->drv_type>=drv_211)) { if ((volume0!=0)&&(volume1==0)) { volume1=volume0; channel1=channel0; } else if ((volume0==0)&&(volume1!=0)) { volume0=volume1; channel0=channel1; } } if (channel0>1) { channel0=0; volume0=0; } if (channel1>1) { channel1=1; volume1=0; } if (fam1_drive) { control0=channel0+1; control1=channel1+1; value0=(volume0>volume1)?volume0:volume1; value1=value0; if (volume0==0) control0=0; if (volume1==0) control1=0; drvcmd[0]=CMD1_SETMODE; drvcmd[1]=0x05; drvcmd[3]=control0; drvcmd[4]=value0; drvcmd[5]=control1; drvcmd[6]=value1; flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; } else if (fam2_drive) { control0=channel0+1; control1=channel1+1; value0=(volume0>volume1)?volume0:volume1; value1=value0; if (volume0==0) control0=0; if (volume1==0) control1=0; drvcmd[0]=CMD2_SETMODE; drvcmd[1]=0x0E; drvcmd[3]=control0; drvcmd[4]=value0; drvcmd[5]=control1; drvcmd[6]=value1; flags_cmd_out=f_putcmd|f_ResponseStatus; } else if (famL_drive) { if ((volume0==0)||(channel0!=0)) control0 |= 0x80; if ((volume1==0)||(channel1!=1)) control0 |= 0x40; if (volume0|volume1) value0=0x80; drvcmd[0]=CMDL_SETMODE; drvcmd[1]=0x03; drvcmd[4]=control0; drvcmd[5]=value0; flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; } else if (fam0_drive) /* different firmware levels */ { if (current_drive->drv_type>=drv_300) { control0=volume0&0xFC; value0=volume1&0xFC; if ((volume0!=0)&&(volume0<4)) control0 |= 0x04; if ((volume1!=0)&&(volume1<4)) value0 |= 0x04; if (channel0!=0) control0 |= 0x01; if (channel1==1) value0 |= 0x01; } else { value0=(volume0>volume1)?volume0:volume1; if (current_drive->drv_typedrv_typedrv_type>=drv_201) { if (volume0==0) control0 |= 0x80; if (volume1==0) control0 |= 0x40; } if (current_drive->drv_type>=drv_211) { if (channel0!=0) control0 |= 0x20; if (channel1!=1) control0 |= 0x10; } } drvcmd[0]=CMD0_SETMODE; drvcmd[1]=0x83; drvcmd[4]=control0; drvcmd[5]=value0; flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; } else if (famT_drive) { current_drive->volume_control=0; if (!volume0) current_drive->volume_control|=0x10; if (!volume1) current_drive->volume_control|=0x20; i=cc_prep_mode_T(); if (i<0) return (i); } if (!famT_drive) { response_count=0; i=cmd_out(); if (i<0) return (i); } current_drive->diskstate_flags |= volume_bit; return (0); } /*==========================================================================*/ static int GetStatus(void) { int i; if (famT_drive) return (0); flags_cmd_out=f_getsta|f_ResponseStatus|f_obey_p_check; response_count=0; cmd_type=0; i=cmd_out(); return (i); } /*==========================================================================*/ static int cc_DriveReset(void) { int i; msg(DBG_RES,"cc_DriveReset called.\n"); clr_cmdbuf(); response_count=0; if (fam0LV_drive) OUT(CDo_reset,0x00); else if (fam1_drive) { drvcmd[0]=CMD1_RESET; flags_cmd_out=f_putcmd; i=cmd_out(); } else if (fam2_drive) { drvcmd[0]=CMD2_RESET; flags_cmd_out=f_putcmd; i=cmd_out(); OUT(CDo_reset,0x00); } else if (famT_drive) { OUT(CDo_sel_i_d,0); OUT(CDo_enable,current_drive->drv_sel); OUT(CDo_command,CMDT_RESET); for (i=1;i<10;i++) OUT(CDo_command,0); } if (fam0LV_drive) sbp_sleep(5*HZ); /* wait 5 seconds */ else sbp_sleep(1*HZ); /* wait a second */ #if 1 if (famT_drive) { msg(DBG_TEA, "================CMDT_RESET given=================.\n"); sbp_sleep(3*HZ); } #endif /* 1 */ flush_status(); i=GetStatus(); if (i<0) return i; if (!famT_drive) if (current_drive->error_byte!=aud_12) return -501; return (0); } /*==========================================================================*/ static int SetSpeed(void) { int i, speed; if (!(current_drive->drv_options&(speed_auto|speed_300|speed_150))) return (0); speed=speed_auto; if (!(current_drive->drv_options&speed_auto)) { speed |= speed_300; if (!(current_drive->drv_options&speed_300)) speed=0; } i=cc_SetSpeed(speed,0,0); return (i); } static void switch_drive(struct sbpcd_drive *); static int sbpcd_select_speed(struct cdrom_device_info *cdi, int speed) { struct sbpcd_drive *p = cdi->handle; if (p != current_drive) switch_drive(p); return cc_SetSpeed(speed == 2 ? speed_300 : speed_150, 0, 0); } /*==========================================================================*/ static int DriveReset(void) { int i; i=cc_DriveReset(); if (i<0) return (-22); do { i=GetStatus(); if ((i<0)&&(i!=-ERR_DISKCHANGE)) { return (-2); /* from sta2err */ } if (!st_caddy_in) break; sbp_sleep(1); } while (!st_diskok); #if 000 current_drive->CD_changed=1; #endif if ((st_door_closed) && (st_caddy_in)) { i=DiskInfo(); if (i<0) return (-23); } return (0); } static int sbpcd_reset(struct cdrom_device_info *cdi) { struct sbpcd_drive *p = cdi->handle; if (p != curren