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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 * The Mitsumi CDROM interface
3
 * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de>
4
 * VERSION: 2.14(hs)
5
 *
6
 * ... anyway, I'm back again, thanks to Marcin, he adopted
7
 * large portions of my code (at least the parts containing
8
 * my main thoughts ...)
9
 *
10
 ****************** H E L P *********************************
11
 * If you ever plan to update your CD ROM drive and perhaps
12
 * want to sell or simply give away your Mitsumi FX-001[DS]
13
 * -- Please --
14
 * mail me (heiko@lotte.sax.de).  When my last drive goes
15
 * ballistic no more driver support will be available from me!
16
 *************************************************************
17
 *
18
 * This program is free software; you can redistribute it and/or modify
19
 * it under the terms of the GNU General Public License as published by
20
 * the Free Software Foundation; either version 2, or (at your option)
21
 * any later version.
22
 *
23
 * This program is distributed in the hope that it will be useful,
24
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26
 * GNU General Public License for more details.
27
 *
28
 * You should have received a copy of the GNU General Public License
29
 * along with this program; see the file COPYING.  If not, write to
30
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
31
 *
32
 * Thanks to
33
 *  The Linux Community at all and ...
34
 *  Martin Harriss (he wrote the first Mitsumi Driver)
35
 *  Eberhard Moenkeberg (he gave me much support and the initial kick)
36
 *  Bernd Huebner, Ruediger Helsch (Unifix-Software GmbH, they
37
 *      improved the original driver)
38
 *  Jon Tombs, Bjorn Ekwall (module support)
39
 *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
40
 *  Gerd Knorr (he lent me his PhotoCD)
41
 *  Nils Faerber and Roger E. Wolff (extensively tested the LU portion)
42
 *  Andreas Kies (testing the mysterious hang-ups)
43
 *  Heiko Eissfeldt (VERIFY_READ/WRITE)
44
 *  Marcin Dalecki (improved performance, shortened code)
45
 *  ... somebody forgotten?
46
 *
47
 */
48
 
49
 
50
#if RCS
51
static const char *mcdx_c_version
52
                = "$Id: mcdx.c,v 1.1.1.1 2001-09-10 07:44:13 simons Exp $";
53
#endif
54
 
55
#include <linux/version.h>
56
#include <linux/module.h>
57
 
58
#include <linux/errno.h>
59
#include <linux/sched.h>
60
#include <linux/fs.h>
61
#include <linux/kernel.h>
62
#include <linux/cdrom.h>
63
#include <linux/ioport.h>
64
#include <linux/mm.h>
65
#include <linux/malloc.h>
66
#include <asm/io.h>
67
 
68
#include <linux/major.h>
69
#define MAJOR_NR MITSUMI_X_CDROM_MAJOR
70
#include <linux/blk.h>
71
 
72
/* for compatible parameter passing with "insmod" */
73
#define mcdx_drive_map mcdx    
74
#include <linux/mcdx.h>
75
 
76
#ifndef HZ 
77
#error HZ not defined
78
#endif
79
 
80
#define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
81
 
82
#if !MCDX_QUIET
83
#define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
84
#else
85
#define xinfo(fmt, args...) { ; }
86
#endif
87
 
