root/drivers/cdrom/mcdx.c

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

DEFINITIONS

This source file includes following definitions.
  1. mcdx_ioctl
  2. do_mcdx_request
  3. mcdx_open
  4. mcdx_close
  5. check_mcdx_media_change
  6. mcdx_setup
  7. mcdx_delay
  8. mcdx_intr
  9. mcdx_talk
  10. init_module
  11. cleanup_module
  12. trace
  13. warn
  14. mcdx_init
  15. mcdx_transfer
  16. port
  17. irq
  18. bcd2uint
  19. uint2bcd
  20. log2msf
  21. msf2log
  22. mcdx_readtoc
  23. mcdx_playmsf
  24. mcdx_playtrk
  25. mcdx_closedoor
  26. mcdx_stop
  27. mcdx_hold
  28. mcdx_eject
  29. mcdx_requestsubqcode
  30. mcdx_requestmultidiskinfo
  31. mcdx_requesttocdata
  32. mcdx_setdrivemode
  33. mcdx_setdatamode
  34. mcdx_config
  35. mcdx_requestversion
  36. mcdx_reset
  37. mcdx_lockdoor
  38. mcdx_getstatus
  39. mcdx_getval
  40. mcdx_setattentuator

   1 /*
   2  * The Mitsumi CDROM interface
   3  * Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
   4  * VERSION: 1.3
   5  * 
   6  * This program is free software; you can redistribute it and/or modify
   7  * it under the terms of the GNU General Public License as published by
   8  * the Free Software Foundation; either version 2, or (at your option)
   9  * any later version.
  10  * 
  11  * This program is distributed in the hope that it will be useful,
  12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14  * GNU General Public License for more details.
  15  * 
  16  * You should have received a copy of the GNU General Public License
  17  * along with this program; see the file COPYING.  If not, write to
  18  * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19  *
  20  * Thanks to
  21  *  The Linux Community at all and ...
  22  *  Martin Harriss (he wrote the first Mitsumi Driver)
  23  *  Eberhard Moenkeberg (he gave me much support and the initial kick)
  24  *  Bernd Huebner, Ruediger Helsch (Unifix-Software GmbH, they
  25  *      improved the original driver)
  26  *  Jon Tombs, Bjorn Ekwall (module support)
  27  *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
  28  *  Gerd Knorr (he lent me his PhotoCD)
  29  *  Nils Faerber and Roger E. Wolff (extensivly tested the LU portion)
  30  *  ... somebody forgotten?
  31  *  
  32  */
  33 
  34 
  35 #if RCS
  36 static const char *mcdx_c_version
  37                 = "mcdx.c,v 1.17 1995/11/06 01:07:57 heiko Exp";
  38 #endif
  39 
  40 #include <linux/config.h>
  41 
  42 #ifdef MODULE
  43 #include <linux/module.h>
  44 #endif
  45 
  46 #include <linux/version.h>
  47 
  48 #ifdef MODULE
  49 #ifndef CONFIG_MODVERSIONS
  50 char kernel_version[] = UTS_RELEASE;
  51 #endif
  52 #else
  53 #define MOD_INC_USE_COUNT
  54 #define MOD_DEC_USE_COUNT
  55 #define MOD_IN_USE 1
  56 #endif MODULE
  57 
  58 #include <linux/errno.h>
  59 #include <linux/signal.h>
  60 #include <linux/sched.h>
  61 #include <linux/timer.h>
  62 #include <linux/fs.h>
  63 #include <linux/kernel.h>
  64 #include <linux/cdrom.h>
  65 #include <linux/ioport.h>
  66 #include <linux/mm.h>
  67 #include <linux/malloc.h>
  68 #include <asm/system.h>
  69 #include <asm/io.h>
  70 #include <asm/segment.h>
  71 
  72 
  73 #include <linux/major.h>
  74 
  75 /* old kernel (doesn't know about MCDX) */
  76 #ifndef MITSUMI_X_CDROM_MAJOR
  77 #define MITSUMI_X_CDROM_MAJOR 20
  78 #define DEVICE_NAME "mcdx"
  79 
  80 /* #define DEVICE_INTR do_mcdx */
  81 #define DEVICE_REQUEST do_mcdx_request
  82 #define DEVICE_NR(device) (MINOR(device))
  83 #define DEVICE_ON(device)
  84 #define DEVICE_OFF(device)
  85 #endif
  86 
  87 #define MAJOR_NR MITSUMI_X_CDROM_MAJOR
  88 #include <linux/blk.h>
  89 
  90 /* for compatible parameter passing with "insmod" */ 
  91 #define mcdx_drive_map mcdx    
  92 #include <linux/mcdx.h>
  93 
  94 #ifndef HZ 
  95 #error HZ not defined
  96 #endif
  97 
  98 /* CONSTANTS *******************************************************/
  99 
 100 const int REQUEST_SIZE = 200;
 101 const int DIRECT_SIZE = 200;
 102 const unsigned long ACLOSE_INHIBIT = 800;  /* 1/100 s of autoclose inhibit */
 103 
 104 enum drivemodes { TOC, DATA, RAW, COOKED };
 105 enum datamodes { MODE0, MODE1, MODE2 };
 106 enum resetmodes { SOFT, HARD };
 107 
 108 const int SINGLE = 0x01;
 109 const int DOUBLE = 0x02;
 110 const int DOOR   = 0x04;
 111 const int MULTI  = 0x08;
 112 const int READY  = 0x70;
 113 
 114 const unsigned char READSSPEED = 0xc0;
 115 const unsigned char READDSPEED = 0xc1;
 116 
 117 
 118 /* DECLARATIONS ****************************************************/ 
 119 struct s_msf {
 120         unsigned char minute;
 121         unsigned char second;
 122         unsigned char frame;
 123 };
 124 
 125 struct s_subqcode {
 126         unsigned char control;
 127         unsigned char tno;
 128         unsigned char index;
 129         struct s_msf tt;
 130         struct s_msf dt;
 131 };
 132 
 133 struct s_diskinfo {
 134         unsigned int n_first;
 135         unsigned int n_last;
 136         struct s_msf msf_leadout;
 137         struct s_msf msf_first;
 138 };
 139         
 140 struct s_multi {
 141         unsigned char multi;
 142         struct s_msf msf_last;
 143 };
 144 
 145 struct s_version {
 146         unsigned char code;
 147         unsigned char ver;
 148 };
 149 
 150 /* Per drive/controller stuff **************************************/
 151 
 152 struct s_drive_stuff {
 153         /* waitquenes */
 154     struct wait_queue *busyq;
 155     struct wait_queue *lockq;
 156     struct wait_queue *sleepq;
 157 
 158         /* flags */
 159     volatile int introk;        /* status of last irq operation */
 160     volatile int busy;          /* drive performs an operation */
 161     volatile int lock;          /* exclusive usage */
 162     int eject_sw;           /* 1 - eject on last close (default 0) */
 163     int autoclose;          /* 1 - close the door on open (default 1) */
 164     
 165         /* cd infos */
 166         struct s_diskinfo di;
 167         struct s_multi multi;
 168         struct s_subqcode* toc; /* first enty of the toc array */
 169         struct s_subqcode start;
 170     struct s_subqcode stop;
 171         int xa;                                 /* 1 if xa disk */
 172         int audio;                              /* 1 if audio disk */
 173         int audiostatus;                        
 174 
 175         /* `buffer' control */
 176     volatile int valid;
 177     volatile int pending;
 178     volatile int off_direct;
 179     volatile int off_requested;
 180 
 181         /* adds and odds */
 182         void* wreg_data;        /* w data */
 183         void* wreg_reset;       /* w hardware reset */
 184         void* wreg_hcon;        /* w hardware conf */
 185         void* wreg_chn;         /* w channel */
 186         void* rreg_data;        /* r data */
 187         void* rreg_status;      /* r status */
 188 
 189     int irq;                    /* irq used by this drive */
 190     int minor;                  /* minor number of this drive */
 191     int present;            /* drive present and its capabilities */
 192     char readcmd;               /* read cmd depends on single/double speed */
 193     char playcmd;       /* play should always be single speed */
 194     unsigned long changed;      /* last jiff the media was changed */
 195     unsigned long xxx;      /* last jiff it was asked for media change */
 196     unsigned long ejected;  /* time we called the eject function */
 197     int users;                          /* keeps track of open/close */
 198     int lastsector;                     /* last block accessible */
 199     int errno;                          /* last operation's error */
 200 };
 201 
 202 
 203 /* Prototypes ******************************************************/ 
 204 
 205 /*      The following prototypes are already declared elsewhere.  They are
 206         repeated here to show what's going on.  And to sense, if they're
 207         changed elsewhere. */
 208 
 209 /* declared in blk.h */
 210 #if LINUX_VERSION_CODE < 66338
 211 unsigned long mcdx_init(unsigned long mem_start, unsigned long mem_end);
 212 #else
 213 int mcdx_init(void);
 214 #endif
 215 void do_mcdx_request(void);
 216 
 217 #if LINUX_VERSION_CODE < 66338
 218 int check_mcdx_media_change(dev_t);
 219 #else
 220 int check_mcdx_media_change(kdev_t);
 221 #endif
 222 
 223 /* already declared in init/main */
 224 void mcdx_setup(char *, int *);
 225 
 226 /*      Indirect exported functions. These functions are exported by their
 227         addresses, such as mcdx_open and mcdx_close in the 
 228         structure fops. */
 229 
 230 /* ???  exported by the mcdx_sigaction struct */
 231 static void mcdx_intr(int, struct pt_regs*);
 232 
 233 /* exported by file_ops */
 234 static int mcdx_open(struct inode*, struct file*);
 235 static void mcdx_close(struct inode*, struct file*);
 236 static int mcdx_ioctl(struct inode*, struct file*, unsigned int, unsigned long);
 237 
 238 /* misc internal support functions */
 239 static void log2msf(unsigned int, struct s_msf*);
 240 static unsigned int msf2log(const struct s_msf*);
 241 static unsigned int uint2bcd(unsigned int);
 242 static unsigned int bcd2uint(unsigned char);
 243 #if MCDX_DEBUG
 244 static void TRACE((int level, const char* fmt, ...));
 245 #endif
 246 static void warn(const char* fmt, ...);
 247 static char *port(int*);
 248 static int irq(int*);
 249 static void mcdx_delay(struct s_drive_stuff*, long jifs);
 250 static int mcdx_transfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
 251 
 252 static int mcdx_config(struct s_drive_stuff*, int);
 253 static int mcdx_closedoor(struct s_drive_stuff*, int);
 254 static int mcdx_requestversion(struct s_drive_stuff*, struct s_version*, int);
 255 static int mcdx_lockdoor(struct s_drive_stuff*, int, int);
 256 static int mcdx_stop(struct s_drive_stuff*, int);
 257 static int mcdx_hold(struct s_drive_stuff*, int);
 258 static int mcdx_reset(struct s_drive_stuff*, enum resetmodes, int);
 259 static int mcdx_eject(struct s_drive_stuff*, int);
 260 static int mcdx_setdrivemode(struct s_drive_stuff*, enum drivemodes, int);
 261 static int mcdx_setdatamode(struct s_drive_stuff*, enum datamodes, int);
 262 static int mcdx_requestsubqcode(struct s_drive_stuff*, struct s_subqcode*, int);
 263 static int mcdx_requestmultidiskinfo(struct s_drive_stuff*, struct s_multi*, int);
 264 static int mcdx_requesttocdata(struct s_drive_stuff*, struct s_diskinfo*, int);
 265 static int mcdx_getstatus(struct s_drive_stuff*, int);
 266 static int mcdx_getval(struct s_drive_stuff*, int to, int delay, char*);
 267 static int mcdx_talk(struct s_drive_stuff*, 
 268                 const unsigned char* cmd, size_t, 
 269         void *buffer, size_t size, 
 270         unsigned int timeout, int);
 271 static int mcdx_readtoc(struct s_drive_stuff*);
 272 static int mcdx_playtrk(struct s_drive_stuff*, const struct cdrom_ti*);
 273 static int mcdx_playmsf(struct s_drive_stuff*, const struct cdrom_msf*);
 274 static int mcdx_setattentuator(struct s_drive_stuff*, struct cdrom_volctrl*, int);
 275 
 276 /* static variables ************************************************/
 277 
 278 static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
 279 static struct s_drive_stuff* mcdx_stuffp[MCDX_NDRIVES];
 280 static struct s_drive_stuff* mcdx_irq_map[16] =
 281                 {0, 0, 0, 0, 0, 0, 0, 0,
 282                 0, 0, 0, 0, 0, 0, 0, 0};
 283 
 284 static struct file_operations mcdx_fops = {
 285         NULL,                   /* lseek - use kernel default */
 286         block_read,             /* read - general block-dev read */
 287         block_write,    /* write - general block-dev write */
 288         NULL,                   /* no readdir */
 289         NULL,                   /* no select */
 290         mcdx_ioctl,             /* ioctl() */
 291         NULL,                   /* no mmap */
 292         mcdx_open,              /* open() */
 293         mcdx_close,             /* close() */
 294         NULL,                   /* fsync */
 295         NULL,                   /* fasync */
 296         check_mcdx_media_change, /* media_change */
 297         NULL                    /* revalidate */
 298 };
 299 
 300 /* KERNEL INTERFACE FUNCTIONS **************************************/ 
 301 
 302 static int 
 303 mcdx_ioctl(
     /* [previous][next][first][last][top][bottom][index][help] */
 304         struct inode* ip, struct file* fp, 
 305         unsigned int cmd, unsigned long arg)
 306 { 
 307         struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
 308 
 309         if (!stuffp->present) return -ENXIO;
 310         if (!ip) return -EINVAL;
 311 
 312         switch (cmd) {
 313                 case CDROMSTART: {
 314                         TRACE((IOCTL, "ioctl() START\n"));
 315                         return 0;
 316                 }
 317 
 318                 case CDROMSTOP: {
 319                         TRACE((IOCTL, "ioctl() STOP\n"));
 320             stuffp->audiostatus = CDROM_AUDIO_INVALID;
 321                         if (-1 == mcdx_stop(stuffp, 1))
 322                                 return -EIO;
 323                         return 0;
 324                 }
 325 
 326                 case CDROMPLAYTRKIND: {
 327                         int ans;
 328                         struct cdrom_ti ti;
 329 
 330                         TRACE((IOCTL, "ioctl() PLAYTRKIND\n"));
 331                         if ((ans = verify_area(VERIFY_READ, (void*) arg, sizeof(ti))))
 332                                 return ans;
 333                         memcpy_fromfs(&ti, (void*) arg, sizeof(ti));
 334                         if ((ti.cdti_trk0 < stuffp->di.n_first)
 335                                         || (ti.cdti_trk0 > stuffp->di.n_last)
 336                                         || (ti.cdti_trk1 < stuffp->di.n_first))
 337                                 return -EINVAL;
 338                         if (ti.cdti_trk1 > stuffp->di.n_last) ti.cdti_trk1 = stuffp->di.n_last;
 339             TRACE((PLAYTRK, "ioctl() track %d to %d\n", ti.cdti_trk0, ti.cdti_trk1));
 340 
 341             return mcdx_playtrk(stuffp, &ti);
 342         }
 343 
 344         case CDROMPLAYMSF: {
 345             int ans;
 346             struct cdrom_msf msf;
 347 
 348             TRACE((IOCTL, "ioctl() PLAYMSF\n"));
 349 
 350             if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
 351                 && (-1 == mcdx_hold(stuffp, 1))) return -EIO;
 352 
 353             if ((ans = verify_area(
 354                     VERIFY_READ, (void*) arg, sizeof(struct cdrom_msf)))) 
 355                 return ans;
 356 
 357             memcpy_fromfs(&msf, (void*) arg, sizeof msf);
 358 
 359             msf.cdmsf_min0 = uint2bcd(msf.cdmsf_min0);
 360             msf.cdmsf_sec0 = uint2bcd(msf.cdmsf_sec0);
 361             msf.cdmsf_frame0 = uint2bcd(msf.cdmsf_frame0);
 362 
 363             msf.cdmsf_min1 = uint2bcd(msf.cdmsf_min1);
 364             msf.cdmsf_sec1 = uint2bcd(msf.cdmsf_sec1);
 365             msf.cdmsf_frame1 = uint2bcd(msf.cdmsf_frame1);
 366 
 367             return mcdx_playmsf(stuffp, &msf);
 368         }
 369 
 370         case CDROMRESUME: {
 371             TRACE((IOCTL, "ioctl() RESUME\n"));
 372             return mcdx_playtrk(stuffp, NULL);
 373         }
 374 
 375                 case CDROMREADTOCENTRY: {
 376                         struct cdrom_tocentry entry;
 377                         struct s_subqcode *tp = NULL;
 378                         int ans;
 379 
 380                         TRACE((IOCTL, "ioctl() READTOCENTRY\n"));
 381 
 382             if (-1 == mcdx_readtoc(stuffp)) return -1;
 383 
 384                         if ((ans = verify_area(VERIFY_READ, (void *) arg, sizeof(entry)))) return ans;
 385                         memcpy_fromfs(&entry, (void *) arg, sizeof(entry));
 386 
 387                         if (entry.cdte_track == CDROM_LEADOUT) 
 388                                 tp = &stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1];
 389                         else if (entry.cdte_track > stuffp->di.n_last 
 390                                         || entry.cdte_track < stuffp->di.n_first) return -EINVAL;
 391                         else tp = &stuffp->toc[entry.cdte_track - stuffp->di.n_first];
 392 
 393                         if (NULL == tp) WARN(("FATAL.\n"));
 394 
 395                         entry.cdte_adr = tp->control;
 396                         entry.cdte_ctrl = tp->control >> 4;
 397 
 398                         if (entry.cdte_format == CDROM_MSF) {
 399                                 entry.cdte_addr.msf.minute = bcd2uint(tp->dt.minute);
 400                                 entry.cdte_addr.msf.second = bcd2uint(tp->dt.second);
 401                                 entry.cdte_addr.msf.frame = bcd2uint(tp->dt.frame);
 402                         } else if (entry.cdte_format == CDROM_LBA)
 403                                 entry.cdte_addr.lba = msf2log(&tp->dt);
 404                         else return -EINVAL;
 405 
 406                         if ((ans = verify_area(VERIFY_WRITE, (void*) arg, sizeof(entry)))) return ans;
 407                         memcpy_tofs((void*) arg, &entry, sizeof(entry));
 408 
 409                         return 0;
 410                 }
 411 
 412                 case CDROMSUBCHNL: {
 413                         int ans;
 414                         struct cdrom_subchnl sub;
 415                         struct s_subqcode q;
 416 
 417                         TRACE((IOCTL, "ioctl() SUBCHNL\n"));
 418 
 419                         if ((ans = verify_area(VERIFY_READ, 
 420                     (void*) arg, sizeof(sub)))) return ans;
 421 
 422                         memcpy_fromfs(&sub, (void*) arg, sizeof(sub));
 423 
 424                         if (-1 == mcdx_requestsubqcode(stuffp, &q, 2)) return -EIO;
 425 
 426             TRACE((SUBCHNL, "audiostatus: %x\n", stuffp->audiostatus));
 427                         sub.cdsc_audiostatus = stuffp->audiostatus;
 428                         sub.cdsc_adr = q.control;
 429                         sub.cdsc_ctrl = q.control >> 4;
 430                         sub.cdsc_trk = bcd2uint(q.tno);
 431                         sub.cdsc_ind = bcd2uint(q.index);
 432 
 433             TRACE((SUBCHNL, "trk %d, ind %d\n", 
 434                     sub.cdsc_trk, sub.cdsc_ind));
 435 
 436                         if (sub.cdsc_format == CDROM_LBA) {
 437                                 sub.cdsc_absaddr.lba = msf2log(&q.dt);
 438                                 sub.cdsc_reladdr.lba = msf2log(&q.tt);
 439                 TRACE((SUBCHNL, "lba: abs %d, rel %d\n",
 440                     sub.cdsc_absaddr.lba,
 441                     sub.cdsc_reladdr.lba));
 442                         } else if (sub.cdsc_format == CDROM_MSF) {
 443                                 sub.cdsc_absaddr.msf.minute = bcd2uint(q.dt.minute);
 444                                 sub.cdsc_absaddr.msf.second = bcd2uint(q.dt.second);
 445                                 sub.cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
 446                                 sub.cdsc_reladdr.msf.minute = bcd2uint(q.tt.minute);
 447                                 sub.cdsc_reladdr.msf.second = bcd2uint(q.tt.second);
 448                                 sub.cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
 449                 TRACE((SUBCHNL,
 450                         "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
 451                         sub.cdsc_absaddr.msf.minute,
 452                         sub.cdsc_absaddr.msf.second,
 453                         sub.cdsc_absaddr.msf.frame,
 454                         sub.cdsc_reladdr.msf.minute,
 455                         sub.cdsc_reladdr.msf.second,
 456                         sub.cdsc_reladdr.msf.frame));
 457                         } else return -EINVAL;
 458 
 459                         if ((ans = verify_area(VERIFY_WRITE, (void*) arg, sizeof(sub))))
 460                                 return ans;
 461                         memcpy_tofs((void*) arg, &sub, sizeof(sub));
 462 
 463                         return 0;
 464                 }
 465 
 466                 case CDROMREADTOCHDR: {
 467                         struct cdrom_tochdr toc;
 468                         int ans;
 469 
 470                         TRACE((IOCTL, "ioctl() READTOCHDR\n"));
 471                         if ((ans = verify_area(VERIFY_WRITE, (void*) arg, sizeof toc)))
 472                                 return ans;
 473                         toc.cdth_trk0 = stuffp->di.n_first;
 474                         toc.cdth_trk1 = stuffp->di.n_last;
 475                         memcpy_tofs((void*) arg, &toc, sizeof toc);
 476                         TRACE((TOCHDR, "ioctl() track0 = %d, track1 = %d\n",
 477                                         stuffp->di.n_first, stuffp->di.n_last));
 478                         return 0;
 479                 }
 480 
 481                 case CDROMPAUSE: {
 482                         TRACE((IOCTL, "ioctl() PAUSE\n"));
 483                         if (stuffp->audiostatus != CDROM_AUDIO_PLAY) return -EINVAL;
 484                         if (-1 == mcdx_stop(stuffp, 1)) return -EIO;
 485             stuffp->audiostatus = CDROM_AUDIO_PAUSED;
 486                         if (-1 == mcdx_requestsubqcode(stuffp, &stuffp->start, 1))
 487                                 return -EIO;
 488                         return 0;
 489                 }
 490 
 491                 case CDROMMULTISESSION: {
 492                         int ans;
 493                         struct cdrom_multisession ms;
 494                         TRACE((IOCTL, "ioctl() MULTISESSION\n"));
 495                         if (0 != (ans = verify_area(VERIFY_READ, (void*) arg, 
 496                                         sizeof(struct cdrom_multisession))))
 497                                 return ans;
 498                                 
 499                         memcpy_fromfs(&ms, (void*) arg, sizeof(struct cdrom_multisession));
 500                         if (ms.addr_format == CDROM_MSF) {
 501                                 ms.addr.msf.minute = bcd2uint(stuffp->multi.msf_last.minute);
 502                                 ms.addr.msf.second = bcd2uint(stuffp->multi.msf_last.second);
 503                                 ms.addr.msf.frame = bcd2uint(stuffp->multi.msf_last.frame);
 504                         } else if (ms.addr_format == CDROM_LBA)
 505                                 ms.addr.lba = msf2log(&stuffp->multi.msf_last);
 506                         else
 507                                 return -EINVAL;
 508                         ms.xa_flag = stuffp->xa;
 509 
 510                         if (0 != (ans = verify_area(VERIFY_WRITE, (void*) arg,
 511                                         sizeof(struct cdrom_multisession))))
 512                                 return ans;
 513 
 514                         memcpy_tofs((void*) arg, &ms, sizeof(struct cdrom_multisession));
 515                         if (ms.addr_format == CDROM_MSF) 
 516                                 TRACE((MS, 
 517                                                 "ioctl() (%d, %02x:%02x.%02x [%02x:%02x.%02x])\n",
 518                                                 ms.xa_flag, 
 519                                                 ms.addr.msf.minute,
 520                                                 ms.addr.msf.second,
 521                                                 ms.addr.msf.frame,
 522                                                 stuffp->multi.msf_last.minute,
 523                                                 stuffp->multi.msf_last.second,
 524                                                 stuffp->multi.msf_last.frame));
 525                         else
 526                           {
 527                             TRACE((MS, 
 528                                         "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
 529                                         ms.xa_flag,
 530                                         ms.addr.lba,
 531                                         stuffp->multi.msf_last.minute,
 532                                         stuffp->multi.msf_last.second,
 533                                         stuffp->multi.msf_last.frame));
 534                           }
 535                         return 0;
 536                 }
 537 
 538                 case CDROMEJECT: {
 539                         TRACE((IOCTL, "ioctl() EJECT\n"));
 540                         if (stuffp->users > 1) return -EBUSY;
 541                         if (-1 == mcdx_eject(stuffp, 1)) return -EIO;
 542                         return 0;
 543                 }
 544 
 545         case CDROMEJECT_SW: {
 546             stuffp->eject_sw = arg;
 547             return 0;
 548         }
 549 
 550         case CDROMVOLCTRL: {
 551             int ans;
 552             struct cdrom_volctrl volctrl;
 553 
 554             TRACE((IOCTL, "ioctl() VOLCTRL\n"));
 555             if ((ans = verify_area(
 556                     VERIFY_READ, 
 557                     (void*) arg,
 558                     sizeof(volctrl))))
 559                 return ans;
 560 
 561             memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
 562             return mcdx_setattentuator(stuffp, &volctrl, 1);
 563         }
 564 
 565                 default:
 566                         WARN(("ioctl(): unknown request 0x%04x\n", cmd));
 567                 return -EINVAL;
 568         }
 569 }
 570 
 571 void do_mcdx_request()
     /* [previous][next][first][last][top][bottom][index][help] */
 572 {
 573     int dev;
 574     struct s_drive_stuff *stuffp;
 575 
 576   again:
 577 
 578         TRACE((REQUEST, "do_request()\n"));
 579 
 580 #if LINUX_VERSION_CODE < 66338
 581         if ((CURRENT == NULL) || (CURRENT->dev < 0))  {
 582 #else
 583         if ((CURRENT == NULL) || (CURRENT->rq_status == RQ_INACTIVE))  {
 584 #endif
 585                 TRACE((REQUEST, "do_request() done\n"));
 586                 return;
 587         }
 588 
 589 #if LINUX_VERSION_CODE < 66338
 590     stuffp = mcdx_stuffp[MINOR(CURRENT->dev)];
 591 #else
 592     stuffp = mcdx_stuffp[MINOR(CURRENT->rq_dev)];
 593 #endif
 594         TRACE((REQUEST, "do_request() stuffp = %p\n", stuffp));
 595 
 596     INIT_REQUEST;
 597 #if LINUX_VERSION_CODE < 66338
 598     dev = MINOR(CURRENT->dev);
 599 #else
 600     dev = MINOR(CURRENT->rq_dev);
 601 #endif
 602 
 603         if ((dev < 0) || (dev >= MCDX_NDRIVES) || (!stuffp->present)) {
 604 #if LINUX_VERSION_CODE < 66338
 605                 WARN(("do_request(): bad device: 0x%04x\n", CURRENT->dev));
 606 #else
 607                 WARN(("do_request(): bad device: %s\n", 
 608             kdevname(CURRENT->rq_dev)));
 609 #endif
 610                 end_request(0);
 611                 goto again;
 612     }
 613 
 614         if (stuffp->audio) {
 615                 WARN(("do_request() attempt to read from audio cd\n"));
 616                 end_request(0);
 617                 goto again;
 618         }
 619 
 620     switch (CURRENT->cmd) {
 621       case WRITE:
 622           WARN(("do_request(): attempt to write to cd!!\n"));
 623           end_request(0);
 624           break;
 625 
 626       case READ:
 627           stuffp->errno = 0;
 628           while (CURRENT->nr_sectors) {
 629               int i;
 630 
 631               if (-1 == (i = mcdx_transfer(
 632                                       stuffp,
 633                                       CURRENT->buffer,
 634                                       CURRENT->sector,
 635                                       CURRENT->nr_sectors))) {
 636               WARN(("do_request() read error\n"));
 637               if (stuffp->errno == MCDX_EOM) {
 638                   CURRENT->sector += CURRENT->nr_sectors;
 639                   CURRENT->nr_sectors = 0;
 640               }
 641               end_request(0);
 642               goto again;
 643               }
 644               CURRENT->sector += i;
 645               CURRENT->nr_sectors -= i;
 646               CURRENT->buffer += (i * 512);
 647 
 648           }
 649 
 650           end_request(1);
 651           break;
 652 
 653       default:
 654           panic(MCDX "do_request: unknown command.\n");
 655           break;
 656     }
 657 
 658     goto again;
 659 }
 660 
 661 static int 
 662 mcdx_open(struct inode *ip, struct file *fp)
     /* [previous][next][first][last][top][bottom][index][help] */
 663 /*  actions done on open:
 664  *  1)  get the drives status */
 665 {
 666     struct s_drive_stuff *stuffp;
 667 
 668         TRACE((OPENCLOSE, "open()\n"));
 669     stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
 670     if (!stuffp->present) return -ENXIO;
 671 
 672     /* this is only done to test if the drive talks with us */
 673     if (-1 == mcdx_getstatus(stuffp, 1)) return -EIO;
 674 
 675         /* close the door, if necessary (get the door information
 676     from the hardware status register). 
 677     If the last eject is too recent, an autoclose wouldn't probably
 678     be what we want ..., if we can't read the CD after an autoclose
 679     no further autclose's will be tried */
 680         if (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_DOOR) {
 681         if (jiffies - stuffp->ejected < ACLOSE_INHIBIT) return -EIO;
 682         if (stuffp->autoclose) mcdx_closedoor(stuffp, 1);
 683         else return -EIO;
 684     }
 685 
 686         /* if the media changed we will have to do a little more */
 687         if (stuffp->xxx < stuffp->changed) {
 688 
 689                 TRACE((OPENCLOSE, "open() media changed\n"));
 690         /* but wait - the time of media change will be set at the 
 691         very last of this block - it seems, some of the following
 692         talk() will detect a media change ... (I think, config()
 693         is the reason. */
 694 
 695         stuffp->audiostatus = CDROM_AUDIO_INVALID;
 696 
 697                 /* get the multisession information */
 698                 {
 699             int ans;
 700 
 701                         TRACE((OPENCLOSE, "open() Request multisession info\n"));
 702             ans = mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6);
 703             if (ans == -1) {
 704                 stuffp->autoclose = 0;
 705                 mcdx_eject(stuffp, 1);
 706                 return -EIO;
 707             }
 708 
 709             /* we succeeded, so on next open(2) we could try auto close
 710             again */
 711             stuffp->autoclose = 1;
 712                 
 713                         if (stuffp->multi.multi > 2)
 714                                 WARN(("open() unknown multisession value (%d)\n", stuffp->multi.multi));
 715 
 716                         /* multisession ? */
 717                         if (!stuffp->multi.multi)
 718                                 stuffp->multi.msf_last.second = 2;
 719 
 720                         TRACE((OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
 721                                         stuffp->multi.multi,
 722                                         stuffp->multi.msf_last.minute,
 723                                         stuffp->multi.msf_last.second,
 724                                         stuffp->multi.msf_last.frame));
 725                 } /* got multisession information */
 726 
 727                 /* request the disks table of contents (aka diskinfo) */
 728                 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) return -EIO;
 729 
 730                 stuffp->lastsector = (CD_FRAMESIZE / 512) 
 731                 * msf2log(&stuffp->di.msf_leadout) - 1;
 732 
 733                 TRACE((OPENCLOSE, "open() start %d (%02x:%02x.%02x) %d\n",
 734                                 stuffp->di.n_first,
 735                                 stuffp->di.msf_first.minute,
 736                                 stuffp->di.msf_first.second,
 737                                 stuffp->di.msf_first.frame,
 738                                 msf2log(&stuffp->di.msf_first)));
 739                 TRACE((OPENCLOSE, "open() last %d (%02x:%02x.%02x) %d\n",
 740                                 stuffp->di.n_last,
 741                                 stuffp->di.msf_leadout.minute,
 742                                 stuffp->di.msf_leadout.second,
 743                                 stuffp->di.msf_leadout.frame,
 744                                 msf2log(&stuffp->di.msf_leadout)));
 745 
 746                 if (stuffp->toc) {
 747                         TRACE((MALLOC, "open() free toc @ %p\n", stuffp->toc));
 748                         kfree(stuffp->toc);
 749                 }
 750                 stuffp->toc = NULL;
 751 
 752                 TRACE((OPENCLOSE, "open() init irq generation\n"));
 753                 if (-1 == mcdx_config(stuffp, 1)) return -EIO;
 754 
 755                 /* try to get the first sector ... */
 756                 {
 757                         char buf[512];
 758                         int ans;
 759                         int tries;
 760 
 761                         stuffp->xa = 0;
 762                         stuffp->audio = 0;
 763 
 764                         for (tries = 6; tries; tries--) {
 765                                 TRACE((OPENCLOSE, "open() try as %s\n",
 766                                         stuffp->xa ? "XA" : "normal"));
 767 
 768                                 /* set data mode */
 769                                 if (-1 == (ans = mcdx_setdatamode(stuffp, 
 770                                                 stuffp->xa ? MODE2 : MODE1, 1)))
 771                                         return -EIO;
 772 
 773                                 if ((stuffp->audio = e_audio(ans))) break; 
 774 
 775                                 while (0 == (ans = mcdx_transfer(stuffp, buf, 0, 1))) 
 776                                         ;
 777 
 778                                 if (ans == 1) break;
 779                                 stuffp->xa = !stuffp->xa; 
 780                         }
 781                         if (!tries) return -EIO;
 782                 }
 783 
 784                 /* xa disks will be read in raw mode, others not */
 785                 if (-1 == mcdx_setdrivemode(stuffp, 
 786                                 stuffp->xa ? RAW : COOKED, 1))
 787                         return -EIO;
 788 
 789                 if (stuffp->audio) {
 790                         INFO(("open() audio disk found\n"));
 791                 } else {
 792                         INFO(("open() %s%s disk found\n",
 793                                         stuffp->xa ? "XA / " : "",
 794                                         stuffp->multi.multi ? "Multi Session" : "Single Session"));
 795                 }
 796 
 797         stuffp->xxx = jiffies;
 798         }
 799 
 800     /* lock the door if not already done */
 801     if (0 == stuffp->users && (-1 == mcdx_lockdoor(stuffp, 1, 1))) 
 802         return -EIO;
 803 
 804     stuffp->users++;
 805     MOD_INC_USE_COUNT;
 806     return 0;
 807 }
 808 
 809 static void 
 810 mcdx_close(struct inode *ip, struct file *fp)
     /* [previous][next][first][last][top][bottom][index][help] */
 811 {
 812     struct s_drive_stuff *stuffp;
 813 
 814     TRACE((OPENCLOSE, "close()\n"));
 815 
 816     stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
 817 
 818     if (0 == --stuffp->users) {
 819                 sync_dev(ip->i_rdev);   /* needed for r/o device? */
 820 
 821                 /* invalidate_inodes(ip->i_rdev); */
 822                 invalidate_buffers(ip->i_rdev);
 823 
 824                 if (-1 == mcdx_lockdoor(stuffp, 0, 3))
 825                                 INFO(("close() Cannot unlock the door\n"));
 826 
 827         /* eject if wished */
 828         if (stuffp->eject_sw) mcdx_eject(stuffp, 1);
 829 
 830     }
 831     MOD_DEC_USE_COUNT;
 832 
 833     return;
 834 }
 835 
 836 #if LINUX_VERSION_CODE < 66338
 837 int check_mcdx_media_change(dev_t full_dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 838 #else
 839 int check_mcdx_media_change(kdev_t full_dev)
 840 #endif
 841 /*      Return: 1 if media changed since last call to 
 842                           this function
 843                         0 else
 844         Setting flag to 0 resets the changed state. */
 845 
 846 {
 847 #if LINUX_VERSION_CODE < 66338
 848     INFO(("check_mcdx_media_change called for device %x\n",
 849           full_dev));
 850 #else
 851     INFO(("check_mcdx_media_change called for device %s\n",
 852           kdevname(full_dev)));
 853 #endif
 854     return 0;
 855 }
 856 
 857 void mcdx_setup(char *str, int *pi)
     /* [previous][next][first][last][top][bottom][index][help] */
 858 {
 859 #if MCDX_DEBUG
 860     printk(MCDX ":: setup(%s, %d) called\n",
 861             str, pi[0]);
 862 #endif
 863 }
 864 
 865 /* DIRTY PART ******************************************************/ 
 866 
 867 static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
     /* [previous][next][first][last][top][bottom][index][help] */
 868 /*      This routine is used for sleeping while initialisation - it seems that
 869         there are no other means available. May be we could use a simple count
 870         loop w/ jumps to itself, but I wanna make this independend of cpu
 871         speed. [1 jiffie is 1/HZ sec */
 872 {
 873     unsigned long tout = jiffies + jifs;
 874 
 875     TRACE((INIT, "mcdx_delay %d\n", jifs));
 876     if (jifs < 0) return;
 877 
 878 #if 1
 879     while (jiffies < tout) {
 880         current->timeout = jiffies;
 881         schedule();
 882     }
 883 #else
 884     if (current->pid == 0) {        /* no sleep allowed */
 885                 while (jiffies < tout) {
 886             current->timeout = jiffies;
 887             schedule();
 888         }
 889     } else {                        /* sleeping is allowed */
 890         current->timeout = tout;
 891         current->state = TASK_INTERRUPTIBLE;
 892         while (current->timeout) {
 893             interruptible_sleep_on(&stuff->sleepq);
 894         }
 895     }
 896 #endif
 897 }
 898 
 899 static void 
 900 mcdx_intr(int irq, struct pt_regs* regs)
     /* [previous][next][first][last][top][bottom][index][help] */
 901 {
 902     struct s_drive_stuff *stuffp;
 903         unsigned char x;
 904 
 905     stuffp = mcdx_irq_map[irq];
 906 
 907     if (stuffp == NULL || !stuffp->busy) {
 908                 TRACE((IRQ, "intr() unexpected interrupt @ irq %d\n", irq));
 909                 return;
 910     }
 911 
 912         /* if not ok read the next byte as the drives status */
 913         if (0 == (stuffp->introk = 
 914                         (~(x = inb((unsigned int) stuffp->rreg_status)) & MCDX_RBIT_DTEN))) 
 915                 TRACE((IRQ, "intr() irq %d failed, status %02x %02x\n",
 916                                 irq, x, inb((unsigned int) stuffp->rreg_data)));
 917         else
 918           {
 919             TRACE((IRQ, "irq() irq %d ok, status %02x\n", irq, x));
 920 
 921           }
 922     stuffp->busy = 0;
 923     wake_up_interruptible(&stuffp->busyq);
 924 }
 925 
 926 
 927 static int 
 928 mcdx_talk (
     /* [previous][next][first][last][top][bottom][index][help] */
 929                 struct s_drive_stuff *stuffp, 
 930                 const unsigned char *cmd, size_t cmdlen,
 931                 void *buffer, size_t size, 
 932                 unsigned int timeout, int tries)
 933 /* Send a command to the drive, wait for the result.
 934  * returns -1 on timeout, drive status otherwise
 935  * If buffer is not zero, the result (length size) is stored there.
 936  * If buffer is zero the size should be the number of bytes to read
 937  * from the drive.  These bytes are discarded.
 938  */
 939 {
 940         int st;
 941     char c;
 942     int disgard;
 943 
 944     if ((disgard = (buffer == NULL))) buffer = &c;
 945 
 946     while (stuffp->lock)
 947                 interruptible_sleep_on(&stuffp->lockq);
 948 
 949     if (current->signal && ~current->blocked) {
 950         WARN(("talk() got signal %d\n", current->signal));
 951         return -1;
 952     }
 953 
 954     stuffp->lock = 1;
 955     stuffp->valid = 0;  
 956 
 957 #if MCDX_DEBUG & TALK
 958         { 
 959                 unsigned char i;
 960                 TRACE((TALK, "talk() %d / %d tries, res.size %d, command 0x%02x", 
 961                                 tries, timeout, size, (unsigned char) cmd[0]));
 962                 for (i = 1; i < cmdlen; i++) printk(" 0x%02x", cmd[i]);
 963                 printk("\n");
 964         }
 965 #endif
 966 
 967     /*  give up if all tries are done (bad) or if the status
 968      *  st != -1 (good) */
 969         for (st = -1; st == -1 && tries; tries--) {
 970 
 971         size_t sz = size;
 972         char* bp = buffer;
 973 
 974                 outsb((unsigned int) stuffp->wreg_data, cmd, cmdlen);
 975         TRACE((TALK, "talk() command sent\n"));
 976 
 977         /* get the status byte */
 978         if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
 979             INFO(("talk() %02x timed out (status), %d tr%s left\n", 
 980                     cmd[0], tries - 1, tries == 2 ? "y" : "ies"));
 981                 continue; 
 982         }
 983         st = *bp;
 984         sz--;
 985         if (!disgard) bp++;
 986 
 987         TRACE((TALK, "talk() got status 0x%02x\n", st));
 988 
 989         /* command error? */
 990         if (e_cmderr(st)) {
 991             WARN(("command error cmd = %02x %s \n", 
 992                     cmd[0], cmdlen > 1 ? "..." : ""));
 993             st = -1;
 994             continue;
 995         }
 996 
 997         /* audio status? */
 998         if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
 999             stuffp->audiostatus = 
1000                     e_audiobusy(st) ? CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS;
1001         else if (stuffp->audiostatus == CDROM_AUDIO_PLAY 
1002                 && e_audiobusy(st) == 0)
1003             stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
1004 
1005         /* media change? */
1006         if (e_changed(st)) {
1007             INFO(("talk() media changed\n"));
1008             stuffp->changed = jiffies;
1009         }
1010 
1011         /* now actually get the data */
1012         while (sz--) {
1013             if (-1 == mcdx_getval(stuffp, timeout, -1, bp)) {
1014                 INFO(("talk() %02x timed out (data), %d tr%s left\n", 
1015                         cmd[0], tries - 1, tries == 2 ? "y" : "ies"));
1016                 st = -1; break;
1017             }
1018             if (!disgard) bp++;
1019             TRACE((TALK, "talk() got 0x%02x\n", *(bp - 1)));
1020         }
1021     }
1022 
1023     if (!tries && st == -1) WARN(("talk() giving up\n"));
1024 
1025     stuffp->lock = 0;
1026     wake_up_interruptible(&stuffp->lockq);
1027 
1028         TRACE((TALK, "talk() done with 0x%02x\n", st));
1029     return st;
1030 }
1031 
1032 /* MODULE STUFF ***********************************************************/
1033 #ifdef MODULE
1034 
1035 int init_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1036 {
1037         int i;
1038         int drives = 0;
1039 
1040 #if LINUX_VERSION_CODE < 66338
1041         mcdx_init(0, 0);
1042 #else
1043         mcdx_init();
1044 #endif
1045         for (i = 0; i < MCDX_NDRIVES; i++)  {
1046                 if (mcdx_stuffp[i]) {
1047                 TRACE((INIT, "init_module() drive %d stuff @ %p\n",
1048                                 i, mcdx_stuffp[i]));
1049                         drives++;
1050                 }
1051         }
1052 
1053     if (!drives) 
1054                 return -EIO;
1055 
1056     register_symtab(0);
1057     return 0;
1058 }
1059 
1060 void cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1061 {
1062     int i;
1063 
1064         WARN(("cleanup_module called\n"));
1065         
1066     for (i = 0; i < MCDX_NDRIVES; i++) {
1067                 struct s_drive_stuff *stuffp;
1068                 stuffp = mcdx_stuffp[i];
1069                 if (!stuffp) continue;
1070                 release_region((unsigned long) stuffp->wreg_data, MCDX_IO_SIZE);
1071                 free_irq(stuffp->irq);
1072                 if (stuffp->toc) {
1073                         TRACE((MALLOC, "cleanup_module() free toc @ %p\n", stuffp->toc));
1074                         kfree(stuffp->toc);
1075                 }
1076                 TRACE((MALLOC, "cleanup_module() free stuffp @ %p\n", stuffp));
1077                 mcdx_stuffp[i] = NULL;
1078                 kfree(stuffp);
1079     }
1080 
1081     if (unregister_blkdev(MAJOR_NR, DEVICE_NAME) != 0) 
1082         WARN(("cleanup() unregister_blkdev() failed\n"));
1083     else INFO(("cleanup() succeeded\n"));
1084 }
1085 
1086 #endif MODULE
1087 
1088 /* Support functions ************************************************/
1089 
1090 #if MCDX_DEBUG
1091 void trace(int level, const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
1092 {
1093         char s[255];
1094         va_list args;
1095         if (level < 1) return;
1096         va_start(args, fmt);
1097         if (sizeof(s) < vsprintf(s, fmt, args))
1098                 printk(MCDX ":: dprintf exeeds limit!!\n");
1099         else printk(MCDX ":: %s", s);
1100         va_end(args);
1101 }
1102 #endif
1103 
1104 void warn(const char* fmt, ...)
     /* [previous][next][first][last][top][bottom][index][help] */
1105 {
1106         char s[255];
1107         va_list args;
1108         va_start(args, fmt);
1109         if (sizeof(s) < vsprintf(s, fmt, args))
1110                 printk(MCDX ":: dprintf exeeds limit!!\n");
1111         else printk(MCDX ": %s", s);
1112         va_end(args);
1113 }
1114 
1115 
1116 #if LINUX_VERSION_CODE < 66338
1117 unsigned long mcdx_init(unsigned long mem_start, unsigned long mem_end)
     /* [previous][next][first][last][top][bottom][index][help] */
1118 #else
1119 int mcdx_init(void)
1120 #endif
1121 {
1122         int drive;
1123 
1124         WARN(("Version 1.3 "
1125                         "mcdx.c,v 1.17 1995/11/06 01:07:57 heiko Exp\n"));
1126         INFO((": Version 1.3 "
1127                         "mcdx.c,v 1.17 1995/11/06 01:07:57 heiko Exp\n"));
1128 
1129         /* zero the pointer array */
1130         for (drive = 0; drive < MCDX_NDRIVES; drive++)
1131                 mcdx_stuffp[drive] = NULL;
1132 
1133         /* do the initialisation */
1134         for (drive = 0; drive < MCDX_NDRIVES; drive++) { 
1135                 struct s_version version;
1136                 struct s_drive_stuff* stuffp;
1137         int size;
1138 
1139         size = sizeof(*stuffp);
1140                 
1141                 TRACE((INIT, "init() try drive %d\n", drive));
1142 
1143 #if defined(MODULE) || LINUX_VERSION_CODE > 66338
1144         TRACE((INIT, "kmalloc space for stuffpt's\n"));
1145                 TRACE((MALLOC, "init() malloc %d bytes\n", size));
1146                 if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
1147                         WARN(("init() malloc failed\n"));
1148                         break; 
1149                 }
1150 #else
1151         TRACE((INIT, "adjust mem_start\n"));
1152         stuffp = (struct s_drive_stuff *) mem_start;
1153         mem_start += size;
1154 #endif
1155 
1156                 TRACE((INIT, "init() got %d bytes for drive stuff @ %p\n", sizeof(*stuffp), stuffp));
1157 
1158                 /* set default values */
1159                 memset(stuffp, 0, sizeof(*stuffp));
1160         stuffp->autoclose = 1;      /* close the door on open(2) */
1161 
1162                 stuffp->present = 0;            /* this should be 0 already */
1163                 stuffp->toc = NULL;                     /* this should be NULL already */
1164                 stuffp->changed = jiffies;
1165 
1166                 /* setup our irq and i/o addresses */
1167                 stuffp->irq = irq(mcdx_drive_map[drive]);
1168                 stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]);
1169                 stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
1170                 stuffp->wreg_hcon = stuffp->wreg_reset + 1;
1171                 stuffp->wreg_chn = stuffp->wreg_hcon + 1;
1172 
1173                 /* check if i/o addresses are available */
1174                 if (0 != check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) {
1175             WARN(("%s=0x%3p,%d: "
1176                     "Init failed. I/O ports (0x%3p..0x3p) already in use.\n"
1177                     MCDX, 
1178                     stuffp->wreg_data, stuffp->irq,
1179                     stuffp->wreg_data, 
1180                     stuffp->wreg_data + MCDX_IO_SIZE - 1));
1181                         TRACE((MALLOC, "init() free stuffp @ %p\n", stuffp));
1182             kfree(stuffp);
1183                         TRACE((INIT, "init() continue at next drive\n"));
1184                         continue; /* next drive */
1185                 }
1186 
1187                 TRACE((INIT, "init() i/o port is available at 0x%3p\n", stuffp->wreg_data));
1188 
1189                 TRACE((INIT, "init() hardware reset\n"));
1190                 mcdx_reset(stuffp, HARD, 1);
1191 
1192                 TRACE((INIT, "init() get version\n"));
1193                 if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
1194                         /* failed, next drive */
1195             WARN(("%s=0x%3p,%d: Init failed. Can't get version.\n",
1196                     MCDX,
1197                     stuffp->wreg_data, stuffp->irq));
1198                         TRACE((MALLOC, "init() free stuffp @ %p\n", stuffp));
1199             kfree(stuffp);
1200                         TRACE((INIT, "init() continue at next drive\n"));
1201                         continue;
1202                 }
1203 
1204                 switch (version.code) {
1205                 case 'D': 
1206                 stuffp->readcmd = READDSPEED; 
1207                 stuffp->present = DOUBLE | DOOR | MULTI; 
1208                 break;
1209                 case 'F': 
1210                 stuffp->readcmd = READSSPEED; 
1211                 stuffp->present = SINGLE | DOOR | MULTI;
1212                 break;
1213                 case 'M': 
1214                 stuffp->readcmd = READSSPEED;
1215                 stuffp->present = SINGLE;
1216                 break;
1217                 default: 
1218                 stuffp->present = 0; break;
1219                 }
1220 
1221         stuffp->playcmd = READSSPEED;
1222 
1223 
1224                 if (!stuffp->present) {
1225             WARN(("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n",
1226                     MCDX, stuffp->wreg_data, stuffp->irq));
1227                         kfree(stuffp);
1228                         continue; /* next drive */
1229                 }
1230 
1231                 TRACE((INIT, "init() register blkdev\n"));
1232                 if (register_blkdev(MAJOR_NR, DEVICE_NAME, &mcdx_fops) != 0) {
1233             WARN(("%s=0x%3p,%d: Init failed. Can't get major %d.\n",
1234                     MCDX,
1235                     stuffp->wreg_data, stuffp->irq, MAJOR_NR));
1236                         kfree(stuffp);
1237                         continue; /* next drive */
1238                 }
1239 
1240                 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1241                 read_ahead[MAJOR_NR] = READ_AHEAD;
1242 
1243 #if WE_KNOW_WHY
1244                  blksize_size[MAJOR_NR] = BLKSIZES;
1245 #endif
1246 
1247                 TRACE((INIT, "init() subscribe irq and i/o\n"));
1248                 mcdx_irq_map[stuffp->irq] = stuffp;
1249                 if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, DEVICE_NAME)) {
1250             WARN(("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n",
1251                     MCDX,
1252                     stuffp->wreg_data, stuffp->irq, stuffp->irq));
1253                         stuffp->irq = 0;
1254                         kfree(stuffp);
1255                         continue;
1256                 }
1257                 request_region((unsigned int) stuffp->wreg_data, 
1258                 MCDX_IO_SIZE, 
1259                 DEVICE_NAME); 
1260 
1261                 TRACE((INIT, "init() get garbage\n"));
1262                 {
1263                         int i;
1264                         mcdx_delay(stuffp, HZ/2);
1265                         for (i = 100; i; i--) (void) inb((unsigned int) stuffp->rreg_status);
1266                 }
1267 
1268 
1269 #if WE_KNOW_WHY
1270                         outb(0x50, (unsigned int) stuffp->wreg_chn);    /* irq 11 -> channel register */
1271 #endif
1272 
1273                 TRACE((INIT, "init() set non dma but irq mode\n"));
1274                 mcdx_config(stuffp, 1);
1275 
1276                 stuffp->minor = drive;
1277 
1278                 WARN((DEVICE_NAME " installed at 0x%3p, irq %d."
1279                            " (Firmware version %c %x)\n",
1280                            stuffp->wreg_data, stuffp->irq, version.code,
1281                version.ver));
1282                 mcdx_stuffp[drive] = stuffp;
1283                 TRACE((INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp));
1284         }
1285 
1286 #if MODULE || LINUX_VERSION_CODE > 66338
1287         return 0;
1288 #else
1289         return mem_start;
1290 #endif
1291 }
1292 
1293 
1294 static int mcdx_transfer(struct s_drive_stuff *stuffp,
     /* [previous][next][first][last][top][bottom][index][help] */
1295                 char *p, int sector, int nr_sectors)
1296 /*      This does actually the transfer from the drive.
1297         Return: -1 on timeout or other error
1298                         else status byte (as in stuff->st) */
1299 {
1300     int off;
1301     int done = 0;
1302 
1303         TRACE((TRANSFER, "transfer() %d sectors at sector %d\n",
1304                         nr_sectors, sector));
1305 
1306         if (stuffp->audio) {
1307                 WARN(("attempt to read from audio cd\n"));
1308                 return -1;
1309         }
1310 
1311     while (stuffp->lock)
1312                 interruptible_sleep_on(&stuffp->lockq);
1313     if (current->signal && ~current->blocked) {
1314         WARN(("talk() got signal %d\n", current->signal));
1315     }
1316 
1317     if (stuffp->valid
1318                         && (sector >= stuffp->pending)
1319                         && (sector < stuffp->off_direct)) {
1320 
1321 
1322         off = stuffp->off_requested < (off = sector + nr_sectors)
1323                         ? stuffp->off_requested : off;
1324 
1325         stuffp->lock = current->pid;
1326 
1327         do {
1328             int sig = 0;
1329             int to = 0;
1330 
1331                 /* wait for the drive become idle */
1332             current->timeout = jiffies + 5*HZ;
1333             while (stuffp->busy) {
1334                         interruptible_sleep_on(&stuffp->busyq);
1335                 }
1336 
1337             current->timeout = 0;
1338 
1339                 /* test for possible errors */
1340             if (((stuffp->busy == 0) && !stuffp->introk)
1341                                 || to) {
1342                         if ((stuffp->busy == 0) && !stuffp->introk)
1343                 WARN(("mcdx_transfer() failure in data request\n"));
1344                         else if (to)
1345                 WARN(("mcdx_transfer(): timeout\n"));
1346                         stuffp->lock = 0;
1347                         stuffp->busy = 0;
1348                         wake_up_interruptible(&stuffp->lockq);
1349                         wake_up_interruptible(&stuffp->busyq);
1350                         stuffp->errno = MCDX_E;
1351                         TRACE((TRANSFER, "transfer() done (-1)\n"));
1352                         return -1;
1353             }
1354 
1355                 /* test if it's the first sector of a block,
1356                  * there we have to skip some bytes as we read raw data */
1357                 if (stuffp->xa && (0 == (stuffp->pending & 3))) {
1358                         const int HEAD = CD_FRAMESIZE_RAW - CD_XA_TAIL - CD_FRAMESIZE;
1359                         TRACE((TRANSFER, "transfer() sector %d, skip %d header bytes\n",
1360                                 stuffp->pending, HEAD));
1361                         insb((unsigned int) stuffp->rreg_data, p, HEAD);
1362                 }
1363 
1364                 /* now actually read the data */
1365 
1366                 TRACE((TRANSFER, "transfer() read sector %d\n", stuffp->pending));
1367             insb((unsigned int) stuffp->rreg_data, p, 512); 
1368 
1369                 /* test if it's the last sector of a block,
1370                  * if so, we have to expect an interrupt and to skip some
1371                  * data too */
1372                 if ((stuffp->busy = (3 == (stuffp->pending & 3))) && stuffp->xa) {
1373                         char dummy[CD_XA_TAIL];
1374                         TRACE((TRANSFER, "transfer() sector %d, skip %d trailer bytes\n",
1375                                         stuffp->pending, CD_XA_TAIL));
1376                         insb((unsigned int) stuffp->rreg_data, &dummy[0], CD_XA_TAIL);
1377                 }
1378 
1379             if (stuffp->pending == sector) {
1380                         p += 512;
1381                         done++;
1382                         sector++;
1383             }
1384         }
1385         while (++(stuffp->pending) < off);
1386 
1387         stuffp->lock = 0;
1388         wake_up_interruptible(&stuffp->lockq);
1389 
1390     } else {
1391 
1392                 static unsigned char cmd[] = {
1393                         0,
1394                         0, 0, 0,
1395                         0, 0, 0
1396                 };
1397 
1398                 cmd[0] = stuffp->readcmd;
1399 
1400                 stuffp->valid = 1;
1401                 stuffp->pending = sector & ~3;
1402 
1403                 /* do some sanity checks */
1404                 TRACE((TRANSFER, "transfer() request sector %d\n", stuffp->pending));
1405                 if (stuffp->pending > stuffp->lastsector) {
1406                         WARN(("transfer() sector %d from nirvana requested.\n",
1407                                 stuffp->pending));
1408                         stuffp->errno = MCDX_EOM;
1409                         TRACE((TRANSFER, "transfer() done (-1)\n"));
1410                         return -1;
1411                 }
1412 
1413                 if ((stuffp->off_direct = stuffp->pending + DIRECT_SIZE)
1414                         > stuffp->lastsector + 1)
1415                         stuffp->off_direct = stuffp->lastsector + 1;
1416                 if ((stuffp->off_requested = stuffp->pending + REQUEST_SIZE)
1417                         > stuffp->lastsector + 1)
1418                         stuffp->off_requested = stuffp->lastsector + 1;
1419 
1420                 TRACE((TRANSFER, "transfer() pending %d\n", stuffp->pending));
1421                 TRACE((TRANSFER, "transfer() off_dir %d\n", stuffp->off_direct));
1422                 TRACE((TRANSFER, "transfer() off_req %d\n", stuffp->off_requested));
1423 
1424                 {
1425                         struct s_msf pending;
1426                         log2msf(stuffp->pending / 4, &pending);
1427                         cmd[1] = pending.minute;
1428                         cmd[2] = pending.second;
1429                         cmd[3] = pending.frame;
1430                 }
1431 
1432                 stuffp->busy = 1;
1433                 cmd[6] = (unsigned char) (stuffp->off_requested - stuffp->pending) / 4;
1434 
1435                 outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
1436 
1437     }
1438 
1439     stuffp->off_direct = (stuffp->off_direct += done) < stuffp->off_requested
1440             ? stuffp->off_direct : stuffp->off_requested;
1441 
1442         TRACE((TRANSFER, "transfer() done (%d)\n", done));
1443     return done;
1444 }
1445 
1446 
1447 /*      Access to elements of the mcdx_drive_map members */
1448 
1449 static char* port(int *ip) { return (char*) ip[0]; }
     /* [previous][next][first][last][top][bottom][index][help] */
