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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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