MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / cdrom / mcdx.c
blob01b4e9a5602e455a1e8522894be3f76905a42595
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/version.h>
60 #include <linux/module.h>
62 #include <linux/errno.h>
63 #include <linux/interrupt.h>
64 #include <linux/fs.h>
65 #include <linux/kernel.h>
66 #include <linux/cdrom.h>
67 #include <linux/ioport.h>
68 #include <linux/mm.h>
69 #include <linux/slab.h>
70 #include <linux/init.h>
71 #include <asm/io.h>
72 #include <asm/current.h>
73 #include <asm/uaccess.h>
75 #include <linux/major.h>
76 #define MAJOR_NR MITSUMI_X_CDROM_MAJOR
77 #include <linux/blkdev.h>
78 #include <linux/devfs_fs_kernel.h>
80 /* for compatible parameter passing with "insmod" */
81 #define mcdx_drive_map mcdx
82 #include "mcdx.h"
84 #ifndef HZ
85 #error HZ not defined
86 #endif
88 #define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
90 #if !MCDX_QUIET
91 #define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
92 #else
93 #define xinfo(fmt, args...) { ; }
94 #endif
96 #if MCDX_DEBUG
97 #define xtrace(lvl, fmt, args...) \
98 { if (lvl > 0) \
99 { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
100 #define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
101 #else
102 #define xtrace(lvl, fmt, args...) { ; }
103 #define xdebug(fmt, args...) { ; }
104 #endif
106 /* CONSTANTS *******************************************************/
108 /* Following are the number of sectors we _request_ from the drive
109 every time an access outside the already requested range is done.
110 The _direct_ size is the number of sectors we're allowed to skip
111 directly (performing a read instead of requesting the new sector
112 needed */
113 const int REQUEST_SIZE = 800; /* should be less then 255 * 4 */
114 const int DIRECT_SIZE = 400; /* should be less then REQUEST_SIZE */
116 enum drivemodes { TOC, DATA, RAW, COOKED };
117 enum datamodes { MODE0, MODE1, MODE2 };
118 enum resetmodes { SOFT, HARD };
120 const int SINGLE = 0x01; /* single speed drive (FX001S, LU) */
121 const int DOUBLE = 0x02; /* double speed drive (FX001D, ..? */
122 const int DOOR = 0x04; /* door locking capability */
123 const int MULTI = 0x08; /* multi session capability */
125 const unsigned char READ1X = 0xc0;
126 const unsigned char READ2X = 0xc1;
129 /* DECLARATIONS ****************************************************/
130 struct s_subqcode {
131 unsigned char control;
132 unsigned char tno;
133 unsigned char index;
134 struct cdrom_msf0 tt;
135 struct cdrom_msf0 dt;
138 struct s_diskinfo {
139 unsigned int n_first;
140 unsigned int n_last;
141 struct cdrom_msf0 msf_leadout;
142 struct cdrom_msf0 msf_first;
145 struct s_multi {
146 unsigned char multi;
147 struct cdrom_msf0 msf_last;
150 struct s_version {
151 unsigned char code;
152 unsigned char ver;
155 /* Per drive/controller stuff **************************************/
157 struct s_drive_stuff {
158 /* waitqueues */
159 wait_queue_head_t busyq;
160 wait_queue_head_t lockq;
161 wait_queue_head_t sleepq;
163 /* flags */
164 volatile int introk; /* status of last irq operation */
165 volatile int busy; /* drive performs an operation */
166 volatile int lock; /* exclusive usage */
168 /* cd infos */
169 struct s_diskinfo di;
170 struct s_multi multi;
171 struct s_subqcode *toc; /* first entry of the toc array */
172 struct s_subqcode start;
173 struct s_subqcode stop;
174 int xa; /* 1 if xa disk */
175 int audio; /* 1 if audio disk */
176 int audiostatus;
178 /* `buffer' control */
179 volatile int valid; /* pending, ..., values are valid */
180 volatile int pending; /* next sector to be read */
181 volatile int low_border; /* first sector not to be skipped direct */
182 volatile int high_border; /* first sector `out of area' */
183 #ifdef AK2
184 volatile int int_err;
185 #endif /* AK2 */
187 /* adds and odds */
188 unsigned wreg_data; /* w data */
189 unsigned wreg_reset; /* w hardware reset */
190 unsigned wreg_hcon; /* w hardware conf */
191 unsigned wreg_chn; /* w channel */
192 unsigned rreg_data; /* r data */
193 unsigned rreg_status; /* r status */
195 int irq; /* irq used by this drive */
196 int present; /* drive present and its capabilities */
197 unsigned char readcmd; /* read cmd depends on single/double speed */
198 unsigned char playcmd; /* play should always be single speed */
199 unsigned int xxx; /* set if changed, reset while open */
200 unsigned int yyy; /* set if changed, reset by media_changed */
201 int users; /* keeps track of open/close */
202 int lastsector; /* last block accessible */
203 int status; /* last operation's error / status */
204 int readerrs; /* # of blocks read w/o error */
205 struct cdrom_device_info info;
206 struct gendisk *disk;
210 /* Prototypes ******************************************************/
212 /* The following prototypes are already declared elsewhere. They are
213 repeated here to show what's going on. And to sense, if they're
214 changed elsewhere. */
216 /* declared in blk.h */
217 int mcdx_init(void);
218 void do_mcdx_request(request_queue_t * q);
220 static int mcdx_block_open(struct inode *inode, struct file *file)
222 struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
223 return cdrom_open(&p->info, inode, file);
226 static int mcdx_block_release(struct inode *inode, struct file *file)
228 struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
229 return cdrom_release(&p->info, file);
232 static int mcdx_block_ioctl(struct inode *inode, struct file *file,
233 unsigned cmd, unsigned long arg)
235 struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
236 return cdrom_ioctl(file, &p->info, inode, cmd, arg);
239 static int mcdx_block_media_changed(struct gendisk *disk)
241 struct s_drive_stuff *p = disk->private_data;
242 return cdrom_media_changed(&p->info);
245 static struct block_device_operations mcdx_bdops =
247 .owner = THIS_MODULE,
248 .open = mcdx_block_open,
249 .release = mcdx_block_release,
250 .ioctl = mcdx_block_ioctl,
251 .media_changed = mcdx_block_media_changed,
255 /* Indirect exported functions. These functions are exported by their
256 addresses, such as mcdx_open and mcdx_close in the
257 structure mcdx_dops. */
259 /* exported by file_ops */
260 static int mcdx_open(struct cdrom_device_info *cdi, int purpose);
261 static void mcdx_close(struct cdrom_device_info *cdi);
262 static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr);
263 static int mcdx_tray_move(struct cdrom_device_info *cdi, int position);
264 static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock);
265 static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
266 unsigned int cmd, void *arg);
268 /* misc internal support functions */
269 static void log2msf(unsigned int, struct cdrom_msf0 *);
270 static unsigned int msf2log(const struct cdrom_msf0 *);
271 static unsigned int uint2bcd(unsigned int);
272 static unsigned int bcd2uint(unsigned char);
273 static unsigned port(int *);
274 static int irq(int *);
275 static void mcdx_delay(struct s_drive_stuff *, long jifs);
276 static int mcdx_transfer(struct s_drive_stuff *, char *buf, int sector,
277 int nr_sectors);
278 static int mcdx_xfer(struct s_drive_stuff *, char *buf, int sector,
279 int nr_sectors);
281 static int mcdx_config(struct s_drive_stuff *, int);
282 static int mcdx_requestversion(struct s_drive_stuff *, struct s_version *,
283 int);
284 static int mcdx_stop(struct s_drive_stuff *, int);
285 static int mcdx_hold(struct s_drive_stuff *, int);
286 static int mcdx_reset(struct s_drive_stuff *, enum resetmodes, int);
287 static int mcdx_setdrivemode(struct s_drive_stuff *, enum drivemodes, int);
288 static int mcdx_setdatamode(struct s_drive_stuff *, enum datamodes, int);
289 static int mcdx_requestsubqcode(struct s_drive_stuff *,
290 struct s_subqcode *, int);
291 static int mcdx_requestmultidiskinfo(struct s_drive_stuff *,
292 struct s_multi *, int);
293 static int mcdx_requesttocdata(struct s_drive_stuff *, struct s_diskinfo *,
294 int);
295 static int mcdx_getstatus(struct s_drive_stuff *, int);
296 static int mcdx_getval(struct s_drive_stuff *, int to, int delay, char *);
297 static int mcdx_talk(struct s_drive_stuff *,
298 const unsigned char *cmd, size_t,
299 void *buffer, size_t size, unsigned int timeout, int);
300 static int mcdx_readtoc(struct s_drive_stuff *);
301 static int mcdx_playtrk(struct s_drive_stuff *, const struct cdrom_ti *);
302 static int mcdx_playmsf(struct s_drive_stuff *, const struct cdrom_msf *);
303 static int mcdx_setattentuator(struct s_drive_stuff *,
304 struct cdrom_volctrl *, int);
306 /* static variables ************************************************/
308 static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
309 static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES];
310 static spinlock_t mcdx_lock = SPIN_LOCK_UNLOCKED;
311 static struct request_queue *mcdx_queue;
312 MODULE_PARM(mcdx, "1-4i");
314 static struct cdrom_device_ops mcdx_dops = {
315 .open = mcdx_open,
316 .release = mcdx_close,
317 .media_changed = mcdx_media_changed,
318 .tray_move = mcdx_tray_move,
319 .lock_door = mcdx_lockdoor,
320 .audio_ioctl = mcdx_audio_ioctl,
321 .capability = CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED |
322 CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
325 /* KERNEL INTERFACE FUNCTIONS **************************************/
328 static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
329 unsigned int cmd, void *arg)
331 struct s_drive_stuff *stuffp = cdi->handle;
333 if (!stuffp->present)
334 return -ENXIO;
336 if (stuffp->xxx) {
337 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
338 stuffp->lastsector = -1;
339 } else {
340 stuffp->lastsector = (CD_FRAMESIZE / 512)
341 * msf2log(&stuffp->di.msf_leadout) - 1;
344 if (stuffp->toc) {
345 kfree(stuffp->toc);
346 stuffp->toc = NULL;
347 if (-1 == mcdx_readtoc(stuffp))
348 return -1;
351 stuffp->xxx = 0;
354 switch (cmd) {
355 case CDROMSTART:{
356 xtrace(IOCTL, "ioctl() START\n");
357 /* Spin up the drive. Don't think we can do this.
358 * For now, ignore it.
360 return 0;
363 case CDROMSTOP:{
364 xtrace(IOCTL, "ioctl() STOP\n");
365 stuffp->audiostatus = CDROM_AUDIO_INVALID;
366 if (-1 == mcdx_stop(stuffp, 1))
367 return -EIO;
368 return 0;
371 case CDROMPLAYTRKIND:{
372 struct cdrom_ti *ti = (struct cdrom_ti *) arg;
374 xtrace(IOCTL, "ioctl() PLAYTRKIND\n");
375 if ((ti->cdti_trk0 < stuffp->di.n_first)
376 || (ti->cdti_trk0 > stuffp->di.n_last)
377 || (ti->cdti_trk1 < stuffp->di.n_first))
378 return -EINVAL;
379 if (ti->cdti_trk1 > stuffp->di.n_last)
380 ti->cdti_trk1 = stuffp->di.n_last;
381 xtrace(PLAYTRK, "ioctl() track %d to %d\n",
382 ti->cdti_trk0, ti->cdti_trk1);
383 return mcdx_playtrk(stuffp, ti);
386 case CDROMPLAYMSF:{
387 struct cdrom_msf *msf = (struct cdrom_msf *) arg;
389 xtrace(IOCTL, "ioctl() PLAYMSF\n");
391 if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
392 && (-1 == mcdx_hold(stuffp, 1)))
393 return -EIO;
395 msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0);
396 msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0);
397 msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0);
399 msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1);
400 msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1);
401 msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1);
403 stuffp->stop.dt.minute = msf->cdmsf_min1;
404 stuffp->stop.dt.second = msf->cdmsf_sec1;
405 stuffp->stop.dt.frame = msf->cdmsf_frame1;
407 return mcdx_playmsf(stuffp, msf);
410 case CDROMRESUME:{
411 xtrace(IOCTL, "ioctl() RESUME\n");
412 return mcdx_playtrk(stuffp, NULL);
415 case CDROMREADTOCENTRY:{
416 struct cdrom_tocentry *entry =
417 (struct cdrom_tocentry *) arg;
418 struct s_subqcode *tp = NULL;
419 xtrace(IOCTL, "ioctl() READTOCENTRY\n");
421 if (-1 == mcdx_readtoc(stuffp))
422 return -1;
423 if (entry->cdte_track == CDROM_LEADOUT)
424 tp = &stuffp->toc[stuffp->di.n_last -
425 stuffp->di.n_first + 1];
426 else if (entry->cdte_track > stuffp->di.n_last
427 || entry->cdte_track < stuffp->di.n_first)
428 return -EINVAL;
429 else
430 tp = &stuffp->toc[entry->cdte_track -
431 stuffp->di.n_first];
433 if (NULL == tp)
434 return -EIO;
435 entry->cdte_adr = tp->control;
436 entry->cdte_ctrl = tp->control >> 4;
437 /* Always return stuff in MSF, and let the Uniform cdrom driver
438 worry about what the user actually wants */
439 entry->cdte_addr.msf.minute =
440 bcd2uint(tp->dt.minute);
441 entry->cdte_addr.msf.second =
442 bcd2uint(tp->dt.second);
443 entry->cdte_addr.msf.frame =
444 bcd2uint(tp->dt.frame);
445 return 0;
448 case CDROMSUBCHNL:{
449 struct cdrom_subchnl *sub =
450 (struct cdrom_subchnl *) arg;
451 struct s_subqcode q;
453 xtrace(IOCTL, "ioctl() SUBCHNL\n");
455 if (-1 == mcdx_requestsubqcode(stuffp, &q, 2))
456 return -EIO;
458 xtrace(SUBCHNL, "audiostatus: %x\n",
459 stuffp->audiostatus);
460 sub->cdsc_audiostatus = stuffp->audiostatus;
461 sub->cdsc_adr = q.control;
462 sub->cdsc_ctrl = q.control >> 4;
463 sub->cdsc_trk = bcd2uint(q.tno);
464 sub->cdsc_ind = bcd2uint(q.index);
466 xtrace(SUBCHNL, "trk %d, ind %d\n",
467 sub->cdsc_trk, sub->cdsc_ind);
468 /* Always return stuff in MSF, and let the Uniform cdrom driver
469 worry about what the user actually wants */
470 sub->cdsc_absaddr.msf.minute =
471 bcd2uint(q.dt.minute);
472 sub->cdsc_absaddr.msf.second =
473 bcd2uint(q.dt.second);
474 sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
475 sub->cdsc_reladdr.msf.minute =
476 bcd2uint(q.tt.minute);
477 sub->cdsc_reladdr.msf.second =
478 bcd2uint(q.tt.second);
479 sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
480 xtrace(SUBCHNL,
481 "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
482 sub->cdsc_absaddr.msf.minute,
483 sub->cdsc_absaddr.msf.second,
484 sub->cdsc_absaddr.msf.frame,
485 sub->cdsc_reladdr.msf.minute,
486 sub->cdsc_reladdr.msf.second,
487 sub->cdsc_reladdr.msf.frame);
489 return 0;
492 case CDROMREADTOCHDR:{
493 struct cdrom_tochdr *toc =
494 (struct cdrom_tochdr *) arg;
496 xtrace(IOCTL, "ioctl() READTOCHDR\n");
497 toc->cdth_trk0 = stuffp->di.n_first;
498 toc->cdth_trk1 = stuffp->di.n_last;
499 xtrace(TOCHDR,
500 "ioctl() track0 = %d, track1 = %d\n",
501 stuffp->di.n_first, stuffp->di.n_last);
502 return 0;
505 case CDROMPAUSE:{
506 xtrace(IOCTL, "ioctl() PAUSE\n");
507 if (stuffp->audiostatus != CDROM_AUDIO_PLAY)
508 return -EINVAL;
509 if (-1 == mcdx_stop(stuffp, 1))
510 return -EIO;
511 stuffp->audiostatus = CDROM_AUDIO_PAUSED;
512 if (-1 ==
513 mcdx_requestsubqcode(stuffp, &stuffp->start,
515 return -EIO;
516 return 0;
519 case CDROMMULTISESSION:{
520 struct cdrom_multisession *ms =
521 (struct cdrom_multisession *) arg;
522 xtrace(IOCTL, "ioctl() MULTISESSION\n");
523 /* Always return stuff in LBA, and let the Uniform cdrom driver
524 worry about what the user actually wants */
525 ms->addr.lba = msf2log(&stuffp->multi.msf_last);
526 ms->xa_flag = !!stuffp->multi.multi;
527 xtrace(MS,
528 "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
529 ms->xa_flag, ms->addr.lba,
530 stuffp->multi.msf_last.minute,
531 stuffp->multi.msf_last.second,
532 stuffp->multi.msf_last.frame);
534 return 0;
537 case CDROMEJECT:{
538 xtrace(IOCTL, "ioctl() EJECT\n");
539 if (stuffp->users > 1)
540 return -EBUSY;
541 return (mcdx_tray_move(cdi, 1));
544 case CDROMCLOSETRAY:{
545 xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n");
546 return (mcdx_tray_move(cdi, 0));
549 case CDROMVOLCTRL:{
550 struct cdrom_volctrl *volctrl =
551 (struct cdrom_volctrl *) arg;
552 xtrace(IOCTL, "ioctl() VOLCTRL\n");
554 #if 0 /* not tested! */
555 /* adjust for the weirdness of workman (md) */
556 /* can't test it (hs) */
557 volctrl.channel2 = volctrl.channel1;
558 volctrl.channel1 = volctrl.channel3 = 0x00;
559 #endif
560 return mcdx_setattentuator(stuffp, volctrl, 2);
563 default:
564 return -EINVAL;
568 void do_mcdx_request(request_queue_t * q)
570 struct s_drive_stuff *stuffp;
571 struct request *req;
573 again:
575 req = elv_next_request(q);
576 if (!req)
577 return;
579 stuffp = req->rq_disk->private_data;
581 if (!stuffp->present) {
582 xwarn("do_request(): bad device: %s\n",req->rq_disk->disk_name);
583 xtrace(REQUEST, "end_request(0): bad device\n");
584 end_request(req, 0);
585 return;
588 if (stuffp->audio) {
589 xwarn("do_request() attempt to read from audio cd\n");
590 xtrace(REQUEST, "end_request(0): read from audio\n");
591 end_request(req, 0);
592 return;
595 xtrace(REQUEST, "do_request() (%lu + %lu)\n",
596 req->sector, req->nr_sectors);
598 if (req->cmd != READ) {
599 xwarn("do_request(): non-read command to cd!!\n");
600 xtrace(REQUEST, "end_request(0): write\n");
601 end_request(req, 0);
602 return;
604 else {
605 stuffp->status = 0;
606 while (req->nr_sectors) {
607 int i;
609 i = mcdx_transfer(stuffp,
610 req->buffer,
611 req->sector,
612 req->nr_sectors);
614 if (i == -1) {
615 end_request(req, 0);
616 goto again;
618 req->sector += i;
619 req->nr_sectors -= i;
620 req->buffer += (i * 512);
622 end_request(req, 1);
623 goto again;
625 xtrace(REQUEST, "end_request(1)\n");
626 end_request(req, 1);
629 goto again;
632 static int mcdx_open(struct cdrom_device_info *cdi, int purpose)
634 struct s_drive_stuff *stuffp;
635 xtrace(OPENCLOSE, "open()\n");
636 stuffp = cdi->handle;
637 if (!stuffp->present)
638 return -ENXIO;
640 /* Make the modules looking used ... (thanx bjorn).
641 * But we shouldn't forget to decrement the module counter
642 * on error return */
644 /* this is only done to test if the drive talks with us */
645 if (-1 == mcdx_getstatus(stuffp, 1))
646 return -EIO;
648 if (stuffp->xxx) {
650 xtrace(OPENCLOSE, "open() media changed\n");
651 stuffp->audiostatus = CDROM_AUDIO_INVALID;
652 stuffp->readcmd = 0;
653 xtrace(OPENCLOSE, "open() Request multisession info\n");
654 if (-1 ==
655 mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6))
656 xinfo("No multidiskinfo\n");
657 } else {
658 /* multisession ? */
659 if (!stuffp->multi.multi)
660 stuffp->multi.msf_last.second = 2;
662 xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
663 stuffp->multi.multi,
664 stuffp->multi.msf_last.minute,
665 stuffp->multi.msf_last.second,
666 stuffp->multi.msf_last.frame);
669 } /* got multisession information */
670 /* request the disks table of contents (aka diskinfo) */
671 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
673 stuffp->lastsector = -1;
675 } else {
677 stuffp->lastsector = (CD_FRAMESIZE / 512)
678 * msf2log(&stuffp->di.msf_leadout) - 1;
680 xtrace(OPENCLOSE,
681 "open() start %d (%02x:%02x.%02x) %d\n",
682 stuffp->di.n_first,
683 stuffp->di.msf_first.minute,
684 stuffp->di.msf_first.second,
685 stuffp->di.msf_first.frame,
686 msf2log(&stuffp->di.msf_first));
687 xtrace(OPENCLOSE,
688 "open() last %d (%02x:%02x.%02x) %d\n",
689 stuffp->di.n_last,
690 stuffp->di.msf_leadout.minute,
691 stuffp->di.msf_leadout.second,
692 stuffp->di.msf_leadout.frame,
693 msf2log(&stuffp->di.msf_leadout));
696 if (stuffp->toc) {
697 xtrace(MALLOC, "open() free old toc @ %p\n",
698 stuffp->toc);
699 kfree(stuffp->toc);
701 stuffp->toc = NULL;
704 xtrace(OPENCLOSE, "open() init irq generation\n");
705 if (-1 == mcdx_config(stuffp, 1))
706 return -EIO;
707 #if FALLBACK
708 /* Set the read speed */
709 xwarn("AAA %x AAA\n", stuffp->readcmd);
710 if (stuffp->readerrs)
711 stuffp->readcmd = READ1X;
712 else
713 stuffp->readcmd =
714 stuffp->present | SINGLE ? READ1X : READ2X;
715 xwarn("XXX %x XXX\n", stuffp->readcmd);
716 #else
717 stuffp->readcmd =
718 stuffp->present | SINGLE ? READ1X : READ2X;
719 #endif
721 /* try to get the first sector, iff any ... */
722 if (stuffp->lastsector >= 0) {
723 char buf[512];
724 int ans;
725 int tries;
727 stuffp->xa = 0;
728 stuffp->audio = 0;
730 for (tries = 6; tries; tries--) {
732 stuffp->introk = 1;
734 xtrace(OPENCLOSE, "open() try as %s\n",
735 stuffp->xa ? "XA" : "normal");
736 /* set data mode */
737 if (-1 == (ans = mcdx_setdatamode(stuffp,
738 stuffp->
739 xa ?
740 MODE2 :
741 MODE1,
742 1))) {
743 /* return -EIO; */
744 stuffp->xa = 0;
745 break;
748 if ((stuffp->audio = e_audio(ans)))
749 break;
751 while (0 ==
752 (ans =
753 mcdx_transfer(stuffp, buf, 0, 1)));
755 if (ans == 1)
756 break;
757 stuffp->xa = !stuffp->xa;
760 /* xa disks will be read in raw mode, others not */
761 if (-1 == mcdx_setdrivemode(stuffp,
762 stuffp->xa ? RAW : COOKED,
764 return -EIO;
765 if (stuffp->audio) {
766 xinfo("open() audio disk found\n");
767 } else if (stuffp->lastsector >= 0) {
768 xinfo("open() %s%s disk found\n",
769 stuffp->xa ? "XA / " : "",
770 stuffp->multi.
771 multi ? "Multi Session" : "Single Session");
774 stuffp->xxx = 0;
775 stuffp->users++;
776 return 0;
779 static void mcdx_close(struct cdrom_device_info *cdi)
781 struct s_drive_stuff *stuffp;
783 xtrace(OPENCLOSE, "close()\n");
785 stuffp = cdi->handle;
787 --stuffp->users;
790 static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr)
791 /* Return: 1 if media changed since last call to this function
792 0 otherwise */
794 struct s_drive_stuff *stuffp;
796 xinfo("mcdx_media_changed called for device %s\n", cdi->name);
798 stuffp = cdi->handle;
799 mcdx_getstatus(stuffp, 1);
801 if (stuffp->yyy == 0)
802 return 0;
804 stuffp->yyy = 0;
805 return 1;
808 #ifndef MODULE
809 static int __init mcdx_setup(char *str)
811 int pi[4];
812 (void) get_options(str, ARRAY_SIZE(pi), pi);
814 if (pi[0] > 0)
815 mcdx_drive_map[0][0] = pi[1];
816 if (pi[0] > 1)
817 mcdx_drive_map[0][1] = pi[2];
818 return 1;
821 __setup("mcdx=", mcdx_setup);
823 #endif
825 /* DIRTY PART ******************************************************/
827 static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
828 /* This routine is used for sleeping.
829 * A jifs value <0 means NO sleeping,
830 * =0 means minimal sleeping (let the kernel
831 * run for other processes)
832 * >0 means at least sleep for that amount.
833 * May be we could use a simple count loop w/ jumps to itself, but
834 * I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
836 if (jifs < 0)
837 return;
839 xtrace(SLEEP, "*** delay: sleepq\n");
840 interruptible_sleep_on_timeout(&stuff->sleepq, jifs);
841 xtrace(SLEEP, "delay awoken\n");
842 if (signal_pending(current)) {
843 xtrace(SLEEP, "got signal\n");
847 static irqreturn_t mcdx_intr(int irq, void *dev_id, struct pt_regs *regs)
849 struct s_drive_stuff *stuffp = dev_id;
850 unsigned char b;
852 if (stuffp == NULL) {
853 xwarn("mcdx: no device for intr %d\n", irq);
854 return IRQ_NONE;
856 #ifdef AK2
857 if (!stuffp->busy && stuffp->pending)
858 stuffp->int_err = 1;
860 #endif /* AK2 */
861 /* get the interrupt status */
862 b = inb(stuffp->rreg_status);
863 stuffp->introk = ~b & MCDX_RBIT_DTEN;
865 /* NOTE: We only should get interrupts if the data we
866 * requested are ready to transfer.
867 * But the drive seems to generate ``asynchronous'' interrupts
868 * on several error conditions too. (Despite the err int enable
869 * setting during initialisation) */
871 /* if not ok, read the next byte as the drives status */
872 if (!stuffp->introk) {
873 xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b);
874 if (~b & MCDX_RBIT_STEN) {
875 xinfo("intr() irq %d status 0x%02x\n",
876 irq, inb(stuffp->rreg_data));
877 } else {
878 xinfo("intr() irq %d ambiguous hw status\n", irq);
880 } else {
881 xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b);
884 stuffp->busy = 0;
885 wake_up_interruptible(&stuffp->busyq);
886 return IRQ_HANDLED;
890 static int mcdx_talk(struct s_drive_stuff *stuffp,
891 const unsigned char *cmd, size_t cmdlen,
892 void *buffer, size_t size, unsigned int timeout, int tries)
893 /* Send a command to the drive, wait for the result.
894 * returns -1 on timeout, drive status otherwise
895 * If buffer is not zero, the result (length size) is stored there.
896 * If buffer is zero the size should be the number of bytes to read
897 * from the drive. These bytes are discarded.
900 int st;
901 char c;
902 int discard;
904 /* Somebody wants the data read? */
905 if ((discard = (buffer == NULL)))
906 buffer = &c;
908 while (stuffp->lock) {
909 xtrace(SLEEP, "*** talk: lockq\n");
910 interruptible_sleep_on(&stuffp->lockq);
911 xtrace(SLEEP, "talk: awoken\n");
914 stuffp->lock = 1;
916 /* An operation other then reading data destroys the
917 * data already requested and remembered in stuffp->request, ... */
918 stuffp->valid = 0;
920 #if MCDX_DEBUG & TALK
922 unsigned char i;
923 xtrace(TALK,
924 "talk() %d / %d tries, res.size %d, command 0x%02x",
925 tries, timeout, size, (unsigned char) cmd[0]);
926 for (i = 1; i < cmdlen; i++)
927 xtrace(TALK, " 0x%02x", cmd[i]);
928 xtrace(TALK, "\n");
930 #endif
932 /* give up if all tries are done (bad) or if the status
933 * st != -1 (good) */
934 for (st = -1; st == -1 && tries; tries--) {
936 char *bp = (char *) buffer;
937 size_t sz = size;
939 outsb(stuffp->wreg_data, cmd, cmdlen);
940 xtrace(TALK, "talk() command sent\n");
942 /* get the status byte */
943 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
944 xinfo("talk() %02x timed out (status), %d tr%s left\n",
945 cmd[0], tries - 1, tries == 2 ? "y" : "ies");
946 continue;
948 st = *bp;
949 sz--;
950 if (!discard)
951 bp++;
953 xtrace(TALK, "talk() got status 0x%02x\n", st);
955 /* command error? */
956 if (e_cmderr(st)) {
957 xwarn("command error cmd = %02x %s \n",
958 cmd[0], cmdlen > 1 ? "..." : "");
959 st = -1;
960 continue;
963 /* audio status? */
964 if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
965 stuffp->audiostatus =
966 e_audiobusy(st) ? CDROM_AUDIO_PLAY :
967 CDROM_AUDIO_NO_STATUS;
968 else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
969 && e_audiobusy(st) == 0)
970 stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
972 /* media change? */
973 if (e_changed(st)) {
974 xinfo("talk() media changed\n");
975 stuffp->xxx = stuffp->yyy = 1;
978 /* now actually get the data */
979 while (sz--) {
980 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
981 xinfo("talk() %02x timed out (data), %d tr%s left\n",
982 cmd[0], tries - 1,
983 tries == 2 ? "y" : "ies");
984 st = -1;
985 break;
987 if (!discard)
988 bp++;
989 xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));
993 #if !MCDX_QUIET
994 if (!tries && st == -1)
995 xinfo("talk() giving up\n");
996 #endif
998 stuffp->lock = 0;
999 wake_up_interruptible(&stuffp->lockq);
1001 xtrace(TALK, "talk() done with 0x%02x\n", st);
1002 return st;
1005 /* MODULE STUFF ***********************************************************/
1007 int __mcdx_init(void)
1009 int i;
1010 int drives = 0;
1012 mcdx_init();
1013 for (i = 0; i < MCDX_NDRIVES; i++) {
1014 if (mcdx_stuffp[i]) {
1015 xtrace(INIT, "init_module() drive %d stuff @ %p\n",
1016 i, mcdx_stuffp[i]);
1017 drives++;
1021 if (!drives)
1022 return -EIO;
1024 return 0;
1027 void __exit mcdx_exit(void)
1029 int i;
1031 xinfo("cleanup_module called\n");
1033 for (i = 0; i < MCDX_NDRIVES; i++) {
1034 struct s_drive_stuff *stuffp = mcdx_stuffp[i];
1035 if (!stuffp)
1036 continue;
1037 del_gendisk(stuffp->disk);
1038 if (unregister_cdrom(&stuffp->info)) {
1039 printk(KERN_WARNING "Can't unregister cdrom mcdx\n");
1040 continue;
1042 put_disk(stuffp->disk);
1043 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1044 free_irq(stuffp->irq, NULL);
1045 if (stuffp->toc) {
1046 xtrace(MALLOC, "cleanup_module() free toc @ %p\n",
1047 stuffp->toc);
1048 kfree(stuffp->toc);
1050 xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n",
1051 stuffp);
1052 mcdx_stuffp[i] = NULL;
1053 kfree(stuffp);
1056 if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
1057 xwarn("cleanup() unregister_blkdev() failed\n");
1059 blk_cleanup_queue(mcdx_queue);
1060 #if !MCDX_QUIET
1061 else
1062 xinfo("cleanup() succeeded\n");
1063 #endif
1066 #ifdef MODULE
1067 module_init(__mcdx_init);
1068 #endif
1069 module_exit(mcdx_exit);
1072 /* Support functions ************************************************/
1074 int __init mcdx_init_drive(int drive)
1076 struct s_version version;
1077 struct gendisk *disk;
1078 struct s_drive_stuff *stuffp;
1079 int size = sizeof(*stuffp);
1080 char msg[80];
1082 xtrace(INIT, "init() try drive %d\n", drive);
1084 xtrace(INIT, "kmalloc space for stuffpt's\n");
1085 xtrace(MALLOC, "init() malloc %d bytes\n", size);
1086 if (!(stuffp = kmalloc(size, GFP_KERNEL))) {
1087 xwarn("init() malloc failed\n");
1088 return 1;
1091 disk = alloc_disk(1);
1092 if (!disk) {
1093 xwarn("init() malloc failed\n");
1094 kfree(stuffp);
1095 return 1;
1098 xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n",
1099 sizeof(*stuffp), stuffp);
1101 /* set default values */
1102 memset(stuffp, 0, sizeof(*stuffp));
1104 stuffp->present = 0; /* this should be 0 already */
1105 stuffp->toc = NULL; /* this should be NULL already */
1107 /* setup our irq and i/o addresses */
1108 stuffp->irq = irq(mcdx_drive_map[drive]);
1109 stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]);
1110 stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
1111 stuffp->wreg_hcon = stuffp->wreg_reset + 1;
1112 stuffp->wreg_chn = stuffp->wreg_hcon + 1;
1114 init_waitqueue_head(&stuffp->busyq);
1115 init_waitqueue_head(&stuffp->lockq);
1116 init_waitqueue_head(&stuffp->sleepq);
1118 /* check if i/o addresses are available */
1119 if (!request_region(stuffp->wreg_data, MCDX_IO_SIZE, "mcdx")) {
1120 xwarn("0x%03x,%d: Init failed. "
1121 "I/O ports (0x%03x..0x%03x) already in use.\n",
1122 stuffp->wreg_data, stuffp->irq,
1123 stuffp->wreg_data,
1124 stuffp->wreg_data + MCDX_IO_SIZE - 1);
1125 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1126 kfree(stuffp);
1127 put_disk(disk);
1128 xtrace(INIT, "init() continue at next drive\n");
1129 return 0; /* next drive */
1132 xtrace(INIT, "init() i/o port is available at 0x%03x\n"
1133 stuffp->wreg_data);
1134 xtrace(INIT, "init() hardware reset\n");
1135 mcdx_reset(stuffp, HARD, 1);
1137 xtrace(INIT, "init() get version\n");
1138 if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
1139 /* failed, next drive */
1140 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1141 xwarn("%s=0x%03x,%d: Init failed. Can't get version.\n",
1142 MCDX, stuffp->wreg_data, stuffp->irq);
1143 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1144 kfree(stuffp);
1145 put_disk(disk);
1146 xtrace(INIT, "init() continue at next drive\n");
1147 return 0;
1150 switch (version.code) {
1151 case 'D':
1152 stuffp->readcmd = READ2X;
1153 stuffp->present = DOUBLE | DOOR | MULTI;
1154 break;
1155 case 'F':
1156 stuffp->readcmd = READ1X;
1157 stuffp->present = SINGLE | DOOR | MULTI;
1158 break;
1159 case 'M':
1160 stuffp->readcmd = READ1X;
1161 stuffp->present = SINGLE;
1162 break;
1163 default:
1164 stuffp->present = 0;
1165 break;
1168 stuffp->playcmd = READ1X;
1170 if (!stuffp->present) {
1171 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1172 xwarn("%s=0x%03x,%d: Init failed. No Mitsumi CD-ROM?.\n",
1173 MCDX, stuffp->wreg_data, stuffp->irq);
1174 kfree(stuffp);
1175 put_disk(disk);
1176 return 0; /* next drive */
1179 xtrace(INIT, "init() register blkdev\n");
1180 if (register_blkdev(MAJOR_NR, "mcdx")) {
1181 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1182 kfree(stuffp);
1183 put_disk(disk);
1184 return 1;
1187 mcdx_queue = blk_init_queue(do_mcdx_request, &mcdx_lock);
1188 if (!mcdx_queue) {
1189 unregister_blkdev(MAJOR_NR, "mcdx");
1190 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1191 kfree(stuffp);
1192 put_disk(disk);
1193 return 1;
1196 xtrace(INIT, "init() subscribe irq and i/o\n");
1197 if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, "mcdx", stuffp)) {
1198 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1199 xwarn("%s=0x%03x,%d: Init failed. Can't get irq (%d).\n",
1200 MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq);
1201 stuffp->irq = 0;
1202 blk_cleanup_queue(mcdx_queue);
1203 kfree(stuffp);
1204 put_disk(disk);
1205 return 0;
1208 xtrace(INIT, "init() get garbage\n");
1210 int i;
1211 mcdx_delay(stuffp, HZ / 2);
1212 for (i = 100; i; i--)
1213 (void) inb(stuffp->rreg_status);
1217 #if WE_KNOW_WHY
1218 /* irq 11 -> channel register */
1219 outb(0x50, stuffp->wreg_chn);
1220 #endif
1222 xtrace(INIT, "init() set non dma but irq mode\n");
1223 mcdx_config(stuffp, 1);
1225 stuffp->info.ops = &mcdx_dops;
1226 stuffp->info.speed = 2;
1227 stuffp->info.capacity = 1;
1228 stuffp->info.handle = stuffp;
1229 sprintf(stuffp->info.name, "mcdx%d", drive);
1230 disk->major = MAJOR_NR;
1231 disk->first_minor = drive;
1232 strcpy(disk->disk_name, stuffp->info.name);
1233 disk->fops = &mcdx_bdops;
1234 disk->flags = GENHD_FL_CD;
1235 stuffp->disk = disk;
1237 sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%03x, irq %d."
1238 " (Firmware version %c %x)\n",
1239 stuffp->wreg_data, stuffp->irq, version.code, version.ver);
1240 mcdx_stuffp[drive] = stuffp;
1241 xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp);
1242 if (register_cdrom(&stuffp->info) != 0) {
1243 printk("Cannot register Mitsumi CD-ROM!\n");
1244 free_irq(stuffp->irq, NULL);
1245 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1246 kfree(stuffp);
1247 put_disk(disk);
1248 if (unregister_blkdev(MAJOR_NR, "mcdx") != 0)
1249 xwarn("cleanup() unregister_blkdev() failed\n");
1250 blk_cleanup_queue(mcdx_queue);
1251 return 2;
1253 disk->private_data = stuffp;
1254 disk->queue = mcdx_queue;
1255 add_disk(disk);
1256 printk(msg);
1257 return 0;
1260 int __init mcdx_init(void)
1262 int drive;
1263 #ifdef MODULE
1264 xwarn("Version 2.14(hs) for " UTS_RELEASE "\n");
1265 #else
1266 xwarn("Version 2.14(hs) \n");
1267 #endif
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);