1450 static int irq(int *ip) { return ip[1]; }
     /* [previous][next][first][last][top][bottom][index][help] */
1451 
1452 /*      Misc number converters */
1453 
1454 static unsigned int bcd2uint(unsigned char c)
     /* [previous][next][first][last][top][bottom][index][help] */
1455 { return (c >> 4) * 10 + (c & 0x0f); }
1456 
1457 static unsigned int uint2bcd(unsigned int ival)
     /* [previous][next][first][last][top][bottom][index][help] */
1458 { return ((ival / 10) << 4) | (ival % 10); }
1459 
1460 static void log2msf(unsigned int l, struct s_msf* pmsf)
     /* [previous][next][first][last][top][bottom][index][help] */
1461 {
1462     l += CD_BLOCK_OFFSET;
1463     pmsf->minute = uint2bcd(l / 4500), l %= 4500;
1464     pmsf->second = uint2bcd(l / 75);
1465     pmsf->frame = uint2bcd(l % 75);
1466 }
1467 
1468 static unsigned int msf2log(const struct s_msf* pmsf)
     /* [previous][next][first][last][top][bottom][index][help] */
1469 {
1470     return bcd2uint(pmsf->frame)
1471     + bcd2uint(pmsf->second) * 75
1472     + bcd2uint(pmsf->minute) * 4500
1473     - CD_BLOCK_OFFSET;
1474 }
1475         
1476 int mcdx_readtoc(struct s_drive_stuff* stuffp)
     /* [previous][next][first][last][top][bottom][index][help] */
