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 struct block_device_operations mcdx_bdops =
223 {
224 owner: THIS_MODULE,
225 open: cdrom_open,
226 release: cdrom_release,
227 ioctl: cdrom_ioctl,
228 check_media_change: cdrom_media_changed,
229 };
230
231
232 /* Indirect exported functions. These functions are exported by their
233 addresses, such as mcdx_open and mcdx_close in the
234 structure mcdx_dops. */
235
236 /* ??? exported by the mcdx_sigaction struct */
237 static void mcdx_intr(int, void *, struct pt_regs *);
238
239 /* exported by file_ops */
240 static int mcdx_open(struct cdrom_device_info *cdi, int purpose);
241 static void mcdx_close(struct cdrom_device_info *cdi);
242 static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr);
243 static int mcdx_tray_move(struct cdrom_device_info *cdi, int position);
244 static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock);
245 static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
246 unsigned int cmd, void *arg);
247
248 /* misc internal support functions */
249 static void log2msf(unsigned int, struct cdrom_msf0 *);
250 static unsigned int msf2log(const struct cdrom_msf0 *);
251 static unsigned int uint2bcd(unsigned int);
252 static unsigned int bcd2uint(unsigned char);
253 static char *port(int *);
254 static int irq(int *);
255 static void mcdx_delay(struct s_drive_stuff *, long jifs);
256 static int mcdx_transfer(struct s_drive_stuff *, char *buf, int sector,
257 int nr_sectors);
258 static int mcdx_xfer(struct s_drive_stuff *, char *buf, int sector,
259 int nr_sectors);
260
261 static int mcdx_config(struct s_drive_stuff *, int);
262 static int mcdx_requestversion(struct s_drive_stuff *, struct s_version *,
263 int);
264 static int mcdx_stop(struct s_drive_stuff *, int);
265 static int mcdx_hold(struct s_drive_stuff *, int);
266 static int mcdx_reset(struct s_drive_stuff *, enum resetmodes, int);
267 static int mcdx_setdrivemode(struct s_drive_stuff *, enum drivemodes, int);
268 static int mcdx_setdatamode(struct s_drive_stuff *, enum datamodes, int);
269 static int mcdx_requestsubqcode(struct s_drive_stuff *,
270 struct s_subqcode *, int);
271 static int mcdx_requestmultidiskinfo(struct s_drive_stuff *,
272 struct s_multi *, int);
273 static int mcdx_requesttocdata(struct s_drive_stuff *, struct s_diskinfo *,
274 int);
275 static int mcdx_getstatus(struct s_drive_stuff *, int);
276 static int mcdx_getval(struct s_drive_stuff *, int to, int delay, char *);
277 static int mcdx_talk(struct s_drive_stuff *,
278 const unsigned char *cmd, size_t,
279 void *buffer, size_t size, unsigned int timeout, int);
280 static int mcdx_readtoc(struct s_drive_stuff *);
281 static int mcdx_playtrk(struct s_drive_stuff *, const struct cdrom_ti *);
282 static int mcdx_playmsf(struct s_drive_stuff *, const struct cdrom_msf *);
283 static int mcdx_setattentuator(struct s_drive_stuff *,
284 struct cdrom_volctrl *, int);
285
286 /* static variables ************************************************/
287
288 static int mcdx_blocksizes[MCDX_NDRIVES];
289 static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
290 static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES];
291 static struct s_drive_stuff *mcdx_irq_map[16] = { 0, 0, 0, 0, 0, 0, 0, 0,
292 0, 0, 0, 0, 0, 0, 0, 0
293 };
294 MODULE_PARM(mcdx, "1-4i");
295
296 static struct cdrom_device_ops mcdx_dops = {
297 open:mcdx_open,
298 release:mcdx_close,
299 media_changed:mcdx_media_changed,
300 tray_move:mcdx_tray_move,
301 lock_door:mcdx_lockdoor,
302 audio_ioctl:mcdx_audio_ioctl,
303 capability:CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED |
304 CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,
305 };
306
307 static struct cdrom_device_info mcdx_info = {
308 ops:&mcdx_dops,
309 speed:2,
310 capacity:1,
311 name:"mcdx",
312 };
313
314
315 /* KERNEL INTERFACE FUNCTIONS **************************************/
316
317
mcdx_audio_ioctl(struct cdrom_device_info * cdi,unsigned int cmd,void * arg)318 static int mcdx_audio_ioctl(struct cdrom_device_info *cdi,
319 unsigned int cmd, void *arg)
320 {
321 struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
322
323 if (!stuffp->present)
324 return -ENXIO;
325
326 if (stuffp->xxx) {
327 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
328 stuffp->lastsector = -1;
329 } else {
330 stuffp->lastsector = (CD_FRAMESIZE / 512)
331 * msf2log(&stuffp->di.msf_leadout) - 1;
332 }
333
334 if (stuffp->toc) {
335 kfree(stuffp->toc);
336 stuffp->toc = NULL;
337 if (-1 == mcdx_readtoc(stuffp))
338 return -1;
339 }
340
341 stuffp->xxx = 0;
342 }
343
344 switch (cmd) {
345 case CDROMSTART:{
346 xtrace(IOCTL, "ioctl() START\n");
347 /* Spin up the drive. Don't think we can do this.
348 * For now, ignore it.
349 */
350 return 0;
351 }
352
353 case CDROMSTOP:{
354 xtrace(IOCTL, "ioctl() STOP\n");
355 stuffp->audiostatus = CDROM_AUDIO_INVALID;
356 if (-1 == mcdx_stop(stuffp, 1))
357 return -EIO;
358 return 0;
359 }
360
361 case CDROMPLAYTRKIND:{
362 struct cdrom_ti *ti = (struct cdrom_ti *) arg;
363
364 xtrace(IOCTL, "ioctl() PLAYTRKIND\n");
365 if ((ti->cdti_trk0 < stuffp->di.n_first)
366 || (ti->cdti_trk0 > stuffp->di.n_last)
367 || (ti->cdti_trk1 < stuffp->di.n_first))
368 return -EINVAL;
369 if (ti->cdti_trk1 > stuffp->di.n_last)
370 ti->cdti_trk1 = stuffp->di.n_last;
371 xtrace(PLAYTRK, "ioctl() track %d to %d\n",
372 ti->cdti_trk0, ti->cdti_trk1);
373 return mcdx_playtrk(stuffp, ti);
374 }
375
376 case CDROMPLAYMSF:{
377 struct cdrom_msf *msf = (struct cdrom_msf *) arg;
378
379 xtrace(IOCTL, "ioctl() PLAYMSF\n");
380
381 if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)
382 && (-1 == mcdx_hold(stuffp, 1)))
383 return -EIO;
384
385 msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0);
386 msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0);
387 msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0);
388
389 msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1);
390 msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1);
391 msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1);
392
393 stuffp->stop.dt.minute = msf->cdmsf_min1;
394 stuffp->stop.dt.second = msf->cdmsf_sec1;
395 stuffp->stop.dt.frame = msf->cdmsf_frame1;
396
397 return mcdx_playmsf(stuffp, msf);
398 }
399
400 case CDROMRESUME:{
401 xtrace(IOCTL, "ioctl() RESUME\n");
402 return mcdx_playtrk(stuffp, NULL);
403 }
404
405 case CDROMREADTOCENTRY:{
406 struct cdrom_tocentry *entry =
407 (struct cdrom_tocentry *) arg;
408 struct s_subqcode *tp = NULL;
409 xtrace(IOCTL, "ioctl() READTOCENTRY\n");
410
411 if (-1 == mcdx_readtoc(stuffp))
412 return -1;
413 if (entry->cdte_track == CDROM_LEADOUT)
414 tp = &stuffp->toc[stuffp->di.n_last -
415 stuffp->di.n_first + 1];
416 else if (entry->cdte_track > stuffp->di.n_last
417 || entry->cdte_track < stuffp->di.n_first)
418 return -EINVAL;
419 else
420 tp = &stuffp->toc[entry->cdte_track -
421 stuffp->di.n_first];
422
423 if (NULL == tp)
424 return -EIO;
425 entry->cdte_adr = tp->control;
426 entry->cdte_ctrl = tp->control >> 4;
427 /* Always return stuff in MSF, and let the Uniform cdrom driver
428 worry about what the user actually wants */
429 entry->cdte_addr.msf.minute =
430 bcd2uint(tp->dt.minute);
431 entry->cdte_addr.msf.second =
432 bcd2uint(tp->dt.second);
433 entry->cdte_addr.msf.frame =
434 bcd2uint(tp->dt.frame);
435 return 0;
436 }
437
438 case CDROMSUBCHNL:{
439 struct cdrom_subchnl *sub =
440 (struct cdrom_subchnl *) arg;
441 struct s_subqcode q;
442
443 xtrace(IOCTL, "ioctl() SUBCHNL\n");
444
445 if (-1 == mcdx_requestsubqcode(stuffp, &q, 2))
446 return -EIO;
447
448 xtrace(SUBCHNL, "audiostatus: %x\n",
449 stuffp->audiostatus);
450 sub->cdsc_audiostatus = stuffp->audiostatus;
451 sub->cdsc_adr = q.control;
452 sub->cdsc_ctrl = q.control >> 4;
453 sub->cdsc_trk = bcd2uint(q.tno);
454 sub->cdsc_ind = bcd2uint(q.index);
455
456 xtrace(SUBCHNL, "trk %d, ind %d\n",
457 sub->cdsc_trk, sub->cdsc_ind);
458 /* Always return stuff in MSF, and let the Uniform cdrom driver
459 worry about what the user actually wants */
460 sub->cdsc_absaddr.msf.minute =
461 bcd2uint(q.dt.minute);
462 sub->cdsc_absaddr.msf.second =
463 bcd2uint(q.dt.second);
464 sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
465 sub->cdsc_reladdr.msf.minute =
466 bcd2uint(q.tt.minute);
467 sub->cdsc_reladdr.msf.second =
468 bcd2uint(q.tt.second);
469 sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
470 xtrace(SUBCHNL,
471 "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",
472 sub->cdsc_absaddr.msf.minute,
473 sub->cdsc_absaddr.msf.second,
474 sub->cdsc_absaddr.msf.frame,
475 sub->cdsc_reladdr.msf.minute,
476 sub->cdsc_reladdr.msf.second,
477 sub->cdsc_reladdr.msf.frame);
478
479 return 0;
480 }
481
482 case CDROMREADTOCHDR:{
483 struct cdrom_tochdr *toc =
484 (struct cdrom_tochdr *) arg;
485
486 xtrace(IOCTL, "ioctl() READTOCHDR\n");
487 toc->cdth_trk0 = stuffp->di.n_first;
488 toc->cdth_trk1 = stuffp->di.n_last;
489 xtrace(TOCHDR,
490 "ioctl() track0 = %d, track1 = %d\n",
491 stuffp->di.n_first, stuffp->di.n_last);
492 return 0;
493 }
494
495 case CDROMPAUSE:{
496 xtrace(IOCTL, "ioctl() PAUSE\n");
497 if (stuffp->audiostatus != CDROM_AUDIO_PLAY)
498 return -EINVAL;
499 if (-1 == mcdx_stop(stuffp, 1))
500 return -EIO;
501 stuffp->audiostatus = CDROM_AUDIO_PAUSED;
502 if (-1 ==
503 mcdx_requestsubqcode(stuffp, &stuffp->start,
504 1))
505 return -EIO;
506 return 0;
507 }
508
509 case CDROMMULTISESSION:{
510 struct cdrom_multisession *ms =
511 (struct cdrom_multisession *) arg;
512 xtrace(IOCTL, "ioctl() MULTISESSION\n");
513 /* Always return stuff in LBA, and let the Uniform cdrom driver
514 worry about what the user actually wants */
515 ms->addr.lba = msf2log(&stuffp->multi.msf_last);
516 ms->xa_flag = !!stuffp->multi.multi;
517 xtrace(MS,
518 "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
519 ms->xa_flag, ms->addr.lba,
520 stuffp->multi.msf_last.minute,
521 stuffp->multi.msf_last.second,
522 stuffp->multi.msf_last.frame);
523
524 return 0;
525 }
526
527 case CDROMEJECT:{
528 xtrace(IOCTL, "ioctl() EJECT\n");
529 if (stuffp->users > 1)
530 return -EBUSY;
531 return (mcdx_tray_move(cdi, 1));
532 }
533
534 case CDROMCLOSETRAY:{
535 xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n");
536 return (mcdx_tray_move(cdi, 0));
537 }
538
539 case CDROMVOLCTRL:{
540 struct cdrom_volctrl *volctrl =
541 (struct cdrom_volctrl *) arg;
542 xtrace(IOCTL, "ioctl() VOLCTRL\n");
543
544 #if 0 /* not tested! */
545 /* adjust for the weirdness of workman (md) */
546 /* can't test it (hs) */
547 volctrl.channel2 = volctrl.channel1;
548 volctrl.channel1 = volctrl.channel3 = 0x00;
549 #endif
550 return mcdx_setattentuator(stuffp, volctrl, 2);
551 }
552
553 default:
554 return -EINVAL;
555 }
556 }
557
do_mcdx_request(request_queue_t * q)558 void do_mcdx_request(request_queue_t * q)
559 {
560 int dev;
561 struct s_drive_stuff *stuffp;
562
563 again:
564
565 if (QUEUE_EMPTY) {
566 xtrace(REQUEST, "end_request(0): CURRENT == NULL\n");
567 return;
568 }
569
570 if (CURRENT->rq_status == RQ_INACTIVE) {
571 xtrace(REQUEST,
572 "end_request(0): rq_status == RQ_INACTIVE\n");
573 return;
574 }
575
576 INIT_REQUEST;
577
578 dev = MINOR(CURRENT->rq_dev);
579 stuffp = mcdx_stuffp[dev];
580
581 if ((dev < 0)
582 || (dev >= MCDX_NDRIVES)
583 || !stuffp || (!stuffp->present)) {
584 xwarn("do_request(): bad device: %s\n",
585 kdevname(CURRENT->rq_dev));
586 xtrace(REQUEST, "end_request(0): bad device\n");
587 end_request(0);
588 return;
589 }
590
591 if (stuffp->audio) {
592 xwarn("do_request() attempt to read from audio cd\n");
593 xtrace(REQUEST, "end_request(0): read from audio\n");
594 end_request(0);
595 return;
596 }
597
598 xtrace(REQUEST, "do_request() (%lu + %lu)\n",
599 CURRENT->sector, CURRENT->nr_sectors);
600
601 switch (CURRENT->cmd) {
602 case WRITE:
603 xwarn("do_request(): attempt to write to cd!!\n");
604 xtrace(REQUEST, "end_request(0): write\n");
605 end_request(0);
606 return;
607
608 case READ:
609 stuffp->status = 0;
610 while (CURRENT->nr_sectors) {
611 int i;
612
613 i = mcdx_transfer(stuffp,
614 CURRENT->buffer,
615 CURRENT->sector,
616 CURRENT->nr_sectors);
617
618 if (i == -1) {
619 end_request(0);
620 goto again;
621 }
622 CURRENT->sector += i;
623 CURRENT->nr_sectors -= i;
624 CURRENT->buffer += (i * 512);
625 }
626 end_request(1);
627 goto again;
628
629 xtrace(REQUEST, "end_request(1)\n");
630 end_request(1);
631 break;
632
633 default:
634 panic(MCDX "do_request: unknown command.\n");
635 break;
636 }
637
638 goto again;
639 }
640
mcdx_open(struct cdrom_device_info * cdi,int purpose)641 static int mcdx_open(struct cdrom_device_info *cdi, int purpose)
642 {
643 struct s_drive_stuff *stuffp;
644 xtrace(OPENCLOSE, "open()\n");
645 stuffp = mcdx_stuffp[MINOR(cdi->dev)];
646 if (!stuffp->present)
647 return -ENXIO;
648
649 /* Make the modules looking used ... (thanx bjorn).
650 * But we shouldn't forget to decrement the module counter
651 * on error return */
652
653 /* this is only done to test if the drive talks with us */
654 if (-1 == mcdx_getstatus(stuffp, 1))
655 return -EIO;
656
657 if (stuffp->xxx) {
658
659 xtrace(OPENCLOSE, "open() media changed\n");
660 stuffp->audiostatus = CDROM_AUDIO_INVALID;
661 stuffp->readcmd = 0;
662 xtrace(OPENCLOSE, "open() Request multisession info\n");
663 if (-1 ==
664 mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6))
665 xinfo("No multidiskinfo\n");
666 } else {
667 /* multisession ? */
668 if (!stuffp->multi.multi)
669 stuffp->multi.msf_last.second = 2;
670
671 xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
672 stuffp->multi.multi,
673 stuffp->multi.msf_last.minute,
674 stuffp->multi.msf_last.second,
675 stuffp->multi.msf_last.frame);
676
677 {;
678 } /* got multisession information */
679 /* request the disks table of contents (aka diskinfo) */
680 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) {
681
682 stuffp->lastsector = -1;
683
684 } else {
685
686 stuffp->lastsector = (CD_FRAMESIZE / 512)
687 * msf2log(&stuffp->di.msf_leadout) - 1;
688
689 xtrace(OPENCLOSE,
690 "open() start %d (%02x:%02x.%02x) %d\n",
691 stuffp->di.n_first,
692 stuffp->di.msf_first.minute,
693 stuffp->di.msf_first.second,
694 stuffp->di.msf_first.frame,
695 msf2log(&stuffp->di.msf_first));
696 xtrace(OPENCLOSE,
697 "open() last %d (%02x:%02x.%02x) %d\n",
698 stuffp->di.n_last,
699 stuffp->di.msf_leadout.minute,
700 stuffp->di.msf_leadout.second,
701 stuffp->di.msf_leadout.frame,
702 msf2log(&stuffp->di.msf_leadout));
703 }
704
705 if (stuffp->toc) {
706 xtrace(MALLOC, "open() free old toc @ %p\n",
707 stuffp->toc);
708 kfree(stuffp->toc);
709
710 stuffp->toc = NULL;
711 }
712
713 xtrace(OPENCLOSE, "open() init irq generation\n");
714 if (-1 == mcdx_config(stuffp, 1))
715 return -EIO;
716 #if FALLBACK
717 /* Set the read speed */
718 xwarn("AAA %x AAA\n", stuffp->readcmd);
719 if (stuffp->readerrs)
720 stuffp->readcmd = READ1X;
721 else
722 stuffp->readcmd =
723 stuffp->present | SINGLE ? READ1X : READ2X;
724 xwarn("XXX %x XXX\n", stuffp->readcmd);
725 #else
726 stuffp->readcmd =
727 stuffp->present | SINGLE ? READ1X : READ2X;
728 #endif
729
730 /* try to get the first sector, iff any ... */
731 if (stuffp->lastsector >= 0) {
732 char buf[512];
733 int ans;
734 int tries;
735
736 stuffp->xa = 0;
737 stuffp->audio = 0;
738
739 for (tries = 6; tries; tries--) {
740
741 stuffp->introk = 1;
742
743 xtrace(OPENCLOSE, "open() try as %s\n",
744 stuffp->xa ? "XA" : "normal");
745 /* set data mode */
746 if (-1 == (ans = mcdx_setdatamode(stuffp,
747 stuffp->
748 xa ?
749 MODE2 :
750 MODE1,
751 1))) {
752 /* return -EIO; */
753 stuffp->xa = 0;
754 break;
755 }
756
757 if ((stuffp->audio = e_audio(ans)))
758 break;
759
760 while (0 ==
761 (ans =
762 mcdx_transfer(stuffp, buf, 0, 1)));
763
764 if (ans == 1)
765 break;
766 stuffp->xa = !stuffp->xa;
767 }
768 }
769 /* xa disks will be read in raw mode, others not */
770 if (-1 == mcdx_setdrivemode(stuffp,
771 stuffp->xa ? RAW : COOKED,
772 1))
773 return -EIO;
774 if (stuffp->audio) {
775 xinfo("open() audio disk found\n");
776 } else if (stuffp->lastsector >= 0) {
777 xinfo("open() %s%s disk found\n",
778 stuffp->xa ? "XA / " : "",
779 stuffp->multi.
780 multi ? "Multi Session" : "Single Session");
781 }
782 }
783 stuffp->xxx = 0;
784 stuffp->users++;
785 return 0;
786 }
787
mcdx_close(struct cdrom_device_info * cdi)788 static void mcdx_close(struct cdrom_device_info *cdi)
789 {
790 struct s_drive_stuff *stuffp;
791
792 xtrace(OPENCLOSE, "close()\n");
793
794 stuffp = mcdx_stuffp[MINOR(cdi->dev)];
795
796 --stuffp->users;
797 }
798
mcdx_media_changed(struct cdrom_device_info * cdi,int disc_nr)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
mcdx_setup(char * str)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
mcdx_delay(struct s_drive_stuff * stuff,long jifs)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
mcdx_intr(int irq,void * dev_id,struct pt_regs * regs)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
mcdx_talk(struct s_drive_stuff * stuffp,const unsigned char * cmd,size_t cmdlen,void * buffer,size_t size,unsigned int timeout,int tries)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
__mcdx_init(void)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
mcdx_exit(void)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
mcdx_init_drive(int drive)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", &mcdx_bdops) != 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 devfs_plain_cdrom(&mcdx_info, &mcdx_bdops);
1244 printk(msg);
1245 return 0;
1246 }
1247
mcdx_init(void)1248 int __init mcdx_init(void)
1249 {
1250 int drive;
1251 #ifdef MODULE
1252 xwarn("Version 2.14(hs) for " UTS_RELEASE "\n");
1253 #else
1254 xwarn("Version 2.14(hs) \n");
1255 #endif
1256
1257 xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n");
1258
1259 /* zero the pointer array */
1260 for (drive = 0; drive < MCDX_NDRIVES; drive++)
1261 mcdx_stuffp[drive] = NULL;
1262
1263 /* do the initialisation */
1264 for (drive = 0; drive < MCDX_NDRIVES; drive++) {
1265 switch (mcdx_init_drive(drive)) {
1266 case 2:
1267 return -EIO;
1268 case 1:
1269 break;
1270 }
1271 }
1272 return 0;
1273 }
1274
mcdx_transfer(struct s_drive_stuff * stuffp,char * p,int sector,int nr_sectors)1275 static int mcdx_transfer(struct s_drive_stuff *stuffp,
1276 char *p, int sector, int nr_sectors)
1277 /* This seems to do the actually transfer. But it does more. It
1278 keeps track of errors occurred and will (if possible) fall back
1279 to single speed on error.
1280 Return: -1 on timeout or other error
1281 else status byte (as in stuff->st) */
1282 {
1283 int ans;
1284
1285 ans = mcdx_xfer(stuffp, p, sector, nr_sectors);
1286 return ans;
1287 #if FALLBACK
1288 if (-1 == ans)
1289 stuffp->readerrs++;
1290 else
1291 return ans;
1292
1293 if (stuffp->readerrs && stuffp->readcmd == READ1X) {
1294 xwarn("XXX Already reading 1x -- no chance\n");
1295 return -1;
1296 }
1297
1298 xwarn("XXX Fallback to 1x\n");
1299
1300 stuffp->readcmd = READ1X;
1301 return mcdx_transfer(stuffp, p, sector, nr_sectors);
1302 #endif
1303
1304 }
1305
1306
mcdx_xfer(struct s_drive_stuff * stuffp,char * p,int sector,int nr_sectors)1307 static int mcdx_xfer(struct s_drive_stuff *stuffp,
1308 char *p, int sector, int nr_sectors)
1309 /* This does actually the transfer from the drive.
1310 Return: -1 on timeout or other error
1311 else status byte (as in stuff->st) */
1312 {
1313 int border;
1314 int done = 0;
1315 long timeout;
1316
1317 if (stuffp->audio) {
1318 xwarn("Attempt to read from audio CD.\n");
1319 return -1;
1320 }
1321
1322 if (!stuffp->readcmd) {
1323 xinfo("Can't transfer from missing disk.\n");
1324 return -1;
1325 }
1326
1327 while (stuffp->lock) {
1328 interruptible_sleep_on(&stuffp->lockq);
1329 }
1330
1331 if (stuffp->valid && (sector >= stuffp->pending)
1332 && (sector < stuffp->low_border)) {
1333
1334 /* All (or at least a part of the sectors requested) seems
1335 * to be already requested, so we don't need to bother the
1336 * drive with new requests ...
1337 * Wait for the drive become idle, but first
1338 * check for possible occurred errors --- the drive
1339 * seems to report them asynchronously */
1340
1341
1342 border = stuffp->high_border < (border =
1343 sector + nr_sectors)
1344 ? stuffp->high_border : border;
1345
1346 stuffp->lock = current->pid;
1347
1348 do {
1349
1350 while (stuffp->busy) {
1351
1352 timeout =
1353 interruptible_sleep_on_timeout
1354 (&stuffp->busyq, 5 * HZ);
1355
1356 if (!stuffp->introk) {
1357 xtrace(XFER,
1358 "error via interrupt\n");
1359 } else if (!timeout) {
1360 xtrace(XFER, "timeout\n");
1361 } else if (signal_pending(current)) {
1362 xtrace(XFER, "signal\n");
1363 } else
1364 continue;
1365
1366 stuffp->lock = 0;
1367 stuffp->busy = 0;
1368 stuffp->valid = 0;
1369
1370 wake_up_interruptible(&stuffp->lockq);
1371 xtrace(XFER, "transfer() done (-1)\n");
1372 return -1;
1373 }
1374
1375 /* check if we need to set the busy flag (as we
1376 * expect an interrupt */
1377 stuffp->busy = (3 == (stuffp->pending & 3));
1378
1379 /* Test if it's the first sector of a block,
1380 * there we have to skip some bytes as we read raw data */
1381 if (stuffp->xa && (0 == (stuffp->pending & 3))) {
1382 const int HEAD =
1383 CD_FRAMESIZE_RAW - CD_XA_TAIL -
1384 CD_FRAMESIZE;
1385 insb((unsigned int) stuffp->rreg_data, p,
1386 HEAD);
1387 }
1388
1389 /* now actually read the data */
1390 insb((unsigned int) stuffp->rreg_data, p, 512);
1391
1392 /* test if it's the last sector of a block,
1393 * if so, we have to handle XA special */
1394 if ((3 == (stuffp->pending & 3)) && stuffp->xa) {
1395 char dummy[CD_XA_TAIL];
1396 insb((unsigned int) stuffp->rreg_data,
1397 &dummy[0], CD_XA_TAIL);
1398 }
1399
1400 if (stuffp->pending == sector) {
1401 p += 512;
1402 done++;
1403 sector++;
1404 }
1405 } while (++(stuffp->pending) < border);
1406
1407 stuffp->lock = 0;
1408 wake_up_interruptible(&stuffp->lockq);
1409
1410 } else {
1411
1412 /* The requested sector(s) is/are out of the
1413 * already requested range, so we have to bother the drive
1414 * with a new request. */
1415
1416 static unsigned char cmd[] = {
1417 0,
1418 0, 0, 0,
1419 0, 0, 0
1420 };
1421
1422 cmd[0] = stuffp->readcmd;
1423
1424 /* The numbers held in ->pending, ..., should be valid */
1425 stuffp->valid = 1;
1426 stuffp->pending = sector & ~3;
1427
1428 /* do some sanity checks */
1429 if (stuffp->pending > stuffp->lastsector) {
1430 xwarn
1431 ("transfer() sector %d from nirvana requested.\n",
1432 stuffp->pending);
1433 stuffp->status = MCDX_ST_EOM;
1434 stuffp->valid = 0;
1435 xtrace(XFER, "transfer() done (-1)\n");
1436 return -1;
1437 }
1438
1439 if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE)
1440 > stuffp->lastsector + 1) {
1441 xtrace(XFER, "cut low_border\n");
1442 stuffp->low_border = stuffp->lastsector + 1;
1443 }
1444 if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE)
1445 > stuffp->lastsector + 1) {
1446 xtrace(XFER, "cut high_border\n");
1447 stuffp->high_border = stuffp->lastsector + 1;
1448 }
1449
1450 { /* Convert the sector to be requested to MSF format */
1451 struct cdrom_msf0 pending;
1452 log2msf(stuffp->pending / 4, &pending);
1453 cmd[1] = pending.minute;
1454 cmd[2] = pending.second;
1455 cmd[3] = pending.frame;
1456 }
1457
1458 cmd[6] =
1459 (unsigned
1460 char) ((stuffp->high_border - stuffp->pending) / 4);
1461 xtrace(XFER, "[%2d]\n", cmd[6]);
1462
1463 stuffp->busy = 1;
1464 /* Now really issue the request command */
1465 outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
1466
1467 }
1468 #ifdef AK2
1469 if (stuffp->int_err) {
1470 stuffp->valid = 0;
1471 stuffp->int_err = 0;
1472 return -1;
1473 }
1474 #endif /* AK2 */
1475
1476 stuffp->low_border = (stuffp->low_border +=
1477 done) <
1478 stuffp->high_border ? stuffp->low_border : stuffp->high_border;
1479
1480 return done;
1481 }
1482
1483
1484 /* Access to elements of the mcdx_drive_map members */
1485
port(int * ip)1486 static char *port(int *ip)
1487 {
1488 return (char *) ip[0];
1489 }
irq(int * ip)1490 static int irq(int *ip)
1491 {
1492 return ip[1];
1493 }
1494
1495 /* Misc number converters */
1496
bcd2uint(unsigned char c)1497 static unsigned int bcd2uint(unsigned char c)
1498 {
1499 return (c >> 4) * 10 + (c & 0x0f);
1500 }
1501
uint2bcd(unsigned int ival)1502 static unsigned int uint2bcd(unsigned int ival)
1503 {
1504 return ((ival / 10) << 4) | (ival % 10);
1505 }
1506
log2msf(unsigned int l,struct cdrom_msf0 * pmsf)1507 static void log2msf(unsigned int l, struct cdrom_msf0 *pmsf)
1508 {
1509 l += CD_MSF_OFFSET;
1510 pmsf->minute = uint2bcd(l / 4500), l %= 4500;
1511 pmsf->second = uint2bcd(l / 75);
1512 pmsf->frame = uint2bcd(l % 75);
1513 }
1514
msf2log(const struct cdrom_msf0 * pmsf)1515 static unsigned int msf2log(const struct cdrom_msf0 *pmsf)
1516 {
1517 return bcd2uint(pmsf->frame)
1518 + bcd2uint(pmsf->second) * 75
1519 + bcd2uint(pmsf->minute) * 4500 - CD_MSF_OFFSET;
1520 }
1521
mcdx_readtoc(struct s_drive_stuff * stuffp)1522 int mcdx_readtoc(struct s_drive_stuff *stuffp)
1523 /* Read the toc entries from the CD,
1524 * Return: -1 on failure, else 0 */
1525 {
1526
1527 if (stuffp->toc) {
1528 xtrace(READTOC, "ioctl() toc already read\n");
1529 return 0;
1530 }
1531
1532 xtrace(READTOC, "ioctl() readtoc for %d tracks\n",
1533 stuffp->di.n_last - stuffp->di.n_first + 1);
1534
1535 if (-1 == mcdx_hold(stuffp, 1))
1536 return -1;
1537
1538 xtrace(READTOC, "ioctl() tocmode\n");
1539 if (-1 == mcdx_setdrivemode(stuffp, TOC, 1))
1540 return -EIO;
1541
1542 /* all seems to be ok so far ... malloc */
1543 {
1544 int size;
1545 size =
1546 sizeof(struct s_subqcode) * (stuffp->di.n_last -
1547 stuffp->di.n_first + 2);
1548
1549 xtrace(MALLOC, "ioctl() malloc %d bytes\n", size);
1550 stuffp->toc = kmalloc(size, GFP_KERNEL);
1551 if (!stuffp->toc) {
1552 xwarn("Cannot malloc %d bytes for toc\n", size);
1553 mcdx_setdrivemode(stuffp, DATA, 1);
1554 return -EIO;
1555 }
1556 }
1557
1558 /* now read actually the index */
1559 {
1560 int trk;
1561 int retries;
1562
1563 for (trk = 0;
1564 trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
1565 trk++)
1566 stuffp->toc[trk].index = 0;
1567
1568 for (retries = 300; retries; retries--) { /* why 300? */
1569 struct s_subqcode q;
1570 unsigned int idx;
1571
1572 if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
1573 mcdx_setdrivemode(stuffp, DATA, 1);
1574 return -EIO;
1575 }
1576
1577 idx = bcd2uint(q.index);
1578
1579 if ((idx > 0)
1580 && (idx <= stuffp->di.n_last)
1581 && (q.tno == 0)
1582 && (stuffp->toc[idx - stuffp->di.n_first].
1583 index == 0)) {
1584 stuffp->toc[idx - stuffp->di.n_first] = q;
1585 xtrace(READTOC,
1586 "ioctl() toc idx %d (trk %d)\n",
1587 idx, trk);
1588 trk--;
1589 }
1590 if (trk == 0)
1591 break;
1592 }
1593 memset(&stuffp->
1594 toc[stuffp->di.n_last - stuffp->di.n_first + 1], 0,
1595 sizeof(stuffp->toc[0]));
1596 stuffp->toc[stuffp->di.n_last - stuffp->di.n_first +
1597 1].dt = stuffp->di.msf_leadout;
1598 }
1599
1600 /* unset toc mode */
1601 xtrace(READTOC, "ioctl() undo toc mode\n");
1602 if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
1603 return -EIO;
1604
1605 #if MCDX_DEBUG && READTOC
1606 {
1607 int trk;
1608 for (trk = 0;
1609 trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
1610 trk++)
1611 xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x"
1612 " %02x:%02x.%02x %02x:%02x.%02x\n",
1613 trk + stuffp->di.n_first,
1614 stuffp->toc[trk].control,
1615 stuffp->toc[trk].tno,
1616 stuffp->toc[trk].index,
1617 stuffp->toc[trk].tt.minute,
1618 stuffp->toc[trk].tt.second,
1619 stuffp->toc[trk].tt.frame,
1620 stuffp->toc[trk].dt.minute,
1621 stuffp->toc[trk].dt.second,
1622 stuffp->toc[trk].dt.frame);
1623 }
1624 #endif
1625
1626 return 0;
1627 }
1628
1629 static int
mcdx_playmsf(struct s_drive_stuff * stuffp,const struct cdrom_msf * msf)1630 mcdx_playmsf(struct s_drive_stuff *stuffp, const struct cdrom_msf *msf)
1631 {
1632 unsigned char cmd[7] = {
1633 0, 0, 0, 0, 0, 0, 0
1634 };
1635
1636 if (!stuffp->readcmd) {
1637 xinfo("Can't play from missing disk.\n");
1638 return -1;
1639 }
1640
1641 cmd[0] = stuffp->playcmd;
1642
1643 cmd[1] = msf->cdmsf_min0;
1644 cmd[2] = msf->cdmsf_sec0;
1645 cmd[3] = msf->cdmsf_frame0;
1646 cmd[4] = msf->cdmsf_min1;
1647 cmd[5] = msf->cdmsf_sec1;
1648 cmd[6] = msf->cdmsf_frame1;
1649
1650 xtrace(PLAYMSF, "ioctl(): play %x "
1651 "%02x:%02x:%02x -- %02x:%02x:%02x\n",
1652 cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]);
1653
1654 outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
1655
1656 if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) {
1657 xwarn("playmsf() timeout\n");
1658 return -1;
1659 }
1660
1661 stuffp->audiostatus = CDROM_AUDIO_PLAY;
1662 return 0;
1663 }
1664
1665 static int
mcdx_playtrk(struct s_drive_stuff * stuffp,const struct cdrom_ti * ti)1666 mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti)
1667 {
1668 struct s_subqcode *p;
1669 struct cdrom_msf msf;
1670
1671 if (-1 == mcdx_readtoc(stuffp))
1672 return -1;
1673
1674 if (ti)
1675 p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first];
1676 else
1677 p = &stuffp->start;
1678
1679 msf.cdmsf_min0 = p->dt.minute;
1680 msf.cdmsf_sec0 = p->dt.second;
1681 msf.cdmsf_frame0 = p->dt.frame;
1682
1683 if (ti) {
1684 p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1];
1685 stuffp->stop = *p;
1686 } else
1687 p = &stuffp->stop;
1688
1689 msf.cdmsf_min1 = p->dt.minute;
1690 msf.cdmsf_sec1 = p->dt.second;
1691 msf.cdmsf_frame1 = p->dt.frame;
1692
1693 return mcdx_playmsf(stuffp, &msf);
1694 }
1695
1696
1697 /* Drive functions ************************************************/
1698
mcdx_tray_move(struct cdrom_device_info * cdi,int position)1699 static int mcdx_tray_move(struct cdrom_device_info *cdi, int position)
1700 {
1701 struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
1702
1703 if (!stuffp->present)
1704 return -ENXIO;
1705 if (!(stuffp->present & DOOR))
1706 return -ENOSYS;
1707
1708 if (position) /* 1: eject */
1709 return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3);
1710 else /* 0: close */
1711 return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3);
1712 return 1;
1713 }
1714
mcdx_stop(struct s_drive_stuff * stuffp,int tries)1715 static int mcdx_stop(struct s_drive_stuff *stuffp, int tries)
1716 {
1717 return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries);
1718 }
1719
mcdx_hold(struct s_drive_stuff * stuffp,int tries)1720 static int mcdx_hold(struct s_drive_stuff *stuffp, int tries)
1721 {
1722 return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries);
1723 }
1724
mcdx_requestsubqcode(struct s_drive_stuff * stuffp,struct s_subqcode * sub,int tries)1725 static int mcdx_requestsubqcode(struct s_drive_stuff *stuffp,
1726 struct s_subqcode *sub, int tries)
1727 {
1728 char buf[11];
1729 int ans;
1730
1731 if (-1 == (ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf),
1732 2 * HZ, tries)))
1733 return -1;
1734 sub->control = buf[1];
1735 sub->tno = buf[2];
1736 sub->index = buf[3];
1737 sub->tt.minute = buf[4];
1738 sub->tt.second = buf[5];
1739 sub->tt.frame = buf[6];
1740 sub->dt.minute = buf[8];
1741 sub->dt.second = buf[9];
1742 sub->dt.frame = buf[10];
1743
1744 return ans;
1745 }
1746
mcdx_requestmultidiskinfo(struct s_drive_stuff * stuffp,struct s_multi * multi,int tries)1747 static int mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp,
1748 struct s_multi *multi, int tries)
1749 {
1750 char buf[5];
1751 int ans;
1752
1753 if (stuffp->present & MULTI) {
1754 ans =
1755 mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ,
1756 tries);
1757 multi->multi = buf[1];
1758 multi->msf_last.minute = buf[2];
1759 multi->msf_last.second = buf[3];
1760 multi->msf_last.frame = buf[4];
1761 return ans;
1762 } else {
1763 multi->multi = 0;
1764 return 0;
1765 }
1766 }
1767
mcdx_requesttocdata(struct s_drive_stuff * stuffp,struct s_diskinfo * info,int tries)1768 static int mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info,
1769 int tries)
1770 {
1771 char buf[9];
1772 int ans;
1773 ans =
1774 mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries);
1775 if (ans == -1) {
1776 info->n_first = 0;
1777 info->n_last = 0;
1778 } else {
1779 info->n_first = bcd2uint(buf[1]);
1780 info->n_last = bcd2uint(buf[2]);
1781 info->msf_leadout.minute = buf[3];
1782 info->msf_leadout.second = buf[4];
1783 info->msf_leadout.frame = buf[5];
1784 info->msf_first.minute = buf[6];
1785 info->msf_first.second = buf[7];
1786 info->msf_first.frame = buf[8];
1787 }
1788 return ans;
1789 }
1790
mcdx_setdrivemode(struct s_drive_stuff * stuffp,enum drivemodes mode,int tries)1791 static int mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode,
1792 int tries)
1793 {
1794 char cmd[2];
1795 int ans;
1796
1797 xtrace(HW, "setdrivemode() %d\n", mode);
1798
1799 if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries)))
1800 return -1;
1801
1802 switch (mode) {
1803 case TOC:
1804 cmd[1] |= 0x04;
1805 break;
1806 case DATA:
1807 cmd[1] &= ~0x04;
1808 break;
1809 case RAW:
1810 cmd[1] |= 0x40;
1811 break;
1812 case COOKED:
1813 cmd[1] &= ~0x40;
1814 break;
1815 default:
1816 break;
1817 }
1818 cmd[0] = 0x50;
1819 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1820 }
1821
mcdx_setdatamode(struct s_drive_stuff * stuffp,enum datamodes mode,int tries)1822 static int mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode,
1823 int tries)
1824 {
1825 unsigned char cmd[2] = { 0xa0 };
1826 xtrace(HW, "setdatamode() %d\n", mode);
1827 switch (mode) {
1828 case MODE0:
1829 cmd[1] = 0x00;
1830 break;
1831 case MODE1:
1832 cmd[1] = 0x01;
1833 break;
1834 case MODE2:
1835 cmd[1] = 0x02;
1836 break;
1837 default:
1838 return -EINVAL;
1839 }
1840 return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries);
1841 }
1842
mcdx_config(struct s_drive_stuff * stuffp,int tries)1843 static int mcdx_config(struct s_drive_stuff *stuffp, int tries)
1844 {
1845 char cmd[4];
1846
1847 xtrace(HW, "config()\n");
1848
1849 cmd[0] = 0x90;
1850
1851 cmd[1] = 0x10; /* irq enable */
1852 cmd[2] = 0x05; /* pre, err irq enable */
1853
1854 if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries))
1855 return -1;
1856
1857 cmd[1] = 0x02; /* dma select */
1858 cmd[2] = 0x00; /* no dma */
1859
1860 return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries);
1861 }
1862
mcdx_requestversion(struct s_drive_stuff * stuffp,struct s_version * ver,int tries)1863 static int mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver,
1864 int tries)
1865 {
1866 char buf[3];
1867 int ans;
1868
1869 if (-1 == (ans = mcdx_talk(stuffp, "\xdc",
1870 1, buf, sizeof(buf), 2 * HZ, tries)))
1871 return ans;
1872
1873 ver->code = buf[1];
1874 ver->ver = buf[2];
1875
1876 return ans;
1877 }
1878
mcdx_reset(struct s_drive_stuff * stuffp,enum resetmodes mode,int tries)1879 static int mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
1880 {
1881 if (mode == HARD) {
1882 outb(0, (unsigned int) stuffp->wreg_chn); /* no dma, no irq -> hardware */
1883 outb(0, (unsigned int) stuffp->wreg_reset); /* hw reset */
1884 return 0;
1885 } else
1886 return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries);
1887 }
1888
mcdx_lockdoor(struct cdrom_device_info * cdi,int lock)1889 static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock)
1890 {
1891 struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];
1892 char cmd[2] = { 0xfe };
1893
1894 if (!(stuffp->present & DOOR))
1895 return -ENOSYS;
1896 if (stuffp->present & DOOR) {
1897 cmd[1] = lock ? 0x01 : 0x00;
1898 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3);
1899 } else
1900 return 0;
1901 }
1902
mcdx_getstatus(struct s_drive_stuff * stuffp,int tries)1903 static int mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
1904 {
1905 return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries);
1906 }
1907
1908 static int
mcdx_getval(struct s_drive_stuff * stuffp,int to,int delay,char * buf)1909 mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char *buf)
1910 {
1911 unsigned long timeout = to + jiffies;
1912 char c;
1913
1914 if (!buf)
1915 buf = &c;
1916
1917 while (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_STEN) {
1918 if (time_after(jiffies, timeout))
1919 return -1;
1920 mcdx_delay(stuffp, delay);
1921 }
1922
1923 *buf = (unsigned char) inb((unsigned int) stuffp->rreg_data) & 0xff;
1924
1925 return 0;
1926 }
1927
mcdx_setattentuator(struct s_drive_stuff * stuffp,struct cdrom_volctrl * vol,int tries)1928 static int mcdx_setattentuator(struct s_drive_stuff *stuffp,
1929 struct cdrom_volctrl *vol, int tries)
1930 {
1931 char cmd[5];
1932 cmd[0] = 0xae;
1933 cmd[1] = vol->channel0;
1934 cmd[2] = 0;
1935 cmd[3] = vol->channel1;
1936 cmd[4] = 0;
1937
1938 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries);
1939 }
1940
1941 MODULE_LICENSE("GPL");
1942