blob: dcd1ab684f3e0dfa120fb373bdc16912f8f132c4 [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
848static irqreturn_t mcdx_intr(int irq, void *dev_id, struct pt_regs *regs)
849{
850 struct s_drive_stuff *stuffp = dev_id;
851 unsigned char b;
852
853 if (stuffp == NULL) {
854 xwarn("mcdx: no device for intr %d\n", irq);
855 return IRQ_NONE;
856 }
857#ifdef AK2
858 if (!stuffp->busy && stuffp->pending)
859 stuffp->int_err = 1;
860
861#endif /* AK2 */
862 /* get the interrupt status */
863 b = inb(stuffp->rreg_status);
864 stuffp->introk = ~b & MCDX_RBIT_DTEN;
865
866 /* NOTE: We only should get interrupts if the data we
867 * requested are ready to transfer.
868 * But the drive seems to generate ``asynchronous'' interrupts
869 * on several error conditions too. (Despite the err int enable
870 * setting during initialisation) */
871
872 /* if not ok, read the next byte as the drives status */
873 if (!stuffp->introk) {
874 xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b);
875 if (~b & MCDX_RBIT_STEN) {
876 xinfo("intr() irq %d status 0x%02x\n",
877 irq, inb(stuffp->rreg_data));
878 } else {
879 xinfo("intr() irq %d ambiguous hw status\n", irq);
880 }
881 } else {
882 xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b);
883 }
884
885 stuffp->busy = 0;
886 wake_up_interruptible(&stuffp->busyq);
887 return IRQ_HANDLED;
888}
889
890
891static int mcdx_talk(struct s_drive_stuff *stuffp,
892 const unsigned char *cmd, size_t cmdlen,
893 void *buffer, size_t size, unsigned int timeout, int tries)
894/* Send a command to the drive, wait for the result.
895 * returns -1 on timeout, drive status otherwise
896 * If buffer is not zero, the result (length size) is stored there.
897 * If buffer is zero the size should be the number of bytes to read
898 * from the drive. These bytes are discarded.
899 */
900{
901 int st;
902 char c;
903 int discard;
904
905 /* Somebody wants the data read? */
906 if ((discard = (buffer == NULL)))
907 buffer = &c;
908
909 while (stuffp->lock) {
910 xtrace(SLEEP, "*** talk: lockq\n");
911 interruptible_sleep_on(&stuffp->lockq);
912 xtrace(SLEEP, "talk: awoken\n");
913 }
914
915 stuffp->lock = 1;
916
917 /* An operation other then reading data destroys the
918 * data already requested and remembered in stuffp->request, ... */
919 stuffp->valid = 0;
920
921#if MCDX_DEBUG & TALK
922 {
923 unsigned char i;
924 xtrace(TALK,
925 "talk() %d / %d tries, res.size %d, command 0x%02x",
926 tries, timeout, size, (unsigned char) cmd[0]);
927 for (i = 1; i < cmdlen; i++)
928 xtrace(TALK, " 0x%02x", cmd[i]);
929 xtrace(TALK, "\n");
930 }
931#endif
932
933 /* give up if all tries are done (bad) or if the status
934 * st != -1 (good) */
935 for (st = -1; st == -1 && tries; tries--) {
936
937 char *bp = (char *) buffer;
938 size_t sz = size;
939
940 outsb(stuffp->wreg_data, cmd, cmdlen);
941 xtrace(TALK, "talk() command sent\n");
942
943 /* get the status byte */
944 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
945 xinfo("talk() %02x timed out (status), %d tr%s left\n",
946 cmd[0], tries - 1, tries == 2 ? "y" : "ies");
947 continue;
948 }
949 st = *bp;
950 sz--;
951 if (!discard)
952 bp++;
953
954 xtrace(TALK, "talk() got status 0x%02x\n", st);
955
956 /* command error? */
957 if (e_cmderr(st)) {
958 xwarn("command error cmd = %02x %s \n",
959 cmd[0], cmdlen > 1 ? "..." : "");
960 st = -1;
961 continue;
962 }
963
964 /* audio status? */
965 if (stuffp->audiostatus == CDROM_AUDIO_INVALID)
966 stuffp->audiostatus =
967 e_audiobusy(st) ? CDROM_AUDIO_PLAY :
968 CDROM_AUDIO_NO_STATUS;
969 else if (stuffp->audiostatus == CDROM_AUDIO_PLAY
970 && e_audiobusy(st) == 0)
971 stuffp->audiostatus = CDROM_AUDIO_COMPLETED;
972
973 /* media change? */
974 if (e_changed(st)) {
975 xinfo("talk() media changed\n");
976 stuffp->xxx = stuffp->yyy = 1;
977 }
978
979 /* now actually get the data */
980 while (sz--) {
981 if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) {
982 xinfo("talk() %02x timed out (data), %d tr%s left\n",
983 cmd[0], tries - 1,
984 tries == 2 ? "y" : "ies");
985 st = -1;
986 break;
987 }
988 if (!discard)
989 bp++;
990 xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1));
991 }
992 }
993
994#if !MCDX_QUIET
995 if (!tries && st == -1)
996 xinfo("talk() giving up\n");
997#endif
998
999 stuffp->lock = 0;
1000 wake_up_interruptible(&stuffp->lockq);
1001
1002 xtrace(TALK, "talk() done with 0x%02x\n", st);
1003 return st;
1004}
1005
1006/* MODULE STUFF ***********************************************************/
1007
Randy Dunlapcad2af52006-06-25 05:48:38 -07001008static int __init __mcdx_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009{
1010 int i;
1011 int drives = 0;
1012
1013 mcdx_init();
1014 for (i = 0; i < MCDX_NDRIVES; i++) {
1015 if (mcdx_stuffp[i]) {
1016 xtrace(INIT, "init_module() drive %d stuff @ %p\n",
1017 i, mcdx_stuffp[i]);
1018 drives++;
1019 }
1020 }
1021
1022 if (!drives)
1023 return -EIO;
1024
1025 return 0;
1026}
1027
Adrian Bunk75c96f82005-05-05 16:16:09 -07001028static void __exit mcdx_exit(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029{
1030 int i;
1031
1032 xinfo("cleanup_module called\n");
1033
1034 for (i = 0; i < MCDX_NDRIVES; i++) {
1035 struct s_drive_stuff *stuffp = mcdx_stuffp[i];
1036 if (!stuffp)
1037 continue;
1038 del_gendisk(stuffp->disk);
1039 if (unregister_cdrom(&stuffp->info)) {
1040 printk(KERN_WARNING "Can't unregister cdrom mcdx\n");
1041 continue;
1042 }
1043 put_disk(stuffp->disk);
1044 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1045 free_irq(stuffp->irq, NULL);
1046 if (stuffp->toc) {
1047 xtrace(MALLOC, "cleanup_module() free toc @ %p\n",
1048 stuffp->toc);
1049 kfree(stuffp->toc);
1050 }
1051 xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n",
1052 stuffp);
1053 mcdx_stuffp[i] = NULL;
1054 kfree(stuffp);
1055 }
1056
1057 if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) {
1058 xwarn("cleanup() unregister_blkdev() failed\n");
1059 }
1060 blk_cleanup_queue(mcdx_queue);
1061#if !MCDX_QUIET
1062 else
1063 xinfo("cleanup() succeeded\n");
1064#endif
1065}
1066
1067#ifdef MODULE
1068module_init(__mcdx_init);
1069#endif
1070module_exit(mcdx_exit);
1071
1072
1073/* Support functions ************************************************/
1074
Adrian Bunk75c96f82005-05-05 16:16:09 -07001075static int __init mcdx_init_drive(int drive)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076{
1077 struct s_version version;
1078 struct gendisk *disk;
1079 struct s_drive_stuff *stuffp;
1080 int size = sizeof(*stuffp);
1081 char msg[80];
1082
1083 xtrace(INIT, "init() try drive %d\n", drive);
1084
1085 xtrace(INIT, "kmalloc space for stuffpt's\n");
1086 xtrace(MALLOC, "init() malloc %d bytes\n", size);
Deepak Saxena5c857ee2005-11-07 01:01:22 -08001087 if (!(stuffp = kzalloc(size, GFP_KERNEL))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001088 xwarn("init() malloc failed\n");
1089 return 1;
1090 }
1091
1092 disk = alloc_disk(1);
1093 if (!disk) {
1094 xwarn("init() malloc failed\n");
1095 kfree(stuffp);
1096 return 1;
1097 }
1098
1099 xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n",
1100 sizeof(*stuffp), stuffp);
1101
1102 /* set default values */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 stuffp->present = 0; /* this should be 0 already */
1104 stuffp->toc = NULL; /* this should be NULL already */
1105
1106 /* setup our irq and i/o addresses */
1107 stuffp->irq = irq(mcdx_drive_map[drive]);
1108 stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]);
1109 stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
1110 stuffp->wreg_hcon = stuffp->wreg_reset + 1;
1111 stuffp->wreg_chn = stuffp->wreg_hcon + 1;
1112
1113 init_waitqueue_head(&stuffp->busyq);
1114 init_waitqueue_head(&stuffp->lockq);
1115 init_waitqueue_head(&stuffp->sleepq);
1116
1117 /* check if i/o addresses are available */
1118 if (!request_region(stuffp->wreg_data, MCDX_IO_SIZE, "mcdx")) {
1119 xwarn("0x%03x,%d: Init failed. "
1120 "I/O ports (0x%03x..0x%03x) already in use.\n",
1121 stuffp->wreg_data, stuffp->irq,
1122 stuffp->wreg_data,
1123 stuffp->wreg_data + MCDX_IO_SIZE - 1);
1124 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1125 kfree(stuffp);
1126 put_disk(disk);
1127 xtrace(INIT, "init() continue at next drive\n");
1128 return 0; /* next drive */
1129 }
1130
1131 xtrace(INIT, "init() i/o port is available at 0x%03x\n"
1132 stuffp->wreg_data);
1133 xtrace(INIT, "init() hardware reset\n");
1134 mcdx_reset(stuffp, HARD, 1);
1135
1136 xtrace(INIT, "init() get version\n");
1137 if (-1 == mcdx_requestversion(stuffp, &version, 4)) {
1138 /* failed, next drive */
1139 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1140 xwarn("%s=0x%03x,%d: Init failed. Can't get version.\n",
1141 MCDX, stuffp->wreg_data, stuffp->irq);
1142 xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp);
1143 kfree(stuffp);
1144 put_disk(disk);
1145 xtrace(INIT, "init() continue at next drive\n");
1146 return 0;
1147 }
1148
1149 switch (version.code) {
1150 case 'D':
1151 stuffp->readcmd = READ2X;
1152 stuffp->present = DOUBLE | DOOR | MULTI;
1153 break;
1154 case 'F':
1155 stuffp->readcmd = READ1X;
1156 stuffp->present = SINGLE | DOOR | MULTI;
1157 break;
1158 case 'M':
1159 stuffp->readcmd = READ1X;
1160 stuffp->present = SINGLE;
1161 break;
1162 default:
1163 stuffp->present = 0;
1164 break;
1165 }
1166
1167 stuffp->playcmd = READ1X;
1168
1169 if (!stuffp->present) {
1170 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1171 xwarn("%s=0x%03x,%d: Init failed. No Mitsumi CD-ROM?.\n",
1172 MCDX, stuffp->wreg_data, stuffp->irq);
1173 kfree(stuffp);
1174 put_disk(disk);
1175 return 0; /* next drive */
1176 }
1177
1178 xtrace(INIT, "init() register blkdev\n");
1179 if (register_blkdev(MAJOR_NR, "mcdx")) {
1180 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1181 kfree(stuffp);
1182 put_disk(disk);
1183 return 1;
1184 }
1185
1186 mcdx_queue = blk_init_queue(do_mcdx_request, &mcdx_lock);
1187 if (!mcdx_queue) {
1188 unregister_blkdev(MAJOR_NR, "mcdx");
1189 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1190 kfree(stuffp);
1191 put_disk(disk);
1192 return 1;
1193 }
1194
1195 xtrace(INIT, "init() subscribe irq and i/o\n");
Thomas Gleixnerdace1452006-07-01 19:29:38 -07001196 if (request_irq(stuffp->irq, mcdx_intr, IRQF_DISABLED, "mcdx", stuffp)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001197 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1198 xwarn("%s=0x%03x,%d: Init failed. Can't get irq (%d).\n",
1199 MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq);
1200 stuffp->irq = 0;
1201 blk_cleanup_queue(mcdx_queue);
1202 kfree(stuffp);
1203 put_disk(disk);
1204 return 0;
1205 }
1206
1207 xtrace(INIT, "init() get garbage\n");
1208 {
1209 int i;
1210 mcdx_delay(stuffp, HZ / 2);
1211 for (i = 100; i; i--)
1212 (void) inb(stuffp->rreg_status);
1213 }
1214
1215
Olaf Hering44456d32005-07-27 11:45:17 -07001216#ifdef WE_KNOW_WHY
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 /* irq 11 -> channel register */
1218 outb(0x50, stuffp->wreg_chn);
1219#endif
1220
1221 xtrace(INIT, "init() set non dma but irq mode\n");
1222 mcdx_config(stuffp, 1);
1223
1224 stuffp->info.ops = &mcdx_dops;
1225 stuffp->info.speed = 2;
1226 stuffp->info.capacity = 1;
1227 stuffp->info.handle = stuffp;
1228 sprintf(stuffp->info.name, "mcdx%d", drive);
1229 disk->major = MAJOR_NR;
1230 disk->first_minor = drive;
1231 strcpy(disk->disk_name, stuffp->info.name);
1232 disk->fops = &mcdx_bdops;
1233 disk->flags = GENHD_FL_CD;
1234 stuffp->disk = disk;
1235
1236 sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%03x, irq %d."
1237 " (Firmware version %c %x)\n",
1238 stuffp->wreg_data, stuffp->irq, version.code, version.ver);
1239 mcdx_stuffp[drive] = stuffp;
1240 xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp);
1241 if (register_cdrom(&stuffp->info) != 0) {
1242 printk("Cannot register Mitsumi CD-ROM!\n");
1243 free_irq(stuffp->irq, NULL);
1244 release_region(stuffp->wreg_data, MCDX_IO_SIZE);
1245 kfree(stuffp);
1246 put_disk(disk);
1247 if (unregister_blkdev(MAJOR_NR, "mcdx") != 0)
1248 xwarn("cleanup() unregister_blkdev() failed\n");
1249 blk_cleanup_queue(mcdx_queue);
1250 return 2;
1251 }
1252 disk->private_data = stuffp;
1253 disk->queue = mcdx_queue;
1254 add_disk(disk);
1255 printk(msg);
1256 return 0;
1257}
1258
Adrian Bunk75c96f82005-05-05 16:16:09 -07001259static int __init mcdx_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260{
1261 int drive;
1262 xwarn("Version 2.14(hs) \n");
1263
1264 xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
1265
1266 /* zero the pointer array */
1267 for (drive = 0; drive < MCDX_NDRIVES; drive++)
1268 mcdx_stuffp[drive] = NULL;
1269
1270 /* do the initialisation */
1271 for (drive = 0; drive < MCDX_NDRIVES; drive++) {
1272 switch (mcdx_init_drive(drive)) {
1273 case 2:
1274 return -EIO;
1275 case 1:
1276 break;
1277 }
1278 }
1279 return 0;
1280}
1281
1282static int mcdx_transfer(struct s_drive_stuff *stuffp,
1283 char *p, int sector, int nr_sectors)
1284/* This seems to do the actually transfer. But it does more. It
1285 keeps track of errors occurred and will (if possible) fall back
1286 to single speed on error.
1287 Return: -1 on timeout or other error
1288 else status byte (as in stuff->st) */
1289{
1290 int ans;
1291
1292 ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
1293 return ans;
Olaf Hering44456d32005-07-27 11:45:17 -07001294#ifdef FALLBACK
Linus Torvalds1da177e2005-04-16 15:20:36 -07001295 if (-1 == ans)
1296 stuffp->readerrs++;
1297 else
1298 return ans;
1299
1300 if (stuffp->readerrs && stuffp->readcmd == READ1X) {
1301 xwarn("XXX Already reading 1x -- no chance\n");
1302 return -1;
1303 }
1304
1305 xwarn("XXX Fallback to 1x\n");
1306
1307 stuffp->readcmd = READ1X;
1308 return mcdx_transfer(stuffp, p, sector, nr_sectors);
1309#endif
1310
1311}
1312
1313
1314static int mcdx_xfer(struct s_drive_stuff *stuffp,
1315 char *p, int sector, int nr_sectors)
1316/* This does actually the transfer from the drive.
1317 Return: -1 on timeout or other error
1318 else status byte (as in stuff->st) */
1319{
1320 int border;
1321 int done = 0;
1322 long timeout;
1323
1324 if (stuffp->audio) {
1325 xwarn("Attempt to read from audio CD.\n");
1326 return -1;
1327 }
1328
1329 if (!stuffp->readcmd) {
1330 xinfo("Can't transfer from missing disk.\n");
1331 return -1;
1332 }
1333
1334 while (stuffp->lock) {
1335 interruptible_sleep_on(&stuffp->lockq);
1336 }
1337
1338 if (stuffp->valid && (sector >= stuffp->pending)
1339 && (sector < stuffp->low_border)) {
1340
1341 /* All (or at least a part of the sectors requested) seems
1342 * to be already requested, so we don't need to bother the
1343 * drive with new requests ...
1344 * Wait for the drive become idle, but first
1345 * check for possible occurred errors --- the drive
1346 * seems to report them asynchronously */
1347
1348
1349 border = stuffp->high_border < (border =
1350 sector + nr_sectors)
1351 ? stuffp->high_border : border;
1352
1353 stuffp->lock = current->pid;
1354
1355 do {
1356
1357 while (stuffp->busy) {
1358
1359 timeout =
1360 interruptible_sleep_on_timeout
1361 (&stuffp->busyq, 5 * HZ);
1362
1363 if (!stuffp->introk) {
1364 xtrace(XFER,
1365 "error via interrupt\n");
1366 } else if (!timeout) {
1367 xtrace(XFER, "timeout\n");
1368 } else if (signal_pending(current)) {
1369 xtrace(XFER, "signal\n");
1370 } else
1371 continue;
1372
1373 stuffp->lock = 0;
1374 stuffp->busy = 0;
1375 stuffp->valid = 0;
1376
1377 wake_up_interruptible(&stuffp->lockq);
1378 xtrace(XFER, "transfer() done (-1)\n");
1379 return -1;
1380 }
1381
1382 /* check if we need to set the busy flag (as we
1383 * expect an interrupt */
1384 stuffp->busy = (3 == (stuffp->pending & 3));
1385
1386 /* Test if it's the first sector of a block,
1387 * there we have to skip some bytes as we read raw data */
1388 if (stuffp->xa && (0 == (stuffp->pending & 3))) {
1389 const int HEAD =
1390 CD_FRAMESIZE_RAW - CD_XA_TAIL -
1391 CD_FRAMESIZE;
1392 insb(stuffp->rreg_data, p, HEAD);
1393 }
1394
1395 /* now actually read the data */
1396 insb(stuffp->rreg_data, p, 512);
1397
1398 /* test if it's the last sector of a block,
1399 * if so, we have to handle XA special */
1400 if ((3 == (stuffp->pending & 3)) && stuffp->xa) {
1401 char dummy[CD_XA_TAIL];
1402 insb(stuffp->rreg_data, &dummy[0], CD_XA_TAIL);
1403 }
1404
1405 if (stuffp->pending == sector) {
1406 p += 512;
1407 done++;
1408 sector++;
1409 }
1410 } while (++(stuffp->pending) < border);
1411
1412 stuffp->lock = 0;
1413 wake_up_interruptible(&stuffp->lockq);
1414
1415 } else {
1416
1417 /* The requested sector(s) is/are out of the
1418 * already requested range, so we have to bother the drive
1419 * with a new request. */
1420
1421 static unsigned char cmd[] = {
1422 0,
1423 0, 0, 0,
1424 0, 0, 0
1425 };
1426
1427 cmd[0] = stuffp->readcmd;
1428
1429 /* The numbers held in ->pending, ..., should be valid */
1430 stuffp->valid = 1;
1431 stuffp->pending = sector & ~3;
1432
1433 /* do some sanity checks */
1434 if (stuffp->pending > stuffp->lastsector) {
1435 xwarn
1436 ("transfer() sector %d from nirvana requested.\n",
1437 stuffp->pending);
1438 stuffp->status = MCDX_ST_EOM;
1439 stuffp->valid = 0;
1440 xtrace(XFER, "transfer() done (-1)\n");
1441 return -1;
1442 }
1443
1444 if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)
1445 > stuffp->lastsector + 1) {
1446 xtrace(XFER, "cut low_border\n");
1447 stuffp->low_border = stuffp->lastsector + 1;
1448 }
1449 if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE)
1450 > stuffp->lastsector + 1) {
1451 xtrace(XFER, "cut high_border\n");
1452 stuffp->high_border = stuffp->lastsector + 1;
1453 }
1454
1455 { /* Convert the sector to be requested to MSF format */
1456 struct cdrom_msf0 pending;
1457 log2msf(stuffp->pending / 4, &pending);
1458 cmd[1] = pending.minute;
1459 cmd[2] = pending.second;
1460 cmd[3] = pending.frame;
1461 }
1462
1463 cmd[6] =
1464 (unsigned
1465 char) ((stuffp->high_border - stuffp->pending) / 4);
1466 xtrace(XFER, "[%2d]\n", cmd[6]);
1467
1468 stuffp->busy = 1;
1469 /* Now really issue the request command */
1470 outsb(stuffp->wreg_data, cmd, sizeof cmd);
1471
1472 }
1473#ifdef AK2
1474 if (stuffp->int_err) {
1475 stuffp->valid = 0;
1476 stuffp->int_err = 0;
1477 return -1;
1478 }
1479#endif /* AK2 */
1480
1481 stuffp->low_border = (stuffp->low_border +=
1482 done) <
1483 stuffp->high_border ? stuffp->low_border : stuffp->high_border;
1484
1485 return done;
1486}
1487
1488
1489/* Access to elements of the mcdx_drive_map members */
1490
1491static unsigned port(int *ip)
1492{
1493 return ip[0];
1494}
1495static int irq(int *ip)
1496{
1497 return ip[1];
1498}
1499
1500/* Misc number converters */
1501
1502static unsigned int bcd2uint(unsigned char c)
1503{
1504 return (c >> 4) * 10 + (c & 0x0f);
1505}
1506
1507static unsigned int uint2bcd(unsigned int ival)
1508{
1509 return ((ival / 10) << 4) | (ival % 10);
1510}
1511
1512static void log2msf(unsigned int l, struct cdrom_msf0 *pmsf)
1513{
1514 l += CD_MSF_OFFSET;
1515 pmsf->minute = uint2bcd(l / 4500), l %= 4500;
1516 pmsf->second = uint2bcd(l / 75);
1517 pmsf->frame = uint2bcd(l % 75);
1518}
1519
1520static unsigned int msf2log(const struct cdrom_msf0 *pmsf)
1521{
1522 return bcd2uint(pmsf->frame)
1523 + bcd2uint(pmsf->second) * 75
1524 + bcd2uint(pmsf->minute) * 4500 - CD_MSF_OFFSET;
1525}
1526
1527int mcdx_readtoc(struct s_drive_stuff *stuffp)
1528/* Read the toc entries from the CD,
1529 * Return: -1 on failure, else 0 */
1530{
1531
1532 if (stuffp->toc) {
1533 xtrace(READTOC, "ioctl() toc already read\n");
1534 return 0;
1535 }
1536
1537 xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
1538 stuffp->di.n_last - stuffp->di.n_first + 1);
1539
1540 if (-1 == mcdx_hold(stuffp, 1))
1541 return -1;
1542
1543 xtrace(READTOC, "ioctl() tocmode\n");
1544 if (-1 == mcdx_setdrivemode(stuffp, TOC, 1))
1545 return -EIO;
1546
1547 /* all seems to be ok so far ... malloc */
1548 {
1549 int size;
1550 size =
1551 sizeof(struct s_subqcode) * (stuffp->di.n_last -
1552 stuffp->di.n_first + 2);
1553
1554 xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
1555 stuffp->toc = kmalloc(size, GFP_KERNEL);
1556 if (!stuffp->toc) {
1557 xwarn("Cannot malloc %d bytes for toc\n", size);
1558 mcdx_setdrivemode(stuffp, DATA, 1);
1559 return -EIO;
1560 }
1561 }
1562
1563 /* now read actually the index */
1564 {
1565 int trk;
1566 int retries;
1567
1568 for (trk = 0;
1569 trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
1570 trk++)
1571 stuffp->toc[trk].index = 0;
1572
1573 for (retries = 300; retries; retries--) { /* why 300? */
1574 struct s_subqcode q;
1575 unsigned int idx;
1576
1577 if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
1578 mcdx_setdrivemode(stuffp, DATA, 1);
1579 return -EIO;
1580 }
1581
1582 idx = bcd2uint(q.index);
1583
1584 if ((idx > 0)
1585 && (idx <= stuffp->di.n_last)
1586 && (q.tno == 0)
1587 && (stuffp->toc[idx - stuffp->di.n_first].
1588 index == 0)) {
1589 stuffp->toc[idx - stuffp->di.n_first] = q;
1590 xtrace(READTOC,
1591 "ioctl() toc idx %d (trk %d)\n",
1592 idx, trk);
1593 trk--;
1594 }
1595 if (trk == 0)
1596 break;
1597 }
1598 memset(&stuffp->
1599 toc[stuffp->di.n_last - stuffp->di.n_first + 1], 0,
1600 sizeof(stuffp->toc[0]));
1601 stuffp->toc[stuffp->di.n_last - stuffp->di.n_first +
1602 1].dt = stuffp->di.msf_leadout;
1603 }
1604
1605 /* unset toc mode */
1606 xtrace(READTOC, "ioctl() undo toc mode\n");
1607 if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
1608 return -EIO;
1609
1610#if MCDX_DEBUG && READTOC
1611 {
1612 int trk;
1613 for (trk = 0;
1614 trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
1615 trk++)
1616 xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
1617 " %02x:%02x.%02x %02x:%02x.%02x\n",
1618 trk + stuffp->di.n_first,
1619 stuffp->toc[trk].control,
1620 stuffp->toc[trk].tno,
1621 stuffp->toc[trk].index,
1622 stuffp->toc[trk].tt.minute,
1623 stuffp->toc[trk].tt.second,
1624 stuffp->toc[trk].tt.frame,
1625 stuffp->toc[trk].dt.minute,
1626 stuffp->toc[trk].dt.second,
1627 stuffp->toc[trk].dt.frame);
1628 }
1629#endif
1630
1631 return 0;
1632}
1633
1634static int
1635mcdx_playmsf(struct s_drive_stuff *stuffp, const struct cdrom_msf *msf)
1636{
1637 unsigned char cmd[7] = {
1638 0, 0, 0, 0, 0, 0, 0
1639 };
1640
1641 if (!stuffp->readcmd) {
1642 xinfo("Can't play from missing disk.\n");
1643 return -1;
1644 }
1645
1646 cmd[0] = stuffp->playcmd;
1647
1648 cmd[1] = msf->cdmsf_min0;
1649 cmd[2] = msf->cdmsf_sec0;
1650 cmd[3] = msf->cdmsf_frame0;
1651 cmd[4] = msf->cdmsf_min1;
1652 cmd[5] = msf->cdmsf_sec1;
1653 cmd[6] = msf->cdmsf_frame1;
1654
1655 xtrace(PLAYMSF, "ioctl(): play %x "
1656 "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1657 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]);
1658
1659 outsb(stuffp->wreg_data, cmd, sizeof cmd);
1660
1661 if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
1662 xwarn("playmsf() timeout\n");
1663 return -1;
1664 }
1665
1666 stuffp->audiostatus = CDROM_AUDIO_PLAY;
1667 return 0;
1668}
1669
1670static int
1671mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti)
1672{
1673 struct s_subqcode *p;
1674 struct cdrom_msf msf;
1675
1676 if (-1 == mcdx_readtoc(stuffp))
1677 return -1;
1678
1679 if (ti)
1680 p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
1681 else
1682 p = &stuffp->start;
1683
1684 msf.cdmsf_min0 = p->dt.minute;
1685 msf.cdmsf_sec0 = p->dt.second;
1686 msf.cdmsf_frame0 = p->dt.frame;
1687
1688 if (ti) {
1689 p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
1690 stuffp->stop = *p;
1691 } else
1692 p = &stuffp->stop;
1693
1694 msf.cdmsf_min1 = p->dt.minute;
1695 msf.cdmsf_sec1 = p->dt.second;
1696 msf.cdmsf_frame1 = p->dt.frame;
1697
1698 return mcdx_playmsf(stuffp, &msf);
1699}
1700
1701
1702/* Drive functions ************************************************/
1703
1704static int mcdx_tray_move(struct cdrom_device_info *cdi, int position)
1705{
1706 struct s_drive_stuff *stuffp = cdi->handle;
1707
1708 if (!stuffp->present)
1709 return -ENXIO;
1710 if (!(stuffp->present & DOOR))
1711 return -ENOSYS;
1712
1713 if (position) /* 1: eject */
1714 return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3);
1715 else /* 0: close */
1716 return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3);
1717 return 1;
1718}
1719
1720static int mcdx_stop(struct s_drive_stuff *stuffp, int tries)
1721{
1722 return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries);
1723}
1724
1725static int mcdx_hold(struct s_drive_stuff *stuffp, int tries)
1726{
1727 return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries);
1728}
1729
1730static int mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
1731 struct s_subqcode *sub, int tries)
1732{
1733 char buf[11];
1734 int ans;
1735
1736 if (-1 == (ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf),
1737 2 * HZ, tries)))
1738 return -1;
1739 sub->control = buf[1];
1740 sub->tno = buf[2];
1741 sub->index = buf[3];
1742 sub->tt.minute = buf[4];
1743 sub->tt.second = buf[5];
1744 sub->tt.frame = buf[6];
1745 sub->dt.minute = buf[8];
1746 sub->dt.second = buf[9];
1747 sub->dt.frame = buf[10];
1748
1749 return ans;
1750}
1751
1752static int mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp,
1753 struct s_multi *multi, int tries)
1754{
1755 char buf[5];
1756 int ans;
1757
1758 if (stuffp->present & MULTI) {
1759 ans =
1760 mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ,
1761 tries);
1762 multi->multi = buf[1];
1763 multi->msf_last.minute = buf[2];
1764 multi->msf_last.second = buf[3];
1765 multi->msf_last.frame = buf[4];
1766 return ans;
1767 } else {
1768 multi->multi = 0;
1769 return 0;
1770 }
1771}
1772
1773static int mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info,
1774 int tries)
1775{
1776 char buf[9];
1777 int ans;
1778 ans =
1779 mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
1780 if (ans == -1) {
1781 info->n_first = 0;
1782 info->n_last = 0;
1783 } else {
1784 info->n_first = bcd2uint(buf[1]);
1785 info->n_last = bcd2uint(buf[2]);
1786 info->msf_leadout.minute = buf[3];
1787 info->msf_leadout.second = buf[4];
1788 info->msf_leadout.frame = buf[5];
1789 info->msf_first.minute = buf[6];
1790 info->msf_first.second = buf[7];
1791 info->msf_first.frame = buf[8];
1792 }
1793 return ans;
1794}
1795
1796static int mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode,
1797 int tries)
1798{
1799 char cmd[2];
1800 int ans;
1801
1802 xtrace(HW, "setdrivemode() %d\n", mode);
1803
1804 if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
1805 return -1;
1806
1807 switch (mode) {
1808 case TOC:
1809 cmd[1] |= 0x04;
1810 break;
1811 case DATA:
1812 cmd[1] &= ~0x04;
1813 break;
1814 case RAW:
1815 cmd[1] |= 0x40;
1816 break;
1817 case COOKED:
1818 cmd[1] &= ~0x40;
1819 break;
1820 default:
1821 break;
1822 }
1823 cmd[0] = 0x50;
1824 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1825}
1826
1827static int mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode,
1828 int tries)
1829{
1830 unsigned char cmd[2] = { 0xa0 };
1831 xtrace(HW, "setdatamode() %d\n", mode);
1832 switch (mode) {
1833 case MODE0:
1834 cmd[1] = 0x00;
1835 break;
1836 case MODE1:
1837 cmd[1] = 0x01;
1838 break;
1839 case MODE2:
1840 cmd[1] = 0x02;
1841 break;
1842 default:
1843 return -EINVAL;
1844 }
1845 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1846}
1847
1848static int mcdx_config(struct s_drive_stuff *stuffp, int tries)
1849{
1850 char cmd[4];
1851
1852 xtrace(HW, "config()\n");
1853
1854 cmd[0] = 0x90;
1855
1856 cmd[1] = 0x10; /* irq enable */
1857 cmd[2] = 0x05; /* pre, err irq enable */
1858
1859 if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
1860 return -1;
1861
1862 cmd[1] = 0x02; /* dma select */
1863 cmd[2] = 0x00; /* no dma */
1864
1865 return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
1866}
1867
1868static int mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver,
1869 int tries)
1870{
1871 char buf[3];
1872 int ans;
1873
1874 if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
1875 1, buf, sizeof(buf), 2 * HZ, tries)))
1876 return ans;
1877
1878 ver->code = buf[1];
1879 ver->ver = buf[2];
1880
1881 return ans;
1882}
1883
1884static int mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
1885{
1886 if (mode == HARD) {
1887 outb(0, stuffp->wreg_chn); /* no dma, no irq -> hardware */
1888 outb(0, stuffp->wreg_reset); /* hw reset */
1889 return 0;
1890 } else
1891 return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
1892}
1893
1894static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock)
1895{
1896 struct s_drive_stuff *stuffp = cdi->handle;
1897 char cmd[2] = { 0xfe };
1898
1899 if (!(stuffp->present & DOOR))
1900 return -ENOSYS;
1901 if (stuffp->present & DOOR) {
1902 cmd[1] = lock ? 0x01 : 0x00;
1903 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3);
1904 } else
1905 return 0;
1906}
1907
1908static int mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
1909{
1910 return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries);
1911}
1912
1913static int
1914mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char *buf)
1915{
1916 unsigned long timeout = to + jiffies;
1917 char c;
1918
1919 if (!buf)
1920 buf = &c;
1921
1922 while (inb(stuffp->rreg_status) & MCDX_RBIT_STEN) {
1923 if (time_after(jiffies, timeout))
1924 return -1;
1925 mcdx_delay(stuffp, delay);
1926 }
1927
1928 *buf = (unsigned char) inb(stuffp->rreg_data) & 0xff;
1929
1930 return 0;
1931}
1932
1933static int mcdx_setattentuator(struct s_drive_stuff *stuffp,
1934 struct cdrom_volctrl *vol, int tries)
1935{
1936 char cmd[5];
1937 cmd[0] = 0xae;
1938 cmd[1] = vol->channel0;
1939 cmd[2] = 0;
1940 cmd[3] = vol->channel1;
1941 cmd[4] = 0;
1942
1943 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
1944}
1945
1946MODULE_LICENSE("GPL");
1947MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_X_CDROM_MAJOR);