1477 /*  Read the toc entries from the CD,
1478  *  Return: -1 on failure, else 0 */
1479 {
1480 
1481         if (stuffp->toc) {
1482                 TRACE((READTOC, "ioctl() toc already read\n"));
1483                 return 0;
1484         }
1485 
1486         TRACE((READTOC, "ioctl() readtoc for %d tracks\n",
1487                         stuffp->di.n_last - stuffp->di.n_first + 1));
1488 
1489     if (-1 == mcdx_hold(stuffp, 1)) return -1;
1490 
1491         TRACE((READTOC, "ioctl() tocmode\n"));
1492         if (-1 == mcdx_setdrivemode(stuffp, TOC, 1)) return -EIO;
1493 
1494         /* all seems to be ok so far ... malloc */
1495         {
1496                 int size;
1497                 size = sizeof(struct s_subqcode) * (stuffp->di.n_last - stuffp->di.n_first + 2);
1498 
1499                 TRACE((MALLOC, "ioctl() malloc %d bytes\n", size));
1500                 stuffp->toc = kmalloc(size, GFP_KERNEL);
1501                 if (!stuffp->toc) {
1502                         WARN(("Cannot malloc %s bytes for toc\n", size));
1503                         mcdx_setdrivemode(stuffp, DATA, 1);
1504                         return -EIO;
1505                 }
1506         }
1507 
1508         /* now read actually the index */
1509         {
1510                 int trk;
1511                 int retries;
1512 
1513                 for (trk = 0; 
1514                                 trk < (stuffp->di.n_last - stuffp->di.n_first + 1); 
1515                                 trk++)
1516                         stuffp->toc[trk].index = 0;
1517 
1518                 for (retries = 300; retries; retries--) { /* why 300? */
1519                         struct s_subqcode q;
1520                         unsigned int idx;
1521                 
1522                         if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
1523                                 mcdx_setdrivemode(stuffp, DATA, 1);
1524                                 return -EIO;
1525                         }
1526 
1527                         idx = bcd2uint(q.index);
1528 
1529                         if ((idx > 0) 
1530                                         && (idx <= stuffp->di.n_last) 
1531                                         && (q.tno == 0)
1532                                         && (stuffp->toc[idx - stuffp->di.n_first].index == 0)) {
1533                                 stuffp->toc[idx - stuffp->di.n_first] = q;
1534                                 TRACE((READTOC, "ioctl() toc idx %d (trk %d)\n", idx, trk));
1535                                 trk--;
1536                         }
1537                         if (trk == 0) break;
1538                 }
1539                 memset(&stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1], 
1540                                 0, sizeof(stuffp->toc[0]));
1541                 stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1].dt
1542                                 = stuffp->di.msf_leadout;
1543         }
1544 
1545         /* unset toc mode */
1546         TRACE((READTOC, "ioctl() undo toc mode\n"));
1547         if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
1548                 return -EIO;
1549 
1550 #if MCDX_DEBUG && READTOC
1551         { int trk;
1552         for (trk = 0; 
1553                         trk < (stuffp->di.n_last - stuffp->di.n_first + 2); 
1554                         trk++)
1555                 TRACE((READTOC, "ioctl() %d readtoc %02x %02x %02x"
1556                                 "  %02x:%02x.%02x  %02x:%02x.%02x\n",
1557                                 trk + stuffp->di.n_first,
1558                                 stuffp->toc[trk].control, stuffp->toc[trk].tno, stuffp->toc[trk].index,
1559                                 stuffp->toc[trk].tt.minute, stuffp->toc[trk].tt.second, stuffp->toc[trk].tt.frame,
1560                                 stuffp->toc[trk].dt.minute, stuffp->toc[trk].dt.second, stuffp->toc[trk].dt.frame));
1561         }
1562 #endif
1563 
1564         return 0;
1565 }
1566 
1567 static int
1568 mcdx_playmsf(struct s_drive_stuff* stuffp, const struct cdrom_msf* msf)
     /* [previous][next][first][last][top][bottom][index][help] */
