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. init_module
  38. cleanup_module

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

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