88
#if MCDX_DEBUG
89
#define xtrace(lvl, fmt, args...) \
90
                { if (lvl > 0) \
91
                        { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
92
#define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
93
#else
94
#define xtrace(lvl, fmt, args...) { ; }
95
#define xdebug(fmt, args...) { ; }
96
#endif
97
 
98
/* CONSTANTS *******************************************************/
99
 
100
/* Following are the number of sectors we _request_ from the drive
101
   every time an access outside the already requested range is done.
102
   The _direct_ size is the number of sectors we're allowed to skip
103
   directly (performing a read instead of requesting the new sector
104
   needed */
105
const int REQUEST_SIZE = 800;   /* should be less then 255 * 4 */
106
const int DIRECT_SIZE = 400;    /* should be less then REQUEST_SIZE */
107
 
108
const unsigned long ACLOSE_INHIBIT = 800;  /* 1/100 s of autoclose inhibit */
109
 
110
enum drivemodes { TOC, DATA, RAW, COOKED };
111
enum datamodes { MODE0, MODE1, MODE2 };
112
enum resetmodes { SOFT, HARD };
113
 
114
const int SINGLE = 0x01;                /* single speed drive (FX001S, LU) */
115
const int DOUBLE = 0x02;                /* double speed drive (FX001D, ..? */
116
const int DOOR   = 0x04;                /* door locking capability */
117
const int MULTI  = 0x08;                /* multi session capability */
118
 
119
const unsigned char READ1X = 0xc0;
120
const unsigned char READ2X = 0xc1;
121
 
122
 
123
/* DECLARATIONS ****************************************************/
124
struct s_subqcode {
125
        unsigned char control;
126
        unsigned char tno;
127
        unsigned char index;
128
        struct cdrom_msf0 tt;
129
        struct cdrom_msf0 dt;
130
};
131
 
132
struct s_diskinfo {
133
        unsigned int n_first;
134
        unsigned int n_last;
135
        struct cdrom_msf0 msf_leadout;
136
        struct cdrom_msf0 msf_first;
137
};
138
 
139
struct s_multi {
140
        unsigned char multi;
141
        struct cdrom_msf0 msf_last;
142
};
143
 
144
struct s_version {
145
        unsigned char code;
146
        unsigned char ver;
147
};
148
 
149
/* Per drive/controller stuff **************************************/
150
 
151
struct s_drive_stuff {
152
        /* waitqueues */
153
    struct wait_queue *busyq;
154
    struct wait_queue *lockq;
155
    struct wait_queue *sleepq;
156
 
157
        /* flags */
158
    volatile int introk;        /* status of last irq operation */
159
    volatile int busy;          /* drive performs an operation */
160
    volatile int lock;          /* exclusive usage */
161
    int eject_sw;           /* 1 - eject on last close (default 0) */
162
    int autoclose;          /* 1 - close the door on open (default 1) */
163
 
164
        /* cd infos */
165
        struct s_diskinfo di;
166
        struct s_multi multi;
167
        struct s_subqcode* toc; /* first entry of the toc array */
168
        struct s_subqcode start;
169
    struct s_subqcode stop;
170
        int xa;                                 /* 1 if xa disk */
171
        int audio;                              /* 1 if audio disk */
172
        int audiostatus;
173
 
174
        /* `buffer' control */
175
    volatile int valid;                 /* pending, ..., values are valid */
176
    volatile int pending;               /* next sector to be read */
177
    volatile int low_border;    /* first sector not to be skipped direct */
178
    volatile int high_border; /* first sector `out of area' */
179
#ifdef AK2
180
    volatile int int_err;
181
#endif /* AK2 */
182
 
183
        /* adds and odds */
184
        void* wreg_data;        /* w data */
185
        void* wreg_reset;       /* w hardware reset */
186
        void* wreg_hcon;        /* w hardware conf */
187
        void* wreg_chn;         /* w channel */
188
        void* rreg_data;        /* r data */
189
        void* rreg_status;      /* r status */
190
 
191
    int irq;                    /* irq used by this drive */
192
    int minor;                  /* minor number of this drive */
193
    int present;            /* drive present and its capabilities */
194
    unsigned char readcmd;      /* read cmd depends on single/double speed */
195
    unsigned char playcmd;  /* play should always be single speed */
196
    unsigned int xxx;      /* set if changed, reset while open */
197
    unsigned int yyy;      /* set if changed, reset by media_changed */
198
    unsigned long ejected;  /* time we called the eject function */
199
    int users;                          /* keeps track of open/close */
200
    int lastsector;                     /* last block accessible */
201
    int status;                         /* last operation's error / status */
202
        int readerrs;                   /* # of blocks read w/o error */
203
};
204
 
205
 
206
/* Prototypes ******************************************************/
207
 
208
/*      The following prototypes are already declared elsewhere.  They are
209
        repeated here to show what's going on.  And to sense, if they're
210
        changed elsewhere. */
211
 
212
/* declared in blk.h */
213
int mcdx_init(void);
214
void do_mcdx_request(void);
215
int check_mcdx_media_change(kdev_t);
216
 
217
/* already declared in init/main */
218
void mcdx_setup(char *, int *);
219
 
220
/*      Indirect exported functions. These functions are exported by their
221
        addresses, such as mcdx_open and mcdx_close in the
222
        structure fops. */
223
 
224
/* ???  exported by the mcdx_sigaction struct */
225
static void mcdx_intr(int, void *, struct pt_regs*);
226
 
227
/* exported by file_ops */
228
static int mcdx_open(struct inode*, struct file*);
229
static void mcdx_close(struct inode*, struct file*);
230
static int mcdx_ioctl(struct inode*, struct file*, unsigned int, unsigned long);
231
 
232
/* misc internal support functions */
233
static void log2msf(unsigned int, struct cdrom_msf0*);
234
static unsigned int msf2log(const struct cdrom_msf0*);
235
static unsigned int uint2bcd(unsigned int);
236
static unsigned int bcd2uint(unsigned char);
237
static char *port(int*);
238
static int irq(int*);
239
static void mcdx_delay(struct s_drive_stuff*, long jifs);
240
static int mcdx_transfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
241
static int mcdx_xfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
242
 
243
static int mcdx_config(struct s_drive_stuff*, int);
244
static int mcdx_closedoor(struct s_drive_stuff*, int);
245
static int mcdx_requestversion(struct s_drive_stuff*, struct s_version*, int);
246
static int mcdx_lockdoor(struct s_drive_stuff*, int, int);
247
static int mcdx_stop(struct s_drive_stuff*, int);
248
static int mcdx_hold(struct s_drive_stuff*, int);
249
static int mcdx_reset(struct s_drive_stuff*, enum resetmodes, int);
250
static int mcdx_eject(struct s_drive_stuff*, int);
251
static int mcdx_setdrivemode(struct s_drive_stuff*, enum drivemodes, int);
252
static int mcdx_setdatamode(struct s_drive_stuff*, enum datamodes, int);
253
static int mcdx_requestsubqcode(struct s_drive_stuff*, struct s_subqcode*, int);
254
static int mcdx_requestmultidiskinfo(struct s_drive_stuff*, struct s_multi*, int);
255
static int mcdx_requesttocdata(struct s_drive_stuff*, struct s_diskinfo*, int);
256
static int mcdx_getstatus(struct s_drive_stuff*, int);
257
static int mcdx_getval(struct s_drive_stuff*, int to, int delay, char*);
258
static int mcdx_talk(struct s_drive_stuff*,
259
                const unsigned char* cmd, size_t,
260
        void *buffer, size_t size,
261
        unsigned int timeout, int);
262
static int mcdx_readtoc(struct s_drive_stuff*);
263
static int mcdx_playtrk(struct s_drive_stuff*, const struct cdrom_ti*);
264
static int mcdx_playmsf(struct s_drive_stuff*, const struct cdrom_msf*);
265
static int mcdx_setattentuator(struct s_drive_stuff*, struct cdrom_volctrl*, int);
266
 
267
/* static variables ************************************************/
268
 
269
static int mcdx_blocksizes[MCDX_NDRIVES];
270
static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
271
static struct s_drive_stuff* mcdx_stuffp[MCDX_NDRIVES];
272
static struct s_drive_stuff* mcdx_irq_map[16] =
273
                {0, 0, 0, 0, 0, 0, 0, 0,
274
                0, 0, 0, 0, 0, 0, 0, 0};
275
 
276
static struct file_operations mcdx_fops = {
277
        NULL,                   /* lseek - use kernel default */
278
        block_read,             /* read - general block-dev read */
279
        block_write,    /* write - general block-dev write */
280
        NULL,                   /* no readdir */
281
        NULL,                   /* no select */
282
        mcdx_ioctl,             /* ioctl() */
283
        NULL,                   /* no mmap */
284
        mcdx_open,              /* open() */
285
        mcdx_close,             /* close() */
286
        NULL,                   /* fsync */
287
        NULL,                     /* fasync */
288
        check_mcdx_media_change,  /* media_change */
289
        NULL                      /* revalidate */
290
};
291
 
292
/* KERNEL INTERFACE FUNCTIONS **************************************/
293
 
294
static int
295
mcdx_ioctl(
296
        struct inode* ip, struct file* fp,
297
        unsigned int cmd, unsigned long arg)
298
{
299
        struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
300
 
301
        if (!stuffp->present) return -ENXIO;
302
        if (!ip) return -EINVAL;
303
 
304
        switch (cmd) {
305
                case CDROMSTART: {
306
                        xtrace(IOCTL, "ioctl() START\n");
307
                        return 0;
308
                }
309
 
310
                case CDROMSTOP: {
311
                        xtrace(IOCTL, "ioctl() STOP\n");
312
            stuffp->audiostatus = CDROM_AUDIO_INVALID;
313
                        if (-1 == mcdx_stop(stuffp, 1))
314
                                return -EIO;
315
                        return 0;
316
                }
317
 
318
                case CDROMPLAYTRKIND: {
319
                        int ans;
320
                        struct cdrom_ti ti;
321
 
322
                        xtrace(IOCTL, "ioctl() PLAYTRKIND\n");
323
                        if ((ans = verify_area(VERIFY_READ, (void*) arg, sizeof(ti))))
324
                                return ans;
325
                        memcpy_fromfs(&ti, (void*) arg, sizeof(ti));
326
                        if ((ti.cdti_trk0 < stuffp->di.n_first)
327
                                        || (ti.cdti_trk0 > stuffp->di.n_last)
328
                                        || (ti.cdti_trk1 < stuffp->di.n_first))
329
                                return -EINVAL;
330
                        if (ti.cdti_trk1 > stuffp->di.n_last) ti.cdti_trk1 = stuffp->di.n_last;
331
            xtrace(PLAYTRK, "ioctl() track %d to %d\n", ti.cdti_trk0, ti.cdti_trk1);
332
 
333
            return mcdx_playtrk(stuffp, &ti);
334
        }
335
 
336
        case CDROMPLAYMSF: {
337
            int ans;
338
            struct cdrom_msf msf;
339
 
340
            xtrace(IOCTL, "ioctl() PLAYMSF\n");
341
 
342
            if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
343
                && (-1 == mcdx_hold(stuffp, 1))) return -EIO;
344
 
345
            if ((ans = verify_area(
346
                    VERIFY_READ, (void*) arg, sizeof(struct cdrom_msf))))
347
                return ans;
348
 
349
            memcpy_fromfs(&msf, (void*) arg, sizeof msf);
350
 
351
            msf.cdmsf_min0 = uint2bcd(msf.cdmsf_min0);
352
            msf.cdmsf_sec0 = uint2bcd(msf.cdmsf_sec0);
353
            msf.cdmsf_frame0 = uint2bcd(msf.cdmsf_frame0);
354
 
355
            msf.cdmsf_min1 = uint2bcd(msf.cdmsf_min1);
356
            msf.cdmsf_sec1 = uint2bcd(msf.cdmsf_sec1);
357
            msf.cdmsf_frame1 = uint2bcd(msf.cdmsf_frame1);
358
 
359
            return mcdx_playmsf(stuffp, &msf);
360
        }
361
 
362
        case CDROMRESUME: {
363
            xtrace(IOCTL, "ioctl() RESUME\n");
364
            return mcdx_playtrk(stuffp, NULL);
365
        }
366
 
367
                case CDROMREADTOCENTRY: {
368
                        struct cdrom_tocentry entry;
369
                        struct s_subqcode *tp = NULL;
370
                        int ans;
371
 
372
                        xtrace(IOCTL, "ioctl() READTOCENTRY\n");
373
 
374
            if (-1 == mcdx_readtoc(stuffp)) return -1;
375
 
376
                        if ((ans = verify_area(VERIFY_WRITE, (void *) arg, sizeof(entry)))) return ans;
377
                        memcpy_fromfs(&entry, (void *) arg, sizeof(entry));
378
 
379
                        if (entry.cdte_track == CDROM_LEADOUT)
380
                                tp = &stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1];
381
                        else if (entry.cdte_track > stuffp->di.n_last
382
                                        || entry.cdte_track < stuffp->di.n_first) return -EINVAL;
383
                        else tp = &stuffp->toc[entry.cdte_track - stuffp->di.n_first];
384
 
385
                        if (NULL == tp) xwarn("FATAL.\n");
386
 
387
                        entry.cdte_adr = tp->control;
388
                        entry.cdte_ctrl = tp->control >> 4;
389
 
390
                        if (entry.cdte_format == CDROM_MSF) {
391
                                entry.cdte_addr.msf.minute = bcd2uint(tp->dt.minute);
392
                                entry.cdte_addr.msf.second = bcd2uint(tp->dt.second);
393
                                entry.cdte_addr.msf.frame = bcd2uint(tp->dt.frame);
394
                        } else if (entry.cdte_format == CDROM_LBA)
395
                                entry.cdte_addr.lba = msf2log(&tp->dt);
396
                        else return -EINVAL;
397
 
398
                        memcpy_tofs((void*) arg, &entry, sizeof(entry));
399
 
400
                        return 0;
401
                }
402
 
403
                case CDROMSUBCHNL: {
404
                        int ans;
405
                        struct cdrom_subchnl sub;
406
                        struct s_subqcode q;
407
 
408
                        xtrace(IOCTL, "ioctl() SUBCHNL\n");
409
 
410
                        if ((ans = verify_area(VERIFY_WRITE,
411
                    (void*) arg, sizeof(sub)))) return ans;
412
 
413
                        memcpy_fromfs(&sub, (void*) arg, sizeof(sub));
414
 
415
                        if (-1 == mcdx_requestsubqcode(stuffp, &q, 2)) return -EIO;
416
 
417
            xtrace(SUBCHNL, "audiostatus: %x\n", stuffp->audiostatus);
418
                        sub.cdsc_audiostatus = stuffp->audiostatus;
419
                        sub.cdsc_adr = q.control;
420
                        sub.cdsc_ctrl = q.control >> 4;
421
                        sub.cdsc_trk = bcd2uint(q.tno);
422
                        sub.cdsc_ind = bcd2uint(q.index);
423
 
424
            xtrace(SUBCHNL, "trk %d, ind %d\n",
425
                    sub.cdsc_trk, sub.cdsc_ind);
426
 
427
                        if (sub.cdsc_format == CDROM_LBA) {
428
                                sub.cdsc_absaddr.lba = msf2log(&q.dt);
429
                                sub.cdsc_reladdr.lba = msf2log(&q.tt);
430
                xtrace(SUBCHNL, "lba: abs %d, rel %d\n",
431
                    sub.cdsc_absaddr.lba,
432
                    sub.cdsc_reladdr.lba);
433
                        } else if (sub.cdsc_format == CDROM_MSF) {
434
                                sub.cdsc_absaddr.msf.minute = bcd2uint(q.dt.minute);
435
                                sub.cdsc_absaddr.msf.second = bcd2uint(q.dt.second);
436
                                sub.cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
437
                                sub.cdsc_reladdr.msf.minute = bcd2uint(q.tt.minute);
438
                                sub.cdsc_reladdr.msf.second = bcd2uint(q.tt.second);
439
                                sub.cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
440
                xtrace(SUBCHNL,
441
                        "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
442
                        sub.cdsc_absaddr.msf.minute,
443
                        sub.cdsc_absaddr.msf.second,
444
                        sub.cdsc_absaddr.msf.frame,
445
                        sub.cdsc_reladdr.msf.minute,
446
                        sub.cdsc_reladdr.msf.second,
447
                        sub.cdsc_reladdr.msf.frame);
448
                        } else return -EINVAL;
449
 
450
                        memcpy_tofs((void*) arg, &sub, sizeof(sub));
451
 
452
                        return 0;
453
                }
454
 
455
                case CDROMREADTOCHDR: {
456
                        struct cdrom_tochdr toc;
457
                        int ans;
458
 
459
                        xtrace(IOCTL, "ioctl() READTOCHDR\n");
460
                        if ((ans = verify_area(VERIFY_WRITE, (void*) arg, sizeof toc)))
461
                                return ans;
462
                        toc.cdth_trk0 = stuffp->di.n_first;
463
                        toc.cdth_trk1 = stuffp->di.n_last;
464
                        memcpy_tofs((void*) arg, &toc, sizeof toc);
465
                        xtrace(TOCHDR, "ioctl() track0 = %d, track1 = %d\n",
466
                                        stuffp->di.n_first, stuffp->di.n_last);
467
                        return 0;
468
                }
469
 
470
                case CDROMPAUSE: {
471
                        xtrace(IOCTL, "ioctl() PAUSE\n");
472
                        if (stuffp->audiostatus != CDROM_AUDIO_PLAY) return -EINVAL;
473
                        if (-1 == mcdx_stop(stuffp, 1)) return -EIO;
474
            stuffp->audiostatus = CDROM_AUDIO_PAUSED;
475
                        if (-1 == mcdx_requestsubqcode(stuffp, &stuffp->start, 1))
476
                                return -EIO;
477
                        return 0;
478
                }
479
 
480
                case CDROMMULTISESSION: {
481
                        int ans;
482
                        struct cdrom_multisession ms;
483
                        xtrace(IOCTL, "ioctl() MULTISESSION\n");
484
                        if (0 != (ans = verify_area(VERIFY_WRITE, (void*) arg,
485
                                        sizeof(struct cdrom_multisession))))
486
                                return ans;
487
 
488
                        memcpy_fromfs(&ms, (void*) arg, sizeof(struct cdrom_multisession));
489
                        if (ms.addr_format == CDROM_MSF) {
490
                                ms.addr.msf.minute = bcd2uint(stuffp->multi.msf_last.minute);
491
                                ms.addr.msf.second = bcd2uint(stuffp->multi.msf_last.second);
492
                                ms.addr.msf.frame = bcd2uint(stuffp->multi.msf_last.frame);
493
                        } else if (ms.addr_format == CDROM_LBA)
494
                                ms.addr.lba = msf2log(&stuffp->multi.msf_last);
495
                        else
496
                                return -EINVAL;
497
                        ms.xa_flag = !!stuffp->multi.multi;
498
 
499
                        memcpy_tofs((void*) arg, &ms, sizeof(struct cdrom_multisession));
500
                        if (ms.addr_format == CDROM_MSF) {
501
                                xtrace(MS,
502
                                                "ioctl() (%d, %02x:%02x.%02x [%02x:%02x.%02x])\n",
503
                                                ms.xa_flag,
504
                                                ms.addr.msf.minute,
505
                                                ms.addr.msf.second,
506
                                                ms.addr.msf.frame,
507
                                                stuffp->multi.msf_last.minute,
508
                                                stuffp->multi.msf_last.second,
509
                                                stuffp->multi.msf_last.frame);
510
                        } else {
511
                            xtrace(MS,
512
                                        "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
513
                                        ms.xa_flag,
514
                                        ms.addr.lba,
515
                                        stuffp->multi.msf_last.minute,
516
                                        stuffp->multi.msf_last.second,
517
                                        stuffp->multi.msf_last.frame);
518
                          }
519
                        return 0;
520
                }
521
 
522
                case CDROMEJECT: {
523
                        xtrace(IOCTL, "ioctl() EJECT\n");
524
                        if (stuffp->users > 1) return -EBUSY;
525
                        if (-1 == mcdx_eject(stuffp, 1)) return -EIO;
526
                        return 0;
527
                }
528
 
529
        case CDROMEJECT_SW: {
530
            stuffp->eject_sw = arg;
531
            return 0;
532
        }
533
 
534
        case CDROMVOLCTRL: {
535
            int ans;
536
            struct cdrom_volctrl volctrl;
537
 
538
            xtrace(IOCTL, "ioctl() VOLCTRL\n");
539
            if ((ans = verify_area(
540
                    VERIFY_READ,
541
                    (void*) arg,
542
                    sizeof(volctrl))))
543
                return ans;
544
 
545
            memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
546
#if 0           /* not tested! */
547
                        /* adjust for the weirdness of workman (md) */
548
                        /* can't test it (hs) */
549
                        volctrl.channel2 = volctrl.channel1;
550
                        volctrl.channel1 = volctrl.channel3 = 0x00;
551
#endif
552
            return mcdx_setattentuator(stuffp, &volctrl, 2);
553
        }
554
 
555
                default:
556
                        xwarn("ioctl(): unknown request 0x%04x\n", cmd);
557
                return -EINVAL;
558
        }
559
}
560
 