1569 {
1570     unsigned char cmd[7] = {
1571         0, 0, 0, 0, 0, 0, 0
1572     };
1573 
1574     cmd[0] = stuffp->playcmd;
1575     
1576     cmd[1] = msf->cdmsf_min0;
1577     cmd[2] = msf->cdmsf_sec0;
1578     cmd[3] = msf->cdmsf_frame0;
1579     cmd[4] = msf->cdmsf_min1;
1580     cmd[5] = msf->cdmsf_sec1;
1581     cmd[6] = msf->cdmsf_frame1;
1582 
1583     TRACE((PLAYMSF, "ioctl(): play %x "
1584             "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1585             cmd[0], cmd[1], cmd[2], cmd[3],
1586             cmd[4], cmd[5], cmd[6])); 
1587 
1588     outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
1589 
1590     if (-1 == mcdx_getval(stuffp, 3*HZ, 0, NULL)) {
1591         WARN(("playmsf() timeout\n")); 
1592         return -1;
1593     }
1594 
1595     stuffp->audiostatus = CDROM_AUDIO_PLAY;
1596     return 0;
1597 }
1598 
1599 static int 
1600 mcdx_playtrk(struct s_drive_stuff* stuffp, const struct cdrom_ti* ti)
     /* [previous][next][first][last][top][bottom][index][help] */
