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?
51 static const char *mcdx_c_version
52 = "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $";
55 #include <linux/version.h>
56 #include <linux/module.h>
58 #include <linux/errno.h>
59 #include <linux/sched.h>
61 #include <linux/kernel.h>
62 #include <linux/cdrom.h>
63 #include <linux/ioport.h>
65 #include <linux/malloc.h>
66 #include <linux/init.h>
68 #include <asm/uaccess.h>
70 #include <linux/major.h>
71 #define MAJOR_NR MITSUMI_X_CDROM_MAJOR
72 #include <linux/blk.h>
74 /* for compatible parameter passing with "insmod" */
75 #define mcdx_drive_map mcdx
82 #define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
85 #define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
87 #define xinfo(fmt, args...) { ; }
91 #define xtrace(lvl, fmt, args...) \
93 { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
94 #define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
96 #define xtrace(lvl, fmt, args...) { ; }
97 #define xdebug(fmt, args...) { ; }
100 /* CONSTANTS *******************************************************/
102 /* Following are the number of sectors we _request_ from the drive
103 every time an access outside the already requested range is done.
104 The _direct_ size is the number of sectors we're allowed to skip
105 directly (performing a read instead of requesting the new sector
107 const int REQUEST_SIZE
= 800; /* should be less then 255 * 4 */
108 const int DIRECT_SIZE
= 400; /* should be less then REQUEST_SIZE */
110 enum drivemodes
{ TOC
, DATA
, RAW
, COOKED
};
111 enum datamodes
{ MODE0
, MODE1
, MODE2
};
112 enum resetmodes
{ SOFT
, HARD
};
114 const int SINGLE
= 0x01; /* single speed drive (FX001S, LU) */
115 const int DOUBLE
= 0x02; /* double speed drive (FX001D, ..? */
116 const int DOOR
= 0x04; /* door locking capability */
117 const int MULTI
= 0x08; /* multi session capability */
119 const unsigned char READ1X
= 0xc0;
120 const unsigned char READ2X
= 0xc1;
123 /* DECLARATIONS ****************************************************/
125 unsigned char control
;
128 struct cdrom_msf0 tt
;
129 struct cdrom_msf0 dt
;
133 unsigned int n_first
;
135 struct cdrom_msf0 msf_leadout
;
136 struct cdrom_msf0 msf_first
;
141 struct cdrom_msf0 msf_last
;
149 /* Per drive/controller stuff **************************************/
151 struct s_drive_stuff
{
153 wait_queue_head_t busyq
;
154 wait_queue_head_t lockq
;
155 wait_queue_head_t sleepq
;
158 volatile int introk
; /* status of last irq operation */
159 volatile int busy
; /* drive performs an operation */
160 volatile int lock
; /* exclusive usage */
163 struct s_diskinfo di
;
164 struct s_multi multi
;
165 struct s_subqcode
* toc
; /* first entry of the toc array */
166 struct s_subqcode start
;
167 struct s_subqcode stop
;
168 int xa
; /* 1 if xa disk */
169 int audio
; /* 1 if audio disk */
172 /* `buffer' control */
173 volatile int valid
; /* pending, ..., values are valid */
174 volatile int pending
; /* next sector to be read */
175 volatile int low_border
; /* first sector not to be skipped direct */
176 volatile int high_border
; /* first sector `out of area' */
178 volatile int int_err
;
182 void* wreg_data
; /* w data */
183 void* wreg_reset
; /* w hardware reset */
184 void* wreg_hcon
; /* w hardware conf */
185 void* wreg_chn
; /* w channel */
186 void* rreg_data
; /* r data */
187 void* rreg_status
; /* r status */
189 int irq
; /* irq used by this drive */
190 int minor
; /* minor number of this drive */
191 int present
; /* drive present and its capabilities */
192 unsigned char readcmd
; /* read cmd depends on single/double speed */
193 unsigned char playcmd
; /* play should always be single speed */
194 unsigned int xxx
; /* set if changed, reset while open */
195 unsigned int yyy
; /* set if changed, reset by media_changed */
196 int users
; /* keeps track of open/close */
197 int lastsector
; /* last block accessible */
198 int status
; /* last operation's error / status */
199 int readerrs
; /* # of blocks read w/o error */
203 /* Prototypes ******************************************************/
205 /* The following prototypes are already declared elsewhere. They are
206 repeated here to show what's going on. And to sense, if they're
207 changed elsewhere. */
209 /* declared in blk.h */
211 void do_mcdx_request(void);
213 /* already declared in init/main */
214 void mcdx_setup(char *, int *);
216 /* Indirect exported functions. These functions are exported by their
217 addresses, such as mcdx_open and mcdx_close in the
218 structure mcdx_dops. */
220 /* ??? exported by the mcdx_sigaction struct */
221 static void mcdx_intr(int, void *, struct pt_regs
*);
223 /* exported by file_ops */
224 static int mcdx_open(struct cdrom_device_info
* cdi
, int purpose
);
225 static void mcdx_close(struct cdrom_device_info
* cdi
);
226 static int mcdx_media_changed(struct cdrom_device_info
* cdi
, int disc_nr
);
227 static int mcdx_tray_move(struct cdrom_device_info
* cdi
, int position
);
228 static int mcdx_lockdoor(struct cdrom_device_info
* cdi
, int lock
);
229 static int mcdx_audio_ioctl(struct cdrom_device_info
* cdi
, unsigned int cmd
,
232 /* misc internal support functions */
233 static void log2msf(unsigned int, struct cdrom_msf0
*);
234 static unsigned int msf2log(const struct cdrom_msf0
*);
235 static unsigned int uint2bcd(unsigned int);
236 static unsigned int bcd2uint(unsigned char);
237 static char *port(int*);
238 static int irq(int*);
239 static void mcdx_delay(struct s_drive_stuff
*, long jifs
);
240 static int mcdx_transfer(struct s_drive_stuff
*, char* buf
, int sector
, int nr_sectors
);
241 static int mcdx_xfer(struct s_drive_stuff
*, char* buf
, int sector
, int nr_sectors
);
243 static int mcdx_config(struct s_drive_stuff
*, int);
244 static int mcdx_requestversion(struct s_drive_stuff
*, struct s_version
*, int);
245 static int mcdx_stop(struct s_drive_stuff
*, int);
246 static int mcdx_hold(struct s_drive_stuff
*, int);
247 static int mcdx_reset(struct s_drive_stuff
*, enum resetmodes
, int);
248 static int mcdx_setdrivemode(struct s_drive_stuff
*, enum drivemodes
, int);
249 static int mcdx_setdatamode(struct s_drive_stuff
*, enum datamodes
, int);
250 static int mcdx_requestsubqcode(struct s_drive_stuff
*, struct s_subqcode
*, int);
251 static int mcdx_requestmultidiskinfo(struct s_drive_stuff
*, struct s_multi
*, int);
252 static int mcdx_requesttocdata(struct s_drive_stuff
*, struct s_diskinfo
*, int);
253 static int mcdx_getstatus(struct s_drive_stuff
*, int);
254 static int mcdx_getval(struct s_drive_stuff
*, int to
, int delay
, char*);
255 static int mcdx_talk(struct s_drive_stuff
*,
256 const unsigned char* cmd
, size_t,
257 void *buffer
, size_t size
,
258 unsigned int timeout
, int);
259 static int mcdx_readtoc(struct s_drive_stuff
*);
260 static int mcdx_playtrk(struct s_drive_stuff
*, const struct cdrom_ti
*);
261 static int mcdx_playmsf(struct s_drive_stuff
*, const struct cdrom_msf
*);
262 static int mcdx_setattentuator(struct s_drive_stuff
*, struct cdrom_volctrl
*, int);
264 /* static variables ************************************************/
266 static int mcdx_blocksizes
[MCDX_NDRIVES
];
267 static int mcdx_drive_map
[][2] = MCDX_DRIVEMAP
;
268 static struct s_drive_stuff
* mcdx_stuffp
[MCDX_NDRIVES
];
269 static struct s_drive_stuff
* mcdx_irq_map
[16] =
270 {0, 0, 0, 0, 0, 0, 0, 0,
271 0, 0, 0, 0, 0, 0, 0, 0};
272 MODULE_PARM(mcdx
, "1-4i");
274 static struct cdrom_device_ops mcdx_dops
= {
275 mcdx_open
, /* open */
276 mcdx_close
, /* release */
277 NULL
, /* drive status */
278 mcdx_media_changed
, /* media changed */
279 mcdx_tray_move
, /* tray move */
280 mcdx_lockdoor
, /* lock door */
281 NULL
, /* select speed */
282 NULL
, /* select disc */
283 NULL
, /* get last session */
284 NULL
, /* get universal product code */
285 NULL
, /* hard reset */
286 mcdx_audio_ioctl
, /* audio ioctl */
287 NULL
, /* device-specific ioctl */
288 CDC_OPEN_TRAY
| CDC_LOCK
| CDC_MEDIA_CHANGED
| CDC_PLAY_AUDIO
289 | CDC_DRIVE_STATUS
, /* capability */
290 0, /* number of minor devices */
293 static struct cdrom_device_info mcdx_info
= {
294 &mcdx_dops
, /* device operations */
299 2, /* maximum speed */
300 1, /* number of discs */
301 0, /* options, not owned */
302 0, /* mc_flags, not owned */
303 0, /* use count, not owned */
304 "mcdx", /* name of the device type */
309 /* KERNEL INTERFACE FUNCTIONS **************************************/
312 static int mcdx_audio_ioctl(struct cdrom_device_info
* cdi
, unsigned int cmd
,
315 struct s_drive_stuff
*stuffp
= mcdx_stuffp
[MINOR(cdi
->dev
)];
317 if (!stuffp
->present
) return -ENXIO
;
321 if(-1 == mcdx_requesttocdata(stuffp
, &stuffp
->di
, 1))
323 stuffp
->lastsector
= -1;
327 stuffp
->lastsector
= (CD_FRAMESIZE
/ 512)
328 * msf2log(&stuffp
->di
.msf_leadout
) - 1;
335 if (-1 == mcdx_readtoc(stuffp
)) return -1;
343 xtrace(IOCTL
, "ioctl() START\n");
344 /* Spin up the drive. Don't think we can do this.
345 * For now, ignore it.
351 xtrace(IOCTL
, "ioctl() STOP\n");
352 stuffp
->audiostatus
= CDROM_AUDIO_INVALID
;
353 if (-1 == mcdx_stop(stuffp
, 1))
358 case CDROMPLAYTRKIND
: {
359 struct cdrom_ti
*ti
=(struct cdrom_ti
*) arg
;
361 xtrace(IOCTL
, "ioctl() PLAYTRKIND\n");
362 if ((ti
->cdti_trk0
< stuffp
->di
.n_first
)
363 || (ti
->cdti_trk0
> stuffp
->di
.n_last
)
364 || (ti
->cdti_trk1
< stuffp
->di
.n_first
))
366 if (ti
->cdti_trk1
> stuffp
->di
.n_last
)
367 ti
->cdti_trk1
= stuffp
->di
.n_last
;
368 xtrace(PLAYTRK
, "ioctl() track %d to %d\n", ti
->cdti_trk0
, ti
->cdti_trk1
);
369 return mcdx_playtrk(stuffp
, ti
);
373 struct cdrom_msf
*msf
=(struct cdrom_msf
*) arg
;
375 xtrace(IOCTL
, "ioctl() PLAYMSF\n");
377 if ((stuffp
->audiostatus
== CDROM_AUDIO_PLAY
)
378 && (-1 == mcdx_hold(stuffp
, 1))) return -EIO
;
380 msf
->cdmsf_min0
= uint2bcd(msf
->cdmsf_min0
);
381 msf
->cdmsf_sec0
= uint2bcd(msf
->cdmsf_sec0
);
382 msf
->cdmsf_frame0
= uint2bcd(msf
->cdmsf_frame0
);
384 msf
->cdmsf_min1
= uint2bcd(msf
->cdmsf_min1
);
385 msf
->cdmsf_sec1
= uint2bcd(msf
->cdmsf_sec1
);
386 msf
->cdmsf_frame1
= uint2bcd(msf
->cdmsf_frame1
);
388 stuffp
->stop
.dt
.minute
= msf
->cdmsf_min1
;
389 stuffp
->stop
.dt
.second
= msf
->cdmsf_sec1
;
390 stuffp
->stop
.dt
.frame
= msf
->cdmsf_frame1
;
392 return mcdx_playmsf(stuffp
, msf
);
396 xtrace(IOCTL
, "ioctl() RESUME\n");
397 return mcdx_playtrk(stuffp
, NULL
);
400 case CDROMREADTOCENTRY
: {
401 struct cdrom_tocentry
*entry
=(struct cdrom_tocentry
*) arg
;
402 struct s_subqcode
*tp
= NULL
;
403 xtrace(IOCTL
, "ioctl() READTOCENTRY\n");
405 if (-1 == mcdx_readtoc(stuffp
)) return -1;
406 if (entry
->cdte_track
== CDROM_LEADOUT
)
407 tp
= &stuffp
->toc
[stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 1];
408 else if (entry
->cdte_track
> stuffp
->di
.n_last
409 || entry
->cdte_track
< stuffp
->di
.n_first
) return -EINVAL
;
410 else tp
= &stuffp
->toc
[entry
->cdte_track
- stuffp
->di
.n_first
];
414 entry
->cdte_adr
= tp
->control
;
415 entry
->cdte_ctrl
= tp
->control
>> 4;
416 /* Always return stuff in MSF, and let the Uniform cdrom driver
417 worry about what the user actually wants */
418 entry
->cdte_addr
.msf
.minute
= bcd2uint(tp
->dt
.minute
);
419 entry
->cdte_addr
.msf
.second
= bcd2uint(tp
->dt
.second
);
420 entry
->cdte_addr
.msf
.frame
= bcd2uint(tp
->dt
.frame
);
425 struct cdrom_subchnl
*sub
= (struct cdrom_subchnl
*)arg
;
428 xtrace(IOCTL
, "ioctl() SUBCHNL\n");
430 if (-1 == mcdx_requestsubqcode(stuffp
, &q
, 2))
433 xtrace(SUBCHNL
, "audiostatus: %x\n", stuffp
->audiostatus
);
434 sub
->cdsc_audiostatus
= stuffp
->audiostatus
;
435 sub
->cdsc_adr
= q
.control
;
436 sub
->cdsc_ctrl
= q
.control
>> 4;
437 sub
->cdsc_trk
= bcd2uint(q
.tno
);
438 sub
->cdsc_ind
= bcd2uint(q
.index
);
440 xtrace(SUBCHNL
, "trk %d, ind %d\n",
441 sub
->cdsc_trk
, sub
->cdsc_ind
);
442 /* Always return stuff in MSF, and let the Uniform cdrom driver
443 worry about what the user actually wants */
444 sub
->cdsc_absaddr
.msf
.minute
= bcd2uint(q
.dt
.minute
);
445 sub
->cdsc_absaddr
.msf
.second
= bcd2uint(q
.dt
.second
);
446 sub
->cdsc_absaddr
.msf
.frame
= bcd2uint(q
.dt
.frame
);
447 sub
->cdsc_reladdr
.msf
.minute
= bcd2uint(q
.tt
.minute
);
448 sub
->cdsc_reladdr
.msf
.second
= bcd2uint(q
.tt
.second
);
449 sub
->cdsc_reladdr
.msf
.frame
= bcd2uint(q
.tt
.frame
);
451 "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
452 sub
->cdsc_absaddr
.msf
.minute
, sub
->cdsc_absaddr
.msf
.second
,
453 sub
->cdsc_absaddr
.msf
.frame
, sub
->cdsc_reladdr
.msf
.minute
,
454 sub
->cdsc_reladdr
.msf
.second
, sub
->cdsc_reladdr
.msf
.frame
);
459 case CDROMREADTOCHDR
: {
460 struct cdrom_tochdr
*toc
=(struct cdrom_tochdr
*) arg
;
462 xtrace(IOCTL
, "ioctl() READTOCHDR\n");
463 toc
->cdth_trk0
= stuffp
->di
.n_first
;
464 toc
->cdth_trk1
= stuffp
->di
.n_last
;
465 xtrace(TOCHDR
, "ioctl() track0 = %d, track1 = %d\n",
466 stuffp
->di
.n_first
, stuffp
->di
.n_last
);
471 xtrace(IOCTL
, "ioctl() PAUSE\n");
472 if (stuffp
->audiostatus
!= CDROM_AUDIO_PLAY
) return -EINVAL
;
473 if (-1 == mcdx_stop(stuffp
, 1)) return -EIO
;
474 stuffp
->audiostatus
= CDROM_AUDIO_PAUSED
;
475 if (-1 == mcdx_requestsubqcode(stuffp
, &stuffp
->start
, 1))
480 case CDROMMULTISESSION
: {
481 struct cdrom_multisession
*ms
=(struct cdrom_multisession
*) arg
;
482 xtrace(IOCTL
, "ioctl() MULTISESSION\n");
483 /* Always return stuff in LBA, and let the Uniform cdrom driver
484 worry about what the user actually wants */
485 ms
->addr
.lba
= msf2log(&stuffp
->multi
.msf_last
);
486 ms
->xa_flag
= !!stuffp
->multi
.multi
;
487 xtrace(MS
, "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
488 ms
->xa_flag
, ms
->addr
.lba
, stuffp
->multi
.msf_last
.minute
,
489 stuffp
->multi
.msf_last
.second
,stuffp
->multi
.msf_last
.frame
);
495 xtrace(IOCTL
, "ioctl() EJECT\n");
496 if (stuffp
->users
> 1) return -EBUSY
;
497 return(mcdx_tray_move(cdi
, 1));
500 case CDROMCLOSETRAY
: {
501 xtrace(IOCTL
, "ioctl() CDROMCLOSETRAY\n");
502 return(mcdx_tray_move(cdi
, 0));
506 struct cdrom_volctrl
*volctrl
=(struct cdrom_volctrl
*)arg
;
507 xtrace(IOCTL
, "ioctl() VOLCTRL\n");
509 #if 0 /* not tested! */
510 /* adjust for the weirdness of workman (md) */
511 /* can't test it (hs) */
512 volctrl
.channel2
= volctrl
.channel1
;
513 volctrl
.channel1
= volctrl
.channel3
= 0x00;
515 return mcdx_setattentuator(stuffp
, volctrl
, 2);
519 xwarn("ioctl(): unknown request 0x%04x\n", cmd
);
524 void do_mcdx_request()
527 struct s_drive_stuff
*stuffp
;
531 if (CURRENT
== NULL
) {
532 xtrace(REQUEST
, "end_request(0): CURRENT == NULL\n");
536 if (CURRENT
->rq_status
== RQ_INACTIVE
) {
537 xtrace(REQUEST
, "end_request(0): rq_status == RQ_INACTIVE\n");
543 dev
= MINOR(CURRENT
->rq_dev
);
544 stuffp
= mcdx_stuffp
[dev
];
547 || (dev
>= MCDX_NDRIVES
)
549 || (!stuffp
->present
)) {
550 xwarn("do_request(): bad device: %s\n",
551 kdevname(CURRENT
->rq_dev
));
552 xtrace(REQUEST
, "end_request(0): bad device\n");
553 end_request(0); return;
557 xwarn("do_request() attempt to read from audio cd\n");
558 xtrace(REQUEST
, "end_request(0): read from audio\n");
559 end_request(0); return;
562 xtrace(REQUEST
, "do_request() (%lu + %lu)\n",
563 CURRENT
->sector
, CURRENT
->nr_sectors
);
565 switch (CURRENT
->cmd
) {
567 xwarn("do_request(): attempt to write to cd!!\n");
568 xtrace(REQUEST
, "end_request(0): write\n");
569 end_request(0); return;
573 while (CURRENT
->nr_sectors
) {
576 i
= mcdx_transfer(stuffp
,
579 CURRENT
->nr_sectors
);
585 CURRENT
->sector
+= i
;
586 CURRENT
->nr_sectors
-= i
;
587 CURRENT
->buffer
+= (i
* 512);
592 xtrace(REQUEST
, "end_request(1)\n");
597 panic(MCDX
"do_request: unknown command.\n");
605 mcdx_open(struct cdrom_device_info
* cdi
, int purpose
)
607 struct s_drive_stuff
*stuffp
;
608 xtrace(OPENCLOSE
, "open()\n");
609 stuffp
= mcdx_stuffp
[MINOR(cdi
->dev
)];
610 if (!stuffp
->present
) return -ENXIO
;
612 /* Make the modules looking used ... (thanx bjorn).
613 * But we shouldn't forget to decrement the module counter
617 /* this is only done to test if the drive talks with us */
618 if (-1 == mcdx_getstatus(stuffp
, 1)) {
625 xtrace(OPENCLOSE
, "open() media changed\n");
626 stuffp
->audiostatus
= CDROM_AUDIO_INVALID
;
628 xtrace(OPENCLOSE
, "open() Request multisession info\n");
629 if (-1 == mcdx_requestmultidiskinfo( stuffp
, &stuffp
->multi
, 6))
630 xinfo("No multidiskinfo\n");
633 if (!stuffp
->multi
.multi
)
634 stuffp
->multi
.msf_last
.second
= 2;
636 xtrace(OPENCLOSE
, "open() MS: %d, last @ %02x:%02x.%02x\n",
638 stuffp
->multi
.msf_last
.minute
,
639 stuffp
->multi
.msf_last
.second
,
640 stuffp
->multi
.msf_last
.frame
);
642 { ; } /* got multisession information */
643 /* request the disks table of contents (aka diskinfo) */
644 if (-1 == mcdx_requesttocdata(stuffp
, &stuffp
->di
, 1)) {
646 stuffp
->lastsector
= -1;
650 stuffp
->lastsector
= (CD_FRAMESIZE
/ 512)
651 * msf2log(&stuffp
->di
.msf_leadout
) - 1;
653 xtrace(OPENCLOSE
, "open() start %d (%02x:%02x.%02x) %d\n",
655 stuffp
->di
.msf_first
.minute
,
656 stuffp
->di
.msf_first
.second
,
657 stuffp
->di
.msf_first
.frame
,
658 msf2log(&stuffp
->di
.msf_first
));
659 xtrace(OPENCLOSE
, "open() last %d (%02x:%02x.%02x) %d\n",
661 stuffp
->di
.msf_leadout
.minute
,
662 stuffp
->di
.msf_leadout
.second
,
663 stuffp
->di
.msf_leadout
.frame
,
664 msf2log(&stuffp
->di
.msf_leadout
));
668 xtrace(MALLOC
, "open() free old toc @ %p\n", stuffp
->toc
);
674 xtrace(OPENCLOSE
, "open() init irq generation\n");
675 if (-1 == mcdx_config(stuffp
, 1)) {
681 /* Set the read speed */
682 xwarn("AAA %x AAA\n", stuffp
->readcmd
);
683 if (stuffp
->readerrs
) stuffp
->readcmd
= READ1X
;
684 else stuffp
->readcmd
=
685 stuffp
->present
| SINGLE
? READ1X
: READ2X
;
686 xwarn("XXX %x XXX\n", stuffp
->readcmd
);
688 stuffp
->readcmd
= stuffp
->present
| SINGLE
? READ1X
: READ2X
;
691 /* try to get the first sector, iff any ... */
692 if (stuffp
->lastsector
>= 0) {
700 for (tries
= 6; tries
; tries
--) {
704 xtrace(OPENCLOSE
, "open() try as %s\n",
705 stuffp
->xa
? "XA" : "normal");
707 if (-1 == (ans
= mcdx_setdatamode(stuffp
,
708 stuffp
->xa
? MODE2
: MODE1
, 1))) {
709 /* MOD_DEC_USE_COUNT, return -EIO; */
714 if ((stuffp
->audio
= e_audio(ans
))) break;
716 while (0 == (ans
= mcdx_transfer(stuffp
, buf
, 0, 1)))
720 stuffp
->xa
= !stuffp
->xa
;
723 /* xa disks will be read in raw mode, others not */
724 if (-1 == mcdx_setdrivemode(stuffp
,
725 stuffp
->xa
? RAW
: COOKED
, 1)) {
730 xinfo("open() audio disk found\n");
731 } else if (stuffp
->lastsector
>= 0) {
732 xinfo("open() %s%s disk found\n",
733 stuffp
->xa
? "XA / " : "",
734 stuffp
->multi
.multi
? "Multi Session" : "Single Session");
742 static void mcdx_close(struct cdrom_device_info
* cdi
)
744 struct s_drive_stuff
*stuffp
;
746 xtrace(OPENCLOSE
, "close()\n");
748 stuffp
= mcdx_stuffp
[MINOR(cdi
->dev
)];
755 static int mcdx_media_changed(struct cdrom_device_info
* cdi
, int disc_nr
)
756 /* Return: 1 if media changed since last call to this function
759 struct s_drive_stuff
*stuffp
;
761 xinfo("mcdx_media_changed called for device %s\n",
764 stuffp
= mcdx_stuffp
[MINOR(cdi
->dev
)];
765 mcdx_getstatus(stuffp
, 1);
767 if (stuffp
->yyy
== 0) return 0;
773 void __init
mcdx_setup(char *str
, int *pi
)
775 if (pi
[0] > 0) mcdx_drive_map
[0][0] = pi
[1];
776 if (pi
[0] > 1) mcdx_drive_map
[0][1] = pi
[2];
779 /* DIRTY PART ******************************************************/
781 static void mcdx_delay(struct s_drive_stuff
*stuff
, long jifs
)
782 /* This routine is used for sleeping.
783 * A jifs value <0 means NO sleeping,
784 * =0 means minimal sleeping (let the kernel
785 * run for other processes)
786 * >0 means at least sleep for that amount.
787 * May be we could use a simple count loop w/ jumps to itself, but
788 * I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
790 if (jifs
< 0) return;
792 xtrace(SLEEP
, "*** delay: sleepq\n");
793 interruptible_sleep_on_timeout(&stuff
->sleepq
, jifs
);
794 xtrace(SLEEP
, "delay awoken\n");
795 if (signal_pending(current
)) {
796 xtrace(SLEEP
, "got signal\n");
801 mcdx_intr(int irq
, void *dev_id
, struct pt_regs
* regs
)
803 struct s_drive_stuff
*stuffp
;
806 stuffp
= mcdx_irq_map
[irq
];
808 if (stuffp
== NULL
) {
809 xwarn("mcdx: no device for intr %d\n", irq
);
814 if ( !stuffp
->busy
&& stuffp
->pending
)
818 /* get the interrupt status */
819 b
= inb((unsigned int) stuffp
->rreg_status
);
820 stuffp
->introk
= ~b
& MCDX_RBIT_DTEN
;
822 /* NOTE: We only should get interrupts if the data we
823 * requested are ready to transfer.
824 * But the drive seems to generate ``asynchronous'' interrupts
825 * on several error conditions too. (Despite the err int enable
826 * setting during initialisation) */
828 /* if not ok, read the next byte as the drives status */
829 if (!stuffp
->introk
) {
830 xtrace(IRQ
, "intr() irq %d hw status 0x%02x\n", irq
, b
);
831 if (~b
& MCDX_RBIT_STEN
) {
832 xinfo( "intr() irq %d status 0x%02x\n",
833 irq
, inb((unsigned int) stuffp
->rreg_data
));
835 xinfo( "intr() irq %d ambiguous hw status\n", irq
);
838 xtrace(IRQ
, "irq() irq %d ok, status %02x\n", irq
, b
);
842 wake_up_interruptible(&stuffp
->busyq
);
848 struct s_drive_stuff
*stuffp
,
849 const unsigned char *cmd
, size_t cmdlen
,
850 void *buffer
, size_t size
,
851 unsigned int timeout
, int tries
)
852 /* Send a command to the drive, wait for the result.
853 * returns -1 on timeout, drive status otherwise
854 * If buffer is not zero, the result (length size) is stored there.
855 * If buffer is zero the size should be the number of bytes to read
856 * from the drive. These bytes are discarded.
863 /* Somebody wants the data read? */
864 if ((discard
= (buffer
== NULL
))) buffer
= &c
;
866 while (stuffp
->lock
) {
867 xtrace(SLEEP
, "*** talk: lockq\n");
868 interruptible_sleep_on(&stuffp
->lockq
);
869 xtrace(SLEEP
, "talk: awoken\n");
874 /* An operation other then reading data destroys the
875 * data already requested and remembered in stuffp->request, ... */
878 #if MCDX_DEBUG & TALK
881 xtrace(TALK
, "talk() %d / %d tries, res.size %d, command 0x%02x",
882 tries
, timeout
, size
, (unsigned char) cmd
[0]);
883 for (i
= 1; i
< cmdlen
; i
++) xtrace(TALK
, " 0x%02x", cmd
[i
]);
888 /* give up if all tries are done (bad) or if the status
890 for (st
= -1; st
== -1 && tries
; tries
--) {
892 char *bp
= (char*) buffer
;
895 outsb((unsigned int) stuffp
->wreg_data
, cmd
, cmdlen
);
896 xtrace(TALK
, "talk() command sent\n");
898 /* get the status byte */
899 if (-1 == mcdx_getval(stuffp
, timeout
, 0, bp
)) {
900 xinfo("talk() %02x timed out (status), %d tr%s left\n",
901 cmd
[0], tries
- 1, tries
== 2 ? "y" : "ies");
908 xtrace(TALK
, "talk() got status 0x%02x\n", st
);
912 xwarn("command error cmd = %02x %s \n",
913 cmd
[0], cmdlen
> 1 ? "..." : "");
919 if (stuffp
->audiostatus
== CDROM_AUDIO_INVALID
)
920 stuffp
->audiostatus
=
921 e_audiobusy(st
) ? CDROM_AUDIO_PLAY
: CDROM_AUDIO_NO_STATUS
;
922 else if (stuffp
->audiostatus
== CDROM_AUDIO_PLAY
923 && e_audiobusy(st
) == 0)
924 stuffp
->audiostatus
= CDROM_AUDIO_COMPLETED
;
928 xinfo("talk() media changed\n");
929 stuffp
->xxx
= stuffp
->yyy
= 1;
932 /* now actually get the data */
934 if (-1 == mcdx_getval(stuffp
, timeout
, 0, bp
)) {
935 xinfo("talk() %02x timed out (data), %d tr%s left\n",
936 cmd
[0], tries
- 1, tries
== 2 ? "y" : "ies");
940 xtrace(TALK
, "talk() got 0x%02x\n", *(bp
- 1));
945 if (!tries
&& st
== -1) xinfo("talk() giving up\n");
949 wake_up_interruptible(&stuffp
->lockq
);
951 xtrace(TALK
, "talk() done with 0x%02x\n", st
);
955 /* MODULE STUFF ***********************************************************/
959 int init_module(void)
965 for (i
= 0; i
< MCDX_NDRIVES
; i
++) {
966 if (mcdx_stuffp
[i
]) {
967 xtrace(INIT
, "init_module() drive %d stuff @ %p\n",
979 void cleanup_module(void)
983 xinfo("cleanup_module called\n");
985 for (i
= 0; i
< MCDX_NDRIVES
; i
++) {
986 struct s_drive_stuff
*stuffp
;
987 if (unregister_cdrom(&mcdx_info
)) {
988 printk(KERN_WARNING
"Can't unregister cdrom mcdx\n");
991 stuffp
= mcdx_stuffp
[i
];
992 if (!stuffp
) continue;
993 release_region((unsigned long) stuffp
->wreg_data
, MCDX_IO_SIZE
);
994 free_irq(stuffp
->irq
, NULL
);
996 xtrace(MALLOC
, "cleanup_module() free toc @ %p\n", stuffp
->toc
);
999 xtrace(MALLOC
, "cleanup_module() free stuffp @ %p\n", stuffp
);
1000 mcdx_stuffp
[i
] = NULL
;
1004 if (unregister_blkdev(MAJOR_NR
, "mcdx") != 0) {
1005 xwarn("cleanup() unregister_blkdev() failed\n");
1008 else xinfo("cleanup() succeeded\n");
1014 /* Support functions ************************************************/
1016 int __init
mcdx_init_drive(int drive
)
1018 struct s_version version
;
1019 struct s_drive_stuff
* stuffp
;
1020 int size
= sizeof(*stuffp
);
1023 mcdx_blocksizes
[drive
] = 0;
1025 xtrace(INIT
, "init() try drive %d\n", drive
);
1027 xtrace(INIT
, "kmalloc space for stuffpt's\n");
1028 xtrace(MALLOC
, "init() malloc %d bytes\n", size
);
1029 if (!(stuffp
= kmalloc(size
, GFP_KERNEL
))) {
1030 xwarn("init() malloc failed\n");
1034 xtrace(INIT
, "init() got %d bytes for drive stuff @ %p\n",
1035 sizeof(*stuffp
), stuffp
);
1037 /* set default values */
1038 memset(stuffp
, 0, sizeof(*stuffp
));
1040 stuffp
->present
= 0; /* this should be 0 already */
1041 stuffp
->toc
= NULL
; /* this should be NULL already */
1043 /* setup our irq and i/o addresses */
1044 stuffp
->irq
= irq(mcdx_drive_map
[drive
]);
1045 stuffp
->wreg_data
= stuffp
->rreg_data
= port(mcdx_drive_map
[drive
]);
1046 stuffp
->wreg_reset
= stuffp
->rreg_status
= stuffp
->wreg_data
+ 1;
1047 stuffp
->wreg_hcon
= stuffp
->wreg_reset
+ 1;
1048 stuffp
->wreg_chn
= stuffp
->wreg_hcon
+ 1;
1050 init_waitqueue_head(&stuffp
->busyq
);
1051 init_waitqueue_head(&stuffp
->lockq
);
1052 init_waitqueue_head(&stuffp
->sleepq
);
1054 /* check if i/o addresses are available */
1055 if (check_region((unsigned int) stuffp
->wreg_data
, MCDX_IO_SIZE
)) {
1056 xwarn("0x%3p,%d: Init failed. "
1057 "I/O ports (0x%3p..0x%3p) already in use.\n",
1058 stuffp
->wreg_data
, stuffp
->irq
,
1060 stuffp
->wreg_data
+ MCDX_IO_SIZE
- 1);
1061 xtrace(MALLOC
, "init() free stuffp @ %p\n", stuffp
);
1063 xtrace(INIT
, "init() continue at next drive\n");
1064 return 0; /* next drive */
1067 xtrace(INIT
, "init() i/o port is available at 0x%3p\n",
1069 xtrace(INIT
, "init() hardware reset\n");
1070 mcdx_reset(stuffp
, HARD
, 1);
1072 xtrace(INIT
, "init() get version\n");
1073 if (-1 == mcdx_requestversion(stuffp
, &version
, 4)) {
1074 /* failed, next drive */
1075 xwarn("%s=0x%3p,%d: Init failed. Can't get version.\n",
1077 stuffp
->wreg_data
, stuffp
->irq
);
1078 xtrace(MALLOC
, "init() free stuffp @ %p\n", stuffp
);
1080 xtrace(INIT
, "init() continue at next drive\n");
1084 switch (version
.code
) {
1086 stuffp
->readcmd
= READ2X
;
1087 stuffp
->present
= DOUBLE
| DOOR
| MULTI
;
1090 stuffp
->readcmd
= READ1X
;
1091 stuffp
->present
= SINGLE
| DOOR
| MULTI
;
1094 stuffp
->readcmd
= READ1X
;
1095 stuffp
->present
= SINGLE
;
1098 stuffp
->present
= 0; break;
1101 stuffp
->playcmd
= READ1X
;
1103 if (!stuffp
->present
) {
1104 xwarn("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n",
1105 MCDX
, stuffp
->wreg_data
, stuffp
->irq
);
1107 return 0; /* next drive */
1110 xtrace(INIT
, "init() register blkdev\n");
1111 if (register_blkdev(MAJOR_NR
, "mcdx", &cdrom_fops
) != 0) {
1112 xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n",
1114 stuffp
->wreg_data
, stuffp
->irq
, MAJOR_NR
);
1119 blk_dev
[MAJOR_NR
].request_fn
= DEVICE_REQUEST
;
1120 read_ahead
[MAJOR_NR
] = READ_AHEAD
;
1121 blksize_size
[MAJOR_NR
] = mcdx_blocksizes
;
1123 xtrace(INIT
, "init() subscribe irq and i/o\n");
1124 mcdx_irq_map
[stuffp
->irq
] = stuffp
;
1125 if (request_irq(stuffp
->irq
, mcdx_intr
, SA_INTERRUPT
, "mcdx", NULL
)) {
1126 xwarn("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n",
1128 stuffp
->wreg_data
, stuffp
->irq
, stuffp
->irq
);
1133 request_region((unsigned int) stuffp
->wreg_data
,
1137 xtrace(INIT
, "init() get garbage\n");
1140 mcdx_delay(stuffp
, HZ
/2);
1141 for (i
= 100; i
; i
--)
1142 (void) inb((unsigned int) stuffp
->rreg_status
);
1147 /* irq 11 -> channel register */
1148 outb(0x50, (unsigned int) stuffp
->wreg_chn
);
1151 xtrace(INIT
, "init() set non dma but irq mode\n");
1152 mcdx_config(stuffp
, 1);
1154 stuffp
->minor
= drive
;
1156 sprintf(msg
, " mcdx: Mitsumi CD-ROM installed at 0x%3p, irq %d."
1157 " (Firmware version %c %x)\n",
1158 stuffp
->wreg_data
, stuffp
->irq
, version
.code
,
1160 mcdx_stuffp
[drive
] = stuffp
;
1161 xtrace(INIT
, "init() mcdx_stuffp[%d] = %p\n", drive
, stuffp
);
1162 mcdx_info
.dev
= MKDEV(MAJOR_NR
,0);
1163 if (register_cdrom(&mcdx_info
) != 0) {
1164 printk("Cannot register Mitsumi CD-ROM!\n");
1165 release_region((unsigned long) stuffp
->wreg_data
,
1167 free_irq(stuffp
->irq
, NULL
);
1169 if (unregister_blkdev(MAJOR_NR
, "mcdx") != 0)
1170 xwarn("cleanup() unregister_blkdev() failed\n");
1177 int __init
mcdx_init(void)
1181 xwarn("Version 2.14(hs) for " UTS_RELEASE
"\n");
1183 xwarn("Version 2.14(hs) \n");
1186 xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
1188 /* zero the pointer array */
1189 for (drive
= 0; drive
< MCDX_NDRIVES
; drive
++)
1190 mcdx_stuffp
[drive
] = NULL
;
1192 /* do the initialisation */
1193 for (drive
= 0; drive
< MCDX_NDRIVES
; drive
++) {
1194 switch(mcdx_init_drive(drive
)) {
1205 mcdx_transfer(struct s_drive_stuff
*stuffp
,
1206 char *p
, int sector
, int nr_sectors
)
1207 /* This seems to do the actually transfer. But it does more. It
1208 keeps track of errors occurred and will (if possible) fall back
1209 to single speed on error.
1210 Return: -1 on timeout or other error
1211 else status byte (as in stuff->st) */
1215 ans
= mcdx_xfer(stuffp
, p
, sector
, nr_sectors
);
1218 if (-1 == ans
) stuffp
->readerrs
++;
1221 if (stuffp
->readerrs
&& stuffp
->readcmd
== READ1X
) {
1222 xwarn("XXX Already reading 1x -- no chance\n");
1226 xwarn("XXX Fallback to 1x\n");
1228 stuffp
->readcmd
= READ1X
;
1229 return mcdx_transfer(stuffp
, p
, sector
, nr_sectors
);
1235 static int mcdx_xfer(struct s_drive_stuff
*stuffp
,
1236 char *p
, int sector
, int nr_sectors
)
1237 /* This does actually the transfer from the drive.
1238 Return: -1 on timeout or other error
1239 else status byte (as in stuff->st) */
1245 if (stuffp
->audio
) {
1246 xwarn("Attempt to read from audio CD.\n");
1250 if (!stuffp
->readcmd
) {
1251 xinfo("Can't transfer from missing disk.\n");
1255 while (stuffp
->lock
) {
1256 interruptible_sleep_on(&stuffp
->lockq
);
1260 && (sector
>= stuffp
->pending
)
1261 && (sector
< stuffp
->low_border
)) {
1263 /* All (or at least a part of the sectors requested) seems
1264 * to be already requested, so we don't need to bother the
1265 * drive with new requests ...
1266 * Wait for the drive become idle, but first
1267 * check for possible occurred errors --- the drive
1268 * seems to report them asynchronously */
1271 border
= stuffp
->high_border
< (border
= sector
+ nr_sectors
)
1272 ? stuffp
->high_border
: border
;
1274 stuffp
->lock
= current
->pid
;
1278 while (stuffp
->busy
) {
1280 timeout
= interruptible_sleep_on_timeout(&stuffp
->busyq
, 5*HZ
);
1282 if (!stuffp
->introk
) { xtrace(XFER
, "error via interrupt\n"); }
1283 else if (!timeout
) { xtrace(XFER
, "timeout\n"); }
1284 else if (signal_pending(current
)) {
1285 xtrace(XFER
, "signal\n");
1292 wake_up_interruptible(&stuffp
->lockq
);
1293 xtrace(XFER
, "transfer() done (-1)\n");
1297 /* check if we need to set the busy flag (as we
1298 * expect an interrupt */
1299 stuffp
->busy
= (3 == (stuffp
->pending
& 3));
1301 /* Test if it's the first sector of a block,
1302 * there we have to skip some bytes as we read raw data */
1303 if (stuffp
->xa
&& (0 == (stuffp
->pending
& 3))) {
1304 const int HEAD
= CD_FRAMESIZE_RAW
- CD_XA_TAIL
- CD_FRAMESIZE
;
1305 insb((unsigned int) stuffp
->rreg_data
, p
, HEAD
);
1308 /* now actually read the data */
1309 insb((unsigned int) stuffp
->rreg_data
, p
, 512);
1311 /* test if it's the last sector of a block,
1312 * if so, we have to handle XA special */
1313 if ((3 == (stuffp
->pending
& 3)) && stuffp
->xa
) {
1314 char dummy
[CD_XA_TAIL
];
1315 insb((unsigned int) stuffp
->rreg_data
, &dummy
[0], CD_XA_TAIL
);
1318 if (stuffp
->pending
== sector
) {
1323 } while (++(stuffp
->pending
) < border
);
1326 wake_up_interruptible(&stuffp
->lockq
);
1330 /* The requested sector(s) is/are out of the
1331 * already requested range, so we have to bother the drive
1332 * with a new request. */
1334 static unsigned char cmd
[] = {
1340 cmd
[0] = stuffp
->readcmd
;
1342 /* The numbers held in ->pending, ..., should be valid */
1344 stuffp
->pending
= sector
& ~3;
1346 /* do some sanity checks */
1347 if (stuffp
->pending
> stuffp
->lastsector
) {
1348 xwarn("transfer() sector %d from nirvana requested.\n",
1350 stuffp
->status
= MCDX_ST_EOM
;
1352 xtrace(XFER
, "transfer() done (-1)\n");
1356 if ((stuffp
->low_border
= stuffp
->pending
+ DIRECT_SIZE
)
1357 > stuffp
->lastsector
+ 1) {
1358 xtrace(XFER
, "cut low_border\n");
1359 stuffp
->low_border
= stuffp
->lastsector
+ 1;
1361 if ((stuffp
->high_border
= stuffp
->pending
+ REQUEST_SIZE
)
1362 > stuffp
->lastsector
+ 1) {
1363 xtrace(XFER
, "cut high_border\n");
1364 stuffp
->high_border
= stuffp
->lastsector
+ 1;
1367 { /* Convert the sector to be requested to MSF format */
1368 struct cdrom_msf0 pending
;
1369 log2msf(stuffp
->pending
/ 4, &pending
);
1370 cmd
[1] = pending
.minute
;
1371 cmd
[2] = pending
.second
;
1372 cmd
[3] = pending
.frame
;
1375 cmd
[6] = (unsigned char) ((stuffp
->high_border
- stuffp
->pending
) / 4);
1376 xtrace(XFER
, "[%2d]\n", cmd
[6]);
1379 /* Now really issue the request command */
1380 outsb((unsigned int) stuffp
->wreg_data
, cmd
, sizeof cmd
);
1384 if ( stuffp
->int_err
) {
1386 stuffp
->int_err
= 0;
1391 stuffp
->low_border
= (stuffp
->low_border
+= done
) < stuffp
->high_border
1392 ? stuffp
->low_border
: stuffp
->high_border
;
1398 /* Access to elements of the mcdx_drive_map members */
1400 static char* port(int *ip
) { return (char*) ip
[0]; }
1401 static int irq(int *ip
) { return ip
[1]; }
1403 /* Misc number converters */
1405 static unsigned int bcd2uint(unsigned char c
)
1406 { return (c
>> 4) * 10 + (c
& 0x0f); }
1408 static unsigned int uint2bcd(unsigned int ival
)
1409 { return ((ival
/ 10) << 4) | (ival
% 10); }
1411 static void log2msf(unsigned int l
, struct cdrom_msf0
* pmsf
)
1414 pmsf
->minute
= uint2bcd(l
/ 4500), l
%= 4500;
1415 pmsf
->second
= uint2bcd(l
/ 75);
1416 pmsf
->frame
= uint2bcd(l
% 75);
1419 static unsigned int msf2log(const struct cdrom_msf0
* pmsf
)
1421 return bcd2uint(pmsf
->frame
)
1422 + bcd2uint(pmsf
->second
) * 75
1423 + bcd2uint(pmsf
->minute
) * 4500
1427 int mcdx_readtoc(struct s_drive_stuff
* stuffp
)
1428 /* Read the toc entries from the CD,
1429 * Return: -1 on failure, else 0 */
1433 xtrace(READTOC
, "ioctl() toc already read\n");
1437 xtrace(READTOC
, "ioctl() readtoc for %d tracks\n",
1438 stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 1);
1440 if (-1 == mcdx_hold(stuffp
, 1)) return -1;
1442 xtrace(READTOC
, "ioctl() tocmode\n");
1443 if (-1 == mcdx_setdrivemode(stuffp
, TOC
, 1)) return -EIO
;
1445 /* all seems to be ok so far ... malloc */
1448 size
= sizeof(struct s_subqcode
) * (stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 2);
1450 xtrace(MALLOC
, "ioctl() malloc %d bytes\n", size
);
1451 stuffp
->toc
= kmalloc(size
, GFP_KERNEL
);
1453 xwarn("Cannot malloc %d bytes for toc\n", size
);
1454 mcdx_setdrivemode(stuffp
, DATA
, 1);
1459 /* now read actually the index */
1465 trk
< (stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 1);
1467 stuffp
->toc
[trk
].index
= 0;
1469 for (retries
= 300; retries
; retries
--) { /* why 300? */
1470 struct s_subqcode q
;
1473 if (-1 == mcdx_requestsubqcode(stuffp
, &q
, 1)) {
1474 mcdx_setdrivemode(stuffp
, DATA
, 1);
1478 idx
= bcd2uint(q
.index
);
1481 && (idx
<= stuffp
->di
.n_last
)
1483 && (stuffp
->toc
[idx
- stuffp
->di
.n_first
].index
== 0)) {
1484 stuffp
->toc
[idx
- stuffp
->di
.n_first
] = q
;
1485 xtrace(READTOC
, "ioctl() toc idx %d (trk %d)\n", idx
, trk
);
1488 if (trk
== 0) break;
1490 memset(&stuffp
->toc
[stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 1],
1491 0, sizeof(stuffp
->toc
[0]));
1492 stuffp
->toc
[stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 1].dt
1493 = stuffp
->di
.msf_leadout
;
1496 /* unset toc mode */
1497 xtrace(READTOC
, "ioctl() undo toc mode\n");
1498 if (-1 == mcdx_setdrivemode(stuffp
, DATA
, 2))
1501 #if MCDX_DEBUG && READTOC
1504 trk
< (stuffp
->di
.n_last
- stuffp
->di
.n_first
+ 2);
1506 xtrace(READTOC
, "ioctl() %d readtoc %02x %02x %02x"
1507 " %02x:%02x.%02x %02x:%02x.%02x\n",
1508 trk
+ stuffp
->di
.n_first
,
1509 stuffp
->toc
[trk
].control
, stuffp
->toc
[trk
].tno
, stuffp
->toc
[trk
].index
,
1510 stuffp
->toc
[trk
].tt
.minute
, stuffp
->toc
[trk
].tt
.second
, stuffp
->toc
[trk
].tt
.frame
,
1511 stuffp
->toc
[trk
].dt
.minute
, stuffp
->toc
[trk
].dt
.second
, stuffp
->toc
[trk
].dt
.frame
);
1519 mcdx_playmsf(struct s_drive_stuff
* stuffp
, const struct cdrom_msf
* msf
)
1521 unsigned char cmd
[7] = {
1525 if (!stuffp
->readcmd
) {
1526 xinfo("Can't play from missing disk.\n");
1530 cmd
[0] = stuffp
->playcmd
;
1532 cmd
[1] = msf
->cdmsf_min0
;
1533 cmd
[2] = msf
->cdmsf_sec0
;
1534 cmd
[3] = msf
->cdmsf_frame0
;
1535 cmd
[4] = msf
->cdmsf_min1
;
1536 cmd
[5] = msf
->cdmsf_sec1
;
1537 cmd
[6] = msf
->cdmsf_frame1
;
1539 xtrace(PLAYMSF
, "ioctl(): play %x "
1540 "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1541 cmd
[0], cmd
[1], cmd
[2], cmd
[3],
1542 cmd
[4], cmd
[5], cmd
[6]);
1544 outsb((unsigned int) stuffp
->wreg_data
, cmd
, sizeof cmd
);
1546 if (-1 == mcdx_getval(stuffp
, 3 * HZ
, 0, NULL
)) {
1547 xwarn("playmsf() timeout\n");
1551 stuffp
->audiostatus
= CDROM_AUDIO_PLAY
;
1556 mcdx_playtrk(struct s_drive_stuff
* stuffp
, const struct cdrom_ti
* ti
)
1558 struct s_subqcode
* p
;
1559 struct cdrom_msf msf
;
1561 if (-1 == mcdx_readtoc(stuffp
)) return -1;
1563 if (ti
) p
= &stuffp
->toc
[ti
->cdti_trk0
- stuffp
->di
.n_first
];
1564 else p
= &stuffp
->start
;
1566 msf
.cdmsf_min0
= p
->dt
.minute
;
1567 msf
.cdmsf_sec0
= p
->dt
.second
;
1568 msf
.cdmsf_frame0
= p
->dt
.frame
;
1571 p
= &stuffp
->toc
[ti
->cdti_trk1
- stuffp
->di
.n_first
+ 1];
1573 } else p
= &stuffp
->stop
;
1575 msf
.cdmsf_min1
= p
->dt
.minute
;
1576 msf
.cdmsf_sec1
= p
->dt
.second
;
1577 msf
.cdmsf_frame1
= p
->dt
.frame
;
1579 return mcdx_playmsf(stuffp
, &msf
);
1583 /* Drive functions ************************************************/
1586 mcdx_tray_move(struct cdrom_device_info
* cdi
, int position
)
1588 struct s_drive_stuff
*stuffp
= mcdx_stuffp
[MINOR(cdi
->dev
)];
1590 if (!stuffp
->present
)
1592 if (!(stuffp
->present
& DOOR
))
1595 if (position
) /* 1: eject */
1596 return mcdx_talk(stuffp
, "\xf6", 1, NULL
, 1, 5 * HZ
, 3);
1598 return mcdx_talk(stuffp
, "\xf8", 1, NULL
, 1, 5 * HZ
, 3);
1603 mcdx_stop(struct s_drive_stuff
*stuffp
, int tries
)
1604 { return mcdx_talk(stuffp
, "\xf0", 1, NULL
, 1, 2 * HZ
, tries
); }
1607 mcdx_hold(struct s_drive_stuff
*stuffp
, int tries
)
1608 { return mcdx_talk(stuffp
, "\x70", 1, NULL
, 1, 2 * HZ
, tries
); }
1611 mcdx_requestsubqcode(struct s_drive_stuff
*stuffp
,
1612 struct s_subqcode
*sub
,
1618 if (-1 == (ans
= mcdx_talk(
1619 stuffp
, "\x20", 1, buf
, sizeof(buf
),
1622 sub
->control
= buf
[1];
1624 sub
->index
= buf
[3];
1625 sub
->tt
.minute
= buf
[4];
1626 sub
->tt
.second
= buf
[5];
1627 sub
->tt
.frame
= buf
[6];
1628 sub
->dt
.minute
= buf
[8];
1629 sub
->dt
.second
= buf
[9];
1630 sub
->dt
.frame
= buf
[10];
1636 mcdx_requestmultidiskinfo(struct s_drive_stuff
*stuffp
, struct s_multi
*multi
, int tries
)
1641 if (stuffp
->present
& MULTI
) {
1642 ans
= mcdx_talk(stuffp
, "\x11", 1, buf
, sizeof(buf
), 2 * HZ
, tries
);
1643 multi
->multi
= buf
[1];
1644 multi
->msf_last
.minute
= buf
[2];
1645 multi
->msf_last
.second
= buf
[3];
1646 multi
->msf_last
.frame
= buf
[4];
1655 mcdx_requesttocdata(struct s_drive_stuff
*stuffp
, struct s_diskinfo
*info
, int tries
)
1659 ans
= mcdx_talk(stuffp
, "\x10", 1, buf
, sizeof(buf
), 2 * HZ
, tries
);
1664 info
->n_first
= bcd2uint(buf
[1]);
1665 info
->n_last
= bcd2uint(buf
[2]);
1666 info
->msf_leadout
.minute
= buf
[3];
1667 info
->msf_leadout
.second
= buf
[4];
1668 info
->msf_leadout
.frame
= buf
[5];
1669 info
->msf_first
.minute
= buf
[6];
1670 info
->msf_first
.second
= buf
[7];
1671 info
->msf_first
.frame
= buf
[8];
1677 mcdx_setdrivemode(struct s_drive_stuff
*stuffp
, enum drivemodes mode
, int tries
)
1682 xtrace(HW
, "setdrivemode() %d\n", mode
);
1684 if (-1 == (ans
= mcdx_talk(stuffp
, "\xc2", 1, cmd
, sizeof(cmd
), 5 * HZ
, tries
)))
1688 case TOC
: cmd
[1] |= 0x04; break;
1689 case DATA
: cmd
[1] &= ~0x04; break;
1690 case RAW
: cmd
[1] |= 0x40; break;
1691 case COOKED
: cmd
[1] &= ~0x40; break;
1695 return mcdx_talk(stuffp
, cmd
, 2, NULL
, 1, 5 * HZ
, tries
);
1699 mcdx_setdatamode(struct s_drive_stuff
*stuffp
, enum datamodes mode
, int tries
)
1701 unsigned char cmd
[2] = { 0xa0 };
1702 xtrace(HW
, "setdatamode() %d\n", mode
);
1704 case MODE0
: cmd
[1] = 0x00; break;
1705 case MODE1
: cmd
[1] = 0x01; break;
1706 case MODE2
: cmd
[1] = 0x02; break;
1707 default: return -EINVAL
;
1709 return mcdx_talk(stuffp
, cmd
, 2, NULL
, 1, 5 * HZ
, tries
);
1713 mcdx_config(struct s_drive_stuff
*stuffp
, int tries
)
1717 xtrace(HW
, "config()\n");
1721 cmd
[1] = 0x10; /* irq enable */
1722 cmd
[2] = 0x05; /* pre, err irq enable */
1724 if (-1 == mcdx_talk(stuffp
, cmd
, 3, NULL
, 1, 1 * HZ
, tries
))
1727 cmd
[1] = 0x02; /* dma select */
1728 cmd
[2] = 0x00; /* no dma */
1730 return mcdx_talk(stuffp
, cmd
, 3, NULL
, 1, 1 * HZ
, tries
);
1734 mcdx_requestversion(struct s_drive_stuff
*stuffp
, struct s_version
*ver
, int tries
)
1739 if (-1 == (ans
= mcdx_talk(stuffp
, "\xdc",
1740 1, buf
, sizeof(buf
), 2 * HZ
, tries
)))
1750 mcdx_reset(struct s_drive_stuff
*stuffp
, enum resetmodes mode
, int tries
)
1753 outb(0, (unsigned int) stuffp
->wreg_chn
); /* no dma, no irq -> hardware */
1754 outb(0, (unsigned int) stuffp
->wreg_reset
); /* hw reset */
1756 } else return mcdx_talk(stuffp
, "\x60", 1, NULL
, 1, 5 * HZ
, tries
);
1759 static int mcdx_lockdoor(struct cdrom_device_info
* cdi
, int lock
)
1761 struct s_drive_stuff
*stuffp
= mcdx_stuffp
[MINOR(cdi
->dev
)];
1762 char cmd
[2] = { 0xfe };
1764 if (!(stuffp
->present
& DOOR
))
1766 if (stuffp
->present
& DOOR
) {
1767 cmd
[1] = lock
? 0x01 : 0x00;
1768 return mcdx_talk(stuffp
, cmd
, sizeof(cmd
), NULL
, 1, 5 * HZ
, 3);
1773 mcdx_getstatus(struct s_drive_stuff
*stuffp
, int tries
)
1774 { return mcdx_talk(stuffp
, "\x40", 1, NULL
, 1, 5 * HZ
, tries
); }
1777 mcdx_getval(struct s_drive_stuff
*stuffp
, int to
, int delay
, char* buf
)
1779 unsigned long timeout
= to
+ jiffies
;
1784 while (inb((unsigned int) stuffp
->rreg_status
) & MCDX_RBIT_STEN
) {
1785 if (time_after(jiffies
, timeout
)) return -1;
1786 mcdx_delay(stuffp
, delay
);
1789 *buf
= (unsigned char) inb((unsigned int) stuffp
->rreg_data
) & 0xff;
1795 mcdx_setattentuator(
1796 struct s_drive_stuff
* stuffp
,
1797 struct cdrom_volctrl
* vol
,
1802 cmd
[1] = vol
->channel0
;
1804 cmd
[3] = vol
->channel1
;
1807 return mcdx_talk(stuffp
, cmd
, sizeof(cmd
), NULL
, 5, 200, tries
);
1810 /* ex:set ts=4 sw=4 ai si: */