561
void do_mcdx_request()
562
{
563
    int dev;
564
    struct s_drive_stuff *stuffp;
565
 
566
  again:
567
 
568
        if (CURRENT == NULL) {
569
                xtrace(REQUEST, "end_request(0): CURRENT == NULL\n");
570
                return;
571
        }
572
 
573
        if (CURRENT->rq_status == RQ_INACTIVE) {
574
                xtrace(REQUEST, "end_request(0): rq_status == RQ_INACTIVE\n");
575
                return;
576
        }
577
 
578
    INIT_REQUEST;
579
 
580
    dev = MINOR(CURRENT->rq_dev);
581
    stuffp = mcdx_stuffp[dev];
582
 
583
        if ((dev < 0)
584
                || (dev >= MCDX_NDRIVES)
585
                || !stuffp
586
                || (!stuffp->present)) {
587
                xwarn("do_request(): bad device: %s\n",
588
                                kdevname(CURRENT->rq_dev));
589
                xtrace(REQUEST, "end_request(0): bad device\n");
590
                end_request(0); return;
591
    }
592
 
593
        if (stuffp->audio) {
594
                xwarn("do_request() attempt to read from audio cd\n");
595
                xtrace(REQUEST, "end_request(0): read from audio\n");
596
                end_request(0); return;
597
        }
598
 
599
        xtrace(REQUEST, "do_request() (%lu + %lu)\n",
600
                        CURRENT->sector, CURRENT->nr_sectors);
601
 
602
    switch (CURRENT->cmd) {
603
      case WRITE:
604
          xwarn("do_request(): attempt to write to cd!!\n");
605
          xtrace(REQUEST, "end_request(0): write\n");
606
          end_request(0); return;
607
 
608
      case READ:
609
          stuffp->status = 0;
610
          while (CURRENT->nr_sectors) {
611
              int i;
612
 
613
              i = mcdx_transfer(stuffp,
614
                                  CURRENT->buffer,
615
                                  CURRENT->sector,
616
                                  CURRENT->nr_sectors);
617
 
618
                  if (i == -1) {
619
                          end_request(0);
620
                          goto again;
621
                  }
622
                  CURRENT->sector += i;
623
                  CURRENT->nr_sectors -= i;
624
                  CURRENT->buffer += (i * 512);
625
          }
626
          end_request(1);
627
          goto again;
628
 
629
          xtrace(REQUEST, "end_request(1)\n");
630
          end_request(1);
631
          break;
632
 
633
      default:
634
          panic(MCDX "do_request: unknown command.\n");
635
          break;
636
    }
637
 
638
    goto again;
639
}
640
 
641
static int
642
mcdx_open(struct inode *ip, struct file *fp)
643
/*  actions done on open:
644
 *  1)  get the drives status
645
 *  2)  set the stuffp.readcmd if a CD is in.
646
 *  (return no error if no CD is found, since ioctl()
647
 *  needs an opened device */