1601 {
1602     struct s_subqcode* p;
1603     struct cdrom_msf msf;
1604 
1605     if (-1 == mcdx_readtoc(stuffp)) return -1;
1606 
1607     if (ti) p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
1608     else p = &stuffp->start;
1609 
1610     msf.cdmsf_min0 = p->dt.minute;
1611     msf.cdmsf_sec0 = p->dt.second;
1612     msf.cdmsf_frame0 = p->dt.frame;
1613 
1614     if (ti) {
1615         p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
1616         stuffp->stop = *p;
1617     } else p = &stuffp->stop;
1618 
1619     msf.cdmsf_min1 = p->dt.minute;
1620     msf.cdmsf_sec1 = p->dt.second;
1621     msf.cdmsf_frame1 = p->dt.frame;
1622 
1623     return mcdx_playmsf(stuffp, &msf);
1624 }
1625 
1626 
1627 /* Drive functions ************************************************/
1628 
1629 static int 
1630 mcdx_closedoor(struct s_drive_stuff *stuffp, int tries)
     /* [previous][next][first][last][top][bottom][index][help] */
1631 {
1632         if (stuffp->present & DOOR)
1633                 return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5*HZ, tries);
1634         else
1635                 return 0;
1636 }
1637 
1638 static int 
1639 mcdx_stop(struct s_drive_stuff *stuffp, int tries)
     /* [previous][next][first][last][top][bottom][index][help] */
