root/drivers/cdrom/aztcd.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. op_ok
  2. pa_ok
  3. sten_low
  4. dten_low
  5. statusAzt
  6. aztStatTimer
  7. aztcd_setup
  8. aztCloseDoor
  9. aztLockDoor
  10. aztUnlockDoor
  11. aztSendCmd
  12. sendAztCmd
  13. aztSeek
  14. aztSetDiskType
  15. check_aztcd_media_change
  16. aztStatus
  17. getAztStatus
  18. aztPlay
  19. azt_msf2hsg
  20. aztcd_ioctl
  21. azt_transfer
  22. do_aztcd_request
  23. azt_poll
  24. azt_invalidate_buffers
  25. aztcd_open
  26. aztcd_release
  27. aztcd_init
  28. azt_hsg2msf
  29. azt_bin2bcd
  30. azt_bcd2bin
  31. aztGetValue
  32. aztGetQChannelInfo
  33. aztUpdateToc
  34. aztGetDiskInfo
  35. aztGetMultiDiskInfo
  36. aztGetToc
  37. cleanup_module

   1 #define AZT_VERSION "1.80"
   2 /*      $Id: aztcd.c,v 1.80 1995/10/11 19:35:03 root Exp root $
   3         linux/drivers/block/aztcd.c - AztechCD268 CDROM driver
   4 
   5         Copyright (C) 1994,1995 Werner Zimmermann (zimmerma@rz.fht-esslingen.de)
   6 
   7         based on Mitsumi CDROM driver by  Martin Hariss and preworks by
   8         Eberhard Moenkeberg; contains contributions by Joe Nardone and Robby 
   9         Schirmer.
  10 
  11         This program is free software; you can redistribute it and/or modify
  12         it under the terms of the GNU General Public License as published by
  13         the Free Software Foundation; either version 2, or (at your option)
  14         any later version.
  15 
  16         This program is distributed in the hope that it will be useful,
  17         but WITHOUT ANY WARRANTY; without even the implied warranty of
  18         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19         GNU General Public License for more details.
  20 
  21         You should have received a copy of the GNU General Public License
  22         along with this program; if not, write to the Free Software
  23         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24 
  25         HISTORY
  26         V0.0    Adaption to Adaptec CD268-01A Version 1.3
  27                 Version is PRE_ALPHA, unresolved points:
  28                 1. I use busy wait instead of timer wait in STEN_LOW,DTEN_LOW
  29                    thus driver causes CPU overhead and is very slow 
  30                 2. could not find a way to stop the drive, when it is
  31                    in data read mode, therefore I had to set
  32                    msf.end.min/sec/frame to 0:0:1 (in azt_poll); so only one
  33                    frame can be read in sequence, this is also the reason for
  34                 3. getting 'timeout in state 4' messages, but nevertheless
  35                    it works
  36                 W.Zimmermann, Oct. 31, 1994
  37         V0.1    Version is ALPHA, problems #2 and #3 resolved.  
  38                 W.Zimmermann, Nov. 3, 1994
  39         V0.2    Modification to some comments, debugging aids for partial test
  40                 with Borland C under DOS eliminated. Timer interrupt wait 
  41                 STEN_LOW_WAIT additionally to busy wait for STEN_LOW implemented; 
  42                 use it only for the 'slow' commands (ACMD_GET_Q_CHANNEL, ACMD_
  43                 SEEK_TO_LEAD_IN), all other commands are so 'fast', that busy 
  44                 waiting seems better to me than interrupt rescheduling.
  45                 Besides that, when used in the wrong place, STEN_LOW_WAIT causes
  46                 kernel panic.
  47                 In function aztPlay command ACMD_PLAY_AUDIO added, should make
  48                 audio functions work. The Aztech drive needs different commands
  49                 to read data tracks and play audio tracks.
  50                 W.Zimmermann, Nov. 8, 1994
  51         V0.3    Recognition of missing drive during boot up improved (speeded up).
  52                 W.Zimmermann, Nov. 13, 1994
  53         V0.35   Rewrote the control mechanism in azt_poll (formerly mcd_poll) 
  54                 including removal of all 'goto' commands. :-); 
  55                 J. Nardone, Nov. 14, 1994
  56         V0.4    Renamed variables and constants to 'azt' instead of 'mcd'; had
  57                 to make some "compatibility" defines in azt.h; please note,
  58                 that the source file was renamed to azt.c, the include file to
  59                 azt.h                
  60                 Speeded up drive recognition during init (will be a little bit 
  61                 slower than before if no drive is installed!); suggested by
  62                 Robby Schirmer.
  63                 read_count declared volatile and set to AZT_BUF_SIZ to make
  64                 drive faster (now 300kB/sec, was 60kB/sec before, measured
  65                 by 'time dd if=/dev/cdrom of=/dev/null bs=2048 count=4096';
  66                 different AZT_BUF_SIZes were test, above 16 no further im-
  67                 provement seems to be possible; suggested by E.Moenkeberg.
  68                 W.Zimmermann, Nov. 18, 1994
  69         V0.42   Included getAztStatus command in GetQChannelInfo() to allow
  70                 reading Q-channel info on audio disks, if drive is stopped, 
  71                 and some other bug fixes in the audio stuff, suggested by 
  72                 Robby Schirmer.
  73                 Added more ioctls (reading data in mode 1 and mode 2).
  74                 Completely removed the old azt_poll() routine.
  75                 Detection of ORCHID CDS-3110 in aztcd_init implemented.
  76                 Additional debugging aids (see the readme file).
  77                 W.Zimmermann, Dec. 9, 1994  
  78         V0.50   Autodetection of drives implemented.
  79                 W.Zimmermann, Dec. 12, 1994
  80         V0.52   Prepared for including in the standard kernel, renamed most
  81                 variables to contain 'azt', included autoconf.h
  82                 W.Zimmermann, Dec. 16, 1994        
  83         V0.6    Version for being included in the standard Linux kernel.
  84                 Renamed source and header file to aztcd.c and aztcd.h
  85                 W.Zimmermann, Dec. 24, 1994
  86         V0.7    Changed VERIFY_READ to VERIFY_WRITE in aztcd_ioctl, case
  87                 CDROMREADMODE1 and CDROMREADMODE2; bug fix in the ioctl,
  88                 which causes kernel crashes when playing audio, changed 
  89                 include-files (config.h instead of autoconf.h, removed
  90                 delay.h)
  91                 W.Zimmermann, Jan. 8, 1995
  92         V0.72   Some more modifications for adaption to the standard kernel.
  93                 W.Zimmermann, Jan. 16, 1995
  94         V0.80   aztcd is now part of the standard kernel since version 1.1.83.
  95                 Modified the SET_TIMER and CLEAR_TIMER macros to comply with
  96                 the new timer scheme.
  97                 W.Zimmermann, Jan. 21, 1995
  98         V0.90   Included CDROMVOLCTRL, but with my Aztech drive I can only turn
  99                 the channels on and off. If it works better with your drive, 
 100                 please mail me. Also implemented ACMD_CLOSE for CDROMSTART.
 101                 W.Zimmermann, Jan. 24, 1995
 102         V1.00   Implemented close and lock tray commands. Patches supplied by
 103                 Frank Racis        
 104                 Added support for loadable MODULEs, so aztcd can now also be
 105                 loaded by insmod and removed by rmmod during run time
 106                 Werner Zimmermann, Mar. 24, 95
 107         V1.10   Implemented soundcard configuration for Orchid CDS-3110 drives
 108                 connected to Soundwave32 cards. Release for LST 2.1.
 109                 (still experimental)
 110                 Werner Zimmermann, May 8, 95
 111         V1.20   Implemented limited support for DOSEMU0.60's cdrom.c. Now it works, but
 112                 sometimes DOSEMU may hang for 30 seconds or so. A fully functional ver-
 113                 sion needs an update of Dosemu0.60's cdrom.c, which will come with the 
 114                 next revision of Dosemu.
 115                 Also Soundwave32 support now works.
 116                 Werner Zimmermann, May 22, 95
 117         V1.30   Auto-eject feature. Inspired by Franc Racis (racis@psu.edu)
 118                 Werner Zimmermann, July 4, 95
 119         V1.40   Started multisession support. Implementation copied from mcdx.c
 120                 by Heiko Schlittermann. Not tested yet.
 121                 Werner Zimmermann, July 15, 95
 122         V1.50   Implementation of ioctl CDROMRESET, continued multisession, began
 123                 XA, but still untested. Heavy modifications to drive status de-
 124                 tection.
 125                 Werner Zimmermann, July 25, 95
 126         V1.60   XA support now should work. Speeded up drive recognition in cases, 
 127                 where no drive is installed.
 128                 Werner Zimmermann, August 8, 1995
 129         V1.70   Multisession support now is completed, but there is still not 
 130                 enough testing done. If you can test it, please contact me. For
 131                 details please read README.aztcd.
 132                 Werner Zimmermann, August 19, 1995
 133         V1.80   Modification to suit the new kernel boot procedure introduced
 134                 with kernel 1.3.33. Will definitely not work with older kernels.
 135                 Programming done by Linus himself.
 136                 Werner Zimmermann, October 11, 1995
 137         NOTE: 
 138         Points marked with ??? are questionable !
 139 */
 140 #include <linux/major.h>
 141 #include <linux/config.h>
 142 
 143 #ifdef MODULE
 144 # include <linux/module.h>
 145 # include <linux/version.h>
 146 # ifndef CONFIG_MODVERSIONS
 147     char kernel_version[]= UTS_RELEASE;
 148 # endif
 149 #define aztcd_init init_module
 150 #endif
 151 
 152 #include <linux/errno.h>
 153 #include <linux/sched.h>
 154 #include <linux/mm.h>
 155 #include <linux/timer.h>
 156 #include <linux/fs.h>
 157 #include <linux/kernel.h>
 158 #include <linux/cdrom.h>
 159 #include <linux/ioport.h>
 160 #include <linux/string.h>
 161 
 162 #include <asm/system.h>
 163 #include <asm/io.h>
 164 #include <asm/segment.h>
 165 
 166 #define MAJOR_NR AZTECH_CDROM_MAJOR 
 167 #include <linux/blk.h>
 168 
 169 #ifdef MODULE
 170 #else
 171 # define MOD_INC_USE_COUNT
 172 # define MOD_DEC_USE_COUNT
 173 #endif
 174 
 175 #include <linux/aztcd.h>
 176 
 177 #define SET_TIMER(func, jifs)   delay_timer.expires = jiffies + (jifs); \
 178                                 delay_timer.function = (void *) (func); \
 179                                 add_timer(&delay_timer); 
 180 
 181 #define CLEAR_TIMER             del_timer(&delay_timer);
 182 
 183 #define RETURNM(message,value) {printk("aztcd: Warning: %s failed\n",message);\
 184                                 return value;}
 185 #define RETURN(message)        {printk("aztcd: Warning: %s failed\n",message);\
 186                                 return;}
 187 
 188 static int aztPresent = 0;
 189 
 190 #if 0
 191 #define AZT_TEST
 192 #define AZT_TEST1 /* <int-..> */
 193 #define AZT_TEST2 /* do_aztcd_request */
 194 #define AZT_TEST3 /* AZT_S_state */
 195 #define AZT_TEST4 /* QUICK_LOOP-counter */
 196 #define AZT_TEST5 /* port(1) state */
 197 #define AZT_DEBUG
 198 #define AZT_DEBUG_MULTISESSION
 199 #endif
 200 
 201 #define CURRENT_VALID \
 202   (CURRENT && MAJOR(CURRENT -> rq_dev) == MAJOR_NR && CURRENT -> cmd == READ \
 203    && CURRENT -> sector != -1)
 204 
 205 #define AFL_STATUSorDATA (AFL_STATUS | AFL_DATA)
 206 #define AZT_BUF_SIZ 16
 207 
 208 static volatile int azt_transfer_is_active=0;
 209 
 210 static char azt_buf[CD_FRAMESIZE_RAW*AZT_BUF_SIZ];/*buffer for block size conversion*/
 211 #if AZT_PRIVATE_IOCTLS
 212 static char buf[CD_FRAMESIZE_RAW];              /*separate buffer for the ioctls*/
 213 #endif
 214 
 215 static volatile int azt_buf_bn[AZT_BUF_SIZ], azt_next_bn;
 216 static volatile int azt_buf_in, azt_buf_out = -1;
 217 static volatile int azt_error=0;
 218 static int azt_open_count=0;
 219 enum azt_state_e 
 220 { AZT_S_IDLE,    /* 0 */
 221   AZT_S_START,   /* 1 */
 222   AZT_S_MODE,    /* 2 */
 223   AZT_S_READ,    /* 3 */
 224   AZT_S_DATA,    /* 4 */
 225   AZT_S_STOP,    /* 5 */
 226   AZT_S_STOPPING /* 6 */
 227 };
 228 static volatile enum azt_state_e azt_state = AZT_S_IDLE;
 229 #ifdef AZT_TEST3
 230 static volatile enum azt_state_e azt_state_old = AZT_S_STOP;  
 231 static volatile int azt_st_old = 0;
 232 #endif
 233 enum azt_read_modes 
 234 { AZT_MODE_0,     /*read mode for audio disks, not supported by Aztech firmware*/
 235   AZT_MODE_1,     /*read mode for normal CD-ROMs*/
 236   AZT_MODE_2      /*read mode for XA CD-ROMs*/
 237 };
 238 static volatile enum azt_read_modes azt_read_mode = AZT_MODE_1;
 239 
 240 static int azt_mode = -1;
 241 static volatile int azt_read_count = 1;
 242 
 243 #define READ_TIMEOUT 3000
 244 
 245 #define azt_port aztcd  /*needed for the modutils*/
 246 static short azt_port = AZT_BASE_ADDR;
 247 
 248 static char  azt_cont = 0;
 249 static char  azt_init_end = 0;
 250 static char  azt_auto_eject = AZT_AUTO_EJECT;
 251 
 252 static int AztTimeout, AztTries;
 253 static struct wait_queue *azt_waitq = NULL; 
 254 static struct timer_list delay_timer = { NULL, NULL, 0, 0, NULL };
 255 
 256 static struct azt_DiskInfo DiskInfo;
 257 static struct azt_Toc Toc[MAX_TRACKS];
 258 static struct azt_Play_msf azt_Play;
 259 
 260 static int  aztAudioStatus = CDROM_AUDIO_NO_STATUS;
 261 static char aztDiskChanged = 1;
 262 static char aztTocUpToDate = 0;
 263 
 264 static void azt_transfer(void);
 265 static void azt_poll(void);
 266 static void azt_invalidate_buffers(void);
 267 static void do_aztcd_request(void);
 268 static void azt_hsg2msf(long hsg, struct msf *msf);
 269 static void azt_bin2bcd(unsigned char *p);
 270 static int  azt_bcd2bin(unsigned char bcd);
 271 static int  aztStatus(void);
 272 static int  getAztStatus(void);
 273 static int  aztSendCmd(int cmd);
 274 static int  sendAztCmd(int cmd, struct azt_Play_msf *params);
 275 static int  aztGetQChannelInfo(struct azt_Toc *qp);
 276 static int  aztUpdateToc(void);
 277 static int  aztGetDiskInfo(void);
 278 #if AZT_MULTISESSION 
 279   static int  aztGetMultiDiskInfo(void);
 280 #endif
 281 static int  aztGetToc(int multi);
 282 static int  aztGetValue(unsigned char *result);
 283 static void aztStatTimer(void);
 284 static void aztCloseDoor(void);
 285 static void aztLockDoor(void);
 286 static void aztUnlockDoor(void);
 287 
 288 static unsigned char aztIndatum;
 289 static unsigned long aztTimeOutCount;
 290 static int aztCmd = 0;
 291 
 292 /* Macros for the drive hardware interface handshake, these macros use
 293    busy waiting */
 294 /* Wait for OP_OK = drive answers with AFL_OP_OK after receiving a command*/
 295 # define OP_OK op_ok()
 296 void op_ok(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 297 { aztTimeOutCount=0; 
 298   do { aztIndatum=inb(DATA_PORT);
 299        aztTimeOutCount++;
 300        if (aztTimeOutCount>=AZT_TIMEOUT)
 301         { printk("aztcd: Error Wait OP_OK\n");
 302           break;
 303         }
 304      } while (aztIndatum!=AFL_OP_OK);
 305 }
 306 
 307 /* Wait for PA_OK = drive answers with AFL_PA_OK after receiving parameters*/
 308 # define PA_OK pa_ok()
 309 void pa_ok(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 310 { aztTimeOutCount=0; 
 311   do { aztIndatum=inb(DATA_PORT);
 312        aztTimeOutCount++;
 313        if (aztTimeOutCount>=AZT_TIMEOUT)
 314         { printk("aztcd: Error Wait PA_OK\n");
 315           break;
 316         }
 317      } while (aztIndatum!=AFL_PA_OK);
 318 }
 319      
 320 /* Wait for STEN=Low = handshake signal 'AFL_.._OK available or command executed*/
 321 # define STEN_LOW  sten_low()
 322 void sten_low(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 323 { aztTimeOutCount=0; 
 324   do { aztIndatum=inb(STATUS_PORT);
 325        aztTimeOutCount++;
 326        if (aztTimeOutCount>=AZT_TIMEOUT)
 327         { if (azt_init_end) printk("aztcd: Error Wait STEN_LOW commands:%x\n",aztCmd);
 328           break;
 329         }
 330      } while (aztIndatum&AFL_STATUS);
 331 }
 332 
 333 /* Wait for DTEN=Low = handshake signal 'Data available'*/
 334 # define DTEN_LOW dten_low()
 335 void dten_low(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 336 { aztTimeOutCount=0; 
 337   do { aztIndatum=inb(STATUS_PORT);
 338        aztTimeOutCount++;
 339        if (aztTimeOutCount>=AZT_TIMEOUT)
 340         { printk("aztcd: Error Wait DTEN_OK\n");
 341           break;
 342         }
 343      } while (aztIndatum&AFL_DATA);
 344 }
 345 
 346 /* 
 347  * Macro for timer wait on STEN=Low, should only be used for 'slow' commands;
 348  * may cause kernel panic when used in the wrong place
 349 */
 350 #define STEN_LOW_WAIT   statusAzt()
 351 void statusAzt(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 352 { AztTimeout = AZT_STATUS_DELAY;
 353   SET_TIMER(aztStatTimer, HZ/100); 
 354   sleep_on(&azt_waitq);
 355   if (AztTimeout <= 0) printk("aztcd: Error Wait STEN_LOW_WAIT command:%x\n",aztCmd);
 356   return;
 357 }
 358 
 359 static void aztStatTimer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 360 { if (!(inb(STATUS_PORT) & AFL_STATUS))
 361      { wake_up(&azt_waitq);
 362        return;
 363      }
 364   AztTimeout--;
 365   if (AztTimeout <= 0)
 366      { wake_up(&azt_waitq);
 367        printk("aztcd: Error aztStatTimer: Timeout\n");
 368        return;
 369      }
 370   SET_TIMER(aztStatTimer, HZ/100);
 371 }
 372 
 373 void aztcd_setup(char *str, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
 374 {  if (ints[0] > 0)
 375       azt_port = ints[1];
 376    if (ints[0] > 1)
 377       azt_cont = ints[2];
 378 }
 379 
 380 /*
 381  * Subroutines to automatically close the door (tray) and 
 382  * lock it closed when the cd is mounted.  Leave the tray
 383  * locking as an option
 384  */
 385 static void aztCloseDoor(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 386 {
 387   aztSendCmd(ACMD_CLOSE);
 388   STEN_LOW;
 389   return;
 390 }
 391 
 392 static void aztLockDoor(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 393 {
 394 #if AZT_ALLOW_TRAY_LOCK
 395   aztSendCmd(ACMD_LOCK);
 396   STEN_LOW;
 397 #endif
 398   return;
 399 }
 400 
 401 static void aztUnlockDoor(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 402 {
 403 #if AZT_ALLOW_TRAY_LOCK
 404   aztSendCmd(ACMD_UNLOCK);
 405   STEN_LOW;
 406 #endif
 407   return;
 408 }
 409 
 410 /* 
 411  * Send a single command, return -1 on error, else 0
 412 */
 413 static int aztSendCmd(int cmd)
     /* [previous][next][first][last][top][bottom][index][help] */
 414 {  unsigned char data;
 415    int retry;
 416 
 417 #ifdef AZT_DEBUG
 418    printk("aztcd: Executing command %x\n",cmd);
 419 #endif
 420    aztCmd=cmd;
 421    outb(POLLED,MODE_PORT);
 422    do { if (inb(STATUS_PORT)&AFL_STATUS) break;
 423         inb(DATA_PORT);    /* if status left from last command, read and */
 424       } while (1);         /* discard it */
 425    do { if (inb(STATUS_PORT)&AFL_DATA) break;
 426         inb(DATA_PORT);    /* if data left from last command, read and */
 427       } while (1);         /* discard it */
 428    for (retry=0;retry<AZT_RETRY_ATTEMPTS;retry++)
 429      { outb((unsigned char) cmd,CMD_PORT);
 430        STEN_LOW;
 431        data=inb(DATA_PORT);
 432        if (data==AFL_OP_OK)
 433          { return 0;}           /*OP_OK?*/
 434        if (data==AFL_OP_ERR)
 435          { STEN_LOW;
 436            data=inb(DATA_PORT);
 437            printk("### Error 1 aztcd: aztSendCmd %x  Error Code %x\n",cmd,data);
 438          }
 439      }
 440    if (retry>=AZT_RETRY_ATTEMPTS)
 441      { printk("### Error 2 aztcd: aztSendCmd %x \n",cmd);
 442        azt_error=0xA5;
 443      }
 444    RETURNM("aztSendCmd",-1);
 445 }
 446 
 447 /*
 448  * Send a play or read command to the drive, return -1 on error, else 0
 449 */
 450 static int sendAztCmd(int cmd, struct azt_Play_msf *params)
     /* [previous][next][first][last][top][bottom][index][help] */
 451 {  unsigned char data;
 452    int retry;
 453 
 454 #ifdef AZT_DEBUG
 455    printk("aztcd: play start=%02x:%02x:%02x  end=%02x:%02x:%02x\n", \
 456            params->start.min, params->start.sec, params->start.frame, \
 457            params->end.min,   params->end.sec,   params->end.frame);
 458 #endif   
 459    for (retry=0;retry<AZT_RETRY_ATTEMPTS;retry++)
 460      { aztSendCmd(cmd);
 461        outb(params -> start.min,CMD_PORT);
 462        outb(params -> start.sec,CMD_PORT);
 463        outb(params -> start.frame,CMD_PORT);
 464        outb(params -> end.min,CMD_PORT);
 465        outb(params -> end.sec,CMD_PORT);
 466        outb(params -> end.frame,CMD_PORT);
 467        STEN_LOW;
 468        data=inb(DATA_PORT);
 469        if (data==AFL_PA_OK)
 470          { return 0;}           /*PA_OK ?*/
 471        if (data==AFL_PA_ERR)
 472          { STEN_LOW;
 473            data=inb(DATA_PORT);
 474            printk("### Error 1 aztcd: sendAztCmd %x  Error Code %x\n",cmd,data);
 475          }
 476      }
 477    if (retry>=AZT_RETRY_ATTEMPTS)
 478      { printk("### Error 2 aztcd: sendAztCmd %x\n ",cmd);
 479        azt_error=0xA5;
 480      }
 481    RETURNM("sendAztCmd",-1);
 482 }
 483 
 484 /*
 485  * Send a seek command to the drive, return -1 on error, else 0
 486 */
 487 static int aztSeek(struct azt_Play_msf *params)
     /* [previous][next][first][last][top][bottom][index][help] */
 488 {  unsigned char data;
 489    int retry;
 490 
 491 #ifdef AZT_DEBUG
 492    printk("aztcd: aztSeek %02x:%02x:%02x\n", \
 493            params->start.min, params->start.sec, params->start.frame);
 494 #endif   
 495    for (retry=0;retry<AZT_RETRY_ATTEMPTS;retry++)
 496      { aztSendCmd(ACMD_SEEK);
 497        outb(params -> start.min,CMD_PORT);
 498        outb(params -> start.sec,CMD_PORT);
 499        outb(params -> start.frame,CMD_PORT);
 500        STEN_LOW;
 501        data=inb(DATA_PORT);
 502        if (data==AFL_PA_OK)
 503          { return 0;}           /*PA_OK ?*/
 504        if (data==AFL_PA_ERR)
 505          { STEN_LOW;
 506            data=inb(DATA_PORT);
 507            printk("### Error 1 aztcd: aztSeek\n");
 508          }
 509      }
 510    if (retry>=AZT_RETRY_ATTEMPTS)
 511      { printk("### Error 2 aztcd: aztSeek\n ");
 512        azt_error=0xA5;
 513      }
 514    RETURNM("aztSeek",-1);
 515 }
 516 
 517 /* Send a Set Disk Type command
 518    does not seem to work with Aztech drives, behavior is completely indepen-
 519    dent on which mode is set ???
 520 */
 521 static int aztSetDiskType(int type)
     /* [previous][next][first][last][top][bottom][index][help] */
 522 {  unsigned char data;
 523    int retry;
 524 
 525 #ifdef AZT_DEBUG
 526    printk("aztcd: set disk type command: type= %i\n",type);
 527 #endif
 528    for (retry=0;retry<AZT_RETRY_ATTEMPTS;retry++)
 529      { aztSendCmd(ACMD_SET_DISK_TYPE);
 530        outb(type,CMD_PORT);
 531        STEN_LOW;
 532        data=inb(DATA_PORT);
 533        if (data==AFL_PA_OK)     /*PA_OK ?*/
 534          { azt_read_mode=type;
 535            return 0;            
 536          }  
 537        if (data==AFL_PA_ERR)
 538          { STEN_LOW;
 539            data=inb(DATA_PORT);
 540            printk("### Error 1 aztcd: aztSetDiskType %x Error Code %x\n",type,data);
 541          }
 542      }
 543    if (retry>=AZT_RETRY_ATTEMPTS)
 544      { printk("### Error 2 aztcd: aztSetDiskType %x\n ",type);
 545        azt_error=0xA5;
 546      }
 547    RETURNM("aztSetDiskType",-1);
 548 }
 549 
 550 
 551 /* 
 552  * Checking if the media has been changed not yet implemented
 553 */
 554 static int check_aztcd_media_change(kdev_t full_dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 555 { return 0;
 556 }
 557 
 558 
 559 /* used in azt_poll to poll the status, expects another program to issue a 
 560  * ACMD_GET_STATUS directly before 
 561  */
 562 static int aztStatus(void)  
     /* [previous][next][first][last][top][bottom][index][help] */
 563 {       int st;
 564 /*      int i;
 565 
 566         i = inb(STATUS_PORT) & AFL_STATUS;    is STEN=0?    ???
 567         if (!i)
 568 */      STEN_LOW;
 569         if (aztTimeOutCount<AZT_TIMEOUT)        
 570         {       st = inb(DATA_PORT) & 0xFF;
 571                 return st;
 572         }
 573         else
 574                 RETURNM("aztStatus",-1);
 575 }
 576 
 577 /*
 578  * Get the drive status
 579  */
 580 static int getAztStatus(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 581 {       int st;
 582 
 583         if (aztSendCmd(ACMD_GET_STATUS)) RETURNM("getAztStatus 1",-1);
 584         STEN_LOW;
 585         st = inb(DATA_PORT) & 0xFF;
 586 #ifdef AZT_DEBUG
 587         printk("aztcd: Status = %x\n",st);
 588 #endif
 589         if ((st == 0xFF)||(st&AST_CMD_CHECK))
 590          { printk("aztcd: AST_CMD_CHECK error or no status available\n");
 591            return -1;
 592          }
 593 
 594         if (((st&AST_MODE_BITS)!=AST_BUSY) && (aztAudioStatus == CDROM_AUDIO_PLAY))
 595            /* XXX might be an error? look at q-channel? */
 596            aztAudioStatus = CDROM_AUDIO_COMPLETED;
 597 
 598         if ((st & AST_DSK_CHG)||(st & AST_NOT_READY))
 599          { aztDiskChanged = 1;
 600            aztTocUpToDate = 0;
 601            aztAudioStatus = CDROM_AUDIO_NO_STATUS;
 602          }
 603         return st;
 604 }
 605 
 606 
 607 /*
 608  * Send a 'Play' command and get the status.  Use only from the top half.
 609  */
 610 static int aztPlay(struct azt_Play_msf *arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 611 {       if (sendAztCmd(ACMD_PLAY_AUDIO, arg) < 0) RETURNM("aztPlay",-1);
 612         return 0;
 613 }
 614 
 615 
 616 long azt_msf2hsg(struct msf *mp)
     /* [previous][next][first][last][top][bottom][index][help] */
 617 { return azt_bcd2bin(mp -> frame) + azt_bcd2bin(mp -> sec) * 75
 618                                   + azt_bcd2bin(mp -> min) * 4500 - CD_BLOCK_OFFSET;
 619 }
 620 
 621 static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, unsigned long arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 622 {       int i, st;
 623         struct azt_Toc qInfo;
 624         struct cdrom_ti ti;
 625         struct cdrom_tochdr tocHdr;
 626         struct cdrom_msf msf;
 627         struct cdrom_tocentry entry;
 628         struct azt_Toc *tocPtr;            
 629         struct cdrom_subchnl subchnl;
 630         struct cdrom_volctrl volctrl;
 631 
 632 #ifdef AZT_DEBUG
 633         printk("aztcd: starting aztcd_ioctl - Command:%x   Time: %li\n",cmd, jiffies);
 634         printk("aztcd Status %x\n", getAztStatus());
 635 #endif
 636         if (!ip) RETURNM("aztcd_ioctl 1",-EINVAL);
 637         if (getAztStatus()<0) RETURNM("aztcd_ioctl 2", -EIO);
 638         if ((!aztTocUpToDate)||(aztDiskChanged))
 639         { if ((i=aztUpdateToc())<0) RETURNM("aztcd_ioctl 3", i); /* error reading TOC */
 640         }
 641 
 642         switch (cmd)
 643         {
 644         case CDROMSTART:     /* Spin up the drive. Don't know, what to do,
 645                                 at least close the tray */
 646 #if AZT_PRIVATE_IOCTLS 
 647                 if (aztSendCmd(ACMD_CLOSE)) RETURNM("aztcd_ioctl 4",-1);
 648                 STEN_LOW_WAIT;
 649 #endif
 650                 break;
 651         case CDROMSTOP:      /* Spin down the drive */
 652                 if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 5",-1);
 653                 STEN_LOW_WAIT;
 654                 /* should we do anything if it fails? */
 655                 aztAudioStatus = CDROM_AUDIO_NO_STATUS;
 656                 break;
 657         case CDROMPAUSE:     /* Pause the drive */
 658                 if (aztAudioStatus != CDROM_AUDIO_PLAY) return -EINVAL; 
 659 
 660                 if (aztGetQChannelInfo(&qInfo) < 0)
 661                 { /* didn't get q channel info */
 662                   aztAudioStatus = CDROM_AUDIO_NO_STATUS;
 663                   RETURNM("aztcd_ioctl 7",0);
 664                 }
 665                 azt_Play.start = qInfo.diskTime;        /* remember restart point */
 666 
 667                 if (aztSendCmd(ACMD_PAUSE)) RETURNM("aztcd_ioctl 8",-1);
 668                 STEN_LOW_WAIT;
 669                 aztAudioStatus = CDROM_AUDIO_PAUSED;
 670                 break;
 671         case CDROMRESUME:    /* Play it again, Sam */
 672                 if (aztAudioStatus != CDROM_AUDIO_PAUSED) return -EINVAL;
 673                 /* restart the drive at the saved position. */
 674                 i = aztPlay(&azt_Play);
 675                 if (i < 0)
 676                 { aztAudioStatus = CDROM_AUDIO_ERROR;
 677                   return -EIO;
 678                 }
 679                 aztAudioStatus = CDROM_AUDIO_PLAY;
 680                 break;
 681         case CDROMMULTISESSION: /*multisession support -- experimental*/
 682                 { struct cdrom_multisession ms;
 683 #ifdef AZT_DEBUG
 684                   printk("aztcd ioctl MULTISESSION\n");
 685 #endif
 686                   st = verify_area(VERIFY_READ, (void*) arg, sizeof(struct cdrom_multisession));
 687                   if (st) return st;
 688                   memcpy_fromfs(&ms, (void*) arg, sizeof(struct cdrom_multisession));
 689                   if (ms.addr_format == CDROM_MSF) 
 690                      { ms.addr.msf.minute = azt_bcd2bin(DiskInfo.lastSession.min);
 691                        ms.addr.msf.second = azt_bcd2bin(DiskInfo.lastSession.sec);
 692                        ms.addr.msf.frame  = azt_bcd2bin(DiskInfo.lastSession.frame);
 693                      } 
 694                   else if (ms.addr_format == CDROM_LBA)
 695                        ms.addr.lba = azt_msf2hsg(&DiskInfo.lastSession);
 696                   else
 697                        return -EINVAL;
 698                   ms.xa_flag = DiskInfo.xa;
 699                   st = verify_area(VERIFY_WRITE, (void*) arg, sizeof(struct cdrom_multisession));
 700                   if (st) return st;
 701                   memcpy_tofs((void*) arg, &ms, sizeof(struct cdrom_multisession));
 702 #ifdef AZT_DEBUG 
 703                   if (ms.addr_format == CDROM_MSF) 
 704                       printk("aztcd multisession xa:%d, msf:%02x:%02x.%02x [%02x:%02x.%02x])\n",
 705                               ms.xa_flag, ms.addr.msf.minute, ms.addr.msf.second, 
 706                               ms.addr.msf.frame, DiskInfo.lastSession.min,
 707                               DiskInfo.lastSession.sec, DiskInfo.lastSession.frame);
 708                   else
 709                       printk("atzcd multisession %d, lba:0x%08x [%02x:%02x.%02x])\n",
 710                               ms.xa_flag, ms.addr.lba, DiskInfo.lastSession.min,
 711                               DiskInfo.lastSession.sec, DiskInfo.lastSession.frame);
 712 #endif
 713                   return 0;
 714                 }
 715         case CDROMPLAYTRKIND:     /* Play a track.  This currently ignores index. */
 716                 st = verify_area(VERIFY_READ, (void *) arg, sizeof ti);
 717                 if (st) return st;
 718                 memcpy_fromfs(&ti, (void *) arg, sizeof ti);
 719                 if (ti.cdti_trk0 < DiskInfo.first
 720                         || ti.cdti_trk0 > DiskInfo.last
 721                         || ti.cdti_trk1 < ti.cdti_trk0)
 722                 { return -EINVAL;
 723                 }
 724                 if (ti.cdti_trk1 > DiskInfo.last)
 725                     ti.cdti_trk1 = DiskInfo.last;
 726                 azt_Play.start = Toc[ti.cdti_trk0].diskTime;
 727                 azt_Play.end = Toc[ti.cdti_trk1 + 1].diskTime;
 728 #ifdef AZT_DEBUG
 729 printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n",
 730         azt_Play.start.min, azt_Play.start.sec, azt_Play.start.frame,
 731         azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame);
 732 #endif
 733                 i = aztPlay(&azt_Play);
 734                 if (i < 0)
 735                 { aztAudioStatus = CDROM_AUDIO_ERROR;
 736                   return -EIO;
 737                 }
 738                 aztAudioStatus = CDROM_AUDIO_PLAY;
 739                 break;
 740         case CDROMPLAYMSF:   /* Play starting at the given MSF address. */
 741 /*              if (aztAudioStatus == CDROM_AUDIO_PLAY) 
 742                 { if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 9",-1);
 743                   STEN_LOW;
 744                   aztAudioStatus = CDROM_AUDIO_NO_STATUS;
 745                 }
 746 */
 747                 st = verify_area(VERIFY_READ, (void *) arg, sizeof msf);
 748                 if (st) return st;
 749                 memcpy_fromfs(&msf, (void *) arg, sizeof msf);
 750                 /* convert to bcd */
 751                 azt_bin2bcd(&msf.cdmsf_min0);
 752                 azt_bin2bcd(&msf.cdmsf_sec0);
 753                 azt_bin2bcd(&msf.cdmsf_frame0);
 754                 azt_bin2bcd(&msf.cdmsf_min1);
 755                 azt_bin2bcd(&msf.cdmsf_sec1);
 756                 azt_bin2bcd(&msf.cdmsf_frame1);
 757                 azt_Play.start.min = msf.cdmsf_min0;
 758                 azt_Play.start.sec = msf.cdmsf_sec0;
 759                 azt_Play.start.frame = msf.cdmsf_frame0;
 760                 azt_Play.end.min = msf.cdmsf_min1;
 761                 azt_Play.end.sec = msf.cdmsf_sec1;
 762                 azt_Play.end.frame = msf.cdmsf_frame1;
 763 #ifdef AZT_DEBUG
 764 printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n",
 765 azt_Play.start.min, azt_Play.start.sec, azt_Play.start.frame,
 766 azt_Play.end.min, azt_Play.end.sec, azt_Play.end.frame);
 767 #endif
 768                 i = aztPlay(&azt_Play);
 769                 if (i < 0)
 770                 { aztAudioStatus = CDROM_AUDIO_ERROR;
 771                   return -EIO;
 772                 }
 773                 aztAudioStatus = CDROM_AUDIO_PLAY;
 774                 break;
 775 
 776         case CDROMREADTOCHDR:        /* Read the table of contents header */
 777                 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof tocHdr);
 778                 if (st) return st;
 779                 tocHdr.cdth_trk0 = DiskInfo.first;
 780                 tocHdr.cdth_trk1 = DiskInfo.last;
 781                 memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr);
 782                 break;
 783         case CDROMREADTOCENTRY:      /* Read an entry in the table of contents */
 784                 st = verify_area(VERIFY_READ, (void *) arg, sizeof entry);
 785                 if (st) return st;
 786                 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry);
 787                 if (st) return st;
 788                 memcpy_fromfs(&entry, (void *) arg, sizeof entry);
 789                 if ((!aztTocUpToDate)||aztDiskChanged) aztUpdateToc();
 790                 if (entry.cdte_track == CDROM_LEADOUT)
 791                   tocPtr = &Toc[DiskInfo.last + 1];   /* ??? */
 792                 else if (entry.cdte_track > DiskInfo.last
 793                                 || entry.cdte_track < DiskInfo.first)
 794                 { return -EINVAL;
 795                 }
 796                 else 
 797                   tocPtr = &Toc[entry.cdte_track];
 798                 entry.cdte_adr = tocPtr -> ctrl_addr;
 799                 entry.cdte_ctrl = tocPtr -> ctrl_addr >> 4;
 800                 if (entry.cdte_format == CDROM_LBA)
 801                   entry.cdte_addr.lba = azt_msf2hsg(&tocPtr -> diskTime);
 802                 else if (entry.cdte_format == CDROM_MSF)
 803                 { entry.cdte_addr.msf.minute = azt_bcd2bin(tocPtr -> diskTime.min);
 804                   entry.cdte_addr.msf.second = azt_bcd2bin(tocPtr -> diskTime.sec);
 805                   entry.cdte_addr.msf.frame  = azt_bcd2bin(tocPtr -> diskTime.frame);
 806                 }
 807                 else
 808                 { return -EINVAL;
 809                 }
 810                 memcpy_tofs((void *) arg, &entry, sizeof entry);
 811                 break;
 812         case CDROMSUBCHNL:   /* Get subchannel info */
 813                 st = verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_subchnl));
 814                 if (st) { 
 815 #ifdef AZT_DEBUG
 816                           printk("aztcd: exiting aztcd_ioctl - Error 1 - Command:%x\n",cmd);
 817 #endif
 818                           return st;
 819                         }  
 820                 st = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl));
 821                 if (st) { 
 822 #ifdef AZT_DEBUG
 823                           printk("aztcd: exiting aztcd_ioctl - Error 2 - Command:%x\n",cmd);
 824 #endif
 825                           return st;
 826                         }  
 827                 memcpy_fromfs(&subchnl, (void *) arg, sizeof (struct cdrom_subchnl));
 828                 if (aztGetQChannelInfo(&qInfo) < 0)
 829                 if (st) { 
 830 #ifdef AZT_DEBUG
 831                           printk("aztcd: exiting aztcd_ioctl - Error 3 - Command:%x\n",cmd);
 832 #endif
 833                           return -EIO;
 834                         }  
 835                 subchnl.cdsc_audiostatus = aztAudioStatus;
 836                 subchnl.cdsc_adr = qInfo.ctrl_addr;
 837                 subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4;
 838                 subchnl.cdsc_trk = azt_bcd2bin(qInfo.track);
 839                 subchnl.cdsc_ind = azt_bcd2bin(qInfo.pointIndex);
 840                 if (subchnl.cdsc_format == CDROM_LBA)
 841                 { subchnl.cdsc_absaddr.lba = azt_msf2hsg(&qInfo.diskTime);
 842                   subchnl.cdsc_reladdr.lba = azt_msf2hsg(&qInfo.trackTime);
 843                 }
 844                 else  /*default*/
 845                 { subchnl.cdsc_format = CDROM_MSF;
 846                   subchnl.cdsc_absaddr.msf.minute = azt_bcd2bin(qInfo.diskTime.min);
 847                   subchnl.cdsc_absaddr.msf.second = azt_bcd2bin(qInfo.diskTime.sec);
 848                   subchnl.cdsc_absaddr.msf.frame  = azt_bcd2bin(qInfo.diskTime.frame);
 849                   subchnl.cdsc_reladdr.msf.minute = azt_bcd2bin(qInfo.trackTime.min);
 850                   subchnl.cdsc_reladdr.msf.second = azt_bcd2bin(qInfo.trackTime.sec);
 851                   subchnl.cdsc_reladdr.msf.frame  = azt_bcd2bin(qInfo.trackTime.frame);
 852                 }
 853                 memcpy_tofs((void *) arg, &subchnl, sizeof (struct cdrom_subchnl));
 854                 break;
 855         case CDROMVOLCTRL:   /* Volume control 
 856          * With my Aztech CD268-01A volume control does not work, I can only
 857            turn the channels on (any value !=0) or off (value==0). Maybe it
 858            works better with your drive */
 859                 st=verify_area(VERIFY_READ,(void *) arg, sizeof(volctrl));
 860                 if (st) return (st);
 861                 memcpy_fromfs(&volctrl,(char *) arg,sizeof(volctrl));
 862                 azt_Play.start.min = 0x21;
 863                 azt_Play.start.sec = 0x84;
 864                 azt_Play.start.frame = volctrl.channel0;
 865                 azt_Play.end.min =     volctrl.channel1;
 866                 azt_Play.end.sec =     volctrl.channel2;
 867                 azt_Play.end.frame =   volctrl.channel3;
 868                 sendAztCmd(ACMD_SET_VOLUME, &azt_Play);
 869                 STEN_LOW_WAIT;
 870                 break;
 871         case CDROMEJECT:
 872                 aztUnlockDoor(); /* Assume user knows what they're doing */
 873                /* all drives can at least stop! */
 874                 if (aztAudioStatus == CDROM_AUDIO_PLAY) 
 875                 { if (aztSendCmd(ACMD_STOP)) RETURNM("azt_ioctl 10",-1);
 876                   STEN_LOW_WAIT;
 877                 }
 878                 if (aztSendCmd(ACMD_EJECT)) RETURNM("azt_ioctl 11",-1);
 879                 STEN_LOW_WAIT; /*???*/
 880                 aztAudioStatus = CDROM_AUDIO_NO_STATUS;
 881                 break;
 882         case CDROMEJECT_SW:
 883                 azt_auto_eject = (char) arg;
 884                 break;  
 885         case CDROMRESET:
 886                 outb(ACMD_SOFT_RESET,CMD_PORT);   /*send reset*/
 887                 STEN_LOW;
 888                 if (inb(DATA_PORT)!=AFL_OP_OK)    /*OP_OK?*/
 889                   { printk("aztcd: AZTECH CD-ROM drive does not respond\n");
 890                   }
 891                 break;
 892 /*Take care, the following code is not compatible with other CD-ROM drivers,
 893   use it at your own risk with cdplay.c. Set AZT_PRIVATE_IOCTLS to 0 in aztcd.h,
 894   if you do not want to use it!
 895 */                  
 896 #if AZT_PRIVATE_IOCTLS 
 897         case CDROMREADCOOKED: /*read data in mode 1 (2048 Bytes)*/
 898         case CDROMREADRAW:    /*read data in mode 2 (2336 Bytes)*/
 899                 { st = verify_area(VERIFY_READ,  (void *) arg, sizeof msf);
 900                   if (st) return st;
 901                   st = verify_area(VERIFY_WRITE, (void *) arg, sizeof buf);
 902                   if (st) return st;
 903                   memcpy_fromfs(&msf, (void *) arg, sizeof msf);
 904                   /* convert to bcd */
 905                   azt_bin2bcd(&msf.cdmsf_min0);
 906                   azt_bin2bcd(&msf.cdmsf_sec0);
 907                   azt_bin2bcd(&msf.cdmsf_frame0);
 908                   msf.cdmsf_min1=0;
 909                   msf.cdmsf_sec1=0;
 910                   msf.cdmsf_frame1=1; /*read only one frame*/
 911                   azt_Play.start.min = msf.cdmsf_min0;
 912                   azt_Play.start.sec = msf.cdmsf_sec0;
 913                   azt_Play.start.frame = msf.cdmsf_frame0;
 914                   azt_Play.end.min = msf.cdmsf_min1;
 915                   azt_Play.end.sec = msf.cdmsf_sec1;
 916                   azt_Play.end.frame = msf.cdmsf_frame1;
 917                   if (cmd==CDROMREADRAW)
 918                   { if (DiskInfo.xa)
 919                        { return -1;         /*XA Disks can't be read raw*/
 920                        }
 921                     else   
 922                        { if (sendAztCmd(ACMD_PLAY_READ_RAW, &azt_Play)) return -1;
 923                          DTEN_LOW;
 924                          insb(DATA_PORT,buf,CD_FRAMESIZE_RAW);
 925                          memcpy_tofs((void *) arg, &buf, CD_FRAMESIZE_RAW);
 926                        }  
 927                   }
 928                   else /*CDROMREADCOOKED*/
 929                   { if (sendAztCmd(ACMD_PLAY_READ, &azt_Play)) return -1;
 930                     DTEN_LOW;
 931                     insb(DATA_PORT,buf,CD_FRAMESIZE);
 932                     memcpy_tofs((void *) arg, &buf, CD_FRAMESIZE);
 933                   }
 934                  } 
 935                 break;
 936         case CDROMSEEK:    /*seek msf address*/
 937                 st = verify_area(VERIFY_READ,  (void *) arg, sizeof msf);
 938                 if (st) return st;
 939                 memcpy_fromfs(&msf, (void *) arg, sizeof msf);
 940                 /* convert to bcd */
 941                 azt_bin2bcd(&msf.cdmsf_min0);
 942                 azt_bin2bcd(&msf.cdmsf_sec0);
 943                 azt_bin2bcd(&msf.cdmsf_frame0);
 944                 azt_Play.start.min = msf.cdmsf_min0;
 945                 azt_Play.start.sec = msf.cdmsf_sec0;
 946                 azt_Play.start.frame = msf.cdmsf_frame0;
 947                 if (aztSeek(&azt_Play)) return -1;
 948                 break;
 949 #endif /*end of incompatible code*/       
 950         case CDROMREADMODE1: /*set read data in mode 1*/
 951                 return aztSetDiskType(AZT_MODE_1);
 952         case CDROMREADMODE2: /*set read data in mode 2*/
 953                 return aztSetDiskType(AZT_MODE_2);          
 954         default:
 955                 return -EINVAL;
 956         }
 957 #ifdef AZT_DEBUG
 958         printk("aztcd: exiting aztcd_ioctl Command:%x  Time:%li\n",cmd,jiffies);
 959 #endif
 960         return 0;
 961 }
 962 
 963 
 964 /*
 965  * Take care of the different block sizes between cdrom and Linux.
 966  * When Linux gets variable block sizes this will probably go away.
 967  */
 968 static void azt_transfer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 969 { 
 970 #ifdef AZT_TEST
 971   printk("aztcd: executing azt_transfer Time:%li\n",jiffies);
 972 #endif
 973   if (CURRENT_VALID) {
 974     while (CURRENT -> nr_sectors) {
 975       int bn = CURRENT -> sector / 4;
 976       int i;
 977       for (i = 0; i < AZT_BUF_SIZ && azt_buf_bn[i] != bn; ++i)
 978         ;
 979       if (i < AZT_BUF_SIZ) {
 980         int offs = (i * 4 + (CURRENT -> sector & 3)) * 512;
 981         int nr_sectors = 4 - (CURRENT -> sector & 3);
 982         if (azt_buf_out != i) {
 983           azt_buf_out = i;
 984           if (azt_buf_bn[i] != bn) {
 985             azt_buf_out = -1;
 986             continue;
 987           }
 988         }
 989         if (nr_sectors > CURRENT -> nr_sectors)
 990           nr_sectors = CURRENT -> nr_sectors;
 991         memcpy(CURRENT -> buffer, azt_buf + offs, nr_sectors * 512);
 992         CURRENT -> nr_sectors -= nr_sectors;
 993         CURRENT -> sector += nr_sectors;
 994         CURRENT -> buffer += nr_sectors * 512;
 995       } else {
 996         azt_buf_out = -1;
 997         break;
 998       }
 999     }
1000   }
1001 }
1002 
1003 
1004 static void do_aztcd_request(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1005 {
1006 #ifdef AZT_TEST
1007   printk(" do_aztcd_request(%ld+%ld) Time:%li\n", CURRENT -> sector, CURRENT -> nr_sectors,jiffies);
1008 #endif
1009   if (DiskInfo.audio) 
1010     { printk("aztcd: Error, tried to mount an Audio CD\n");
1011       end_request(0);
1012       return;
1013     }
1014   azt_transfer_is_active = 1;
1015   while (CURRENT_VALID) {
1016     if (CURRENT->bh) {
1017       if (!CURRENT->bh->b_lock)
1018         panic(DEVICE_NAME ": block not locked");
1019     }
1020     azt_transfer();
1021     if (CURRENT -> nr_sectors == 0) {
1022       end_request(1);
1023     } else {
1024       azt_buf_out = -1;         /* Want to read a block not in buffer */
1025       if (azt_state == AZT_S_IDLE) {
1026         if ((!aztTocUpToDate)||aztDiskChanged) {
1027           if (aztUpdateToc() < 0) {
1028             while (CURRENT_VALID)
1029               end_request(0);
1030             break;
1031           }
1032         }
1033         azt_state = AZT_S_START;
1034         AztTries = 5;
1035         SET_TIMER(azt_poll, HZ/100);
1036       }
1037       break;
1038     }
1039   }
1040   azt_transfer_is_active = 0;
1041 #ifdef AZT_TEST2
1042   printk("azt_next_bn:%x  azt_buf_in:%x azt_buf_out:%x  azt_buf_bn:%x\n", \
1043           azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
1044   printk(" do_aztcd_request ends  Time:%li\n",jiffies);
1045 #endif
1046 }
1047 
1048 static void azt_poll(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1049 {
1050     int st = 0;
1051     int loop_ctl = 1;
1052     int skip = 0;
1053 
1054     if (azt_error) {                             /* ???*/
1055         if (aztSendCmd(ACMD_GET_ERROR)) RETURN("azt_poll 1");
1056         STEN_LOW;
1057         azt_error=inb(DATA_PORT)&0xFF;
1058         printk("aztcd: I/O error 0x%02x\n", azt_error);
1059         azt_invalidate_buffers();
1060 #ifdef WARN_IF_READ_FAILURE
1061         if (AztTries == 5)
1062           printk("aztcd: Read of Block %d Failed - Maybe Audio Disk?\n", azt_next_bn);
1063 #endif
1064         if (!AztTries--) {
1065           printk("aztcd: Read of Block %d Failed, Maybe Audio Disk? Giving up\n", azt_next_bn);
1066           if (azt_transfer_is_active) {
1067             AztTries = 0;
1068             loop_ctl = 0;
1069           }
1070           if (CURRENT_VALID)
1071             end_request(0);
1072           AztTries = 5;
1073         }
1074     azt_error = 0;
1075     azt_state = AZT_S_STOP;
1076     }
1077 
1078     while (loop_ctl)
1079     {
1080       loop_ctl = 0;   /* each case must flip this back to 1 if we want
1081                          to come back up here */
1082       switch (azt_state) {
1083 
1084         case AZT_S_IDLE:
1085 #ifdef AZT_TEST3
1086           if (azt_state!=azt_state_old) {
1087             azt_state_old=azt_state;
1088             printk("AZT_S_IDLE\n");
1089             }
1090 #endif
1091           return;
1092 
1093         case AZT_S_START:
1094 #ifdef AZT_TEST3
1095           if (azt_state!=azt_state_old) {
1096             azt_state_old=azt_state;
1097             printk("AZT_S_START\n");
1098           }
1099 #endif
1100           if(aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 2");  /*result will be checked by aztStatus() */
1101           azt_state = azt_mode == 1 ? AZT_S_READ : AZT_S_MODE;
1102           AztTimeout = 3000;
1103           break;
1104 
1105         case AZT_S_MODE:
1106 #ifdef AZT_TEST3
1107           if (azt_state!=azt_state_old) {
1108             azt_state_old=azt_state;
1109             printk("AZT_S_MODE\n");
1110           }
1111 #endif
1112           if (!skip) {
1113             if ((st = aztStatus()) != -1) {
1114               if ((st & AST_DSK_CHG)||(st & AST_NOT_READY)) {
1115                 aztDiskChanged = 1;
1116                 aztTocUpToDate = 0;
1117                 azt_invalidate_buffers();
1118                 end_request(0);
1119                 printk("aztcd: Disk Changed or Not Ready 1 - Unmount Disk!\n");
1120               }
1121             } else break;
1122           }
1123           skip = 0;
1124 
1125           if ((st & AST_DOOR_OPEN)||(st & AST_NOT_READY)) {
1126             aztDiskChanged = 1;
1127             aztTocUpToDate = 0;
1128             printk("aztcd: Disk Changed or Not Ready 2 - Unmount Disk!\n");
1129             end_request(0);
1130             printk((st & AST_DOOR_OPEN) ? "aztcd: door open\n" : "aztcd: disk removed\n");
1131             if (azt_transfer_is_active) {
1132               azt_state = AZT_S_START;
1133               loop_ctl = 1;   /* goto immediately */
1134               break;
1135             }
1136             azt_state = AZT_S_IDLE;
1137             while (CURRENT_VALID)
1138               end_request(0);
1139             return;
1140           }
1141                                         /*???*/
1142 /*        if (aztSendCmd(ACMD_SET_MODE)) RETURN("azt_poll 3");
1143           outb(0x01, DATA_PORT);          
1144           PA_OK;
1145           STEN_LOW;
1146 */        if (aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 4");
1147           STEN_LOW; /*???*/
1148           azt_mode = 1;
1149           azt_state = AZT_S_READ;
1150           AztTimeout = 3000;
1151 
1152           break;
1153 
1154 
1155         case AZT_S_READ:
1156 #ifdef AZT_TEST3
1157           if (azt_state!=azt_state_old)  {
1158             azt_state_old=azt_state;
1159             printk("AZT_S_READ\n");
1160           }
1161 #endif
1162           if (!skip) {
1163               if ((st = aztStatus()) != -1) {
1164                 if ((st & AST_DSK_CHG)||(st & AST_NOT_READY)) {
1165                 aztDiskChanged = 1;
1166                 aztTocUpToDate = 0;
1167                 azt_invalidate_buffers();
1168                 printk("aztcd: Disk Changed or Not Ready 3 - Unmount Disk!\n");
1169                 end_request(0);               
1170                 }
1171               } else break;
1172           } 
1173             
1174           skip = 0;
1175           if ((st & AST_DOOR_OPEN)||(st & AST_NOT_READY)) {
1176             aztDiskChanged = 1;
1177             aztTocUpToDate = 0;
1178             printk((st & AST_DOOR_OPEN) ? "aztcd: door open\n" : "aztcd: disk removed\n");
1179             if (azt_transfer_is_active) {
1180               azt_state = AZT_S_START;
1181               loop_ctl = 1;
1182               break;
1183             }
1184             azt_state = AZT_S_IDLE;
1185             while (CURRENT_VALID)
1186             end_request(0);
1187             return;
1188           }
1189 
1190           if (CURRENT_VALID) {
1191             struct azt_Play_msf msf;
1192             azt_next_bn = CURRENT -> sector / 4;
1193             azt_hsg2msf(azt_next_bn, &msf.start);
1194             azt_read_count=AZT_BUF_SIZ;    /*??? fast, because we read ahead*/
1195 /*          azt_read_count= CURRENT->nr_sectors;      slow
1196 */
1197             msf.end.min = 0;
1198             msf.end.sec = 0;            
1199             msf.end.frame = azt_read_count ;/*Mitsumi here reads 0xffffff sectors*/
1200 #ifdef AZT_TEST3
1201             printk("---reading msf-address %x:%x:%x  %x:%x:%x\n",msf.start.min,msf.start.sec,msf.start.frame,msf.end.min,msf.end.sec,msf.end.frame);
1202             printk("azt_next_bn:%x  azt_buf_in:%x azt_buf_out:%x  azt_buf_bn:%x\n", \
1203                     azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
1204 #endif 
1205             if (azt_read_mode==AZT_MODE_2)
1206                { sendAztCmd(ACMD_PLAY_READ_RAW, &msf); /*XA disks in raw mode*/
1207                }
1208             else
1209                { sendAztCmd(ACMD_PLAY_READ, &msf);     /*others in cooked mode*/
1210                }
1211             azt_state = AZT_S_DATA;
1212             AztTimeout = READ_TIMEOUT;
1213           } else {
1214             azt_state = AZT_S_STOP;
1215             loop_ctl = 1;
1216             break;
1217           }
1218 
1219           break;
1220 
1221 
1222         case AZT_S_DATA:
1223 #ifdef AZT_TEST3
1224           if (azt_state!=azt_state_old)  {
1225             azt_state_old=azt_state;
1226             printk("AZT_S_DATA\n");
1227           }
1228 #endif
1229 
1230           st = inb(STATUS_PORT) & AFL_STATUSorDATA;   /*???*/
1231 
1232           switch (st) {
1233 
1234             case AFL_DATA:
1235 #ifdef AZT_TEST3
1236               if (st!=azt_st_old)  {
1237                 azt_st_old=st; 
1238                 printk("---AFL_DATA st:%x\n",st);
1239               }
1240 #endif
1241               if (!AztTries--) {
1242                 printk("aztcd: Read of Block %d Failed, Maybe Audio Disk ? Giving up\n", azt_next_bn);
1243                 if (azt_transfer_is_active) {
1244                   AztTries = 0;
1245                   break;
1246                 }
1247                 if (CURRENT_VALID)
1248                   end_request(0);
1249                 AztTries = 5;
1250               }
1251               azt_state = AZT_S_START;
1252               AztTimeout = READ_TIMEOUT;
1253               loop_ctl = 1;
1254               break;
1255 
1256             case AFL_STATUSorDATA:
1257 #ifdef AZT_TEST3
1258               if (st!=azt_st_old)  {
1259                 azt_st_old=st;
1260                 printk("---AFL_STATUSorDATA st:%x\n",st);
1261               }
1262 #endif
1263               break;
1264 
1265             default:
1266 #ifdef AZT_TEST3
1267               if (st!=azt_st_old)  {
1268                 azt_st_old=st;
1269                 printk("---default: st:%x\n",st);
1270               }
1271 #endif
1272               AztTries = 5;
1273               if (!CURRENT_VALID && azt_buf_in == azt_buf_out) {
1274                 azt_state = AZT_S_STOP;
1275                 loop_ctl = 1;
1276                 break;
1277               }
1278               if (azt_read_count<=0)
1279                 printk("aztcd: warning - try to read 0 frames\n");
1280               while (azt_read_count)      /*??? fast read ahead loop*/
1281                { azt_buf_bn[azt_buf_in] = -1;
1282                  DTEN_LOW;                      /*??? unsolved problem, very
1283                                                       seldom we get timeouts
1284                                                       here, don't now the real
1285                                                       reason. With my drive this
1286                                                       sometimes also happens with
1287                                                       Aztech's original driver under
1288                                                       DOS. Is it a hardware bug? 
1289                                                       I tried to recover from such
1290                                                       situations here. Zimmermann*/
1291                  if (aztTimeOutCount>=AZT_TIMEOUT) 
1292                   { printk("read_count:%d CURRENT->nr_sectors:%ld azt_buf_in:%d\n", azt_read_count,CURRENT->nr_sectors,azt_buf_in);
1293                     printk("azt_transfer_is_active:%x\n",azt_transfer_is_active);
1294                     azt_read_count=0;
1295                     azt_state = AZT_S_STOP;
1296                     loop_ctl = 1;
1297                     end_request(1);  /*should we have here (1) or (0)? */
1298                   }
1299                  else
1300                   { if (azt_read_mode==AZT_MODE_2)
1301                        { insb(DATA_PORT, azt_buf + CD_FRAMESIZE_RAW * azt_buf_in, CD_FRAMESIZE_RAW);
1302                        }
1303                     else
1304                        { insb(DATA_PORT, azt_buf + CD_FRAMESIZE * azt_buf_in, CD_FRAMESIZE);
1305                        }
1306                     azt_read_count--;
1307 #ifdef AZT_TEST3
1308                     printk("AZT_S_DATA; ---I've read data- read_count: %d\n",azt_read_count);
1309                     printk("azt_next_bn:%d  azt_buf_in:%d azt_buf_out:%d  azt_buf_bn:%d\n", \
1310                          azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]);
1311 #endif
1312                     azt_buf_bn[azt_buf_in] = azt_next_bn++;
1313                     if (azt_buf_out == -1)
1314                       azt_buf_out = azt_buf_in;
1315                     azt_buf_in = azt_buf_in + 1 == AZT_BUF_SIZ ? 0 : azt_buf_in + 1;
1316                   }
1317                }
1318               if (!azt_transfer_is_active) {
1319                 while (CURRENT_VALID) {
1320                   azt_transfer();
1321                   if (CURRENT -> nr_sectors == 0)
1322                     end_request(1);
1323                   else
1324                     break;
1325                 }
1326               }
1327 
1328               if (CURRENT_VALID
1329                 && (CURRENT -> sector / 4 < azt_next_bn ||
1330                 CURRENT -> sector / 4 > azt_next_bn + AZT_BUF_SIZ)) {
1331                 azt_state = AZT_S_STOP;
1332                 loop_ctl = 1;
1333                 break;
1334               }
1335               AztTimeout = READ_TIMEOUT;   
1336               if (azt_read_count==0) {
1337                 azt_state = AZT_S_STOP;   /*???*/
1338                 loop_ctl = 1;
1339                 break;           
1340               } 
1341               break;
1342             }
1343     break;
1344 
1345 
1346         case AZT_S_STOP:
1347 #ifdef AZT_TEST3
1348           if (azt_state!=azt_state_old) {
1349             azt_state_old=azt_state;
1350             printk("AZT_S_STOP\n");
1351           }
1352 #endif
1353           if (azt_read_count!=0) printk("aztcd: discard data=%x frames\n",azt_read_count);  /*???*/
1354           while (azt_read_count!=0) {
1355             int i;
1356             if ( !(inb(STATUS_PORT) & AFL_DATA) ) {
1357               if (azt_read_mode==AZT_MODE_2)
1358                  for (i=0; i<CD_FRAMESIZE_RAW; i++) inb(DATA_PORT);
1359               else   
1360                  for (i=0; i<CD_FRAMESIZE; i++) inb(DATA_PORT);
1361             }
1362             azt_read_count--;
1363           }  
1364           if (aztSendCmd(ACMD_GET_STATUS)) RETURN("azt_poll 5");
1365           azt_state = AZT_S_STOPPING;
1366           AztTimeout = 1000;
1367           break;
1368 
1369         case AZT_S_STOPPING:
1370 #ifdef AZT_TEST3
1371           if (azt_state!=azt_state_old) {
1372             azt_state_old=azt_state;
1373             printk("AZT_S_STOPPING\n");
1374           }
1375 #endif
1376 
1377           if ((st = aztStatus()) == -1 && AztTimeout)
1378             break;
1379 
1380           if ((st != -1) && ((st & AST_DSK_CHG)||(st & AST_NOT_READY))) {
1381             aztDiskChanged = 1;
1382             aztTocUpToDate = 0;
1383             azt_invalidate_buffers();
1384             printk("aztcd: Disk Changed or Not Ready 4 - Unmount Disk!\n");
1385             end_request(0);
1386           }
1387 
1388 
1389 #ifdef AZT_TEST3
1390           printk("CURRENT_VALID %d azt_mode %d\n",
1391              CURRENT_VALID, azt_mode);
1392 #endif
1393 
1394           if (CURRENT_VALID) {
1395             if (st != -1) {
1396               if (azt_mode == 1) {
1397                 azt_state = AZT_S_READ;
1398                 loop_ctl = 1;
1399                 skip = 1;
1400                 break;
1401               } else {
1402                 azt_state = AZT_S_MODE;
1403                 loop_ctl = 1;
1404                 skip = 1;
1405                 break;
1406               }
1407             } else {
1408               azt_state = AZT_S_START;
1409               AztTimeout = 1;
1410             }
1411           } else {
1412             azt_state = AZT_S_IDLE;
1413             return;
1414           }
1415           break;
1416 
1417         default:
1418           printk("aztcd: invalid state %d\n", azt_state);
1419           return;
1420       }  /* case */
1421     } /* while */
1422   
1423 
1424    if (!AztTimeout--) 
1425     { printk("aztcd: timeout in state %d\n", azt_state);
1426       azt_state = AZT_S_STOP;
1427       if (aztSendCmd(ACMD_STOP)) RETURN("azt_poll 6"); 
1428       STEN_LOW_WAIT;     
1429     };
1430 
1431   SET_TIMER(azt_poll, HZ/100);
1432 }
1433 
1434 static void azt_invalidate_buffers(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1435 { int i;
1436 
1437 #ifdef AZT_DEBUG
1438   printk("aztcd: executing azt_invalidate_buffers\n");
1439 #endif
1440   for (i = 0; i < AZT_BUF_SIZ; ++i)
1441     azt_buf_bn[i] = -1;
1442   azt_buf_out = -1;
1443 }
1444 
1445 /*
1446  * Open the device special file.  Check that a disk is in.
1447  */
1448 int aztcd_open(struct inode *ip, struct file *fp)
     /* [previous][next][first][last][top][bottom][index][help] */
1449 {       int st;
1450 
1451 #ifdef AZT_DEBUG
1452         printk("aztcd: starting aztcd_open\n");
1453 #endif
1454         if (aztPresent == 0)
1455                 return -ENXIO;                  /* no hardware */
1456 
1457         if (!azt_open_count && azt_state == AZT_S_IDLE) 
1458           { azt_invalidate_buffers();
1459 
1460             st = getAztStatus();                    /* check drive status */
1461             if (st == -1) return -EIO;              /* drive doesn't respond */
1462 
1463             if (st & AST_DOOR_OPEN)
1464                { /* close door, then get the status again. */
1465                  printk("aztcd: Door Open?\n");
1466                  aztCloseDoor();     
1467                  st = getAztStatus();
1468                }        
1469 
1470             if ((st & AST_NOT_READY) || (st & AST_DSK_CHG)) /*no disk in drive or changed*/
1471                { printk("aztcd: Disk Changed or No Disk in Drive?\n");
1472                  aztTocUpToDate=0;
1473                }
1474             if (aztUpdateToc()) return -EIO;
1475                
1476           }
1477         ++azt_open_count;
1478         MOD_INC_USE_COUNT;
1479         aztLockDoor();
1480 
1481 
1482 #ifdef AZT_DEBUG
1483         printk("aztcd: exiting aztcd_open\n");
1484 #endif
1485         return 0;
1486 }
1487 
1488 
1489 /*
1490  * On close, we flush all azt blocks from the buffer cache.
1491  */
1492 static void aztcd_release(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
1493 { 
1494 #ifdef AZT_DEBUG
1495   printk("aztcd: executing aztcd_release\n");
1496   printk("inode: %p, inode->i_rdev: %x    file: %p\n",inode,inode->i_rdev,file);
1497 #endif
1498   MOD_DEC_USE_COUNT;
1499   if (!--azt_open_count) {
1500         azt_invalidate_buffers();
1501         sync_dev(inode->i_rdev);             /*??? isn't it a read only dev?*/
1502         invalidate_buffers(inode -> i_rdev);
1503         aztUnlockDoor();
1504         if (azt_auto_eject)
1505            aztSendCmd(ACMD_EJECT);
1506         CLEAR_TIMER;
1507   }
1508   return;
1509 }
1510 
1511 
1512 static struct file_operations azt_fops = {
1513         NULL,                   /* lseek - default */
1514         block_read,             /* read - general block-dev read */
1515         block_write,            /* write - general block-dev write */
1516         NULL,                   /* readdir - bad */
1517         NULL,                   /* select */
1518         aztcd_ioctl,            /* ioctl */
1519         NULL,                   /* mmap */
1520         aztcd_open,             /* open */
1521         aztcd_release,          /* release */
1522         NULL,                   /* fsync */
1523         NULL,                   /* fasync*/
1524         check_aztcd_media_change, /*media change*/
1525         NULL                    /* revalidate*/
1526 };
1527 
1528 /*
1529  * Test for presence of drive and initialize it.  Called at boot time.
1530  */
1531 
1532 int aztcd_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1533 {       long int count, max_count;
1534         unsigned char result[50];
1535         int st;
1536 
1537         if (azt_port <= 0) {
1538           printk("aztcd: no Aztech CD-ROM Initialization");
1539           return -EIO;
1540         }
1541         printk("aztcd: Aztech, Orchid, Okano, Wearnes CD-ROM Driver (C) 1994,1995 W.Zimmermann\n");
1542         printk("aztcd: DriverVersion=%s  BaseAddress=0x%x \n",AZT_VERSION,azt_port);
1543 
1544         if (check_region(azt_port, 4)) {
1545           printk("aztcd: conflict, I/O port (%X) already used\n",
1546                  azt_port);
1547           return -EIO;
1548         }
1549 
1550 #ifdef AZT_SW32   /*CDROM connected to Soundwave32 card*/
1551         if ((0xFF00 & inw(AZT_SW32_ID_REG)) != 0x4500)
1552            { printk("aztcd: no Soundwave32 card detected at base:%x init:%x config:%x id:%x\n",
1553                  AZT_SW32_BASE_ADDR,AZT_SW32_INIT,AZT_SW32_CONFIG_REG,AZT_SW32_ID_REG);
1554                  return -EIO;
1555            }
1556         else                
1557            { printk("aztcd: Soundwave32 card detected at %x  Version %x\n",
1558                  AZT_SW32_BASE_ADDR, inw(AZT_SW32_ID_REG));
1559              outw(AZT_SW32_INIT,AZT_SW32_CONFIG_REG);
1560              for (count=0;count<10000;count++);          /*delay a bit*/         
1561            }
1562 #endif  
1563 
1564         /* check for presence of drive */
1565         outb(POLLED,MODE_PORT);                 /*???*/
1566         inb(CMD_PORT);
1567         inb(CMD_PORT);
1568         outb(ACMD_GET_VERSION,CMD_PORT); /*Try to get version info*/
1569 
1570 /*      STEN_LOW  - special implementation for drive recognition
1571 */      aztTimeOutCount=0;   
1572         do { aztIndatum=inb(STATUS_PORT);
1573              aztTimeOutCount++; 
1574              if (aztTimeOutCount>=AZT_FAST_TIMEOUT) break; 
1575            } while (aztIndatum&AFL_STATUS); 
1576 
1577         if (inb(DATA_PORT)!=AFL_OP_OK) /*OP_OK? If not, reset and try again*/
1578            { 
1579 #ifndef MODULE
1580              if (azt_cont!=0x79)   
1581                 { printk("aztcd: no AZTECH CD-ROM drive found-Try boot parameter aztcd=<BaseAddress>,0x79\n");
1582                   return -EIO;
1583                 }
1584 #else        
1585              if (0)
1586                 {
1587                 }
1588 #endif       
1589              else   
1590                 { printk("aztcd: drive reset - please wait\n");
1591                   for (count=0;count<50;count++)
1592                     { inb(STATUS_PORT);    /*removing all data from earlier tries*/
1593                       inb(DATA_PORT);
1594                     }
1595                   outb(POLLED,MODE_PORT);           /*???*/
1596                   inb(CMD_PORT);
1597                   inb(CMD_PORT);
1598                   getAztStatus();                   /*trap errors*/
1599                   outb(ACMD_SOFT_RESET,CMD_PORT);   /*send reset*/
1600                   STEN_LOW;
1601                   if (inb(DATA_PORT)!=AFL_OP_OK)    /*OP_OK?*/
1602                      { printk("aztcd: no AZTECH CD-ROM drive found\n");
1603                        return -EIO;
1604                      } 
1605                   for (count = 0; count < AZT_TIMEOUT; count++); 
1606                      { count=count*2;          /* delay a bit */
1607                        count=count/2;
1608                      }                        
1609                   if ((st=getAztStatus())==-1)
1610                      { printk("aztcd: Drive Status Error Status=%x\n",st);
1611                        return -EIO;
1612                      }
1613 #ifdef AZT_DEBUG
1614                   printk("aztcd: Status = %x\n",st);
1615 #endif
1616                   outb(POLLED,MODE_PORT);              /*???*/
1617                   inb(CMD_PORT);
1618                   inb(CMD_PORT);
1619                   outb(ACMD_GET_VERSION,CMD_PORT); /*GetVersion*/
1620                   STEN_LOW;
1621                   OP_OK;
1622                 } 
1623            }
1624         azt_init_end=1;
1625         STEN_LOW;
1626         result[0]=inb(DATA_PORT);        /*reading in a null byte???*/
1627         for (count=1;count<50;count++)   /*Reading version string*/
1628          { aztTimeOutCount=0;            /*here we must implement STEN_LOW differently*/
1629            do { aztIndatum=inb(STATUS_PORT);/*because we want to exit by timeout*/
1630                 aztTimeOutCount++; 
1631                 if (aztTimeOutCount>=AZT_FAST_TIMEOUT) break; 
1632               } while (aztIndatum&AFL_STATUS); 
1633            if (aztTimeOutCount>=AZT_FAST_TIMEOUT) break;  /*all chars read?*/
1634            result[count]=inb(DATA_PORT);
1635          }
1636         if (count>30) max_count=30;  /*print max.30 chars of the version string*/
1637         else          max_count=count;
1638         printk("aztcd: FirmwareVersion=");
1639         for (count=1;count<max_count;count++) printk("%c",result[count]);
1640         printk("<<<\n");
1641 
1642         if ((result[1]=='A')&&(result[2]=='Z')&&(result[3]=='T'))
1643          { printk("aztcd: AZTECH drive detected\n"); /*AZTECH*/    
1644          }
1645         else if ((result[2]=='C')&&(result[3]=='D')&&(result[4]=='D'))
1646          { printk("aztcd: ORCHID or WEARNES drive detected\n"); /*ORCHID or WEARNES*/
1647          }
1648         else                                               /*OTHERS or none*/
1649          { printk("aztcd: : unknown drive or firmware version detected\n");
1650            printk("                      azt may not run stable, if you want to try anyhow,\n");
1651            printk("                      boot with: aztcd=<BaseAddress>,0x79\n");
1652            if ((azt_cont!=0x79))     
1653              { printk("aztcd: FirmwareVersion=");
1654                for (count=1;count<5;count++) printk("%c",result[count]);
1655                printk("\n");
1656                printk("aztcd: Aborted\n");
1657                return -EIO;
1658              }
1659          }
1660         if (register_blkdev(MAJOR_NR, "aztcd", &azt_fops) != 0)
1661         {
1662                 printk("aztcd: Unable to get major %d for Aztech CD-ROM\n",
1663                        MAJOR_NR);
1664                 return -EIO;
1665         }
1666         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1667         read_ahead[MAJOR_NR] = 4;
1668 
1669         request_region(azt_port, 4, "aztcd");
1670 
1671         azt_invalidate_buffers();
1672         aztPresent = 1;
1673         aztCloseDoor();
1674         printk("aztcd: End Init\n");
1675         return (0);
1676 }
1677 
1678 
1679 static void azt_hsg2msf(long hsg, struct msf *msf)
     /* [previous][next][first][last][top][bottom][index][help] */
1680 {       hsg += 150;
1681         msf -> min = hsg / 4500;
1682         hsg %= 4500;
1683         msf -> sec = hsg / 75;
1684         msf -> frame = hsg % 75;
1685 #ifdef AZT_DEBUG
1686         if (msf->min  >=70) printk("aztcd: Error hsg2msf address Minutes\n");
1687         if (msf->sec  >=60) printk("aztcd: Error hsg2msf address Seconds\n");
1688         if (msf->frame>=75) printk("aztcd: Error hsg2msf address Frames\n");
1689 #endif
1690         azt_bin2bcd(&msf -> min);           /* convert to BCD */
1691         azt_bin2bcd(&msf -> sec);
1692         azt_bin2bcd(&msf -> frame);
1693 }
1694 
1695 
1696 static void azt_bin2bcd(unsigned char *p)
     /* [previous][next][first][last][top][bottom][index][help] */
1697 {       int u, t;
1698 
1699         u = *p % 10;
1700         t = *p / 10;
1701         *p = u | (t << 4);
1702 }
1703 
1704 static int azt_bcd2bin(unsigned char bcd)
     /* [previous][next][first][last][top][bottom][index][help] */
1705 {       return (bcd >> 4) * 10 + (bcd & 0xF);
1706 }
1707 
1708 
1709 
1710 /*
1711  * Read a value from the drive.  Should return quickly, so a busy wait
1712  * is used to avoid excessive rescheduling. The read command itself must
1713  * be issued with aztSendCmd() directly before
1714  */
1715 static int aztGetValue(unsigned char *result)
     /* [previous][next][first][last][top][bottom][index][help] */
1716 {       int s;
1717 
1718         STEN_LOW;
1719         if (aztTimeOutCount>=AZT_TIMEOUT)
1720         {       printk("aztcd: aztGetValue timeout\n");
1721                 return -1;
1722         }
1723         s = inb(DATA_PORT) & 0xFF;
1724         *result = (unsigned char) s;
1725         return 0;
1726 }
1727 
1728 
1729 /*
1730  * Read the current Q-channel info.  Also used for reading the
1731  * table of contents.
1732  */
1733 int aztGetQChannelInfo(struct azt_Toc *qp)
     /* [previous][next][first][last][top][bottom][index][help] */
1734 {       unsigned char notUsed;
1735         int st;
1736 
1737 #ifdef AZT_DEBUG
1738         printk("aztcd: starting aztGetQChannelInfo  Time:%li\n",jiffies);
1739 #endif
1740         if ((st=getAztStatus())==-1)        RETURNM("aztGetQChannelInfo 1",-1);
1741         if (aztSendCmd(ACMD_GET_Q_CHANNEL)) RETURNM("aztGetQChannelInfo 2",-1);
1742         /*STEN_LOW_WAIT; ??? Dosemu0.60's cdrom.c does not like STEN_LOW_WAIT here*/
1743         if (aztGetValue(&notUsed)) RETURNM("aztGetQChannelInfo 3",-1); /*??? Nullbyte einlesen*/
1744         if ((st&AST_MODE_BITS)==AST_INITIAL)
1745          { qp->ctrl_addr=0;      /* when audio stop ACMD_GET_Q_CHANNEL returns */
1746            qp->track=0;          /* only one byte with Aztech drives */
1747            qp->pointIndex=0;
1748            qp->trackTime.min=0;
1749            qp->trackTime.sec=0;
1750            qp->trackTime.frame=0;
1751            qp->diskTime.min=0;
1752            qp->diskTime.sec=0;
1753            qp->diskTime.frame=0;
1754            return 0;  
1755          }
1756         else
1757          { if (aztGetValue(&qp -> ctrl_addr) < 0)       RETURNM("aztGetQChannelInfo 4",-1);
1758            if (aztGetValue(&qp -> track) < 0)           RETURNM("aztGetQChannelInfo 4",-1);
1759            if (aztGetValue(&qp -> pointIndex) < 0)      RETURNM("aztGetQChannelInfo 4",-1);
1760            if (aztGetValue(&qp -> trackTime.min) < 0)   RETURNM("aztGetQChannelInfo 4",-1);
1761            if (aztGetValue(&qp -> trackTime.sec) < 0)   RETURNM("aztGetQChannelInfo 4",-1);
1762            if (aztGetValue(&qp -> trackTime.frame) < 0) RETURNM("aztGetQChannelInfo 4",-1);
1763            if (aztGetValue(&notUsed) < 0)               RETURNM("aztGetQChannelInfo 4",-1);
1764            if (aztGetValue(&qp -> diskTime.min) < 0)    RETURNM("aztGetQChannelInfo 4",-1);
1765            if (aztGetValue(&qp -> diskTime.sec) < 0)    RETURNM("aztGetQChannelInfo 4",-1);
1766            if (aztGetValue(&qp -> diskTime.frame) < 0)  RETURNM("aztGetQChannelInfo 4",-1);
1767          }
1768 #ifdef AZT_DEBUG
1769         printk("aztcd: exiting aztGetQChannelInfo  Time:%li\n",jiffies);
1770 #endif
1771         return 0;
1772 }
1773 
1774 /*
1775  * Read the table of contents (TOC) and TOC header if necessary
1776  */
1777 static int aztUpdateToc()
     /* [previous][next][first][last][top][bottom][index][help] */
1778 {       int st;
1779 
1780 #ifdef AZT_DEBUG
1781         printk("aztcd: starting aztUpdateToc  Time:%li\n",jiffies);
1782 #endif  
1783         if (aztTocUpToDate)
1784                 return 0;
1785 
1786         if (aztGetDiskInfo() < 0)
1787                 return -EIO;
1788 
1789         if (aztGetToc(0) < 0)
1790                 return -EIO;
1791 
1792         /*audio disk detection
1793           with my Aztech drive there is no audio status bit, so I use the copy
1794           protection bit of the first track. If this track is copy protected 
1795           (copy bit = 0), I assume, it's an audio  disk. Strange, but works ??? */
1796         if (!(Toc[DiskInfo.first].ctrl_addr & 0x40)) 
1797            DiskInfo.audio=1;
1798         else 
1799            DiskInfo.audio=0;
1800 
1801         /* XA detection */
1802         if (! DiskInfo.audio) 
1803            { azt_Play.start.min   = 0;  /*XA detection only seems to work*/
1804              azt_Play.start.sec   = 2;  /*when we play a track*/
1805              azt_Play.start.frame = 0;
1806              azt_Play.end.min     = 0;
1807              azt_Play.end.sec     = 0;
1808              azt_Play.end.frame   = 1;
1809              if (sendAztCmd(ACMD_PLAY_READ, &azt_Play)) return -1;
1810              DTEN_LOW;
1811              for (st=0;st<CD_FRAMESIZE;st++) inb(DATA_PORT);
1812            } 
1813         DiskInfo.xa = getAztStatus() & AST_MODE;
1814         if (DiskInfo.xa) 
1815            { printk("aztcd: XA support experimental - mail results to zimmerma@rz.fht-esslingen.de\n");
1816            }
1817         
1818         /*multisession detection
1819           support for multisession CDs is done automatically with Aztech drives,
1820           we don't have to take care about TOC redirection; if we want the isofs
1821           to take care about redirection, we have to set AZT_MULTISESSION to 1*/
1822         DiskInfo.multi=0;
1823 #if AZT_MULTISESSION
1824         if (DiskInfo.xa) 
1825            { aztGetMultiDiskInfo(); /*here Disk.Info.multi is set*/
1826            }
1827 #endif
1828         if (DiskInfo.multi)
1829            { DiskInfo.lastSession.min  = Toc[DiskInfo.next].diskTime.min;
1830              DiskInfo.lastSession.sec  = Toc[DiskInfo.next].diskTime.sec;
1831              DiskInfo.lastSession.frame= Toc[DiskInfo.next].diskTime.frame;
1832              printk("aztcd: Multisession support experimental\n");
1833            }
1834         else
1835            { DiskInfo.lastSession.min  = Toc[DiskInfo.first].diskTime.min;
1836              DiskInfo.lastSession.sec  = Toc[DiskInfo.first].diskTime.sec;
1837              DiskInfo.lastSession.frame= Toc[DiskInfo.first].diskTime.frame;
1838            }
1839 
1840         aztTocUpToDate = 1;
1841 #ifdef AZT_DEBUG
1842         printk("aztcd: exiting aztUpdateToc  Time:%li\n",jiffies);
1843 #endif
1844         return 0;
1845 }
1846 
1847 
1848 /* Read the table of contents header, i.e. no. of tracks and start of first 
1849  * track
1850  */
1851 static int aztGetDiskInfo()
     /* [previous][next][first][last][top][bottom][index][help] */
1852 { int limit;
1853   unsigned char test;
1854   struct azt_Toc qInfo;
1855 
1856 #ifdef AZT_DEBUG
1857   printk("aztcd: starting aztGetDiskInfo  Time:%li\n",jiffies);
1858 #endif
1859   if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) RETURNM("aztGetDiskInfo 1",-1);
1860   STEN_LOW_WAIT;
1861   test=0;
1862   for (limit=300;limit>0;limit--)
1863    {  if (aztGetQChannelInfo(&qInfo)<0) RETURNM("aztGetDiskInfo 2",-1);
1864       if (qInfo.pointIndex==0xA0)   /*Number of FirstTrack*/
1865         { DiskInfo.first = qInfo.diskTime.min;
1866           DiskInfo.first = azt_bcd2bin(DiskInfo.first);
1867           test=test|0x01;
1868         }
1869       if (qInfo.pointIndex==0xA1)   /*Number of LastTrack*/
1870         { DiskInfo.last  = qInfo.diskTime.min;
1871           DiskInfo.last  = azt_bcd2bin(DiskInfo.last);
1872           test=test|0x02;
1873         }
1874       if (qInfo.pointIndex==0xA2)   /*DiskLength*/
1875         { DiskInfo.diskLength.min=qInfo.diskTime.min;
1876           DiskInfo.diskLength.sec=qInfo.diskTime.sec;
1877           DiskInfo.diskLength.frame=qInfo.diskTime.frame;
1878           test=test|0x04;
1879         }
1880       if ((qInfo.pointIndex==DiskInfo.first)&&(test&0x01))   /*StartTime of First Track*/
1881         { DiskInfo.firstTrack.min=qInfo.diskTime.min;
1882           DiskInfo.firstTrack.sec=qInfo.diskTime.sec;
1883           DiskInfo.firstTrack.frame=qInfo.diskTime.frame;
1884           test=test|0x08;
1885         }
1886       if (test==0x0F) break;
1887    }
1888 #ifdef AZT_DEBUG
1889   printk ("aztcd: exiting aztGetDiskInfo  Time:%li\n",jiffies);
1890   printk("Disk Info: first %d last %d length %02X:%02X.%02X dez  first %02X:%02X.%02X dez\n",
1891           DiskInfo.first,
1892           DiskInfo.last,
1893           DiskInfo.diskLength.min,
1894           DiskInfo.diskLength.sec,
1895           DiskInfo.diskLength.frame,
1896           DiskInfo.firstTrack.min,
1897           DiskInfo.firstTrack.sec,
1898           DiskInfo.firstTrack.frame);
1899 #endif
1900   if (test!=0x0F) return -1;
1901   return 0;
1902 }
1903 
1904 #if AZT_MULTISESSION
1905 /*
1906  * Get Multisession Disk Info
1907  */
1908 static int aztGetMultiDiskInfo(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1909 { int limit, k=5;
1910   unsigned char test;
1911   struct azt_Toc qInfo;
1912 
1913 #ifdef AZT_DEBUG
1914   printk("aztcd: starting aztGetMultiDiskInfo\n");
1915 #endif
1916 
1917   do { azt_Play.start.min   = Toc[DiskInfo.last+1].diskTime.min;
1918        azt_Play.start.sec   = Toc[DiskInfo.last+1].diskTime.sec;
1919        azt_Play.start.frame = Toc[DiskInfo.last+1].diskTime.frame;
1920        test=0;
1921 
1922        for (limit=30;limit>0;limit--)   /*Seek for LeadIn of next session*/
1923            { if (aztSeek(&azt_Play)) RETURNM("aztGetMultiDiskInfo 1",-1);
1924              if (aztGetQChannelInfo(&qInfo)<0) RETURNM("aztGetMultiDiskInfo 2",-1);
1925              if ((qInfo.track==0)&&(qInfo.pointIndex)) break;  /*LeadIn found*/
1926              if ((azt_Play.start.sec+=10) > 59)
1927                 { azt_Play.start.sec=0;
1928                   azt_Play.start.min++;
1929                 }
1930            }
1931        if (!limit) break;  /*Check, if a leadin track was found, if not we're
1932                              at the end of the disk*/
1933 #ifdef AZT_DEBUG_MULTISESSION
1934        printk("leadin found track %d  pointIndex %x  limit %d\n",qInfo.track,qInfo.pointIndex,limit);
1935 #endif
1936        for (limit=300;limit>0;limit--)
1937            { if (++azt_Play.start.frame>74)
1938                 { azt_Play.start.frame=0;
1939                   if (azt_Play.start.sec > 59)
1940                      { azt_Play.start.sec=0;
1941                        azt_Play.start.min++;
1942                      }
1943                 }     
1944              if (aztSeek(&azt_Play)) RETURNM("aztGetMultiDiskInfo 3",-1);
1945              if (aztGetQChannelInfo(&qInfo)<0) RETURNM("aztGetMultiDiskInfo 4",-1);
1946              if (qInfo.pointIndex==0xA0)   /*Number of NextTrack*/
1947                 { DiskInfo.next = qInfo.diskTime.min;
1948                   DiskInfo.next = azt_bcd2bin(DiskInfo.next);
1949                   test=test|0x01;
1950                 }
1951              if (qInfo.pointIndex==0xA1)   /*Number of LastTrack*/
1952                 { DiskInfo.last  = qInfo.diskTime.min;
1953                   DiskInfo.last  = azt_bcd2bin(DiskInfo.last);
1954                   test=test|0x02;
1955                 }
1956              if (qInfo.pointIndex==0xA2)   /*DiskLength*/
1957                 { DiskInfo.diskLength.min  =qInfo.diskTime.min;
1958                   DiskInfo.diskLength.sec  =qInfo.diskTime.sec;
1959                   DiskInfo.diskLength.frame=qInfo.diskTime.frame;
1960                   test=test|0x04;
1961                 }
1962              if ((qInfo.pointIndex==DiskInfo.next)&&(test&0x01))   /*StartTime of Next Track*/
1963                 { DiskInfo.nextSession.min=qInfo.diskTime.min;
1964                   DiskInfo.nextSession.sec=qInfo.diskTime.sec;
1965                   DiskInfo.nextSession.frame=qInfo.diskTime.frame;
1966                   test=test|0x08;
1967                 }
1968              if (test==0x0F) break;
1969            }
1970 #ifdef AZT_DEBUG_MULTISESSION
1971        printk ("MultiDisk Info: first %d next %d last %d length %02x:%02x.%02x dez  first %02x:%02x.%02x dez  next %02x:%02x.%02x dez\n",
1972                 DiskInfo.first,
1973                 DiskInfo.next,
1974                 DiskInfo.last,
1975                 DiskInfo.diskLength.min,
1976                 DiskInfo.diskLength.sec,
1977                 DiskInfo.diskLength.frame,
1978                 DiskInfo.firstTrack.min,
1979                 DiskInfo.firstTrack.sec,
1980                 DiskInfo.firstTrack.frame,
1981                 DiskInfo.nextSession.min,
1982                 DiskInfo.nextSession.sec,
1983                 DiskInfo.nextSession.frame);
1984 #endif
1985        if (test!=0x0F) 
1986            break;
1987        else 
1988            DiskInfo.multi=1;   /*found TOC of more than one session*/
1989        aztGetToc(1);
1990      } while(--k);
1991 
1992 #ifdef AZT_DEBUG
1993   printk ("aztcd: exiting aztGetMultiDiskInfo  Time:%li\n",jiffies);
1994 #endif
1995   return 0;
1996 }
1997 #endif
1998 
1999 /*
2000  * Read the table of contents (TOC)
2001  */
2002 static int aztGetToc(int multi)
     /* [previous][next][first][last][top][bottom][index][help] */
2003 { int i, px;
2004   int limit;
2005   struct azt_Toc qInfo;
2006 
2007 #ifdef AZT_DEBUG
2008   printk("aztcd: starting aztGetToc  Time:%li\n",jiffies);
2009 #endif
2010   if (!multi)
2011      { for (i = 0; i < MAX_TRACKS; i++)
2012             Toc[i].pointIndex = 0;
2013        i = DiskInfo.last + 3;
2014      }
2015   else
2016      { for (i = DiskInfo.next; i < MAX_TRACKS; i++)
2017             Toc[i].pointIndex = 0; 
2018        i = DiskInfo.last + 4 - DiskInfo.next;
2019      }
2020 
2021 /*Is there a good reason to stop motor before TOC read?
2022   if (aztSendCmd(ACMD_STOP)) RETURNM("aztGetToc 1",-1);
2023       STEN_LOW_WAIT;
2024 */
2025 
2026   if (!multi)
2027      { azt_mode = 0x05;
2028        if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) RETURNM("aztGetToc 2",-1); /*???*/
2029        STEN_LOW_WAIT;
2030      }
2031   for (limit = 300; limit > 0; limit--)
2032       { if (multi)
2033            { if (++azt_Play.start.sec > 59)
2034                 { azt_Play.start.sec=0;
2035                   azt_Play.start.min++;
2036                 }
2037              if (aztSeek(&azt_Play)) RETURNM("aztGetToc 3",-1);
2038            }
2039         if (aztGetQChannelInfo(&qInfo) < 0)
2040             break;
2041 
2042         px = azt_bcd2bin(qInfo.pointIndex);
2043 
2044         if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
2045             if (Toc[px].pointIndex == 0)
2046                { Toc[px] = qInfo;
2047                  i--;
2048                }
2049 
2050         if (i <= 0)
2051             break;
2052       }
2053 
2054   Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
2055 
2056 
2057 #ifdef AZT_DEBUG_MULTISESSION 
2058   printk("aztcd: exiting aztGetToc\n");
2059   for (i = 1; i <= DiskInfo.last+1; i++)
2060        printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez  %02X:%02X.%02X dez\n",
2061                i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
2062                Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
2063                Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
2064   for (i = 100; i < 103; i++)
2065        printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez  %02X:%02X.%02X dez\n",
2066                i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
2067                Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame,
2068                Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
2069 #endif
2070 
2071   return limit > 0 ? 0 : -1;
2072 }
2073 
2074 #ifdef MODULE
2075 void cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
2076 { if (MOD_IN_USE)
2077     { printk("aztcd module in use - can't remove it.\n");
2078       return;
2079     }
2080   if ((unregister_blkdev(MAJOR_NR, "aztcd") == -EINVAL))    
2081     { printk("What's that: can't unregister aztcd\n");
2082       return;
2083     }
2084    release_region(azt_port,4);
2085    printk("aztcd module released.\n");
2086 }   
2087 #endif MODULE

/* [previous][next][first][last][top][bottom][index][help] */