648
{
649
    struct s_drive_stuff *stuffp;
650
 
651
        xtrace(OPENCLOSE, "open()\n");
652
 
653
    stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
654
    if (!stuffp->present) return -ENXIO;
655
 
656
        /* Make the modules looking used ... (thanx bjorn).
657
         * But we shouldn't forget to decrement the module counter
658
         * on error return */
659
        MOD_INC_USE_COUNT;
660
 
661
#if 0
662
        /* We don't allow multiple users of a drive.  In case of data CDs
663
     * they'll be used by mounting, which ensures anyway exclusive
664
         * usage. In case of audio CDs it's meaningless to try playing to
665
         * different tracks at once! (md)
666
         * - Hey, what about cat /dev/cdrom? Why shouldn't it called by
667
         * more then one process at any time?  (hs) */
668
        if (stuffp->users) {
669
                MOD_DEC_USE_COUNT;
670
                return -EBUSY;
671
        }
672
#endif
673
 
674
    /* this is only done to test if the drive talks with us */
675
    if (-1 == mcdx_getstatus(stuffp, 1)) {
676
                MOD_DEC_USE_COUNT;
677
                return -EIO;
678
        }
679
 
680
        /* close the door,
681
         * This should be explained ...
682
         * - If the door is open and its last close is too recent the
683
         *   autoclose wouldn't probably be what we want.
684
         * - If we didn't try to close the door yet, close it and go on.
685
         * - If we autoclosed the door and couldn't succeed in find a valid
686
         *   CD we shouldn't try autoclose any longer (until a valid CD is
687
         *   in.) */
688
 
689
        if (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_DOOR) {
690
        if (jiffies - stuffp->ejected < ACLOSE_INHIBIT) {
691
                        MOD_DEC_USE_COUNT;
692
                        return -EIO;
693
                }
694
        if (stuffp->autoclose) mcdx_closedoor(stuffp, 1);
695
                else {
696
                        MOD_DEC_USE_COUNT;
697
                        return -EIO;
698
                }
699
    }
700
 
701
        /* if the media changed we will have to do a little more */
702
        if (stuffp->xxx) {
703
 
704
                xtrace(OPENCLOSE, "open() media changed\n");
705
        /* but wait - the time of media change will be set at the
706
         * very last of this block - it seems, some of the following
707
         * talk() will detect a media change ... (I think, config()
708
         * is the reason. */
709
 
710
        stuffp->audiostatus = CDROM_AUDIO_INVALID;
711
                stuffp->readcmd = 0;
712
 
713
                /* get the multisession information */
714
                xtrace(OPENCLOSE, "open() Request multisession info\n");
715
                if (-1 == mcdx_requestmultidiskinfo(
716
                                stuffp, &stuffp->multi, 6)) {
717
                        xinfo("No multidiskinfo\n");
718
                        stuffp->autoclose = 0;
719
                        /*
720
                        MOD_DEC_USE_COUNT;
721
                        stuffp->xxx = 0;
722
                        return -EIO;
723
                        */
724
                } else {
725
                        /* we succeeded, so on next open(2) we could try auto close
726
                         * again */
727
                        stuffp->autoclose = 1;
728
 
729
#if !MCDX_QUIET
730
                        if (stuffp->multi.multi > 2)
731
                                xinfo("open() unknown multisession value (%d)\n",
732
                                                stuffp->multi.multi);
733
#endif
734
 
735
                        /* multisession ? */
736
                        if (!stuffp->multi.multi)
737
                                stuffp->multi.msf_last.second = 2;
738
 
739
                        xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
740
                                        stuffp->multi.multi,
741
                                        stuffp->multi.msf_last.minute,
742
                                        stuffp->multi.msf_last.second,
743
                                        stuffp->multi.msf_last.frame);
744
 
745
                { ; } /* got multisession information */
746
 
747
                /* request the disks table of contents (aka diskinfo) */
748
                if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
749
 
750
                        stuffp->lastsector = -1;
751
 
752
                } else {
753
 
754
                        stuffp->lastsector = (CD_FRAMESIZE / 512)
755
                                        * msf2log(&stuffp->di.msf_leadout) - 1;
756
 
757
                        xtrace(OPENCLOSE, "open() start %d (%02x:%02x.%02x) %d\n",
758
                                        stuffp->di.n_first,
759
                                        stuffp->di.msf_first.minute,
760
                                        stuffp->di.msf_first.second,
761
                                        stuffp->di.msf_first.frame,
762
                                        msf2log(&stuffp->di.msf_first));
763
                        xtrace(OPENCLOSE, "open() last %d (%02x:%02x.%02x) %d\n",
764
                                        stuffp->di.n_last,
765
                                        stuffp->di.msf_leadout.minute,
766
                                        stuffp->di.msf_leadout.second,
767
                                        stuffp->di.msf_leadout.frame,
768
                                        msf2log(&stuffp->di.msf_leadout));
769
                }
770
 
771
                if (stuffp->toc) {
772
                        xtrace(MALLOC, "open() free old toc @ %p\n", stuffp->toc);
773
                        kfree(stuffp->toc);
774
 
775
                        stuffp->toc = NULL;
776
                }
777
 
778
                xtrace(OPENCLOSE, "open() init irq generation\n");
779
                if (-1 == mcdx_config(stuffp, 1)) {
780
                        MOD_DEC_USE_COUNT;
781
                        return -EIO;
782
                }
783
 
784
#if FALLBACK
785
                /* Set the read speed */
786
                xwarn("AAA %x AAA\n", stuffp->readcmd);
787
                if (stuffp->readerrs) stuffp->readcmd = READ1X;
788
                else stuffp->readcmd =
789
                                stuffp->present | SINGLE ? READ1X : READ2X;
790
                xwarn("XXX %x XXX\n", stuffp->readcmd);
791
#else
792
                stuffp->readcmd = stuffp->present | SINGLE ? READ1X : READ2X;
793
#endif
794
 
795
                /* try to get the first sector, iff any ... */
796
                if (stuffp->lastsector >= 0) {
797
                        char buf[512];
798
                        int ans;
799
                        int tries;
800
 
801
                        stuffp->xa = 0;
802
                        stuffp->audio = 0;
803
 
804
                        for (tries = 6; tries; tries--) {
805
 
806
                                stuffp->introk = 1;
807
 
808
                                xtrace(OPENCLOSE, "open() try as %s\n",
809
                                        stuffp->xa ? "XA" : "normal");
810
 
811
                                /* set data mode */
812
                                if (-1 == (ans = mcdx_setdatamode(stuffp,
813
                                                stuffp->xa ? MODE2 : MODE1, 1))) {
814
                                        /* MOD_DEC_USE_COUNT, return -EIO; */
815
                                        stuffp->xa = 0;
816
                                        break;
817
                                }
818
 
819
                                if ((stuffp->audio = e_audio(ans))) break;
820
 
821
                                while (0 == (ans = mcdx_transfer(stuffp, buf, 0, 1)))
822
                                        ;
823
 
824
                                if (ans == 1) break;
825
                                stuffp->xa = !stuffp->xa;
826
                        }
827
                        /* if (!tries) MOD_DEC_USE_COUNT, return -EIO; */
828
                }
829
 
830
                /* xa disks will be read in raw mode, others not */
831
                if (-1 == mcdx_setdrivemode(stuffp,
832
                                stuffp->xa ? RAW : COOKED, 1)) {
833
                        MOD_DEC_USE_COUNT;
834
                        return -EIO;
835
                }
836
 
837
                if (stuffp->audio) {
838
                        xinfo("open() audio disk found\n");
839
                } else if (stuffp->lastsector >= 0) {
840
                        xinfo("open() %s%s disk found\n",
841
                                        stuffp->xa ? "XA / " : "",
842
                                        stuffp->multi.multi ? "Multi Session" : "Single Session");
843
                }
844
 
845
        /* stuffp->xxx = 0; */
846
        }
847
 
848
    /* lock the door if not already done */
849
    if (0 == stuffp->users && (-1 == mcdx_lockdoor(stuffp, 1, 1)))  {
850
                MOD_DEC_USE_COUNT;
851
        return -EIO;
852
        }
853
        }
854
 
855
        stuffp->xxx = 0;
856
    stuffp->users++;
857
    return 0;
858
 
859
}
860
 
861
static void
862
mcdx_close(struct inode *ip, struct file *fp)
863
{
864
    struct s_drive_stuff *stuffp;
865
 
866
    xtrace(OPENCLOSE, "close()\n");
867
 
868
    stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
869
 
870
    if (0 == --stuffp->users) {
871
                sync_dev(ip->i_rdev);   /* needed for r/o device? */
872
 
873
                /* invalidate_inodes(ip->i_rdev); */
874
                invalidate_buffers(ip->i_rdev);
875
 
876
 
877
#if !MCDX_QUIET
878
                if (-1 == mcdx_lockdoor(stuffp, 0, 3))
879
                                xinfo("close() Cannot unlock the door\n");
880
#else
881
                mcdx_lockdoor(stuffp, 0, 3);
882
#endif
883
 
884
        /* eject if wished */
885
        if (stuffp->eject_sw) mcdx_eject(stuffp, 1);
886
 
887
    }
888
 
889
    MOD_DEC_USE_COUNT;
890
    return;
891
}
892
 
893
int check_mcdx_media_change(kdev_t full_dev)
894
/*      Return: 1 if media changed since last call to this function
895
 
896
{
897
    struct s_drive_stuff *stuffp;
898
 
899
    xinfo("check_mcdx_media_change called for device %s\n",
900
          kdevname(full_dev));
901
 
902
        stuffp = mcdx_stuffp[MINOR(full_dev)];
903
        mcdx_getstatus(stuffp, 1);
904
 
905
        if (stuffp->yyy == 0) return 0;
906
 
907
        stuffp->yyy = 0;
908
        return 1;
909
}
910
 
911
void mcdx_setup(char *str, int *pi)
912
{
913
        if (pi[0] > 0) mcdx_drive_map[0][0] = pi[1];
914
        if (pi[0] > 1) mcdx_drive_map[0][1] = pi[2];
915
}
916
 
917
/* DIRTY PART ******************************************************/
918
 
