ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / cdrom / mcd.c
1 /*
2         linux/kernel/blk_drv/mcd.c - Mitsumi CDROM driver
3
4         Copyright (C) 1992  Martin Harriss
5         Portions Copyright (C) 2001 Red Hat
6
7         martin@bdsi.com (no longer valid - where are you now, Martin?)
8
9         This program is free software; you can redistribute it and/or modify
10         it under the terms of the GNU General Public License as published by
11         the Free Software Foundation; either version 2, or (at your option)
12         any later version.
13
14         This program is distributed in the hope that it will be useful,
15         but WITHOUT ANY WARRANTY; without even the implied warranty of
16         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17         GNU General Public License for more details.
18
19         You should have received a copy of the GNU General Public License
20         along with this program; if not, write to the Free Software
21         Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22
23         HISTORY
24
25         0.1     First attempt - internal use only
26         0.2     Cleaned up delays and use of timer - alpha release
27         0.3     Audio support added
28         0.3.1 Changes for mitsumi CRMC LU005S march version
29                    (stud11@cc4.kuleuven.ac.be)
30         0.3.2 bug fixes to the ioctls and merged with ALPHA0.99-pl12
31                    (Jon Tombs <jon@robots.ox.ac.uk>)
32         0.3.3 Added more #defines and mcd_setup()
33                    (Jon Tombs <jon@gtex02.us.es>)
34
35         October 1993 Bernd Huebner and Ruediger Helsch, Unifix Software GmbH,
36         Braunschweig, Germany: rework to speed up data read operation.
37         Also enabled definition of irq and address from bootstrap, using the
38         environment.
39         November 93 added code for FX001 S,D (single & double speed).
40         February 94 added code for broken M 5/6 series of 16-bit single speed.
41
42
43         0.4   
44         Added support for loadable MODULEs, so mcd can now also be loaded by 
45         insmod and removed by rmmod during runtime.
46         Werner Zimmermann (zimmerma@rz.fht-esslingen.de), Mar. 26, 95
47
48         0.5
49         I added code for FX001 D to drop from double speed to single speed 
50         when encountering errors... this helps with some "problematic" CD's
51         that are supposedly "OUT OF TOLERANCE" (but are really shitty presses!)
52         severely scratched, or possibly slightly warped! I have noticed that
53         the Mitsumi 2x/4x drives are just less tolerant and the firmware is 
54         not smart enough to drop speed, so let's just kludge it with software!
55         ****** THE 4X SPEED MITSUMI DRIVES HAVE THE SAME PROBLEM!!!!!! ******
56         Anyone want to "DONATE" one to me?! ;) I hear sometimes they are
57         even WORSE! ;)
58         ** HINT... HINT... TAKE NOTES MITSUMI This could save some hassles with
59         certain "large" CD's that have data on the outside edge in your 
60         DOS DRIVERS .... Accuracy counts... speed is secondary ;)
61         17 June 95 Modifications By Andrew J. Kroll <ag784@freenet.buffalo.edu>
62         07 July 1995 Modifications by Andrew J. Kroll
63
64         Bjorn Ekwall <bj0rn@blox.se> added unregister_blkdev to mcd_init()
65
66         Michael K. Johnson <johnsonm@redhat.com> added retries on open
67         for slow drives which take a while to recognize that they contain
68         a CD.
69
70         November 1997 -- ported to the Uniform CD-ROM driver by Erik Andersen.
71         March    1999 -- made io base and irq CONFIG_ options (Tigran Aivazian).
72         
73         November 1999 -- Make kernel-parameter implementation work with 2.3.x 
74                          Removed init_module & cleanup_module in favor of 
75                          module_init & module_exit.
76                          Torben Mathiasen <tmm@image.dk>
77                 
78         September 2001 - Reformatted and cleaned up the code
79                          Alan Cox <alan@redhat.com>                      
80 */
81
82 #include <linux/module.h>
83
84 #include <linux/errno.h>
85 #include <linux/interrupt.h>
86 #include <linux/signal.h>
87 #include <linux/mm.h>
88 #include <linux/timer.h>
89 #include <linux/fs.h>
90 #include <linux/kernel.h>
91 #include <linux/devfs_fs_kernel.h>
92 #include <linux/cdrom.h>
93 #include <linux/ioport.h>
94 #include <linux/string.h>
95 #include <linux/delay.h>
96 #include <linux/init.h>
97 #include <linux/config.h>
98
99 /* #define REALLY_SLOW_IO  */
100 #include <asm/system.h>
101 #include <asm/io.h>
102 #include <asm/current.h>
103 #include <asm/uaccess.h>
104 #include <linux/blkdev.h>
105
106 #define mcd_port mcd            /* for compatible parameter passing with "insmod" */
107 #include "mcd.h"
108
109 /* I added A flag to drop to 1x speed if too many errors 0 = 1X ; 1 = 2X */
110 static int mcdDouble;
111
112 /* How many sectors to hold at 1x speed counter */
113 static int mcd1xhold;
114
115 /* Is the drive connected properly and responding?? */
116 static int mcdPresent;
117 static struct request_queue *mcd_queue;
118
119 #define MAJOR_NR MITSUMI_CDROM_MAJOR
120 #define QUEUE (mcd_queue)
121 #define CURRENT elv_next_request(mcd_queue)
122
123 #define QUICK_LOOP_DELAY udelay(45)     /* use udelay */
124 #define QUICK_LOOP_COUNT 20
125
126 static int current_valid(void)
127 {
128         return CURRENT &&
129                 CURRENT->cmd == READ &&
130                 CURRENT->sector != -1;
131 }
132
133 #define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA)
134 #define MCD_BUF_SIZ 16
135 static volatile int mcd_transfer_is_active;
136 static char mcd_buf[2048 * MCD_BUF_SIZ];        /* buffer for block size conversion */
137 static volatile int mcd_buf_bn[MCD_BUF_SIZ], mcd_next_bn;
138 static volatile int mcd_buf_in, mcd_buf_out = -1;
139 static volatile int mcd_error;
140 static int mcd_open_count;
141 enum mcd_state_e {
142         MCD_S_IDLE,             /* 0 */
143         MCD_S_START,            /* 1 */
144         MCD_S_MODE,             /* 2 */
145         MCD_S_READ,             /* 3 */
146         MCD_S_DATA,             /* 4 */
147         MCD_S_STOP,             /* 5 */
148         MCD_S_STOPPING          /* 6 */
149 };
150 static volatile enum mcd_state_e mcd_state = MCD_S_IDLE;
151 static int mcd_mode = -1;
152 static int MCMD_DATA_READ = MCMD_PLAY_READ;
153
154 #define READ_TIMEOUT 3000
155
156 int mitsumi_bug_93_wait;
157
158 static short mcd_port = CONFIG_MCD_BASE;        /* used as "mcd" by "insmod" */
159 static int mcd_irq = CONFIG_MCD_IRQ;    /* must directly follow mcd_port */
160 MODULE_PARM(mcd, "1-2i");
161
162 static int McdTimeout, McdTries;
163 static DECLARE_WAIT_QUEUE_HEAD(mcd_waitq);
164
165 static struct mcd_DiskInfo DiskInfo;
166 static struct mcd_Toc Toc[MAX_TRACKS];
167 static struct mcd_Play_msf mcd_Play;
168
169 static int audioStatus;
170 static char mcdDiskChanged;
171 static char tocUpToDate;
172 static char mcdVersion;
173
174 static void mcd_transfer(void);
175 static void mcd_poll(unsigned long dummy);
176 static void mcd_invalidate_buffers(void);
177 static void hsg2msf(long hsg, struct msf *msf);
178 static void bin2bcd(unsigned char *p);
179 static int bcd2bin(unsigned char bcd);
180 static int mcdStatus(void);
181 static void sendMcdCmd(int cmd, struct mcd_Play_msf *params);
182 static int getMcdStatus(int timeout);
183 static int GetQChannelInfo(struct mcd_Toc *qp);
184 static int updateToc(void);
185 static int GetDiskInfo(void);
186 static int GetToc(void);
187 static int getValue(unsigned char *result);
188 static int mcd_open(struct cdrom_device_info *cdi, int purpose);
189 static void mcd_release(struct cdrom_device_info *cdi);
190 static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr);
191 static int mcd_tray_move(struct cdrom_device_info *cdi, int position);
192 static spinlock_t mcd_spinlock = SPIN_LOCK_UNLOCKED;
193 static int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
194                     void *arg);
195 static int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
196
197 static struct timer_list mcd_timer = TIMER_INITIALIZER(NULL, 0, 0);
198
199 static struct cdrom_device_ops mcd_dops = {
200         .open                   = mcd_open,
201         .release                = mcd_release,
202         .drive_status           = mcd_drive_status,
203         .media_changed          = mcd_media_changed,
204         .tray_move              = mcd_tray_move,
205         .audio_ioctl            = mcd_audio_ioctl,
206         .capability             = CDC_OPEN_TRAY | CDC_MEDIA_CHANGED |
207                                   CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
208 };
209
210 static struct cdrom_device_info mcd_info = {
211         .ops            = &mcd_dops,
212         .speed          = 2,
213         .capacity       = 1,
214         .name           = "mcd",
215 };
216
217 static int mcd_block_open(struct inode *inode, struct file *file)
218 {
219         return cdrom_open(&mcd_info, inode, file);
220 }
221
222 static int mcd_block_release(struct inode *inode, struct file *file)
223 {
224         return cdrom_release(&mcd_info, file);
225 }
226
227 static int mcd_block_ioctl(struct inode *inode, struct file *file,
228                                 unsigned cmd, unsigned long arg)
229 {
230         return cdrom_ioctl(&mcd_info, inode, cmd, arg);
231 }
232
233 static int mcd_block_media_changed(struct gendisk *disk)
234 {
235         return cdrom_media_changed(&mcd_info);
236 }
237
238 static struct block_device_operations mcd_bdops =
239 {
240         .owner          = THIS_MODULE,
241         .open           = mcd_block_open,
242         .release        = mcd_block_release,
243         .ioctl          = mcd_block_ioctl,
244         .media_changed  = mcd_block_media_changed,
245 };
246
247 static struct gendisk *mcd_gendisk;
248
249 #ifndef MODULE
250 static int __init mcd_setup(char *str)
251 {
252         int ints[9];
253
254         (void) get_options(str, ARRAY_SIZE(ints), ints);
255
256         if (ints[0] > 0)
257                 mcd_port = ints[1];
258         if (ints[0] > 1)
259                 mcd_irq = ints[2];
260         if (ints[0] > 2)
261                 mitsumi_bug_93_wait = ints[3];
262
263         return 1;
264 }
265
266 __setup("mcd=", mcd_setup);
267
268 #endif                          /* MODULE */
269
270 static int mcd_media_changed(struct cdrom_device_info *cdi, int disc_nr)
271 {
272         return 0;
273 }
274
275
276 /*
277  * Do a 'get status' command and get the result.  Only use from the top half
278  * because it calls 'getMcdStatus' which sleeps.
279  */
280
281 static int statusCmd(void)
282 {
283         int st = -1, retry;
284
285         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
286                 /* send get-status cmd */
287                 outb(MCMD_GET_STATUS, MCDPORT(0));
288
289                 st = getMcdStatus(MCD_STATUS_DELAY);
290                 if (st != -1)
291                         break;
292         }
293
294         return st;
295 }
296
297
298 /*
299  * Send a 'Play' command and get the status.  Use only from the top half.
300  */
301
302 static int mcdPlay(struct mcd_Play_msf *arg)
303 {
304         int retry, st = -1;
305
306         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
307                 sendMcdCmd(MCMD_PLAY_READ, arg);
308                 st = getMcdStatus(2 * MCD_STATUS_DELAY);
309                 if (st != -1)
310                         break;
311         }
312
313         return st;
314 }
315
316
317 static int mcd_tray_move(struct cdrom_device_info *cdi, int position)
318 {
319         int i;
320         if (position) {
321                 /*  Eject */
322                 /* all drives can at least stop! */
323                 if (audioStatus == CDROM_AUDIO_PLAY) {
324                         outb(MCMD_STOP, MCDPORT(0));
325                         i = getMcdStatus(MCD_STATUS_DELAY);
326                 }
327
328                 audioStatus = CDROM_AUDIO_NO_STATUS;
329
330                 outb(MCMD_EJECT, MCDPORT(0));
331                 /*
332                  * the status (i) shows failure on all but the FX drives.
333                  * But nothing we can do about that in software!
334                  * So just read the status and forget it. - Jon.
335                  */
336                 i = getMcdStatus(MCD_STATUS_DELAY);
337                 return 0;
338         } else
339                 return -EINVAL;
340 }
341
342 long msf2hsg(struct msf *mp)
343 {
344         return bcd2bin(mp->frame) + bcd2bin(mp->sec) * 75 + bcd2bin(mp->min) * 4500 - 150;
345 }
346
347
348 int mcd_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
349                     void *arg)
350 {
351         int i, st;
352         struct mcd_Toc qInfo;
353         struct cdrom_ti *ti;
354         struct cdrom_tochdr *tocHdr;
355         struct cdrom_msf *msf;
356         struct cdrom_subchnl *subchnl;
357         struct cdrom_tocentry *entry;
358         struct mcd_Toc *tocPtr;
359         struct cdrom_volctrl *volctrl;
360
361         st = statusCmd();
362         if (st < 0)
363                 return -EIO;
364
365         if (!tocUpToDate) {
366                 i = updateToc();
367                 if (i < 0)
368                         return i;       /* error reading TOC */
369         }
370
371         switch (cmd) {
372         case CDROMSTART:        /* Spin up the drive */
373                 /* Don't think we can do this.  Even if we could,
374                  * I think the drive times out and stops after a while
375                  * anyway.  For now, ignore it.
376                  */
377
378                 return 0;
379
380         case CDROMSTOP: /* Spin down the drive */
381                 outb(MCMD_STOP, MCDPORT(0));
382                 i = getMcdStatus(MCD_STATUS_DELAY);
383
384                 /* should we do anything if it fails? */
385
386                 audioStatus = CDROM_AUDIO_NO_STATUS;
387                 return 0;
388
389         case CDROMPAUSE:        /* Pause the drive */
390                 if (audioStatus != CDROM_AUDIO_PLAY)
391                         return -EINVAL;
392
393                 outb(MCMD_STOP, MCDPORT(0));
394                 i = getMcdStatus(MCD_STATUS_DELAY);
395
396                 if (GetQChannelInfo(&qInfo) < 0) {
397                         /* didn't get q channel info */
398
399                         audioStatus = CDROM_AUDIO_NO_STATUS;
400                         return 0;
401                 }
402
403                 mcd_Play.start = qInfo.diskTime;        /* remember restart point */
404
405                 audioStatus = CDROM_AUDIO_PAUSED;
406                 return 0;
407
408         case CDROMRESUME:       /* Play it again, Sam */
409                 if (audioStatus != CDROM_AUDIO_PAUSED)
410                         return -EINVAL;
411
412                 /* restart the drive at the saved position. */
413
414                 i = mcdPlay(&mcd_Play);
415                 if (i < 0) {
416                         audioStatus = CDROM_AUDIO_ERROR;
417                         return -EIO;
418                 }
419
420                 audioStatus = CDROM_AUDIO_PLAY;
421                 return 0;
422
423         case CDROMPLAYTRKIND:   /* Play a track.  This currently ignores index. */
424
425                 ti = (struct cdrom_ti *) arg;
426
427                 if (ti->cdti_trk0 < DiskInfo.first
428                     || ti->cdti_trk0 > DiskInfo.last
429                     || ti->cdti_trk1 < ti->cdti_trk0) {
430                         return -EINVAL;
431                 }
432
433                 if (ti->cdti_trk1 > DiskInfo.last)
434                         ti->cdti_trk1 = DiskInfo.last;
435
436                 mcd_Play.start = Toc[ti->cdti_trk0].diskTime;
437                 mcd_Play.end = Toc[ti->cdti_trk1 + 1].diskTime;
438
439 #ifdef MCD_DEBUG
440                 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
441                        mcd_Play.start.min, mcd_Play.start.sec,
442                        mcd_Play.start.frame, mcd_Play.end.min,
443                        mcd_Play.end.sec, mcd_Play.end.frame);
444 #endif
445
446                 i = mcdPlay(&mcd_Play);
447                 if (i < 0) {
448                         audioStatus = CDROM_AUDIO_ERROR;
449                         return -EIO;
450                 }
451
452                 audioStatus = CDROM_AUDIO_PLAY;
453                 return 0;
454
455         case CDROMPLAYMSF:      /* Play starting at the given MSF address. */
456
457                 if (audioStatus == CDROM_AUDIO_PLAY) {
458                         outb(MCMD_STOP, MCDPORT(0));
459                         i = getMcdStatus(MCD_STATUS_DELAY);
460                         audioStatus = CDROM_AUDIO_NO_STATUS;
461                 }
462
463                 msf = (struct cdrom_msf *) arg;
464
465                 /* convert to bcd */
466
467                 bin2bcd(&msf->cdmsf_min0);
468                 bin2bcd(&msf->cdmsf_sec0);
469                 bin2bcd(&msf->cdmsf_frame0);
470                 bin2bcd(&msf->cdmsf_min1);
471                 bin2bcd(&msf->cdmsf_sec1);
472                 bin2bcd(&msf->cdmsf_frame1);
473
474                 mcd_Play.start.min = msf->cdmsf_min0;
475                 mcd_Play.start.sec = msf->cdmsf_sec0;
476                 mcd_Play.start.frame = msf->cdmsf_frame0;
477                 mcd_Play.end.min = msf->cdmsf_min1;
478                 mcd_Play.end.sec = msf->cdmsf_sec1;
479                 mcd_Play.end.frame = msf->cdmsf_frame1;
480
481 #ifdef MCD_DEBUG
482                 printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n",
483                        mcd_Play.start.min, mcd_Play.start.sec,
484                        mcd_Play.start.frame, mcd_Play.end.min,
485                        mcd_Play.end.sec, mcd_Play.end.frame);
486 #endif
487
488                 i = mcdPlay(&mcd_Play);
489                 if (i < 0) {
490                         audioStatus = CDROM_AUDIO_ERROR;
491                         return -EIO;
492                 }
493
494                 audioStatus = CDROM_AUDIO_PLAY;
495                 return 0;
496
497         case CDROMREADTOCHDR:   /* Read the table of contents header */
498                 tocHdr = (struct cdrom_tochdr *) arg;
499                 tocHdr->cdth_trk0 = DiskInfo.first;
500                 tocHdr->cdth_trk1 = DiskInfo.last;
501                 return 0;
502
503         case CDROMREADTOCENTRY: /* Read an entry in the table of contents */
504                 entry = (struct cdrom_tocentry *) arg;
505                 if (entry->cdte_track == CDROM_LEADOUT)
506                         tocPtr = &Toc[DiskInfo.last - DiskInfo.first + 1];
507
508                 else if (entry->cdte_track > DiskInfo.last
509                          || entry->cdte_track < DiskInfo.first)
510                         return -EINVAL;
511
512                 else
513                         tocPtr = &Toc[entry->cdte_track];
514
515                 entry->cdte_adr = tocPtr->ctrl_addr;
516                 entry->cdte_ctrl = tocPtr->ctrl_addr >> 4;
517
518                 if (entry->cdte_format == CDROM_LBA)
519                         entry->cdte_addr.lba = msf2hsg(&tocPtr->diskTime);
520
521                 else if (entry->cdte_format == CDROM_MSF) {
522                         entry->cdte_addr.msf.minute =
523                             bcd2bin(tocPtr->diskTime.min);
524                         entry->cdte_addr.msf.second =
525                             bcd2bin(tocPtr->diskTime.sec);
526                         entry->cdte_addr.msf.frame =
527                             bcd2bin(tocPtr->diskTime.frame);
528                 }
529
530                 else
531                         return -EINVAL;
532
533                 return 0;
534
535         case CDROMSUBCHNL:      /* Get subchannel info */
536
537                 subchnl = (struct cdrom_subchnl *) arg;
538                 if (GetQChannelInfo(&qInfo) < 0)
539                         return -EIO;
540
541                 subchnl->cdsc_audiostatus = audioStatus;
542                 subchnl->cdsc_adr = qInfo.ctrl_addr;
543                 subchnl->cdsc_ctrl = qInfo.ctrl_addr >> 4;
544                 subchnl->cdsc_trk = bcd2bin(qInfo.track);
545                 subchnl->cdsc_ind = bcd2bin(qInfo.pointIndex);
546                 subchnl->cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min);
547                 subchnl->cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec);
548                 subchnl->cdsc_absaddr.msf.frame  = bcd2bin(qInfo.diskTime.frame);
549                 subchnl->cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min);
550                 subchnl->cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec);
551                 subchnl->cdsc_reladdr.msf.frame  = bcd2bin(qInfo.trackTime.frame);
552                 return (0);
553
554         case CDROMVOLCTRL:      /* Volume control */
555                 volctrl = (struct cdrom_volctrl *) arg;
556                 outb(MCMD_SET_VOLUME, MCDPORT(0));
557                 outb(volctrl->channel0, MCDPORT(0));
558                 outb(255, MCDPORT(0));
559                 outb(volctrl->channel1, MCDPORT(0));
560                 outb(255, MCDPORT(0));
561
562                 i = getMcdStatus(MCD_STATUS_DELAY);
563                 if (i < 0)
564                         return -EIO;
565
566                 {
567                         char a, b, c, d;
568
569                         getValue(&a);
570                         getValue(&b);
571                         getValue(&c);
572                         getValue(&d);
573                 }
574
575                 return 0;
576
577         default:
578                 return -EINVAL;
579         }
580 }
581
582 /*
583  * Take care of the different block sizes between cdrom and Linux.
584  * When Linux gets variable block sizes this will probably go away.
585  */
586
587 static void mcd_transfer(void)
588 {
589         if (!current_valid())
590                 return;
591
592         while (CURRENT->nr_sectors) {
593                 int bn = CURRENT->sector / 4;
594                 int i;
595                 for (i = 0; i < MCD_BUF_SIZ && mcd_buf_bn[i] != bn; ++i)
596                         ;
597                 if (i < MCD_BUF_SIZ) {
598                         int offs =(i * 4 + (CURRENT->sector & 3)) * 512;
599                         int nr_sectors = 4 - (CURRENT->sector & 3);
600                         if (mcd_buf_out != i) {
601                                 mcd_buf_out = i;
602                                 if (mcd_buf_bn[i] != bn) {
603                                         mcd_buf_out = -1;
604                                         continue;
605                                 }
606                         }
607                         if (nr_sectors > CURRENT->nr_sectors)
608                                 nr_sectors = CURRENT->nr_sectors;
609                         memcpy(CURRENT->buffer, mcd_buf + offs, nr_sectors * 512);
610                         CURRENT->nr_sectors -= nr_sectors;
611                         CURRENT->sector += nr_sectors;
612                         CURRENT->buffer += nr_sectors * 512;
613                 } else {
614                         mcd_buf_out = -1;
615                         break;
616                 }
617         }
618 }
619
620
621 /*
622  * We only seem to get interrupts after an error.
623  * Just take the interrupt and clear out the status reg.
624  */
625
626 static irqreturn_t mcd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
627 {
628         int st;
629
630         st = inb(MCDPORT(1)) & 0xFF;
631         test1(printk("<int1-%02X>", st));
632         if (!(st & MFL_STATUS)) {
633                 st = inb(MCDPORT(0)) & 0xFF;
634                 test1(printk("<int0-%02X>", st));
635                 if ((st & 0xFF) != 0xFF)
636                         mcd_error = st ? st & 0xFF : -1;
637         }
638         return IRQ_HANDLED;
639 }
640
641
642 static void do_mcd_request(request_queue_t * q)
643 {
644         test2(printk(" do_mcd_request(%ld+%ld)\n", CURRENT->sector,
645                CURRENT->nr_sectors));
646
647                 mcd_transfer_is_active = 1;
648         while (current_valid()) {
649                 mcd_transfer();
650                 if (CURRENT->nr_sectors == 0) {
651                         end_request(CURRENT, 1);
652                 } else {
653                         mcd_buf_out = -1;       /* Want to read a block not in buffer */
654                         if (mcd_state == MCD_S_IDLE) {
655                                 if (!tocUpToDate) {
656                                         if (updateToc() < 0) {
657                                                 while (current_valid())
658                                                         end_request(CURRENT, 0);
659                                                 break;
660                                         }
661                                 }
662                                 mcd_state = MCD_S_START;
663                                 McdTries = 5;
664                                 mcd_timer.function = mcd_poll;
665                                 mod_timer(&mcd_timer, jiffies + 1);
666                         }
667                         break;
668                 }
669         }
670         mcd_transfer_is_active = 0;
671         test2(printk(" do_mcd_request ends\n"));
672 }
673
674
675
676 static void mcd_poll(unsigned long dummy)
677 {
678         int st;
679
680
681         if (mcd_error) {
682                 if (mcd_error & 0xA5) {
683                         printk(KERN_ERR "mcd: I/O error 0x%02x", mcd_error);
684                         if (mcd_error & 0x80)
685                                 printk(" (Door open)");
686                         if (mcd_error & 0x20)
687                                 printk(" (Disk changed)");
688                         if (mcd_error & 0x04) {
689                                 printk(" (Read error)");        /* Bitch about the problem. */
690
691                                 /* Time to get fancy! If at 2x speed and 1 error, drop to 1x speed! */
692                                 /* Interesting how it STAYS at MCD_RETRY_ATTEMPTS on first error! */
693                                 /* But I find that rather HANDY!!! */
694                                 /* Neat! it REALLY WORKS on those LOW QUALITY CD's!!! Smile! :) */
695                                 /* AJK [06/17/95] */
696
697                                 /* Slap the CD down to single speed! */
698                                 if (mcdDouble == 1
699                                     && McdTries == MCD_RETRY_ATTEMPTS
700                                     && MCMD_DATA_READ == MCMD_2X_READ) {
701                                         MCMD_DATA_READ = MCMD_PLAY_READ;        /* Uhhh, Ummmm, muhuh-huh! */
702                                         mcd1xhold = SINGLE_HOLD_SECTORS;        /* Hey Beavis! */
703                                         printk(" Speed now 1x");        /* Pull my finger! */
704                                 }
705                         }
706                         printk("\n");
707                         mcd_invalidate_buffers();
708 #ifdef WARN_IF_READ_FAILURE
709                         if (McdTries == MCD_RETRY_ATTEMPTS)
710                                 printk(KERN_ERR "mcd: read of block %d failed\n",
711                                        mcd_next_bn);
712 #endif
713                         if (!McdTries--) {
714                                 /* Nuts! This cd is ready for recycling! */
715                                 /* When WAS the last time YOU cleaned it CORRECTLY?! */
716                                 printk(KERN_ERR "mcd: read of block %d failed, giving up\n",
717                                      mcd_next_bn);
718                                 if (mcd_transfer_is_active) {
719                                         McdTries = 0;
720                                         goto ret;
721                                 }
722                                 if (current_valid())
723                                         end_request(CURRENT, 0);
724                                 McdTries = MCD_RETRY_ATTEMPTS;
725                         }
726                 }
727                 mcd_error = 0;
728                 mcd_state = MCD_S_STOP;
729         }
730         /* Switch back to Double speed if enough GOOD sectors were read! */
731
732         /* Are we a double speed with a crappy CD?! */
733         if (mcdDouble == 1 && McdTries == MCD_RETRY_ATTEMPTS
734             && MCMD_DATA_READ == MCMD_PLAY_READ) {
735                 /* We ARE a double speed and we ARE bitching! */
736                 if (mcd1xhold == 0) {   /* Okay, Like are we STILL at single speed? *//* We need to switch back to double speed now... */
737                         MCMD_DATA_READ = MCMD_2X_READ;  /* Uhhh... BACK You GO! */
738                         printk(KERN_INFO "mcd: Switching back to 2X speed!\n"); /* Tell 'em! */
739                 } else
740                         mcd1xhold--;    /* No?! Count down the good reads some more... */
741                 /* and try, try again! */
742         }
743
744 immediately:
745         switch (mcd_state) {
746         case MCD_S_IDLE:
747                 test3(printk("MCD_S_IDLE\n"));
748                 goto out;
749
750         case MCD_S_START:
751                 test3(printk("MCD_S_START\n"));
752                 outb(MCMD_GET_STATUS, MCDPORT(0));
753                 mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE;
754                 McdTimeout = 3000;
755                 break;
756
757         case MCD_S_MODE:
758                 test3(printk("MCD_S_MODE\n"));
759                 if ((st = mcdStatus()) != -1) {
760                         if (st & MST_DSK_CHG) {
761                                 mcdDiskChanged = 1;
762                                 tocUpToDate = 0;
763                                 mcd_invalidate_buffers();
764                         }
765
766 set_mode_immediately:
767                         if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
768                                 mcdDiskChanged = 1;
769                                 tocUpToDate = 0;
770                                 if (mcd_transfer_is_active) {
771                                         mcd_state = MCD_S_START;
772                                         goto immediately;
773                                 }
774                                 printk(KERN_INFO);
775                                 printk((st & MST_DOOR_OPEN) ?
776                                        "mcd: door open\n" :
777                                        "mcd: disk removed\n");
778                                 mcd_state = MCD_S_IDLE;
779                                 while (current_valid())
780                                         end_request(CURRENT, 0);
781                                 goto out;
782                         }
783                         outb(MCMD_SET_MODE, MCDPORT(0));
784                         outb(1, MCDPORT(0));
785                         mcd_mode = 1;
786                         mcd_state = MCD_S_READ;
787                         McdTimeout = 3000;
788                 }
789                 break;
790
791         case MCD_S_READ:
792                 test3(printk("MCD_S_READ\n"));
793                 if ((st = mcdStatus()) != -1) {
794                         if (st & MST_DSK_CHG) {
795                                 mcdDiskChanged = 1;
796                                 tocUpToDate = 0;
797                                 mcd_invalidate_buffers();
798                         }
799
800 read_immediately:
801                         if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) {
802                                 mcdDiskChanged = 1;
803                                 tocUpToDate = 0;
804                                 if (mcd_transfer_is_active) {
805                                         mcd_state = MCD_S_START;
806                                         goto immediately;
807                                 }
808                                 printk(KERN_INFO);
809                                 printk((st & MST_DOOR_OPEN) ?
810                                        "mcd: door open\n" :
811                                        "mcd: disk removed\n");
812                                 mcd_state = MCD_S_IDLE;
813                                 while (current_valid())
814                                         end_request(CURRENT, 0);
815                                 goto out;
816                         }
817
818                         if (current_valid()) {
819                                 struct mcd_Play_msf msf;
820                                 mcd_next_bn = CURRENT->sector / 4;
821                                 hsg2msf(mcd_next_bn, &msf.start);
822                                 msf.end.min = ~0;
823                                 msf.end.sec = ~0;
824                                 msf.end.frame = ~0;
825                                 sendMcdCmd(MCMD_DATA_READ, &msf);
826                                 mcd_state = MCD_S_DATA;
827                                 McdTimeout = READ_TIMEOUT;
828                         } else {
829                                 mcd_state = MCD_S_STOP;
830                                 goto immediately;
831                         }
832
833                 }
834                 break;
835
836         case MCD_S_DATA:
837                 test3(printk("MCD_S_DATA\n"));
838                 st = inb(MCDPORT(1)) & (MFL_STATUSorDATA);
839 data_immediately:
840                 test5(printk("Status %02x\n", st))
841                 switch (st) {
842                 case MFL_DATA:
843 #ifdef WARN_IF_READ_FAILURE
844                         if (McdTries == 5)
845                                 printk(KERN_WARNING "mcd: read of block %d failed\n",
846                                        mcd_next_bn);
847 #endif
848                         if (!McdTries--) {
849                                 printk(KERN_ERR "mcd: read of block %d failed, giving up\n", mcd_next_bn);
850                                 if (mcd_transfer_is_active) {
851                                         McdTries = 0;
852                                         break;
853                                 }
854                                 if (current_valid())
855                                         end_request(CURRENT, 0);
856                                 McdTries = 5;
857                         }
858                         mcd_state = MCD_S_START;
859                         McdTimeout = READ_TIMEOUT;
860                         goto immediately;
861
862                 case MFL_STATUSorDATA:
863                         break;
864
865                 default:
866                         McdTries = 5;
867                         if (!current_valid() && mcd_buf_in == mcd_buf_out) {
868                                 mcd_state = MCD_S_STOP;
869                                 goto immediately;
870                         }
871                         mcd_buf_bn[mcd_buf_in] = -1;
872                         insb(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in,
873                                   2048);
874                         mcd_buf_bn[mcd_buf_in] = mcd_next_bn++;
875                         if (mcd_buf_out == -1)
876                                 mcd_buf_out = mcd_buf_in;
877                         mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1;
878                         if (!mcd_transfer_is_active) {
879                                 while (current_valid()) {
880                                         mcd_transfer();
881                                         if (CURRENT->nr_sectors == 0)
882                                                 end_request(CURRENT, 1);
883                                         else
884                                                 break;
885                                 }
886                         }
887
888                         if (current_valid()
889                             && (CURRENT->sector / 4 < mcd_next_bn ||
890                                 CURRENT->sector / 4 > mcd_next_bn + 16)) {
891                                 mcd_state = MCD_S_STOP;
892                                 goto immediately;
893                         }
894                         McdTimeout = READ_TIMEOUT;
895                         {
896                                 int count = QUICK_LOOP_COUNT;
897                                 while (count--) {
898                                         QUICK_LOOP_DELAY;
899                                         if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) {
900                                                 test4(printk(" %d ", QUICK_LOOP_COUNT - count));
901                                                 goto data_immediately;
902                                         }
903                                 }
904                                 test4(printk("ended "));
905                         }
906                         break;
907                 }
908                 break;
909
910         case MCD_S_STOP:
911                 test3(printk("MCD_S_STOP\n"));
912                 if (!mitsumi_bug_93_wait)
913                         goto do_not_work_around_mitsumi_bug_93_1;
914
915                 McdTimeout = mitsumi_bug_93_wait;
916                 mcd_state = 9 + 3 + 1;
917                 break;
918
919         case 9 + 3 + 1:
920                 if (McdTimeout)
921                         break;
922
923 do_not_work_around_mitsumi_bug_93_1:
924                 outb(MCMD_STOP, MCDPORT(0));
925                 if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
926                         int i = 4096;
927                         do {
928                                 inb(MCDPORT(0));
929                         } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
930                         outb(MCMD_STOP, MCDPORT(0));
931                         if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) {
932                                 i = 4096;
933                                 do {
934                                         inb(MCDPORT(0));
935                                 } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i);
936                                 outb(MCMD_STOP, MCDPORT(0));
937                         }
938                 }
939
940                 mcd_state = MCD_S_STOPPING;
941                 McdTimeout = 1000;
942                 break;
943
944         case MCD_S_STOPPING:
945                 test3(printk("MCD_S_STOPPING\n"));
946                 if ((st = mcdStatus()) == -1 && McdTimeout)
947                         break;
948
949                 if ((st != -1) && (st & MST_DSK_CHG)) {
950                         mcdDiskChanged = 1;
951                         tocUpToDate = 0;
952                         mcd_invalidate_buffers();
953                 }
954                 if (!mitsumi_bug_93_wait)
955                         goto do_not_work_around_mitsumi_bug_93_2;
956
957                 McdTimeout = mitsumi_bug_93_wait;
958                 mcd_state = 9 + 3 + 2;
959                 break;
960
961         case 9 + 3 + 2:
962                 if (McdTimeout)
963                         break;
964                 st = -1;
965
966 do_not_work_around_mitsumi_bug_93_2:
967                 test3(printk("CURRENT_VALID %d mcd_mode %d\n", current_valid(),
968                             mcd_mode));
969                 if (current_valid()) {
970                         if (st != -1) {
971                                 if (mcd_mode == 1)
972                                         goto read_immediately;
973                                 else
974                                         goto set_mode_immediately;
975                         } else {
976                                 mcd_state = MCD_S_START;
977                                 McdTimeout = 1;
978                         }
979                 } else {
980                         mcd_state = MCD_S_IDLE;
981                         goto out;
982                 }
983                 break;
984         default:
985                 printk(KERN_ERR "mcd: invalid state %d\n", mcd_state);
986                 goto out;
987         }
988 ret:
989         if (!McdTimeout--) {
990                 printk(KERN_WARNING "mcd: timeout in state %d\n", mcd_state);
991                 mcd_state = MCD_S_STOP;
992         }
993         mcd_timer.function = mcd_poll;
994         mod_timer(&mcd_timer, jiffies + 1);
995 out:
996         return;
997 }
998
999 static void mcd_invalidate_buffers(void)
1000 {
1001         int i;
1002         for (i = 0; i < MCD_BUF_SIZ; ++i)
1003                 mcd_buf_bn[i] = -1;
1004         mcd_buf_out = -1;
1005 }
1006
1007 /*
1008  * Open the device special file.  Check that a disk is in.
1009  */
1010 static int mcd_open(struct cdrom_device_info *cdi, int purpose)
1011 {
1012         int st, count = 0;
1013         if (mcdPresent == 0)
1014                 return -ENXIO;  /* no hardware */
1015
1016         if (mcd_open_count || mcd_state != MCD_S_IDLE)
1017                 goto bump_count;
1018
1019         mcd_invalidate_buffers();
1020         do {
1021                 st = statusCmd();       /* check drive status */
1022                 if (st == -1)
1023                         goto err_out;   /* drive doesn't respond */
1024                 if ((st & MST_READY) == 0) {    /* no disk? wait a sec... */
1025                         current->state = TASK_INTERRUPTIBLE;
1026                         schedule_timeout(HZ);
1027                 }
1028         } while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS);
1029
1030         if (updateToc() < 0)
1031                 goto err_out;
1032
1033 bump_count:
1034         ++mcd_open_count;
1035         return 0;
1036
1037 err_out:
1038         return -EIO;
1039 }
1040
1041
1042 /*
1043  * On close, we flush all mcd blocks from the buffer cache.
1044  */
1045 static void mcd_release(struct cdrom_device_info *cdi)
1046 {
1047         if (!--mcd_open_count) {
1048                 mcd_invalidate_buffers();
1049         }
1050 }
1051
1052 /*
1053  * Test for presence of drive and initialize it.  Called at boot time.
1054  */
1055
1056 int __init mcd_init(void)
1057 {
1058         struct gendisk *disk = alloc_disk(1);
1059         int count;
1060         unsigned char result[3];
1061         char msg[80];
1062
1063         if (!disk) {
1064                 printk(KERN_INFO "mcd: can't allocated disk.\n");
1065                 return -ENOMEM;
1066         }
1067         if (mcd_port <= 0 || mcd_irq <= 0) {
1068                 printk(KERN_INFO "mcd: not probing.\n");
1069                 put_disk(disk);
1070                 return -EIO;
1071         }
1072         if (register_blkdev(MAJOR_NR, "mcd")) {
1073                 put_disk(disk);
1074                 return -EIO;
1075         }
1076         if (!request_region(mcd_port, 4, "mcd")) {
1077                 printk(KERN_ERR "mcd: Initialization failed, I/O port (%X) already in use\n", mcd_port);
1078                 goto out_region;
1079         }
1080
1081         mcd_queue = blk_init_queue(do_mcd_request, &mcd_spinlock);
1082         if (!mcd_queue)
1083                 goto out_queue;
1084
1085         /* check for card */
1086
1087         outb(0, MCDPORT(1));    /* send reset */
1088         for (count = 0; count < 2000000; count++)
1089                 (void) inb(MCDPORT(1)); /* delay a bit */
1090
1091         outb(0x40, MCDPORT(0)); /* send get-stat cmd */
1092         for (count = 0; count < 2000000; count++)
1093                 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1094                         break;
1095
1096         if (count >= 2000000) {
1097                 printk(KERN_INFO "mcd: initialisation failed - No mcd device at 0x%x irq %d\n",
1098                        mcd_port, mcd_irq);
1099                 goto out_probe;
1100         }
1101         count = inb(MCDPORT(0));        /* pick up the status */
1102
1103         outb(MCMD_GET_VERSION, MCDPORT(0));
1104         for (count = 0; count < 3; count++)
1105                 if (getValue(result + count)) {
1106                         printk(KERN_ERR "mcd: mitsumi get version failed at 0x%x\n",
1107                                mcd_port);
1108                         goto out_probe;
1109                 }
1110
1111         if (result[0] == result[1] && result[1] == result[2])
1112                 goto out_probe;
1113
1114         mcdVersion = result[2];
1115
1116         if (mcdVersion >= 4)
1117                 outb(4, MCDPORT(2));    /* magic happens */
1118
1119         /* don't get the IRQ until we know for sure the drive is there */
1120
1121         if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL)) {
1122                 printk(KERN_ERR "mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
1123                 goto out_probe;
1124         }
1125
1126         if (result[1] == 'D') {
1127                 MCMD_DATA_READ = MCMD_2X_READ;
1128                 /* Added flag to drop to 1x speed if too many errors */
1129                 mcdDouble = 1;
1130         } else
1131                 mcd_info.speed = 1;
1132         sprintf(msg, " mcd: Mitsumi %s Speed CD-ROM at port=0x%x,"
1133                 " irq=%d\n", mcd_info.speed == 1 ? "Single" : "Double",
1134                 mcd_port, mcd_irq);
1135
1136         outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1137         outb(0x02, MCDPORT(0));
1138         outb(0x00, MCDPORT(0));
1139         getValue(result);
1140
1141         outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1142         outb(0x10, MCDPORT(0));
1143         outb(0x04, MCDPORT(0));
1144         getValue(result);
1145
1146         mcd_invalidate_buffers();
1147         mcdPresent = 1;
1148
1149         disk->major = MAJOR_NR;
1150         disk->first_minor = 0;
1151         sprintf(disk->disk_name, "mcd");
1152         disk->fops = &mcd_bdops;
1153         disk->flags = GENHD_FL_CD;
1154         mcd_gendisk = disk;
1155
1156         if (register_cdrom(&mcd_info) != 0) {
1157                 printk(KERN_ERR "mcd: Unable to register Mitsumi CD-ROM.\n");
1158                 goto out_cdrom;
1159         }
1160         disk->queue = mcd_queue;
1161         add_disk(disk);
1162         printk(msg);
1163         return 0;
1164
1165 out_cdrom:
1166         free_irq(mcd_irq, NULL);
1167 out_queue:
1168         release_region(mcd_port, 4);
1169 out_probe:
1170         blk_cleanup_queue(mcd_queue);
1171 out_region:
1172         unregister_blkdev(MAJOR_NR, "mcd");
1173         put_disk(disk);
1174         return -EIO;
1175 }
1176
1177
1178 static void hsg2msf(long hsg, struct msf *msf)
1179 {
1180         hsg += 150;
1181         msf->min = hsg / 4500;
1182         hsg %= 4500;
1183         msf->sec = hsg / 75;
1184         msf->frame = hsg % 75;
1185
1186         bin2bcd(&msf->min);     /* convert to BCD */
1187         bin2bcd(&msf->sec);
1188         bin2bcd(&msf->frame);
1189 }
1190
1191
1192 static void bin2bcd(unsigned char *p)
1193 {
1194         int u, t;
1195
1196         u = *p % 10;
1197         t = *p / 10;
1198         *p = u | (t << 4);
1199 }
1200
1201 static int bcd2bin(unsigned char bcd)
1202 {
1203         return (bcd >> 4) * 10 + (bcd & 0xF);
1204 }
1205
1206
1207 /*
1208  * See if a status is ready from the drive and return it
1209  * if it is ready.
1210  */
1211
1212 static int mcdStatus(void)
1213 {
1214         int i;
1215         int st;
1216
1217         st = inb(MCDPORT(1)) & MFL_STATUS;
1218         if (!st) {
1219                 i = inb(MCDPORT(0)) & 0xFF;
1220                 return i;
1221         } else
1222                 return -1;
1223 }
1224
1225
1226 /*
1227  * Send a play or read command to the drive
1228  */
1229
1230 static void sendMcdCmd(int cmd, struct mcd_Play_msf *params)
1231 {
1232         outb(cmd, MCDPORT(0));
1233         outb(params->start.min, MCDPORT(0));
1234         outb(params->start.sec, MCDPORT(0));
1235         outb(params->start.frame, MCDPORT(0));
1236         outb(params->end.min, MCDPORT(0));
1237         outb(params->end.sec, MCDPORT(0));
1238         outb(params->end.frame, MCDPORT(0));
1239 }
1240
1241
1242 /*
1243  * Timer interrupt routine to test for status ready from the drive.
1244  * (see the next routine)
1245  */
1246
1247 static void mcdStatTimer(unsigned long dummy)
1248 {
1249         if (!(inb(MCDPORT(1)) & MFL_STATUS)) {
1250                 wake_up(&mcd_waitq);
1251                 return;
1252         }
1253
1254         McdTimeout--;
1255         if (McdTimeout <= 0) {
1256                 wake_up(&mcd_waitq);
1257                 return;
1258         }
1259         mcd_timer.function = mcdStatTimer;
1260         mod_timer(&mcd_timer, jiffies + 1);
1261 }
1262
1263
1264 /*
1265  * Wait for a status to be returned from the drive.  The actual test
1266  * (see routine above) is done by the timer interrupt to avoid
1267  * excessive rescheduling.
1268  */
1269
1270 static int getMcdStatus(int timeout)
1271 {
1272         int st;
1273
1274         McdTimeout = timeout;
1275         mcd_timer.function = mcdStatTimer;
1276         mod_timer(&mcd_timer, jiffies + 1);
1277         sleep_on(&mcd_waitq);
1278         if (McdTimeout <= 0)
1279                 return -1;
1280
1281         st = inb(MCDPORT(0)) & 0xFF;
1282         if (st == 0xFF)
1283                 return -1;
1284
1285         if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
1286                 /* XXX might be an error? look at q-channel? */
1287                 audioStatus = CDROM_AUDIO_COMPLETED;
1288
1289         if (st & MST_DSK_CHG) {
1290                 mcdDiskChanged = 1;
1291                 tocUpToDate = 0;
1292                 audioStatus = CDROM_AUDIO_NO_STATUS;
1293         }
1294
1295         return st;
1296 }
1297
1298
1299 /* gives current state of the drive This function is quite unreliable, 
1300    and should probably be rewritten by someone, eventually... */
1301
1302 int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
1303 {
1304         int st;
1305
1306         st = statusCmd();       /* check drive status */
1307         if (st == -1)
1308                 return -EIO;    /* drive doesn't respond */
1309         if ((st & MST_READY))
1310                 return CDS_DISC_OK;
1311         if ((st & MST_DOOR_OPEN))
1312                 return CDS_TRAY_OPEN;
1313         if ((st & MST_DSK_CHG))
1314                 return CDS_NO_DISC;
1315         if ((st & MST_BUSY))
1316                 return CDS_DRIVE_NOT_READY;
1317         return -EIO;
1318 }
1319
1320
1321 /*
1322  * Read a value from the drive.
1323  */
1324
1325 static int getValue(unsigned char *result)
1326 {
1327         int count;
1328         int s;
1329
1330         for (count = 0; count < 2000; count++)
1331                 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1332                         break;
1333
1334         if (count >= 2000) {
1335                 printk("mcd: getValue timeout\n");
1336                 return -1;
1337         }
1338
1339         s = inb(MCDPORT(0)) & 0xFF;
1340         *result = (unsigned char) s;
1341         return 0;
1342 }
1343
1344 /*
1345  * Read the current Q-channel info.  Also used for reading the
1346  * table of contents.
1347  */
1348
1349 int GetQChannelInfo(struct mcd_Toc *qp)
1350 {
1351         unsigned char notUsed;
1352         int retry;
1353
1354         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1355                 outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
1356                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1357                         break;
1358         }
1359
1360         if (retry >= MCD_RETRY_ATTEMPTS)
1361                 return -1;
1362
1363         if (getValue(&qp->ctrl_addr) < 0)
1364                 return -1;
1365         if (getValue(&qp->track) < 0)
1366                 return -1;
1367         if (getValue(&qp->pointIndex) < 0)
1368                 return -1;
1369         if (getValue(&qp->trackTime.min) < 0)
1370                 return -1;
1371         if (getValue(&qp->trackTime.sec) < 0)
1372                 return -1;
1373         if (getValue(&qp->trackTime.frame) < 0)
1374                 return -1;
1375         if (getValue(&notUsed) < 0)
1376                 return -1;
1377         if (getValue(&qp->diskTime.min) < 0)
1378                 return -1;
1379         if (getValue(&qp->diskTime.sec) < 0)
1380                 return -1;
1381         if (getValue(&qp->diskTime.frame) < 0)
1382                 return -1;
1383
1384         return 0;
1385 }
1386
1387 /*
1388  * Read the table of contents (TOC) and TOC header if necessary
1389  */
1390
1391 static int updateToc(void)
1392 {
1393         if (tocUpToDate)
1394                 return 0;
1395
1396         if (GetDiskInfo() < 0)
1397                 return -EIO;
1398
1399         if (GetToc() < 0)
1400                 return -EIO;
1401
1402         tocUpToDate = 1;
1403         return 0;
1404 }
1405
1406 /*
1407  * Read the table of contents header
1408  */
1409
1410 static int GetDiskInfo(void)
1411 {
1412         int retry;
1413
1414         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1415                 outb(MCMD_GET_DISK_INFO, MCDPORT(0));
1416                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1417                         break;
1418         }
1419
1420         if (retry >= MCD_RETRY_ATTEMPTS)
1421                 return -1;
1422
1423         if (getValue(&DiskInfo.first) < 0)
1424                 return -1;
1425         if (getValue(&DiskInfo.last) < 0)
1426                 return -1;
1427
1428         DiskInfo.first = bcd2bin(DiskInfo.first);
1429         DiskInfo.last = bcd2bin(DiskInfo.last);
1430
1431 #ifdef MCD_DEBUG
1432         printk
1433             ("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
1434              DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min,
1435              DiskInfo.diskLength.sec, DiskInfo.diskLength.frame,
1436              DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec,
1437              DiskInfo.firstTrack.frame);
1438 #endif
1439
1440         if (getValue(&DiskInfo.diskLength.min) < 0)
1441                 return -1;
1442         if (getValue(&DiskInfo.diskLength.sec) < 0)
1443                 return -1;
1444         if (getValue(&DiskInfo.diskLength.frame) < 0)
1445                 return -1;
1446         if (getValue(&DiskInfo.firstTrack.min) < 0)
1447                 return -1;
1448         if (getValue(&DiskInfo.firstTrack.sec) < 0)
1449                 return -1;
1450         if (getValue(&DiskInfo.firstTrack.frame) < 0)
1451                 return -1;
1452
1453         return 0;
1454 }
1455
1456 /*
1457  * Read the table of contents (TOC)
1458  */
1459
1460 static int GetToc(void)
1461 {
1462         int i, px;
1463         int limit;
1464         int retry;
1465         struct mcd_Toc qInfo;
1466
1467         for (i = 0; i < MAX_TRACKS; i++)
1468                 Toc[i].pointIndex = 0;
1469
1470         i = DiskInfo.last + 3;
1471
1472         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1473                 outb(MCMD_STOP, MCDPORT(0));
1474                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1475                         break;
1476         }
1477
1478         if (retry >= MCD_RETRY_ATTEMPTS)
1479                 return -1;
1480
1481         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1482                 outb(MCMD_SET_MODE, MCDPORT(0));
1483                 outb(0x05, MCDPORT(0)); /* mode: toc */
1484                 mcd_mode = 0x05;
1485                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1486                         break;
1487         }
1488
1489         if (retry >= MCD_RETRY_ATTEMPTS)
1490                 return -1;
1491
1492         for (limit = 300; limit > 0; limit--) {
1493                 if (GetQChannelInfo(&qInfo) < 0)
1494                         break;
1495
1496                 px = bcd2bin(qInfo.pointIndex);
1497                 if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
1498                         if (Toc[px].pointIndex == 0) {
1499                                 Toc[px] = qInfo;
1500                                 i--;
1501                         }
1502
1503                 if (i <= 0)
1504                         break;
1505         }
1506
1507         Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
1508
1509         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1510                 outb(MCMD_SET_MODE, MCDPORT(0));
1511                 outb(0x01, MCDPORT(0));
1512                 mcd_mode = 1;
1513                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1514                         break;
1515         }
1516
1517 #ifdef MCD_DEBUG
1518         for (i = 1; i <= DiskInfo.last; i++)
1519                 printk
1520                     ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1521                      i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1522                      Toc[i].trackTime.min, Toc[i].trackTime.sec,
1523                      Toc[i].trackTime.frame, Toc[i].diskTime.min,
1524                      Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1525         for (i = 100; i < 103; i++)
1526                 printk
1527                     ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1528                      i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1529                      Toc[i].trackTime.min, Toc[i].trackTime.sec,
1530                      Toc[i].trackTime.frame, Toc[i].diskTime.min,
1531                      Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1532 #endif
1533
1534         return limit > 0 ? 0 : -1;
1535 }
1536
1537 void __exit mcd_exit(void)
1538 {
1539         del_gendisk(mcd_gendisk);
1540         put_disk(mcd_gendisk);
1541         if (unregister_cdrom(&mcd_info)) {
1542                 printk(KERN_WARNING "Can't unregister cdrom mcd\n");
1543                 return;
1544         }
1545         free_irq(mcd_irq, NULL);
1546         release_region(mcd_port, 4);
1547         if (unregister_blkdev(MAJOR_NR, "mcd")) {
1548                 printk(KERN_WARNING "Can't unregister major mcd\n");
1549                 return;
1550         }
1551         blk_cleanup_queue(mcd_queue);
1552         del_timer_sync(&mcd_timer);
1553 }
1554
1555 #ifdef MODULE
1556 module_init(mcd_init);
1557 #endif
1558 module_exit(mcd_exit);
1559
1560 MODULE_AUTHOR("Martin Harriss");
1561 MODULE_LICENSE("GPL");
1562 MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_CDROM_MAJOR);