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