root/drivers/block/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

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

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