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