919
static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
920
/* This routine is used for sleeping.
921
 * A jifs value <0 means NO sleeping,
922
 *              =0 means minimal sleeping (let the kernel
923
 *                 run for other processes)
924
 *              >0 means at least sleep for that amount.
925
 *      May be we could use a simple count loop w/ jumps to itself, but
926
 *      I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
927
{
928
    unsigned long tout = jiffies + jifs;
929
    if (jifs < 0) return;
930
 
931
        /* If loaded during kernel boot no *_sleep_on is
932
         * allowed! */
933
    if (current->pid == 0) {
934
                while (jiffies < tout) {
935
            current->timeout = jiffies;
936
            schedule();
937
        }
938
    } else {
939
        current->timeout = tout;
940
                xtrace(SLEEP, "*** delay: sleepq\n");
941
                interruptible_sleep_on(&stuff->sleepq);
942
                xtrace(SLEEP, "delay awoken\n");
943
                if (current->signal & ~current->blocked) {
944
                        xtrace(SLEEP, "got signal\n");
945
                }
946
        }
947
}
948
 
949
static void
950
mcdx_intr(int irq, void *dev_id, struct pt_regs* regs)
951
{
952
    struct s_drive_stuff *stuffp;
953
        unsigned char b;
954
 
955
    stuffp = mcdx_irq_map[irq];
956
 
957
    if (stuffp == NULL ) {
958
                xwarn("mcdx: no device for intr %d\n", irq);
959
                return;
960
    }
961
 
962
#ifdef AK2
963
        if ( !stuffp->busy && stuffp->pending )
964
                stuffp->int_err = 1;
965
 
966
#endif /* AK2 */
967
        /* get the interrupt status */
968
        b = inb((unsigned int) stuffp->rreg_status);
969
        stuffp->introk = ~b & MCDX_RBIT_DTEN;
970
 
971
        /* NOTE: We only should get interrupts if the data we
972
         * requested are ready to transfer.
973
         * But the drive seems to generate ``asynchronous'' interrupts
974
         * on several error conditions too.  (Despite the err int enable
975
         * setting during initialisation) */
976
 
977
        /* if not ok, read the next byte as the drives status */
978
        if (!stuffp->introk) {
979
                xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b);
980
                if (~b & MCDX_RBIT_STEN) {
981
                        xinfo(  "intr() irq %d    status 0x%02x\n",
982
                                        irq, inb((unsigned int) stuffp->rreg_data));
983
                } else {
984
                        xinfo(  "intr() irq %d ambiguous hw status\n", irq);
985
                }
986
        } else {
987
                xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b);
988
    }
989
 
990
    stuffp->busy = 0;
991
    wake_up_interruptible(&stuffp->busyq);
992
}
993
 
994
 
995
static int
996
mcdx_talk (
997
                struct s_drive_stuff *stuffp,
998
                const unsigned char *cmd, size_t cmdlen,
999
                void *buffer, size_t size,
1000
                unsigned int timeout, int tries)
1001
/* Send a command to the drive, wait for the result.
1002
 * returns -1 on timeout, drive status otherwise
1003
 * If buffer is not zero, the result (length size) is stored there.
1004
 * If buffer is zero the size should be the number of bytes to read
1005
 * from the drive.  These bytes are discarded.
1006
 */
1007
{
1008
        int st;
1009
    char c;
1010
    int discard;
1011
 
1012
        /* Somebody wants the data read? */
1013
    if ((discard = (buffer == NULL))) buffer = &c;
1014
 
1015
    while (stuffp->lock) {
1016
                xtrace(SLEEP, "*** talk: lockq\n");
1017
                interruptible_sleep_on(&stuffp->lockq);
1018
                xtrace(SLEEP, "talk: awoken\n");
1019
        }
1020
 
1021
    stuffp->lock = 1;
1022
 
1023
        /* An operation other then reading data destroys the
1024
     * data already requested and remembered in stuffp->request, ... */
1025
    stuffp->valid = 0;
1026
 
1027
#if MCDX_DEBUG & TALK
1028
        {
1029
                unsigned char i;
1030
                xtrace(TALK, "talk() %d / %d tries, res.size %d, command 0x%02x",
1031
                                tries, timeout, size, (unsigned char) cmd[0]);
1032
                for (i = 1; i < cmdlen; i++) xtrace(TALK, " 0x%02x", cmd[i]);
1033
                xtrace(TALK, "\n");
1034
        }
1035
#endif
1036
 
1037
    /*  give up if all tries are done (bad) or if the status
1038
     *  st != -1 (good) */
1039
        for (st = -1; st == -1 && tries; tries--) {
1040
 
1041
                char *bp = (char*) buffer;
1042
                size_t sz = size;
1043
 
1044
                outsb((unsigned int) stuffp->wreg_data, cmd, cmdlen);
1045
        xtrace(TALK, "talk() command sent\n");
1046
 
1047
        /* get the status byte */
1048
        if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
1049
            xinfo("talk() %02x timed out (status), %d tr%s left\n",
1050
                    cmd[0], tries - 1, tries == 2 ? "y" : "ies");
1051
                continue;
1052
        }
1053
        st = *bp;
1054
        sz--;
1055
        if (!discard) bp++;
1056
 
1057
        xtrace(TALK, "talk() got status 0x%02x\n", st);
1058
 
1059
        /* command error? */
1060
        if (e_cmderr(st)) {
1061
            xwarn("command error cmd = %02x %s \n",
1062
                    cmd[0], cmdlen > 1 ? "..." : "");
1063
            st = -1;
1064
            continue;
1065
                }
1066
 
1067
        /* audio status? */
1068
        if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
1069
            stuffp->audiostatus =
1070
                    e_audiobusy(st) ? CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS;
1071
        else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
1072
                && e_audiobusy(st) == 0)
1073
            stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
1074
 
1075
        /* media change? */
1076
        if (e_changed(st)) {
1077
            xinfo("talk() media changed\n");
1078
            stuffp->xxx = stuffp->yyy = 1;
1079
        }
1080
 
1081
        /* now actually get the data */
1082
        while (sz--) {
1083
            if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
1084
                xinfo("talk() %02x timed out (data), %d tr%s left\n",
1085
                        cmd[0], tries - 1, tries == 2 ? "y" : "ies");
1086
                st = -1; break;
1087
            }
1088
            if (!discard) bp++;
1089
            xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));
1090
        }
1091
    }
1092
 
1093
#if !MCDX_QUIET
1094
    if (!tries && st == -1) xinfo("talk() giving up\n");
1095
#endif
1096
 
1097
    stuffp->lock = 0;
1098
    wake_up_interruptible(&stuffp->lockq);
1099
 
1100
        xtrace(TALK, "talk() done with 0x%02x\n", st);
1101
    return st;
1102
}
1103
 
1104
/* MODULE STUFF ***********************************************************/
1105
#ifdef MODULE
1106
 
1107
int init_module(void)
1108
{
1109
        int i;
1110
        int drives = 0;
1111
 
1112
        mcdx_init();
1113
        for (i = 0; i < MCDX_NDRIVES; i++)  {
1114
                if (mcdx_stuffp[i]) {
1115
                xtrace(INIT, "init_module() drive %d stuff @ %p\n",
1116
                                i, mcdx_stuffp[i]);
1117
                        drives++;
1118
                }
1119
        }
1120
 
1121
    if (!drives)
1122
                return -EIO;
1123
 
1124
    register_symtab(0);
1125
    return 0;
1126
}
1127
 
1128
void cleanup_module(void)
1129
{
1130
    int i;
1131
 
1132
        xinfo("cleanup_module called\n");
1133
 
1134
    for (i = 0; i < MCDX_NDRIVES; i++) {
1135
                struct s_drive_stuff *stuffp;
1136
                stuffp = mcdx_stuffp[i];
1137
                if (!stuffp) continue;
1138
                release_region((unsigned long) stuffp->wreg_data, MCDX_IO_SIZE);
1139
                free_irq(stuffp->irq, NULL);
1140
                if (stuffp->toc) {
1141
                        xtrace(MALLOC, "cleanup_module() free toc @ %p\n", stuffp->toc);
1142
                        kfree(stuffp->toc);
1143
                }
1144
                xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n", stuffp);
1145
                mcdx_stuffp[i] = NULL;
1146
                kfree(stuffp);
1147
    }
1148
 
1149
    if (unregister_blkdev(MAJOR_NR, DEVICE_NAME) != 0) {
1150
        xwarn("cleanup() unregister_blkdev() failed\n");
1151
    }
1152
#if !MCDX_QUIET
1153
        else xinfo("cleanup() succeeded\n");
1154
#endif
1155
}
1156
 
1157
#endif MODULE
1158
 
1159
/* Support functions ************************************************/
1160
 
