Linux-2.6.12-rc2
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / cdrom / mcdx.c
blobccde7ab491d4f96b162357ed817fd8b27287b801
1 /*
2 * The Mitsumi CDROM interface
3 * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de>
4 * VERSION: 2.14(hs)
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]
13 * -- Please --
14 * mail me (heiko@lotte.sax.de). When my last drive goes
15 * ballistic no more driver support will be available from me!
16 *************************************************************
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2, or (at your option)
21 * any later version.
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.
32 * Thanks to
33 * The Linux Community at all and ...
34 * Martin Harriss (he wrote the first Mitsumi Driver)
35 * Eberhard Moenkeberg (he gave me much support and the initial kick)
36 * Bernd Huebner, Ruediger Helsch (Unifix-Software GmbH, they
37 * improved the original driver)
38 * Jon Tombs, Bjorn Ekwall (module support)
39 * Daniel v. Mosnenck (he sent me the Technical and Programming Reference)
40 * Gerd Knorr (he lent me his PhotoCD)
41 * Nils Faerber and Roger E. Wolff (extensively tested the LU portion)
42 * Andreas Kies (testing the mysterious hang-ups)
43 * Heiko Eissfeldt (VERIFY_READ/WRITE)
44 * Marcin Dalecki (improved performance, shortened code)
45 * ... somebody forgotten?
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>
54 #if RCS
55 static const char *mcdx_c_version
56 = "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $";
57 #endif
59 #include <linux/module.h>
61 #include <linux/errno.h>
62 #include <linux/interrupt.h>
63 #include <linux/fs.h>
64 #include <linux/kernel.h>
65 #include <linux/cdrom.h>
66 #include <linux/ioport.h>
67 #include <linux/mm.h>
68 #include <linux/slab.h>
69 #include <linux/init.h>
70 #include <asm/io.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>
79 #include "mcdx.h"
81 #ifndef HZ
82 #error HZ not defined
83 #endif
85 #define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
87 #if !MCDX_QUIET
88 #define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
89 #else
90 #define xinfo(fmt, args...) { ; }
91 #endif
93 #if MCDX_DEBUG
94 #define xtrace(lvl, fmt, args...) \
95 { if (lvl > 0) \
96 { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
97 #define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
98 #else
99 #define xtrace(lvl, fmt, args...) { ; }
100 #define xdebug(fmt, args...) { ; }
101 #endif
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
109 needed */
110 const int REQUEST_SIZE = 800; /* should be less then 255 * 4 */
111 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 const int SINGLE = 0x01; /* single speed drive (FX001S, LU) */
118 const int DOUBLE = 0x02; /* double speed drive (FX001D, ..? */
119 const int DOOR = 0x04; /* door locking capability */
120 const int MULTI = 0x08; /* multi session capability */
122 const unsigned char READ1X = 0xc0;
123 const unsigned char READ2X = 0xc1;
126 /* DECLARATIONS ****************************************************/
127 struct s_subqcode {
128 unsigned char control;
129 unsigned char tno;
130 unsigned char index;
131 struct cdrom_msf0 tt;
132 struct cdrom_msf0 dt;
135 struct s_diskinfo {
136 unsigned int n_first;
137 unsigned int n_last;
138 struct cdrom_msf0 msf_leadout;
139 struct cdrom_msf0 msf_first;
142 struct s_multi {
143 unsigned char multi;
144 struct cdrom_msf0 msf_last;
147 struct s_version {
148 unsigned char code;
149 unsigned char ver;
152 /* Per drive/controller stuff **************************************/
154 struct s_drive_stuff {
155 /* waitqueues */
156 wait_queue_head_t busyq;
157 wait_queue_head_t lockq;
158 wait_queue_head_t sleepq;
160 /* flags */
161 volatile int introk; /* status of last irq operation */
162 volatile int busy; /* drive performs an operation */
163 volatile int lock; /* exclusive usage */
165 /* cd infos */
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 */
173 int audiostatus;
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' */
180 #ifdef AK2
181 volatile int int_err;
182 #endif /* AK2 */
184 /* adds and odds */
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 /* declared in blk.h */
214 int mcdx_init(void);
215 void do_mcdx_request(request_queue_t * q);
217 static int mcdx_block_open(struct inode *inode, struct file *file)
219 struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
220 return cdrom_open(&p->info, inode, file);
223 static int mcdx_block_release(struct inode *inode, struct file *file)
225 struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
226 return cdrom_release(&p->info, file);
229 static int mcdx_block_ioctl(struct inode *inode, struct file *file,
230 unsigned cmd, unsigned long arg)
232 struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
233 return cdrom_ioctl(file, &p->info, inode, cmd, arg);
236 static int mcdx_block_media_changed(struct gendisk *disk)
238 struct s_drive_stuff *p = disk->private_data;
239 return cdrom_media_changed(&p->info);
242 static struct block_device_operations mcdx_bdops =
244 .owner = THIS_MODULE,
245 .open = mcdx_block_open,
246 .release = mcdx_block_release,
247 .ioctl = mcdx_block_ioctl,
248 .media_changed = mcdx_block_media_changed,
252 /* Indirect exported functions. These functions are exported by their
253 addresses, such as mcdx_open and mcdx_close in the
254 structure mcdx_dops. */
256 /* exported by file_ops */
257 static int mcdx_open(struct cdrom_device_info *cdi, int purpose);
258 static void mcdx_close(struct cdrom_device_info *cdi);
259 static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr);
260 static int mcdx_tray_move(struct cdrom_device_info *cdi, int position);
261 static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock);
262 static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
263 unsigned int cmd, void *arg);
265 /* misc internal support functions */
266 static void log2msf(unsigned int, struct cdrom_msf0 *);
267 static unsigned int msf2log(const struct cdrom_msf0 *);
268 static unsigned int uint2bcd(unsigned int);
269 static unsigned int bcd2uint(unsigned char);
270 static unsigned port(int *);
271 static int irq(int *);
272 static void mcdx_delay(struct s_drive_stuff *, long jifs);
273 static int mcdx_transfer(struct s_drive_stuff *, char *buf, int sector,
274 int nr_sectors);
275 static int mcdx_xfer(struct s_drive_stuff *, char *buf, int sector,
276 int nr_sectors);
278 static int mcdx_config(struct s_drive_stuff *, int);
279 static int mcdx_requestversion(struct s_drive_stuff *, struct s_version *,
280 int);
281 static int mcdx_stop(struct s_drive_stuff *, int);
282 static int mcdx_hold(struct s_drive_stuff *, int);
283 static int mcdx_reset(struct s_drive_stuff *, enum resetmodes, int);
284 static int mcdx_setdrivemode(struct s_drive_stuff *, enum drivemodes, int);
285 static int mcdx_setdatamode(struct s_drive_stuff *, enum datamodes, int);
286 static int mcdx_requestsubqcode(struct s_drive_stuff *,
287 struct s_subqcode *, int);
288 static int mcdx_requestmultidiskinfo(struct s_drive_stuff *,
289 struct s_multi *, int);
290 static int mcdx_requesttocdata(struct s_drive_stuff *, struct s_diskinfo *,
291 int);
292 static int mcdx_getstatus(struct s_drive_stuff *, int);
293 static int mcdx_getval(struct s_drive_stuff *, int to, int delay, char *);
294 static int mcdx_talk(struct s_drive_stuff *,
295 const unsigned char *cmd, size_t,
296 void *buffer, size_t size, unsigned int timeout, int);
297 static int mcdx_readtoc(struct s_drive_stuff *);
298 static int mcdx_playtrk(struct s_drive_stuff *, const struct cdrom_ti *);
299 static int mcdx_playmsf(struct s_drive_stuff *, const struct cdrom_msf *);
300 static int mcdx_setattentuator(struct s_drive_stuff *,
301 struct cdrom_volctrl *, int);
303 /* static variables ************************************************/
305 static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
306 static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES];
307 static DEFINE_SPINLOCK(mcdx_lock);
308 static struct request_queue *mcdx_queue;
310 /* You can only set the first two pairs, from old MODULE_PARM code. */
311 static int mcdx_set(const char *val, struct kernel_param *kp)
313 get_options((char *)val, 4, (int *)mcdx_drive_map);
314 return 0;
316 module_param_call(mcdx, mcdx_set, NULL, NULL, 0);
318 static struct cdrom_device_ops mcdx_dops = {
319 .open = mcdx_open,
320 .release = mcdx_close,
321 .media_changed = mcdx_media_changed,
322 .tray_move = mcdx_tray_move,
323 .lock_door = mcdx_lockdoor,
324 .audio_ioctl = mcdx_audio_ioctl,
325 .capability = CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED |
326 CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
329 /* KERNEL INTERFACE FUNCTIONS **************************************/
332 static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
333 unsigned int cmd, void *arg)
335 struct s_drive_stuff *stuffp = cdi->handle;
337 if (!stuffp->present)
338 return -ENXIO;
340 if (stuffp->xxx) {
341 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
342 stuffp->lastsector = -1;
343 } else {
344 stuffp->lastsector = (CD_FRAMESIZE / 512)
345 * msf2log(&stuffp->di.msf_leadout) - 1;
348 if (stuffp->toc) {
349 kfree(stuffp->toc);
350 stuffp->toc = NULL;
351 if (-1 == mcdx_readtoc(stuffp))
352 return -1;
355 stuffp->xxx = 0;
358 switch (cmd) {
359 case CDROMSTART:{
360 xtrace(IOCTL, "ioctl() START\n");
361 /* Spin up the drive. Don't think we can do this.
362 * For now, ignore it.
364 return 0;
367 case CDROMSTOP:{
368 xtrace(IOCTL, "ioctl() STOP\n");
369 stuffp->audiostatus = CDROM_AUDIO_INVALID;
370 if (-1 == mcdx_stop(stuffp, 1))
371 return -EIO;
372 return 0;
375 case CDROMPLAYTRKIND:{
376 struct cdrom_ti *ti = (struct cdrom_ti *) arg;
378 xtrace(IOCTL, "ioctl() PLAYTRKIND\n");
379 if ((ti->cdti_trk0 < stuffp->di.n_first)
380 || (ti->cdti_trk0 > stuffp->di.n_last)
381 || (ti->cdti_trk1 < stuffp->di.n_first))
382 return -EINVAL;
383 if (ti->cdti_trk1 > stuffp->di.n_last)
384 ti->cdti_trk1 = stuffp->di.n_last;
385 xtrace(PLAYTRK, "ioctl() track %d to %d\n",
386 ti->cdti_trk0, ti->cdti_trk1);
387 return mcdx_playtrk(stuffp, ti);
390 case CDROMPLAYMSF:{
391 struct cdrom_msf *msf = (struct cdrom_msf *) arg;
393 xtrace(IOCTL, "ioctl() PLAYMSF\n");
395 if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
396 && (-1 == mcdx_hold(stuffp, 1)))
397 return -EIO;
399 msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0);
400 msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0);
401 msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0);
403 msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1);
404 msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1);
405 msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1);
407 stuffp->stop.dt.minute = msf->cdmsf_min1;
408 stuffp->stop.dt.second = msf->cdmsf_sec1;
409 stuffp->stop.dt.frame = msf->cdmsf_frame1;
411 return mcdx_playmsf(stuffp, msf);
414 case CDROMRESUME:{
415 xtrace(IOCTL, "ioctl() RESUME\n");
416 return mcdx_playtrk(stuffp, NULL);
419 case CDROMREADTOCENTRY:{
420 struct cdrom_tocentry *entry =
421 (struct cdrom_tocentry *) arg;
422 struct s_subqcode *tp = NULL;
423 xtrace(IOCTL, "ioctl() READTOCENTRY\n");
425 if (-1 == mcdx_readtoc(stuffp))
426 return -1;
427 if (entry->cdte_track == CDROM_LEADOUT)
428 tp = &stuffp->toc[stuffp->di.n_last -
429 stuffp->di.n_first + 1];
430 else if (entry->cdte_track > stuffp->di.n_last
431 || entry->cdte_track < stuffp->di.n_first)
432 return -EINVAL;
433 else
434 tp = &stuffp->toc[entry->cdte_track -
435 stuffp->di.n_first];
437 if (NULL == tp)
438 return -EIO;
439 entry->cdte_adr = tp->control;
440 entry->cdte_ctrl = tp->control >> 4;
441 /* Always return stuff in MSF, and let the Uniform cdrom driver
442 worry about what the user actually wants */
443 entry->cdte_addr.msf.minute =
444 bcd2uint(tp->dt.minute);
445 entry->cdte_addr.msf.second =
446 bcd2uint(tp->dt.second);
447 entry->cdte_addr.msf.frame =
448 bcd2uint(tp->dt.frame);
449 return 0;
452 case CDROMSUBCHNL:{
453 struct cdrom_subchnl *sub =
454 (struct cdrom_subchnl *) arg;
455 struct s_subqcode q;
457 xtrace(IOCTL, "ioctl() SUBCHNL\n");
459 if (-1 == mcdx_requestsubqcode(stuffp, &q, 2))
460 return -EIO;
462 xtrace(SUBCHNL, "audiostatus: %x\n",
463 stuffp->audiostatus);
464 sub->cdsc_audiostatus = stuffp->audiostatus;
465 sub->cdsc_adr = q.control;
466 sub->cdsc_ctrl = q.control >> 4;
467 sub->cdsc_trk = bcd2uint(q.tno);
468 sub->cdsc_ind = bcd2uint(q.index);
470 xtrace(SUBCHNL, "trk %d, ind %d\n",
471 sub->cdsc_trk, sub->cdsc_ind);
472 /* Always return stuff in MSF, and let the Uniform cdrom driver
473 worry about what the user actually wants */
474 sub->cdsc_absaddr.msf.minute =
475 bcd2uint(q.dt.minute);
476 sub->cdsc_absaddr.msf.second =
477 bcd2uint(q.dt.second);
478 sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
479 sub->cdsc_reladdr.msf.minute =
480 bcd2uint(q.tt.minute);
481 sub->cdsc_reladdr.msf.second =
482 bcd2uint(q.tt.second);
483 sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
484 xtrace(SUBCHNL,
485 "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
486 sub->cdsc_absaddr.msf.minute,
487 sub->cdsc_absaddr.msf.second,
488 sub->cdsc_absaddr.msf.frame,
489 sub->cdsc_reladdr.msf.minute,
490 sub->cdsc_reladdr.msf.second,
491 sub->cdsc_reladdr.msf.frame);
493 return 0;
496 case CDROMREADTOCHDR:{
497 struct cdrom_tochdr *toc =
498 (struct cdrom_tochdr *) arg;
500 xtrace(IOCTL, "ioctl() READTOCHDR\n");
501 toc->cdth_trk0 = stuffp->di.n_first;
502 toc->cdth_trk1 = stuffp->di.n_last;
503 xtrace(TOCHDR,
504 "ioctl() track0 = %d, track1 = %d\n",
505 stuffp->di.n_first, stuffp->di.n_last);
506 return 0;
509 case CDROMPAUSE:{
510 xtrace(IOCTL, "ioctl() PAUSE\n");
511 if (stuffp->audiostatus != CDROM_AUDIO_PLAY)
512 return -EINVAL;
513 if (-1 == mcdx_stop(stuffp, 1))
514 return -EIO;
515 stuffp->audiostatus = CDROM_AUDIO_PAUSED;
516 if (-1 ==
517 mcdx_requestsubqcode(stuffp, &stuffp->start,
519 return -EIO;
520 return 0;
523 case CDROMMULTISESSION:{
524 struct cdrom_multisession *ms =
525 (struct cdrom_multisession *) arg;
526 xtrace(IOCTL, "ioctl() MULTISESSION\n");
527 /* Always return stuff in LBA, and let the Uniform cdrom driver
528 worry about what the user actually wants */
529 ms->addr.lba = msf2log(&stuffp->multi.msf_last);
530 ms->xa_flag = !!stuffp->multi.multi;
531 xtrace(MS,
532 "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
533 ms->xa_flag, ms->addr.lba,
534 stuffp->multi.msf_last.minute,
535 stuffp->multi.msf_last.second,
536 stuffp->multi.msf_last.frame);
538 return 0;
541 case CDROMEJECT:{
542 xtrace(IOCTL, "ioctl() EJECT\n");
543 if (stuffp->users > 1)
544 return -EBUSY;
545 return (mcdx_tray_move(cdi, 1));
548 case CDROMCLOSETRAY:{
549 xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n");
550 return (mcdx_tray_move(cdi, 0));
553 case CDROMVOLCTRL:{
554 struct cdrom_volctrl *volctrl =
555 (struct cdrom_volctrl *) arg;
556 xtrace(IOCTL, "ioctl() VOLCTRL\n");
558 #if 0 /* not tested! */
559 /* adjust for the weirdness of workman (md) */
560 /* can't test it (hs) */
561 volctrl.channel2 = volctrl.channel1;
562 volctrl.channel1 = volctrl.channel3 = 0x00;
563 #endif
564 return mcdx_setattentuator(stuffp, volctrl, 2);
567 default:
568 return -EINVAL;
572 void do_mcdx_request(request_queue_t * q)
574 struct s_drive_stuff *stuffp;
575 struct request *req;
577 again:
579 req = elv_next_request(q);
580 if (!req)
581 return;
583 stuffp = req->rq_disk->private_data;
585 if (!stuffp->present) {
586 xwarn("do_request(): bad device: %s\n",req->rq_disk->disk_name);
587 xtrace(REQUEST, "end_request(0): bad device\n");
588 end_request(req, 0);
589 return;
592 if (stuffp->audio) {
593 xwarn("do_request() attempt to read from audio cd\n");
594 xtrace(REQUEST, "end_request(0): read from audio\n");
595 end_request(req, 0);
596 return;
599 xtrace(REQUEST, "do_request() (%lu + %lu)\n",
600 req->sector, req->nr_sectors);
602 if (req->cmd != READ) {
603 xwarn("do_request(): non-read command to cd!!\n");
604 xtrace(REQUEST, "end_request(0): write\n");
605 end_request(req, 0);
606 return;
608 else {
609 stuffp->status = 0;
610 while (req->nr_sectors) {
611 int i;
613 i = mcdx_transfer(stuffp,
614 req->buffer,
615 req->sector,
616 req->nr_sectors);
618 if (i == -1) {
619 end_request(req, 0);
620 goto again;
622 req->sector += i;
623 req->nr_sectors -= i;
624 req->buffer += (i * 512);
626 end_request(req, 1);
627 goto again;
629 xtrace(REQUEST, "end_request(1)\n");
630 end_request(req, 1);
633 goto again;
636 static int mcdx_open(struct cdrom_device_info *cdi, int purpose)
638 struct s_drive_stuff *stuffp;
639 xtrace(OPENCLOSE, "open()\n");
640 stuffp = cdi->handle;
641 if (!stuffp->present)
642 return -ENXIO;
644 /* Make the modules looking used ... (thanx bjorn).
645 * But we shouldn't forget to decrement the module counter
646 * on error return */
648 /* this is only done to test if the drive talks with us */
649 if (-1 == mcdx_getstatus(stuffp, 1))
650 return -EIO;
652 if (stuffp->xxx) {
654 xtrace(OPENCLOSE, "open() media changed\n");
655 stuffp->audiostatus = CDROM_AUDIO_INVALID;
656 stuffp->readcmd = 0;
657 xtrace(OPENCLOSE, "open() Request multisession info\n");
658 if (-1 ==
659 mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6))
660 xinfo("No multidiskinfo\n");
661 } else {
662 /* multisession ? */
663 if (!stuffp->multi.multi)
664 stuffp->multi.msf_last.second = 2;
666 xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
667 stuffp->multi.multi,
668 stuffp->multi.msf_last.minute,
669 stuffp->multi.msf_last.second,
670 stuffp->multi.msf_last.frame);
673 } /* got multisession information */
674 /* request the disks table of contents (aka diskinfo) */
675 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
677 stuffp->lastsector = -1;
679 } else {
681 stuffp->lastsector = (CD_FRAMESIZE / 512)
682 * msf2log(&stuffp->di.msf_leadout) - 1;
684 xtrace(OPENCLOSE,
685 "open() start %d (%02x:%02x.%02x) %d\n",
686 stuffp->di.n_first,
687 stuffp->di.msf_first.minute,
688 stuffp->di.msf_first.second,
689 stuffp->di.msf_first.frame,
690 msf2log(&stuffp->di.msf_first));
691 xtrace(OPENCLOSE,
692 "open() last %d (%02x:%02x.%02x) %d\n",
693 stuffp->di.n_last,
694 stuffp->di.msf_leadout.minute,
695 stuffp->di.msf_leadout.second,
696 stuffp->di.msf_leadout.frame,
697 msf2log(&stuffp->di.msf_leadout));
700 if (stuffp->toc) {
701 xtrace(MALLOC, "open() free old toc @ %p\n",
702 stuffp->toc);
703 kfree(stuffp->toc);
705 stuffp->toc = NULL;
708 xtrace(OPENCLOSE, "open() init irq generation\n");
709 if (-1 == mcdx_config(stuffp, 1))
710 return -EIO;
711 #if FALLBACK
712 /* Set the read speed */
713 xwarn("AAA %x AAA\n", stuffp->readcmd);
714 if (stuffp->readerrs)
715 stuffp->readcmd = READ1X;
716 else
717 stuffp->readcmd =
718 stuffp->present | SINGLE ? READ1X : READ2X;
719 xwarn("XXX %x XXX\n", stuffp->readcmd);
720 #else
721 stuffp->readcmd =
722 stuffp->present | SINGLE ? READ1X : READ2X;
723 #endif
725 /* try to get the first sector, iff any ... */
726 if (stuffp->lastsector >= 0) {
727 char buf[512];
728 int ans;
729 int tries;
731 stuffp->xa = 0;
732 stuffp->audio = 0;
734 for (tries = 6; tries; tries--) {
736 stuffp->introk = 1;
738 xtrace(OPENCLOSE, "open() try as %s\n",
739 stuffp->xa ? "XA" : "normal");
740 /* set data mode */
741 if (-1 == (ans = mcdx_setdatamode(stuffp,
742 stuffp->
743 xa ?
744 MODE2 :
745 MODE1,
746 1))) {
747 /* return -EIO; */
748 stuffp->xa = 0;
749 break;
752 if ((stuffp->audio = e_audio(ans)))
753 break;
755 while (0 ==
756 (ans =
757 mcdx_transfer(stuffp, buf, 0, 1)));
759 if (ans == 1)
760 break;
761 stuffp->xa = !stuffp->xa;
764 /* xa disks will be read in raw mode, others not */
765 if (-1 == mcdx_setdrivemode(stuffp,
766 stuffp->xa ? RAW : COOKED,
768 return -EIO;
769 if (stuffp->audio) {
770 xinfo("open() audio disk found\n");
771 } else if (stuffp->lastsector >= 0) {
772 xinfo("open() %s%s disk found\n",
773 stuffp->xa ? "XA / " : "",
774 stuffp->multi.
775 multi ? "Multi Session" : "Single Session");
778 stuffp->xxx = 0;
779 stuffp->users++;
780 return 0;
783 static void mcdx_close(struct cdrom_device_info *cdi)
785 struct s_drive_stuff *stuffp;
787 xtrace(OPENCLOSE, "close()\n");
789 stuffp = cdi->handle;
791 --stuffp->users;
794 static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr)
795 /* Return: 1 if media changed since last call to this function
796 0 otherwise */
798 struct s_drive_stuff *stuffp;
800 xinfo("mcdx_media_changed called for device %s\n", cdi->name);
802 stuffp = cdi->handle;
803 mcdx_getstatus(stuffp, 1);
805 if (stuffp->yyy == 0)
806 return 0;
808 stuffp->yyy = 0;
809 return 1;
812 #ifndef MODULE
813 static int __init mcdx_setup(char *str)
815 int pi[4];
816 (void) get_options(str, ARRAY_SIZE(pi), pi);
818 if (pi[0] > 0)
819 mcdx_drive_map[0][0] = pi[1];
820 if (pi[0] > 1)
821 mcdx_drive_map[0][1] = pi[2];
822 return 1;
825 __setup("mcdx=", mcdx_setup);
827 #endif
829 /* DIRTY PART ******************************************************/
831 static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
832 /* This routine is used for sleeping.
833 * A jifs value <0 means NO sleeping,
834 * =0 means minimal sleeping (let the kernel
835 * run for other processes)
836 * >0 means at least sleep for that amount.
837 * May be we could use a simple count loop w/ jumps to itself, but
838 * I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
840 if (jifs < 0)
841 return;
843 xtrace(SLEEP, "*** delay: sleepq\n");
844 interruptible_sleep_on_timeout(&stuff->sleepq, jifs);
845 xtrace(SLEEP, "delay awoken\n");
846 if (signal_pending(current)) {
847 xtrace(SLEEP, "got signal\n");
851 static irqreturn_t mcdx_intr(int irq, void *dev_id, struct pt_regs *regs)
853 struct s_drive_stuff *stuffp = dev_id;
854 unsigned char b;
856 if (stuffp == NULL) {
857 xwarn("mcdx: no device for intr %d\n", irq);
858 return IRQ_NONE;
860 #ifdef AK2
861 if (!stuffp->busy && stuffp->pending)
862 stuffp->int_err = 1;
864 #endif /* AK2 */
865 /* get the interrupt status */
866 b = inb(stuffp->rreg_status);
867 stuffp->introk = ~b & MCDX_RBIT_DTEN;
869 /* NOTE: We only should get interrupts if the data we
870 * requested are ready to transfer.
871 * But the drive seems to generate ``asynchronous'' interrupts
872 * on several error conditions too. (Despite the err int enable
873 * setting during initialisation) */
875 /* if not ok, read the next byte as the drives status */
876 if (!stuffp->introk) {
877 xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b);
878 if (~b & MCDX_RBIT_STEN) {
879 xinfo("intr() irq %d status 0x%02x\n",
880 irq, inb(stuffp->rreg_data));
881 } else {
882 xinfo("intr() irq %d ambiguous hw status\n", irq);
884 } else {
885 xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b);
888 stuffp->busy = 0;
889 wake_up_interruptible(&stuffp->busyq);
890 return IRQ_HANDLED;
894 static int mcdx_talk(struct s_drive_stuff *stuffp,
895 const unsigned char *cmd, size_t cmdlen,
896 void *buffer, size_t size, unsigned int timeout, int tries)
897 /* Send a command to the drive, wait for the result.
898 * returns -1 on timeout, drive status otherwise
899 * If buffer is not zero, the result (length size) is stored there.
900 * If buffer is zero the size should be the number of bytes to read
901 * from the drive. These bytes are discarded.
904 int st;
905 char c;
906 int discard;
908 /* Somebody wants the data read? */
909 if ((discard = (buffer == NULL)))
910 buffer = &c;
912 while (stuffp->lock) {
913 xtrace(SLEEP, "*** talk: lockq\n");
914 interruptible_sleep_on(&stuffp->lockq);
915 xtrace(SLEEP, "talk: awoken\n");
918 stuffp->lock = 1;
920 /* An operation other then reading data destroys the
921 * data already requested and remembered in stuffp->request, ... */
922 stuffp->valid = 0;
924 #if MCDX_DEBUG & TALK
926 unsigned char i;
927 xtrace(TALK,
928 "talk() %d / %d tries, res.size %d, command 0x%02x",
929 tries, timeout, size, (unsigned char) cmd[0]);
930 for (i = 1; i < cmdlen; i++)
931 xtrace(TALK, " 0x%02x", cmd[i]);
932 xtrace(TALK, "\n");
934 #endif
936 /* give up if all tries are done (bad) or if the status
937 * st != -1 (good) */
938 for (st = -1; st == -1 && tries; tries--) {
940 char *bp = (char *) buffer;
941 size_t sz = size;
943 outsb(stuffp->wreg_data, cmd, cmdlen);
944 xtrace(TALK, "talk() command sent\n");
946 /* get the status byte */
947 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
948 xinfo("talk() %02x timed out (status), %d tr%s left\n",
949 cmd[0], tries - 1, tries == 2 ? "y" : "ies");
950 continue;
952 st = *bp;
953 sz--;
954 if (!discard)
955 bp++;
957 xtrace(TALK, "talk() got status 0x%02x\n", st);
959 /* command error? */
960 if (e_cmderr(st)) {
961 xwarn("command error cmd = %02x %s \n",
962 cmd[0], cmdlen > 1 ? "..." : "");
963 st = -1;
964 continue;
967 /* audio status? */
968 if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
969 stuffp->audiostatus =
970 e_audiobusy(st) ? CDROM_AUDIO_PLAY :
971 CDROM_AUDIO_NO_STATUS;
972 else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
973 && e_audiobusy(st) == 0)
974 stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
976 /* media change? */
977 if (e_changed(st)) {
978 xinfo("talk() media changed\n");
979 stuffp->xxx = stuffp->yyy = 1;
982 /* now actually get the data */
983 while (sz--) {
984 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
985 xinfo("talk() %02x timed out (data), %d tr%s left\n",
986 cmd[0], tries - 1,
987 tries == 2 ? "y" : "ies");
988 st = -1;
989 break;
991 if (!discard)
992 bp++;
993 xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));
997 #if !MCDX_QUIET
998 if (!tries && st == -1)
999 xinfo("talk() giving up\n");
1000 #endif
1002 stuffp->lock = 0;
1003 wake_up_interruptible(&stuffp->lockq);
1005 xtrace(TALK, "talk() done with 0x%02x\n", st);
1006 return st;
1009 /* MODULE STUFF ***********************************************************/
1011 int __mcdx_init(void)
1013 int i;
1014 int drives = 0;
1016 mcdx_init();
1017 for (i = 0; i < MCDX_NDRIVES; i++) {
1018 if (mcdx_stuffp[i]) {
1019 xtrace(INIT, "init_module() drive %d stuff @ %p\n",
1020 i, mcdx_stuffp[i]);
1021 drives++;
1025 if (!drives)
1026 return -EIO;
1028 return 0;
1031 void __exit mcdx_exit(void)
1033 int i;
1035 xinfo("cleanup_module called\n");
1037 for (i = 0; i < MCDX_NDRIVES; i++) {
1038 struct s_drive_stuff *stuffp = mcdx_stuffp[i];
1039 if (!stuffp)
1040 continue;
1041 del_gendisk(stuffp->disk);
1042 if (unregister_cdrom(&stuffp->info)) {
1043 printk(KERN_WARNING "Can't unregister cdrom mcdx\n");
1044 continue;
1046 put_disk(stuffp->disk);
1047 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1048 free_irq(stuffp->irq, NULL);
1049 if (stuffp->toc) {
1050 xtrace(MALLOC, "cleanup_module() free toc @ %p\n",
1051 stuffp->toc);
1052 kfree(stuffp->toc);
1054 xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n",
1055 stuffp);
1056 mcdx_stuffp[i] = NULL;
1057 kfree(stuffp);
1060 if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
1061 xwarn("cleanup() unregister_blkdev() failed\n");
1063 blk_cleanup_queue(mcdx_queue);
1064 #if !MCDX_QUIET
1065 else
1066 xinfo("cleanup() succeeded\n");
1067 #endif
1070 #ifdef MODULE
1071 module_init(__mcdx_init);
1072 #endif
1073 module_exit(mcdx_exit);
1076 /* Support functions ************************************************/
1078 int __init mcdx_init_drive(int drive)
1080 struct s_version version;
1081 struct gendisk *disk;
1082 struct s_drive_stuff *stuffp;
1083 int size = sizeof(*stuffp);
1084 char msg[80];
1086 xtrace(INIT, "init() try drive %d\n", drive);
1088 xtrace(INIT, "kmalloc space for stuffpt's\n");
1089 xtrace(MALLOC, "init() malloc %d bytes\n", size);
1090 if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
1091 xwarn("init() malloc failed\n");
1092 return 1;
1095 disk = alloc_disk(1);
1096 if (!disk) {
1097 xwarn("init() malloc failed\n");
1098 kfree(stuffp);
1099 return 1;
1102 xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n",
1103 sizeof(*stuffp), stuffp);
1105 /* set default values */
1106 memset(stuffp, 0, sizeof(*stuffp));
1108 stuffp->present = 0; /* this should be 0 already */
1109 stuffp->toc = NULL; /* this should be NULL already */
1111 /* setup our irq and i/o addresses */
1112 stuffp->irq = irq(mcdx_drive_map[drive]);
1113 stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]);
1114 stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
1115 stuffp->wreg_hcon = stuffp->wreg_reset + 1;
1116 stuffp->wreg_chn = stuffp->wreg_hcon + 1;
1118 init_waitqueue_head(&stuffp->busyq);
1119 init_waitqueue_head(&stuffp->lockq);
1120 init_waitqueue_head(&stuffp->sleepq);
1122 /* check if i/o addresses are available */
1123 if (!request_region(stuffp->wreg_data, MCDX_IO_SIZE, "mcdx")) {
1124 xwarn("0x%03x,%d: Init failed. "
1125 "I/O ports (0x%03x..0x%03x) already in use.\n",
1126 stuffp->wreg_data, stuffp->irq,
1127 stuffp->wreg_data,
1128 stuffp->wreg_data + MCDX_IO_SIZE - 1);
1129 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1130 kfree(stuffp);
1131 put_disk(disk);
1132 xtrace(INIT, "init() continue at next drive\n");
1133 return 0; /* next drive */
1136 xtrace(INIT, "init() i/o port is available at 0x%03x\n"
1137 stuffp->wreg_data);
1138 xtrace(INIT, "init() hardware reset\n");
1139 mcdx_reset(stuffp, HARD, 1);
1141 xtrace(INIT, "init() get version\n");
1142 if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
1143 /* failed, next drive */
1144 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1145 xwarn("%s=0x%03x,%d: Init failed. Can't get version.\n",
1146 MCDX, stuffp->wreg_data, stuffp->irq);
1147 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1148 kfree(stuffp);
1149 put_disk(disk);
1150 xtrace(INIT, "init() continue at next drive\n");
1151 return 0;
1154 switch (version.code) {
1155 case 'D':
1156 stuffp->readcmd = READ2X;
1157 stuffp->present = DOUBLE | DOOR | MULTI;
1158 break;
1159 case 'F':
1160 stuffp->readcmd = READ1X;
1161 stuffp->present = SINGLE | DOOR | MULTI;
1162 break;
1163 case 'M':
1164 stuffp->readcmd = READ1X;
1165 stuffp->present = SINGLE;
1166 break;
1167 default:
1168 stuffp->present = 0;
1169 break;
1172 stuffp->playcmd = READ1X;
1174 if (!stuffp->present) {
1175 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1176 xwarn("%s=0x%03x,%d: Init failed. No Mitsumi CD-ROM?.\n",
1177 MCDX, stuffp->wreg_data, stuffp->irq);
1178 kfree(stuffp);
1179 put_disk(disk);
1180 return 0; /* next drive */
1183 xtrace(INIT, "init() register blkdev\n");
1184 if (register_blkdev(MAJOR_NR, "mcdx")) {
1185 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1186 kfree(stuffp);
1187 put_disk(disk);
1188 return 1;
1191 mcdx_queue = blk_init_queue(do_mcdx_request, &mcdx_lock);
1192 if (!mcdx_queue) {
1193 unregister_blkdev(MAJOR_NR, "mcdx");
1194 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1195 kfree(stuffp);
1196 put_disk(disk);
1197 return 1;
1200 xtrace(INIT, "init() subscribe irq and i/o\n");
1201 if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", stuffp)) {
1202 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1203 xwarn("%s=0x%03x,%d: Init failed. Can't get irq (%d).\n",
1204 MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq);
1205 stuffp->irq = 0;
1206 blk_cleanup_queue(mcdx_queue);
1207 kfree(stuffp);
1208 put_disk(disk);
1209 return 0;
1212 xtrace(INIT, "init() get garbage\n");
1214 int i;
1215 mcdx_delay(stuffp, HZ / 2);
1216 for (i = 100; i; i--)
1217 (void) inb(stuffp->rreg_status);
1221 #if WE_KNOW_WHY
1222 /* irq 11 -> channel register */
1223 outb(0x50, stuffp->wreg_chn);
1224 #endif
1226 xtrace(INIT, "init() set non dma but irq mode\n");
1227 mcdx_config(stuffp, 1);
1229 stuffp->info.ops = &mcdx_dops;
1230 stuffp->info.speed = 2;
1231 stuffp->info.capacity = 1;
1232 stuffp->info.handle = stuffp;
1233 sprintf(stuffp->info.name, "mcdx%d", drive);
1234 disk->major = MAJOR_NR;
1235 disk->first_minor = drive;
1236 strcpy(disk->disk_name, stuffp->info.name);
1237 disk->fops = &mcdx_bdops;
1238 disk->flags = GENHD_FL_CD;
1239 stuffp->disk = disk;
1241 sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%03x, irq %d."
1242 " (Firmware version %c %x)\n",
1243 stuffp->wreg_data, stuffp->irq, version.code, version.ver);
1244 mcdx_stuffp[drive] = stuffp;
1245 xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp);
1246 if (register_cdrom(&stuffp->info) != 0) {
1247 printk("Cannot register Mitsumi CD-ROM!\n");
1248 free_irq(stuffp->irq, NULL);
1249 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1250 kfree(stuffp);
1251 put_disk(disk);
1252 if (unregister_blkdev(MAJOR_NR, "mcdx") != 0)
1253 xwarn("cleanup() unregister_blkdev() failed\n");
1254 blk_cleanup_queue(mcdx_queue);
1255 return 2;
1257 disk->private_data = stuffp;
1258 disk->queue = mcdx_queue;
1259 add_disk(disk);
1260 printk(msg);
1261 return 0;
1264 int __init mcdx_init(void)
1266 int drive;
1267 xwarn("Version 2.14(hs) \n");
1269 xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
1271 /* zero the pointer array */
1272 for (drive = 0; drive < MCDX_NDRIVES; drive++)
1273 mcdx_stuffp[drive] = NULL;
1275 /* do the initialisation */
1276 for (drive = 0; drive < MCDX_NDRIVES; drive++) {
1277 switch (mcdx_init_drive(drive)) {
1278 case 2:
1279 return -EIO;
1280 case 1:
1281 break;
1284 return 0;
1287 static int mcdx_transfer(struct s_drive_stuff *stuffp,
1288 char *p, int sector, int nr_sectors)
1289 /* This seems to do the actually transfer. But it does more. It
1290 keeps track of errors occurred and will (if possible) fall back
1291 to single speed on error.
1292 Return: -1 on timeout or other error
1293 else status byte (as in stuff->st) */
1295 int ans;
1297 ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
1298 return ans;
1299 #if FALLBACK
1300 if (-1 == ans)
1301 stuffp->readerrs++;
1302 else
1303 return ans;
1305 if (stuffp->readerrs && stuffp->readcmd == READ1X) {
1306 xwarn("XXX Already reading 1x -- no chance\n");
1307 return -1;
1310 xwarn("XXX Fallback to 1x\n");
1312 stuffp->readcmd = READ1X;
1313 return mcdx_transfer(stuffp, p, sector, nr_sectors);
1314 #endif
1319 static int mcdx_xfer(struct s_drive_stuff *stuffp,
1320 char *p, int sector, int nr_sectors)
1321 /* This does actually the transfer from the drive.
1322 Return: -1 on timeout or other error
1323 else status byte (as in stuff->st) */
1325 int border;
1326 int done = 0;
1327 long timeout;
1329 if (stuffp->audio) {
1330 xwarn("Attempt to read from audio CD.\n");
1331 return -1;
1334 if (!stuffp->readcmd) {
1335 xinfo("Can't transfer from missing disk.\n");
1336 return -1;
1339 while (stuffp->lock) {
1340 interruptible_sleep_on(&stuffp->lockq);
1343 if (stuffp->valid && (sector >= stuffp->pending)
1344 && (sector < stuffp->low_border)) {
1346 /* All (or at least a part of the sectors requested) seems
1347 * to be already requested, so we don't need to bother the
1348 * drive with new requests ...
1349 * Wait for the drive become idle, but first
1350 * check for possible occurred errors --- the drive
1351 * seems to report them asynchronously */
1354 border = stuffp->high_border < (border =
1355 sector + nr_sectors)
1356 ? stuffp->high_border : border;
1358 stuffp->lock = current->pid;
1360 do {
1362 while (stuffp->busy) {
1364 timeout =
1365 interruptible_sleep_on_timeout
1366 (&stuffp->busyq, 5 * HZ);
1368 if (!stuffp->introk) {
1369 xtrace(XFER,
1370 "error via interrupt\n");
1371 } else if (!timeout) {
1372 xtrace(XFER, "timeout\n");
1373 } else if (signal_pending(current)) {
1374 xtrace(XFER, "signal\n");
1375 } else
1376 continue;
1378 stuffp->lock = 0;
1379 stuffp->busy = 0;
1380 stuffp->valid = 0;
1382 wake_up_interruptible(&stuffp->lockq);
1383 xtrace(XFER, "transfer() done (-1)\n");
1384 return -1;
1387 /* check if we need to set the busy flag (as we
1388 * expect an interrupt */
1389 stuffp->busy = (3 == (stuffp->pending & 3));
1391 /* Test if it's the first sector of a block,
1392 * there we have to skip some bytes as we read raw data */
1393 if (stuffp->xa && (0 == (stuffp->pending & 3))) {
1394 const int HEAD =
1395 CD_FRAMESIZE_RAW - CD_XA_TAIL -
1396 CD_FRAMESIZE;
1397 insb(stuffp->rreg_data, p, HEAD);
1400 /* now actually read the data */
1401 insb(stuffp->rreg_data, p, 512);
1403 /* test if it's the last sector of a block,
1404 * if so, we have to handle XA special */
1405 if ((3 == (stuffp->pending & 3)) && stuffp->xa) {
1406 char dummy[CD_XA_TAIL];
1407 insb(stuffp->rreg_data, &dummy[0], CD_XA_TAIL);
1410 if (stuffp->pending == sector) {
1411 p += 512;
1412 done++;
1413 sector++;
1415 } while (++(stuffp->pending) < border);
1417 stuffp->lock = 0;
1418 wake_up_interruptible(&stuffp->lockq);
1420 } else {
1422 /* The requested sector(s) is/are out of the
1423 * already requested range, so we have to bother the drive
1424 * with a new request. */
1426 static unsigned char cmd[] = {
1428 0, 0, 0,
1429 0, 0, 0
1432 cmd[0] = stuffp->readcmd;
1434 /* The numbers held in ->pending, ..., should be valid */
1435 stuffp->valid = 1;
1436 stuffp->pending = sector & ~3;
1438 /* do some sanity checks */
1439 if (stuffp->pending > stuffp->lastsector) {
1440 xwarn
1441 ("transfer() sector %d from nirvana requested.\n",
1442 stuffp->pending);
1443 stuffp->status = MCDX_ST_EOM;
1444 stuffp->valid = 0;
1445 xtrace(XFER, "transfer() done (-1)\n");
1446 return -1;
1449 if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)
1450 > stuffp->lastsector + 1) {
1451 xtrace(XFER, "cut low_border\n");
1452 stuffp->low_border = stuffp->lastsector + 1;
1454 if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE)
1455 > stuffp->lastsector + 1) {
1456 xtrace(XFER, "cut high_border\n");
1457 stuffp->high_border = stuffp->lastsector + 1;
1460 { /* Convert the sector to be requested to MSF format */
1461 struct cdrom_msf0 pending;
1462 log2msf(stuffp->pending / 4, &pending);
1463 cmd[1] = pending.minute;
1464 cmd[2] = pending.second;
1465 cmd[3] = pending.frame;
1468 cmd[6] =
1469 (unsigned
1470 char) ((stuffp->high_border - stuffp->pending) / 4);
1471 xtrace(XFER, "[%2d]\n", cmd[6]);
1473 stuffp->busy = 1;
1474 /* Now really issue the request command */
1475 outsb(stuffp->wreg_data, cmd, sizeof cmd);
1478 #ifdef AK2
1479 if (stuffp->int_err) {
1480 stuffp->valid = 0;
1481 stuffp->int_err = 0;
1482 return -1;
1484 #endif /* AK2 */
1486 stuffp->low_border = (stuffp->low_border +=
1487 done) <
1488 stuffp->high_border ? stuffp->low_border : stuffp->high_border;
1490 return done;
1494 /* Access to elements of the mcdx_drive_map members */
1496 static unsigned port(int *ip)
1498 return ip[0];
1500 static int irq(int *ip)
1502 return ip[1];
1505 /* Misc number converters */
1507 static unsigned int bcd2uint(unsigned char c)
1509 return (c >> 4) * 10 + (c & 0x0f);
1512 static unsigned int uint2bcd(unsigned int ival)
1514 return ((ival / 10) << 4) | (ival % 10);
1517 static void log2msf(unsigned int l, struct cdrom_msf0 *pmsf)
1519 l += CD_MSF_OFFSET;
1520 pmsf->minute = uint2bcd(l / 4500), l %= 4500;
1521 pmsf->second = uint2bcd(l / 75);
1522 pmsf->frame = uint2bcd(l % 75);
1525 static unsigned int msf2log(const struct cdrom_msf0 *pmsf)
1527 return bcd2uint(pmsf->frame)
1528 + bcd2uint(pmsf->second) * 75
1529 + bcd2uint(pmsf->minute) * 4500 - CD_MSF_OFFSET;
1532 int mcdx_readtoc(struct s_drive_stuff *stuffp)
1533 /* Read the toc entries from the CD,
1534 * Return: -1 on failure, else 0 */
1537 if (stuffp->toc) {
1538 xtrace(READTOC, "ioctl() toc already read\n");
1539 return 0;
1542 xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
1543 stuffp->di.n_last - stuffp->di.n_first + 1);
1545 if (-1 == mcdx_hold(stuffp, 1))
1546 return -1;
1548 xtrace(READTOC, "ioctl() tocmode\n");
1549 if (-1 == mcdx_setdrivemode(stuffp, TOC, 1))
1550 return -EIO;
1552 /* all seems to be ok so far ... malloc */
1554 int size;
1555 size =
1556 sizeof(struct s_subqcode) * (stuffp->di.n_last -
1557 stuffp->di.n_first + 2);
1559 xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
1560 stuffp->toc = kmalloc(size, GFP_KERNEL);
1561 if (!stuffp->toc) {
1562 xwarn("Cannot malloc %d bytes for toc\n", size);
1563 mcdx_setdrivemode(stuffp, DATA, 1);
1564 return -EIO;
1568 /* now read actually the index */
1570 int trk;
1571 int retries;
1573 for (trk = 0;
1574 trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
1575 trk++)
1576 stuffp->toc[trk].index = 0;
1578 for (retries = 300; retries; retries--) { /* why 300? */
1579 struct s_subqcode q;
1580 unsigned int idx;
1582 if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
1583 mcdx_setdrivemode(stuffp, DATA, 1);
1584 return -EIO;
1587 idx = bcd2uint(q.index);
1589 if ((idx > 0)
1590 && (idx <= stuffp->di.n_last)
1591 && (q.tno == 0)
1592 && (stuffp->toc[idx - stuffp->di.n_first].
1593 index == 0)) {
1594 stuffp->toc[idx - stuffp->di.n_first] = q;
1595 xtrace(READTOC,
1596 "ioctl() toc idx %d (trk %d)\n",
1597 idx, trk);
1598 trk--;
1600 if (trk == 0)
1601 break;
1603 memset(&stuffp->
1604 toc[stuffp->di.n_last - stuffp->di.n_first + 1], 0,
1605 sizeof(stuffp->toc[0]));
1606 stuffp->toc[stuffp->di.n_last - stuffp->di.n_first +
1607 1].dt = stuffp->di.msf_leadout;
1610 /* unset toc mode */
1611 xtrace(READTOC, "ioctl() undo toc mode\n");
1612 if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
1613 return -EIO;
1615 #if MCDX_DEBUG && READTOC
1617 int trk;
1618 for (trk = 0;
1619 trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
1620 trk++)
1621 xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
1622 " %02x:%02x.%02x %02x:%02x.%02x\n",
1623 trk + stuffp->di.n_first,
1624 stuffp->toc[trk].control,
1625 stuffp->toc[trk].tno,
1626 stuffp->toc[trk].index,
1627 stuffp->toc[trk].tt.minute,
1628 stuffp->toc[trk].tt.second,
1629 stuffp->toc[trk].tt.frame,
1630 stuffp->toc[trk].dt.minute,
1631 stuffp->toc[trk].dt.second,
1632 stuffp->toc[trk].dt.frame);
1634 #endif
1636 return 0;
1639 static int
1640 mcdx_playmsf(struct s_drive_stuff *stuffp, const struct cdrom_msf *msf)
1642 unsigned char cmd[7] = {
1643 0, 0, 0, 0, 0, 0, 0
1646 if (!stuffp->readcmd) {
1647 xinfo("Can't play from missing disk.\n");
1648 return -1;
1651 cmd[0] = stuffp->playcmd;
1653 cmd[1] = msf->cdmsf_min0;
1654 cmd[2] = msf->cdmsf_sec0;
1655 cmd[3] = msf->cdmsf_frame0;
1656 cmd[4] = msf->cdmsf_min1;
1657 cmd[5] = msf->cdmsf_sec1;
1658 cmd[6] = msf->cdmsf_frame1;
1660 xtrace(PLAYMSF, "ioctl(): play %x "
1661 "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1662 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]);
1664 outsb(stuffp->wreg_data, cmd, sizeof cmd);
1666 if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
1667 xwarn("playmsf() timeout\n");
1668 return -1;
1671 stuffp->audiostatus = CDROM_AUDIO_PLAY;
1672 return 0;
1675 static int
1676 mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti)
1678 struct s_subqcode *p;
1679 struct cdrom_msf msf;
1681 if (-1 == mcdx_readtoc(stuffp))
1682 return -1;
1684 if (ti)
1685 p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
1686 else
1687 p = &stuffp->start;
1689 msf.cdmsf_min0 = p->dt.minute;
1690 msf.cdmsf_sec0 = p->dt.second;
1691 msf.cdmsf_frame0 = p->dt.frame;
1693 if (ti) {
1694 p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
1695 stuffp->stop = *p;
1696 } else
1697 p = &stuffp->stop;
1699 msf.cdmsf_min1 = p->dt.minute;
1700 msf.cdmsf_sec1 = p->dt.second;
1701 msf.cdmsf_frame1 = p->dt.frame;
1703 return mcdx_playmsf(stuffp, &msf);
1707 /* Drive functions ************************************************/
1709 static int mcdx_tray_move(struct cdrom_device_info *cdi, int position)
1711 struct s_drive_stuff *stuffp = cdi->handle;
1713 if (!stuffp->present)
1714 return -ENXIO;
1715 if (!(stuffp->present & DOOR))
1716 return -ENOSYS;
1718 if (position) /* 1: eject */
1719 return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3);
1720 else /* 0: close */
1721 return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3);
1722 return 1;
1725 static int mcdx_stop(struct s_drive_stuff *stuffp, int tries)
1727 return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries);
1730 static int mcdx_hold(struct s_drive_stuff *stuffp, int tries)
1732 return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries);
1735 static int mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
1736 struct s_subqcode *sub, int tries)
1738 char buf[11];
1739 int ans;
1741 if (-1 == (ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf),
1742 2 * HZ, tries)))
1743 return -1;
1744 sub->control = buf[1];
1745 sub->tno = buf[2];
1746 sub->index = buf[3];
1747 sub->tt.minute = buf[4];
1748 sub->tt.second = buf[5];
1749 sub->tt.frame = buf[6];
1750 sub->dt.minute = buf[8];
1751 sub->dt.second = buf[9];
1752 sub->dt.frame = buf[10];
1754 return ans;
1757 static int mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp,
1758 struct s_multi *multi, int tries)
1760 char buf[5];
1761 int ans;
1763 if (stuffp->present & MULTI) {
1764 ans =
1765 mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ,
1766 tries);
1767 multi->multi = buf[1];
1768 multi->msf_last.minute = buf[2];
1769 multi->msf_last.second = buf[3];
1770 multi->msf_last.frame = buf[4];
1771 return ans;
1772 } else {
1773 multi->multi = 0;
1774 return 0;
1778 static int mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info,
1779 int tries)
1781 char buf[9];
1782 int ans;
1783 ans =
1784 mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
1785 if (ans == -1) {
1786 info->n_first = 0;
1787 info->n_last = 0;
1788 } else {
1789 info->n_first = bcd2uint(buf[1]);
1790 info->n_last = bcd2uint(buf[2]);
1791 info->msf_leadout.minute = buf[3];
1792 info->msf_leadout.second = buf[4];
1793 info->msf_leadout.frame = buf[5];
1794 info->msf_first.minute = buf[6];
1795 info->msf_first.second = buf[7];
1796 info->msf_first.frame = buf[8];
1798 return ans;
1801 static int mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode,
1802 int tries)
1804 char cmd[2];
1805 int ans;
1807 xtrace(HW, "setdrivemode() %d\n", mode);
1809 if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
1810 return -1;
1812 switch (mode) {
1813 case TOC:
1814 cmd[1] |= 0x04;
1815 break;
1816 case DATA:
1817 cmd[1] &= ~0x04;
1818 break;
1819 case RAW:
1820 cmd[1] |= 0x40;
1821 break;
1822 case COOKED:
1823 cmd[1] &= ~0x40;
1824 break;
1825 default:
1826 break;
1828 cmd[0] = 0x50;
1829 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1832 static int mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode,
1833 int tries)
1835 unsigned char cmd[2] = { 0xa0 };
1836 xtrace(HW, "setdatamode() %d\n", mode);
1837 switch (mode) {
1838 case MODE0:
1839 cmd[1] = 0x00;
1840 break;
1841 case MODE1:
1842 cmd[1] = 0x01;
1843 break;
1844 case MODE2:
1845 cmd[1] = 0x02;
1846 break;
1847 default:
1848 return -EINVAL;
1850 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1853 static int mcdx_config(struct s_drive_stuff *stuffp, int tries)
1855 char cmd[4];
1857 xtrace(HW, "config()\n");
1859 cmd[0] = 0x90;
1861 cmd[1] = 0x10; /* irq enable */
1862 cmd[2] = 0x05; /* pre, err irq enable */
1864 if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
1865 return -1;
1867 cmd[1] = 0x02; /* dma select */
1868 cmd[2] = 0x00; /* no dma */
1870 return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
1873 static int mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver,
1874 int tries)
1876 char buf[3];
1877 int ans;
1879 if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
1880 1, buf, sizeof(buf), 2 * HZ, tries)))
1881 return ans;
1883 ver->code = buf[1];
1884 ver->ver = buf[2];
1886 return ans;
1889 static int mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
1891 if (mode == HARD) {
1892 outb(0, stuffp->wreg_chn); /* no dma, no irq -> hardware */
1893 outb(0, stuffp->wreg_reset); /* hw reset */
1894 return 0;
1895 } else
1896 return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
1899 static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock)
1901 struct s_drive_stuff *stuffp = cdi->handle;
1902 char cmd[2] = { 0xfe };
1904 if (!(stuffp->present & DOOR))
1905 return -ENOSYS;
1906 if (stuffp->present & DOOR) {
1907 cmd[1] = lock ? 0x01 : 0x00;
1908 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3);
1909 } else
1910 return 0;
1913 static int mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
1915 return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries);
1918 static int
1919 mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char *buf)
1921 unsigned long timeout = to + jiffies;
1922 char c;
1924 if (!buf)
1925 buf = &c;
1927 while (inb(stuffp->rreg_status) & MCDX_RBIT_STEN) {
1928 if (time_after(jiffies, timeout))
1929 return -1;
1930 mcdx_delay(stuffp, delay);
1933 *buf = (unsigned char) inb(stuffp->rreg_data) & 0xff;
1935 return 0;
1938 static int mcdx_setattentuator(struct s_drive_stuff *stuffp,
1939 struct cdrom_volctrl *vol, int tries)
1941 char cmd[5];
1942 cmd[0] = 0xae;
1943 cmd[1] = vol->channel0;
1944 cmd[2] = 0;
1945 cmd[3] = vol->channel1;
1946 cmd[4] = 0;
1948 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
1951 MODULE_LICENSE("GPL");
1952 MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_X_CDROM_MAJOR);