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