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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [drivers/] [cdrom/] [mcd.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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