blob: f574962f4288d36233491eb0d98f8968e2d0da2b [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * The Mitsumi CDROM interface
3 * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de>
4 * VERSION: 2.14(hs)
5 *
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 ...)
9 *
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 *************************************************************
17 *
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.
22 *
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.
27 *
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.
31 *
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?
46 *
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>
51 */
52
53
Olaf Hering44456d32005-07-27 11:45:17 -070054#ifdef RCS
Linus Torvalds1da177e2005-04-16 15:20:36 -070055static const char *mcdx_c_version
56 = "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $";
57#endif
58
59#include <linux/module.h>
60
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>
73
74#include <linux/major.h>
75#define MAJOR_NR MITSUMI_X_CDROM_MAJOR
76#include <linux/blkdev.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78#include "mcdx.h"
79
80#ifndef HZ
81#error HZ not defined
82#endif
83
84#define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)
85
86#if !MCDX_QUIET
87#define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)
88#else
89#define xinfo(fmt, args...) { ; }
90#endif
91
92#if MCDX_DEBUG
93#define xtrace(lvl, fmt, args...) \
94 { if (lvl > 0) \
95 { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }
96#define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)
97#else
98#define xtrace(lvl, fmt, args...) { ; }
99#define xdebug(fmt, args...) { ; }
100#endif
101
102/* CONSTANTS *******************************************************/
103
104/* Following are the number of sectors we _request_ from the drive
105 every time an access outside the already requested range is done.
106 The _direct_ size is the number of sectors we're allowed to skip
107 directly (performing a read instead of requesting the new sector
108 needed */
Adrian Bunk75c96f82005-05-05 16:16:09 -0700109static const int REQUEST_SIZE = 800; /* should be less then 255 * 4 */
110static const int DIRECT_SIZE = 400; /* should be less then REQUEST_SIZE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
112enum drivemodes { TOC, DATA, RAW, COOKED };
113enum datamodes { MODE0, MODE1, MODE2 };
114enum resetmodes { SOFT, HARD };
115
Adrian Bunk75c96f82005-05-05 16:16:09 -0700116static const int SINGLE = 0x01; /* single speed drive (FX001S, LU) */
117static const int DOUBLE = 0x02; /* double speed drive (FX001D, ..? */
118static const int DOOR = 0x04; /* door locking capability */
119static const int MULTI = 0x08; /* multi session capability */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
Adrian Bunk75c96f82005-05-05 16:16:09 -0700121static const unsigned char READ1X = 0xc0;
122static const unsigned char READ2X = 0xc1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123
124
125/* DECLARATIONS ****************************************************/
126struct s_subqcode {
127 unsigned char control;
128 unsigned char tno;
129 unsigned char index;
130 struct cdrom_msf0 tt;
131 struct cdrom_msf0 dt;
132};
133
134struct s_diskinfo {
135 unsigned int n_first;
136 unsigned int n_last;
137 struct cdrom_msf0 msf_leadout;
138 struct cdrom_msf0 msf_first;
139};
140
141struct s_multi {
142 unsigned char multi;
143 struct cdrom_msf0 msf_last;
144};
145
146struct s_version {
147 unsigned char code;
148 unsigned char ver;
149};
150
151/* Per drive/controller stuff **************************************/
152
153struct s_drive_stuff {
154 /* waitqueues */
155 wait_queue_head_t busyq;
156 wait_queue_head_t lockq;
157 wait_queue_head_t sleepq;
158
159 /* flags */
160 volatile int introk; /* status of last irq operation */
161 volatile int busy; /* drive performs an operation */
162 volatile int lock; /* exclusive usage */
163
164 /* cd infos */
165 struct s_diskinfo di;
166 struct s_multi multi;
167 struct s_subqcode *toc; /* first entry of the toc array */
168 struct s_subqcode start;
169 struct s_subqcode stop;
170 int xa; /* 1 if xa disk */
171 int audio; /* 1 if audio disk */
172 int audiostatus;
173
174 /* `buffer' control */
175 volatile int valid; /* pending, ..., values are valid */
176 volatile int pending; /* next sector to be read */
177 volatile int low_border; /* first sector not to be skipped direct */
178 volatile int high_border; /* first sector `out of area' */
179#ifdef AK2
180 volatile int int_err;
181#endif /* AK2 */
182
183 /* adds and odds */
184 unsigned wreg_data; /* w data */
185 unsigned wreg_reset; /* w hardware reset */
186 unsigned wreg_hcon; /* w hardware conf */
187 unsigned wreg_chn; /* w channel */
188 unsigned rreg_data; /* r data */
189 unsigned rreg_status; /* r status */
190
191 int irq; /* irq used by this drive */
192 int present; /* drive present and its capabilities */
193 unsigned char readcmd; /* read cmd depends on single/double speed */
194 unsigned char playcmd; /* play should always be single speed */
195 unsigned int xxx; /* set if changed, reset while open */
196 unsigned int yyy; /* set if changed, reset by media_changed */
197 int users; /* keeps track of open/close */
198 int lastsector; /* last block accessible */
199 int status; /* last operation's error / status */
200 int readerrs; /* # of blocks read w/o error */
201 struct cdrom_device_info info;
202 struct gendisk *disk;
203};
204
205
206/* Prototypes ******************************************************/
207
208/* The following prototypes are already declared elsewhere. They are
209 repeated here to show what's going on. And to sense, if they're
210 changed elsewhere. */
211
Adrian Bunk75c96f82005-05-05 16:16:09 -0700212static int mcdx_init(void);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
214static int mcdx_block_open(struct inode *inode, struct file *file)
215{
216 struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
217 return cdrom_open(&p->info, inode, file);
218}
219
220static int mcdx_block_release(struct inode *inode, struct file *file)
221{
222 struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
223 return cdrom_release(&p->info, file);
224}
225
226static int mcdx_block_ioctl(struct inode *inode, struct file *file,
227 unsigned cmd, unsigned long arg)
228{
229 struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data;
230 return cdrom_ioctl(file, &p->info, inode, cmd, arg);
231}
232
233static int mcdx_block_media_changed(struct gendisk *disk)
234{
235 struct s_drive_stuff *p = disk->private_data;
236 return cdrom_media_changed(&p->info);
237}
238
239static struct block_device_operations mcdx_bdops =
240{
241 .owner = THIS_MODULE,
242 .open = mcdx_block_open,
243 .release = mcdx_block_release,
244 .ioctl = mcdx_block_ioctl,
245 .media_changed = mcdx_block_media_changed,
246};
247
248
249/* Indirect exported functions. These functions are exported by their
250 addresses, such as mcdx_open and mcdx_close in the
251 structure mcdx_dops. */
252
253/* exported by file_ops */
254static int mcdx_open(struct cdrom_device_info *cdi, int purpose);
255static void mcdx_close(struct cdrom_device_info *cdi);
256static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr);
257static int mcdx_tray_move(struct cdrom_device_info *cdi, int position);
258static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock);
259static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
260 unsigned int cmd, void *arg);
261
262/* misc internal support functions */
263static void log2msf(unsigned int, struct cdrom_msf0 *);
264static unsigned int msf2log(const struct cdrom_msf0 *);
265static unsigned int uint2bcd(unsigned int);
266static unsigned int bcd2uint(unsigned char);
267static unsigned port(int *);
268static int irq(int *);
269static void mcdx_delay(struct s_drive_stuff *, long jifs);
270static int mcdx_transfer(struct s_drive_stuff *, char *buf, int sector,
271 int nr_sectors);
272static int mcdx_xfer(struct s_drive_stuff *, char *buf, int sector,
273 int nr_sectors);
274
275static int mcdx_config(struct s_drive_stuff *, int);
276static int mcdx_requestversion(struct s_drive_stuff *, struct s_version *,
277 int);
278static int mcdx_stop(struct s_drive_stuff *, int);
279static int mcdx_hold(struct s_drive_stuff *, int);
280static int mcdx_reset(struct s_drive_stuff *, enum resetmodes, int);
281static int mcdx_setdrivemode(struct s_drive_stuff *, enum drivemodes, int);
282static int mcdx_setdatamode(struct s_drive_stuff *, enum datamodes, int);
283static int mcdx_requestsubqcode(struct s_drive_stuff *,
284 struct s_subqcode *, int);
285static int mcdx_requestmultidiskinfo(struct s_drive_stuff *,
286 struct s_multi *, int);
287static int mcdx_requesttocdata(struct s_drive_stuff *, struct s_diskinfo *,
288 int);
289static int mcdx_getstatus(struct s_drive_stuff *, int);
290static int mcdx_getval(struct s_drive_stuff *, int to, int delay, char *);
291static int mcdx_talk(struct s_drive_stuff *,
292 const unsigned char *cmd, size_t,
293 void *buffer, size_t size, unsigned int timeout, int);
294static int mcdx_readtoc(struct s_drive_stuff *);
295static int mcdx_playtrk(struct s_drive_stuff *, const struct cdrom_ti *);
296static int mcdx_playmsf(struct s_drive_stuff *, const struct cdrom_msf *);
297static int mcdx_setattentuator(struct s_drive_stuff *,
298 struct cdrom_volctrl *, int);
299
300/* static variables ************************************************/
301
302static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
303static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES];
304static DEFINE_SPINLOCK(mcdx_lock);
305static struct request_queue *mcdx_queue;
306
307/* You can only set the first two pairs, from old MODULE_PARM code. */
308static int mcdx_set(const char *val, struct kernel_param *kp)
309{
310 get_options((char *)val, 4, (int *)mcdx_drive_map);
311 return 0;
312}
313module_param_call(mcdx, mcdx_set, NULL, NULL, 0);
314
315static struct cdrom_device_ops mcdx_dops = {
316 .open = mcdx_open,
317 .release = mcdx_close,
318 .media_changed = mcdx_media_changed,
319 .tray_move = mcdx_tray_move,
320 .lock_door = mcdx_lockdoor,
321 .audio_ioctl = mcdx_audio_ioctl,
322 .capability = CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED |
323 CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
324};
325
326/* KERNEL INTERFACE FUNCTIONS **************************************/
327
328
329static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
330 unsigned int cmd, void *arg)
331{
332 struct s_drive_stuff *stuffp = cdi->handle;
333
334 if (!stuffp->present)
335 return -ENXIO;
336
337 if (stuffp->xxx) {
338 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
339 stuffp->lastsector = -1;
340 } else {
341 stuffp->lastsector = (CD_FRAMESIZE / 512)
342 * msf2log(&stuffp->di.msf_leadout) - 1;
343 }
344
345 if (stuffp->toc) {
346 kfree(stuffp->toc);
347 stuffp->toc = NULL;
348 if (-1 == mcdx_readtoc(stuffp))
349 return -1;
350 }
351
352 stuffp->xxx = 0;
353 }
354
355 switch (cmd) {
356 case CDROMSTART:{
357 xtrace(IOCTL, "ioctl() START\n");
358 /* Spin up the drive. Don't think we can do this.
359 * For now, ignore it.
360 */
361 return 0;
362 }
363
364 case CDROMSTOP:{
365 xtrace(IOCTL, "ioctl() STOP\n");
366 stuffp->audiostatus = CDROM_AUDIO_INVALID;
367 if (-1 == mcdx_stop(stuffp, 1))
368 return -EIO;
369 return 0;
370 }
371
372 case CDROMPLAYTRKIND:{
373 struct cdrom_ti *ti = (struct cdrom_ti *) arg;
374
375 xtrace(IOCTL, "ioctl() PLAYTRKIND\n");
376 if ((ti->cdti_trk0 < stuffp->di.n_first)
377 || (ti->cdti_trk0 > stuffp->di.n_last)
378 || (ti->cdti_trk1 < stuffp->di.n_first))
379 return -EINVAL;
380 if (ti->cdti_trk1 > stuffp->di.n_last)
381 ti->cdti_trk1 = stuffp->di.n_last;
382 xtrace(PLAYTRK, "ioctl() track %d to %d\n",
383 ti->cdti_trk0, ti->cdti_trk1);
384 return mcdx_playtrk(stuffp, ti);
385 }
386
387 case CDROMPLAYMSF:{
388 struct cdrom_msf *msf = (struct cdrom_msf *) arg;
389
390 xtrace(IOCTL, "ioctl() PLAYMSF\n");
391
392 if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
393 && (-1 == mcdx_hold(stuffp, 1)))
394 return -EIO;
395
396 msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0);
397 msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0);
398 msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0);
399
400 msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1);
401 msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1);
402 msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1);
403
404 stuffp->stop.dt.minute = msf->cdmsf_min1;
405 stuffp->stop.dt.second = msf->cdmsf_sec1;
406 stuffp->stop.dt.frame = msf->cdmsf_frame1;
407
408 return mcdx_playmsf(stuffp, msf);
409 }
410
411 case CDROMRESUME:{
412 xtrace(IOCTL, "ioctl() RESUME\n");
413 return mcdx_playtrk(stuffp, NULL);
414 }
415
416 case CDROMREADTOCENTRY:{
417 struct cdrom_tocentry *entry =
418 (struct cdrom_tocentry *) arg;
419 struct s_subqcode *tp = NULL;
420 xtrace(IOCTL, "ioctl() READTOCENTRY\n");
421
422 if (-1 == mcdx_readtoc(stuffp))
423 return -1;
424 if (entry->cdte_track == CDROM_LEADOUT)
425 tp = &stuffp->toc[stuffp->di.n_last -
426 stuffp->di.n_first + 1];
427 else if (entry->cdte_track > stuffp->di.n_last
428 || entry->cdte_track < stuffp->di.n_first)
429 return -EINVAL;
430 else
431 tp = &stuffp->toc[entry->cdte_track -
432 stuffp->di.n_first];
433
434 if (NULL == tp)
435 return -EIO;
436 entry->cdte_adr = tp->control;
437 entry->cdte_ctrl = tp->control >> 4;
438 /* Always return stuff in MSF, and let the Uniform cdrom driver
439 worry about what the user actually wants */
440 entry->cdte_addr.msf.minute =
441 bcd2uint(tp->dt.minute);
442 entry->cdte_addr.msf.second =
443 bcd2uint(tp->dt.second);
444 entry->cdte_addr.msf.frame =
445 bcd2uint(tp->dt.frame);
446 return 0;
447 }
448
449 case CDROMSUBCHNL:{
450 struct cdrom_subchnl *sub =
451 (struct cdrom_subchnl *) arg;
452 struct s_subqcode q;
453
454 xtrace(IOCTL, "ioctl() SUBCHNL\n");
455
456 if (-1 == mcdx_requestsubqcode(stuffp, &q, 2))
457 return -EIO;
458
459 xtrace(SUBCHNL, "audiostatus: %x\n",
460 stuffp->audiostatus);
461 sub->cdsc_audiostatus = stuffp->audiostatus;
462 sub->cdsc_adr = q.control;
463 sub->cdsc_ctrl = q.control >> 4;
464 sub->cdsc_trk = bcd2uint(q.tno);
465 sub->cdsc_ind = bcd2uint(q.index);
466
467 xtrace(SUBCHNL, "trk %d, ind %d\n",
468 sub->cdsc_trk, sub->cdsc_ind);
469 /* Always return stuff in MSF, and let the Uniform cdrom driver
470 worry about what the user actually wants */
471 sub->cdsc_absaddr.msf.minute =
472 bcd2uint(q.dt.minute);
473 sub->cdsc_absaddr.msf.second =
474 bcd2uint(q.dt.second);
475 sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
476 sub->cdsc_reladdr.msf.minute =
477 bcd2uint(q.tt.minute);
478 sub->cdsc_reladdr.msf.second =
479 bcd2uint(q.tt.second);
480 sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
481 xtrace(SUBCHNL,
482 "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
483 sub->cdsc_absaddr.msf.minute,
484 sub->cdsc_absaddr.msf.second,
485 sub->cdsc_absaddr.msf.frame,
486 sub->cdsc_reladdr.msf.minute,
487 sub->cdsc_reladdr.msf.second,
488 sub->cdsc_reladdr.msf.frame);
489
490 return 0;
491 }
492
493 case CDROMREADTOCHDR:{
494 struct cdrom_tochdr *toc =
495 (struct cdrom_tochdr *) arg;
496
497 xtrace(IOCTL, "ioctl() READTOCHDR\n");
498 toc->cdth_trk0 = stuffp->di.n_first;
499 toc->cdth_trk1 = stuffp->di.n_last;
500 xtrace(TOCHDR,
501 "ioctl() track0 = %d, track1 = %d\n",
502 stuffp->di.n_first, stuffp->di.n_last);
503 return 0;
504 }
505
506 case CDROMPAUSE:{
507 xtrace(IOCTL, "ioctl() PAUSE\n");
508 if (stuffp->audiostatus != CDROM_AUDIO_PLAY)
509 return -EINVAL;
510 if (-1 == mcdx_stop(stuffp, 1))
511 return -EIO;
512 stuffp->audiostatus = CDROM_AUDIO_PAUSED;
513 if (-1 ==
514 mcdx_requestsubqcode(stuffp, &stuffp->start,
515 1))
516 return -EIO;
517 return 0;
518 }
519
520 case CDROMMULTISESSION:{
521 struct cdrom_multisession *ms =
522 (struct cdrom_multisession *) arg;
523 xtrace(IOCTL, "ioctl() MULTISESSION\n");
524 /* Always return stuff in LBA, and let the Uniform cdrom driver
525 worry about what the user actually wants */
526 ms->addr.lba = msf2log(&stuffp->multi.msf_last);
527 ms->xa_flag = !!stuffp->multi.multi;
528 xtrace(MS,
529 "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
530 ms->xa_flag, ms->addr.lba,
531 stuffp->multi.msf_last.minute,
532 stuffp->multi.msf_last.second,
533 stuffp->multi.msf_last.frame);
534
535 return 0;
536 }
537
538 case CDROMEJECT:{
539 xtrace(IOCTL, "ioctl() EJECT\n");
540 if (stuffp->users > 1)
541 return -EBUSY;
542 return (mcdx_tray_move(cdi, 1));
543 }
544
545 case CDROMCLOSETRAY:{
546 xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n");
547 return (mcdx_tray_move(cdi, 0));
548 }
549
550 case CDROMVOLCTRL:{
551 struct cdrom_volctrl *volctrl =
552 (struct cdrom_volctrl *) arg;
553 xtrace(IOCTL, "ioctl() VOLCTRL\n");
554
555#if 0 /* not tested! */
556 /* adjust for the weirdness of workman (md) */
557 /* can't test it (hs) */
558 volctrl.channel2 = volctrl.channel1;
559 volctrl.channel1 = volctrl.channel3 = 0x00;
560#endif
561 return mcdx_setattentuator(stuffp, volctrl, 2);
562 }
563
564 default:
565 return -EINVAL;
566 }
567}
568
Adrian Bunk75c96f82005-05-05 16:16:09 -0700569static void do_mcdx_request(request_queue_t * q)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570{
571 struct s_drive_stuff *stuffp;
572 struct request *req;
573
574 again:
575
576 req = elv_next_request(q);
577 if (!req)
578 return;
579
580 stuffp = req->rq_disk->private_data;
581
582 if (!stuffp->present) {
583 xwarn("do_request(): bad device: %s\n",req->rq_disk->disk_name);
584 xtrace(REQUEST, "end_request(0): bad device\n");
585 end_request(req, 0);
586 return;
587 }
588
589 if (stuffp->audio) {
590 xwarn("do_request() attempt to read from audio cd\n");
591 xtrace(REQUEST, "end_request(0): read from audio\n");
592 end_request(req, 0);
593 return;
594 }
595
596 xtrace(REQUEST, "do_request() (%lu + %lu)\n",
597 req->sector, req->nr_sectors);
598
599 if (req->cmd != READ) {
600 xwarn("do_request(): non-read command to cd!!\n");
601 xtrace(REQUEST, "end_request(0): write\n");
602 end_request(req, 0);
603 return;
604 }
605 else {
606 stuffp->status = 0;
607 while (req->nr_sectors) {
608 int i;
609
610 i = mcdx_transfer(stuffp,
611 req->buffer,
612 req->sector,
613 req->nr_sectors);
614
615 if (i == -1) {
616 end_request(req, 0);
617 goto again;
618 }
619 req->sector += i;
620 req->nr_sectors -= i;
621 req->buffer += (i * 512);
622 }
623 end_request(req, 1);
624 goto again;
625
626 xtrace(REQUEST, "end_request(1)\n");
627 end_request(req, 1);
628 }
629
630 goto again;
631}
632
633static int mcdx_open(struct cdrom_device_info *cdi, int purpose)
634{
635 struct s_drive_stuff *stuffp;
636 xtrace(OPENCLOSE, "open()\n");
637 stuffp = cdi->handle;
638 if (!stuffp->present)
639 return -ENXIO;
640
641 /* Make the modules looking used ... (thanx bjorn).
642 * But we shouldn't forget to decrement the module counter
643 * on error return */
644
645 /* this is only done to test if the drive talks with us */
646 if (-1 == mcdx_getstatus(stuffp, 1))
647 return -EIO;
648
649 if (stuffp->xxx) {
650
651 xtrace(OPENCLOSE, "open() media changed\n");
652 stuffp->audiostatus = CDROM_AUDIO_INVALID;
653 stuffp->readcmd = 0;
654 xtrace(OPENCLOSE, "open() Request multisession info\n");
655 if (-1 ==
656 mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6))
657 xinfo("No multidiskinfo\n");
658 } else {
659 /* multisession ? */
660 if (!stuffp->multi.multi)
661 stuffp->multi.msf_last.second = 2;
662
663 xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
664 stuffp->multi.multi,
665 stuffp->multi.msf_last.minute,
666 stuffp->multi.msf_last.second,
667 stuffp->multi.msf_last.frame);
668
669 {;
670 } /* got multisession information */
671 /* request the disks table of contents (aka diskinfo) */
672 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
673
674 stuffp->lastsector = -1;
675
676 } else {
677
678 stuffp->lastsector = (CD_FRAMESIZE / 512)
679 * msf2log(&stuffp->di.msf_leadout) - 1;
680
681 xtrace(OPENCLOSE,
682 "open() start %d (%02x:%02x.%02x) %d\n",
683 stuffp->di.n_first,
684 stuffp->di.msf_first.minute,
685 stuffp->di.msf_first.second,
686 stuffp->di.msf_first.frame,
687 msf2log(&stuffp->di.msf_first));
688 xtrace(OPENCLOSE,
689 "open() last %d (%02x:%02x.%02x) %d\n",
690 stuffp->di.n_last,
691 stuffp->di.msf_leadout.minute,
692 stuffp->di.msf_leadout.second,
693 stuffp->di.msf_leadout.frame,
694 msf2log(&stuffp->di.msf_leadout));
695 }
696
697 if (stuffp->toc) {
698 xtrace(MALLOC, "open() free old toc @ %p\n",
699 stuffp->toc);
700 kfree(stuffp->toc);
701
702 stuffp->toc = NULL;
703 }
704
705 xtrace(OPENCLOSE, "open() init irq generation\n");
706 if (-1 == mcdx_config(stuffp, 1))
707 return -EIO;
Olaf Hering44456d32005-07-27 11:45:17 -0700708#ifdef FALLBACK
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 /* Set the read speed */
710 xwarn("AAA %x AAA\n", stuffp->readcmd);
711 if (stuffp->readerrs)
712 stuffp->readcmd = READ1X;
713 else
714 stuffp->readcmd =
715 stuffp->present | SINGLE ? READ1X : READ2X;
716 xwarn("XXX %x XXX\n", stuffp->readcmd);
717#else
718 stuffp->readcmd =
719 stuffp->present | SINGLE ? READ1X : READ2X;
720#endif
721
722 /* try to get the first sector, iff any ... */
723 if (stuffp->lastsector >= 0) {
724 char buf[512];
725 int ans;
726 int tries;
727
728 stuffp->xa = 0;
729 stuffp->audio = 0;
730
731 for (tries = 6; tries; tries--) {
732
733 stuffp->introk = 1;
734
735 xtrace(OPENCLOSE, "open() try as %s\n",
736 stuffp->xa ? "XA" : "normal");
737 /* set data mode */
738 if (-1 == (ans = mcdx_setdatamode(stuffp,
739 stuffp->
740 xa ?
741 MODE2 :
742 MODE1,
743 1))) {
744 /* return -EIO; */
745 stuffp->xa = 0;
746 break;
747 }
748
749 if ((stuffp->audio = e_audio(ans)))
750 break;
751
752 while (0 ==
753 (ans =
754 mcdx_transfer(stuffp, buf, 0, 1)));
755
756 if (ans == 1)
757 break;
758 stuffp->xa = !stuffp->xa;
759 }
760 }
761 /* xa disks will be read in raw mode, others not */
762 if (-1 == mcdx_setdrivemode(stuffp,
763 stuffp->xa ? RAW : COOKED,
764 1))
765 return -EIO;
766 if (stuffp->audio) {
767 xinfo("open() audio disk found\n");
768 } else if (stuffp->lastsector >= 0) {
769 xinfo("open() %s%s disk found\n",
770 stuffp->xa ? "XA / " : "",
771 stuffp->multi.
772 multi ? "Multi Session" : "Single Session");
773 }
774 }
775 stuffp->xxx = 0;
776 stuffp->users++;
777 return 0;
778}
779
780static void mcdx_close(struct cdrom_device_info *cdi)
781{
782 struct s_drive_stuff *stuffp;
783
784 xtrace(OPENCLOSE, "close()\n");
785
786 stuffp = cdi->handle;
787
788 --stuffp->users;
789}
790
791static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr)
792/* Return: 1 if media changed since last call to this function
793 0 otherwise */
794{
795 struct s_drive_stuff *stuffp;
796
797 xinfo("mcdx_media_changed called for device %s\n", cdi->name);
798
799 stuffp = cdi->handle;
800 mcdx_getstatus(stuffp, 1);
801
802 if (stuffp->yyy == 0)
803 return 0;
804
805 stuffp->yyy = 0;
806 return 1;
807}
808
809#ifndef MODULE
810static int __init mcdx_setup(char *str)
811{
812 int pi[4];
813 (void) get_options(str, ARRAY_SIZE(pi), pi);
814
815 if (pi[0] > 0)
816 mcdx_drive_map[0][0] = pi[1];
817 if (pi[0] > 1)
818 mcdx_drive_map[0][1] = pi[2];
819 return 1;
820}
821
822__setup("mcdx=", mcdx_setup);
823
824#endif
825
826/* DIRTY PART ******************************************************/
827
828static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
829/* This routine is used for sleeping.
830 * A jifs value <0 means NO sleeping,
831 * =0 means minimal sleeping (let the kernel
832 * run for other processes)
833 * >0 means at least sleep for that amount.
834 * May be we could use a simple count loop w/ jumps to itself, but
835 * I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */
836{
837 if (jifs < 0)
838 return;
839
840 xtrace(SLEEP, "*** delay: sleepq\n");
841 interruptible_sleep_on_timeout(&stuff->sleepq, jifs);
842 xtrace(SLEEP, "delay awoken\n");
843 if (signal_pending(current)) {
844 xtrace(SLEEP, "got signal\n");
845 }
846}
847
David Howells7d12e782006-10-05 14:55:46 +0100848static irqreturn_t mcdx_intr(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849{
850 struct s_drive_stuff *stuffp = dev_id;
851 unsigned char b;
852
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853#ifdef AK2
854 if (!stuffp->busy && stuffp->pending)
855 stuffp->int_err = 1;
856
857#endif /* AK2 */
858 /* get the interrupt status */
859 b = inb(stuffp->rreg_status);
860 stuffp->introk = ~b & MCDX_RBIT_DTEN;
861
862 /* NOTE: We only should get interrupts if the data we
863 * requested are ready to transfer.
864 * But the drive seems to generate ``asynchronous'' interrupts
865 * on several error conditions too. (Despite the err int enable
866 * setting during initialisation) */
867
868 /* if not ok, read the next byte as the drives status */
869 if (!stuffp->introk) {
870 xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b);
871 if (~b & MCDX_RBIT_STEN) {
872 xinfo("intr() irq %d status 0x%02x\n",
873 irq, inb(stuffp->rreg_data));
874 } else {
875 xinfo("intr() irq %d ambiguous hw status\n", irq);
876 }
877 } else {
878 xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b);
879 }
880
881 stuffp->busy = 0;
882 wake_up_interruptible(&stuffp->busyq);
883 return IRQ_HANDLED;
884}
885
886
887static int mcdx_talk(struct s_drive_stuff *stuffp,
888 const unsigned char *cmd, size_t cmdlen,
889 void *buffer, size_t size, unsigned int timeout, int tries)
890/* Send a command to the drive, wait for the result.
891 * returns -1 on timeout, drive status otherwise
892 * If buffer is not zero, the result (length size) is stored there.
893 * If buffer is zero the size should be the number of bytes to read
894 * from the drive. These bytes are discarded.
895 */
896{
897 int st;
898 char c;
899 int discard;
900
901 /* Somebody wants the data read? */
902 if ((discard = (buffer == NULL)))
903 buffer = &c;
904
905 while (stuffp->lock) {
906 xtrace(SLEEP, "*** talk: lockq\n");
907 interruptible_sleep_on(&stuffp->lockq);
908 xtrace(SLEEP, "talk: awoken\n");
909 }
910
911 stuffp->lock = 1;
912
913 /* An operation other then reading data destroys the
914 * data already requested and remembered in stuffp->request, ... */
915 stuffp->valid = 0;
916
917#if MCDX_DEBUG & TALK
918 {
919 unsigned char i;
920 xtrace(TALK,
921 "talk() %d / %d tries, res.size %d, command 0x%02x",
922 tries, timeout, size, (unsigned char) cmd[0]);
923 for (i = 1; i < cmdlen; i++)
924 xtrace(TALK, " 0x%02x", cmd[i]);
925 xtrace(TALK, "\n");
926 }
927#endif
928
929 /* give up if all tries are done (bad) or if the status
930 * st != -1 (good) */
931 for (st = -1; st == -1 && tries; tries--) {
932
933 char *bp = (char *) buffer;
934 size_t sz = size;
935
936 outsb(stuffp->wreg_data, cmd, cmdlen);
937 xtrace(TALK, "talk() command sent\n");
938
939 /* get the status byte */
940 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
941 xinfo("talk() %02x timed out (status), %d tr%s left\n",
942 cmd[0], tries - 1, tries == 2 ? "y" : "ies");
943 continue;
944 }
945 st = *bp;
946 sz--;
947 if (!discard)
948 bp++;
949
950 xtrace(TALK, "talk() got status 0x%02x\n", st);
951
952 /* command error? */
953 if (e_cmderr(st)) {
954 xwarn("command error cmd = %02x %s \n",
955 cmd[0], cmdlen > 1 ? "..." : "");
956 st = -1;
957 continue;
958 }
959
960 /* audio status? */
961 if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
962 stuffp->audiostatus =
963 e_audiobusy(st) ? CDROM_AUDIO_PLAY :
964 CDROM_AUDIO_NO_STATUS;
965 else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
966 && e_audiobusy(st) == 0)
967 stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
968
969 /* media change? */
970 if (e_changed(st)) {
971 xinfo("talk() media changed\n");
972 stuffp->xxx = stuffp->yyy = 1;
973 }
974
975 /* now actually get the data */
976 while (sz--) {
977 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
978 xinfo("talk() %02x timed out (data), %d tr%s left\n",
979 cmd[0], tries - 1,
980 tries == 2 ? "y" : "ies");
981 st = -1;
982 break;
983 }
984 if (!discard)
985 bp++;
986 xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));
987 }
988 }
989
990#if !MCDX_QUIET
991 if (!tries && st == -1)
992 xinfo("talk() giving up\n");
993#endif
994
995 stuffp->lock = 0;
996 wake_up_interruptible(&stuffp->lockq);
997
998 xtrace(TALK, "talk() done with 0x%02x\n", st);
999 return st;
1000}
1001
1002/* MODULE STUFF ***********************************************************/
1003
Randy Dunlapcad2af52006-06-25 05:48:38 -07001004static int __init __mcdx_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005{
1006 int i;
1007 int drives = 0;
1008
1009 mcdx_init();
1010 for (i = 0; i < MCDX_NDRIVES; i++) {
1011 if (mcdx_stuffp[i]) {
1012 xtrace(INIT, "init_module() drive %d stuff @ %p\n",
1013 i, mcdx_stuffp[i]);
1014 drives++;
1015 }
1016 }
1017
1018 if (!drives)
1019 return -EIO;
1020
1021 return 0;
1022}
1023
Adrian Bunk75c96f82005-05-05 16:16:09 -07001024static void __exit mcdx_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025{
1026 int i;
1027
1028 xinfo("cleanup_module called\n");
1029
1030 for (i = 0; i < MCDX_NDRIVES; i++) {
1031 struct s_drive_stuff *stuffp = mcdx_stuffp[i];
1032 if (!stuffp)
1033 continue;
1034 del_gendisk(stuffp->disk);
1035 if (unregister_cdrom(&stuffp->info)) {
1036 printk(KERN_WARNING "Can't unregister cdrom mcdx\n");
1037 continue;
1038 }
1039 put_disk(stuffp->disk);
1040 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1041 free_irq(stuffp->irq, NULL);
1042 if (stuffp->toc) {
1043 xtrace(MALLOC, "cleanup_module() free toc @ %p\n",
1044 stuffp->toc);
1045 kfree(stuffp->toc);
1046 }
1047 xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n",
1048 stuffp);
1049 mcdx_stuffp[i] = NULL;
1050 kfree(stuffp);
1051 }
1052
1053 if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
1054 xwarn("cleanup() unregister_blkdev() failed\n");
1055 }
1056 blk_cleanup_queue(mcdx_queue);
1057#if !MCDX_QUIET
1058 else
1059 xinfo("cleanup() succeeded\n");
1060#endif
1061}
1062
1063#ifdef MODULE
1064module_init(__mcdx_init);
1065#endif
1066module_exit(mcdx_exit);
1067
1068
1069/* Support functions ************************************************/
1070
Adrian Bunk75c96f82005-05-05 16:16:09 -07001071static int __init mcdx_init_drive(int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072{
1073 struct s_version version;
1074 struct gendisk *disk;
1075 struct s_drive_stuff *stuffp;
1076 int size = sizeof(*stuffp);
1077 char msg[80];
1078
1079 xtrace(INIT, "init() try drive %d\n", drive);
1080
1081 xtrace(INIT, "kmalloc space for stuffpt's\n");
1082 xtrace(MALLOC, "init() malloc %d bytes\n", size);
Deepak Saxena5c857ee2005-11-07 01:01:22 -08001083 if (!(stuffp = kzalloc(size, GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001084 xwarn("init() malloc failed\n");
1085 return 1;
1086 }
1087
1088 disk = alloc_disk(1);
1089 if (!disk) {
1090 xwarn("init() malloc failed\n");
1091 kfree(stuffp);
1092 return 1;
1093 }
1094
1095 xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n",
1096 sizeof(*stuffp), stuffp);
1097
1098 /* set default values */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 stuffp->present = 0; /* this should be 0 already */
1100 stuffp->toc = NULL; /* this should be NULL already */
1101
1102 /* setup our irq and i/o addresses */
1103 stuffp->irq = irq(mcdx_drive_map[drive]);
1104 stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]);
1105 stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
1106 stuffp->wreg_hcon = stuffp->wreg_reset + 1;
1107 stuffp->wreg_chn = stuffp->wreg_hcon + 1;
1108
1109 init_waitqueue_head(&stuffp->busyq);
1110 init_waitqueue_head(&stuffp->lockq);
1111 init_waitqueue_head(&stuffp->sleepq);
1112
1113 /* check if i/o addresses are available */
1114 if (!request_region(stuffp->wreg_data, MCDX_IO_SIZE, "mcdx")) {
1115 xwarn("0x%03x,%d: Init failed. "
1116 "I/O ports (0x%03x..0x%03x) already in use.\n",
1117 stuffp->wreg_data, stuffp->irq,
1118 stuffp->wreg_data,
1119 stuffp->wreg_data + MCDX_IO_SIZE - 1);
1120 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1121 kfree(stuffp);
1122 put_disk(disk);
1123 xtrace(INIT, "init() continue at next drive\n");
1124 return 0; /* next drive */
1125 }
1126
1127 xtrace(INIT, "init() i/o port is available at 0x%03x\n"
1128 stuffp->wreg_data);
1129 xtrace(INIT, "init() hardware reset\n");
1130 mcdx_reset(stuffp, HARD, 1);
1131
1132 xtrace(INIT, "init() get version\n");
1133 if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
1134 /* failed, next drive */
1135 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1136 xwarn("%s=0x%03x,%d: Init failed. Can't get version.\n",
1137 MCDX, stuffp->wreg_data, stuffp->irq);
1138 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1139 kfree(stuffp);
1140 put_disk(disk);
1141 xtrace(INIT, "init() continue at next drive\n");
1142 return 0;
1143 }
1144
1145 switch (version.code) {
1146 case 'D':
1147 stuffp->readcmd = READ2X;
1148 stuffp->present = DOUBLE | DOOR | MULTI;
1149 break;
1150 case 'F':
1151 stuffp->readcmd = READ1X;
1152 stuffp->present = SINGLE | DOOR | MULTI;
1153 break;
1154 case 'M':
1155 stuffp->readcmd = READ1X;
1156 stuffp->present = SINGLE;
1157 break;
1158 default:
1159 stuffp->present = 0;
1160 break;
1161 }
1162
1163 stuffp->playcmd = READ1X;
1164
1165 if (!stuffp->present) {
1166 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1167 xwarn("%s=0x%03x,%d: Init failed. No Mitsumi CD-ROM?.\n",
1168 MCDX, stuffp->wreg_data, stuffp->irq);
1169 kfree(stuffp);
1170 put_disk(disk);
1171 return 0; /* next drive */
1172 }
1173
1174 xtrace(INIT, "init() register blkdev\n");
1175 if (register_blkdev(MAJOR_NR, "mcdx")) {
1176 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1177 kfree(stuffp);
1178 put_disk(disk);
1179 return 1;
1180 }
1181
1182 mcdx_queue = blk_init_queue(do_mcdx_request, &mcdx_lock);
1183 if (!mcdx_queue) {
1184 unregister_blkdev(MAJOR_NR, "mcdx");
1185 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1186 kfree(stuffp);
1187 put_disk(disk);
1188 return 1;
1189 }
1190
1191 xtrace(INIT, "init() subscribe irq and i/o\n");
Thomas Gleixnerdace1452006-07-01 19:29:38 -07001192 if (request_irq(stuffp->irq, mcdx_intr, IRQF_DISABLED, "mcdx", stuffp)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1194 xwarn("%s=0x%03x,%d: Init failed. Can't get irq (%d).\n",
1195 MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq);
1196 stuffp->irq = 0;
1197 blk_cleanup_queue(mcdx_queue);
1198 kfree(stuffp);
1199 put_disk(disk);
1200 return 0;
1201 }
1202
1203 xtrace(INIT, "init() get garbage\n");
1204 {
1205 int i;
1206 mcdx_delay(stuffp, HZ / 2);
1207 for (i = 100; i; i--)
1208 (void) inb(stuffp->rreg_status);
1209 }
1210
1211
Olaf Hering44456d32005-07-27 11:45:17 -07001212#ifdef WE_KNOW_WHY
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 /* irq 11 -> channel register */
1214 outb(0x50, stuffp->wreg_chn);
1215#endif
1216
1217 xtrace(INIT, "init() set non dma but irq mode\n");
1218 mcdx_config(stuffp, 1);
1219
1220 stuffp->info.ops = &mcdx_dops;
1221 stuffp->info.speed = 2;
1222 stuffp->info.capacity = 1;
1223 stuffp->info.handle = stuffp;
1224 sprintf(stuffp->info.name, "mcdx%d", drive);
1225 disk->major = MAJOR_NR;
1226 disk->first_minor = drive;
1227 strcpy(disk->disk_name, stuffp->info.name);
1228 disk->fops = &mcdx_bdops;
1229 disk->flags = GENHD_FL_CD;
1230 stuffp->disk = disk;
1231
1232 sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%03x, irq %d."
1233 " (Firmware version %c %x)\n",
1234 stuffp->wreg_data, stuffp->irq, version.code, version.ver);
1235 mcdx_stuffp[drive] = stuffp;
1236 xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp);
1237 if (register_cdrom(&stuffp->info) != 0) {
1238 printk("Cannot register Mitsumi CD-ROM!\n");
1239 free_irq(stuffp->irq, NULL);
1240 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1241 kfree(stuffp);
1242 put_disk(disk);
1243 if (unregister_blkdev(MAJOR_NR, "mcdx") != 0)
1244 xwarn("cleanup() unregister_blkdev() failed\n");
1245 blk_cleanup_queue(mcdx_queue);
1246 return 2;
1247 }
1248 disk->private_data = stuffp;
1249 disk->queue = mcdx_queue;
1250 add_disk(disk);
1251 printk(msg);
1252 return 0;
1253}
1254
Adrian Bunk75c96f82005-05-05 16:16:09 -07001255static int __init mcdx_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001256{
1257 int drive;
1258 xwarn("Version 2.14(hs) \n");
1259
1260 xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
1261
1262 /* zero the pointer array */
1263 for (drive = 0; drive < MCDX_NDRIVES; drive++)
1264 mcdx_stuffp[drive] = NULL;
1265
1266 /* do the initialisation */
1267 for (drive = 0; drive < MCDX_NDRIVES; drive++) {
1268 switch (mcdx_init_drive(drive)) {
1269 case 2:
1270 return -EIO;
1271 case 1:
1272 break;
1273 }
1274 }
1275 return 0;
1276}
1277
1278static int mcdx_transfer(struct s_drive_stuff *stuffp,
1279 char *p, int sector, int nr_sectors)
1280/* This seems to do the actually transfer. But it does more. It
1281 keeps track of errors occurred and will (if possible) fall back
1282 to single speed on error.
1283 Return: -1 on timeout or other error
1284 else status byte (as in stuff->st) */
1285{
1286 int ans;
1287
1288 ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
1289 return ans;
Olaf Hering44456d32005-07-27 11:45:17 -07001290#ifdef FALLBACK
Linus Torvalds1da177e2005-04-16 15:20:36 -07001291 if (-1 == ans)
1292 stuffp->readerrs++;
1293 else
1294 return ans;
1295
1296 if (stuffp->readerrs && stuffp->readcmd == READ1X) {
1297 xwarn("XXX Already reading 1x -- no chance\n");
1298 return -1;
1299 }
1300
1301 xwarn("XXX Fallback to 1x\n");
1302
1303 stuffp->readcmd = READ1X;
1304 return mcdx_transfer(stuffp, p, sector, nr_sectors);
1305#endif
1306
1307}
1308
1309
1310static int mcdx_xfer(struct s_drive_stuff *stuffp,
1311 char *p, int sector, int nr_sectors)
1312/* This does actually the transfer from the drive.
1313 Return: -1 on timeout or other error
1314 else status byte (as in stuff->st) */
1315{
1316 int border;
1317 int done = 0;
1318 long timeout;
1319
1320 if (stuffp->audio) {
1321 xwarn("Attempt to read from audio CD.\n");
1322 return -1;
1323 }
1324
1325 if (!stuffp->readcmd) {
1326 xinfo("Can't transfer from missing disk.\n");
1327 return -1;
1328 }
1329
1330 while (stuffp->lock) {
1331 interruptible_sleep_on(&stuffp->lockq);
1332 }
1333
1334 if (stuffp->valid && (sector >= stuffp->pending)
1335 && (sector < stuffp->low_border)) {
1336
1337 /* All (or at least a part of the sectors requested) seems
1338 * to be already requested, so we don't need to bother the
1339 * drive with new requests ...
1340 * Wait for the drive become idle, but first
1341 * check for possible occurred errors --- the drive
1342 * seems to report them asynchronously */
1343
1344
1345 border = stuffp->high_border < (border =
1346 sector + nr_sectors)
1347 ? stuffp->high_border : border;
1348
1349 stuffp->lock = current->pid;
1350
1351 do {
1352
1353 while (stuffp->busy) {
1354
1355 timeout =
1356 interruptible_sleep_on_timeout
1357 (&stuffp->busyq, 5 * HZ);
1358
1359 if (!stuffp->introk) {
1360 xtrace(XFER,
1361 "error via interrupt\n");
1362 } else if (!timeout) {
1363 xtrace(XFER, "timeout\n");
1364 } else if (signal_pending(current)) {
1365 xtrace(XFER, "signal\n");
1366 } else
1367 continue;
1368
1369 stuffp->lock = 0;
1370 stuffp->busy = 0;
1371 stuffp->valid = 0;
1372
1373 wake_up_interruptible(&stuffp->lockq);
1374 xtrace(XFER, "transfer() done (-1)\n");
1375 return -1;
1376 }
1377
1378 /* check if we need to set the busy flag (as we
1379 * expect an interrupt */
1380 stuffp->busy = (3 == (stuffp->pending & 3));
1381
1382 /* Test if it's the first sector of a block,
1383 * there we have to skip some bytes as we read raw data */
1384 if (stuffp->xa && (0 == (stuffp->pending & 3))) {
1385 const int HEAD =
1386 CD_FRAMESIZE_RAW - CD_XA_TAIL -
1387 CD_FRAMESIZE;
1388 insb(stuffp->rreg_data, p, HEAD);
1389 }
1390
1391 /* now actually read the data */
1392 insb(stuffp->rreg_data, p, 512);
1393
1394 /* test if it's the last sector of a block,
1395 * if so, we have to handle XA special */
1396 if ((3 == (stuffp->pending & 3)) && stuffp->xa) {
1397 char dummy[CD_XA_TAIL];
1398 insb(stuffp->rreg_data, &dummy[0], CD_XA_TAIL);
1399 }
1400
1401 if (stuffp->pending == sector) {
1402 p += 512;
1403 done++;
1404 sector++;
1405 }
1406 } while (++(stuffp->pending) < border);
1407
1408 stuffp->lock = 0;
1409 wake_up_interruptible(&stuffp->lockq);
1410
1411 } else {
1412
1413 /* The requested sector(s) is/are out of the
1414 * already requested range, so we have to bother the drive
1415 * with a new request. */
1416
1417 static unsigned char cmd[] = {
1418 0,
1419 0, 0, 0,
1420 0, 0, 0
1421 };
1422
1423 cmd[0] = stuffp->readcmd;
1424
1425 /* The numbers held in ->pending, ..., should be valid */
1426 stuffp->valid = 1;
1427 stuffp->pending = sector & ~3;
1428
1429 /* do some sanity checks */
1430 if (stuffp->pending > stuffp->lastsector) {
1431 xwarn
1432 ("transfer() sector %d from nirvana requested.\n",
1433 stuffp->pending);
1434 stuffp->status = MCDX_ST_EOM;
1435 stuffp->valid = 0;
1436 xtrace(XFER, "transfer() done (-1)\n");
1437 return -1;
1438 }
1439
1440 if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)
1441 > stuffp->lastsector + 1) {
1442 xtrace(XFER, "cut low_border\n");
1443 stuffp->low_border = stuffp->lastsector + 1;
1444 }
1445 if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE)
1446 > stuffp->lastsector + 1) {
1447 xtrace(XFER, "cut high_border\n");
1448 stuffp->high_border = stuffp->lastsector + 1;
1449 }
1450
1451 { /* Convert the sector to be requested to MSF format */
1452 struct cdrom_msf0 pending;
1453 log2msf(stuffp->pending / 4, &pending);
1454 cmd[1] = pending.minute;
1455 cmd[2] = pending.second;
1456 cmd[3] = pending.frame;
1457 }
1458
1459 cmd[6] =
1460 (unsigned
1461 char) ((stuffp->high_border - stuffp->pending) / 4);
1462 xtrace(XFER, "[%2d]\n", cmd[6]);
1463
1464 stuffp->busy = 1;
1465 /* Now really issue the request command */
1466 outsb(stuffp->wreg_data, cmd, sizeof cmd);
1467
1468 }
1469#ifdef AK2
1470 if (stuffp->int_err) {
1471 stuffp->valid = 0;
1472 stuffp->int_err = 0;
1473 return -1;
1474 }
1475#endif /* AK2 */
1476
1477 stuffp->low_border = (stuffp->low_border +=
1478 done) <
1479 stuffp->high_border ? stuffp->low_border : stuffp->high_border;
1480
1481 return done;
1482}
1483
1484
1485/* Access to elements of the mcdx_drive_map members */
1486
1487static unsigned port(int *ip)
1488{
1489 return ip[0];
1490}
1491static int irq(int *ip)
1492{
1493 return ip[1];
1494}
1495
1496/* Misc number converters */
1497
1498static unsigned int bcd2uint(unsigned char c)
1499{
1500 return (c >> 4) * 10 + (c & 0x0f);
1501}
1502
1503static unsigned int uint2bcd(unsigned int ival)
1504{
1505 return ((ival / 10) << 4) | (ival % 10);
1506}
1507
1508static void log2msf(unsigned int l, struct cdrom_msf0 *pmsf)
1509{
1510 l += CD_MSF_OFFSET;
1511 pmsf->minute = uint2bcd(l / 4500), l %= 4500;
1512 pmsf->second = uint2bcd(l / 75);
1513 pmsf->frame = uint2bcd(l % 75);
1514}
1515
1516static unsigned int msf2log(const struct cdrom_msf0 *pmsf)
1517{
1518 return bcd2uint(pmsf->frame)
1519 + bcd2uint(pmsf->second) * 75
1520 + bcd2uint(pmsf->minute) * 4500 - CD_MSF_OFFSET;
1521}
1522
1523int mcdx_readtoc(struct s_drive_stuff *stuffp)
1524/* Read the toc entries from the CD,
1525 * Return: -1 on failure, else 0 */
1526{
1527
1528 if (stuffp->toc) {
1529 xtrace(READTOC, "ioctl() toc already read\n");
1530 return 0;
1531 }
1532
1533 xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
1534 stuffp->di.n_last - stuffp->di.n_first + 1);
1535
1536 if (-1 == mcdx_hold(stuffp, 1))
1537 return -1;
1538
1539 xtrace(READTOC, "ioctl() tocmode\n");
1540 if (-1 == mcdx_setdrivemode(stuffp, TOC, 1))
1541 return -EIO;
1542
1543 /* all seems to be ok so far ... malloc */
1544 {
1545 int size;
1546 size =
1547 sizeof(struct s_subqcode) * (stuffp->di.n_last -
1548 stuffp->di.n_first + 2);
1549
1550 xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
1551 stuffp->toc = kmalloc(size, GFP_KERNEL);
1552 if (!stuffp->toc) {
1553 xwarn("Cannot malloc %d bytes for toc\n", size);
1554 mcdx_setdrivemode(stuffp, DATA, 1);
1555 return -EIO;
1556 }
1557 }
1558
1559 /* now read actually the index */
1560 {
1561 int trk;
1562 int retries;
1563
1564 for (trk = 0;
1565 trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
1566 trk++)
1567 stuffp->toc[trk].index = 0;
1568
1569 for (retries = 300; retries; retries--) { /* why 300? */
1570 struct s_subqcode q;
1571 unsigned int idx;
1572
1573 if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
1574 mcdx_setdrivemode(stuffp, DATA, 1);
1575 return -EIO;
1576 }
1577
1578 idx = bcd2uint(q.index);
1579
1580 if ((idx > 0)
1581 && (idx <= stuffp->di.n_last)
1582 && (q.tno == 0)
1583 && (stuffp->toc[idx - stuffp->di.n_first].
1584 index == 0)) {
1585 stuffp->toc[idx - stuffp->di.n_first] = q;
1586 xtrace(READTOC,
1587 "ioctl() toc idx %d (trk %d)\n",
1588 idx, trk);
1589 trk--;
1590 }
1591 if (trk == 0)
1592 break;
1593 }
1594 memset(&stuffp->
1595 toc[stuffp->di.n_last - stuffp->di.n_first + 1], 0,
1596 sizeof(stuffp->toc[0]));
1597 stuffp->toc[stuffp->di.n_last - stuffp->di.n_first +
1598 1].dt = stuffp->di.msf_leadout;
1599 }
1600
1601 /* unset toc mode */
1602 xtrace(READTOC, "ioctl() undo toc mode\n");
1603 if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
1604 return -EIO;
1605
1606#if MCDX_DEBUG && READTOC
1607 {
1608 int trk;
1609 for (trk = 0;
1610 trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
1611 trk++)
1612 xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
1613 " %02x:%02x.%02x %02x:%02x.%02x\n",
1614 trk + stuffp->di.n_first,
1615 stuffp->toc[trk].control,
1616 stuffp->toc[trk].tno,
1617 stuffp->toc[trk].index,
1618 stuffp->toc[trk].tt.minute,
1619 stuffp->toc[trk].tt.second,
1620 stuffp->toc[trk].tt.frame,
1621 stuffp->toc[trk].dt.minute,
1622 stuffp->toc[trk].dt.second,
1623 stuffp->toc[trk].dt.frame);
1624 }
1625#endif
1626
1627 return 0;
1628}
1629
1630static int
1631mcdx_playmsf(struct s_drive_stuff *stuffp, const struct cdrom_msf *msf)
1632{
1633 unsigned char cmd[7] = {
1634 0, 0, 0, 0, 0, 0, 0
1635 };
1636
1637 if (!stuffp->readcmd) {
1638 xinfo("Can't play from missing disk.\n");
1639 return -1;
1640 }
1641
1642 cmd[0] = stuffp->playcmd;
1643
1644 cmd[1] = msf->cdmsf_min0;
1645 cmd[2] = msf->cdmsf_sec0;
1646 cmd[3] = msf->cdmsf_frame0;
1647 cmd[4] = msf->cdmsf_min1;
1648 cmd[5] = msf->cdmsf_sec1;
1649 cmd[6] = msf->cdmsf_frame1;
1650
1651 xtrace(PLAYMSF, "ioctl(): play %x "
1652 "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1653 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]);
1654
1655 outsb(stuffp->wreg_data, cmd, sizeof cmd);
1656
1657 if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
1658 xwarn("playmsf() timeout\n");
1659 return -1;
1660 }
1661
1662 stuffp->audiostatus = CDROM_AUDIO_PLAY;
1663 return 0;
1664}
1665
1666static int
1667mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti)
1668{
1669 struct s_subqcode *p;
1670 struct cdrom_msf msf;
1671
1672 if (-1 == mcdx_readtoc(stuffp))
1673 return -1;
1674
1675 if (ti)
1676 p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
1677 else
1678 p = &stuffp->start;
1679
1680 msf.cdmsf_min0 = p->dt.minute;
1681 msf.cdmsf_sec0 = p->dt.second;
1682 msf.cdmsf_frame0 = p->dt.frame;
1683
1684 if (ti) {
1685 p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
1686 stuffp->stop = *p;
1687 } else
1688 p = &stuffp->stop;
1689
1690 msf.cdmsf_min1 = p->dt.minute;
1691 msf.cdmsf_sec1 = p->dt.second;
1692 msf.cdmsf_frame1 = p->dt.frame;
1693
1694 return mcdx_playmsf(stuffp, &msf);
1695}
1696
1697
1698/* Drive functions ************************************************/
1699
1700static int mcdx_tray_move(struct cdrom_device_info *cdi, int position)
1701{
1702 struct s_drive_stuff *stuffp = cdi->handle;
1703
1704 if (!stuffp->present)
1705 return -ENXIO;
1706 if (!(stuffp->present & DOOR))
1707 return -ENOSYS;
1708
1709 if (position) /* 1: eject */
1710 return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3);
1711 else /* 0: close */
1712 return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3);
1713 return 1;
1714}
1715
1716static int mcdx_stop(struct s_drive_stuff *stuffp, int tries)
1717{
1718 return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries);
1719}
1720
1721static int mcdx_hold(struct s_drive_stuff *stuffp, int tries)
1722{
1723 return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries);
1724}
1725
1726static int mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
1727 struct s_subqcode *sub, int tries)
1728{
1729 char buf[11];
1730 int ans;
1731
1732 if (-1 == (ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf),
1733 2 * HZ, tries)))
1734 return -1;
1735 sub->control = buf[1];
1736 sub->tno = buf[2];
1737 sub->index = buf[3];
1738 sub->tt.minute = buf[4];
1739 sub->tt.second = buf[5];
1740 sub->tt.frame = buf[6];
1741 sub->dt.minute = buf[8];
1742 sub->dt.second = buf[9];
1743 sub->dt.frame = buf[10];
1744
1745 return ans;
1746}
1747
1748static int mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp,
1749 struct s_multi *multi, int tries)
1750{
1751 char buf[5];
1752 int ans;
1753
1754 if (stuffp->present & MULTI) {
1755 ans =
1756 mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ,
1757 tries);
1758 multi->multi = buf[1];
1759 multi->msf_last.minute = buf[2];
1760 multi->msf_last.second = buf[3];
1761 multi->msf_last.frame = buf[4];
1762 return ans;
1763 } else {
1764 multi->multi = 0;
1765 return 0;
1766 }
1767}
1768
1769static int mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info,
1770 int tries)
1771{
1772 char buf[9];
1773 int ans;
1774 ans =
1775 mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
1776 if (ans == -1) {
1777 info->n_first = 0;
1778 info->n_last = 0;
1779 } else {
1780 info->n_first = bcd2uint(buf[1]);
1781 info->n_last = bcd2uint(buf[2]);
1782 info->msf_leadout.minute = buf[3];
1783 info->msf_leadout.second = buf[4];
1784 info->msf_leadout.frame = buf[5];
1785 info->msf_first.minute = buf[6];
1786 info->msf_first.second = buf[7];
1787 info->msf_first.frame = buf[8];
1788 }
1789 return ans;
1790}
1791
1792static int mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode,
1793 int tries)
1794{
1795 char cmd[2];
1796 int ans;
1797
1798 xtrace(HW, "setdrivemode() %d\n", mode);
1799
1800 if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
1801 return -1;
1802
1803 switch (mode) {
1804 case TOC:
1805 cmd[1] |= 0x04;
1806 break;
1807 case DATA:
1808 cmd[1] &= ~0x04;
1809 break;
1810 case RAW:
1811 cmd[1] |= 0x40;
1812 break;
1813 case COOKED:
1814 cmd[1] &= ~0x40;
1815 break;
1816 default:
1817 break;
1818 }
1819 cmd[0] = 0x50;
1820 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1821}
1822
1823static int mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode,
1824 int tries)
1825{
1826 unsigned char cmd[2] = { 0xa0 };
1827 xtrace(HW, "setdatamode() %d\n", mode);
1828 switch (mode) {
1829 case MODE0:
1830 cmd[1] = 0x00;
1831 break;
1832 case MODE1:
1833 cmd[1] = 0x01;
1834 break;
1835 case MODE2:
1836 cmd[1] = 0x02;
1837 break;
1838 default:
1839 return -EINVAL;
1840 }
1841 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1842}
1843
1844static int mcdx_config(struct s_drive_stuff *stuffp, int tries)
1845{
1846 char cmd[4];
1847
1848 xtrace(HW, "config()\n");
1849
1850 cmd[0] = 0x90;
1851
1852 cmd[1] = 0x10; /* irq enable */
1853 cmd[2] = 0x05; /* pre, err irq enable */
1854
1855 if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
1856 return -1;
1857
1858 cmd[1] = 0x02; /* dma select */
1859 cmd[2] = 0x00; /* no dma */
1860
1861 return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
1862}
1863
1864static int mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver,
1865 int tries)
1866{
1867 char buf[3];
1868 int ans;
1869
1870 if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
1871 1, buf, sizeof(buf), 2 * HZ, tries)))
1872 return ans;
1873
1874 ver->code = buf[1];
1875 ver->ver = buf[2];
1876
1877 return ans;
1878}
1879
1880static int mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
1881{
1882 if (mode == HARD) {
1883 outb(0, stuffp->wreg_chn); /* no dma, no irq -> hardware */
1884 outb(0, stuffp->wreg_reset); /* hw reset */
1885 return 0;
1886 } else
1887 return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
1888}
1889
1890static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock)
1891{
1892 struct s_drive_stuff *stuffp = cdi->handle;
1893 char cmd[2] = { 0xfe };
1894
1895 if (!(stuffp->present & DOOR))
1896 return -ENOSYS;
1897 if (stuffp->present & DOOR) {
1898 cmd[1] = lock ? 0x01 : 0x00;
1899 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3);
1900 } else
1901 return 0;
1902}
1903
1904static int mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
1905{
1906 return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries);
1907}
1908
1909static int
1910mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char *buf)
1911{
1912 unsigned long timeout = to + jiffies;
1913 char c;
1914
1915 if (!buf)
1916 buf = &c;
1917
1918 while (inb(stuffp->rreg_status) & MCDX_RBIT_STEN) {
1919 if (time_after(jiffies, timeout))
1920 return -1;
1921 mcdx_delay(stuffp, delay);
1922 }
1923
1924 *buf = (unsigned char) inb(stuffp->rreg_data) & 0xff;
1925
1926 return 0;
1927}
1928
1929static int mcdx_setattentuator(struct s_drive_stuff *stuffp,
1930 struct cdrom_volctrl *vol, int tries)
1931{
1932 char cmd[5];
1933 cmd[0] = 0xae;
1934 cmd[1] = vol->channel0;
1935 cmd[2] = 0;
1936 cmd[3] = vol->channel1;
1937 cmd[4] = 0;
1938
1939 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
1940}
1941
1942MODULE_LICENSE("GPL");
1943MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_X_CDROM_MAJOR);