This source file includes following definitions.
- mcdx_ioctl
- do_mcdx_request
- mcdx_open
- mcdx_close
- check_mcdx_media_change
- mcdx_setup
- mcdx_delay
- mcdx_intr
- mcdx_talk
- init_module
- cleanup_module
- trace
- warn
- mcdx_init
- mcdx_transfer
- port
- irq
- bcd2uint
- uint2bcd
- log2msf
- msf2log
- mcdx_readtoc
- mcdx_closedoor
- mcdx_stop
- mcdx_eject
- mcdx_requestsubqcode
- mcdx_requestmultidiskinfo
- mcdx_requesttocdata
- mcdx_setdrivemode
- mcdx_setdatamode
- mcdx_config
- mcdx_requestversion
- mcdx_reset
- mcdx_lockdoor
- mcdx_getstatus
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 #if RCS
36 static const char *mcdx_c_version
37 = "$Id: mcdx.c,v 1.2 1995/06/18 18:00:53 heiko Exp $";
38 #endif
39
40 #include <linux/config.h>
41 #ifdef MODULE
42 #include <linux/module.h>
43 #include <linux/version.h>
44 #ifndef CONFIG_MODVERSIONS
45 char kernel_version[]=UTS_RELEASE;
46 #endif
47 #else
48 #define MOD_INC_USE_COUNT
49 #define MOD_DEC_USE_COUNT
50 #define MOD_IN_USE 1
51 #endif MODULE
52
53 #include <linux/errno.h>
54 #include <linux/signal.h>
55 #include <linux/sched.h>
56 #include <linux/timer.h>
57 #include <linux/fs.h>
58 #include <linux/kernel.h>
59 #include <linux/cdrom.h>
60 #include <linux/ioport.h>
61 #include <linux/mm.h>
62 #include <linux/malloc.h>
63 #include <asm/system.h>
64 #include <asm/io.h>
65 #include <asm/segment.h>
66
67 #define MAJOR_NR MITSUMI_X_CDROM_MAJOR
68 #include "blk.h"
69 #define mcdx_drive_map mcdx
70 #include <linux/mcdx.h>
71
72
73
74 const int REQUEST_SIZE = 200;
75 const int DIRECT_SIZE = 200;
76
77 enum drivemodes { TOC, DATA, RAW, COOKED };
78 enum datamodes { MODE0, MODE1, MODE2 };
79 enum resetmodes { SOFT, HARD };
80
81 const int SINGLE = 0x01;
82 const int DOUBLE = 0x02;
83 const int DOOR = 0x04;
84 const int MULTI = 0x08;
85
86 const unsigned char READSSPEED = 0xc0;
87 const unsigned char READDSPEED = 0xc1;
88
89
90
91 struct s_msf {
92 unsigned char minute;
93 unsigned char second;
94 unsigned char frame;
95 };
96
97 struct s_subqcode {
98 unsigned char control;
99 unsigned char tno;
100 unsigned char index;
101 struct s_msf tt;
102 struct s_msf dt;
103 };
104
105 struct s_diskinfo {
106 unsigned int n_first;
107 unsigned int n_last;
108 struct s_msf msf_leadout;
109 struct s_msf msf_first;
110 };
111
112 struct s_multi {
113 unsigned char multi;
114 struct s_msf msf_last;
115 };
116
117 struct s_version {
118 unsigned char code;
119 unsigned char ver;
120 };
121
122
123
124 struct s_drive_stuff {
125
126 struct wait_queue *busyq;
127 struct wait_queue *lockq;
128 struct wait_queue *sleepq;
129
130
131 volatile int introk;
132 volatile int busy;
133 volatile int lock;
134
135
136 struct s_diskinfo di;
137 struct s_multi multi;
138 struct s_subqcode* toc;
139 struct s_subqcode start;
140 struct s_subqcode stop;
141 int xa;
142 int audio;
143 int audiostatus;
144
145
146 volatile int valid;
147 volatile int pending;
148 volatile int off_direct;
149 volatile int off_requested;
150
151
152 void* wreg_data;
153 void* wreg_reset;
154 void* wreg_hcon;
155 void* wreg_chn;
156 void* rreg_data;
157 void* rreg_status;
158
159 int irq;
160 int minor;
161 int present;
162 char readcmd;
163 unsigned long changed;
164 int users;
165 int lastsector;
166 int errno;
167
168 };
169
170
171
172
173
174
175
176
177 unsigned long mcdx_init(unsigned long mem_start, unsigned long mem_end);
178 void do_mcdx_request(void);
179
180 int check_mcdx_media_change(dev_t);
181
182
183 void mcdx_setup(char *, int *);
184
185
186
187
188
189
190 static void mcdx_intr(int, struct pt_regs*);
191
192
193 static int mcdx_open(struct inode*, struct file*);
194 static void mcdx_close(struct inode*, struct file*);
195 static int mcdx_ioctl(struct inode*, struct file*, unsigned int, unsigned long);
196
197
198 static void log2msf(unsigned int, struct s_msf*);
199 static unsigned int msf2log(const struct s_msf*);
200 static unsigned int uint2bcd(unsigned int);
201 static unsigned int bcd2uint(unsigned char);
202 #if MCDX_DEBUG
203 static void TRACE((int level, const char* fmt, ...));
204 #endif
205 #ifndef NOWARN
206 static void WARN((const char* fmt, ...));
207 #endif
208 static char *port(int*);
209 static int irq(int*);
210 static void mcdx_delay(struct s_drive_stuff*, long jifs);
211 static int mcdx_transfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);
212
213 static int mcdx_config(struct s_drive_stuff*, int);
214 static int mcdx_closedoor(struct s_drive_stuff*, int);
215 static int mcdx_requestversion(struct s_drive_stuff*, struct s_version*, int);
216 static int mcdx_lockdoor(struct s_drive_stuff*, int, int);
217 #if 0
218 static int mcdx_getstatus(struct s_drive_stuff*, int);
219 #endif
220 static int mcdx_stop(struct s_drive_stuff*, int);
221 static int mcdx_reset(struct s_drive_stuff*, enum resetmodes, int);
222 static int mcdx_eject(struct s_drive_stuff*, int);
223 static int mcdx_setdrivemode(struct s_drive_stuff*, enum drivemodes, int);
224 static int mcdx_setdatamode(struct s_drive_stuff*, enum datamodes, int);
225 static int mcdx_requestsubqcode(struct s_drive_stuff*, struct s_subqcode*, int);
226 static int mcdx_requestmultidiskinfo(struct s_drive_stuff*, struct s_multi*, int);
227 static int mcdx_requesttocdata(struct s_drive_stuff*, struct s_diskinfo*, int);
228
229 static int mcdx_talk(struct s_drive_stuff*,
230 const unsigned char* cmd, size_t, void *buffer,
231 size_t size, unsigned int timeout, int);
232 static int mcdx_readtoc(struct s_drive_stuff*);
233
234
235
236 static int dummy0;
237 static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;
238 static struct s_drive_stuff* mcdx_stuffp[MCDX_NDRIVES];
239 static struct s_drive_stuff* mcdx_irq_map[16] =
240 {0, 0, 0, 0, 0, 0, 0, 0,
241 0, 0, 0, 0, 0, 0, 0, 0};
242
243 static struct file_operations mcdx_fops = {
244 NULL,
245 block_read,
246 block_write,
247 NULL,
248 NULL,
249 mcdx_ioctl,
250 NULL,
251 mcdx_open,
252 mcdx_close,
253 NULL,
254 NULL,
255 check_mcdx_media_change,
256 NULL
257 };
258
259
260
261 static int
262 mcdx_ioctl(
263 struct inode* ip, struct file* fp,
264 unsigned int cmd, unsigned long arg)
265 {
266 struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
267
268 if (!stuffp->present) return -ENXIO;
269 if (!ip) return -EINVAL;
270
271 switch (cmd) {
272 case CDROMSTART: {
273 TRACE((IOCTL, "ioctl() START\n"));
274 return 0;
275 }
276 case CDROMSTOP: {
277 TRACE((IOCTL, "ioctl() STOP\n"));
278 if (-1 == mcdx_stop(stuffp, 1))
279 return -EIO;
280 return 0;
281 }
282 case CDROMPLAYTRKIND: {
283 return -EINVAL;
284
285
286
287
288
289
290
291
292
293
294
295
296
297 }
298
299 case CDROMREADTOCENTRY: {
300 struct cdrom_tocentry entry;
301 struct s_subqcode *tp = NULL;
302 int ans;
303
304 TRACE((IOCTL, "ioctl() READTOCENTRY\n"));
305
306 if ((stuffp->toc == NULL) && (0 != (ans = mcdx_readtoc(stuffp)))) return ans;
307
308 if ((ans = verify_area(VERIFY_READ, (void *) arg, sizeof(entry)))) return ans;
309 memcpy_fromfs(&entry, (void *) arg, sizeof(entry));
310
311 if (entry.cdte_track == CDROM_LEADOUT)
312 tp = &stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1];
313 else if (entry.cdte_track > stuffp->di.n_last
314 || entry.cdte_track < stuffp->di.n_first) return -EINVAL;
315 else tp = &stuffp->toc[entry.cdte_track - stuffp->di.n_first];
316
317 if (NULL == tp) WARN(("FATAL.\n"));
318
319 entry.cdte_adr = tp->control;
320 entry.cdte_ctrl = tp->control >> 4;
321
322 if (entry.cdte_format == CDROM_MSF) {
323 entry.cdte_addr.msf.minute = bcd2uint(tp->dt.minute);
324 entry.cdte_addr.msf.second = bcd2uint(tp->dt.second);
325 entry.cdte_addr.msf.frame = bcd2uint(tp->dt.frame);
326 } else if (entry.cdte_format == CDROM_LBA)
327 entry.cdte_addr.lba = msf2log(&tp->dt);
328 else return -EINVAL;
329
330 if ((ans = verify_area(VERIFY_WRITE, (void*) arg, sizeof(entry)))) return ans;
331 memcpy_tofs((void*) arg, &entry, sizeof(entry));
332
333 return 0;
334 }
335
336 case CDROMSUBCHNL: {
337 int ans;
338 struct cdrom_subchnl sub;
339 struct s_subqcode q;
340 TRACE((IOCTL, "ioctl() SUBCHNL\n"));
341
342 if ((ans = verify_area(VERIFY_READ, (void*) arg, sizeof(sub)))) return ans;
343 memcpy_fromfs(&sub, (void*) arg, sizeof(sub));
344
345 if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) return -EIO;
346
347 TRACE((IOCTL, "audiostatus: %x\n", stuffp->audiostatus));
348 sub.cdsc_audiostatus = stuffp->audiostatus;
349 sub.cdsc_adr = q.control;
350 sub.cdsc_ctrl = q.control >> 4;
351 sub.cdsc_trk = bcd2uint(q.tno);
352 sub.cdsc_ind = bcd2uint(q.index);
353
354 if (sub.cdsc_format == CDROM_LBA) {
355 sub.cdsc_absaddr.lba = msf2log(&q.dt);
356 sub.cdsc_reladdr.lba = msf2log(&q.tt);
357 } else if (sub.cdsc_format == CDROM_MSF) {
358 sub.cdsc_absaddr.msf.minute = bcd2uint(q.dt.minute);
359 sub.cdsc_absaddr.msf.second = bcd2uint(q.dt.second);
360 sub.cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);
361 sub.cdsc_reladdr.msf.minute = bcd2uint(q.tt.minute);
362 sub.cdsc_reladdr.msf.second = bcd2uint(q.tt.second);
363 sub.cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);
364 } else return -EINVAL;
365
366 if ((ans = verify_area(VERIFY_WRITE, (void*) arg, sizeof(sub))))
367 return ans;
368 memcpy_tofs((void*) arg, &sub, sizeof(sub));
369
370 return 0;
371 }
372
373 case CDROMREADTOCHDR: {
374 struct cdrom_tochdr toc;
375 int ans;
376 TRACE((IOCTL, "ioctl() READTOCHDR\n"));
377 if ((ans = verify_area(VERIFY_WRITE, (void*) arg, sizeof toc)))
378 return ans;
379 toc.cdth_trk0 = stuffp->di.n_first;
380 toc.cdth_trk1 = stuffp->di.n_last;
381 memcpy_tofs((void*) arg, &toc, sizeof toc);
382 TRACE((IOCTL, "ioctl() track0 = %d, track1 = %d\n",
383 stuffp->di.n_first, stuffp->di.n_last));
384 return 0;
385 }
386
387 case CDROMPAUSE: {
388 TRACE((IOCTL, "ioctl() PAUSE\n"));
389 if (stuffp->audiostatus != CDROM_AUDIO_PLAY) return -EINVAL;
390 if (-1 == mcdx_stop(stuffp, 1)) return -EIO;
391 if (-1 == mcdx_requestsubqcode(stuffp, &stuffp->start, 1))
392 return -EIO;
393 return 0;
394 }
395 case CDROMMULTISESSION: {
396 int ans;
397 struct cdrom_multisession ms;
398 TRACE((IOCTL, "ioctl() MULTISESSION\n"));
399 if (0 != (ans = verify_area(VERIFY_READ, (void*) arg,
400 sizeof(struct cdrom_multisession))))
401 return ans;
402
403 memcpy_fromfs(&ms, (void*) arg, sizeof(struct cdrom_multisession));
404 if (ms.addr_format == CDROM_MSF) {
405 ms.addr.msf.minute = bcd2uint(stuffp->multi.msf_last.minute);
406 ms.addr.msf.second = bcd2uint(stuffp->multi.msf_last.second);
407 ms.addr.msf.frame = bcd2uint(stuffp->multi.msf_last.frame);
408 } else if (ms.addr_format == CDROM_LBA)
409 ms.addr.lba = msf2log(&stuffp->multi.msf_last);
410 else
411 return -EINVAL;
412 ms.xa_flag = stuffp->xa;
413
414 if (0 != (ans = verify_area(VERIFY_WRITE, (void*) arg,
415 sizeof(struct cdrom_multisession))))
416 return ans;
417
418 memcpy_tofs((void*) arg, &ms, sizeof(struct cdrom_multisession));
419 if (ms.addr_format == CDROM_MSF)
420 TRACE((IOCTL,
421 "ioctl() (%d, %02x:%02x.%02x [%02x:%02x.%02x])\n",
422 ms.xa_flag,
423 ms.addr.msf.minute,
424 ms.addr.msf.second,
425 ms.addr.msf.frame,
426 stuffp->multi.msf_last.minute,
427 stuffp->multi.msf_last.second,
428 stuffp->multi.msf_last.frame));
429 else
430 {
431 dummy0=0;
432 TRACE((IOCTL,
433 "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n",
434 ms.xa_flag,
435 ms.addr.lba,
436 stuffp->multi.msf_last.minute,
437 stuffp->multi.msf_last.second,
438 stuffp->multi.msf_last.frame));
439 }
440 return 0;
441 }
442
443 case CDROMEJECT: {
444 TRACE((IOCTL, "ioctl() EJECT\n"));
445 if (stuffp->users > 1) return -EBUSY;
446 if (-1 == mcdx_eject(stuffp, 1)) return -EIO;
447 return 0;
448 }
449
450 default:
451 WARN(("ioctl(): unknown request 0x%04x\n", cmd));
452 return -EINVAL;
453 }
454 }
455
456 void do_mcdx_request()
457 {
458 int dev;
459 struct s_drive_stuff *stuffp;
460
461 again:
462
463 TRACE((REQUEST, "do_request()\n"));
464
465 if ((CURRENT == NULL) || (CURRENT->dev < 0)) {
466 TRACE((REQUEST, "do_request() done\n"));
467 return;
468 }
469
470 stuffp = mcdx_stuffp[MINOR(CURRENT->dev)];
471 TRACE((REQUEST, "do_request() stuffp = %p\n", stuffp));
472
473 INIT_REQUEST;
474 dev = MINOR(CURRENT->dev);
475
476 if ((dev < 0) || (dev >= MCDX_NDRIVES) || (!stuffp->present)) {
477 printk(MCD "do_request(): bad device: 0x%04x\n", CURRENT->dev);
478 end_request(0);
479 goto again;
480 }
481
482 if (stuffp->audio) {
483 WARN(("do_request() attempt to read from audio cd\n"));
484 end_request(0);
485 goto again;
486 }
487
488 switch (CURRENT->cmd) {
489 case WRITE:
490 printk(MCD ": do_request(): attempt to write to cd!!\n");
491 end_request(0);
492 break;
493
494 case READ:
495 stuffp->errno = 0;
496 while (CURRENT->nr_sectors) {
497 int i;
498
499 if (-1 == (i = mcdx_transfer(
500 stuffp,
501 CURRENT->buffer,
502 CURRENT->sector,
503 CURRENT->nr_sectors))) {
504 printk(MCD " read error\n");
505 if (stuffp->errno == MCDX_EOM) {
506 CURRENT->sector += CURRENT->nr_sectors;
507 CURRENT->nr_sectors = 0;
508 }
509 end_request(0);
510 goto again;
511 }
512 CURRENT->sector += i;
513 CURRENT->nr_sectors -= i;
514 CURRENT->buffer += (i * 512);
515
516 }
517
518 end_request(1);
519 break;
520
521 default:
522 panic(MCD "do_request: unknown command.\n");
523 break;
524 }
525
526 goto again;
527 }
528
529 static int
530 mcdx_open(struct inode *ip, struct file *fp)
531 {
532 struct s_drive_stuff *stuffp;
533 static unsigned long changed = 0;
534
535 TRACE((OPENCLOSE, "open()\n"));
536 stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
537 if (!stuffp->present) return -ENXIO;
538
539
540
541 if (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_DOOR)
542 mcdx_closedoor(stuffp, 1);
543
544
545 if (changed < stuffp->changed) {
546
547 TRACE((OPENCLOSE, "open() media changed\n"));
548
549
550
551
552
553
554 {
555 TRACE((OPENCLOSE, "open() Request multisession info\n"));
556 if (-1 == mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6))
557 return -EIO;
558
559 if (stuffp->multi.multi > 2)
560 WARN(("open() unknown multisession value (%d)\n", stuffp->multi.multi));
561
562
563 if (!stuffp->multi.multi)
564 stuffp->multi.msf_last.second = 2;
565
566 TRACE((OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n",
567 stuffp->multi.multi,
568 stuffp->multi.msf_last.minute,
569 stuffp->multi.msf_last.second,
570 stuffp->multi.msf_last.frame));
571 }
572
573
574
575 if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) return -EIO;
576
577 stuffp->lastsector = (CD_FRAMESIZE / 512) * msf2log(&stuffp->di.msf_leadout) - 1;
578
579 TRACE((OPENCLOSE, "open() start %d (%02x:%02x.%02x) %d\n",
580 stuffp->di.n_first,
581 stuffp->di.msf_first.minute,
582 stuffp->di.msf_first.second,
583 stuffp->di.msf_first.frame,
584 msf2log(&stuffp->di.msf_first)));
585 TRACE((OPENCLOSE, "open() last %d (%02x:%02x.%02x) %d\n",
586 stuffp->di.n_last,
587 stuffp->di.msf_leadout.minute,
588 stuffp->di.msf_leadout.second,
589 stuffp->di.msf_leadout.frame,
590 msf2log(&stuffp->di.msf_leadout)));
591
592 if (stuffp->toc) {
593 TRACE((MALLOC, "open() free toc @ %p\n", stuffp->toc));
594 kfree(stuffp->toc);
595 }
596 stuffp->toc = NULL;
597
598 TRACE((OPENCLOSE, "open() init irq generation\n"));
599 if (-1 == mcdx_config(stuffp, 1)) return -EIO;
600
601
602 {
603 char buf[512];
604 int ans;
605 int tries;
606
607 stuffp->xa = 0;
608 stuffp->audio = 0;
609
610 for (tries = 6; tries; tries--) {
611 TRACE((OPENCLOSE, "open() try as %s\n",
612 stuffp->xa ? "XA" : "normal"));
613
614
615 if (-1 == (ans = mcdx_setdatamode(stuffp,
616 stuffp->xa ? MODE2 : MODE1, 1)))
617 return -EIO;
618
619 if ((stuffp->audio = e_audio(ans))) break;
620
621 while (0 == (ans = mcdx_transfer(stuffp, buf, 0, 1)))
622 ;
623
624 if (ans == 1) break;
625 stuffp->xa = !stuffp->xa;
626 }
627 if (!tries) return -EIO;
628 }
629
630
631 if (-1 == mcdx_setdrivemode(stuffp,
632 stuffp->xa ? RAW : COOKED, 1))
633 return -EIO;
634
635 if (stuffp->audio) {
636 WARN(("open() audio disk found\n"));
637 } else {
638 WARN(("open() %s%s disk found\n",
639 stuffp->xa ? "XA / " : "",
640 stuffp->multi.multi ? "Multi Session" : "Single Session"));
641 }
642
643 changed = stuffp->changed;
644 }
645
646 if (-1 == mcdx_lockdoor(stuffp, 1, 1)) return -EIO;
647
648 stuffp->users++;
649 MOD_INC_USE_COUNT;
650 return 0;
651 }
652
653 static void
654 mcdx_close(struct inode *ip, struct file *fp)
655 {
656 struct s_drive_stuff *stuffp;
657
658 TRACE((OPENCLOSE, "close()\n"));
659
660 stuffp = mcdx_stuffp[MINOR(ip->i_rdev)];
661
662 if (0 == --stuffp->users) {
663 sync_dev(ip->i_rdev);
664
665
666 invalidate_buffers(ip->i_rdev);
667
668 if (-1 == mcdx_lockdoor(stuffp, 0, 1))
669 printk(MCD ": Cannot unlock the door\n");
670 }
671 MOD_DEC_USE_COUNT;
672
673 return;
674 }
675
676 int check_mcdx_media_change(dev_t full_dev)
677
678
679
680
681
682 {
683 printk(MCD ":: check_mcdx_media_change(0x%x) called\n", full_dev);
684 return 0;
685 }
686
687 void mcdx_setup(char *str, int *pi)
688 {
689 #if MCDX_DEBUG
690 printk(MCD ":: setup(%s, %d) called\n",
691 str, pi[0]);
692 #endif
693 }
694
695
696
697 static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
698
699
700
701
702 {
703 unsigned long tout = jiffies + jifs;
704
705 if (jifs < 0) return;
706
707 #ifdef MODULE
708
709 current->timeout = tout;
710 while (current->timeout)
711 interruptible_sleep_on(&stuff->sleepq);
712 #else
713
714 if (stuff->present) {
715 current->state = TASK_INTERRUPTIBLE;
716 current->timeout = tout;
717 interruptible_sleep_on(&stuff->sleepq);
718 } else
719 while (jiffies < tout) {
720 current->timeout = jiffies;
721 schedule();
722 }
723 #endif MODULE
724 }
725
726 static void
727 mcdx_intr(int irq, struct pt_regs* regs)
728 {
729 struct s_drive_stuff *stuffp;
730 unsigned char x;
731
732 stuffp = mcdx_irq_map[irq];
733
734 if (!stuffp->busy) {
735 WARN(("intr() unexpected interrupt @ irq %d\n", irq));
736 return;
737 }
738
739
740 if (0 == (stuffp->introk =
741 (~(x = inb((unsigned int) stuffp->rreg_status)) & MCDX_RBIT_DTEN)))
742 TRACE((IRQ, "intr() irq %d failed, status %02x %02x\n",
743 irq, x, inb((unsigned int) stuffp->rreg_data)));
744 else
745 {
746 dummy0=0;
747 TRACE((IRQ, "irq() irq %d ok, status %02x\n", irq, x));
748 }
749 stuffp->busy = 0;
750 wake_up_interruptible(&stuffp->busyq);
751 }
752
753
754 static int
755 mcdx_talk (
756 struct s_drive_stuff *stuffp,
757 const unsigned char *cmd, size_t cmdlen,
758 void *buffer, size_t size,
759 unsigned int timeout, int tries)
760
761
762
763 {
764 const DELAY = 1;
765 char c;
766 int st;
767
768 if (!buffer || size == 0) buffer = &c, size = 1;
769
770 while (stuffp->lock)
771 interruptible_sleep_on(&stuffp->lockq);
772
773 stuffp->lock = 1;
774 stuffp->valid = 0;
775
776 #if MCDX_DEBUG & TALK
777 {
778 unsigned char i;
779 TRACE((TALK, "talk() res.size %d, command 0x%02x",
780 size, (unsigned char) cmd[0]));
781 for (i = 1; i < cmdlen; i++) printk(" 0x%02x", cmd[i]);
782 printk("\n");
783 }
784 #endif
785
786 for (st = -1; st == -1 && tries; tries--) {
787
788 int sz = size;
789 unsigned char* bp = buffer;
790
791 outsb((unsigned int) stuffp->wreg_data, cmd, cmdlen);
792
793 while (sz--) {
794 int to = 0;
795
796
797 {
798 unsigned long limit = jiffies + timeout;
799 while ((inb((unsigned int) stuffp->rreg_status)) & MCDX_RBIT_STEN) {
800 if ((to = (jiffies > limit))) break;
801 mcdx_delay(stuffp, DELAY);
802 }
803 }
804
805 if (!to) {
806
807
808 if (st == -1) {
809
810
811 *bp++ = st = (unsigned char) inb((unsigned int) stuffp->rreg_data);
812
813 TRACE((TALK, "talk() got status 0x%02x\n", st));
814
815
816 stuffp->audiostatus = e_audiobusy(st) ?
817 CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS;
818
819
820 if (e_changed(st)) {
821 WARN(("talk() media changed\n"));
822 stuffp->changed = jiffies;
823 }
824
825
826 if (e_cmderr(st)) {
827 WARN(("command error\n"));
828 st = -1;
829 break;
830 }
831 } else {
832
833 *bp++ = (unsigned char) inb((unsigned int) stuffp->rreg_data);
834 }
835 } else {
836 WARN(("talk() timed out, %1d %s left\n",
837 tries - 1, (tries -1 ) > 1 ? "tries" : "try"));
838 st = -1;
839 break;
840 }
841 }
842 }
843
844 if (tries) WARN(("talk() giving up\n"));
845
846
847 stuffp->lock = 0;
848 wake_up_interruptible(&stuffp->lockq);
849
850 TRACE((TALK, "talk() done with 0x%02x\n", st));
851 return st;
852 }
853
854
855 #ifdef MODULE
856
857 int init_module(void)
858 {
859 int i;
860 int drives = 0;
861
862 mcdx_init(0, 0);
863 for (i = 0; i < MCDX_NDRIVES; i++) {
864 if (mcdx_stuffp[i]) {
865 TRACE((INIT, "init_module() drive %d stuff @ %p\n",
866 i, mcdx_stuffp[i]));
867 drives++;
868 }
869 }
870
871 if (!drives) {
872 WARN(("init_module() cannot init any drive\n"));
873 return -EIO;
874 }
875
876 return 0;
877 }
878
879 void cleanup_module(void)
880 {
881 int i;
882
883 WARN(("cleanup_module called\n"));
884
885 for (i = 0; i < MCDX_NDRIVES; i++) {
886 struct s_drive_stuff *stuffp;
887 stuffp = mcdx_stuffp[i];
888 if (!stuffp) continue;
889 release_region((unsigned long) stuffp->wreg_data, MCDX_IO_SIZE);
890 free_irq(stuffp->irq);
891 if (stuffp->toc) {
892 TRACE((MALLOC, "cleanup_module() free toc @ %p\n", stuffp->toc));
893 kfree(stuffp->toc);
894 }
895 TRACE((MALLOC, "cleanup_module() free stuffp @ %p\n", stuffp));
896 mcdx_stuffp[i] = NULL;
897 kfree(stuffp);
898 }
899
900 if (unregister_blkdev(MAJOR_NR, MCD) != 0)
901 printk(MCD ": cleanup_module failed.\n");
902 else
903 printk(MCD ": cleanup_module succeeded.\n");
904 }
905
906 #endif MODULE
907
908
909
910 #if MCDX_DEBUG
911 void trace(int level, const char* fmt, ...)
912 {
913 char s[255];
914 va_list args;
915 if (level < 1) return;
916 va_start(args, fmt);
917 if (sizeof(s) < vsprintf(s, fmt, args))
918 printk(MCD ":: dprintf exeeds limit!!\n");
919 else printk(MCD ":: %s", s);
920 va_end(args);
921 }
922 #endif
923
924 #ifndef NOWARN
925 void warn(const char* fmt, ...)
926 {
927 char s[255];
928 va_list args;
929 va_start(args, fmt);
930 if (sizeof(s) < vsprintf(s, fmt, args))
931 printk(MCD ":: dprintf exeeds limit!!\n");
932 else printk(MCD ": %s", s);
933 va_end(args);
934 }
935 #endif
936
937
938 unsigned long mcdx_init(unsigned long mem_start, unsigned long mem_end)
939 {
940 int drive;
941
942 printk(MCD
943 ": Version @VERSION@ "
944 "$Id: mcdx.c,v 1.2 1995/06/18 18:00:53 heiko Exp $ \n");
945
946
947 for (drive = 0; drive < MCDX_NDRIVES; drive++)
948 mcdx_stuffp[drive] = NULL;
949
950
951 for (drive = 0; drive < MCDX_NDRIVES; drive++) {
952 struct s_version version;
953 struct s_drive_stuff* stuffp;
954
955 TRACE((INIT, "init() try drive %d\n", drive));
956 TRACE((MALLOC, "init() malloc %d bytes\n", sizeof(*stuffp)));
957
958 if (!(stuffp = kmalloc(sizeof(*stuffp), GFP_KERNEL))) {
959 WARN(("init() malloc failed\n"));
960 break;
961 }
962
963 TRACE((INIT, "init() got %d bytes for drive stuff @ %p\n", sizeof(*stuffp), stuffp));
964
965
966 memset(stuffp, 0, sizeof(*stuffp));
967
968 stuffp->present = 0;
969 stuffp->toc = NULL;
970 stuffp->changed = jiffies;
971
972
973 stuffp->irq = irq(mcdx_drive_map[drive]);
974 stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]);
975 stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1;
976 stuffp->wreg_hcon = stuffp->wreg_reset + 1;
977 stuffp->wreg_chn = stuffp->wreg_hcon + 1;
978
979
980 if (0 != check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) {
981 WARN(("init() i/o ports at 0x%3p .. 0x%3p not available\n",
982 stuffp->wreg_data, stuffp->wreg_data + MCDX_IO_SIZE - 1));
983 stuffp->wreg_data = 0;
984 TRACE((MALLOC, "init() free stuffp @ %p\n", stuffp));
985 kfree(stuffp);
986 TRACE((INIT, "init() continue at next drive\n"));
987 continue;
988 }
989
990 TRACE((INIT, "init() i/o port is available at 0x%3p\n", stuffp->wreg_data));
991
992 TRACE((INIT, "init() hardware reset\n"));
993 mcdx_reset(stuffp, HARD, 1);
994
995 TRACE((INIT, "init() get version\n"));
996 if (-1 == mcdx_requestversion(stuffp, &version, 2)) {
997
998 TRACE((MALLOC, "init() free stuffp @ %p\n", stuffp));
999 kfree(stuffp);
1000 TRACE((INIT, "init() continue at next drive\n"));
1001 continue;
1002 }
1003 switch (version.code) {
1004 case 'D':
1005 stuffp->readcmd = READDSPEED;
1006 stuffp->present = DOUBLE | DOOR | MULTI;
1007 break;
1008 case 'F':
1009 stuffp->readcmd = READSSPEED;
1010 stuffp->present = SINGLE | DOOR | MULTI;
1011 break;
1012 case 'M':
1013 stuffp->readcmd = READSSPEED;
1014 stuffp->present = SINGLE;
1015 break;
1016 default:
1017 stuffp->present = 0; break;
1018 }
1019
1020
1021 if (!stuffp->present) {
1022 printk(MCD ": no drive found. continue at next drive\n");
1023 kfree(stuffp);
1024 continue;
1025 }
1026
1027 TRACE((INIT, "init() register blkdev\n"));
1028 if (register_blkdev(MAJOR_NR, MCD, &mcdx_fops) != 0) {
1029 printk(MCD ": unable to get major %d for " DEVICE_NAME "\n",
1030 MAJOR_NR);
1031 kfree(stuffp);
1032 continue;
1033 }
1034
1035 blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1036 read_ahead[MAJOR_NR] = READ_AHEAD;
1037
1038 #if WE_KNOW_WHY
1039 blksize_size[MAJOR_NR] = BLKSIZES;
1040 #endif
1041
1042 TRACE((INIT, "init() subscribe irq and i/o\n"));
1043 mcdx_irq_map[stuffp->irq] = stuffp;
1044 if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, MCD)) {
1045 printk(MCD ": init() unable to get IRQ %d for "
1046 DEVICE_NAME "\n", stuffp->irq);
1047 stuffp->irq = 0;
1048 kfree(stuffp);
1049 continue;
1050 }
1051 request_region((unsigned long) (unsigned int) stuffp->wreg_data, MCDX_IO_SIZE, MCD);
1052
1053 TRACE((INIT, "init() get garbage\n"));
1054 {
1055 int i;
1056 mcdx_delay(stuffp, 50);
1057 for (i = 100; i; i--) (void) inb((unsigned int) stuffp->rreg_status);
1058 }
1059
1060
1061 #if WE_KNOW_WHY
1062 outb(0x50, (unsigned int) stuffp->wreg_chn);
1063 #endif
1064
1065 TRACE((INIT, "init() set non dma but irq mode\n"));
1066 mcdx_config(stuffp, 1);
1067
1068 stuffp->minor = drive;
1069
1070 printk(MCD ": " DEVICE_NAME " installed at 0x%3p, irq %d.\n"
1071 MCD ": Firmware version %c %x\n",
1072 stuffp->wreg_data, stuffp->irq, version.code, version.ver);
1073 mcdx_stuffp[drive] = stuffp;
1074 TRACE((INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp));
1075 }
1076
1077 return mem_start;
1078 }
1079
1080
1081 static int mcdx_transfer(struct s_drive_stuff *stuffp,
1082 char *p, int sector, int nr_sectors)
1083
1084
1085
1086 {
1087 int off;
1088 int done = 0;
1089
1090 TRACE((TRANSFER, "transfer() %d sectors at sector %d\n",
1091 nr_sectors, sector));
1092
1093 if (stuffp->audio) {
1094 printk(MCD ": attempt to read from audio disk\n");
1095 return -1;
1096 }
1097
1098 while (stuffp->lock)
1099 interruptible_sleep_on(&stuffp->lockq);
1100
1101 if (stuffp->valid
1102 && (sector >= stuffp->pending)
1103 && (sector < stuffp->off_direct)) {
1104
1105
1106 off = stuffp->off_requested < (off = sector + nr_sectors)
1107 ? stuffp->off_requested : off;
1108
1109 stuffp->lock = current->pid;
1110
1111 do {
1112 int sig = 0;
1113 int to = 0;
1114
1115
1116 current->timeout = jiffies + 500;
1117 while (stuffp->busy) {
1118 interruptible_sleep_on(&stuffp->busyq);
1119 if ((sig = (current->signal && ~current->blocked))
1120 || (to = (current->timeout == 0))) {
1121 break;
1122 }
1123 }
1124
1125 current->timeout = 0;
1126
1127
1128 if (((stuffp->busy == 0) && !stuffp->introk)
1129 || sig
1130 || to) {
1131 if ((stuffp->busy == 0) && !stuffp->introk)
1132 printk(MCD ": failure in data request\n");
1133 else if (to)
1134 printk(MCD ": timeout\n");
1135 else if (sig)
1136 printk(MCD ": got signal 0x%lx\n", current->signal);
1137
1138 stuffp->lock = 0;
1139 stuffp->busy = 0;
1140 wake_up_interruptible(&stuffp->lockq);
1141 wake_up_interruptible(&stuffp->busyq);
1142 stuffp->errno = MCDX_E;
1143 TRACE((TRANSFER, "transfer() done (-1)\n"));
1144 return -1;
1145 }
1146
1147
1148
1149 if (stuffp->xa && (0 == (stuffp->pending & 3))) {
1150 const int HEAD = CD_FRAMESIZE_RAW - CD_XA_TAIL - CD_FRAMESIZE;
1151 TRACE((TRANSFER, "transfer() sector %d, skip %d header bytes\n",
1152 stuffp->pending, HEAD));
1153 insb((unsigned int) stuffp->rreg_data, p, HEAD);
1154 }
1155
1156
1157
1158 TRACE((TRANSFER, "transfer() read sector %d\n", stuffp->pending));
1159 insb((unsigned int) stuffp->rreg_data, p, 512);
1160
1161
1162
1163
1164 if ((stuffp->busy = (3 == (stuffp->pending & 3))) && stuffp->xa) {
1165 char dummy[CD_XA_TAIL];
1166 TRACE((TRANSFER, "transfer() sector %d, skip %d trailer bytes\n",
1167 stuffp->pending, CD_XA_TAIL));
1168 insb((unsigned int) stuffp->rreg_data, &dummy[0], CD_XA_TAIL);
1169 }
1170
1171 if (stuffp->pending == sector) {
1172 p += 512;
1173 done++;
1174 sector++;
1175 }
1176 }
1177 while (++(stuffp->pending) < off);
1178
1179 stuffp->lock = 0;
1180 wake_up_interruptible(&stuffp->lockq);
1181
1182 } else {
1183
1184 static unsigned char cmd[] = {
1185 0,
1186 0, 0, 0,
1187 0, 0, 0
1188 };
1189
1190 cmd[0] = stuffp->readcmd;
1191
1192 stuffp->valid = 1;
1193 stuffp->pending = sector & ~3;
1194
1195
1196 TRACE((TRANSFER, "transfer() request sector %d\n", stuffp->pending));
1197 if (stuffp->pending > stuffp->lastsector) {
1198 printk(MCD ": transfer() sector %d from nirvana requested.\n",
1199 stuffp->pending);
1200 stuffp->errno = MCDX_EOM;
1201 TRACE((TRANSFER, "transfer() done (-1)\n"));
1202 return -1;
1203 }
1204
1205 if ((stuffp->off_direct = stuffp->pending + DIRECT_SIZE)
1206 > stuffp->lastsector + 1)
1207 stuffp->off_direct = stuffp->lastsector + 1;
1208 if ((stuffp->off_requested = stuffp->pending + REQUEST_SIZE)
1209 > stuffp->lastsector + 1)
1210 stuffp->off_requested = stuffp->lastsector + 1;
1211
1212 TRACE((TRANSFER, "transfer() pending %d\n", stuffp->pending));
1213 TRACE((TRANSFER, "transfer() off_dir %d\n", stuffp->off_direct));
1214 TRACE((TRANSFER, "transfer() off_req %d\n", stuffp->off_requested));
1215
1216 {
1217 struct s_msf pending;
1218 log2msf(stuffp->pending / 4, &pending);
1219 cmd[1] = pending.minute;
1220 cmd[2] = pending.second;
1221 cmd[3] = pending.frame;
1222 }
1223
1224 stuffp->busy = 1;
1225 cmd[6] = (unsigned char) (stuffp->off_requested - stuffp->pending) / 4;
1226
1227 outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd);
1228
1229 }
1230
1231 stuffp->off_direct = (stuffp->off_direct += done) < stuffp->off_requested
1232 ? stuffp->off_direct : stuffp->off_requested;
1233
1234 TRACE((TRANSFER, "transfer() done (%d)\n", done));
1235 return done;
1236 }
1237
1238
1239
1240
1241 static char* port(int *ip) { return (char*) ip[0]; }
1242 static int irq(int *ip) { return ip[1]; }
1243
1244
1245
1246 static unsigned int bcd2uint(unsigned char c)
1247 { return (c >> 4) * 10 + (c & 0x0f); }
1248
1249 static unsigned int uint2bcd(unsigned int ival)
1250 { return ((ival / 10) << 4) | (ival % 10); }
1251
1252 static void log2msf(unsigned int l, struct s_msf* pmsf)
1253 {
1254 l += CD_BLOCK_OFFSET;
1255 pmsf->minute = uint2bcd(l / 4500), l %= 4500;
1256 pmsf->second = uint2bcd(l / 75);
1257 pmsf->frame = uint2bcd(l % 75);
1258 }
1259
1260 static unsigned int msf2log(const struct s_msf* pmsf)
1261 {
1262 return bcd2uint(pmsf->frame)
1263 + bcd2uint(pmsf->second) * 75
1264 + bcd2uint(pmsf->minute) * 4500
1265 - CD_BLOCK_OFFSET;
1266 }
1267
1268 int mcdx_readtoc(struct s_drive_stuff* stuffp)
1269 {
1270
1271 TRACE((IOCTL, "ioctl() readtoc for %d tracks\n",
1272 stuffp->di.n_last - stuffp->di.n_first + 1));
1273
1274 #if MCDX_DEBUG && IOCTL
1275 if (stuffp->toc) {
1276 TRACE((IOCTL, "ioctl() toc already read\n"));
1277 return 0;
1278 }
1279 #endif
1280
1281 TRACE((IOCTL, "ioctl() tocmode\n"));
1282 if (-1 == mcdx_setdrivemode(stuffp, TOC, 1)) return -EIO;
1283
1284
1285 {
1286 int size;
1287 size = sizeof(struct s_subqcode) * (stuffp->di.n_last - stuffp->di.n_first + 2);
1288
1289 TRACE((MALLOC, "ioctl() malloc %d bytes\n", size));
1290 stuffp->toc = kmalloc(size, GFP_KERNEL);
1291 if (!stuffp->toc) {
1292 WARN(("Cannot malloc %s bytes for toc\n", size));
1293 mcdx_setdrivemode(stuffp, DATA, 1);
1294 return -EIO;
1295 }
1296 }
1297
1298
1299 {
1300 int trk;
1301 int retries;
1302
1303 for (trk = 0;
1304 trk < (stuffp->di.n_last - stuffp->di.n_first + 1);
1305 trk++)
1306 stuffp->toc[trk].index = 0;
1307
1308 for (retries = 300; retries; retries--) {
1309 struct s_subqcode q;
1310 unsigned int idx;
1311
1312 if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) {
1313 mcdx_setdrivemode(stuffp, DATA, 1);
1314 return -EIO;
1315 }
1316
1317 idx = bcd2uint(q.index);
1318
1319 if ((idx > 0)
1320 && (idx <= stuffp->di.n_last)
1321 && (q.tno == 0)
1322 && (stuffp->toc[idx - stuffp->di.n_first].index == 0)) {
1323 stuffp->toc[idx - stuffp->di.n_first] = q;
1324 trk--;
1325 }
1326 if (trk == 0) break;
1327 }
1328 memset(&stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1],
1329 0, sizeof(stuffp->toc[0]));
1330 stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1].dt
1331 = stuffp->di.msf_leadout;
1332 }
1333
1334
1335 TRACE((IOCTL, "ioctl() undo toc mode\n"));
1336 if (-1 == mcdx_setdrivemode(stuffp, DATA, 2))
1337 return -EIO;
1338
1339 #if MCDX_DEBUG && IOCTL
1340 { int trk;
1341 for (trk = 0;
1342 trk < (stuffp->di.n_last - stuffp->di.n_first + 2);
1343 trk++)
1344 TRACE((IOCTL, "ioctl() %d readtoc %02x %02x %02x"
1345 " %02x:%02x.%02x %02x:%02x.%02x\n",
1346 trk + stuffp->di.n_first,
1347 stuffp->toc[trk].control, stuffp->toc[trk].tno, stuffp->toc[trk].index,
1348 stuffp->toc[trk].tt.minute, stuffp->toc[trk].tt.second, stuffp->toc[trk].tt.frame,
1349 stuffp->toc[trk].dt.minute, stuffp->toc[trk].dt.second, stuffp->toc[trk].dt.frame));
1350 }
1351 #endif
1352
1353
1354 return 0;
1355 }
1356
1357
1358
1359 static int
1360 mcdx_closedoor(struct s_drive_stuff *stuffp, int tries)
1361 {
1362 if (stuffp->present & DOOR)
1363 return mcdx_talk(stuffp, "\xf8", 1, NULL, 0, 500, tries);
1364 else
1365 return 0;
1366 }
1367
1368 static int
1369 mcdx_stop(struct s_drive_stuff *stuffp, int tries)
1370 { return mcdx_talk(stuffp, "\xf0", 1, NULL, 0, 200, tries); }
1371
1372 static int
1373 mcdx_eject(struct s_drive_stuff *stuffp, int tries)
1374 {
1375 if (stuffp->present & DOOR)
1376 return mcdx_talk(stuffp, "\xf6", 1, NULL, 0, 500, tries);
1377 else
1378 return 0;
1379 }
1380
1381 static int
1382 mcdx_requestsubqcode(struct s_drive_stuff *stuffp, struct s_subqcode *sub, int tries)
1383 {
1384 char buf[11];
1385 int ans;
1386 ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf), 200, tries);
1387 sub->control = buf[1];
1388 sub->tno = buf[2];
1389 sub->index = buf[3];
1390 sub->tt.minute = buf[4];
1391 sub->tt.second = buf[5];
1392 sub->tt.frame = buf[6];
1393 sub->dt.minute = buf[8];
1394 sub->dt.second = buf[9];
1395 sub->dt.frame = buf[10];
1396 return ans;
1397 }
1398
1399 static int
1400 mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp, struct s_multi *multi, int tries)
1401 {
1402 char buf[5];
1403 int ans;
1404
1405 if (stuffp->present & MULTI) {
1406 ans = mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 200, tries);
1407 multi->multi = buf[1];
1408 multi->msf_last.minute = buf[2];
1409 multi->msf_last.second = buf[3];
1410 multi->msf_last.frame = buf[4];
1411 return ans;
1412 } else {
1413 multi->multi = 0;
1414 return 0;
1415 }
1416 }
1417
1418 static int
1419 mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info, int tries)
1420 {
1421 char buf[9];
1422 int ans;
1423 ans = mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 200, tries);
1424 info->n_first = bcd2uint(buf[1]);
1425 info->n_last = bcd2uint(buf[2]);
1426 info->msf_leadout.minute = buf[3];
1427 info->msf_leadout.second = buf[4];
1428 info->msf_leadout.frame = buf[5];
1429 info->msf_first.minute = buf[6];
1430 info->msf_first.second = buf[7];
1431 info->msf_first.frame = buf[8];
1432 return ans;
1433 }
1434
1435 static int
1436 mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode, int tries)
1437 {
1438 char cmd[2];
1439 int ans;
1440
1441 TRACE((HW, "setdrivemode() %d\n", mode));
1442
1443 if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 500, tries)))
1444 return ans;
1445
1446 switch (mode) {
1447 case TOC: cmd[1] |= 0x04; break;
1448 case DATA: cmd[1] &= ~0x04; break;
1449 case RAW: cmd[1] |= 0x40; break;
1450 case COOKED: cmd[1] &= ~0x40; break;
1451 default: break;
1452 }
1453 cmd[0] = 0x50;
1454 return mcdx_talk(stuffp, cmd, 2, NULL, 0, 500, tries);
1455 }
1456
1457
1458 static int
1459 mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode, int tries)
1460 {
1461 unsigned char cmd[2] = { 0xa0 };
1462 TRACE((HW, "setdatamode() %d\n", mode));
1463 switch (mode) {
1464 case MODE0: cmd[1] = 0x00; break;
1465 case MODE1: cmd[1] = 0x01; break;
1466 case MODE2: cmd[1] = 0x02; break;
1467 default: return -EINVAL;
1468 }
1469 return mcdx_talk(stuffp, cmd, 2, NULL, 0, 500, tries);
1470 }
1471
1472 static int
1473 mcdx_config(struct s_drive_stuff *stuffp, int tries)
1474 {
1475 char cmd[4];
1476
1477 TRACE((HW, "config()\n"));
1478
1479 cmd[0] = 0x90;
1480
1481 cmd[1] = 0x10;
1482 cmd[2] = 0x05;
1483
1484 if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 0, 100, tries))
1485 return -1;
1486
1487 cmd[1] = 0x02;
1488 cmd[2] = 0x00;
1489
1490 return mcdx_talk(stuffp, cmd, 3, NULL, 0, 100, tries);
1491 }
1492
1493 static int
1494 mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver, int tries)
1495 {
1496 char buf[3];
1497 int ans;
1498
1499 if (-1 == (ans = mcdx_talk(stuffp, "\xdc", 1, buf, sizeof(buf), 200, tries)))
1500 return ans;
1501
1502 ver->code = buf[1];
1503 ver->ver = buf[2];
1504
1505 return ans;
1506 }
1507
1508 static int
1509 mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries)
1510 {
1511 if (mode == HARD) {
1512 outb(0, (unsigned int) stuffp->wreg_chn);
1513 outb(0, (unsigned int) stuffp->wreg_reset);
1514 return 0;
1515 } else return mcdx_talk(stuffp, "\x60", 1, NULL, 0, 500, tries);
1516 }
1517
1518 static int
1519 mcdx_lockdoor(struct s_drive_stuff *stuffp, int lock, int tries)
1520 {
1521 char cmd[2] = { 0xfe };
1522 if (stuffp->present & DOOR) {
1523 cmd[1] = lock ? 0x01 : 0x00;
1524 return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 0, 500, tries);
1525 } else
1526 return 0;
1527 }
1528
1529 #if 0
1530 static int
1531 mcdx_getstatus(struct s_drive_stuff *stuffp, int tries)
1532 { return mcdx_talk(stuffp, "\x40", 1, NULL, 0, 500, tries); }
1533 #endif