1640 { return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2*HZ, tries); }
1641 
1642 static int
1643 mcdx_hold(struct s_drive_stuff *stuffp, int tries)
     /* [previous][next][first][last][top][bottom][index][help] */
1644 { return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2*HZ, tries); }
1645 
1646 static int
1647 mcdx_eject(struct s_drive_stuff *stuffp, int tries)
     /* [previous][next][first][last][top][bottom][index][help] */
1648 {
1649         if (stuffp->present & DOOR) {
1650         stuffp->ejected = jiffies;
1651                 return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5*HZ, tries);
1652     } else return 0;
1653 }
1654 
1655 static int
1656 mcdx_requestsubqcode(struct s_drive_stuff *stuffp, 
     /* [previous][next][first][last][top][bottom][index][help] */
1657         struct s_subqcode *sub, 
1658         int tries)
1659 {
1660         char buf[11];
1661         int ans;
1662 
1663         if (-1 == (ans = mcdx_talk(
1664             stuffp, "\x20", 1, buf, sizeof(buf),
1665             2*HZ, tries))) 
1666         return -1;
1667         sub->control = buf[1];
1668         sub->tno = buf[2];
1669         sub->index = buf[3];
1670         sub->tt.minute = buf[4];
1671         sub->tt.second = buf[5];
1672         sub->tt.frame = buf[6];
1673         sub->dt.minute = buf[8];
1674         sub->dt.second = buf[9];
1675         sub->dt.frame = buf[10];
1676 
1677         return ans;
1678 }
1679 
1680 static int
1681 mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp, struct s_multi *multi, int tries)
     /* [previous][next][first][last][top][bottom][index][help] */
