2 * The Mitsumi CDROM interface
3 * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de>
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 ...)
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]
14 * mail me (heiko@lotte.sax.de). When my last drive goes
15 * ballistic no more driver support will be available from me!
16 *************************************************************
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)
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.
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.
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?
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>
55 static const char *mcdx_c_version
56 = "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $";
59 #include <linux/version.h>
60 #include <linux/module.h>
62 #include <linux/errno.h>
63 #include <linux/sched.h>
65 #include <linux/kernel.h>
66 #include <linux/cdrom.h>
67 #include <linux/ioport.h>
69 #include <linux/malloc.h>
70 #include <linux/init.h>
72 #include <asm/uaccess.h>
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>
79 /* for compatible parameter passing with "insmod" */
80 #define mcdx_drive_map mcdx
87 #define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
90 #define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
92 #define xinfo(fmt, args...) { ; }
96 #define xtrace(lvl, fmt, args...) \
98 { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
99 #define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
101 #define xtrace(lvl, fmt, args...) { ; }
102 #define xdebug(fmt, args...) { ; }
105 /* CONSTANTS *******************************************************/
107 /* Following are the number of sectors we _request_ from the drive
108 every time an access outside the already requested range is done.
109 The _direct_ size is the number of sectors we're allowed to skip
110 directly (performing a read instead of requesting the new sector
112 const int REQUEST_SIZE
= 800; /* should be less then 255 * 4 */
113 const int DIRECT_SIZE
= 400; /* should be less then REQUEST_SIZE */
115 enum drivemodes
{ TOC
, DATA
, RAW
, COOKED
};
116 enum datamodes
{ MODE0
, MODE1
, MODE2
};
117 enum resetmodes
{ SOFT
, HARD
};
119 const int SINGLE
= 0x01; /* single speed drive (FX001S, LU) */
120 const int DOUBLE
= 0x02; /* double speed drive (FX001D, ..? */
121 const int DOOR
= 0x04; /* door locking capability */
122 const int MULTI
= 0x08; /* multi session capability */
124 const unsigned char READ1X
= 0xc0;
125 const unsigned char READ2X
= 0xc1;
128 /* DECLARATIONS ****************************************************/
130 unsigned char control
;
133 struct cdrom_msf0 tt
;
134 struct cdrom_msf0 dt
;
138 unsigned int n_first
;
140 struct cdrom_msf0 msf_leadout
;
141 struct cdrom_msf0 msf_first
;
146 struct cdrom_msf0 msf_last
;
154 /* Per drive/controller stuff **************************************/
156 struct s_drive_stuff
{
158 wait_queue_head_t busyq
;
159 wait_queue_head_t lockq
;
160 wait_queue_head_t sleepq
;
163 volatile int introk
; /* status of last irq operation */
164 volatile int busy
; /* drive performs an operation */
165 volatile int lock
; /* exclusive usage */
168 struct s_diskinfo di
;
169 struct s_multi multi
;
170 struct s_subqcode
* toc
; /* first entry of the toc array */
171 struct s_subqcode start
;
172 struct s_subqcode stop
;
173 int xa
; /* 1 if xa disk */
174 int audio
; /* 1 if audio disk */
177 /* `buffer' control */
178 volatile int valid
; /* pending, ..., values are valid */
179 volatile int pending
; /* next sector to be read */
180 volatile int low_border
; /* first sector not to be skipped direct */
181 volatile int high_border
; /* first sector `out of area' */
183 volatile int int_err
;
187 void* wreg_data
; /* w data */
188 void* wreg_reset
; /* w hardware reset */
189 void* wreg_hcon
; /* w hardware conf */
190 void* wreg_chn
; /* w channel */
191 void* rreg_data
; /* r data */
192 void* rreg_status
; /* r status */
194 int irq
; /* irq used by this drive */
195 int minor
; /* minor number of this drive */
196 int present
; /* drive present and its capabilities */
197 unsigned char readcmd
; /* read cmd depends on single/double speed */
198 unsigned char playcmd
; /* play should always be single speed */
199 unsigned int xxx
; /* set if changed, reset while open */
200 unsigned int yyy
; /* set if changed, reset by media_changed */
201 int users
; /* keeps track of open/close */
202 int lastsector
; /* last block accessible */
203 int status
; /* last operation's error / status */
204 int readerrs
; /* # of blocks read w/o error */
208 /* Prototypes ******************************************************/
210 /* The following prototypes are already declared elsewhere. They are
211 repeated here to show what's going on. And to sense, if they're
212 changed elsewhere. */
214 /* declared in blk.h */
216 void do_mcdx_request(request_queue_t
* q
);
219 /* Indirect exported functions. These functions are exported by their
220 addresses, such as mcdx_open and mcdx_close in the
221 structure mcdx_dops. */
223 /* ??? exported by the mcdx_sigaction struct */
224 static void mcdx_intr(int, void *, struct pt_regs
*);
226 /* exported by file_ops */
227 static int mcdx_open(struct cdrom_device_info
* cdi
, int purpose
);
228 static void mcdx_close(struct cdrom_device_info
* cdi
);
229 static int mcdx_media_changed(struct cdrom_device_info
* cdi
, int disc_nr
);
230 static int mcdx_tray_move(struct cdrom_device_info
* cdi
, int position
);
231 static int mcdx_lockdoor(struct cdrom_device_info
* cdi
, int lock
);
232 static int mcdx_audio_ioctl(struct cdrom_device_info
* cdi
, unsigned int cmd
,
235 /* misc internal support functions */
236 static void log2msf(unsigned int, struct cdrom_msf0
*);
237 static unsigned int msf2log(const struct cdrom_msf0
*);
238 static unsigned int uint2bcd(unsigned int);
239 static unsigned int bcd2uint(unsigned char);
240 static char *port(int*);
241 static int irq(int*);
242 static void mcdx_delay(struct s_drive_stuff
*, long jifs
);
243 static int mcdx_transfer(struct s_drive_stuff
*, char* buf
, int sector
, int nr_sectors
);
244 static int mcdx_xfer(struct s_drive_stuff
*, char* buf
, int sector
, int nr_sectors
);
246 static int mcdx_config(struct s_drive_stuff
*, int);
247 static int mcdx_requestversion(struct s_drive_stuff
*, struct s_version
*, int);
248 static int mcdx_stop(struct s_drive_stuff
*, int);
249 static int mcdx_hold(struct s_drive_stuff
*, int);
250 static int mcdx_reset(struct s_drive_stuff
*, enum resetmodes
, 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);
267 /* static variables ************************************************/
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 MODULE_PARM(mcdx
, "1-4i");
277 static struct cdrom_device_ops mcdx_dops
= {
278 mcdx_open
, /* open */
279 mcdx_close
, /* release */
280 NULL
, /* drive status */
281 mcdx_media_changed
, /* media changed */
282 mcdx_tray_move
, /* tray move */
283 mcdx_lockdoor
, /* lock door */
284 NULL
, /* select speed */
285 NULL
, /* select disc */
286 NULL
, /* get last session */
287 NULL
, /* get universal product code */
288 NULL
, /* hard reset */
289 mcdx_audio_ioctl
, /* audio ioctl */
290 NULL
, /* device-specific ioctl */
291 CDC_OPEN_TRAY
| CDC_LOCK
| CDC_MEDIA_CHANGED
| CDC_PLAY_AUDIO
292 | CDC_DRIVE_STATUS
, /* capability */
293 0, /* number of minor devices */
296 static struct cdrom_device_info mcdx_info
= {
297 &mcdx_dops
, /* device operations */
303 2, /* maximum speed */
304 1, /* number of discs */
305 0, /* options, not owned */
306 0, /* mc_flags, not owned */
307 0, /* use count, not owned */
308 "mcdx", /* name of the device type */
313 /* KERNEL INTERFACE FUNCTIONS **************************************/
316 static int mcdx_audio_ioctl(struct cdrom_device_info
* cdi
, unsigned int cmd
,
319 struct s_drive_stuff
*stuffp
= mcdx_stuffp
[MINOR(cdi
->dev
)];
321 if (!stuffp
->present
) return -ENXIO
;
325 if(-1 == mcdx_requesttocdata(stuffp
, &stuffp
->di
, 1))
327 stuffp
->lastsector
= -1;
331 stuffp
->lastsector
= (CD_FRAMESIZE
/ 512)
332 * msf2log(&stuffp
->di
.msf_leadout
) - 1;
339 if (-1 == mcdx_readtoc(stuffp
)) return -1;
347 xtrace(IOCTL
, "ioctl() START\n");
348 /* Spin up the drive. Don't think we can do this.
349 * For now, ignore it.
355 xtrace(IOCTL
, "ioctl() STOP\n");
356 stuffp
->audiostatus
= CDROM_AUDIO_INVALID
;
357 if (-1 == mcdx_stop(stuffp
, 1))
362 case CDROMPLAYTRKIND
: {
363 struct cdrom_ti
*ti
=(struct cdrom_ti
*) arg
;
365 xtrace(IOCTL
, "ioctl() PLAYTRKIND\n");
366 if ((ti
->cdti_trk0
< stuffp
->di
.n_first
)
367 || (ti
->cdti_trk0
> stuffp
->di
.n_last
)
368 || (ti
->cdti_trk1
< stuffp
->di
.n_first
))
370 if (ti
->cdti_trk1
> stuffp
->di
.n_last
)
371 ti
->cdti_trk1
= stuffp
->di
.n_last
;
372 xtrace(PLAYTRK
, "ioctl() track %d to %d\n", ti
->cdti_trk0
, ti
->cdti_trk1
);
373 return mcdx_playtrk(stuffp
, ti
);
377 struct cdrom_msf
*msf
=(struct cdrom_msf
*) arg
;
379 xtrace(IOCTL
, "ioctl() PLAYMSF\n");
381 if ((stuffp
->audiostatus
== CDROM_AUDIO_PLAY
)
382 && (-1 == mcdx_hold(stuffp
, 1))) return -EIO
;
384 msf
->cdmsf_min0
= uint2bcd(msf
->cdmsf_min0
);
385 msf
->cdmsf_sec0
= uint2bcd(msf
->cdmsf_sec0
);
386 msf
->cdmsf_frame0
= uint2bcd(msf
->cdmsf_frame0
);
388 msf
->cdmsf_min1
= uint2bcd(msf
->cdmsf_min1
);
389 msf
->cdmsf_sec1
= uint2bcd(msf
->cdmsf_sec1
);
390 msf
->cdmsf_frame1
= uint2bcd(msf
->cdmsf_frame1
);
392 stuffp
->stop
.dt
.minute
= msf
->cdmsf_min1
;
393 stuffp
->stop
.dt
.second
= msf
->cdmsf_sec1
;
394 stuffp
->stop
.dt
.frame
= msf
->cdmsf_frame1
;
396 return mcdx_playmsf(stuffp
, msf
);
400 xtrace(IOCTL
, "ioctl() RESUME\n");
401 return mcdx_playtrk(stuffp
, NULL
);
404 case CDROMREADTOCENTRY
: {
405 struct cdrom_tocentry
*entry
=(struct cdrom_tocentry
*) arg
;
406 struct s_subqcode
*tp
= NULL
;
407 xtrace(IOCTL
, "ioctl() READTOCENTRY\n");
409 if (-1 == mcdx_readtoc(stuffp
)) return -1;
410 if (entry
->cdte_track
== CDROM_LEADOUT
)
411 tp
= &stuffp
->toc
[stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 1];
412 else if (entry
->cdte_track
> stuffp
->di
.n_last
413 || entry
->cdte_track
< stuffp
->di
.n_first
) return -EINVAL
;
414 else tp
= &stuffp
->toc
[entry
->cdte_track
- stuffp
->di
.n_first
];
418 entry
->cdte_adr
= tp
->control
;
419 entry
->cdte_ctrl
= tp
->control
>> 4;
420 /* Always return stuff in MSF, and let the Uniform cdrom driver
421 worry about what the user actually wants */
422 entry
->cdte_addr
.msf
.minute
= bcd2uint(tp
->dt
.minute
);
423 entry
->cdte_addr
.msf
.second
= bcd2uint(tp
->dt
.second
);
424 entry
->cdte_addr
.msf
.frame
= bcd2uint(tp
->dt
.frame
);
429 struct cdrom_subchnl
*sub
= (struct cdrom_subchnl
*)arg
;
432 xtrace(IOCTL
, "ioctl() SUBCHNL\n");
434 if (-1 == mcdx_requestsubqcode(stuffp
, &q
, 2))
437 xtrace(SUBCHNL
, "audiostatus: %x\n", stuffp
->audiostatus
);
438 sub
->cdsc_audiostatus
= stuffp
->audiostatus
;
439 sub
->cdsc_adr
= q
.control
;
440 sub
->cdsc_ctrl
= q
.control
>> 4;
441 sub
->cdsc_trk
= bcd2uint(q
.tno
);
442 sub
->cdsc_ind
= bcd2uint(q
.index
);
444 xtrace(SUBCHNL
, "trk %d, ind %d\n",
445 sub
->cdsc_trk
, sub
->cdsc_ind
);
446 /* Always return stuff in MSF, and let the Uniform cdrom driver
447 worry about what the user actually wants */
448 sub
->cdsc_absaddr
.msf
.minute
= bcd2uint(q
.dt
.minute
);
449 sub
->cdsc_absaddr
.msf
.second
= bcd2uint(q
.dt
.second
);
450 sub
->cdsc_absaddr
.msf
.frame
= bcd2uint(q
.dt
.frame
);
451 sub
->cdsc_reladdr
.msf
.minute
= bcd2uint(q
.tt
.minute
);
452 sub
->cdsc_reladdr
.msf
.second
= bcd2uint(q
.tt
.second
);
453 sub
->cdsc_reladdr
.msf
.frame
= bcd2uint(q
.tt
.frame
);
455 "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
456 sub
->cdsc_absaddr
.msf
.minute
, sub
->cdsc_absaddr
.msf
.second
,
457 sub
->cdsc_absaddr
.msf
.frame
, sub
->cdsc_reladdr
.msf
.minute
,
458 sub
->cdsc_reladdr
.msf
.second
, sub
->cdsc_reladdr
.msf
.frame
);
463 case CDROMREADTOCHDR
: {
464 struct cdrom_tochdr
*toc
=(struct cdrom_tochdr
*) arg
;
466 xtrace(IOCTL
, "ioctl() READTOCHDR\n");
467 toc
->cdth_trk0
= stuffp
->di
.n_first
;
468 toc
->cdth_trk1
= stuffp
->di
.n_last
;
469 xtrace(TOCHDR
, "ioctl() track0 = %d, track1 = %d\n",
470 stuffp
->di
.n_first
, stuffp
->di
.n_last
);
475 xtrace(IOCTL
, "ioctl() PAUSE\n");
476 if (stuffp
->audiostatus
!= CDROM_AUDIO_PLAY
) return -EINVAL
;
477 if (-1 == mcdx_stop(stuffp
, 1)) return -EIO
;
478 stuffp
->audiostatus
= CDROM_AUDIO_PAUSED
;
479 if (-1 == mcdx_requestsubqcode(stuffp
, &stuffp
->start
, 1))
484 case CDROMMULTISESSION
: {
485 struct cdrom_multisession
*ms
=(struct cdrom_multisession
*) arg
;
486 xtrace(IOCTL
, "ioctl() MULTISESSION\n");
487 /* Always return stuff in LBA, and let the Uniform cdrom driver
488 worry about what the user actually wants */
489 ms
->addr
.lba
= msf2log(&stuffp
->multi
.msf_last
);
490 ms
->xa_flag
= !!stuffp
->multi
.multi
;
491 xtrace(MS
, "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
492 ms
->xa_flag
, ms
->addr
.lba
, stuffp
->multi
.msf_last
.minute
,
493 stuffp
->multi
.msf_last
.second
,stuffp
->multi
.msf_last
.frame
);
499 xtrace(IOCTL
, "ioctl() EJECT\n");
500 if (stuffp
->users
> 1) return -EBUSY
;
501 return(mcdx_tray_move(cdi
, 1));
504 case CDROMCLOSETRAY
: {
505 xtrace(IOCTL
, "ioctl() CDROMCLOSETRAY\n");
506 return(mcdx_tray_move(cdi
, 0));
510 struct cdrom_volctrl
*volctrl
=(struct cdrom_volctrl
*)arg
;
511 xtrace(IOCTL
, "ioctl() VOLCTRL\n");
513 #if 0 /* not tested! */
514 /* adjust for the weirdness of workman (md) */
515 /* can't test it (hs) */
516 volctrl
.channel2
= volctrl
.channel1
;
517 volctrl
.channel1
= volctrl
.channel3
= 0x00;
519 return mcdx_setattentuator(stuffp
, volctrl
, 2);
523 xwarn("ioctl(): unknown request 0x%04x\n", cmd
);
528 void do_mcdx_request(request_queue_t
* q
)
531 struct s_drive_stuff
*stuffp
;
536 xtrace(REQUEST
, "end_request(0): CURRENT == NULL\n");
540 if (CURRENT
->rq_status
== RQ_INACTIVE
) {
541 xtrace(REQUEST
, "end_request(0): rq_status == RQ_INACTIVE\n");
547 dev
= MINOR(CURRENT
->rq_dev
);
548 stuffp
= mcdx_stuffp
[dev
];
551 || (dev
>= MCDX_NDRIVES
)
553 || (!stuffp
->present
)) {
554 xwarn("do_request(): bad device: %s\n",
555 kdevname(CURRENT
->rq_dev
));
556 xtrace(REQUEST
, "end_request(0): bad device\n");
557 end_request(0); return;
561 xwarn("do_request() attempt to read from audio cd\n");
562 xtrace(REQUEST
, "end_request(0): read from audio\n");
563 end_request(0); return;
566 xtrace(REQUEST
, "do_request() (%lu + %lu)\n",
567 CURRENT
->sector
, CURRENT
->nr_sectors
);
569 switch (CURRENT
->cmd
) {
571 xwarn("do_request(): attempt to write to cd!!\n");
572 xtrace(REQUEST
, "end_request(0): write\n");
573 end_request(0); return;
577 while (CURRENT
->nr_sectors
) {
580 i
= mcdx_transfer(stuffp
,
583 CURRENT
->nr_sectors
);
589 CURRENT
->sector
+= i
;
590 CURRENT
->nr_sectors
-= i
;
591 CURRENT
->buffer
+= (i
* 512);
596 xtrace(REQUEST
, "end_request(1)\n");
601 panic(MCDX
"do_request: unknown command.\n");
609 mcdx_open(struct cdrom_device_info
* cdi
, int purpose
)
611 struct s_drive_stuff
*stuffp
;
612 xtrace(OPENCLOSE
, "open()\n");
613 stuffp
= mcdx_stuffp
[MINOR(cdi
->dev
)];
614 if (!stuffp
->present
) return -ENXIO
;
616 /* Make the modules looking used ... (thanx bjorn).
617 * But we shouldn't forget to decrement the module counter
621 /* this is only done to test if the drive talks with us */
622 if (-1 == mcdx_getstatus(stuffp
, 1)) {
629 xtrace(OPENCLOSE
, "open() media changed\n");
630 stuffp
->audiostatus
= CDROM_AUDIO_INVALID
;
632 xtrace(OPENCLOSE
, "open() Request multisession info\n");
633 if (-1 == mcdx_requestmultidiskinfo( stuffp
, &stuffp
->multi
, 6))
634 xinfo("No multidiskinfo\n");
637 if (!stuffp
->multi
.multi
)
638 stuffp
->multi
.msf_last
.second
= 2;
640 xtrace(OPENCLOSE
, "open() MS: %d, last @ %02x:%02x.%02x\n",
642 stuffp
->multi
.msf_last
.minute
,
643 stuffp
->multi
.msf_last
.second
,
644 stuffp
->multi
.msf_last
.frame
);
646 { ; } /* got multisession information */
647 /* request the disks table of contents (aka diskinfo) */
648 if (-1 == mcdx_requesttocdata(stuffp
, &stuffp
->di
, 1)) {
650 stuffp
->lastsector
= -1;
654 stuffp
->lastsector
= (CD_FRAMESIZE
/ 512)
655 * msf2log(&stuffp
->di
.msf_leadout
) - 1;
657 xtrace(OPENCLOSE
, "open() start %d (%02x:%02x.%02x) %d\n",
659 stuffp
->di
.msf_first
.minute
,
660 stuffp
->di
.msf_first
.second
,
661 stuffp
->di
.msf_first
.frame
,
662 msf2log(&stuffp
->di
.msf_first
));
663 xtrace(OPENCLOSE
, "open() last %d (%02x:%02x.%02x) %d\n",
665 stuffp
->di
.msf_leadout
.minute
,
666 stuffp
->di
.msf_leadout
.second
,
667 stuffp
->di
.msf_leadout
.frame
,
668 msf2log(&stuffp
->di
.msf_leadout
));
672 xtrace(MALLOC
, "open() free old toc @ %p\n", stuffp
->toc
);
678 xtrace(OPENCLOSE
, "open() init irq generation\n");
679 if (-1 == mcdx_config(stuffp
, 1)) {
685 /* Set the read speed */
686 xwarn("AAA %x AAA\n", stuffp
->readcmd
);
687 if (stuffp
->readerrs
) stuffp
->readcmd
= READ1X
;
688 else stuffp
->readcmd
=
689 stuffp
->present
| SINGLE
? READ1X
: READ2X
;
690 xwarn("XXX %x XXX\n", stuffp
->readcmd
);
692 stuffp
->readcmd
= stuffp
->present
| SINGLE
? READ1X
: READ2X
;
695 /* try to get the first sector, iff any ... */
696 if (stuffp
->lastsector
>= 0) {
704 for (tries
= 6; tries
; tries
--) {
708 xtrace(OPENCLOSE
, "open() try as %s\n",
709 stuffp
->xa
? "XA" : "normal");
711 if (-1 == (ans
= mcdx_setdatamode(stuffp
,
712 stuffp
->xa
? MODE2
: MODE1
, 1))) {
713 /* MOD_DEC_USE_COUNT, return -EIO; */
718 if ((stuffp
->audio
= e_audio(ans
))) break;
720 while (0 == (ans
= mcdx_transfer(stuffp
, buf
, 0, 1)))
724 stuffp
->xa
= !stuffp
->xa
;
727 /* xa disks will be read in raw mode, others not */
728 if (-1 == mcdx_setdrivemode(stuffp
,
729 stuffp
->xa
? RAW
: COOKED
, 1)) {
734 xinfo("open() audio disk found\n");
735 } else if (stuffp
->lastsector
>= 0) {
736 xinfo("open() %s%s disk found\n",
737 stuffp
->xa
? "XA / " : "",
738 stuffp
->multi
.multi
? "Multi Session" : "Single Session");
746 static void mcdx_close(struct cdrom_device_info
* cdi
)
748 struct s_drive_stuff
*stuffp
;
750 xtrace(OPENCLOSE
, "close()\n");
752 stuffp
= mcdx_stuffp
[MINOR(cdi
->dev
)];
759 static int mcdx_media_changed(struct cdrom_device_info
* cdi
, int disc_nr
)
760 /* Return: 1 if media changed since last call to this function
763 struct s_drive_stuff
*stuffp
;
765 xinfo("mcdx_media_changed called for device %s\n",
768 stuffp
= mcdx_stuffp
[MINOR(cdi
->dev
)];
769 mcdx_getstatus(stuffp
, 1);
771 if (stuffp
->yyy
== 0) return 0;
778 static int __init
mcdx_setup(char *str
)
781 (void)get_options(str
, ARRAY_SIZE(pi
), pi
);
783 if (pi
[0] > 0) mcdx_drive_map
[0][0] = pi
[1];
784 if (pi
[0] > 1) mcdx_drive_map
[0][1] = pi
[2];
788 __setup("mcdx=", mcdx_setup
);
792 /* DIRTY PART ******************************************************/
794 static void mcdx_delay(struct s_drive_stuff
*stuff
, long jifs
)
795 /* This routine is used for sleeping.
796 * A jifs value <0 means NO sleeping,
797 * =0 means minimal sleeping (let the kernel
798 * run for other processes)
799 * >0 means at least sleep for that amount.
800 * May be we could use a simple count loop w/ jumps to itself, but
801 * I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
803 if (jifs
< 0) return;
805 xtrace(SLEEP
, "*** delay: sleepq\n");
806 interruptible_sleep_on_timeout(&stuff
->sleepq
, jifs
);
807 xtrace(SLEEP
, "delay awoken\n");
808 if (signal_pending(current
)) {
809 xtrace(SLEEP
, "got signal\n");
814 mcdx_intr(int irq
, void *dev_id
, struct pt_regs
* regs
)
816 struct s_drive_stuff
*stuffp
;
819 stuffp
= mcdx_irq_map
[irq
];
821 if (stuffp
== NULL
) {
822 xwarn("mcdx: no device for intr %d\n", irq
);
827 if ( !stuffp
->busy
&& stuffp
->pending
)
831 /* get the interrupt status */
832 b
= inb((unsigned int) stuffp
->rreg_status
);
833 stuffp
->introk
= ~b
& MCDX_RBIT_DTEN
;
835 /* NOTE: We only should get interrupts if the data we
836 * requested are ready to transfer.
837 * But the drive seems to generate ``asynchronous'' interrupts
838 * on several error conditions too. (Despite the err int enable
839 * setting during initialisation) */
841 /* if not ok, read the next byte as the drives status */
842 if (!stuffp
->introk
) {
843 xtrace(IRQ
, "intr() irq %d hw status 0x%02x\n", irq
, b
);
844 if (~b
& MCDX_RBIT_STEN
) {
845 xinfo( "intr() irq %d status 0x%02x\n",
846 irq
, inb((unsigned int) stuffp
->rreg_data
));
848 xinfo( "intr() irq %d ambiguous hw status\n", irq
);
851 xtrace(IRQ
, "irq() irq %d ok, status %02x\n", irq
, b
);
855 wake_up_interruptible(&stuffp
->busyq
);
861 struct s_drive_stuff
*stuffp
,
862 const unsigned char *cmd
, size_t cmdlen
,
863 void *buffer
, size_t size
,
864 unsigned int timeout
, int tries
)
865 /* Send a command to the drive, wait for the result.
866 * returns -1 on timeout, drive status otherwise
867 * If buffer is not zero, the result (length size) is stored there.
868 * If buffer is zero the size should be the number of bytes to read
869 * from the drive. These bytes are discarded.
876 /* Somebody wants the data read? */
877 if ((discard
= (buffer
== NULL
))) buffer
= &c
;
879 while (stuffp
->lock
) {
880 xtrace(SLEEP
, "*** talk: lockq\n");
881 interruptible_sleep_on(&stuffp
->lockq
);
882 xtrace(SLEEP
, "talk: awoken\n");
887 /* An operation other then reading data destroys the
888 * data already requested and remembered in stuffp->request, ... */
891 #if MCDX_DEBUG & TALK
894 xtrace(TALK
, "talk() %d / %d tries, res.size %d, command 0x%02x",
895 tries
, timeout
, size
, (unsigned char) cmd
[0]);
896 for (i
= 1; i
< cmdlen
; i
++) xtrace(TALK
, " 0x%02x", cmd
[i
]);
901 /* give up if all tries are done (bad) or if the status
903 for (st
= -1; st
== -1 && tries
; tries
--) {
905 char *bp
= (char*) buffer
;
908 outsb((unsigned int) stuffp
->wreg_data
, cmd
, cmdlen
);
909 xtrace(TALK
, "talk() command sent\n");
911 /* get the status byte */
912 if (-1 == mcdx_getval(stuffp
, timeout
, 0, bp
)) {
913 xinfo("talk() %02x timed out (status), %d tr%s left\n",
914 cmd
[0], tries
- 1, tries
== 2 ? "y" : "ies");
921 xtrace(TALK
, "talk() got status 0x%02x\n", st
);
925 xwarn("command error cmd = %02x %s \n",
926 cmd
[0], cmdlen
> 1 ? "..." : "");
932 if (stuffp
->audiostatus
== CDROM_AUDIO_INVALID
)
933 stuffp
->audiostatus
=
934 e_audiobusy(st
) ? CDROM_AUDIO_PLAY
: CDROM_AUDIO_NO_STATUS
;
935 else if (stuffp
->audiostatus
== CDROM_AUDIO_PLAY
936 && e_audiobusy(st
) == 0)
937 stuffp
->audiostatus
= CDROM_AUDIO_COMPLETED
;
941 xinfo("talk() media changed\n");
942 stuffp
->xxx
= stuffp
->yyy
= 1;
945 /* now actually get the data */
947 if (-1 == mcdx_getval(stuffp
, timeout
, 0, bp
)) {
948 xinfo("talk() %02x timed out (data), %d tr%s left\n",
949 cmd
[0], tries
- 1, tries
== 2 ? "y" : "ies");
953 xtrace(TALK
, "talk() got 0x%02x\n", *(bp
- 1));
958 if (!tries
&& st
== -1) xinfo("talk() giving up\n");
962 wake_up_interruptible(&stuffp
->lockq
);
964 xtrace(TALK
, "talk() done with 0x%02x\n", st
);
968 /* MODULE STUFF ***********************************************************/
972 int __mcdx_init(void)
978 for (i
= 0; i
< MCDX_NDRIVES
; i
++) {
979 if (mcdx_stuffp
[i
]) {
980 xtrace(INIT
, "init_module() drive %d stuff @ %p\n",
992 void __exit
mcdx_exit(void)
996 xinfo("cleanup_module called\n");
998 for (i
= 0; i
< MCDX_NDRIVES
; i
++) {
999 struct s_drive_stuff
*stuffp
;
1000 if (unregister_cdrom(&mcdx_info
)) {
1001 printk(KERN_WARNING
"Can't unregister cdrom mcdx\n");
1004 stuffp
= mcdx_stuffp
[i
];
1005 if (!stuffp
) continue;
1006 release_region((unsigned long) stuffp
->wreg_data
, MCDX_IO_SIZE
);
1007 free_irq(stuffp
->irq
, NULL
);
1009 xtrace(MALLOC
, "cleanup_module() free toc @ %p\n", stuffp
->toc
);
1012 xtrace(MALLOC
, "cleanup_module() free stuffp @ %p\n", stuffp
);
1013 mcdx_stuffp
[i
] = NULL
;
1017 if (devfs_unregister_blkdev(MAJOR_NR
, "mcdx") != 0) {
1018 xwarn("cleanup() unregister_blkdev() failed\n");
1020 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR
));
1022 else xinfo("cleanup() succeeded\n");
1027 module_init(__mcdx_init
);
1029 module_exit(mcdx_exit
);
1032 /* Support functions ************************************************/
1034 int __init
mcdx_init_drive(int drive
)
1036 struct s_version version
;
1037 struct s_drive_stuff
* stuffp
;
1038 int size
= sizeof(*stuffp
);
1041 mcdx_blocksizes
[drive
] = 0;
1043 xtrace(INIT
, "init() try drive %d\n", drive
);
1045 xtrace(INIT
, "kmalloc space for stuffpt's\n");
1046 xtrace(MALLOC
, "init() malloc %d bytes\n", size
);
1047 if (!(stuffp
= kmalloc(size
, GFP_KERNEL
))) {
1048 xwarn("init() malloc failed\n");
1052 xtrace(INIT
, "init() got %d bytes for drive stuff @ %p\n",
1053 sizeof(*stuffp
), stuffp
);
1055 /* set default values */
1056 memset(stuffp
, 0, sizeof(*stuffp
));
1058 stuffp
->present
= 0; /* this should be 0 already */
1059 stuffp
->toc
= NULL
; /* this should be NULL already */
1061 /* setup our irq and i/o addresses */
1062 stuffp
->irq
= irq(mcdx_drive_map
[drive
]);
1063 stuffp
->wreg_data
= stuffp
->rreg_data
= port(mcdx_drive_map
[drive
]);
1064 stuffp
->wreg_reset
= stuffp
->rreg_status
= stuffp
->wreg_data
+ 1;
1065 stuffp
->wreg_hcon
= stuffp
->wreg_reset
+ 1;
1066 stuffp
->wreg_chn
= stuffp
->wreg_hcon
+ 1;
1068 init_waitqueue_head(&stuffp
->busyq
);
1069 init_waitqueue_head(&stuffp
->lockq
);
1070 init_waitqueue_head(&stuffp
->sleepq
);
1072 /* check if i/o addresses are available */
1073 if (check_region((unsigned int) stuffp
->wreg_data
, MCDX_IO_SIZE
)) {
1074 xwarn("0x%3p,%d: Init failed. "
1075 "I/O ports (0x%3p..0x%3p) already in use.\n",
1076 stuffp
->wreg_data
, stuffp
->irq
,
1078 stuffp
->wreg_data
+ MCDX_IO_SIZE
- 1);
1079 xtrace(MALLOC
, "init() free stuffp @ %p\n", stuffp
);
1081 xtrace(INIT
, "init() continue at next drive\n");
1082 return 0; /* next drive */
1085 xtrace(INIT
, "init() i/o port is available at 0x%3p\n",
1087 xtrace(INIT
, "init() hardware reset\n");
1088 mcdx_reset(stuffp
, HARD
, 1);
1090 xtrace(INIT
, "init() get version\n");
1091 if (-1 == mcdx_requestversion(stuffp
, &version
, 4)) {
1092 /* failed, next drive */
1093 xwarn("%s=0x%3p,%d: Init failed. Can't get version.\n",
1095 stuffp
->wreg_data
, stuffp
->irq
);
1096 xtrace(MALLOC
, "init() free stuffp @ %p\n", stuffp
);
1098 xtrace(INIT
, "init() continue at next drive\n");
1102 switch (version
.code
) {
1104 stuffp
->readcmd
= READ2X
;
1105 stuffp
->present
= DOUBLE
| DOOR
| MULTI
;
1108 stuffp
->readcmd
= READ1X
;
1109 stuffp
->present
= SINGLE
| DOOR
| MULTI
;
1112 stuffp
->readcmd
= READ1X
;
1113 stuffp
->present
= SINGLE
;
1116 stuffp
->present
= 0; break;
1119 stuffp
->playcmd
= READ1X
;
1121 if (!stuffp
->present
) {
1122 xwarn("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n",
1123 MCDX
, stuffp
->wreg_data
, stuffp
->irq
);
1125 return 0; /* next drive */
1128 xtrace(INIT
, "init() register blkdev\n");
1129 if (devfs_register_blkdev(MAJOR_NR
, "mcdx", &cdrom_fops
) != 0) {
1130 xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n",
1132 stuffp
->wreg_data
, stuffp
->irq
, MAJOR_NR
);
1137 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR
), DEVICE_REQUEST
);
1138 read_ahead
[MAJOR_NR
] = READ_AHEAD
;
1139 blksize_size
[MAJOR_NR
] = mcdx_blocksizes
;
1141 xtrace(INIT
, "init() subscribe irq and i/o\n");
1142 mcdx_irq_map
[stuffp
->irq
] = stuffp
;
1143 if (request_irq(stuffp
->irq
, mcdx_intr
, SA_INTERRUPT
, "mcdx", NULL
)) {
1144 xwarn("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n",
1146 stuffp
->wreg_data
, stuffp
->irq
, stuffp
->irq
);
1148 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR
));
1152 request_region((unsigned int) stuffp
->wreg_data
,
1156 xtrace(INIT
, "init() get garbage\n");
1159 mcdx_delay(stuffp
, HZ
/2);
1160 for (i
= 100; i
; i
--)
1161 (void) inb((unsigned int) stuffp
->rreg_status
);
1166 /* irq 11 -> channel register */
1167 outb(0x50, (unsigned int) stuffp
->wreg_chn
);
1170 xtrace(INIT
, "init() set non dma but irq mode\n");
1171 mcdx_config(stuffp
, 1);
1173 stuffp
->minor
= drive
;
1175 sprintf(msg
, " mcdx: Mitsumi CD-ROM installed at 0x%3p, irq %d."
1176 " (Firmware version %c %x)\n",
1177 stuffp
->wreg_data
, stuffp
->irq
, version
.code
,
1179 mcdx_stuffp
[drive
] = stuffp
;
1180 xtrace(INIT
, "init() mcdx_stuffp[%d] = %p\n", drive
, stuffp
);
1181 mcdx_info
.dev
= MKDEV(MAJOR_NR
,0);
1182 if (register_cdrom(&mcdx_info
) != 0) {
1183 printk("Cannot register Mitsumi CD-ROM!\n");
1184 release_region((unsigned long) stuffp
->wreg_data
,
1186 free_irq(stuffp
->irq
, NULL
);
1188 if (devfs_unregister_blkdev(MAJOR_NR
, "mcdx") != 0)
1189 xwarn("cleanup() unregister_blkdev() failed\n");
1190 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR
));
1197 int __init
mcdx_init(void)
1201 xwarn("Version 2.14(hs) for " UTS_RELEASE
"\n");
1203 xwarn("Version 2.14(hs) \n");
1206 xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
1208 /* zero the pointer array */
1209 for (drive
= 0; drive
< MCDX_NDRIVES
; drive
++)
1210 mcdx_stuffp
[drive
] = NULL
;
1212 /* do the initialisation */
1213 for (drive
= 0; drive
< MCDX_NDRIVES
; drive
++) {
1214 switch(mcdx_init_drive(drive
)) {
1225 mcdx_transfer(struct s_drive_stuff
*stuffp
,
1226 char *p
, int sector
, int nr_sectors
)
1227 /* This seems to do the actually transfer. But it does more. It
1228 keeps track of errors occurred and will (if possible) fall back
1229 to single speed on error.
1230 Return: -1 on timeout or other error
1231 else status byte (as in stuff->st) */
1235 ans
= mcdx_xfer(stuffp
, p
, sector
, nr_sectors
);
1238 if (-1 == ans
) stuffp
->readerrs
++;
1241 if (stuffp
->readerrs
&& stuffp
->readcmd
== READ1X
) {
1242 xwarn("XXX Already reading 1x -- no chance\n");
1246 xwarn("XXX Fallback to 1x\n");
1248 stuffp
->readcmd
= READ1X
;
1249 return mcdx_transfer(stuffp
, p
, sector
, nr_sectors
);
1255 static int mcdx_xfer(struct s_drive_stuff
*stuffp
,
1256 char *p
, int sector
, int nr_sectors
)
1257 /* This does actually the transfer from the drive.
1258 Return: -1 on timeout or other error
1259 else status byte (as in stuff->st) */
1265 if (stuffp
->audio
) {
1266 xwarn("Attempt to read from audio CD.\n");
1270 if (!stuffp
->readcmd
) {
1271 xinfo("Can't transfer from missing disk.\n");
1275 while (stuffp
->lock
) {
1276 interruptible_sleep_on(&stuffp
->lockq
);
1280 && (sector
>= stuffp
->pending
)
1281 && (sector
< stuffp
->low_border
)) {
1283 /* All (or at least a part of the sectors requested) seems
1284 * to be already requested, so we don't need to bother the
1285 * drive with new requests ...
1286 * Wait for the drive become idle, but first
1287 * check for possible occurred errors --- the drive
1288 * seems to report them asynchronously */
1291 border
= stuffp
->high_border
< (border
= sector
+ nr_sectors
)
1292 ? stuffp
->high_border
: border
;
1294 stuffp
->lock
= current
->pid
;
1298 while (stuffp
->busy
) {
1300 timeout
= interruptible_sleep_on_timeout(&stuffp
->busyq
, 5*HZ
);
1302 if (!stuffp
->introk
) { xtrace(XFER
, "error via interrupt\n"); }
1303 else if (!timeout
) { xtrace(XFER
, "timeout\n"); }
1304 else if (signal_pending(current
)) {
1305 xtrace(XFER
, "signal\n");
1312 wake_up_interruptible(&stuffp
->lockq
);
1313 xtrace(XFER
, "transfer() done (-1)\n");
1317 /* check if we need to set the busy flag (as we
1318 * expect an interrupt */
1319 stuffp
->busy
= (3 == (stuffp
->pending
& 3));
1321 /* Test if it's the first sector of a block,
1322 * there we have to skip some bytes as we read raw data */
1323 if (stuffp
->xa
&& (0 == (stuffp
->pending
& 3))) {
1324 const int HEAD
= CD_FRAMESIZE_RAW
- CD_XA_TAIL
- CD_FRAMESIZE
;
1325 insb((unsigned int) stuffp
->rreg_data
, p
, HEAD
);
1328 /* now actually read the data */
1329 insb((unsigned int) stuffp
->rreg_data
, p
, 512);
1331 /* test if it's the last sector of a block,
1332 * if so, we have to handle XA special */
1333 if ((3 == (stuffp
->pending
& 3)) && stuffp
->xa
) {
1334 char dummy
[CD_XA_TAIL
];
1335 insb((unsigned int) stuffp
->rreg_data
, &dummy
[0], CD_XA_TAIL
);
1338 if (stuffp
->pending
== sector
) {
1343 } while (++(stuffp
->pending
) < border
);
1346 wake_up_interruptible(&stuffp
->lockq
);
1350 /* The requested sector(s) is/are out of the
1351 * already requested range, so we have to bother the drive
1352 * with a new request. */
1354 static unsigned char cmd
[] = {
1360 cmd
[0] = stuffp
->readcmd
;
1362 /* The numbers held in ->pending, ..., should be valid */
1364 stuffp
->pending
= sector
& ~3;
1366 /* do some sanity checks */
1367 if (stuffp
->pending
> stuffp
->lastsector
) {
1368 xwarn("transfer() sector %d from nirvana requested.\n",
1370 stuffp
->status
= MCDX_ST_EOM
;
1372 xtrace(XFER
, "transfer() done (-1)\n");
1376 if ((stuffp
->low_border
= stuffp
->pending
+ DIRECT_SIZE
)
1377 > stuffp
->lastsector
+ 1) {
1378 xtrace(XFER
, "cut low_border\n");
1379 stuffp
->low_border
= stuffp
->lastsector
+ 1;
1381 if ((stuffp
->high_border
= stuffp
->pending
+ REQUEST_SIZE
)
1382 > stuffp
->lastsector
+ 1) {
1383 xtrace(XFER
, "cut high_border\n");
1384 stuffp
->high_border
= stuffp
->lastsector
+ 1;
1387 { /* Convert the sector to be requested to MSF format */
1388 struct cdrom_msf0 pending
;
1389 log2msf(stuffp
->pending
/ 4, &pending
);
1390 cmd
[1] = pending
.minute
;
1391 cmd
[2] = pending
.second
;
1392 cmd
[3] = pending
.frame
;
1395 cmd
[6] = (unsigned char) ((stuffp
->high_border
- stuffp
->pending
) / 4);
1396 xtrace(XFER
, "[%2d]\n", cmd
[6]);
1399 /* Now really issue the request command */
1400 outsb((unsigned int) stuffp
->wreg_data
, cmd
, sizeof cmd
);
1404 if ( stuffp
->int_err
) {
1406 stuffp
->int_err
= 0;
1411 stuffp
->low_border
= (stuffp
->low_border
+= done
) < stuffp
->high_border
1412 ? stuffp
->low_border
: stuffp
->high_border
;
1418 /* Access to elements of the mcdx_drive_map members */
1420 static char* port(int *ip
) { return (char*) ip
[0]; }
1421 static int irq(int *ip
) { return ip
[1]; }
1423 /* Misc number converters */
1425 static unsigned int bcd2uint(unsigned char c
)
1426 { return (c
>> 4) * 10 + (c
& 0x0f); }
1428 static unsigned int uint2bcd(unsigned int ival
)
1429 { return ((ival
/ 10) << 4) | (ival
% 10); }
1431 static void log2msf(unsigned int l
, struct cdrom_msf0
* pmsf
)
1434 pmsf
->minute
= uint2bcd(l
/ 4500), l
%= 4500;
1435 pmsf
->second
= uint2bcd(l
/ 75);
1436 pmsf
->frame
= uint2bcd(l
% 75);
1439 static unsigned int msf2log(const struct cdrom_msf0
* pmsf
)
1441 return bcd2uint(pmsf
->frame
)
1442 + bcd2uint(pmsf
->second
) * 75
1443 + bcd2uint(pmsf
->minute
) * 4500
1447 int mcdx_readtoc(struct s_drive_stuff
* stuffp
)
1448 /* Read the toc entries from the CD,
1449 * Return: -1 on failure, else 0 */
1453 xtrace(READTOC
, "ioctl() toc already read\n");
1457 xtrace(READTOC
, "ioctl() readtoc for %d tracks\n",
1458 stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 1);
1460 if (-1 == mcdx_hold(stuffp
, 1)) return -1;
1462 xtrace(READTOC
, "ioctl() tocmode\n");
1463 if (-1 == mcdx_setdrivemode(stuffp
, TOC
, 1)) return -EIO
;
1465 /* all seems to be ok so far ... malloc */
1468 size
= sizeof(struct s_subqcode
) * (stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 2);
1470 xtrace(MALLOC
, "ioctl() malloc %d bytes\n", size
);
1471 stuffp
->toc
= kmalloc(size
, GFP_KERNEL
);
1473 xwarn("Cannot malloc %d bytes for toc\n", size
);
1474 mcdx_setdrivemode(stuffp
, DATA
, 1);
1479 /* now read actually the index */
1485 trk
< (stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 1);
1487 stuffp
->toc
[trk
].index
= 0;
1489 for (retries
= 300; retries
; retries
--) { /* why 300? */
1490 struct s_subqcode q
;
1493 if (-1 == mcdx_requestsubqcode(stuffp
, &q
, 1)) {
1494 mcdx_setdrivemode(stuffp
, DATA
, 1);
1498 idx
= bcd2uint(q
.index
);
1501 && (idx
<= stuffp
->di
.n_last
)
1503 && (stuffp
->toc
[idx
- stuffp
->di
.n_first
].index
== 0)) {
1504 stuffp
->toc
[idx
- stuffp
->di
.n_first
] = q
;
1505 xtrace(READTOC
, "ioctl() toc idx %d (trk %d)\n", idx
, trk
);
1508 if (trk
== 0) break;
1510 memset(&stuffp
->toc
[stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 1],
1511 0, sizeof(stuffp
->toc
[0]));
1512 stuffp
->toc
[stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 1].dt
1513 = stuffp
->di
.msf_leadout
;
1516 /* unset toc mode */
1517 xtrace(READTOC
, "ioctl() undo toc mode\n");
1518 if (-1 == mcdx_setdrivemode(stuffp
, DATA
, 2))
1521 #if MCDX_DEBUG && READTOC
1524 trk
< (stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 2);
1526 xtrace(READTOC
, "ioctl() %d readtoc %02x %02x %02x"
1527 " %02x:%02x.%02x %02x:%02x.%02x\n",
1528 trk
+ stuffp
->di
.n_first
,
1529 stuffp
->toc
[trk
].control
, stuffp
->toc
[trk
].tno
, stuffp
->toc
[trk
].index
,
1530 stuffp
->toc
[trk
].tt
.minute
, stuffp
->toc
[trk
].tt
.second
, stuffp
->toc
[trk
].tt
.frame
,
1531 stuffp
->toc
[trk
].dt
.minute
, stuffp
->toc
[trk
].dt
.second
, stuffp
->toc
[trk
].dt
.frame
);
1539 mcdx_playmsf(struct s_drive_stuff
* stuffp
, const struct cdrom_msf
* msf
)
1541 unsigned char cmd
[7] = {
1545 if (!stuffp
->readcmd
) {
1546 xinfo("Can't play from missing disk.\n");
1550 cmd
[0] = stuffp
->playcmd
;
1552 cmd
[1] = msf
->cdmsf_min0
;
1553 cmd
[2] = msf
->cdmsf_sec0
;
1554 cmd
[3] = msf
->cdmsf_frame0
;
1555 cmd
[4] = msf
->cdmsf_min1
;
1556 cmd
[5] = msf
->cdmsf_sec1
;
1557 cmd
[6] = msf
->cdmsf_frame1
;
1559 xtrace(PLAYMSF
, "ioctl(): play %x "
1560 "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1561 cmd
[0], cmd
[1], cmd
[2], cmd
[3],
1562 cmd
[4], cmd
[5], cmd
[6]);
1564 outsb((unsigned int) stuffp
->wreg_data
, cmd
, sizeof cmd
);
1566 if (-1 == mcdx_getval(stuffp
, 3 * HZ
, 0, NULL
)) {
1567 xwarn("playmsf() timeout\n");
1571 stuffp
->audiostatus
= CDROM_AUDIO_PLAY
;
1576 mcdx_playtrk(struct s_drive_stuff
* stuffp
, const struct cdrom_ti
* ti
)
1578 struct s_subqcode
* p
;
1579 struct cdrom_msf msf
;
1581 if (-1 == mcdx_readtoc(stuffp
)) return -1;
1583 if (ti
) p
= &stuffp
->toc
[ti
->cdti_trk0
- stuffp
->di
.n_first
];
1584 else p
= &stuffp
->start
;
1586 msf
.cdmsf_min0
= p
->dt
.minute
;
1587 msf
.cdmsf_sec0
= p
->dt
.second
;
1588 msf
.cdmsf_frame0
= p
->dt
.frame
;
1591 p
= &stuffp
->toc
[ti
->cdti_trk1
- stuffp
->di
.n_first
+ 1];
1593 } else p
= &stuffp
->stop
;
1595 msf
.cdmsf_min1
= p
->dt
.minute
;
1596 msf
.cdmsf_sec1
= p
->dt
.second
;
1597 msf
.cdmsf_frame1
= p
->dt
.frame
;
1599 return mcdx_playmsf(stuffp
, &msf
);
1603 /* Drive functions ************************************************/
1606 mcdx_tray_move(struct cdrom_device_info
* cdi
, int position
)
1608 struct s_drive_stuff
*stuffp
= mcdx_stuffp
[MINOR(cdi
->dev
)];
1610 if (!stuffp
->present
)
1612 if (!(stuffp
->present
& DOOR
))
1615 if (position
) /* 1: eject */
1616 return mcdx_talk(stuffp
, "\xf6", 1, NULL
, 1, 5 * HZ
, 3);
1618 return mcdx_talk(stuffp
, "\xf8", 1, NULL
, 1, 5 * HZ
, 3);
1623 mcdx_stop(struct s_drive_stuff
*stuffp
, int tries
)
1624 { return mcdx_talk(stuffp
, "\xf0", 1, NULL
, 1, 2 * HZ
, tries
); }
1627 mcdx_hold(struct s_drive_stuff
*stuffp
, int tries
)
1628 { return mcdx_talk(stuffp
, "\x70", 1, NULL
, 1, 2 * HZ
, tries
); }
1631 mcdx_requestsubqcode(struct s_drive_stuff
*stuffp
,
1632 struct s_subqcode
*sub
,
1638 if (-1 == (ans
= mcdx_talk(
1639 stuffp
, "\x20", 1, buf
, sizeof(buf
),
1642 sub
->control
= buf
[1];
1644 sub
->index
= buf
[3];
1645 sub
->tt
.minute
= buf
[4];
1646 sub
->tt
.second
= buf
[5];
1647 sub
->tt
.frame
= buf
[6];
1648 sub
->dt
.minute
= buf
[8];
1649 sub
->dt
.second
= buf
[9];
1650 sub
->dt
.frame
= buf
[10];
1656 mcdx_requestmultidiskinfo(struct s_drive_stuff
*stuffp
, struct s_multi
*multi
, int tries
)
1661 if (stuffp
->present
& MULTI
) {
1662 ans
= mcdx_talk(stuffp
, "\x11", 1, buf
, sizeof(buf
), 2 * HZ
, tries
);
1663 multi
->multi
= buf
[1];
1664 multi
->msf_last
.minute
= buf
[2];
1665 multi
->msf_last
.second
= buf
[3];
1666 multi
->msf_last
.frame
= buf
[4];
1675 mcdx_requesttocdata(struct s_drive_stuff
*stuffp
, struct s_diskinfo
*info
, int tries
)
1679 ans
= mcdx_talk(stuffp
, "\x10", 1, buf
, sizeof(buf
), 2 * HZ
, tries
);
1684 info
->n_first
= bcd2uint(buf
[1]);
1685 info
->n_last
= bcd2uint(buf
[2]);
1686 info
->msf_leadout
.minute
= buf
[3];
1687 info
->msf_leadout
.second
= buf
[4];
1688 info
->msf_leadout
.frame
= buf
[5];
1689 info
->msf_first
.minute
= buf
[6];
1690 info
->msf_first
.second
= buf
[7];
1691 info
->msf_first
.frame
= buf
[8];
1697 mcdx_setdrivemode(struct s_drive_stuff
*stuffp
, enum drivemodes mode
, int tries
)
1702 xtrace(HW
, "setdrivemode() %d\n", mode
);
1704 if (-1 == (ans
= mcdx_talk(stuffp
, "\xc2", 1, cmd
, sizeof(cmd
), 5 * HZ
, tries
)))
1708 case TOC
: cmd
[1] |= 0x04; break;
1709 case DATA
: cmd
[1] &= ~0x04; break;
1710 case RAW
: cmd
[1] |= 0x40; break;
1711 case COOKED
: cmd
[1] &= ~0x40; break;
1715 return mcdx_talk(stuffp
, cmd
, 2, NULL
, 1, 5 * HZ
, tries
);
1719 mcdx_setdatamode(struct s_drive_stuff
*stuffp
, enum datamodes mode
, int tries
)
1721 unsigned char cmd
[2] = { 0xa0 };
1722 xtrace(HW
, "setdatamode() %d\n", mode
);
1724 case MODE0
: cmd
[1] = 0x00; break;
1725 case MODE1
: cmd
[1] = 0x01; break;
1726 case MODE2
: cmd
[1] = 0x02; break;
1727 default: return -EINVAL
;
1729 return mcdx_talk(stuffp
, cmd
, 2, NULL
, 1, 5 * HZ
, tries
);
1733 mcdx_config(struct s_drive_stuff
*stuffp
, int tries
)
1737 xtrace(HW
, "config()\n");
1741 cmd
[1] = 0x10; /* irq enable */
1742 cmd
[2] = 0x05; /* pre, err irq enable */
1744 if (-1 == mcdx_talk(stuffp
, cmd
, 3, NULL
, 1, 1 * HZ
, tries
))
1747 cmd
[1] = 0x02; /* dma select */
1748 cmd
[2] = 0x00; /* no dma */
1750 return mcdx_talk(stuffp
, cmd
, 3, NULL
, 1, 1 * HZ
, tries
);
1754 mcdx_requestversion(struct s_drive_stuff
*stuffp
, struct s_version
*ver
, int tries
)
1759 if (-1 == (ans
= mcdx_talk(stuffp
, "\xdc",
1760 1, buf
, sizeof(buf
), 2 * HZ
, tries
)))
1770 mcdx_reset(struct s_drive_stuff
*stuffp
, enum resetmodes mode
, int tries
)
1773 outb(0, (unsigned int) stuffp
->wreg_chn
); /* no dma, no irq -> hardware */
1774 outb(0, (unsigned int) stuffp
->wreg_reset
); /* hw reset */
1776 } else return mcdx_talk(stuffp
, "\x60", 1, NULL
, 1, 5 * HZ
, tries
);
1779 static int mcdx_lockdoor(struct cdrom_device_info
* cdi
, int lock
)
1781 struct s_drive_stuff
*stuffp
= mcdx_stuffp
[MINOR(cdi
->dev
)];
1782 char cmd
[2] = { 0xfe };
1784 if (!(stuffp
->present
& DOOR
))
1786 if (stuffp
->present
& DOOR
) {
1787 cmd
[1] = lock
? 0x01 : 0x00;
1788 return mcdx_talk(stuffp
, cmd
, sizeof(cmd
), NULL
, 1, 5 * HZ
, 3);
1793 mcdx_getstatus(struct s_drive_stuff
*stuffp
, int tries
)
1794 { return mcdx_talk(stuffp
, "\x40", 1, NULL
, 1, 5 * HZ
, tries
); }
1797 mcdx_getval(struct s_drive_stuff
*stuffp
, int to
, int delay
, char* buf
)
1799 unsigned long timeout
= to
+ jiffies
;
1804 while (inb((unsigned int) stuffp
->rreg_status
) & MCDX_RBIT_STEN
) {
1805 if (time_after(jiffies
, timeout
)) return -1;
1806 mcdx_delay(stuffp
, delay
);
1809 *buf
= (unsigned char) inb((unsigned int) stuffp
->rreg_data
) & 0xff;
1815 mcdx_setattentuator(
1816 struct s_drive_stuff
* stuffp
,
1817 struct cdrom_volctrl
* vol
,
1822 cmd
[1] = vol
->channel0
;
1824 cmd
[3] = vol
->channel1
;
1827 return mcdx_talk(stuffp
, cmd
, sizeof(cmd
), NULL
, 5, 200, tries
);
1830 /* ex:set ts=4 sw=4 ai si: */