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