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/module.h>
61 #include <linux/errno.h>
62 #include <linux/interrupt.h>
64 #include <linux/kernel.h>
65 #include <linux/cdrom.h>
66 #include <linux/ioport.h>
68 #include <linux/slab.h>
69 #include <linux/init.h>
71 #include <asm/current.h>
72 #include <asm/uaccess.h>
74 #include <linux/major.h>
75 #define MAJOR_NR MITSUMI_X_CDROM_MAJOR
76 #include <linux/blkdev.h>
77 #include <linux/devfs_fs_kernel.h>
85 #define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
88 #define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
90 #define xinfo(fmt, args...) { ; }
94 #define xtrace(lvl, fmt, args...) \
96 { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
97 #define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
99 #define xtrace(lvl, fmt, args...) { ; }
100 #define xdebug(fmt, args...) { ; }
103 /* CONSTANTS *******************************************************/
105 /* Following are the number of sectors we _request_ from the drive
106 every time an access outside the already requested range is done.
107 The _direct_ size is the number of sectors we're allowed to skip
108 directly (performing a read instead of requesting the new sector
110 static const int REQUEST_SIZE
= 800; /* should be less then 255 * 4 */
111 static const int DIRECT_SIZE
= 400; /* should be less then REQUEST_SIZE */
113 enum drivemodes
{ TOC
, DATA
, RAW
, COOKED
};
114 enum datamodes
{ MODE0
, MODE1
, MODE2
};
115 enum resetmodes
{ SOFT
, HARD
};
117 static const int SINGLE
= 0x01; /* single speed drive (FX001S, LU) */
118 static const int DOUBLE
= 0x02; /* double speed drive (FX001D, ..? */
119 static const int DOOR
= 0x04; /* door locking capability */
120 static const int MULTI
= 0x08; /* multi session capability */
122 static const unsigned char READ1X
= 0xc0;
123 static const unsigned char READ2X
= 0xc1;
126 /* DECLARATIONS ****************************************************/
128 unsigned char control
;
131 struct cdrom_msf0 tt
;
132 struct cdrom_msf0 dt
;
136 unsigned int n_first
;
138 struct cdrom_msf0 msf_leadout
;
139 struct cdrom_msf0 msf_first
;
144 struct cdrom_msf0 msf_last
;
152 /* Per drive/controller stuff **************************************/
154 struct s_drive_stuff
{
156 wait_queue_head_t busyq
;
157 wait_queue_head_t lockq
;
158 wait_queue_head_t sleepq
;
161 volatile int introk
; /* status of last irq operation */
162 volatile int busy
; /* drive performs an operation */
163 volatile int lock
; /* exclusive usage */
166 struct s_diskinfo di
;
167 struct s_multi multi
;
168 struct s_subqcode
*toc
; /* first entry of the toc array */
169 struct s_subqcode start
;
170 struct s_subqcode stop
;
171 int xa
; /* 1 if xa disk */
172 int audio
; /* 1 if audio disk */
175 /* `buffer' control */
176 volatile int valid
; /* pending, ..., values are valid */
177 volatile int pending
; /* next sector to be read */
178 volatile int low_border
; /* first sector not to be skipped direct */
179 volatile int high_border
; /* first sector `out of area' */
181 volatile int int_err
;
185 unsigned wreg_data
; /* w data */
186 unsigned wreg_reset
; /* w hardware reset */
187 unsigned wreg_hcon
; /* w hardware conf */
188 unsigned wreg_chn
; /* w channel */
189 unsigned rreg_data
; /* r data */
190 unsigned rreg_status
; /* r status */
192 int irq
; /* irq used by this drive */
193 int present
; /* drive present and its capabilities */
194 unsigned char readcmd
; /* read cmd depends on single/double speed */
195 unsigned char playcmd
; /* play should always be single speed */
196 unsigned int xxx
; /* set if changed, reset while open */
197 unsigned int yyy
; /* set if changed, reset by media_changed */
198 int users
; /* keeps track of open/close */
199 int lastsector
; /* last block accessible */
200 int status
; /* last operation's error / status */
201 int readerrs
; /* # of blocks read w/o error */
202 struct cdrom_device_info info
;
203 struct gendisk
*disk
;
207 /* Prototypes ******************************************************/
209 /* The following prototypes are already declared elsewhere. They are
210 repeated here to show what's going on. And to sense, if they're
211 changed elsewhere. */
213 static int mcdx_init(void);
215 static int mcdx_block_open(struct inode
*inode
, struct file
*file
)
217 struct s_drive_stuff
*p
= inode
->i_bdev
->bd_disk
->private_data
;
218 return cdrom_open(&p
->info
, inode
, file
);
221 static int mcdx_block_release(struct inode
*inode
, struct file
*file
)
223 struct s_drive_stuff
*p
= inode
->i_bdev
->bd_disk
->private_data
;
224 return cdrom_release(&p
->info
, file
);
227 static int mcdx_block_ioctl(struct inode
*inode
, struct file
*file
,
228 unsigned cmd
, unsigned long arg
)
230 struct s_drive_stuff
*p
= inode
->i_bdev
->bd_disk
->private_data
;
231 return cdrom_ioctl(file
, &p
->info
, inode
, cmd
, arg
);
234 static int mcdx_block_media_changed(struct gendisk
*disk
)
236 struct s_drive_stuff
*p
= disk
->private_data
;
237 return cdrom_media_changed(&p
->info
);
240 static struct block_device_operations mcdx_bdops
=
242 .owner
= THIS_MODULE
,
243 .open
= mcdx_block_open
,
244 .release
= mcdx_block_release
,
245 .ioctl
= mcdx_block_ioctl
,
246 .media_changed
= mcdx_block_media_changed
,
250 /* Indirect exported functions. These functions are exported by their
251 addresses, such as mcdx_open and mcdx_close in the
252 structure mcdx_dops. */
254 /* exported by file_ops */
255 static int mcdx_open(struct cdrom_device_info
*cdi
, int purpose
);
256 static void mcdx_close(struct cdrom_device_info
*cdi
);
257 static int mcdx_media_changed(struct cdrom_device_info
*cdi
, int disc_nr
);
258 static int mcdx_tray_move(struct cdrom_device_info
*cdi
, int position
);
259 static int mcdx_lockdoor(struct cdrom_device_info
*cdi
, int lock
);
260 static int mcdx_audio_ioctl(struct cdrom_device_info
*cdi
,
261 unsigned int cmd
, void *arg
);
263 /* misc internal support functions */
264 static void log2msf(unsigned int, struct cdrom_msf0
*);
265 static unsigned int msf2log(const struct cdrom_msf0
*);
266 static unsigned int uint2bcd(unsigned int);
267 static unsigned int bcd2uint(unsigned char);
268 static unsigned port(int *);
269 static int irq(int *);
270 static void mcdx_delay(struct s_drive_stuff
*, long jifs
);
271 static int mcdx_transfer(struct s_drive_stuff
*, char *buf
, int sector
,
273 static int mcdx_xfer(struct s_drive_stuff
*, char *buf
, int sector
,
276 static int mcdx_config(struct s_drive_stuff
*, int);
277 static int mcdx_requestversion(struct s_drive_stuff
*, struct s_version
*,
279 static int mcdx_stop(struct s_drive_stuff
*, int);
280 static int mcdx_hold(struct s_drive_stuff
*, int);
281 static int mcdx_reset(struct s_drive_stuff
*, enum resetmodes
, int);
282 static int mcdx_setdrivemode(struct s_drive_stuff
*, enum drivemodes
, int);
283 static int mcdx_setdatamode(struct s_drive_stuff
*, enum datamodes
, int);
284 static int mcdx_requestsubqcode(struct s_drive_stuff
*,
285 struct s_subqcode
*, int);
286 static int mcdx_requestmultidiskinfo(struct s_drive_stuff
*,
287 struct s_multi
*, int);
288 static int mcdx_requesttocdata(struct s_drive_stuff
*, struct s_diskinfo
*,
290 static int mcdx_getstatus(struct s_drive_stuff
*, int);
291 static int mcdx_getval(struct s_drive_stuff
*, int to
, int delay
, char *);
292 static int mcdx_talk(struct s_drive_stuff
*,
293 const unsigned char *cmd
, size_t,
294 void *buffer
, size_t size
, unsigned int timeout
, int);
295 static int mcdx_readtoc(struct s_drive_stuff
*);
296 static int mcdx_playtrk(struct s_drive_stuff
*, const struct cdrom_ti
*);
297 static int mcdx_playmsf(struct s_drive_stuff
*, const struct cdrom_msf
*);
298 static int mcdx_setattentuator(struct s_drive_stuff
*,
299 struct cdrom_volctrl
*, int);
301 /* static variables ************************************************/
303 static int mcdx_drive_map
[][2] = MCDX_DRIVEMAP
;
304 static struct s_drive_stuff
*mcdx_stuffp
[MCDX_NDRIVES
];
305 static DEFINE_SPINLOCK(mcdx_lock
);
306 static struct request_queue
*mcdx_queue
;
308 /* You can only set the first two pairs, from old MODULE_PARM code. */
309 static int mcdx_set(const char *val
, struct kernel_param
*kp
)
311 get_options((char *)val
, 4, (int *)mcdx_drive_map
);
314 module_param_call(mcdx
, mcdx_set
, NULL
, NULL
, 0);
316 static struct cdrom_device_ops mcdx_dops
= {
318 .release
= mcdx_close
,
319 .media_changed
= mcdx_media_changed
,
320 .tray_move
= mcdx_tray_move
,
321 .lock_door
= mcdx_lockdoor
,
322 .audio_ioctl
= mcdx_audio_ioctl
,
323 .capability
= CDC_OPEN_TRAY
| CDC_LOCK
| CDC_MEDIA_CHANGED
|
324 CDC_PLAY_AUDIO
| CDC_DRIVE_STATUS
,
327 /* KERNEL INTERFACE FUNCTIONS **************************************/
330 static int mcdx_audio_ioctl(struct cdrom_device_info
*cdi
,
331 unsigned int cmd
, void *arg
)
333 struct s_drive_stuff
*stuffp
= cdi
->handle
;
335 if (!stuffp
->present
)
339 if (-1 == mcdx_requesttocdata(stuffp
, &stuffp
->di
, 1)) {
340 stuffp
->lastsector
= -1;
342 stuffp
->lastsector
= (CD_FRAMESIZE
/ 512)
343 * msf2log(&stuffp
->di
.msf_leadout
) - 1;
349 if (-1 == mcdx_readtoc(stuffp
))
358 xtrace(IOCTL
, "ioctl() START\n");
359 /* Spin up the drive. Don't think we can do this.
360 * For now, ignore it.
366 xtrace(IOCTL
, "ioctl() STOP\n");
367 stuffp
->audiostatus
= CDROM_AUDIO_INVALID
;
368 if (-1 == mcdx_stop(stuffp
, 1))
373 case CDROMPLAYTRKIND
:{
374 struct cdrom_ti
*ti
= (struct cdrom_ti
*) arg
;
376 xtrace(IOCTL
, "ioctl() PLAYTRKIND\n");
377 if ((ti
->cdti_trk0
< stuffp
->di
.n_first
)
378 || (ti
->cdti_trk0
> stuffp
->di
.n_last
)
379 || (ti
->cdti_trk1
< stuffp
->di
.n_first
))
381 if (ti
->cdti_trk1
> stuffp
->di
.n_last
)
382 ti
->cdti_trk1
= stuffp
->di
.n_last
;
383 xtrace(PLAYTRK
, "ioctl() track %d to %d\n",
384 ti
->cdti_trk0
, ti
->cdti_trk1
);
385 return mcdx_playtrk(stuffp
, ti
);
389 struct cdrom_msf
*msf
= (struct cdrom_msf
*) arg
;
391 xtrace(IOCTL
, "ioctl() PLAYMSF\n");
393 if ((stuffp
->audiostatus
== CDROM_AUDIO_PLAY
)
394 && (-1 == mcdx_hold(stuffp
, 1)))
397 msf
->cdmsf_min0
= uint2bcd(msf
->cdmsf_min0
);
398 msf
->cdmsf_sec0
= uint2bcd(msf
->cdmsf_sec0
);
399 msf
->cdmsf_frame0
= uint2bcd(msf
->cdmsf_frame0
);
401 msf
->cdmsf_min1
= uint2bcd(msf
->cdmsf_min1
);
402 msf
->cdmsf_sec1
= uint2bcd(msf
->cdmsf_sec1
);
403 msf
->cdmsf_frame1
= uint2bcd(msf
->cdmsf_frame1
);
405 stuffp
->stop
.dt
.minute
= msf
->cdmsf_min1
;
406 stuffp
->stop
.dt
.second
= msf
->cdmsf_sec1
;
407 stuffp
->stop
.dt
.frame
= msf
->cdmsf_frame1
;
409 return mcdx_playmsf(stuffp
, msf
);
413 xtrace(IOCTL
, "ioctl() RESUME\n");
414 return mcdx_playtrk(stuffp
, NULL
);
417 case CDROMREADTOCENTRY
:{
418 struct cdrom_tocentry
*entry
=
419 (struct cdrom_tocentry
*) arg
;
420 struct s_subqcode
*tp
= NULL
;
421 xtrace(IOCTL
, "ioctl() READTOCENTRY\n");
423 if (-1 == mcdx_readtoc(stuffp
))
425 if (entry
->cdte_track
== CDROM_LEADOUT
)
426 tp
= &stuffp
->toc
[stuffp
->di
.n_last
-
427 stuffp
->di
.n_first
+ 1];
428 else if (entry
->cdte_track
> stuffp
->di
.n_last
429 || entry
->cdte_track
< stuffp
->di
.n_first
)
432 tp
= &stuffp
->toc
[entry
->cdte_track
-
437 entry
->cdte_adr
= tp
->control
;
438 entry
->cdte_ctrl
= tp
->control
>> 4;
439 /* Always return stuff in MSF, and let the Uniform cdrom driver
440 worry about what the user actually wants */
441 entry
->cdte_addr
.msf
.minute
=
442 bcd2uint(tp
->dt
.minute
);
443 entry
->cdte_addr
.msf
.second
=
444 bcd2uint(tp
->dt
.second
);
445 entry
->cdte_addr
.msf
.frame
=
446 bcd2uint(tp
->dt
.frame
);
451 struct cdrom_subchnl
*sub
=
452 (struct cdrom_subchnl
*) arg
;
455 xtrace(IOCTL
, "ioctl() SUBCHNL\n");
457 if (-1 == mcdx_requestsubqcode(stuffp
, &q
, 2))
460 xtrace(SUBCHNL
, "audiostatus: %x\n",
461 stuffp
->audiostatus
);
462 sub
->cdsc_audiostatus
= stuffp
->audiostatus
;
463 sub
->cdsc_adr
= q
.control
;
464 sub
->cdsc_ctrl
= q
.control
>> 4;
465 sub
->cdsc_trk
= bcd2uint(q
.tno
);
466 sub
->cdsc_ind
= bcd2uint(q
.index
);
468 xtrace(SUBCHNL
, "trk %d, ind %d\n",
469 sub
->cdsc_trk
, sub
->cdsc_ind
);
470 /* Always return stuff in MSF, and let the Uniform cdrom driver
471 worry about what the user actually wants */
472 sub
->cdsc_absaddr
.msf
.minute
=
473 bcd2uint(q
.dt
.minute
);
474 sub
->cdsc_absaddr
.msf
.second
=
475 bcd2uint(q
.dt
.second
);
476 sub
->cdsc_absaddr
.msf
.frame
= bcd2uint(q
.dt
.frame
);
477 sub
->cdsc_reladdr
.msf
.minute
=
478 bcd2uint(q
.tt
.minute
);
479 sub
->cdsc_reladdr
.msf
.second
=
480 bcd2uint(q
.tt
.second
);
481 sub
->cdsc_reladdr
.msf
.frame
= bcd2uint(q
.tt
.frame
);
483 "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
484 sub
->cdsc_absaddr
.msf
.minute
,
485 sub
->cdsc_absaddr
.msf
.second
,
486 sub
->cdsc_absaddr
.msf
.frame
,
487 sub
->cdsc_reladdr
.msf
.minute
,
488 sub
->cdsc_reladdr
.msf
.second
,
489 sub
->cdsc_reladdr
.msf
.frame
);
494 case CDROMREADTOCHDR
:{
495 struct cdrom_tochdr
*toc
=
496 (struct cdrom_tochdr
*) arg
;
498 xtrace(IOCTL
, "ioctl() READTOCHDR\n");
499 toc
->cdth_trk0
= stuffp
->di
.n_first
;
500 toc
->cdth_trk1
= stuffp
->di
.n_last
;
502 "ioctl() track0 = %d, track1 = %d\n",
503 stuffp
->di
.n_first
, stuffp
->di
.n_last
);
508 xtrace(IOCTL
, "ioctl() PAUSE\n");
509 if (stuffp
->audiostatus
!= CDROM_AUDIO_PLAY
)
511 if (-1 == mcdx_stop(stuffp
, 1))
513 stuffp
->audiostatus
= CDROM_AUDIO_PAUSED
;
515 mcdx_requestsubqcode(stuffp
, &stuffp
->start
,
521 case CDROMMULTISESSION
:{
522 struct cdrom_multisession
*ms
=
523 (struct cdrom_multisession
*) arg
;
524 xtrace(IOCTL
, "ioctl() MULTISESSION\n");
525 /* Always return stuff in LBA, and let the Uniform cdrom driver
526 worry about what the user actually wants */
527 ms
->addr
.lba
= msf2log(&stuffp
->multi
.msf_last
);
528 ms
->xa_flag
= !!stuffp
->multi
.multi
;
530 "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
531 ms
->xa_flag
, ms
->addr
.lba
,
532 stuffp
->multi
.msf_last
.minute
,
533 stuffp
->multi
.msf_last
.second
,
534 stuffp
->multi
.msf_last
.frame
);
540 xtrace(IOCTL
, "ioctl() EJECT\n");
541 if (stuffp
->users
> 1)
543 return (mcdx_tray_move(cdi
, 1));
546 case CDROMCLOSETRAY
:{
547 xtrace(IOCTL
, "ioctl() CDROMCLOSETRAY\n");
548 return (mcdx_tray_move(cdi
, 0));
552 struct cdrom_volctrl
*volctrl
=
553 (struct cdrom_volctrl
*) arg
;
554 xtrace(IOCTL
, "ioctl() VOLCTRL\n");
556 #if 0 /* not tested! */
557 /* adjust for the weirdness of workman (md) */
558 /* can't test it (hs) */
559 volctrl
.channel2
= volctrl
.channel1
;
560 volctrl
.channel1
= volctrl
.channel3
= 0x00;
562 return mcdx_setattentuator(stuffp
, volctrl
, 2);
570 static void do_mcdx_request(request_queue_t
* q
)
572 struct s_drive_stuff
*stuffp
;
577 req
= elv_next_request(q
);
581 stuffp
= req
->rq_disk
->private_data
;
583 if (!stuffp
->present
) {
584 xwarn("do_request(): bad device: %s\n",req
->rq_disk
->disk_name
);
585 xtrace(REQUEST
, "end_request(0): bad device\n");
591 xwarn("do_request() attempt to read from audio cd\n");
592 xtrace(REQUEST
, "end_request(0): read from audio\n");
597 xtrace(REQUEST
, "do_request() (%lu + %lu)\n",
598 req
->sector
, req
->nr_sectors
);
600 if (req
->cmd
!= READ
) {
601 xwarn("do_request(): non-read command to cd!!\n");
602 xtrace(REQUEST
, "end_request(0): write\n");
608 while (req
->nr_sectors
) {
611 i
= mcdx_transfer(stuffp
,
621 req
->nr_sectors
-= i
;
622 req
->buffer
+= (i
* 512);
627 xtrace(REQUEST
, "end_request(1)\n");
634 static int mcdx_open(struct cdrom_device_info
*cdi
, int purpose
)
636 struct s_drive_stuff
*stuffp
;
637 xtrace(OPENCLOSE
, "open()\n");
638 stuffp
= cdi
->handle
;
639 if (!stuffp
->present
)
642 /* Make the modules looking used ... (thanx bjorn).
643 * But we shouldn't forget to decrement the module counter
646 /* this is only done to test if the drive talks with us */
647 if (-1 == mcdx_getstatus(stuffp
, 1))
652 xtrace(OPENCLOSE
, "open() media changed\n");
653 stuffp
->audiostatus
= CDROM_AUDIO_INVALID
;
655 xtrace(OPENCLOSE
, "open() Request multisession info\n");
657 mcdx_requestmultidiskinfo(stuffp
, &stuffp
->multi
, 6))
658 xinfo("No multidiskinfo\n");
661 if (!stuffp
->multi
.multi
)
662 stuffp
->multi
.msf_last
.second
= 2;
664 xtrace(OPENCLOSE
, "open() MS: %d, last @ %02x:%02x.%02x\n",
666 stuffp
->multi
.msf_last
.minute
,
667 stuffp
->multi
.msf_last
.second
,
668 stuffp
->multi
.msf_last
.frame
);
671 } /* got multisession information */
672 /* request the disks table of contents (aka diskinfo) */
673 if (-1 == mcdx_requesttocdata(stuffp
, &stuffp
->di
, 1)) {
675 stuffp
->lastsector
= -1;
679 stuffp
->lastsector
= (CD_FRAMESIZE
/ 512)
680 * msf2log(&stuffp
->di
.msf_leadout
) - 1;
683 "open() start %d (%02x:%02x.%02x) %d\n",
685 stuffp
->di
.msf_first
.minute
,
686 stuffp
->di
.msf_first
.second
,
687 stuffp
->di
.msf_first
.frame
,
688 msf2log(&stuffp
->di
.msf_first
));
690 "open() last %d (%02x:%02x.%02x) %d\n",
692 stuffp
->di
.msf_leadout
.minute
,
693 stuffp
->di
.msf_leadout
.second
,
694 stuffp
->di
.msf_leadout
.frame
,
695 msf2log(&stuffp
->di
.msf_leadout
));
699 xtrace(MALLOC
, "open() free old toc @ %p\n",
706 xtrace(OPENCLOSE
, "open() init irq generation\n");
707 if (-1 == mcdx_config(stuffp
, 1))
710 /* Set the read speed */
711 xwarn("AAA %x AAA\n", stuffp
->readcmd
);
712 if (stuffp
->readerrs
)
713 stuffp
->readcmd
= READ1X
;
716 stuffp
->present
| SINGLE
? READ1X
: READ2X
;
717 xwarn("XXX %x XXX\n", stuffp
->readcmd
);
720 stuffp
->present
| SINGLE
? READ1X
: READ2X
;
723 /* try to get the first sector, iff any ... */
724 if (stuffp
->lastsector
>= 0) {
732 for (tries
= 6; tries
; tries
--) {
736 xtrace(OPENCLOSE
, "open() try as %s\n",
737 stuffp
->xa
? "XA" : "normal");
739 if (-1 == (ans
= mcdx_setdatamode(stuffp
,
750 if ((stuffp
->audio
= e_audio(ans
)))
755 mcdx_transfer(stuffp
, buf
, 0, 1)));
759 stuffp
->xa
= !stuffp
->xa
;
762 /* xa disks will be read in raw mode, others not */
763 if (-1 == mcdx_setdrivemode(stuffp
,
764 stuffp
->xa
? RAW
: COOKED
,
768 xinfo("open() audio disk found\n");
769 } else if (stuffp
->lastsector
>= 0) {
770 xinfo("open() %s%s disk found\n",
771 stuffp
->xa
? "XA / " : "",
773 multi
? "Multi Session" : "Single Session");
781 static void mcdx_close(struct cdrom_device_info
*cdi
)
783 struct s_drive_stuff
*stuffp
;
785 xtrace(OPENCLOSE
, "close()\n");
787 stuffp
= cdi
->handle
;
792 static int mcdx_media_changed(struct cdrom_device_info
*cdi
, int disc_nr
)
793 /* Return: 1 if media changed since last call to this function
796 struct s_drive_stuff
*stuffp
;
798 xinfo("mcdx_media_changed called for device %s\n", cdi
->name
);
800 stuffp
= cdi
->handle
;
801 mcdx_getstatus(stuffp
, 1);
803 if (stuffp
->yyy
== 0)
811 static int __init
mcdx_setup(char *str
)
814 (void) get_options(str
, ARRAY_SIZE(pi
), pi
);
817 mcdx_drive_map
[0][0] = pi
[1];
819 mcdx_drive_map
[0][1] = pi
[2];
823 __setup("mcdx=", mcdx_setup
);
827 /* DIRTY PART ******************************************************/
829 static void mcdx_delay(struct s_drive_stuff
*stuff
, long jifs
)
830 /* This routine is used for sleeping.
831 * A jifs value <0 means NO sleeping,
832 * =0 means minimal sleeping (let the kernel
833 * run for other processes)
834 * >0 means at least sleep for that amount.
835 * May be we could use a simple count loop w/ jumps to itself, but
836 * I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
841 xtrace(SLEEP
, "*** delay: sleepq\n");
842 interruptible_sleep_on_timeout(&stuff
->sleepq
, jifs
);
843 xtrace(SLEEP
, "delay awoken\n");
844 if (signal_pending(current
)) {
845 xtrace(SLEEP
, "got signal\n");
849 static irqreturn_t
mcdx_intr(int irq
, void *dev_id
, struct pt_regs
*regs
)
851 struct s_drive_stuff
*stuffp
= dev_id
;
854 if (stuffp
== NULL
) {
855 xwarn("mcdx: no device for intr %d\n", irq
);
859 if (!stuffp
->busy
&& stuffp
->pending
)
863 /* get the interrupt status */
864 b
= inb(stuffp
->rreg_status
);
865 stuffp
->introk
= ~b
& MCDX_RBIT_DTEN
;
867 /* NOTE: We only should get interrupts if the data we
868 * requested are ready to transfer.
869 * But the drive seems to generate ``asynchronous'' interrupts
870 * on several error conditions too. (Despite the err int enable
871 * setting during initialisation) */
873 /* if not ok, read the next byte as the drives status */
874 if (!stuffp
->introk
) {
875 xtrace(IRQ
, "intr() irq %d hw status 0x%02x\n", irq
, b
);
876 if (~b
& MCDX_RBIT_STEN
) {
877 xinfo("intr() irq %d status 0x%02x\n",
878 irq
, inb(stuffp
->rreg_data
));
880 xinfo("intr() irq %d ambiguous hw status\n", irq
);
883 xtrace(IRQ
, "irq() irq %d ok, status %02x\n", irq
, b
);
887 wake_up_interruptible(&stuffp
->busyq
);
892 static int mcdx_talk(struct s_drive_stuff
*stuffp
,
893 const unsigned char *cmd
, size_t cmdlen
,
894 void *buffer
, size_t size
, unsigned int timeout
, int tries
)
895 /* Send a command to the drive, wait for the result.
896 * returns -1 on timeout, drive status otherwise
897 * If buffer is not zero, the result (length size) is stored there.
898 * If buffer is zero the size should be the number of bytes to read
899 * from the drive. These bytes are discarded.
906 /* Somebody wants the data read? */
907 if ((discard
= (buffer
== NULL
)))
910 while (stuffp
->lock
) {
911 xtrace(SLEEP
, "*** talk: lockq\n");
912 interruptible_sleep_on(&stuffp
->lockq
);
913 xtrace(SLEEP
, "talk: awoken\n");
918 /* An operation other then reading data destroys the
919 * data already requested and remembered in stuffp->request, ... */
922 #if MCDX_DEBUG & TALK
926 "talk() %d / %d tries, res.size %d, command 0x%02x",
927 tries
, timeout
, size
, (unsigned char) cmd
[0]);
928 for (i
= 1; i
< cmdlen
; i
++)
929 xtrace(TALK
, " 0x%02x", cmd
[i
]);
934 /* give up if all tries are done (bad) or if the status
936 for (st
= -1; st
== -1 && tries
; tries
--) {
938 char *bp
= (char *) buffer
;
941 outsb(stuffp
->wreg_data
, cmd
, cmdlen
);
942 xtrace(TALK
, "talk() command sent\n");
944 /* get the status byte */
945 if (-1 == mcdx_getval(stuffp
, timeout
, 0, bp
)) {
946 xinfo("talk() %02x timed out (status), %d tr%s left\n",
947 cmd
[0], tries
- 1, tries
== 2 ? "y" : "ies");
955 xtrace(TALK
, "talk() got status 0x%02x\n", st
);
959 xwarn("command error cmd = %02x %s \n",
960 cmd
[0], cmdlen
> 1 ? "..." : "");
966 if (stuffp
->audiostatus
== CDROM_AUDIO_INVALID
)
967 stuffp
->audiostatus
=
968 e_audiobusy(st
) ? CDROM_AUDIO_PLAY
:
969 CDROM_AUDIO_NO_STATUS
;
970 else if (stuffp
->audiostatus
== CDROM_AUDIO_PLAY
971 && e_audiobusy(st
) == 0)
972 stuffp
->audiostatus
= CDROM_AUDIO_COMPLETED
;
976 xinfo("talk() media changed\n");
977 stuffp
->xxx
= stuffp
->yyy
= 1;
980 /* now actually get the data */
982 if (-1 == mcdx_getval(stuffp
, timeout
, 0, bp
)) {
983 xinfo("talk() %02x timed out (data), %d tr%s left\n",
985 tries
== 2 ? "y" : "ies");
991 xtrace(TALK
, "talk() got 0x%02x\n", *(bp
- 1));
996 if (!tries
&& st
== -1)
997 xinfo("talk() giving up\n");
1001 wake_up_interruptible(&stuffp
->lockq
);
1003 xtrace(TALK
, "talk() done with 0x%02x\n", st
);
1007 /* MODULE STUFF ***********************************************************/
1009 int __mcdx_init(void)
1015 for (i
= 0; i
< MCDX_NDRIVES
; i
++) {
1016 if (mcdx_stuffp
[i
]) {
1017 xtrace(INIT
, "init_module() drive %d stuff @ %p\n",
1029 static void __exit
mcdx_exit(void)
1033 xinfo("cleanup_module called\n");
1035 for (i
= 0; i
< MCDX_NDRIVES
; i
++) {
1036 struct s_drive_stuff
*stuffp
= mcdx_stuffp
[i
];
1039 del_gendisk(stuffp
->disk
);
1040 if (unregister_cdrom(&stuffp
->info
)) {
1041 printk(KERN_WARNING
"Can't unregister cdrom mcdx\n");
1044 put_disk(stuffp
->disk
);
1045 release_region(stuffp
->wreg_data
, MCDX_IO_SIZE
);
1046 free_irq(stuffp
->irq
, NULL
);
1048 xtrace(MALLOC
, "cleanup_module() free toc @ %p\n",
1052 xtrace(MALLOC
, "cleanup_module() free stuffp @ %p\n",
1054 mcdx_stuffp
[i
] = NULL
;
1058 if (unregister_blkdev(MAJOR_NR
, "mcdx") != 0) {
1059 xwarn("cleanup() unregister_blkdev() failed\n");
1061 blk_cleanup_queue(mcdx_queue
);
1064 xinfo("cleanup() succeeded\n");
1069 module_init(__mcdx_init
);
1071 module_exit(mcdx_exit
);
1074 /* Support functions ************************************************/
1076 static int __init
mcdx_init_drive(int drive
)
1078 struct s_version version
;
1079 struct gendisk
*disk
;
1080 struct s_drive_stuff
*stuffp
;
1081 int size
= sizeof(*stuffp
);
1084 xtrace(INIT
, "init() try drive %d\n", drive
);
1086 xtrace(INIT
, "kmalloc space for stuffpt's\n");
1087 xtrace(MALLOC
, "init() malloc %d bytes\n", size
);
1088 if (!(stuffp
= kmalloc(size
, GFP_KERNEL
))) {
1089 xwarn("init() malloc failed\n");
1093 disk
= alloc_disk(1);
1095 xwarn("init() malloc failed\n");
1100 xtrace(INIT
, "init() got %d bytes for drive stuff @ %p\n",
1101 sizeof(*stuffp
), stuffp
);
1103 /* set default values */
1104 memset(stuffp
, 0, sizeof(*stuffp
));
1106 stuffp
->present
= 0; /* this should be 0 already */
1107 stuffp
->toc
= NULL
; /* this should be NULL already */
1109 /* setup our irq and i/o addresses */
1110 stuffp
->irq
= irq(mcdx_drive_map
[drive
]);
1111 stuffp
->wreg_data
= stuffp
->rreg_data
= port(mcdx_drive_map
[drive
]);
1112 stuffp
->wreg_reset
= stuffp
->rreg_status
= stuffp
->wreg_data
+ 1;
1113 stuffp
->wreg_hcon
= stuffp
->wreg_reset
+ 1;
1114 stuffp
->wreg_chn
= stuffp
->wreg_hcon
+ 1;
1116 init_waitqueue_head(&stuffp
->busyq
);
1117 init_waitqueue_head(&stuffp
->lockq
);
1118 init_waitqueue_head(&stuffp
->sleepq
);
1120 /* check if i/o addresses are available */
1121 if (!request_region(stuffp
->wreg_data
, MCDX_IO_SIZE
, "mcdx")) {
1122 xwarn("0x%03x,%d: Init failed. "
1123 "I/O ports (0x%03x..0x%03x) already in use.\n",
1124 stuffp
->wreg_data
, stuffp
->irq
,
1126 stuffp
->wreg_data
+ MCDX_IO_SIZE
- 1);
1127 xtrace(MALLOC
, "init() free stuffp @ %p\n", stuffp
);
1130 xtrace(INIT
, "init() continue at next drive\n");
1131 return 0; /* next drive */
1134 xtrace(INIT
, "init() i/o port is available at 0x%03x\n"
1136 xtrace(INIT
, "init() hardware reset\n");
1137 mcdx_reset(stuffp
, HARD
, 1);
1139 xtrace(INIT
, "init() get version\n");
1140 if (-1 == mcdx_requestversion(stuffp
, &version
, 4)) {
1141 /* failed, next drive */
1142 release_region(stuffp
->wreg_data
, MCDX_IO_SIZE
);
1143 xwarn("%s=0x%03x,%d: Init failed. Can't get version.\n",
1144 MCDX
, stuffp
->wreg_data
, stuffp
->irq
);
1145 xtrace(MALLOC
, "init() free stuffp @ %p\n", stuffp
);
1148 xtrace(INIT
, "init() continue at next drive\n");
1152 switch (version
.code
) {
1154 stuffp
->readcmd
= READ2X
;
1155 stuffp
->present
= DOUBLE
| DOOR
| MULTI
;
1158 stuffp
->readcmd
= READ1X
;
1159 stuffp
->present
= SINGLE
| DOOR
| MULTI
;
1162 stuffp
->readcmd
= READ1X
;
1163 stuffp
->present
= SINGLE
;
1166 stuffp
->present
= 0;
1170 stuffp
->playcmd
= READ1X
;
1172 if (!stuffp
->present
) {
1173 release_region(stuffp
->wreg_data
, MCDX_IO_SIZE
);
1174 xwarn("%s=0x%03x,%d: Init failed. No Mitsumi CD-ROM?.\n",
1175 MCDX
, stuffp
->wreg_data
, stuffp
->irq
);
1178 return 0; /* next drive */
1181 xtrace(INIT
, "init() register blkdev\n");
1182 if (register_blkdev(MAJOR_NR
, "mcdx")) {
1183 release_region(stuffp
->wreg_data
, MCDX_IO_SIZE
);
1189 mcdx_queue
= blk_init_queue(do_mcdx_request
, &mcdx_lock
);
1191 unregister_blkdev(MAJOR_NR
, "mcdx");
1192 release_region(stuffp
->wreg_data
, MCDX_IO_SIZE
);
1198 xtrace(INIT
, "init() subscribe irq and i/o\n");
1199 if (request_irq(stuffp
->irq
, mcdx_intr
, SA_INTERRUPT
, "mcdx", stuffp
)) {
1200 release_region(stuffp
->wreg_data
, MCDX_IO_SIZE
);
1201 xwarn("%s=0x%03x,%d: Init failed. Can't get irq (%d).\n",
1202 MCDX
, stuffp
->wreg_data
, stuffp
->irq
, stuffp
->irq
);
1204 blk_cleanup_queue(mcdx_queue
);
1210 xtrace(INIT
, "init() get garbage\n");
1213 mcdx_delay(stuffp
, HZ
/ 2);
1214 for (i
= 100; i
; i
--)
1215 (void) inb(stuffp
->rreg_status
);
1220 /* irq 11 -> channel register */
1221 outb(0x50, stuffp
->wreg_chn
);
1224 xtrace(INIT
, "init() set non dma but irq mode\n");
1225 mcdx_config(stuffp
, 1);
1227 stuffp
->info
.ops
= &mcdx_dops
;
1228 stuffp
->info
.speed
= 2;
1229 stuffp
->info
.capacity
= 1;
1230 stuffp
->info
.handle
= stuffp
;
1231 sprintf(stuffp
->info
.name
, "mcdx%d", drive
);
1232 disk
->major
= MAJOR_NR
;
1233 disk
->first_minor
= drive
;
1234 strcpy(disk
->disk_name
, stuffp
->info
.name
);
1235 disk
->fops
= &mcdx_bdops
;
1236 disk
->flags
= GENHD_FL_CD
;
1237 stuffp
->disk
= disk
;
1239 sprintf(msg
, " mcdx: Mitsumi CD-ROM installed at 0x%03x, irq %d."
1240 " (Firmware version %c %x)\n",
1241 stuffp
->wreg_data
, stuffp
->irq
, version
.code
, version
.ver
);
1242 mcdx_stuffp
[drive
] = stuffp
;
1243 xtrace(INIT
, "init() mcdx_stuffp[%d] = %p\n", drive
, stuffp
);
1244 if (register_cdrom(&stuffp
->info
) != 0) {
1245 printk("Cannot register Mitsumi CD-ROM!\n");
1246 free_irq(stuffp
->irq
, NULL
);
1247 release_region(stuffp
->wreg_data
, MCDX_IO_SIZE
);
1250 if (unregister_blkdev(MAJOR_NR
, "mcdx") != 0)
1251 xwarn("cleanup() unregister_blkdev() failed\n");
1252 blk_cleanup_queue(mcdx_queue
);
1255 disk
->private_data
= stuffp
;
1256 disk
->queue
= mcdx_queue
;
1262 static int __init
mcdx_init(void)
1265 xwarn("Version 2.14(hs) \n");
1267 xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
1269 /* zero the pointer array */
1270 for (drive
= 0; drive
< MCDX_NDRIVES
; drive
++)
1271 mcdx_stuffp
[drive
] = NULL
;
1273 /* do the initialisation */
1274 for (drive
= 0; drive
< MCDX_NDRIVES
; drive
++) {
1275 switch (mcdx_init_drive(drive
)) {
1285 static int mcdx_transfer(struct s_drive_stuff
*stuffp
,
1286 char *p
, int sector
, int nr_sectors
)
1287 /* This seems to do the actually transfer. But it does more. It
1288 keeps track of errors occurred and will (if possible) fall back
1289 to single speed on error.
1290 Return: -1 on timeout or other error
1291 else status byte (as in stuff->st) */
1295 ans
= mcdx_xfer(stuffp
, p
, sector
, nr_sectors
);
1303 if (stuffp
->readerrs
&& stuffp
->readcmd
== READ1X
) {
1304 xwarn("XXX Already reading 1x -- no chance\n");
1308 xwarn("XXX Fallback to 1x\n");
1310 stuffp
->readcmd
= READ1X
;
1311 return mcdx_transfer(stuffp
, p
, sector
, nr_sectors
);
1317 static int mcdx_xfer(struct s_drive_stuff
*stuffp
,
1318 char *p
, int sector
, int nr_sectors
)
1319 /* This does actually the transfer from the drive.
1320 Return: -1 on timeout or other error
1321 else status byte (as in stuff->st) */
1327 if (stuffp
->audio
) {
1328 xwarn("Attempt to read from audio CD.\n");
1332 if (!stuffp
->readcmd
) {
1333 xinfo("Can't transfer from missing disk.\n");
1337 while (stuffp
->lock
) {
1338 interruptible_sleep_on(&stuffp
->lockq
);
1341 if (stuffp
->valid
&& (sector
>= stuffp
->pending
)
1342 && (sector
< stuffp
->low_border
)) {
1344 /* All (or at least a part of the sectors requested) seems
1345 * to be already requested, so we don't need to bother the
1346 * drive with new requests ...
1347 * Wait for the drive become idle, but first
1348 * check for possible occurred errors --- the drive
1349 * seems to report them asynchronously */
1352 border
= stuffp
->high_border
< (border
=
1353 sector
+ nr_sectors
)
1354 ? stuffp
->high_border
: border
;
1356 stuffp
->lock
= current
->pid
;
1360 while (stuffp
->busy
) {
1363 interruptible_sleep_on_timeout
1364 (&stuffp
->busyq
, 5 * HZ
);
1366 if (!stuffp
->introk
) {
1368 "error via interrupt\n");
1369 } else if (!timeout
) {
1370 xtrace(XFER
, "timeout\n");
1371 } else if (signal_pending(current
)) {
1372 xtrace(XFER
, "signal\n");
1380 wake_up_interruptible(&stuffp
->lockq
);
1381 xtrace(XFER
, "transfer() done (-1)\n");
1385 /* check if we need to set the busy flag (as we
1386 * expect an interrupt */
1387 stuffp
->busy
= (3 == (stuffp
->pending
& 3));
1389 /* Test if it's the first sector of a block,
1390 * there we have to skip some bytes as we read raw data */
1391 if (stuffp
->xa
&& (0 == (stuffp
->pending
& 3))) {
1393 CD_FRAMESIZE_RAW
- CD_XA_TAIL
-
1395 insb(stuffp
->rreg_data
, p
, HEAD
);
1398 /* now actually read the data */
1399 insb(stuffp
->rreg_data
, p
, 512);
1401 /* test if it's the last sector of a block,
1402 * if so, we have to handle XA special */
1403 if ((3 == (stuffp
->pending
& 3)) && stuffp
->xa
) {
1404 char dummy
[CD_XA_TAIL
];
1405 insb(stuffp
->rreg_data
, &dummy
[0], CD_XA_TAIL
);
1408 if (stuffp
->pending
== sector
) {
1413 } while (++(stuffp
->pending
) < border
);
1416 wake_up_interruptible(&stuffp
->lockq
);
1420 /* The requested sector(s) is/are out of the
1421 * already requested range, so we have to bother the drive
1422 * with a new request. */
1424 static unsigned char cmd
[] = {
1430 cmd
[0] = stuffp
->readcmd
;
1432 /* The numbers held in ->pending, ..., should be valid */
1434 stuffp
->pending
= sector
& ~3;
1436 /* do some sanity checks */
1437 if (stuffp
->pending
> stuffp
->lastsector
) {
1439 ("transfer() sector %d from nirvana requested.\n",
1441 stuffp
->status
= MCDX_ST_EOM
;
1443 xtrace(XFER
, "transfer() done (-1)\n");
1447 if ((stuffp
->low_border
= stuffp
->pending
+ DIRECT_SIZE
)
1448 > stuffp
->lastsector
+ 1) {
1449 xtrace(XFER
, "cut low_border\n");
1450 stuffp
->low_border
= stuffp
->lastsector
+ 1;
1452 if ((stuffp
->high_border
= stuffp
->pending
+ REQUEST_SIZE
)
1453 > stuffp
->lastsector
+ 1) {
1454 xtrace(XFER
, "cut high_border\n");
1455 stuffp
->high_border
= stuffp
->lastsector
+ 1;
1458 { /* Convert the sector to be requested to MSF format */
1459 struct cdrom_msf0 pending
;
1460 log2msf(stuffp
->pending
/ 4, &pending
);
1461 cmd
[1] = pending
.minute
;
1462 cmd
[2] = pending
.second
;
1463 cmd
[3] = pending
.frame
;
1468 char) ((stuffp
->high_border
- stuffp
->pending
) / 4);
1469 xtrace(XFER
, "[%2d]\n", cmd
[6]);
1472 /* Now really issue the request command */
1473 outsb(stuffp
->wreg_data
, cmd
, sizeof cmd
);
1477 if (stuffp
->int_err
) {
1479 stuffp
->int_err
= 0;
1484 stuffp
->low_border
= (stuffp
->low_border
+=
1486 stuffp
->high_border
? stuffp
->low_border
: stuffp
->high_border
;
1492 /* Access to elements of the mcdx_drive_map members */
1494 static unsigned port(int *ip
)
1498 static int irq(int *ip
)
1503 /* Misc number converters */
1505 static unsigned int bcd2uint(unsigned char c
)
1507 return (c
>> 4) * 10 + (c
& 0x0f);
1510 static unsigned int uint2bcd(unsigned int ival
)
1512 return ((ival
/ 10) << 4) | (ival
% 10);
1515 static void log2msf(unsigned int l
, struct cdrom_msf0
*pmsf
)
1518 pmsf
->minute
= uint2bcd(l
/ 4500), l
%= 4500;
1519 pmsf
->second
= uint2bcd(l
/ 75);
1520 pmsf
->frame
= uint2bcd(l
% 75);
1523 static unsigned int msf2log(const struct cdrom_msf0
*pmsf
)
1525 return bcd2uint(pmsf
->frame
)
1526 + bcd2uint(pmsf
->second
) * 75
1527 + bcd2uint(pmsf
->minute
) * 4500 - CD_MSF_OFFSET
;
1530 int mcdx_readtoc(struct s_drive_stuff
*stuffp
)
1531 /* Read the toc entries from the CD,
1532 * Return: -1 on failure, else 0 */
1536 xtrace(READTOC
, "ioctl() toc already read\n");
1540 xtrace(READTOC
, "ioctl() readtoc for %d tracks\n",
1541 stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 1);
1543 if (-1 == mcdx_hold(stuffp
, 1))
1546 xtrace(READTOC
, "ioctl() tocmode\n");
1547 if (-1 == mcdx_setdrivemode(stuffp
, TOC
, 1))
1550 /* all seems to be ok so far ... malloc */
1554 sizeof(struct s_subqcode
) * (stuffp
->di
.n_last
-
1555 stuffp
->di
.n_first
+ 2);
1557 xtrace(MALLOC
, "ioctl() malloc %d bytes\n", size
);
1558 stuffp
->toc
= kmalloc(size
, GFP_KERNEL
);
1560 xwarn("Cannot malloc %d bytes for toc\n", size
);
1561 mcdx_setdrivemode(stuffp
, DATA
, 1);
1566 /* now read actually the index */
1572 trk
< (stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 1);
1574 stuffp
->toc
[trk
].index
= 0;
1576 for (retries
= 300; retries
; retries
--) { /* why 300? */
1577 struct s_subqcode q
;
1580 if (-1 == mcdx_requestsubqcode(stuffp
, &q
, 1)) {
1581 mcdx_setdrivemode(stuffp
, DATA
, 1);
1585 idx
= bcd2uint(q
.index
);
1588 && (idx
<= stuffp
->di
.n_last
)
1590 && (stuffp
->toc
[idx
- stuffp
->di
.n_first
].
1592 stuffp
->toc
[idx
- stuffp
->di
.n_first
] = q
;
1594 "ioctl() toc idx %d (trk %d)\n",
1602 toc
[stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 1], 0,
1603 sizeof(stuffp
->toc
[0]));
1604 stuffp
->toc
[stuffp
->di
.n_last
- stuffp
->di
.n_first
+
1605 1].dt
= stuffp
->di
.msf_leadout
;
1608 /* unset toc mode */
1609 xtrace(READTOC
, "ioctl() undo toc mode\n");
1610 if (-1 == mcdx_setdrivemode(stuffp
, DATA
, 2))
1613 #if MCDX_DEBUG && READTOC
1617 trk
< (stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 2);
1619 xtrace(READTOC
, "ioctl() %d readtoc %02x %02x %02x"
1620 " %02x:%02x.%02x %02x:%02x.%02x\n",
1621 trk
+ stuffp
->di
.n_first
,
1622 stuffp
->toc
[trk
].control
,
1623 stuffp
->toc
[trk
].tno
,
1624 stuffp
->toc
[trk
].index
,
1625 stuffp
->toc
[trk
].tt
.minute
,
1626 stuffp
->toc
[trk
].tt
.second
,
1627 stuffp
->toc
[trk
].tt
.frame
,
1628 stuffp
->toc
[trk
].dt
.minute
,
1629 stuffp
->toc
[trk
].dt
.second
,
1630 stuffp
->toc
[trk
].dt
.frame
);
1638 mcdx_playmsf(struct s_drive_stuff
*stuffp
, const struct cdrom_msf
*msf
)
1640 unsigned char cmd
[7] = {
1644 if (!stuffp
->readcmd
) {
1645 xinfo("Can't play from missing disk.\n");
1649 cmd
[0] = stuffp
->playcmd
;
1651 cmd
[1] = msf
->cdmsf_min0
;
1652 cmd
[2] = msf
->cdmsf_sec0
;
1653 cmd
[3] = msf
->cdmsf_frame0
;
1654 cmd
[4] = msf
->cdmsf_min1
;
1655 cmd
[5] = msf
->cdmsf_sec1
;
1656 cmd
[6] = msf
->cdmsf_frame1
;
1658 xtrace(PLAYMSF
, "ioctl(): play %x "
1659 "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1660 cmd
[0], cmd
[1], cmd
[2], cmd
[3], cmd
[4], cmd
[5], cmd
[6]);
1662 outsb(stuffp
->wreg_data
, cmd
, sizeof cmd
);
1664 if (-1 == mcdx_getval(stuffp
, 3 * HZ
, 0, NULL
)) {
1665 xwarn("playmsf() timeout\n");
1669 stuffp
->audiostatus
= CDROM_AUDIO_PLAY
;
1674 mcdx_playtrk(struct s_drive_stuff
*stuffp
, const struct cdrom_ti
*ti
)
1676 struct s_subqcode
*p
;
1677 struct cdrom_msf msf
;
1679 if (-1 == mcdx_readtoc(stuffp
))
1683 p
= &stuffp
->toc
[ti
->cdti_trk0
- stuffp
->di
.n_first
];
1687 msf
.cdmsf_min0
= p
->dt
.minute
;
1688 msf
.cdmsf_sec0
= p
->dt
.second
;
1689 msf
.cdmsf_frame0
= p
->dt
.frame
;
1692 p
= &stuffp
->toc
[ti
->cdti_trk1
- stuffp
->di
.n_first
+ 1];
1697 msf
.cdmsf_min1
= p
->dt
.minute
;
1698 msf
.cdmsf_sec1
= p
->dt
.second
;
1699 msf
.cdmsf_frame1
= p
->dt
.frame
;
1701 return mcdx_playmsf(stuffp
, &msf
);
1705 /* Drive functions ************************************************/
1707 static int mcdx_tray_move(struct cdrom_device_info
*cdi
, int position
)
1709 struct s_drive_stuff
*stuffp
= cdi
->handle
;
1711 if (!stuffp
->present
)
1713 if (!(stuffp
->present
& DOOR
))
1716 if (position
) /* 1: eject */
1717 return mcdx_talk(stuffp
, "\xf6", 1, NULL
, 1, 5 * HZ
, 3);
1719 return mcdx_talk(stuffp
, "\xf8", 1, NULL
, 1, 5 * HZ
, 3);
1723 static int mcdx_stop(struct s_drive_stuff
*stuffp
, int tries
)
1725 return mcdx_talk(stuffp
, "\xf0", 1, NULL
, 1, 2 * HZ
, tries
);
1728 static int mcdx_hold(struct s_drive_stuff
*stuffp
, int tries
)
1730 return mcdx_talk(stuffp
, "\x70", 1, NULL
, 1, 2 * HZ
, tries
);
1733 static int mcdx_requestsubqcode(struct s_drive_stuff
*stuffp
,
1734 struct s_subqcode
*sub
, int tries
)
1739 if (-1 == (ans
= mcdx_talk(stuffp
, "\x20", 1, buf
, sizeof(buf
),
1742 sub
->control
= buf
[1];
1744 sub
->index
= buf
[3];
1745 sub
->tt
.minute
= buf
[4];
1746 sub
->tt
.second
= buf
[5];
1747 sub
->tt
.frame
= buf
[6];
1748 sub
->dt
.minute
= buf
[8];
1749 sub
->dt
.second
= buf
[9];
1750 sub
->dt
.frame
= buf
[10];
1755 static int mcdx_requestmultidiskinfo(struct s_drive_stuff
*stuffp
,
1756 struct s_multi
*multi
, int tries
)
1761 if (stuffp
->present
& MULTI
) {
1763 mcdx_talk(stuffp
, "\x11", 1, buf
, sizeof(buf
), 2 * HZ
,
1765 multi
->multi
= buf
[1];
1766 multi
->msf_last
.minute
= buf
[2];
1767 multi
->msf_last
.second
= buf
[3];
1768 multi
->msf_last
.frame
= buf
[4];
1776 static int mcdx_requesttocdata(struct s_drive_stuff
*stuffp
, struct s_diskinfo
*info
,
1782 mcdx_talk(stuffp
, "\x10", 1, buf
, sizeof(buf
), 2 * HZ
, tries
);
1787 info
->n_first
= bcd2uint(buf
[1]);
1788 info
->n_last
= bcd2uint(buf
[2]);
1789 info
->msf_leadout
.minute
= buf
[3];
1790 info
->msf_leadout
.second
= buf
[4];
1791 info
->msf_leadout
.frame
= buf
[5];
1792 info
->msf_first
.minute
= buf
[6];
1793 info
->msf_first
.second
= buf
[7];
1794 info
->msf_first
.frame
= buf
[8];
1799 static int mcdx_setdrivemode(struct s_drive_stuff
*stuffp
, enum drivemodes mode
,
1805 xtrace(HW
, "setdrivemode() %d\n", mode
);
1807 if (-1 == (ans
= mcdx_talk(stuffp
, "\xc2", 1, cmd
, sizeof(cmd
), 5 * HZ
, tries
)))
1827 return mcdx_talk(stuffp
, cmd
, 2, NULL
, 1, 5 * HZ
, tries
);
1830 static int mcdx_setdatamode(struct s_drive_stuff
*stuffp
, enum datamodes mode
,
1833 unsigned char cmd
[2] = { 0xa0 };
1834 xtrace(HW
, "setdatamode() %d\n", mode
);
1848 return mcdx_talk(stuffp
, cmd
, 2, NULL
, 1, 5 * HZ
, tries
);
1851 static int mcdx_config(struct s_drive_stuff
*stuffp
, int tries
)
1855 xtrace(HW
, "config()\n");
1859 cmd
[1] = 0x10; /* irq enable */
1860 cmd
[2] = 0x05; /* pre, err irq enable */
1862 if (-1 == mcdx_talk(stuffp
, cmd
, 3, NULL
, 1, 1 * HZ
, tries
))
1865 cmd
[1] = 0x02; /* dma select */
1866 cmd
[2] = 0x00; /* no dma */
1868 return mcdx_talk(stuffp
, cmd
, 3, NULL
, 1, 1 * HZ
, tries
);
1871 static int mcdx_requestversion(struct s_drive_stuff
*stuffp
, struct s_version
*ver
,
1877 if (-1 == (ans
= mcdx_talk(stuffp
, "\xdc",
1878 1, buf
, sizeof(buf
), 2 * HZ
, tries
)))
1887 static int mcdx_reset(struct s_drive_stuff
*stuffp
, enum resetmodes mode
, int tries
)
1890 outb(0, stuffp
->wreg_chn
); /* no dma, no irq -> hardware */
1891 outb(0, stuffp
->wreg_reset
); /* hw reset */
1894 return mcdx_talk(stuffp
, "\x60", 1, NULL
, 1, 5 * HZ
, tries
);
1897 static int mcdx_lockdoor(struct cdrom_device_info
*cdi
, int lock
)
1899 struct s_drive_stuff
*stuffp
= cdi
->handle
;
1900 char cmd
[2] = { 0xfe };
1902 if (!(stuffp
->present
& DOOR
))
1904 if (stuffp
->present
& DOOR
) {
1905 cmd
[1] = lock
? 0x01 : 0x00;
1906 return mcdx_talk(stuffp
, cmd
, sizeof(cmd
), NULL
, 1, 5 * HZ
, 3);
1911 static int mcdx_getstatus(struct s_drive_stuff
*stuffp
, int tries
)
1913 return mcdx_talk(stuffp
, "\x40", 1, NULL
, 1, 5 * HZ
, tries
);
1917 mcdx_getval(struct s_drive_stuff
*stuffp
, int to
, int delay
, char *buf
)
1919 unsigned long timeout
= to
+ jiffies
;
1925 while (inb(stuffp
->rreg_status
) & MCDX_RBIT_STEN
) {
1926 if (time_after(jiffies
, timeout
))
1928 mcdx_delay(stuffp
, delay
);
1931 *buf
= (unsigned char) inb(stuffp
->rreg_data
) & 0xff;
1936 static int mcdx_setattentuator(struct s_drive_stuff
*stuffp
,
1937 struct cdrom_volctrl
*vol
, int tries
)
1941 cmd
[1] = vol
->channel0
;
1943 cmd
[3] = vol
->channel1
;
1946 return mcdx_talk(stuffp
, cmd
, sizeof(cmd
), NULL
, 5, 200, tries
);
1949 MODULE_LICENSE("GPL");
1950 MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_X_CDROM_MAJOR
);