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