1682 {
1683         char buf[5];
1684         int ans;
1685 
1686     if (stuffp->present & MULTI) {
1687         ans = mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2*HZ, tries);
1688         multi->multi = buf[1];
1689         multi->msf_last.minute = buf[2];
1690         multi->msf_last.second = buf[3];
1691         multi->msf_last.frame = buf[4];
1692         return ans;
1693     } else {
1694         multi->multi = 0;
1695         return 0;
1696     }
1697 }
1698 
1699 static int 
1700 mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info, int tries)
     /* [previous][next][first][last][top][bottom][index][help] */
1701 {
1702         char buf[9];
1703         int ans;
1704         ans = mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2*HZ, tries);
1705         info->n_first = bcd2uint(buf[1]);
1706         info->n_last = bcd2uint(buf[2]);
1707         info->msf_leadout.minute = buf[3];
1708         info->msf_leadout.second = buf[4];
1709         info->msf_leadout.frame = buf[5];
1710         info->msf_first.minute = buf[6];
1711         info->msf_first.second = buf[7];
1712         info->msf_first.frame = buf[8];
1713         return ans;
1714 }
1715 
1716 static int
1717 mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode, int tries)
     /* [previous][next][first][last][top][bottom][index][help] */
1718 {
1719         char cmd[2];
1720         int ans;
1721 
1722         TRACE((HW, "setdrivemode() %d\n", mode));
1723 
1724         if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5*HZ, tries)))
1725                 return -1;
1726 
1727         switch (mode) {
1728           case TOC: cmd[1] |= 0x04; break;
1729           case DATA: cmd[1] &= ~0x04; break;
1730           case RAW: cmd[1] |= 0x40; break;
1731           case COOKED: cmd[1] &= ~0x40; break;
1732           default: break;
1733         }
1734         cmd[0] = 0x50;
1735         return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5*HZ, tries);
1736 }
1737 
1738 
1739 static int
1740 mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode, int tries)
     /* [previous][next][first][last][top][bottom][index][help] */
