OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [cdrom/] [mcd.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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");

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.