1161
int mcdx_init(void)
1162
{
1163
        int drive;
1164
 
1165
#ifdef MODULE
1166
        xwarn("Version 2.14(hs) for %s\n", kernel_version);
1167
#else
1168
        xwarn("Version 2.14(hs) \n");
1169
#endif
1170
 
1171
        xwarn("$Id: mcdx.c,v 1.1.1.1 2001-09-10 07:44:13 simons Exp $\n");
1172
 
1173
        /* zero the pointer array */
1174
        for (drive = 0; drive < MCDX_NDRIVES; drive++)
1175
                mcdx_stuffp[drive] = NULL;
1176
 
1177
        /* do the initialisation */
1178
        for (drive = 0; drive < MCDX_NDRIVES; drive++) {
1179
                struct s_version version;
1180
                struct s_drive_stuff* stuffp;
1181
        int size;
1182
 
1183
                mcdx_blocksizes[drive] = 0;
1184
 
1185
        size = sizeof(*stuffp);
1186
 
1187
                xtrace(INIT, "init() try drive %d\n", drive);
1188
 
1189
        xtrace(INIT, "kmalloc space for stuffpt's\n");
1190
                xtrace(MALLOC, "init() malloc %d bytes\n", size);
1191
                if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
1192
                        xwarn("init() malloc failed\n");
1193
                        break;
1194
                }
1195
 
1196
                xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n", sizeof(*stuffp), stuffp);
1197
 
1198
                /* set default values */
1199
                memset(stuffp, 0, sizeof(*stuffp));
1200
        stuffp->autoclose = 1;      /* close the door on open(2) */
1201
 
1202
                stuffp->present = 0;             /* this should be 0 already */
1203
                stuffp->toc = NULL;                     /* this should be NULL already */
1204
 
1205
                /* setup our irq and i/o addresses */
1206
                stuffp->irq = irq(mcdx_drive_map[drive]);
1207
                stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]);
1208
                stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
1209
                stuffp->wreg_hcon = stuffp->wreg_reset + 1;
1210
                stuffp->wreg_chn = stuffp->wreg_hcon + 1;
1211
 
1212
                /* check if i/o addresses are available */
1213
                if (0 != check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) {
1214
            xwarn("0x%3p,%d: "
1215
                    "Init failed. I/O ports (0x%3p..0x%3p) already in use.\n",
1216
                    stuffp->wreg_data, stuffp->irq,
1217
                    stuffp->wreg_data,
1218
                    stuffp->wreg_data + MCDX_IO_SIZE - 1);
1219
                        xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1220
            kfree(stuffp);
1221
                        xtrace(INIT, "init() continue at next drive\n");
1222
                        continue; /* next drive */
1223
                }
1224
 
1225
                xtrace(INIT, "init() i/o port is available at 0x%3p\n", stuffp->wreg_data);
1226
 
1227
                xtrace(INIT, "init() hardware reset\n");
1228
                mcdx_reset(stuffp, HARD, 1);
1229
 
1230
                xtrace(INIT, "init() get version\n");
1231
                if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
1232
                        /* failed, next drive */
1233
            xwarn("%s=0x%3p,%d: Init failed. Can't get version.\n",
1234
                    MCDX,
1235
                    stuffp->wreg_data, stuffp->irq);
1236
                        xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1237
            kfree(stuffp);
1238
                        xtrace(INIT, "init() continue at next drive\n");
1239
                        continue;
1240
                }
1241
 
1242
                switch (version.code) {
1243
                case 'D':
1244
                stuffp->readcmd = READ2X;
1245
                stuffp->present = DOUBLE | DOOR | MULTI;
1246
                break;
1247
                case 'F':
1248
                stuffp->readcmd = READ1X;
1249
                stuffp->present = SINGLE | DOOR | MULTI;
1250
                break;
1251
                case 'M':
1252
                stuffp->readcmd = READ1X;
1253
                stuffp->present = SINGLE;
1254
                break;
1255
                default:
1256
                stuffp->present = 0; break;
1257
                }
1258
 
1259
        stuffp->playcmd = READ1X;
1260
 
1261
 
1262
                if (!stuffp->present) {
1263
            xwarn("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n",
1264
                    MCDX, stuffp->wreg_data, stuffp->irq);
1265
                        kfree(stuffp);
1266
                        continue; /* next drive */
1267
                }
1268
 
1269
                xtrace(INIT, "init() register blkdev\n");
1270
                if (register_blkdev(MAJOR_NR, DEVICE_NAME, &mcdx_fops) != 0) {
1271
            xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n",
1272
                    MCDX,
1273
                    stuffp->wreg_data, stuffp->irq, MAJOR_NR);
1274
                        kfree(stuffp);
1275
                        continue; /* next drive */
1276
                }
1277
 
1278
                blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1279
                read_ahead[MAJOR_NR] = READ_AHEAD;
1280
 
1281
                blksize_size[MAJOR_NR] = mcdx_blocksizes;
1282
 
1283
                xtrace(INIT, "init() subscribe irq and i/o\n");
1284
                mcdx_irq_map[stuffp->irq] = stuffp;
1285
                if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, DEVICE_NAME, NULL)) {
1286
            xwarn("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n",
1287
                    MCDX,
1288
                    stuffp->wreg_data, stuffp->irq, stuffp->irq);
1289
                        stuffp->irq = 0;
1290
                        kfree(stuffp);
1291
                        continue;
1292
                }
1293
                request_region((unsigned int) stuffp->wreg_data,
1294
                MCDX_IO_SIZE,
1295
                DEVICE_NAME);
1296
 
1297
                xtrace(INIT, "init() get garbage\n");
1298
                {
1299
                        int i;
1300
                        mcdx_delay(stuffp, HZ/2);
1301
                        for (i = 100; i; i--) (void) inb((unsigned int) stuffp->rreg_status);
1302
                }
1303
 
1304
 
1305
#if WE_KNOW_WHY
1306
                        outb(0x50, (unsigned int) stuffp->wreg_chn);    /* irq 11 -> channel register */
1307
#endif
1308
 
1309
                xtrace(INIT, "init() set non dma but irq mode\n");
1310
                mcdx_config(stuffp, 1);
1311
 
1312
                stuffp->minor = drive;
1313
 
1314
                xwarn("(%s) installed at 0x%3p, irq %d."
1315
                           " (Firmware version %c %x)\n",
1316
                           DEVICE_NAME,
1317
                           stuffp->wreg_data, stuffp->irq, version.code,
1318
               version.ver);
1319
                mcdx_stuffp[drive] = stuffp;
1320
                xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp);
1321
        }
1322
 
1323
        return 0;
1324
}
1325
 
1326
static int
1327
mcdx_transfer(struct s_drive_stuff *stuffp,
1328
                char *p, int sector, int nr_sectors)
1329
/*      This seems to do the actually transfer.  But it does more.  It
1330
        keeps track of errors occurred and will (if possible) fall back
1331
        to single speed on error.
1332
        Return: -1 on timeout or other error
1333
                        else status byte (as in stuff->st) */
1334
{
1335
        int ans;
1336
 
1337
        ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
1338
        return ans;
1339
#if FALLBACK
1340
        if (-1 == ans) stuffp->readerrs++;
1341
        else return ans;
1342
 
1343
        if (stuffp->readerrs && stuffp->readcmd == READ1X) {
1344
                xwarn("XXX Already reading 1x -- no chance\n");
1345
                return -1;
1346
        }
1347
 
1348
        xwarn("XXX Fallback to 1x\n");
1349
 
1350
        stuffp->readcmd = READ1X;
1351
        return mcdx_transfer(stuffp, p, sector, nr_sectors);
1352
#endif
1353
 
1354
}
1355
 
1356
 
1357
static int mcdx_xfer(struct s_drive_stuff *stuffp,
1358
                char *p, int sector, int nr_sectors)
1359
/*      This does actually the transfer from the drive.
1360
        Return: -1 on timeout or other error
1361
                        else status byte (as in stuff->st) */