1741 {
1742         unsigned char cmd[2] = { 0xa0 };
1743         TRACE((HW, "setdatamode() %d\n", mode));
1744         switch (mode) {
1745           case MODE0: cmd[1] = 0x00; break;
1746           case MODE1: cmd[1] = 0x01; break;
1747           case MODE2: cmd[1] = 0x02; break;
1748           default: return -EINVAL;
1749         }
1750         return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5*HZ, tries);
1751 }
1752 
1753 static int
1754 mcdx_config(struct s_drive_stuff *stuffp, int tries)
     /* [previous][next][first][last][top][bottom][index][help] */
1755 {
1756         char cmd[4];
1757 
1758         TRACE((HW, "config()\n"));
1759 
1760         cmd[0] = 0x90;
1761 
1762         cmd[1] = 0x10;          /* irq enable */
1763         cmd[2] = 0x05;          /* pre, err irq enable */
1764 
1765         if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1*HZ, tries))
1766                 return -1;
1767 
1768         cmd[1] = 0x02;          /* dma select */
1769         cmd[2] = 0x00;          /* no dma */
1770 
1771         return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1*HZ, tries);
1772 }
1773 
1774 static int
1775 mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver, int tries)
     /* [previous][next][first][last][top][bottom][index][help] */
1776 {
1777         char buf[3];
1778         int ans;
1779 
1780         if (-1 == (ans = mcdx_talk(stuffp, "\xdc", 1, buf, sizeof(buf), 2*HZ, tries)))
1781                 return ans;
1782 
1783         ver->code = buf[1];
1784         ver->ver = buf[2];
1785 
1786         return ans;
1787 }
1788 
1789 static int
1790 mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
     /* [previous][next][first][last][top][bottom][index][help] */
1791 { 
1792         if (mode == HARD) {
1793                 outb(0, (unsigned int) stuffp->wreg_chn);               /* no dma, no irq -> hardware */
1794                 outb(0, (unsigned int) stuffp->wreg_reset);             /* hw reset */
1795                 return 0;
1796         } else return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5*HZ, tries);
1797 }
1798 
1799 static int
1800 mcdx_lockdoor(struct s_drive_stuff *stuffp, int lock, int tries)
     /* [previous][next][first][last][top][bottom][index][help] */
1801 {
1802         char cmd[2] = { 0xfe };
1803     if (stuffp->present & DOOR) {
1804         cmd[1] = lock ? 0x01 : 0x00;
1805         return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5*HZ, tries);
1806     } else 
1807         return 0;
1808 }
1809 
1810 static int
1811 mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
     /* [previous][next][first][last][top][bottom][index][help] */
1812 { return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5*HZ, tries); }
1813 
1814 static int
1815 mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char* buf)
     /* [previous][next][first][last][top][bottom][index][help] */
1816 {
1817     unsigned long timeout = to + jiffies;
1818     char c;
1819 
1820     if (!buf) buf = &c;
1821 
1822     while (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_STEN) {
1823         if (jiffies > timeout) return -1;
1824         mcdx_delay(stuffp, delay);
1825     }
1826 
1827     *buf = (unsigned char) inb((unsigned int) stuffp->rreg_data) & 0xff;
1828 
1829     return 0;
1830 }
1831 
1832 static int
1833 mcdx_setattentuator(
     /* [previous][next][first][last][top][bottom][index][help] */
1834         struct s_drive_stuff* stuffp, 
1835         struct cdrom_volctrl* vol, 
1836         int tries)
1837 {
1838     char cmd[5];
1839     cmd[0] = 0xae;
1840     cmd[1] = vol->channel0;
1841     cmd[2] = 0;
1842     cmd[3] = vol->channel1;
1843     cmd[4] = 0;
1844 
1845     return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
1846 }
1847 

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