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

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