1362
{
1363
    int border;
1364
    int done = 0;
1365
 
1366
        if (stuffp->audio) {
1367
                        xwarn("Attempt to read from audio CD.\n");
1368
                        return -1;
1369
        }
1370
 
1371
        if (!stuffp->readcmd) {
1372
                        xinfo("Can't transfer from missing disk.\n");
1373
                        return -1;
1374
        }
1375
 
1376
    while (stuffp->lock) {
1377
                interruptible_sleep_on(&stuffp->lockq);
1378
        }
1379
 
1380
    if (stuffp->valid
1381
                        && (sector >= stuffp->pending)
1382
                        && (sector < stuffp->low_border)) {
1383
 
1384
                /* All (or at least a part of the sectors requested) seems
1385
         * to be already requested, so we don't need to bother the
1386
                 * drive with new requests ...
1387
                 * Wait for the drive become idle, but first
1388
                 * check for possible occurred errors --- the drive
1389
                 * seems to report them asynchronously */
1390
 
1391
 
1392
        border = stuffp->high_border < (border = sector + nr_sectors)
1393
                        ? stuffp->high_border : border;
1394
 
1395
        stuffp->lock = current->pid;
1396
 
1397
        do {
1398
 
1399
            current->timeout = jiffies + 5 * HZ;
1400
            while (stuffp->busy) {
1401
 
1402
                        interruptible_sleep_on(&stuffp->busyq);
1403
 
1404
                        if (!stuffp->introk) { xtrace(XFER, "error via interrupt\n"); }
1405
                        else if (current->timeout == 0) { xtrace(XFER, "timeout\n"); }
1406
                        else if (current->signal & ~current->blocked) {
1407
                                xtrace(XFER, "signal\n");
1408
                        } else continue;
1409
 
1410
                        stuffp->lock = 0;
1411
                        stuffp->busy = 0;
1412
                        stuffp->valid = 0;
1413
 
1414
                        wake_up_interruptible(&stuffp->lockq);
1415
                        xtrace(XFER, "transfer() done (-1)\n");
1416
                        return -1;
1417
            }
1418
 
1419
                /* check if we need to set the busy flag (as we
1420
                 * expect an interrupt */
1421
                stuffp->busy = (3 == (stuffp->pending & 3));
1422
 
1423
                /* Test if it's the first sector of a block,
1424
                 * there we have to skip some bytes as we read raw data */
1425
                if (stuffp->xa && (0 == (stuffp->pending & 3))) {
1426
                        const int HEAD = CD_FRAMESIZE_RAW - CD_XA_TAIL - CD_FRAMESIZE;
1427
                        insb((unsigned int) stuffp->rreg_data, p, HEAD);
1428
                }
1429
 
1430
                /* now actually read the data */
1431
            insb((unsigned int) stuffp->rreg_data, p, 512);
1432
 
1433
                /* test if it's the last sector of a block,
1434
                 * if so, we have to handle XA special */
1435
                if ((3 == (stuffp->pending & 3)) && stuffp->xa) {
1436
                        char dummy[CD_XA_TAIL];
1437
                        insb((unsigned int) stuffp->rreg_data, &dummy[0], CD_XA_TAIL);
1438
                }
1439
 
1440
            if (stuffp->pending == sector) {
1441
                        p += 512;
1442
                        done++;
1443
                        sector++;
1444
            }
1445
        } while (++(stuffp->pending) < border);
1446
 
1447
        stuffp->lock = 0;
1448
        wake_up_interruptible(&stuffp->lockq);
1449
 
1450
    } else {
1451
 
1452
                /* The requested sector(s) is/are out of the
1453
                 * already requested range, so we have to bother the drive
1454
                 * with a new request. */
1455
 
1456
                static unsigned char cmd[] = {
1457
                        0,
1458
                        0, 0, 0,
1459
                        0, 0, 0
1460
                };
1461
 
1462
                cmd[0] = stuffp->readcmd;
1463
 
1464
                /* The numbers held in ->pending, ..., should be valid */
1465
                stuffp->valid = 1;
1466
                stuffp->pending = sector & ~3;
1467
 
1468
                /* do some sanity checks */
1469
                if (stuffp->pending > stuffp->lastsector) {
1470
                        xwarn("transfer() sector %d from nirvana requested.\n",
1471
                                stuffp->pending);
1472
                        stuffp->status = MCDX_ST_EOM;
1473
                        stuffp->valid = 0;
1474
                        xtrace(XFER, "transfer() done (-1)\n");
1475
                        return -1;
1476
                }
1477
 
1478
                if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)
1479
                                > stuffp->lastsector + 1) {
1480
                        xtrace(XFER, "cut low_border\n");
1481
                        stuffp->low_border = stuffp->lastsector + 1;
1482
                }
1483
                if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE)
1484
                                > stuffp->lastsector + 1) {
1485
                        xtrace(XFER,  "cut high_border\n");
1486
                        stuffp->high_border = stuffp->lastsector + 1;
1487
                }
1488
 
1489
                {       /* Convert the sector to be requested to MSF format */
1490
                        struct cdrom_msf0 pending;
1491
                        log2msf(stuffp->pending / 4, &pending);
1492
                        cmd[1] = pending.minute;
1493
                        cmd[2] = pending.second;
1494
                        cmd[3] = pending.frame;
1495
                }
1496
 
1497
                cmd[6] = (unsigned char) ((stuffp->high_border - stuffp->pending) / 4);
1498
                xtrace(XFER, "[%2d]\n", cmd[6]);
1499
 
1500
                stuffp->busy = 1;
1501
                /* Now really issue the request command */
1502
                outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
1503
 
1504
    }
1505
#ifdef AK2
1506
        if ( stuffp->int_err ) {
1507
                stuffp->valid = 0;
1508
                stuffp->int_err = 0;
1509
                return -1;
1510
        }
1511
#endif /* AK2 */
1512
 
1513
    stuffp->low_border = (stuffp->low_border += done) < stuffp->high_border
1514
            ? stuffp->low_border : stuffp->high_border;
1515
 
1516
    return done;
1517
}
1518
 
1519
 
1520
/*      Access to elements of the mcdx_drive_map members */
1521
 
1522
static char* port(int *ip) { return (char*) ip[0]; }
1523
static int irq(int *ip) { return ip[1]; }
1524
 
1525
/*      Misc number converters */
1526
 
1527
static unsigned int bcd2uint(unsigned char c)
1528
{ return (c >> 4) * 10 + (c & 0x0f); }
1529
 
1530
static unsigned int uint2bcd(unsigned int ival)
1531
{ return ((ival / 10) << 4) | (ival % 10); }
1532
 
1533
static void log2msf(unsigned int l, struct cdrom_msf0* pmsf)
1534
{
1535
    l += CD_BLOCK_OFFSET;
1536
    pmsf->minute = uint2bcd(l / 4500), l %= 4500;
1537
    pmsf->second = uint2bcd(l / 75);
1538
    pmsf->frame = uint2bcd(l % 75);
1539
}
1540
 
1541
static unsigned int msf2log(const struct cdrom_msf0* pmsf)
1542
{
1543
    return bcd2uint(pmsf->frame)
1544
    + bcd2uint(pmsf->second) * 75
1545
    + bcd2uint(pmsf->minute) * 4500
1546
    - CD_BLOCK_OFFSET;
1547
}
1548
 
1549
int mcdx_readtoc(struct s_drive_stuff* stuffp)
1550
/*  Read the toc entries from the CD,
1551
 *  Return: -1 on failure, else 0 */
1552
{
1553
 
1554
        if (stuffp->toc) {
1555
                xtrace(READTOC, "ioctl() toc already read\n");
1556
                return 0;
1557
        }
1558
 
1559
        xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
1560
                        stuffp->di.n_last - stuffp->di.n_first + 1);
1561
 
1562
    if (-1 == mcdx_hold(stuffp, 1)) return -1;
1563
 
1564
        xtrace(READTOC, "ioctl() tocmode\n");
1565
        if (-1 == mcdx_setdrivemode(stuffp, TOC, 1)) return -EIO;
1566
 
1567
        /* all seems to be ok so far ... malloc */
1568
        {
1569
                int size;
1570
                size = sizeof(struct s_subqcode) * (stuffp->di.n_last - stuffp->di.n_first + 2);
1571
 
1572
                xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
1573
                stuffp->toc = kmalloc(size, GFP_KERNEL);
1574
                if (!stuffp->toc) {
1575
                        xwarn("Cannot malloc %d bytes for toc\n", size);
1576
                        mcdx_setdrivemode(stuffp, DATA, 1);
1577
                        return -EIO;
1578
                }
1579
        }
1580
 
1581
        /* now read actually the index */
1582
        {
1583
                int trk;
1584
                int retries;
1585
 
1586
                for (trk = 0;
1587
                                trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
1588
                                trk++)
1589
                        stuffp->toc[trk].index = 0;
1590
 
1591
                for (retries = 300; retries; retries--) { /* why 300? */
1592
                        struct s_subqcode q;
1593
                        unsigned int idx;
1594
 
1595
                        if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
1596
                                mcdx_setdrivemode(stuffp, DATA, 1);
1597
                                return -EIO;
1598
                        }
1599
 
1600
                        idx = bcd2uint(q.index);
1601
 
1602
                        if ((idx > 0)
1603
                                        && (idx <= stuffp->di.n_last)
1604
                                        && (q.tno == 0)
1605
                                        && (stuffp->toc[idx - stuffp->di.n_first].index == 0)) {
1606
                                stuffp->toc[idx - stuffp->di.n_first] = q;
1607
                                xtrace(READTOC, "ioctl() toc idx %d (trk %d)\n", idx, trk);
1608
                                trk--;
1609
                        }
1610
                        if (trk == 0) break;
1611
                }
1612
                memset(&stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1],
1613
                                0, sizeof(stuffp->toc[0]));
1614
                stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1].dt
1615
                                = stuffp->di.msf_leadout;
1616
        }
1617
 
1618
        /* unset toc mode */
1619
        xtrace(READTOC, "ioctl() undo toc mode\n");
1620
        if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
1621
                return -EIO;
1622
 
1623
#if MCDX_DEBUG && READTOC
1624
        { int trk;
1625
        for (trk = 0;
1626
                        trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
1627
                        trk++)
1628
                xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
1629
                                "  %02x:%02x.%02x  %02x:%02x.%02x\n",
1630
                                trk + stuffp->di.n_first,
1631
                                stuffp->toc[trk].control, stuffp->toc[trk].tno, stuffp->toc[trk].index,
1632
                                stuffp->toc[trk].tt.minute, stuffp->toc[trk].tt.second, stuffp->toc[trk].tt.frame,
1633
                                stuffp->toc[trk].dt.minute, stuffp->toc[trk].dt.second, stuffp->toc[trk].dt.frame);
1634
        }
1635
#endif
1636
 
1637
        return 0;
1638
}
1639
 
