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>
84 #define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
87 #define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
89 #define xinfo(fmt, args...) { ; }
93 #define xtrace(lvl, fmt, args...) \
95 { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
96 #define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
98 #define xtrace(lvl, fmt, args...) { ; }
99 #define xdebug(fmt, args...) { ; }
102 /* CONSTANTS *******************************************************/
104 /* Following are the number of sectors we _request_ from the drive
105 every time an access outside the already requested range is done.
106 The _direct_ size is the number of sectors we're allowed to skip
107 directly (performing a read instead of requesting the new sector
109 static const int REQUEST_SIZE
= 800; /* should be less then 255 * 4 */
110 static const int DIRECT_SIZE
= 400; /* should be less then REQUEST_SIZE */
112 enum drivemodes
{ TOC
, DATA
, RAW
, COOKED
};
113 enum datamodes
{ MODE0
, MODE1
, MODE2
};
114 enum resetmodes
{ SOFT
, HARD
};
116 static const int SINGLE
= 0x01; /* single speed drive (FX001S, LU) */
117 static const int DOUBLE
= 0x02; /* double speed drive (FX001D, ..? */
118 static const int DOOR
= 0x04; /* door locking capability */
119 static const int MULTI
= 0x08; /* multi session capability */
121 static const unsigned char READ1X
= 0xc0;
122 static const unsigned char READ2X
= 0xc1;
125 /* DECLARATIONS ****************************************************/
127 unsigned char control
;
130 struct cdrom_msf0 tt
;
131 struct cdrom_msf0 dt
;
135 unsigned int n_first
;
137 struct cdrom_msf0 msf_leadout
;
138 struct cdrom_msf0 msf_first
;
143 struct cdrom_msf0 msf_last
;
151 /* Per drive/controller stuff **************************************/
153 struct s_drive_stuff
{
155 wait_queue_head_t busyq
;
156 wait_queue_head_t lockq
;
157 wait_queue_head_t sleepq
;
160 volatile int introk
; /* status of last irq operation */
161 volatile int busy
; /* drive performs an operation */
162 volatile int lock
; /* exclusive usage */
165 struct s_diskinfo di
;
166 struct s_multi multi
;
167 struct s_subqcode
*toc
; /* first entry of the toc array */
168 struct s_subqcode start
;
169 struct s_subqcode stop
;
170 int xa
; /* 1 if xa disk */
171 int audio
; /* 1 if audio disk */
174 /* `buffer' control */
175 volatile int valid
; /* pending, ..., values are valid */
176 volatile int pending
; /* next sector to be read */
177 volatile int low_border
; /* first sector not to be skipped direct */
178 volatile int high_border
; /* first sector `out of area' */
180 volatile int int_err
;
184 unsigned wreg_data
; /* w data */
185 unsigned wreg_reset
; /* w hardware reset */
186 unsigned wreg_hcon
; /* w hardware conf */
187 unsigned wreg_chn
; /* w channel */
188 unsigned rreg_data
; /* r data */
189 unsigned rreg_status
; /* r status */
191 int irq
; /* irq used by this drive */
192 int present
; /* drive present and its capabilities */
193 unsigned char readcmd
; /* read cmd depends on single/double speed */
194 unsigned char playcmd
; /* play should always be single speed */
195 unsigned int xxx
; /* set if changed, reset while open */
196 unsigned int yyy
; /* set if changed, reset by media_changed */
197 int users
; /* keeps track of open/close */
198 int lastsector
; /* last block accessible */
199 int status
; /* last operation's error / status */
200 int readerrs
; /* # of blocks read w/o error */
201 struct cdrom_device_info info
;
202 struct gendisk
*disk
;
206 /* Prototypes ******************************************************/
208 /* The following prototypes are already declared elsewhere. They are
209 repeated here to show what's going on. And to sense, if they're
210 changed elsewhere. */
212 static int mcdx_init(void);
214 static int mcdx_block_open(struct inode
*inode
, struct file
*file
)
216 struct s_drive_stuff
*p
= inode
->i_bdev
->bd_disk
->private_data
;
217 return cdrom_open(&p
->info
, inode
, file
);
220 static int mcdx_block_release(struct inode
*inode
, struct file
*file
)
222 struct s_drive_stuff
*p
= inode
->i_bdev
->bd_disk
->private_data
;
223 return cdrom_release(&p
->info
, file
);
226 static int mcdx_block_ioctl(struct inode
*inode
, struct file
*file
,
227 unsigned cmd
, unsigned long arg
)
229 struct s_drive_stuff
*p
= inode
->i_bdev
->bd_disk
->private_data
;
230 return cdrom_ioctl(file
, &p
->info
, inode
, cmd
, arg
);
233 static int mcdx_block_media_changed(struct gendisk
*disk
)
235 struct s_drive_stuff
*p
= disk
->private_data
;
236 return cdrom_media_changed(&p
->info
);
239 static struct block_device_operations mcdx_bdops
=
241 .owner
= THIS_MODULE
,
242 .open
= mcdx_block_open
,
243 .release
= mcdx_block_release
,
244 .ioctl
= mcdx_block_ioctl
,
245 .media_changed
= mcdx_block_media_changed
,
249 /* Indirect exported functions. These functions are exported by their
250 addresses, such as mcdx_open and mcdx_close in the
251 structure mcdx_dops. */
253 /* exported by file_ops */
254 static int mcdx_open(struct cdrom_device_info
*cdi
, int purpose
);
255 static void mcdx_close(struct cdrom_device_info
*cdi
);
256 static int mcdx_media_changed(struct cdrom_device_info
*cdi
, int disc_nr
);
257 static int mcdx_tray_move(struct cdrom_device_info
*cdi
, int position
);
258 static int mcdx_lockdoor(struct cdrom_device_info
*cdi
, int lock
);
259 static int mcdx_audio_ioctl(struct cdrom_device_info
*cdi
,
260 unsigned int cmd
, void *arg
);
262 /* misc internal support functions */
263 static void log2msf(unsigned int, struct cdrom_msf0
*);
264 static unsigned int msf2log(const struct cdrom_msf0
*);
265 static unsigned int uint2bcd(unsigned int);
266 static unsigned int bcd2uint(unsigned char);
267 static unsigned port(int *);
268 static int irq(int *);
269 static void mcdx_delay(struct s_drive_stuff
*, long jifs
);
270 static int mcdx_transfer(struct s_drive_stuff
*, char *buf
, int sector
,
272 static int mcdx_xfer(struct s_drive_stuff
*, char *buf
, int sector
,
275 static int mcdx_config(struct s_drive_stuff
*, int);
276 static int mcdx_requestversion(struct s_drive_stuff
*, struct s_version
*,
278 static int mcdx_stop(struct s_drive_stuff
*, int);
279 static int mcdx_hold(struct s_drive_stuff
*, int);
280 static int mcdx_reset(struct s_drive_stuff
*, enum resetmodes
, int);
281 static int mcdx_setdrivemode(struct s_drive_stuff
*, enum drivemodes
, int);
282 static int mcdx_setdatamode(struct s_drive_stuff
*, enum datamodes
, int);
283 static int mcdx_requestsubqcode(struct s_drive_stuff
*,
284 struct s_subqcode
*, int);
285 static int mcdx_requestmultidiskinfo(struct s_drive_stuff
*,
286 struct s_multi
*, int);
287 static int mcdx_requesttocdata(struct s_drive_stuff
*, struct s_diskinfo
*,
289 static int mcdx_getstatus(struct s_drive_stuff
*, int);
290 static int mcdx_getval(struct s_drive_stuff
*, int to
, int delay
, char *);
291 static int mcdx_talk(struct s_drive_stuff
*,
292 const unsigned char *cmd
, size_t,
293 void *buffer
, size_t size
, unsigned int timeout
, int);
294 static int mcdx_readtoc(struct s_drive_stuff
*);
295 static int mcdx_playtrk(struct s_drive_stuff
*, const struct cdrom_ti
*);
296 static int mcdx_playmsf(struct s_drive_stuff
*, const struct cdrom_msf
*);
297 static int mcdx_setattentuator(struct s_drive_stuff
*,
298 struct cdrom_volctrl
*, int);
300 /* static variables ************************************************/
302 static int mcdx_drive_map
[][2] = MCDX_DRIVEMAP
;
303 static struct s_drive_stuff
*mcdx_stuffp
[MCDX_NDRIVES
];
304 static DEFINE_SPINLOCK(mcdx_lock
);
305 static struct request_queue
*mcdx_queue
;
307 /* You can only set the first two pairs, from old MODULE_PARM code. */
308 static int mcdx_set(const char *val
, struct kernel_param
*kp
)
310 get_options((char *)val
, 4, (int *)mcdx_drive_map
);
313 module_param_call(mcdx
, mcdx_set
, NULL
, NULL
, 0);
315 static struct cdrom_device_ops mcdx_dops
= {
317 .release
= mcdx_close
,
318 .media_changed
= mcdx_media_changed
,
319 .tray_move
= mcdx_tray_move
,
320 .lock_door
= mcdx_lockdoor
,
321 .audio_ioctl
= mcdx_audio_ioctl
,
322 .capability
= CDC_OPEN_TRAY
| CDC_LOCK
| CDC_MEDIA_CHANGED
|
323 CDC_PLAY_AUDIO
| CDC_DRIVE_STATUS
,
326 /* KERNEL INTERFACE FUNCTIONS **************************************/
329 static int mcdx_audio_ioctl(struct cdrom_device_info
*cdi
,
330 unsigned int cmd
, void *arg
)
332 struct s_drive_stuff
*stuffp
= cdi
->handle
;
334 if (!stuffp
->present
)
338 if (-1 == mcdx_requesttocdata(stuffp
, &stuffp
->di
, 1)) {
339 stuffp
->lastsector
= -1;
341 stuffp
->lastsector
= (CD_FRAMESIZE
/ 512)
342 * msf2log(&stuffp
->di
.msf_leadout
) - 1;
348 if (-1 == mcdx_readtoc(stuffp
))
357 xtrace(IOCTL
, "ioctl() START\n");
358 /* Spin up the drive. Don't think we can do this.
359 * For now, ignore it.
365 xtrace(IOCTL
, "ioctl() STOP\n");
366 stuffp
->audiostatus
= CDROM_AUDIO_INVALID
;
367 if (-1 == mcdx_stop(stuffp
, 1))
372 case CDROMPLAYTRKIND
:{
373 struct cdrom_ti
*ti
= (struct cdrom_ti
*) arg
;
375 xtrace(IOCTL
, "ioctl() PLAYTRKIND\n");
376 if ((ti
->cdti_trk0
< stuffp
->di
.n_first
)
377 || (ti
->cdti_trk0
> stuffp
->di
.n_last
)
378 || (ti
->cdti_trk1
< stuffp
->di
.n_first
))
380 if (ti
->cdti_trk1
> stuffp
->di
.n_last
)
381 ti
->cdti_trk1
= stuffp
->di
.n_last
;
382 xtrace(PLAYTRK
, "ioctl() track %d to %d\n",
383 ti
->cdti_trk0
, ti
->cdti_trk1
);
384 return mcdx_playtrk(stuffp
, ti
);
388 struct cdrom_msf
*msf
= (struct cdrom_msf
*) arg
;
390 xtrace(IOCTL
, "ioctl() PLAYMSF\n");
392 if ((stuffp
->audiostatus
== CDROM_AUDIO_PLAY
)
393 && (-1 == mcdx_hold(stuffp
, 1)))
396 msf
->cdmsf_min0
= uint2bcd(msf
->cdmsf_min0
);
397 msf
->cdmsf_sec0
= uint2bcd(msf
->cdmsf_sec0
);
398 msf
->cdmsf_frame0
= uint2bcd(msf
->cdmsf_frame0
);
400 msf
->cdmsf_min1
= uint2bcd(msf
->cdmsf_min1
);
401 msf
->cdmsf_sec1
= uint2bcd(msf
->cdmsf_sec1
);
402 msf
->cdmsf_frame1
= uint2bcd(msf
->cdmsf_frame1
);
404 stuffp
->stop
.dt
.minute
= msf
->cdmsf_min1
;
405 stuffp
->stop
.dt
.second
= msf
->cdmsf_sec1
;
406 stuffp
->stop
.dt
.frame
= msf
->cdmsf_frame1
;
408 return mcdx_playmsf(stuffp
, msf
);
412 xtrace(IOCTL
, "ioctl() RESUME\n");
413 return mcdx_playtrk(stuffp
, NULL
);
416 case CDROMREADTOCENTRY
:{
417 struct cdrom_tocentry
*entry
=
418 (struct cdrom_tocentry
*) arg
;
419 struct s_subqcode
*tp
= NULL
;
420 xtrace(IOCTL
, "ioctl() READTOCENTRY\n");
422 if (-1 == mcdx_readtoc(stuffp
))
424 if (entry
->cdte_track
== CDROM_LEADOUT
)
425 tp
= &stuffp
->toc
[stuffp
->di
.n_last
-
426 stuffp
->di
.n_first
+ 1];
427 else if (entry
->cdte_track
> stuffp
->di
.n_last
428 || entry
->cdte_track
< stuffp
->di
.n_first
)
431 tp
= &stuffp
->toc
[entry
->cdte_track
-
436 entry
->cdte_adr
= tp
->control
;
437 entry
->cdte_ctrl
= tp
->control
>> 4;
438 /* Always return stuff in MSF, and let the Uniform cdrom driver
439 worry about what the user actually wants */
440 entry
->cdte_addr
.msf
.minute
=
441 bcd2uint(tp
->dt
.minute
);
442 entry
->cdte_addr
.msf
.second
=
443 bcd2uint(tp
->dt
.second
);
444 entry
->cdte_addr
.msf
.frame
=
445 bcd2uint(tp
->dt
.frame
);
450 struct cdrom_subchnl
*sub
=
451 (struct cdrom_subchnl
*) arg
;
454 xtrace(IOCTL
, "ioctl() SUBCHNL\n");
456 if (-1 == mcdx_requestsubqcode(stuffp
, &q
, 2))
459 xtrace(SUBCHNL
, "audiostatus: %x\n",
460 stuffp
->audiostatus
);
461 sub
->cdsc_audiostatus
= stuffp
->audiostatus
;
462 sub
->cdsc_adr
= q
.control
;
463 sub
->cdsc_ctrl
= q
.control
>> 4;
464 sub
->cdsc_trk
= bcd2uint(q
.tno
);
465 sub
->cdsc_ind
= bcd2uint(q
.index
);
467 xtrace(SUBCHNL
, "trk %d, ind %d\n",
468 sub
->cdsc_trk
, sub
->cdsc_ind
);
469 /* Always return stuff in MSF, and let the Uniform cdrom driver
470 worry about what the user actually wants */
471 sub
->cdsc_absaddr
.msf
.minute
=
472 bcd2uint(q
.dt
.minute
);
473 sub
->cdsc_absaddr
.msf
.second
=
474 bcd2uint(q
.dt
.second
);
475 sub
->cdsc_absaddr
.msf
.frame
= bcd2uint(q
.dt
.frame
);
476 sub
->cdsc_reladdr
.msf
.minute
=
477 bcd2uint(q
.tt
.minute
);
478 sub
->cdsc_reladdr
.msf
.second
=
479 bcd2uint(q
.tt
.second
);
480 sub
->cdsc_reladdr
.msf
.frame
= bcd2uint(q
.tt
.frame
);
482 "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
483 sub
->cdsc_absaddr
.msf
.minute
,
484 sub
->cdsc_absaddr
.msf
.second
,
485 sub
->cdsc_absaddr
.msf
.frame
,
486 sub
->cdsc_reladdr
.msf
.minute
,
487 sub
->cdsc_reladdr
.msf
.second
,
488 sub
->cdsc_reladdr
.msf
.frame
);
493 case CDROMREADTOCHDR
:{
494 struct cdrom_tochdr
*toc
=
495 (struct cdrom_tochdr
*) arg
;
497 xtrace(IOCTL
, "ioctl() READTOCHDR\n");
498 toc
->cdth_trk0
= stuffp
->di
.n_first
;
499 toc
->cdth_trk1
= stuffp
->di
.n_last
;
501 "ioctl() track0 = %d, track1 = %d\n",
502 stuffp
->di
.n_first
, stuffp
->di
.n_last
);
507 xtrace(IOCTL
, "ioctl() PAUSE\n");
508 if (stuffp
->audiostatus
!= CDROM_AUDIO_PLAY
)
510 if (-1 == mcdx_stop(stuffp
, 1))
512 stuffp
->audiostatus
= CDROM_AUDIO_PAUSED
;
514 mcdx_requestsubqcode(stuffp
, &stuffp
->start
,
520 case CDROMMULTISESSION
:{
521 struct cdrom_multisession
*ms
=
522 (struct cdrom_multisession
*) arg
;
523 xtrace(IOCTL
, "ioctl() MULTISESSION\n");
524 /* Always return stuff in LBA, and let the Uniform cdrom driver
525 worry about what the user actually wants */
526 ms
->addr
.lba
= msf2log(&stuffp
->multi
.msf_last
);
527 ms
->xa_flag
= !!stuffp
->multi
.multi
;
529 "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
530 ms
->xa_flag
, ms
->addr
.lba
,
531 stuffp
->multi
.msf_last
.minute
,
532 stuffp
->multi
.msf_last
.second
,
533 stuffp
->multi
.msf_last
.frame
);
539 xtrace(IOCTL
, "ioctl() EJECT\n");
540 if (stuffp
->users
> 1)
542 return (mcdx_tray_move(cdi
, 1));
545 case CDROMCLOSETRAY
:{
546 xtrace(IOCTL
, "ioctl() CDROMCLOSETRAY\n");
547 return (mcdx_tray_move(cdi
, 0));
551 struct cdrom_volctrl
*volctrl
=
552 (struct cdrom_volctrl
*) arg
;
553 xtrace(IOCTL
, "ioctl() VOLCTRL\n");
555 #if 0 /* not tested! */
556 /* adjust for the weirdness of workman (md) */
557 /* can't test it (hs) */
558 volctrl
.channel2
= volctrl
.channel1
;
559 volctrl
.channel1
= volctrl
.channel3
= 0x00;
561 return mcdx_setattentuator(stuffp
, volctrl
, 2);
569 static void do_mcdx_request(request_queue_t
* q
)
571 struct s_drive_stuff
*stuffp
;
576 req
= elv_next_request(q
);
580 stuffp
= req
->rq_disk
->private_data
;
582 if (!stuffp
->present
) {
583 xwarn("do_request(): bad device: %s\n",req
->rq_disk
->disk_name
);
584 xtrace(REQUEST
, "end_request(0): bad device\n");
590 xwarn("do_request() attempt to read from audio cd\n");
591 xtrace(REQUEST
, "end_request(0): read from audio\n");
596 xtrace(REQUEST
, "do_request() (%lu + %lu)\n",
597 req
->sector
, req
->nr_sectors
);
599 if (req
->cmd
!= READ
) {
600 xwarn("do_request(): non-read command to cd!!\n");
601 xtrace(REQUEST
, "end_request(0): write\n");
607 while (req
->nr_sectors
) {
610 i
= mcdx_transfer(stuffp
,
620 req
->nr_sectors
-= i
;
621 req
->buffer
+= (i
* 512);
626 xtrace(REQUEST
, "end_request(1)\n");
633 static int mcdx_open(struct cdrom_device_info
*cdi
, int purpose
)
635 struct s_drive_stuff
*stuffp
;
636 xtrace(OPENCLOSE
, "open()\n");
637 stuffp
= cdi
->handle
;
638 if (!stuffp
->present
)
641 /* Make the modules looking used ... (thanx bjorn).
642 * But we shouldn't forget to decrement the module counter
645 /* this is only done to test if the drive talks with us */
646 if (-1 == mcdx_getstatus(stuffp
, 1))
651 xtrace(OPENCLOSE
, "open() media changed\n");
652 stuffp
->audiostatus
= CDROM_AUDIO_INVALID
;
654 xtrace(OPENCLOSE
, "open() Request multisession info\n");
656 mcdx_requestmultidiskinfo(stuffp
, &stuffp
->multi
, 6))
657 xinfo("No multidiskinfo\n");
660 if (!stuffp
->multi
.multi
)
661 stuffp
->multi
.msf_last
.second
= 2;
663 xtrace(OPENCLOSE
, "open() MS: %d, last @ %02x:%02x.%02x\n",
665 stuffp
->multi
.msf_last
.minute
,
666 stuffp
->multi
.msf_last
.second
,
667 stuffp
->multi
.msf_last
.frame
);
670 } /* got multisession information */
671 /* request the disks table of contents (aka diskinfo) */
672 if (-1 == mcdx_requesttocdata(stuffp
, &stuffp
->di
, 1)) {
674 stuffp
->lastsector
= -1;
678 stuffp
->lastsector
= (CD_FRAMESIZE
/ 512)
679 * msf2log(&stuffp
->di
.msf_leadout
) - 1;
682 "open() start %d (%02x:%02x.%02x) %d\n",
684 stuffp
->di
.msf_first
.minute
,
685 stuffp
->di
.msf_first
.second
,
686 stuffp
->di
.msf_first
.frame
,
687 msf2log(&stuffp
->di
.msf_first
));
689 "open() last %d (%02x:%02x.%02x) %d\n",
691 stuffp
->di
.msf_leadout
.minute
,
692 stuffp
->di
.msf_leadout
.second
,
693 stuffp
->di
.msf_leadout
.frame
,
694 msf2log(&stuffp
->di
.msf_leadout
));
698 xtrace(MALLOC
, "open() free old toc @ %p\n",
705 xtrace(OPENCLOSE
, "open() init irq generation\n");
706 if (-1 == mcdx_config(stuffp
, 1))
709 /* Set the read speed */
710 xwarn("AAA %x AAA\n", stuffp
->readcmd
);
711 if (stuffp
->readerrs
)
712 stuffp
->readcmd
= READ1X
;
715 stuffp
->present
| SINGLE
? READ1X
: READ2X
;
716 xwarn("XXX %x XXX\n", stuffp
->readcmd
);
719 stuffp
->present
| SINGLE
? READ1X
: READ2X
;
722 /* try to get the first sector, iff any ... */
723 if (stuffp
->lastsector
>= 0) {
731 for (tries
= 6; tries
; tries
--) {
735 xtrace(OPENCLOSE
, "open() try as %s\n",
736 stuffp
->xa
? "XA" : "normal");
738 if (-1 == (ans
= mcdx_setdatamode(stuffp
,
749 if ((stuffp
->audio
= e_audio(ans
)))
754 mcdx_transfer(stuffp
, buf
, 0, 1)));
758 stuffp
->xa
= !stuffp
->xa
;
761 /* xa disks will be read in raw mode, others not */
762 if (-1 == mcdx_setdrivemode(stuffp
,
763 stuffp
->xa
? RAW
: COOKED
,
767 xinfo("open() audio disk found\n");
768 } else if (stuffp
->lastsector
>= 0) {
769 xinfo("open() %s%s disk found\n",
770 stuffp
->xa
? "XA / " : "",
772 multi
? "Multi Session" : "Single Session");
780 static void mcdx_close(struct cdrom_device_info
*cdi
)
782 struct s_drive_stuff
*stuffp
;
784 xtrace(OPENCLOSE
, "close()\n");
786 stuffp
= cdi
->handle
;
791 static int mcdx_media_changed(struct cdrom_device_info
*cdi
, int disc_nr
)
792 /* Return: 1 if media changed since last call to this function
795 struct s_drive_stuff
*stuffp
;
797 xinfo("mcdx_media_changed called for device %s\n", cdi
->name
);
799 stuffp
= cdi
->handle
;
800 mcdx_getstatus(stuffp
, 1);
802 if (stuffp
->yyy
== 0)
810 static int __init
mcdx_setup(char *str
)
813 (void) get_options(str
, ARRAY_SIZE(pi
), pi
);
816 mcdx_drive_map
[0][0] = pi
[1];
818 mcdx_drive_map
[0][1] = pi
[2];
822 __setup("mcdx=", mcdx_setup
);
826 /* DIRTY PART ******************************************************/
828 static void mcdx_delay(struct s_drive_stuff
*stuff
, long jifs
)
829 /* This routine is used for sleeping.
830 * A jifs value <0 means NO sleeping,
831 * =0 means minimal sleeping (let the kernel
832 * run for other processes)
833 * >0 means at least sleep for that amount.
834 * May be we could use a simple count loop w/ jumps to itself, but
835 * I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
840 xtrace(SLEEP
, "*** delay: sleepq\n");
841 interruptible_sleep_on_timeout(&stuff
->sleepq
, jifs
);
842 xtrace(SLEEP
, "delay awoken\n");
843 if (signal_pending(current
)) {
844 xtrace(SLEEP
, "got signal\n");
848 static irqreturn_t
mcdx_intr(int irq
, void *dev_id
, struct pt_regs
*regs
)
850 struct s_drive_stuff
*stuffp
= dev_id
;
853 if (stuffp
== NULL
) {
854 xwarn("mcdx: no device for intr %d\n", irq
);
858 if (!stuffp
->busy
&& stuffp
->pending
)
862 /* get the interrupt status */
863 b
= inb(stuffp
->rreg_status
);
864 stuffp
->introk
= ~b
& MCDX_RBIT_DTEN
;
866 /* NOTE: We only should get interrupts if the data we
867 * requested are ready to transfer.
868 * But the drive seems to generate ``asynchronous'' interrupts
869 * on several error conditions too. (Despite the err int enable
870 * setting during initialisation) */
872 /* if not ok, read the next byte as the drives status */
873 if (!stuffp
->introk
) {
874 xtrace(IRQ
, "intr() irq %d hw status 0x%02x\n", irq
, b
);
875 if (~b
& MCDX_RBIT_STEN
) {
876 xinfo("intr() irq %d status 0x%02x\n",
877 irq
, inb(stuffp
->rreg_data
));
879 xinfo("intr() irq %d ambiguous hw status\n", irq
);
882 xtrace(IRQ
, "irq() irq %d ok, status %02x\n", irq
, b
);
886 wake_up_interruptible(&stuffp
->busyq
);
891 static int mcdx_talk(struct s_drive_stuff
*stuffp
,
892 const unsigned char *cmd
, size_t cmdlen
,
893 void *buffer
, size_t size
, unsigned int timeout
, int tries
)
894 /* Send a command to the drive, wait for the result.
895 * returns -1 on timeout, drive status otherwise
896 * If buffer is not zero, the result (length size) is stored there.
897 * If buffer is zero the size should be the number of bytes to read
898 * from the drive. These bytes are discarded.
905 /* Somebody wants the data read? */
906 if ((discard
= (buffer
== NULL
)))
909 while (stuffp
->lock
) {
910 xtrace(SLEEP
, "*** talk: lockq\n");
911 interruptible_sleep_on(&stuffp
->lockq
);
912 xtrace(SLEEP
, "talk: awoken\n");
917 /* An operation other then reading data destroys the
918 * data already requested and remembered in stuffp->request, ... */
921 #if MCDX_DEBUG & TALK
925 "talk() %d / %d tries, res.size %d, command 0x%02x",
926 tries
, timeout
, size
, (unsigned char) cmd
[0]);
927 for (i
= 1; i
< cmdlen
; i
++)
928 xtrace(TALK
, " 0x%02x", cmd
[i
]);
933 /* give up if all tries are done (bad) or if the status
935 for (st
= -1; st
== -1 && tries
; tries
--) {
937 char *bp
= (char *) buffer
;
940 outsb(stuffp
->wreg_data
, cmd
, cmdlen
);
941 xtrace(TALK
, "talk() command sent\n");
943 /* get the status byte */
944 if (-1 == mcdx_getval(stuffp
, timeout
, 0, bp
)) {
945 xinfo("talk() %02x timed out (status), %d tr%s left\n",
946 cmd
[0], tries
- 1, tries
== 2 ? "y" : "ies");
954 xtrace(TALK
, "talk() got status 0x%02x\n", st
);
958 xwarn("command error cmd = %02x %s \n",
959 cmd
[0], cmdlen
> 1 ? "..." : "");
965 if (stuffp
->audiostatus
== CDROM_AUDIO_INVALID
)
966 stuffp
->audiostatus
=
967 e_audiobusy(st
) ? CDROM_AUDIO_PLAY
:
968 CDROM_AUDIO_NO_STATUS
;
969 else if (stuffp
->audiostatus
== CDROM_AUDIO_PLAY
970 && e_audiobusy(st
) == 0)
971 stuffp
->audiostatus
= CDROM_AUDIO_COMPLETED
;
975 xinfo("talk() media changed\n");
976 stuffp
->xxx
= stuffp
->yyy
= 1;
979 /* now actually get the data */
981 if (-1 == mcdx_getval(stuffp
, timeout
, 0, bp
)) {
982 xinfo("talk() %02x timed out (data), %d tr%s left\n",
984 tries
== 2 ? "y" : "ies");
990 xtrace(TALK
, "talk() got 0x%02x\n", *(bp
- 1));
995 if (!tries
&& st
== -1)
996 xinfo("talk() giving up\n");
1000 wake_up_interruptible(&stuffp
->lockq
);
1002 xtrace(TALK
, "talk() done with 0x%02x\n", st
);
1006 /* MODULE STUFF ***********************************************************/
1008 static int __init
__mcdx_init(void)
1014 for (i
= 0; i
< MCDX_NDRIVES
; i
++) {
1015 if (mcdx_stuffp
[i
]) {
1016 xtrace(INIT
, "init_module() drive %d stuff @ %p\n",
1028 static void __exit
mcdx_exit(void)
1032 xinfo("cleanup_module called\n");
1034 for (i
= 0; i
< MCDX_NDRIVES
; i
++) {
1035 struct s_drive_stuff
*stuffp
= mcdx_stuffp
[i
];
1038 del_gendisk(stuffp
->disk
);
1039 if (unregister_cdrom(&stuffp
->info
)) {
1040 printk(KERN_WARNING
"Can't unregister cdrom mcdx\n");
1043 put_disk(stuffp
->disk
);
1044 release_region(stuffp
->wreg_data
, MCDX_IO_SIZE
);
1045 free_irq(stuffp
->irq
, NULL
);
1047 xtrace(MALLOC
, "cleanup_module() free toc @ %p\n",
1051 xtrace(MALLOC
, "cleanup_module() free stuffp @ %p\n",
1053 mcdx_stuffp
[i
] = NULL
;
1057 if (unregister_blkdev(MAJOR_NR
, "mcdx") != 0) {
1058 xwarn("cleanup() unregister_blkdev() failed\n");
1060 blk_cleanup_queue(mcdx_queue
);
1063 xinfo("cleanup() succeeded\n");
1068 module_init(__mcdx_init
);
1070 module_exit(mcdx_exit
);
1073 /* Support functions ************************************************/
1075 static int __init
mcdx_init_drive(int drive
)
1077 struct s_version version
;
1078 struct gendisk
*disk
;
1079 struct s_drive_stuff
*stuffp
;
1080 int size
= sizeof(*stuffp
);
1083 xtrace(INIT
, "init() try drive %d\n", drive
);
1085 xtrace(INIT
, "kmalloc space for stuffpt's\n");
1086 xtrace(MALLOC
, "init() malloc %d bytes\n", size
);
1087 if (!(stuffp
= kzalloc(size
, GFP_KERNEL
))) {
1088 xwarn("init() malloc failed\n");
1092 disk
= alloc_disk(1);
1094 xwarn("init() malloc failed\n");
1099 xtrace(INIT
, "init() got %d bytes for drive stuff @ %p\n",
1100 sizeof(*stuffp
), stuffp
);
1102 /* set default values */
1103 stuffp
->present
= 0; /* this should be 0 already */
1104 stuffp
->toc
= NULL
; /* this should be NULL already */
1106 /* setup our irq and i/o addresses */
1107 stuffp
->irq
= irq(mcdx_drive_map
[drive
]);
1108 stuffp
->wreg_data
= stuffp
->rreg_data
= port(mcdx_drive_map
[drive
]);
1109 stuffp
->wreg_reset
= stuffp
->rreg_status
= stuffp
->wreg_data
+ 1;
1110 stuffp
->wreg_hcon
= stuffp
->wreg_reset
+ 1;
1111 stuffp
->wreg_chn
= stuffp
->wreg_hcon
+ 1;
1113 init_waitqueue_head(&stuffp
->busyq
);
1114 init_waitqueue_head(&stuffp
->lockq
);
1115 init_waitqueue_head(&stuffp
->sleepq
);
1117 /* check if i/o addresses are available */
1118 if (!request_region(stuffp
->wreg_data
, MCDX_IO_SIZE
, "mcdx")) {
1119 xwarn("0x%03x,%d: Init failed. "
1120 "I/O ports (0x%03x..0x%03x) already in use.\n",
1121 stuffp
->wreg_data
, stuffp
->irq
,
1123 stuffp
->wreg_data
+ MCDX_IO_SIZE
- 1);
1124 xtrace(MALLOC
, "init() free stuffp @ %p\n", stuffp
);
1127 xtrace(INIT
, "init() continue at next drive\n");
1128 return 0; /* next drive */
1131 xtrace(INIT
, "init() i/o port is available at 0x%03x\n"
1133 xtrace(INIT
, "init() hardware reset\n");
1134 mcdx_reset(stuffp
, HARD
, 1);
1136 xtrace(INIT
, "init() get version\n");
1137 if (-1 == mcdx_requestversion(stuffp
, &version
, 4)) {
1138 /* failed, next drive */
1139 release_region(stuffp
->wreg_data
, MCDX_IO_SIZE
);
1140 xwarn("%s=0x%03x,%d: Init failed. Can't get version.\n",
1141 MCDX
, stuffp
->wreg_data
, stuffp
->irq
);
1142 xtrace(MALLOC
, "init() free stuffp @ %p\n", stuffp
);
1145 xtrace(INIT
, "init() continue at next drive\n");
1149 switch (version
.code
) {
1151 stuffp
->readcmd
= READ2X
;
1152 stuffp
->present
= DOUBLE
| DOOR
| MULTI
;
1155 stuffp
->readcmd
= READ1X
;
1156 stuffp
->present
= SINGLE
| DOOR
| MULTI
;
1159 stuffp
->readcmd
= READ1X
;
1160 stuffp
->present
= SINGLE
;
1163 stuffp
->present
= 0;
1167 stuffp
->playcmd
= READ1X
;
1169 if (!stuffp
->present
) {
1170 release_region(stuffp
->wreg_data
, MCDX_IO_SIZE
);
1171 xwarn("%s=0x%03x,%d: Init failed. No Mitsumi CD-ROM?.\n",
1172 MCDX
, stuffp
->wreg_data
, stuffp
->irq
);
1175 return 0; /* next drive */
1178 xtrace(INIT
, "init() register blkdev\n");
1179 if (register_blkdev(MAJOR_NR
, "mcdx")) {
1180 release_region(stuffp
->wreg_data
, MCDX_IO_SIZE
);
1186 mcdx_queue
= blk_init_queue(do_mcdx_request
, &mcdx_lock
);
1188 unregister_blkdev(MAJOR_NR
, "mcdx");
1189 release_region(stuffp
->wreg_data
, MCDX_IO_SIZE
);
1195 xtrace(INIT
, "init() subscribe irq and i/o\n");
1196 if (request_irq(stuffp
->irq
, mcdx_intr
, SA_INTERRUPT
, "mcdx", stuffp
)) {
1197 release_region(stuffp
->wreg_data
, MCDX_IO_SIZE
);
1198 xwarn("%s=0x%03x,%d: Init failed. Can't get irq (%d).\n",
1199 MCDX
, stuffp
->wreg_data
, stuffp
->irq
, stuffp
->irq
);
1201 blk_cleanup_queue(mcdx_queue
);
1207 xtrace(INIT
, "init() get garbage\n");
1210 mcdx_delay(stuffp
, HZ
/ 2);
1211 for (i
= 100; i
; i
--)
1212 (void) inb(stuffp
->rreg_status
);
1217 /* irq 11 -> channel register */
1218 outb(0x50, stuffp
->wreg_chn
);
1221 xtrace(INIT
, "init() set non dma but irq mode\n");
1222 mcdx_config(stuffp
, 1);
1224 stuffp
->info
.ops
= &mcdx_dops
;
1225 stuffp
->info
.speed
= 2;
1226 stuffp
->info
.capacity
= 1;
1227 stuffp
->info
.handle
= stuffp
;
1228 sprintf(stuffp
->info
.name
, "mcdx%d", drive
);
1229 disk
->major
= MAJOR_NR
;
1230 disk
->first_minor
= drive
;
1231 strcpy(disk
->disk_name
, stuffp
->info
.name
);
1232 disk
->fops
= &mcdx_bdops
;
1233 disk
->flags
= GENHD_FL_CD
;
1234 stuffp
->disk
= disk
;
1236 sprintf(msg
, " mcdx: Mitsumi CD-ROM installed at 0x%03x, irq %d."
1237 " (Firmware version %c %x)\n",
1238 stuffp
->wreg_data
, stuffp
->irq
, version
.code
, version
.ver
);
1239 mcdx_stuffp
[drive
] = stuffp
;
1240 xtrace(INIT
, "init() mcdx_stuffp[%d] = %p\n", drive
, stuffp
);
1241 if (register_cdrom(&stuffp
->info
) != 0) {
1242 printk("Cannot register Mitsumi CD-ROM!\n");
1243 free_irq(stuffp
->irq
, NULL
);
1244 release_region(stuffp
->wreg_data
, MCDX_IO_SIZE
);
1247 if (unregister_blkdev(MAJOR_NR
, "mcdx") != 0)
1248 xwarn("cleanup() unregister_blkdev() failed\n");
1249 blk_cleanup_queue(mcdx_queue
);
1252 disk
->private_data
= stuffp
;
1253 disk
->queue
= mcdx_queue
;
1259 static int __init
mcdx_init(void)
1262 xwarn("Version 2.14(hs) \n");
1264 xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
1266 /* zero the pointer array */
1267 for (drive
= 0; drive
< MCDX_NDRIVES
; drive
++)
1268 mcdx_stuffp
[drive
] = NULL
;
1270 /* do the initialisation */
1271 for (drive
= 0; drive
< MCDX_NDRIVES
; drive
++) {
1272 switch (mcdx_init_drive(drive
)) {
1282 static int mcdx_transfer(struct s_drive_stuff
*stuffp
,
1283 char *p
, int sector
, int nr_sectors
)
1284 /* This seems to do the actually transfer. But it does more. It
1285 keeps track of errors occurred and will (if possible) fall back
1286 to single speed on error.
1287 Return: -1 on timeout or other error
1288 else status byte (as in stuff->st) */
1292 ans
= mcdx_xfer(stuffp
, p
, sector
, nr_sectors
);
1300 if (stuffp
->readerrs
&& stuffp
->readcmd
== READ1X
) {
1301 xwarn("XXX Already reading 1x -- no chance\n");
1305 xwarn("XXX Fallback to 1x\n");
1307 stuffp
->readcmd
= READ1X
;
1308 return mcdx_transfer(stuffp
, p
, sector
, nr_sectors
);
1314 static int mcdx_xfer(struct s_drive_stuff
*stuffp
,
1315 char *p
, int sector
, int nr_sectors
)
1316 /* This does actually the transfer from the drive.
1317 Return: -1 on timeout or other error
1318 else status byte (as in stuff->st) */
1324 if (stuffp
->audio
) {
1325 xwarn("Attempt to read from audio CD.\n");
1329 if (!stuffp
->readcmd
) {
1330 xinfo("Can't transfer from missing disk.\n");
1334 while (stuffp
->lock
) {
1335 interruptible_sleep_on(&stuffp
->lockq
);
1338 if (stuffp
->valid
&& (sector
>= stuffp
->pending
)
1339 && (sector
< stuffp
->low_border
)) {
1341 /* All (or at least a part of the sectors requested) seems
1342 * to be already requested, so we don't need to bother the
1343 * drive with new requests ...
1344 * Wait for the drive become idle, but first
1345 * check for possible occurred errors --- the drive
1346 * seems to report them asynchronously */
1349 border
= stuffp
->high_border
< (border
=
1350 sector
+ nr_sectors
)
1351 ? stuffp
->high_border
: border
;
1353 stuffp
->lock
= current
->pid
;
1357 while (stuffp
->busy
) {
1360 interruptible_sleep_on_timeout
1361 (&stuffp
->busyq
, 5 * HZ
);
1363 if (!stuffp
->introk
) {
1365 "error via interrupt\n");
1366 } else if (!timeout
) {
1367 xtrace(XFER
, "timeout\n");
1368 } else if (signal_pending(current
)) {
1369 xtrace(XFER
, "signal\n");
1377 wake_up_interruptible(&stuffp
->lockq
);
1378 xtrace(XFER
, "transfer() done (-1)\n");
1382 /* check if we need to set the busy flag (as we
1383 * expect an interrupt */
1384 stuffp
->busy
= (3 == (stuffp
->pending
& 3));
1386 /* Test if it's the first sector of a block,
1387 * there we have to skip some bytes as we read raw data */
1388 if (stuffp
->xa
&& (0 == (stuffp
->pending
& 3))) {
1390 CD_FRAMESIZE_RAW
- CD_XA_TAIL
-
1392 insb(stuffp
->rreg_data
, p
, HEAD
);
1395 /* now actually read the data */
1396 insb(stuffp
->rreg_data
, p
, 512);
1398 /* test if it's the last sector of a block,
1399 * if so, we have to handle XA special */
1400 if ((3 == (stuffp
->pending
& 3)) && stuffp
->xa
) {
1401 char dummy
[CD_XA_TAIL
];
1402 insb(stuffp
->rreg_data
, &dummy
[0], CD_XA_TAIL
);
1405 if (stuffp
->pending
== sector
) {
1410 } while (++(stuffp
->pending
) < border
);
1413 wake_up_interruptible(&stuffp
->lockq
);
1417 /* The requested sector(s) is/are out of the
1418 * already requested range, so we have to bother the drive
1419 * with a new request. */
1421 static unsigned char cmd
[] = {
1427 cmd
[0] = stuffp
->readcmd
;
1429 /* The numbers held in ->pending, ..., should be valid */
1431 stuffp
->pending
= sector
& ~3;
1433 /* do some sanity checks */
1434 if (stuffp
->pending
> stuffp
->lastsector
) {
1436 ("transfer() sector %d from nirvana requested.\n",
1438 stuffp
->status
= MCDX_ST_EOM
;
1440 xtrace(XFER
, "transfer() done (-1)\n");
1444 if ((stuffp
->low_border
= stuffp
->pending
+ DIRECT_SIZE
)
1445 > stuffp
->lastsector
+ 1) {
1446 xtrace(XFER
, "cut low_border\n");
1447 stuffp
->low_border
= stuffp
->lastsector
+ 1;
1449 if ((stuffp
->high_border
= stuffp
->pending
+ REQUEST_SIZE
)
1450 > stuffp
->lastsector
+ 1) {
1451 xtrace(XFER
, "cut high_border\n");
1452 stuffp
->high_border
= stuffp
->lastsector
+ 1;
1455 { /* Convert the sector to be requested to MSF format */
1456 struct cdrom_msf0 pending
;
1457 log2msf(stuffp
->pending
/ 4, &pending
);
1458 cmd
[1] = pending
.minute
;
1459 cmd
[2] = pending
.second
;
1460 cmd
[3] = pending
.frame
;
1465 char) ((stuffp
->high_border
- stuffp
->pending
) / 4);
1466 xtrace(XFER
, "[%2d]\n", cmd
[6]);
1469 /* Now really issue the request command */
1470 outsb(stuffp
->wreg_data
, cmd
, sizeof cmd
);
1474 if (stuffp
->int_err
) {
1476 stuffp
->int_err
= 0;
1481 stuffp
->low_border
= (stuffp
->low_border
+=
1483 stuffp
->high_border
? stuffp
->low_border
: stuffp
->high_border
;
1489 /* Access to elements of the mcdx_drive_map members */
1491 static unsigned port(int *ip
)
1495 static int irq(int *ip
)
1500 /* Misc number converters */
1502 static unsigned int bcd2uint(unsigned char c
)
1504 return (c
>> 4) * 10 + (c
& 0x0f);
1507 static unsigned int uint2bcd(unsigned int ival
)
1509 return ((ival
/ 10) << 4) | (ival
% 10);
1512 static void log2msf(unsigned int l
, struct cdrom_msf0
*pmsf
)
1515 pmsf
->minute
= uint2bcd(l
/ 4500), l
%= 4500;
1516 pmsf
->second
= uint2bcd(l
/ 75);
1517 pmsf
->frame
= uint2bcd(l
% 75);
1520 static unsigned int msf2log(const struct cdrom_msf0
*pmsf
)
1522 return bcd2uint(pmsf
->frame
)
1523 + bcd2uint(pmsf
->second
) * 75
1524 + bcd2uint(pmsf
->minute
) * 4500 - CD_MSF_OFFSET
;
1527 int mcdx_readtoc(struct s_drive_stuff
*stuffp
)
1528 /* Read the toc entries from the CD,
1529 * Return: -1 on failure, else 0 */
1533 xtrace(READTOC
, "ioctl() toc already read\n");
1537 xtrace(READTOC
, "ioctl() readtoc for %d tracks\n",
1538 stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 1);
1540 if (-1 == mcdx_hold(stuffp
, 1))
1543 xtrace(READTOC
, "ioctl() tocmode\n");
1544 if (-1 == mcdx_setdrivemode(stuffp
, TOC
, 1))
1547 /* all seems to be ok so far ... malloc */
1551 sizeof(struct s_subqcode
) * (stuffp
->di
.n_last
-
1552 stuffp
->di
.n_first
+ 2);
1554 xtrace(MALLOC
, "ioctl() malloc %d bytes\n", size
);
1555 stuffp
->toc
= kmalloc(size
, GFP_KERNEL
);
1557 xwarn("Cannot malloc %d bytes for toc\n", size
);
1558 mcdx_setdrivemode(stuffp
, DATA
, 1);
1563 /* now read actually the index */
1569 trk
< (stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 1);
1571 stuffp
->toc
[trk
].index
= 0;
1573 for (retries
= 300; retries
; retries
--) { /* why 300? */
1574 struct s_subqcode q
;
1577 if (-1 == mcdx_requestsubqcode(stuffp
, &q
, 1)) {
1578 mcdx_setdrivemode(stuffp
, DATA
, 1);
1582 idx
= bcd2uint(q
.index
);
1585 && (idx
<= stuffp
->di
.n_last
)
1587 && (stuffp
->toc
[idx
- stuffp
->di
.n_first
].
1589 stuffp
->toc
[idx
- stuffp
->di
.n_first
] = q
;
1591 "ioctl() toc idx %d (trk %d)\n",
1599 toc
[stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 1], 0,
1600 sizeof(stuffp
->toc
[0]));
1601 stuffp
->toc
[stuffp
->di
.n_last
- stuffp
->di
.n_first
+
1602 1].dt
= stuffp
->di
.msf_leadout
;
1605 /* unset toc mode */
1606 xtrace(READTOC
, "ioctl() undo toc mode\n");
1607 if (-1 == mcdx_setdrivemode(stuffp
, DATA
, 2))
1610 #if MCDX_DEBUG && READTOC
1614 trk
< (stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 2);
1616 xtrace(READTOC
, "ioctl() %d readtoc %02x %02x %02x"
1617 " %02x:%02x.%02x %02x:%02x.%02x\n",
1618 trk
+ stuffp
->di
.n_first
,
1619 stuffp
->toc
[trk
].control
,
1620 stuffp
->toc
[trk
].tno
,
1621 stuffp
->toc
[trk
].index
,
1622 stuffp
->toc
[trk
].tt
.minute
,
1623 stuffp
->toc
[trk
].tt
.second
,
1624 stuffp
->toc
[trk
].tt
.frame
,
1625 stuffp
->toc
[trk
].dt
.minute
,
1626 stuffp
->toc
[trk
].dt
.second
,
1627 stuffp
->toc
[trk
].dt
.frame
);
1635 mcdx_playmsf(struct s_drive_stuff
*stuffp
, const struct cdrom_msf
*msf
)
1637 unsigned char cmd
[7] = {
1641 if (!stuffp
->readcmd
) {
1642 xinfo("Can't play from missing disk.\n");
1646 cmd
[0] = stuffp
->playcmd
;
1648 cmd
[1] = msf
->cdmsf_min0
;
1649 cmd
[2] = msf
->cdmsf_sec0
;
1650 cmd
[3] = msf
->cdmsf_frame0
;
1651 cmd
[4] = msf
->cdmsf_min1
;
1652 cmd
[5] = msf
->cdmsf_sec1
;
1653 cmd
[6] = msf
->cdmsf_frame1
;
1655 xtrace(PLAYMSF
, "ioctl(): play %x "
1656 "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1657 cmd
[0], cmd
[1], cmd
[2], cmd
[3], cmd
[4], cmd
[5], cmd
[6]);
1659 outsb(stuffp
->wreg_data
, cmd
, sizeof cmd
);
1661 if (-1 == mcdx_getval(stuffp
, 3 * HZ
, 0, NULL
)) {
1662 xwarn("playmsf() timeout\n");
1666 stuffp
->audiostatus
= CDROM_AUDIO_PLAY
;
1671 mcdx_playtrk(struct s_drive_stuff
*stuffp
, const struct cdrom_ti
*ti
)
1673 struct s_subqcode
*p
;
1674 struct cdrom_msf msf
;
1676 if (-1 == mcdx_readtoc(stuffp
))
1680 p
= &stuffp
->toc
[ti
->cdti_trk0
- stuffp
->di
.n_first
];
1684 msf
.cdmsf_min0
= p
->dt
.minute
;
1685 msf
.cdmsf_sec0
= p
->dt
.second
;
1686 msf
.cdmsf_frame0
= p
->dt
.frame
;
1689 p
= &stuffp
->toc
[ti
->cdti_trk1
- stuffp
->di
.n_first
+ 1];
1694 msf
.cdmsf_min1
= p
->dt
.minute
;
1695 msf
.cdmsf_sec1
= p
->dt
.second
;
1696 msf
.cdmsf_frame1
= p
->dt
.frame
;
1698 return mcdx_playmsf(stuffp
, &msf
);
1702 /* Drive functions ************************************************/
1704 static int mcdx_tray_move(struct cdrom_device_info
*cdi
, int position
)
1706 struct s_drive_stuff
*stuffp
= cdi
->handle
;
1708 if (!stuffp
->present
)
1710 if (!(stuffp
->present
& DOOR
))
1713 if (position
) /* 1: eject */
1714 return mcdx_talk(stuffp
, "\xf6", 1, NULL
, 1, 5 * HZ
, 3);
1716 return mcdx_talk(stuffp
, "\xf8", 1, NULL
, 1, 5 * HZ
, 3);
1720 static int mcdx_stop(struct s_drive_stuff
*stuffp
, int tries
)
1722 return mcdx_talk(stuffp
, "\xf0", 1, NULL
, 1, 2 * HZ
, tries
);
1725 static int mcdx_hold(struct s_drive_stuff
*stuffp
, int tries
)
1727 return mcdx_talk(stuffp
, "\x70", 1, NULL
, 1, 2 * HZ
, tries
);
1730 static int mcdx_requestsubqcode(struct s_drive_stuff
*stuffp
,
1731 struct s_subqcode
*sub
, int tries
)
1736 if (-1 == (ans
= mcdx_talk(stuffp
, "\x20", 1, buf
, sizeof(buf
),
1739 sub
->control
= buf
[1];
1741 sub
->index
= buf
[3];
1742 sub
->tt
.minute
= buf
[4];
1743 sub
->tt
.second
= buf
[5];
1744 sub
->tt
.frame
= buf
[6];
1745 sub
->dt
.minute
= buf
[8];
1746 sub
->dt
.second
= buf
[9];
1747 sub
->dt
.frame
= buf
[10];
1752 static int mcdx_requestmultidiskinfo(struct s_drive_stuff
*stuffp
,
1753 struct s_multi
*multi
, int tries
)
1758 if (stuffp
->present
& MULTI
) {
1760 mcdx_talk(stuffp
, "\x11", 1, buf
, sizeof(buf
), 2 * HZ
,
1762 multi
->multi
= buf
[1];
1763 multi
->msf_last
.minute
= buf
[2];
1764 multi
->msf_last
.second
= buf
[3];
1765 multi
->msf_last
.frame
= buf
[4];
1773 static int mcdx_requesttocdata(struct s_drive_stuff
*stuffp
, struct s_diskinfo
*info
,
1779 mcdx_talk(stuffp
, "\x10", 1, buf
, sizeof(buf
), 2 * HZ
, tries
);
1784 info
->n_first
= bcd2uint(buf
[1]);
1785 info
->n_last
= bcd2uint(buf
[2]);
1786 info
->msf_leadout
.minute
= buf
[3];
1787 info
->msf_leadout
.second
= buf
[4];
1788 info
->msf_leadout
.frame
= buf
[5];
1789 info
->msf_first
.minute
= buf
[6];
1790 info
->msf_first
.second
= buf
[7];
1791 info
->msf_first
.frame
= buf
[8];
1796 static int mcdx_setdrivemode(struct s_drive_stuff
*stuffp
, enum drivemodes mode
,
1802 xtrace(HW
, "setdrivemode() %d\n", mode
);
1804 if (-1 == (ans
= mcdx_talk(stuffp
, "\xc2", 1, cmd
, sizeof(cmd
), 5 * HZ
, tries
)))
1824 return mcdx_talk(stuffp
, cmd
, 2, NULL
, 1, 5 * HZ
, tries
);
1827 static int mcdx_setdatamode(struct s_drive_stuff
*stuffp
, enum datamodes mode
,
1830 unsigned char cmd
[2] = { 0xa0 };
1831 xtrace(HW
, "setdatamode() %d\n", mode
);
1845 return mcdx_talk(stuffp
, cmd
, 2, NULL
, 1, 5 * HZ
, tries
);
1848 static int mcdx_config(struct s_drive_stuff
*stuffp
, int tries
)
1852 xtrace(HW
, "config()\n");
1856 cmd
[1] = 0x10; /* irq enable */
1857 cmd
[2] = 0x05; /* pre, err irq enable */
1859 if (-1 == mcdx_talk(stuffp
, cmd
, 3, NULL
, 1, 1 * HZ
, tries
))
1862 cmd
[1] = 0x02; /* dma select */
1863 cmd
[2] = 0x00; /* no dma */
1865 return mcdx_talk(stuffp
, cmd
, 3, NULL
, 1, 1 * HZ
, tries
);
1868 static int mcdx_requestversion(struct s_drive_stuff
*stuffp
, struct s_version
*ver
,
1874 if (-1 == (ans
= mcdx_talk(stuffp
, "\xdc",
1875 1, buf
, sizeof(buf
), 2 * HZ
, tries
)))
1884 static int mcdx_reset(struct s_drive_stuff
*stuffp
, enum resetmodes mode
, int tries
)
1887 outb(0, stuffp
->wreg_chn
); /* no dma, no irq -> hardware */
1888 outb(0, stuffp
->wreg_reset
); /* hw reset */
1891 return mcdx_talk(stuffp
, "\x60", 1, NULL
, 1, 5 * HZ
, tries
);
1894 static int mcdx_lockdoor(struct cdrom_device_info
*cdi
, int lock
)
1896 struct s_drive_stuff
*stuffp
= cdi
->handle
;
1897 char cmd
[2] = { 0xfe };
1899 if (!(stuffp
->present
& DOOR
))
1901 if (stuffp
->present
& DOOR
) {
1902 cmd
[1] = lock
? 0x01 : 0x00;
1903 return mcdx_talk(stuffp
, cmd
, sizeof(cmd
), NULL
, 1, 5 * HZ
, 3);
1908 static int mcdx_getstatus(struct s_drive_stuff
*stuffp
, int tries
)
1910 return mcdx_talk(stuffp
, "\x40", 1, NULL
, 1, 5 * HZ
, tries
);
1914 mcdx_getval(struct s_drive_stuff
*stuffp
, int to
, int delay
, char *buf
)
1916 unsigned long timeout
= to
+ jiffies
;
1922 while (inb(stuffp
->rreg_status
) & MCDX_RBIT_STEN
) {
1923 if (time_after(jiffies
, timeout
))
1925 mcdx_delay(stuffp
, delay
);
1928 *buf
= (unsigned char) inb(stuffp
->rreg_data
) & 0xff;
1933 static int mcdx_setattentuator(struct s_drive_stuff
*stuffp
,
1934 struct cdrom_volctrl
*vol
, int tries
)
1938 cmd
[1] = vol
->channel0
;
1940 cmd
[3] = vol
->channel1
;
1943 return mcdx_talk(stuffp
, cmd
, sizeof(cmd
), NULL
, 5, 200, tries
);
1946 MODULE_LICENSE("GPL");
1947 MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_X_CDROM_MAJOR
);