vserver 1.9.3
[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(file, &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                         msleep(1000);
1026
1027         } while (((st & MST_READY) == 0) && count++ < MCD_RETRY_ATTEMPTS);
1028
1029         if (updateToc() < 0)
1030                 goto err_out;
1031
1032 bump_count:
1033         ++mcd_open_count;
1034         return 0;
1035
1036 err_out:
1037         return -EIO;
1038 }
1039
1040
1041 /*
1042  * On close, we flush all mcd blocks from the buffer cache.
1043  */
1044 static void mcd_release(struct cdrom_device_info *cdi)
1045 {
1046         if (!--mcd_open_count) {
1047                 mcd_invalidate_buffers();
1048         }
1049 }
1050
1051 /*
1052  * Test for presence of drive and initialize it.  Called at boot time.
1053  */
1054
1055 int __init mcd_init(void)
1056 {
1057         struct gendisk *disk = alloc_disk(1);
1058         int count;
1059         unsigned char result[3];
1060         char msg[80];
1061
1062         if (!disk) {
1063                 printk(KERN_INFO "mcd: can't allocated disk.\n");
1064                 return -ENOMEM;
1065         }
1066         if (mcd_port <= 0 || mcd_irq <= 0) {
1067                 printk(KERN_INFO "mcd: not probing.\n");
1068                 put_disk(disk);
1069                 return -EIO;
1070         }
1071         if (register_blkdev(MAJOR_NR, "mcd")) {
1072                 put_disk(disk);
1073                 return -EIO;
1074         }
1075         if (!request_region(mcd_port, 4, "mcd")) {
1076                 printk(KERN_ERR "mcd: Initialization failed, I/O port (%X) already in use\n", mcd_port);
1077                 goto out_region;
1078         }
1079
1080         mcd_queue = blk_init_queue(do_mcd_request, &mcd_spinlock);
1081         if (!mcd_queue)
1082                 goto out_queue;
1083
1084         /* check for card */
1085
1086         outb(0, MCDPORT(1));    /* send reset */
1087         for (count = 0; count < 2000000; count++)
1088                 (void) inb(MCDPORT(1)); /* delay a bit */
1089
1090         outb(0x40, MCDPORT(0)); /* send get-stat cmd */
1091         for (count = 0; count < 2000000; count++)
1092                 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1093                         break;
1094
1095         if (count >= 2000000) {
1096                 printk(KERN_INFO "mcd: initialisation failed - No mcd device at 0x%x irq %d\n",
1097                        mcd_port, mcd_irq);
1098                 goto out_probe;
1099         }
1100         count = inb(MCDPORT(0));        /* pick up the status */
1101
1102         outb(MCMD_GET_VERSION, MCDPORT(0));
1103         for (count = 0; count < 3; count++)
1104                 if (getValue(result + count)) {
1105                         printk(KERN_ERR "mcd: mitsumi get version failed at 0x%x\n",
1106                                mcd_port);
1107                         goto out_probe;
1108                 }
1109
1110         if (result[0] == result[1] && result[1] == result[2])
1111                 goto out_probe;
1112
1113         mcdVersion = result[2];
1114
1115         if (mcdVersion >= 4)
1116                 outb(4, MCDPORT(2));    /* magic happens */
1117
1118         /* don't get the IRQ until we know for sure the drive is there */
1119
1120         if (request_irq(mcd_irq, mcd_interrupt, SA_INTERRUPT, "Mitsumi CD", NULL)) {
1121                 printk(KERN_ERR "mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq);
1122                 goto out_probe;
1123         }
1124
1125         if (result[1] == 'D') {
1126                 MCMD_DATA_READ = MCMD_2X_READ;
1127                 /* Added flag to drop to 1x speed if too many errors */
1128                 mcdDouble = 1;
1129         } else
1130                 mcd_info.speed = 1;
1131         sprintf(msg, " mcd: Mitsumi %s Speed CD-ROM at port=0x%x,"
1132                 " irq=%d\n", mcd_info.speed == 1 ? "Single" : "Double",
1133                 mcd_port, mcd_irq);
1134
1135         outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1136         outb(0x02, MCDPORT(0));
1137         outb(0x00, MCDPORT(0));
1138         getValue(result);
1139
1140         outb(MCMD_CONFIG_DRIVE, MCDPORT(0));
1141         outb(0x10, MCDPORT(0));
1142         outb(0x04, MCDPORT(0));
1143         getValue(result);
1144
1145         mcd_invalidate_buffers();
1146         mcdPresent = 1;
1147
1148         disk->major = MAJOR_NR;
1149         disk->first_minor = 0;
1150         sprintf(disk->disk_name, "mcd");
1151         disk->fops = &mcd_bdops;
1152         disk->flags = GENHD_FL_CD;
1153         mcd_gendisk = disk;
1154
1155         if (register_cdrom(&mcd_info) != 0) {
1156                 printk(KERN_ERR "mcd: Unable to register Mitsumi CD-ROM.\n");
1157                 goto out_cdrom;
1158         }
1159         disk->queue = mcd_queue;
1160         add_disk(disk);
1161         printk(msg);
1162         return 0;
1163
1164 out_cdrom:
1165         free_irq(mcd_irq, NULL);
1166 out_queue:
1167         release_region(mcd_port, 4);
1168 out_probe:
1169         blk_cleanup_queue(mcd_queue);
1170 out_region:
1171         unregister_blkdev(MAJOR_NR, "mcd");
1172         put_disk(disk);
1173         return -EIO;
1174 }
1175
1176
1177 static void hsg2msf(long hsg, struct msf *msf)
1178 {
1179         hsg += 150;
1180         msf->min = hsg / 4500;
1181         hsg %= 4500;
1182         msf->sec = hsg / 75;
1183         msf->frame = hsg % 75;
1184
1185         bin2bcd(&msf->min);     /* convert to BCD */
1186         bin2bcd(&msf->sec);
1187         bin2bcd(&msf->frame);
1188 }
1189
1190
1191 static void bin2bcd(unsigned char *p)
1192 {
1193         int u, t;
1194
1195         u = *p % 10;
1196         t = *p / 10;
1197         *p = u | (t << 4);
1198 }
1199
1200 static int bcd2bin(unsigned char bcd)
1201 {
1202         return (bcd >> 4) * 10 + (bcd & 0xF);
1203 }
1204
1205
1206 /*
1207  * See if a status is ready from the drive and return it
1208  * if it is ready.
1209  */
1210
1211 static int mcdStatus(void)
1212 {
1213         int i;
1214         int st;
1215
1216         st = inb(MCDPORT(1)) & MFL_STATUS;
1217         if (!st) {
1218                 i = inb(MCDPORT(0)) & 0xFF;
1219                 return i;
1220         } else
1221                 return -1;
1222 }
1223
1224
1225 /*
1226  * Send a play or read command to the drive
1227  */
1228
1229 static void sendMcdCmd(int cmd, struct mcd_Play_msf *params)
1230 {
1231         outb(cmd, MCDPORT(0));
1232         outb(params->start.min, MCDPORT(0));
1233         outb(params->start.sec, MCDPORT(0));
1234         outb(params->start.frame, MCDPORT(0));
1235         outb(params->end.min, MCDPORT(0));
1236         outb(params->end.sec, MCDPORT(0));
1237         outb(params->end.frame, MCDPORT(0));
1238 }
1239
1240
1241 /*
1242  * Timer interrupt routine to test for status ready from the drive.
1243  * (see the next routine)
1244  */
1245
1246 static void mcdStatTimer(unsigned long dummy)
1247 {
1248         if (!(inb(MCDPORT(1)) & MFL_STATUS)) {
1249                 wake_up(&mcd_waitq);
1250                 return;
1251         }
1252
1253         McdTimeout--;
1254         if (McdTimeout <= 0) {
1255                 wake_up(&mcd_waitq);
1256                 return;
1257         }
1258         mcd_timer.function = mcdStatTimer;
1259         mod_timer(&mcd_timer, jiffies + 1);
1260 }
1261
1262
1263 /*
1264  * Wait for a status to be returned from the drive.  The actual test
1265  * (see routine above) is done by the timer interrupt to avoid
1266  * excessive rescheduling.
1267  */
1268
1269 static int getMcdStatus(int timeout)
1270 {
1271         int st;
1272
1273         McdTimeout = timeout;
1274         mcd_timer.function = mcdStatTimer;
1275         mod_timer(&mcd_timer, jiffies + 1);
1276         sleep_on(&mcd_waitq);
1277         if (McdTimeout <= 0)
1278                 return -1;
1279
1280         st = inb(MCDPORT(0)) & 0xFF;
1281         if (st == 0xFF)
1282                 return -1;
1283
1284         if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY)
1285                 /* XXX might be an error? look at q-channel? */
1286                 audioStatus = CDROM_AUDIO_COMPLETED;
1287
1288         if (st & MST_DSK_CHG) {
1289                 mcdDiskChanged = 1;
1290                 tocUpToDate = 0;
1291                 audioStatus = CDROM_AUDIO_NO_STATUS;
1292         }
1293
1294         return st;
1295 }
1296
1297
1298 /* gives current state of the drive This function is quite unreliable, 
1299    and should probably be rewritten by someone, eventually... */
1300
1301 int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr)
1302 {
1303         int st;
1304
1305         st = statusCmd();       /* check drive status */
1306         if (st == -1)
1307                 return -EIO;    /* drive doesn't respond */
1308         if ((st & MST_READY))
1309                 return CDS_DISC_OK;
1310         if ((st & MST_DOOR_OPEN))
1311                 return CDS_TRAY_OPEN;
1312         if ((st & MST_DSK_CHG))
1313                 return CDS_NO_DISC;
1314         if ((st & MST_BUSY))
1315                 return CDS_DRIVE_NOT_READY;
1316         return -EIO;
1317 }
1318
1319
1320 /*
1321  * Read a value from the drive.
1322  */
1323
1324 static int getValue(unsigned char *result)
1325 {
1326         int count;
1327         int s;
1328
1329         for (count = 0; count < 2000; count++)
1330                 if (!(inb(MCDPORT(1)) & MFL_STATUS))
1331                         break;
1332
1333         if (count >= 2000) {
1334                 printk("mcd: getValue timeout\n");
1335                 return -1;
1336         }
1337
1338         s = inb(MCDPORT(0)) & 0xFF;
1339         *result = (unsigned char) s;
1340         return 0;
1341 }
1342
1343 /*
1344  * Read the current Q-channel info.  Also used for reading the
1345  * table of contents.
1346  */
1347
1348 int GetQChannelInfo(struct mcd_Toc *qp)
1349 {
1350         unsigned char notUsed;
1351         int retry;
1352
1353         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1354                 outb(MCMD_GET_Q_CHANNEL, MCDPORT(0));
1355                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1356                         break;
1357         }
1358
1359         if (retry >= MCD_RETRY_ATTEMPTS)
1360                 return -1;
1361
1362         if (getValue(&qp->ctrl_addr) < 0)
1363                 return -1;
1364         if (getValue(&qp->track) < 0)
1365                 return -1;
1366         if (getValue(&qp->pointIndex) < 0)
1367                 return -1;
1368         if (getValue(&qp->trackTime.min) < 0)
1369                 return -1;
1370         if (getValue(&qp->trackTime.sec) < 0)
1371                 return -1;
1372         if (getValue(&qp->trackTime.frame) < 0)
1373                 return -1;
1374         if (getValue(&notUsed) < 0)
1375                 return -1;
1376         if (getValue(&qp->diskTime.min) < 0)
1377                 return -1;
1378         if (getValue(&qp->diskTime.sec) < 0)
1379                 return -1;
1380         if (getValue(&qp->diskTime.frame) < 0)
1381                 return -1;
1382
1383         return 0;
1384 }
1385
1386 /*
1387  * Read the table of contents (TOC) and TOC header if necessary
1388  */
1389
1390 static int updateToc(void)
1391 {
1392         if (tocUpToDate)
1393                 return 0;
1394
1395         if (GetDiskInfo() < 0)
1396                 return -EIO;
1397
1398         if (GetToc() < 0)
1399                 return -EIO;
1400
1401         tocUpToDate = 1;
1402         return 0;
1403 }
1404
1405 /*
1406  * Read the table of contents header
1407  */
1408
1409 static int GetDiskInfo(void)
1410 {
1411         int retry;
1412
1413         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1414                 outb(MCMD_GET_DISK_INFO, MCDPORT(0));
1415                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1416                         break;
1417         }
1418
1419         if (retry >= MCD_RETRY_ATTEMPTS)
1420                 return -1;
1421
1422         if (getValue(&DiskInfo.first) < 0)
1423                 return -1;
1424         if (getValue(&DiskInfo.last) < 0)
1425                 return -1;
1426
1427         DiskInfo.first = bcd2bin(DiskInfo.first);
1428         DiskInfo.last = bcd2bin(DiskInfo.last);
1429
1430 #ifdef MCD_DEBUG
1431         printk
1432             ("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n",
1433              DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min,
1434              DiskInfo.diskLength.sec, DiskInfo.diskLength.frame,
1435              DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec,
1436              DiskInfo.firstTrack.frame);
1437 #endif
1438
1439         if (getValue(&DiskInfo.diskLength.min) < 0)
1440                 return -1;
1441         if (getValue(&DiskInfo.diskLength.sec) < 0)
1442                 return -1;
1443         if (getValue(&DiskInfo.diskLength.frame) < 0)
1444                 return -1;
1445         if (getValue(&DiskInfo.firstTrack.min) < 0)
1446                 return -1;
1447         if (getValue(&DiskInfo.firstTrack.sec) < 0)
1448                 return -1;
1449         if (getValue(&DiskInfo.firstTrack.frame) < 0)
1450                 return -1;
1451
1452         return 0;
1453 }
1454
1455 /*
1456  * Read the table of contents (TOC)
1457  */
1458
1459 static int GetToc(void)
1460 {
1461         int i, px;
1462         int limit;
1463         int retry;
1464         struct mcd_Toc qInfo;
1465
1466         for (i = 0; i < MAX_TRACKS; i++)
1467                 Toc[i].pointIndex = 0;
1468
1469         i = DiskInfo.last + 3;
1470
1471         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1472                 outb(MCMD_STOP, MCDPORT(0));
1473                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1474                         break;
1475         }
1476
1477         if (retry >= MCD_RETRY_ATTEMPTS)
1478                 return -1;
1479
1480         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1481                 outb(MCMD_SET_MODE, MCDPORT(0));
1482                 outb(0x05, MCDPORT(0)); /* mode: toc */
1483                 mcd_mode = 0x05;
1484                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1485                         break;
1486         }
1487
1488         if (retry >= MCD_RETRY_ATTEMPTS)
1489                 return -1;
1490
1491         for (limit = 300; limit > 0; limit--) {
1492                 if (GetQChannelInfo(&qInfo) < 0)
1493                         break;
1494
1495                 px = bcd2bin(qInfo.pointIndex);
1496                 if (px > 0 && px < MAX_TRACKS && qInfo.track == 0)
1497                         if (Toc[px].pointIndex == 0) {
1498                                 Toc[px] = qInfo;
1499                                 i--;
1500                         }
1501
1502                 if (i <= 0)
1503                         break;
1504         }
1505
1506         Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength;
1507
1508         for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) {
1509                 outb(MCMD_SET_MODE, MCDPORT(0));
1510                 outb(0x01, MCDPORT(0));
1511                 mcd_mode = 1;
1512                 if (getMcdStatus(MCD_STATUS_DELAY) != -1)
1513                         break;
1514         }
1515
1516 #ifdef MCD_DEBUG
1517         for (i = 1; i <= DiskInfo.last; i++)
1518                 printk
1519                     ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1520                      i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1521                      Toc[i].trackTime.min, Toc[i].trackTime.sec,
1522                      Toc[i].trackTime.frame, Toc[i].diskTime.min,
1523                      Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1524         for (i = 100; i < 103; i++)
1525                 printk
1526                     ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X    %02X:%02X.%02X\n",
1527                      i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex,
1528                      Toc[i].trackTime.min, Toc[i].trackTime.sec,
1529                      Toc[i].trackTime.frame, Toc[i].diskTime.min,
1530                      Toc[i].diskTime.sec, Toc[i].diskTime.frame);
1531 #endif
1532
1533         return limit > 0 ? 0 : -1;
1534 }
1535
1536 void __exit mcd_exit(void)
1537 {
1538         del_gendisk(mcd_gendisk);
1539         put_disk(mcd_gendisk);
1540         if (unregister_cdrom(&mcd_info)) {
1541                 printk(KERN_WARNING "Can't unregister cdrom mcd\n");
1542                 return;
1543         }
1544         free_irq(mcd_irq, NULL);
1545         release_region(mcd_port, 4);
1546         if (unregister_blkdev(MAJOR_NR, "mcd")) {
1547                 printk(KERN_WARNING "Can't unregister major mcd\n");
1548                 return;
1549         }
1550         blk_cleanup_queue(mcd_queue);
1551         del_timer_sync(&mcd_timer);
1552 }
1553
1554 #ifdef MODULE
1555 module_init(mcd_init);
1556 #endif
1557 module_exit(mcd_exit);
1558
1559 MODULE_AUTHOR("Martin Harriss");
1560 MODULE_LICENSE("GPL");
1561 MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_CDROM_MAJOR);