1640
static int
1641
mcdx_playmsf(struct s_drive_stuff* stuffp, const struct cdrom_msf* msf)
1642
{
1643
    unsigned char cmd[7] = {
1644
        0, 0, 0, 0, 0, 0, 0
1645
    };
1646
 
1647
        if (!stuffp->readcmd) {
1648
                xinfo("Can't play from missing disk.\n");
1649
                return -1;
1650
        }
1651
 
1652
    cmd[0] = stuffp->playcmd;
1653
 
1654
    cmd[1] = msf->cdmsf_min0;
1655
    cmd[2] = msf->cdmsf_sec0;
1656
    cmd[3] = msf->cdmsf_frame0;
1657
    cmd[4] = msf->cdmsf_min1;
1658
    cmd[5] = msf->cdmsf_sec1;
1659
    cmd[6] = msf->cdmsf_frame1;
1660
 
1661
    xtrace(PLAYMSF, "ioctl(): play %x "
1662
            "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1663
            cmd[0], cmd[1], cmd[2], cmd[3],
1664
            cmd[4], cmd[5], cmd[6]);
1665
 
1666
    outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
1667
 
1668
    if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
1669
        xwarn("playmsf() timeout\n");
1670
        return -1;
1671
    }
1672
 
1673
    stuffp->audiostatus = CDROM_AUDIO_PLAY;
1674
    return 0;
1675
}
1676
 
1677
static int
1678
mcdx_playtrk(struct s_drive_stuff* stuffp, const struct cdrom_ti* ti)
1679
{
1680
    struct s_subqcode* p;
1681
    struct cdrom_msf msf;
1682
 
1683
    if (-1 == mcdx_readtoc(stuffp)) return -1;
1684
 
1685
    if (ti) p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
1686
    else p = &stuffp->start;
1687
 
1688
    msf.cdmsf_min0 = p->dt.minute;
1689
    msf.cdmsf_sec0 = p->dt.second;
1690
    msf.cdmsf_frame0 = p->dt.frame;
1691
 
1692
    if (ti) {
1693
        p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
1694
        stuffp->stop = *p;
1695
    } else p = &stuffp->stop;
1696
 
1697
    msf.cdmsf_min1 = p->dt.minute;
1698
    msf.cdmsf_sec1 = p->dt.second;
1699
    msf.cdmsf_frame1 = p->dt.frame;
1700
 
1701
    return mcdx_playmsf(stuffp, &msf);
1702
}
1703
 
1704
 
1705
/* Drive functions ************************************************/
1706
 
1707
static int
1708
mcdx_closedoor(struct s_drive_stuff *stuffp, int tries)
1709
{
1710
        if (stuffp->present & DOOR)
1711
                return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, tries);
1712
        else
1713
                return 0;
1714
}
1715
 
1716
static int
1717
mcdx_stop(struct s_drive_stuff *stuffp, int tries)
1718
{ return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries); }
1719
 
1720
static int
1721
mcdx_hold(struct s_drive_stuff *stuffp, int tries)
1722
{ return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries); }
1723
 
1724
static int
1725
mcdx_eject(struct s_drive_stuff *stuffp, int tries)
1726
{
1727
        if (stuffp->present & DOOR) {
1728
        stuffp->ejected = jiffies;
1729
                return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, tries);
1730
    } else return 0;
1731
}
1732
 
1733
static int
1734
mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
1735
        struct s_subqcode *sub,
1736
        int tries)
1737
{
1738
        char buf[11];
1739
        int ans;
1740
 
1741
        if (-1 == (ans = mcdx_talk(
1742
            stuffp, "\x20", 1, buf, sizeof(buf),
1743
            2 * HZ, tries)))
1744
        return -1;
1745
        sub->control = buf[1];
1746
        sub->tno = buf[2];
1747
        sub->index = buf[3];
1748
        sub->tt.minute = buf[4];
1749
        sub->tt.second = buf[5];
1750
        sub->tt.frame = buf[6];
1751
        sub->dt.minute = buf[8];
1752
        sub->dt.second = buf[9];
1753
        sub->dt.frame = buf[10];
1754
 
1755
        return ans;
1756
}
1757
 
1758
static int
1759
mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp, struct s_multi *multi, int tries)
1760
{
1761
        char buf[5];
1762
        int ans;
1763
 
1764
    if (stuffp->present & MULTI) {
1765
                ans = mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ, tries);
1766
                multi->multi = buf[1];
1767
        multi->msf_last.minute = buf[2];
1768
        multi->msf_last.second = buf[3];
1769
        multi->msf_last.frame = buf[4];
1770
        return ans;
1771
    } else {
1772
        multi->multi = 0;
1773
        return 0;
1774
    }
1775
}
1776
 
1777
static int
1778
mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info, int tries)
1779
{
1780
        char buf[9];
1781
        int ans;
1782
        ans = mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
1783
        if (ans == -1) {
1784
                info->n_first = 0;
1785
                info->n_last = 0;
1786
        } else {
1787
                info->n_first = bcd2uint(buf[1]);
1788
                info->n_last = bcd2uint(buf[2]);
1789
                info->msf_leadout.minute = buf[3];
1790
                info->msf_leadout.second = buf[4];
1791
                info->msf_leadout.frame = buf[5];
1792
                info->msf_first.minute = buf[6];
1793
                info->msf_first.second = buf[7];
1794
                info->msf_first.frame = buf[8];
1795
        }
1796
        return ans;
1797
}
1798
 
1799
static int
1800
mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode, int tries)
1801
{
1802
        char cmd[2];
1803
        int ans;
1804
 
1805
        xtrace(HW, "setdrivemode() %d\n", mode);
1806
 
1807
        if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
1808
                return -1;
1809
 
1810
        switch (mode) {
1811
          case TOC: cmd[1] |= 0x04; break;
1812
          case DATA: cmd[1] &= ~0x04; break;
1813
          case RAW: cmd[1] |= 0x40; break;
1814
          case COOKED: cmd[1] &= ~0x40; break;
1815
          default: break;
1816
        }
1817
        cmd[0] = 0x50;
1818
        return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1819
}
1820
 
1821
static int
1822
mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode, int tries)
1823
{
1824
        unsigned char cmd[2] = { 0xa0 };
1825
        xtrace(HW, "setdatamode() %d\n", mode);
1826
        switch (mode) {
1827
          case MODE0: cmd[1] = 0x00; break;
1828
          case MODE1: cmd[1] = 0x01; break;
1829
          case MODE2: cmd[1] = 0x02; break;
1830
          default: return -EINVAL;
1831
        }
1832
        return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1833
}
1834
 
1835
static int
1836
mcdx_config(struct s_drive_stuff *stuffp, int tries)
1837
{
1838
        char cmd[4];
1839
 
1840
        xtrace(HW, "config()\n");
1841
 
1842
        cmd[0] = 0x90;
1843
 
1844
        cmd[1] = 0x10;          /* irq enable */
1845
        cmd[2] = 0x05;          /* pre, err irq enable */
1846
 
1847
        if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
1848
                return -1;
1849
 
1850
        cmd[1] = 0x02;          /* dma select */
1851
        cmd[2] = 0x00;          /* no dma */
1852
 
1853
        return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
1854
}
1855
 
1856
static int
1857
mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver, int tries)
1858
{
1859
        char buf[3];
1860
        int ans;
1861
 
1862
        if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
1863
                        1, buf, sizeof(buf), 2 * HZ, tries)))
1864
                return ans;
1865
 
1866
        ver->code = buf[1];
1867
        ver->ver = buf[2];
1868
 
1869
        return ans;
1870
}
1871
 
1872
static int
1873
mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
1874
{
1875
        if (mode == HARD) {
1876
                outb(0, (unsigned int) stuffp->wreg_chn);                /* no dma, no irq -> hardware */
1877
                outb(0, (unsigned int) stuffp->wreg_reset);              /* hw reset */
1878
                return 0;
1879
        } else return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
1880
}
1881
 
1882
static int
1883
mcdx_lockdoor(struct s_drive_stuff *stuffp, int lock, int tries)
1884
{
1885
        char cmd[2] = { 0xfe };
1886
    if (stuffp->present & DOOR) {
1887
        cmd[1] = lock ? 0x01 : 0x00;
1888
        return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, tries);
1889
    } else return 0;
1890
}
1891
 
1892
static int
1893
mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
1894
{ return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries); }
1895
 
1896
static int
1897
mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char* buf)
1898
{
1899
    unsigned long timeout = to + jiffies;
1900
    char c;
1901
 
1902
    if (!buf) buf = &c;
1903
 
1904
    while (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_STEN) {
1905
        if (jiffies > timeout) return -1;
1906
        mcdx_delay(stuffp, delay);
1907
    }
1908
 
1909
    *buf = (unsigned char) inb((unsigned int) stuffp->rreg_data) & 0xff;
1910
 
1911
    return 0;
1912
}
1913
 
1914
static int
1915
mcdx_setattentuator(
1916
        struct s_drive_stuff* stuffp,
1917
        struct cdrom_volctrl* vol,
1918
        int tries)
1919
{
1920
    char cmd[5];
1921
    cmd[0] = 0xae;
1922
    cmd[1] = vol->channel0;
1923
    cmd[2] = 0;
1924
    cmd[3] = vol->channel1;
1925
    cmd[4] = 0;
1926
 
1927
    return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
1928
}
1929
 
1930
/* ex:set ts=4 sw=4 ai si: */

powered by: WebSVN 2.1.0

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