File: /usr/src/linux/drivers/cdrom/gscd.c
1 #define GSCD_VERSION "0.4a Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>"
2
3 /*
4 linux/drivers/block/gscd.c - GoldStar R420 CDROM driver
5
6 Copyright (C) 1995 Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>
7 based upon pre-works by Eberhard Moenkeberg <emoenke@gwdg.de>
8
9
10 For all kind of other information about the GoldStar CDROM
11 and this Linux device driver I installed a WWW-URL:
12 http://linux.rz.fh-hannover.de/~raupach
13
14
15 If you are the editor of a Linux CD, you should
16 enable gscd.c within your boot floppy kernel and
17 send me one of your CDs for free.
18
19
20 --------------------------------------------------------------------
21 This program is free software; you can redistribute it and/or modify
22 it under the terms of the GNU General Public License as published by
23 the Free Software Foundation; either version 2, or (at your option)
24 any later version.
25
26 This program is distributed in the hope that it will be useful,
27 but WITHOUT ANY WARRANTY; without even the implied warranty of
28 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 GNU General Public License for more details.
30
31 You should have received a copy of the GNU General Public License
32 along with this program; if not, write to the Free Software
33 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
34
35 --------------------------------------------------------------------
36
37 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x
38 Removed init_module & cleanup_module in favor of
39 module_init & module_exit.
40 Torben Mathiasen <tmm@image.dk>
41
42 */
43
44 /* These settings are for various debug-level. Leave they untouched ... */
45 #define NO_GSCD_DEBUG
46 #define NO_IOCTL_DEBUG
47 #define NO_MODULE_DEBUG
48 #define NO_FUTURE_WORK
49 /*------------------------*/
50
51 #include <linux/module.h>
52
53 #include <linux/slab.h>
54 #include <linux/errno.h>
55 #include <linux/signal.h>
56 #include <linux/sched.h>
57 #include <linux/timer.h>
58 #include <linux/fs.h>
59 #include <linux/mm.h>
60 #include <linux/kernel.h>
61 #include <linux/cdrom.h>
62 #include <linux/ioport.h>
63 #include <linux/major.h>
64 #include <linux/string.h>
65 #include <linux/init.h>
66 #include <linux/devfs_fs_kernel.h>
67
68 #include <asm/system.h>
69 #include <asm/io.h>
70 #include <asm/uaccess.h>
71
72 #define MAJOR_NR GOLDSTAR_CDROM_MAJOR
73 #include <linux/blk.h>
74 #define gscd_port gscd /* for compatible parameter passing with "insmod" */
75 #include "gscd.h"
76
77 static int gscd_blocksizes[1] = { 512 };
78
79 static int gscdPresent = 0;
80
81 static unsigned char gscd_buf[2048]; /* buffer for block size conversion */
82 static int gscd_bn = -1;
83 static short gscd_port = GSCD_BASE_ADDR;
84 MODULE_PARM(gscd, "h");
85
86 /* Kommt spaeter vielleicht noch mal dran ...
87 * static DECLARE_WAIT_QUEUE_HEAD(gscd_waitq);
88 */
89
90 static void gscd_transfer(void);
91 static void gscd_read_cmd(void);
92 static void gscd_hsg2msf(long hsg, struct msf *msf);
93 static void gscd_bin2bcd(unsigned char *p);
94
95 /* Schnittstellen zum Kern/FS */
96
97 static void do_gscd_request(request_queue_t *);
98 static void __do_gscd_request(unsigned long dummy);
99 static int gscd_ioctl(struct inode *, struct file *, unsigned int,
100 unsigned long);
101 static int gscd_open(struct inode *, struct file *);
102 static int gscd_release(struct inode *, struct file *);
103 static int check_gscd_med_chg(kdev_t);
104
105 /* GoldStar Funktionen */
106
107 static void cc_Reset(void);
108 static int wait_drv_ready(void);
109 static int find_drives(void);
110 static void cmd_out(int, char *, char *, int);
111 static void cmd_status(void);
112 static void cc_Ident(char *);
113 static void cc_SetSpeed(void);
114 static void init_cd_drive(int);
115
116 static int get_status(void);
117 static void clear_Audio(void);
118 static void cc_invalidate(void);
119
120 /* some things for the next version */
121 #ifdef FUTURE_WORK
122 static void update_state(void);
123 static long gscd_msf2hsg(struct msf *mp);
124 static int gscd_bcd2bin(unsigned char bcd);
125 #endif
126
127 /* common GoldStar Initialization */
128
129 static int my_gscd_init(void);
130
131
132 /* lo-level cmd-Funktionen */
133
134 static void cmd_info_in(char *, int);
135 static void cmd_end(void);
136 static void cmd_read_b(char *, int, int);
137 static void cmd_read_w(char *, int, int);
138 static int cmd_unit_alive(void);
139 static void cmd_write_cmd(char *);
140
141
142 /* GoldStar Variablen */
143
144 static int curr_drv_state;
145 static int drv_states[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
146 static int drv_mode;
147 static int disk_state;
148 static int speed;
149 static int ndrives;
150
151 static unsigned char drv_num_read;
152 static unsigned char f_dsk_valid;
153 static unsigned char current_drive;
154 static unsigned char f_drv_ok;
155
156
157 static char f_AudioPlay;
158 static char f_AudioPause;
159 static int AudioStart_m;
160 static int AudioStart_f;
161 static int AudioEnd_m;
162 static int AudioEnd_f;
163
164 static struct timer_list gscd_timer;
165
166 static struct block_device_operations gscd_fops = {
167 open:gscd_open,
168 release:gscd_release,
169 ioctl:gscd_ioctl,
170 check_media_change:check_gscd_med_chg,
171 };
172
173 /*
174 * Checking if the media has been changed
175 * (not yet implemented)
176 */
177 static int check_gscd_med_chg(kdev_t full_dev)
178 {
179 int target;
180
181
182 target = MINOR(full_dev);
183
184 if (target > 0) {
185 printk
186 ("GSCD: GoldStar CD-ROM request error: invalid device.\n");
187 return 0;
188 }
189 #ifdef GSCD_DEBUG
190 printk("gscd: check_med_change\n");
191 #endif
192
193 return 0;
194 }
195
196
197 #ifndef MODULE
198 /* Using new interface for kernel-parameters */
199
200 static int __init gscd_setup(char *str)
201 {
202 int ints[2];
203 (void) get_options(str, ARRAY_SIZE(ints), ints);
204
205 if (ints[0] > 0) {
206 gscd_port = ints[1];
207 }
208 return 1;
209 }
210
211 __setup("gscd=", gscd_setup);
212
213 #endif
214
215 static int gscd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
216 unsigned long arg)
217 {
218 unsigned char to_do[10];
219 unsigned char dummy;
220
221
222 switch (cmd) {
223 case CDROMSTART: /* Spin up the drive */
224 /* Don't think we can do this. Even if we could,
225 * I think the drive times out and stops after a while
226 * anyway. For now, ignore it.
227 */
228 return 0;
229
230 case CDROMRESUME: /* keine Ahnung was das ist */
231 return 0;
232
233
234 case CDROMEJECT:
235 cmd_status();
236 to_do[0] = CMD_TRAY_CTL;
237 cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0);
238
239 return 0;
240
241 default:
242 return -EINVAL;
243 }
244
245 }
246
247
248 /*
249 * Take care of the different block sizes between cdrom and Linux.
250 * When Linux gets variable block sizes this will probably go away.
251 */
252
253 static void gscd_transfer(void)
254 {
255 long offs;
256
257 while (CURRENT->nr_sectors > 0 && gscd_bn == CURRENT->sector / 4) {
258 offs = (CURRENT->sector & 3) * 512;
259 memcpy(CURRENT->buffer, gscd_buf + offs, 512);
260 CURRENT->nr_sectors--;
261 CURRENT->sector++;
262 CURRENT->buffer += 512;
263 }
264 }
265
266
267 /*
268 * I/O request routine called from Linux kernel.
269 */
270
271 static void do_gscd_request(request_queue_t * q)
272 {
273 __do_gscd_request(0);
274 }
275
276 static void __do_gscd_request(unsigned long dummy)
277 {
278 unsigned int block, dev;
279 unsigned int nsect;
280
281 repeat:
282 if (QUEUE_EMPTY || CURRENT->rq_status == RQ_INACTIVE)
283 goto out;
284 INIT_REQUEST;
285 dev = MINOR(CURRENT->rq_dev);
286 block = CURRENT->sector;
287 nsect = CURRENT->nr_sectors;
288
289 if (QUEUE_EMPTY || CURRENT->sector == -1)
290 goto out;
291
292 if (CURRENT->cmd != READ) {
293 printk("GSCD: bad cmd %d\n", CURRENT->cmd);
294 end_request(0);
295 goto repeat;
296 }
297
298 if (MINOR(CURRENT->rq_dev) != 0) {
299 printk("GSCD: this version supports only one device\n");
300 end_request(0);
301 goto repeat;
302 }
303
304 gscd_transfer();
305
306 /* if we satisfied the request from the buffer, we're done. */
307
308 if (CURRENT->nr_sectors == 0) {
309 end_request(1);
310 goto repeat;
311 }
312 #ifdef GSCD_DEBUG
313 printk("GSCD: dev %d, block %d, nsect %d\n", dev, block, nsect);
314 #endif
315
316 gscd_read_cmd();
317 out:
318 return;
319 }
320
321
322
323 /*
324 * Check the result of the set-mode command. On success, send the
325 * read-data command.
326 */
327
328 static void gscd_read_cmd(void)
329 {
330 long block;
331 struct gscd_Play_msf gscdcmd;
332 char cmd[] = { CMD_READ, 0x80, 0, 0, 0, 0, 1 }; /* cmd mode M-S-F secth sectl */
333
334
335
336 cmd_status();
337 if (disk_state & (ST_NO_DISK | ST_DOOR_OPEN)) {
338 printk("GSCD: no disk or door open\n");
339 end_request(0);
340 } else {
341 if (disk_state & ST_INVALID) {
342 printk("GSCD: disk invalid\n");
343 end_request(0);
344 } else {
345 gscd_bn = -1; /* purge our buffer */
346 block = CURRENT->sector / 4;
347 gscd_hsg2msf(block, &gscdcmd.start); /* cvt to msf format */
348
349 cmd[2] = gscdcmd.start.min;
350 cmd[3] = gscdcmd.start.sec;
351 cmd[4] = gscdcmd.start.frame;
352
353 #ifdef GSCD_DEBUG
354 printk("GSCD: read msf %d:%d:%d\n", cmd[2], cmd[3],
355 cmd[4]);
356 #endif
357 cmd_out(TYPE_DATA, (char *) &cmd,
358 (char *) &gscd_buf[0], 1);
359
360 gscd_bn = CURRENT->sector / 4;
361 gscd_transfer();
362 end_request(1);
363 }
364 }
365 SET_TIMER(__do_gscd_request, 1);
366 }
367
368
369 /*
370 * Open the device special file. Check that a disk is in.
371 */
372
373 static int gscd_open(struct inode *ip, struct file *fp)
374 {
375 int st;
376
377 #ifdef GSCD_DEBUG
378 printk("GSCD: open\n");
379 #endif
380
381 if (gscdPresent == 0)
382 return -ENXIO; /* no hardware */
383
384 MOD_INC_USE_COUNT;
385
386 get_status();
387 st = disk_state & (ST_NO_DISK | ST_DOOR_OPEN);
388 if (st) {
389 printk("GSCD: no disk or door open\n");
390 MOD_DEC_USE_COUNT;
391 return -ENXIO;
392 }
393
394 /* if (updateToc() < 0)
395 return -EIO;
396 */
397
398 return 0;
399 }
400
401
402 /*
403 * On close, we flush all gscd blocks from the buffer cache.
404 */
405
406 static int gscd_release(struct inode *inode, struct file *file)
407 {
408
409 #ifdef GSCD_DEBUG
410 printk("GSCD: release\n");
411 #endif
412
413 gscd_bn = -1;
414
415 MOD_DEC_USE_COUNT;
416 return 0;
417 }
418
419
420 int get_status(void)
421 {
422 int status;
423
424 cmd_status();
425 status = disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01);
426
427 if (status == (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) {
428 cc_invalidate();
429 return 1;
430 } else {
431 return 0;
432 }
433 }
434
435
436 void cc_invalidate(void)
437 {
438 drv_num_read = 0xFF;
439 f_dsk_valid = 0xFF;
440 current_drive = 0xFF;
441 f_drv_ok = 0xFF;
442
443 clear_Audio();
444
445 }
446
447 void clear_Audio(void)
448 {
449
450 f_AudioPlay = 0;
451 f_AudioPause = 0;
452 AudioStart_m = 0;
453 AudioStart_f = 0;
454 AudioEnd_m = 0;
455 AudioEnd_f = 0;
456
457 }
458
459 /*
460 * waiting ?
461 */
462
463 int wait_drv_ready(void)
464 {
465 int found, read;
466
467 do {
468 found = inb(GSCDPORT(0));
469 found &= 0x0f;
470 read = inb(GSCDPORT(0));
471 read &= 0x0f;
472 } while (read != found);
473
474 #ifdef GSCD_DEBUG
475 printk("Wait for: %d\n", read);
476 #endif
477
478 return read;
479 }
480
481 void cc_Ident(char *respons)
482 {
483 char to_do[] = { CMD_IDENT, 0, 0 };
484
485 cmd_out(TYPE_INFO, (char *) &to_do, (char *) respons, (int) 0x1E);
486
487 }
488
489 void cc_SetSpeed(void)
490 {
491 char to_do[] = { CMD_SETSPEED, 0, 0 };
492 char dummy;
493
494 if (speed > 0) {
495 to_do[1] = speed & 0x0F;
496 cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0);
497 }
498 }
499
500
501 void cc_Reset(void)
502 {
503 char to_do[] = { CMD_RESET, 0 };
504 char dummy;
505
506 cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0);
507 }
508
509
510
511 void cmd_status(void)
512 {
513 char to_do[] = { CMD_STATUS, 0 };
514 char dummy;
515
516 cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0);
517
518 #ifdef GSCD_DEBUG
519 printk("GSCD: Status: %d\n", disk_state);
520 #endif
521
522 }
523
524 void cmd_out(int cmd_type, char *cmd, char *respo_buf, int respo_count)
525 {
526 int result;
527
528
529 result = wait_drv_ready();
530 if (result != drv_mode) {
531 unsigned long test_loops = 0xFFFF;
532 int i, dummy;
533
534 outb(curr_drv_state, GSCDPORT(0));
535
536 /* LOCLOOP_170 */
537 do {
538 result = wait_drv_ready();
539 test_loops--;
540 } while ((result != drv_mode) && (test_loops > 0));
541
542 if (result != drv_mode) {
543 disk_state = ST_x08 | ST_x04 | ST_INVALID;
544 return;
545 }
546
547 /* ...and waiting */
548 for (i = 1, dummy = 1; i < 0xFFFF; i++) {
549 dummy *= i;
550 }
551 }
552
553 /* LOC_172 */
554 /* check the unit */
555 /* and wake it up */
556 if (cmd_unit_alive() != 0x08) {
557 /* LOC_174 */
558 /* game over for this unit */
559 disk_state = ST_x08 | ST_x04 | ST_INVALID;
560 return;
561 }
562
563 /* LOC_176 */
564 #ifdef GSCD_DEBUG
565 printk("LOC_176 ");
566 #endif
567 if (drv_mode == 0x09) {
568 /* magic... */
569 printk("GSCD: magic ...\n");
570 outb(result, GSCDPORT(2));
571 }
572
573 /* write the command to the drive */
574 cmd_write_cmd(cmd);
575
576 /* LOC_178 */
577 for (;;) {
578 result = wait_drv_ready();
579 if (result != drv_mode) {
580 /* LOC_179 */
581 if (result == 0x04) { /* Mode 4 */
582 /* LOC_205 */
583 #ifdef GSCD_DEBUG
584 printk("LOC_205 ");
585 #endif
586 disk_state = inb(GSCDPORT(2));
587
588 do {
589 result = wait_drv_ready();
590 } while (result != drv_mode);
591 return;
592
593 } else {
594 if (result == 0x06) { /* Mode 6 */
595 /* LOC_181 */
596 #ifdef GSCD_DEBUG
597 printk("LOC_181 ");
598 #endif
599
600 if (cmd_type == TYPE_DATA) {
601 /* read data */
602 /* LOC_184 */
603 if (drv_mode == 9) {
604 /* read the data to the buffer (word) */
605
606 /* (*(cmd+1))?(CD_FRAMESIZE/2):(CD_FRAMESIZE_RAW/2) */
607 cmd_read_w
608 (respo_buf,
609 respo_count,
610 CD_FRAMESIZE /
611 2);
612 return;
613 } else {
614 /* read the data to the buffer (byte) */
615
616 /* (*(cmd+1))?(CD_FRAMESIZE):(CD_FRAMESIZE_RAW) */
617 cmd_read_b
618 (respo_buf,
619 respo_count,
620 CD_FRAMESIZE);
621 return;
622 }
623 } else {
624 /* read the info to the buffer */
625 cmd_info_in(respo_buf,
626 respo_count);
627 return;
628 }
629
630 return;
631 }
632 }
633
634 } else {
635 disk_state = ST_x08 | ST_x04 | ST_INVALID;
636 return;
637 }
638 } /* for (;;) */
639
640
641 #ifdef GSCD_DEBUG
642 printk("\n");
643 #endif
644 }
645
646
647 static void cmd_write_cmd(char *pstr)
648 {
649 int i, j;
650
651 /* LOC_177 */
652 #ifdef GSCD_DEBUG
653 printk("LOC_177 ");
654 #endif
655
656 /* calculate the number of parameter */
657 j = *pstr & 0x0F;
658
659 /* shift it out */
660 for (i = 0; i < j; i++) {
661 outb(*pstr, GSCDPORT(2));
662 pstr++;
663 }
664 }
665
666
667 static int cmd_unit_alive(void)
668 {
669 int result;
670 unsigned long max_test_loops;
671
672
673 /* LOC_172 */
674 #ifdef GSCD_DEBUG
675 printk("LOC_172 ");
676 #endif
677
678 outb(curr_drv_state, GSCDPORT(0));
679 max_test_loops = 0xFFFF;
680
681 do {
682 result = wait_drv_ready();
683 max_test_loops--;
684 } while ((result != 0x08) && (max_test_loops > 0));
685
686 return result;
687 }
688
689
690 static void cmd_info_in(char *pb, int count)
691 {
692 int result;
693 char read;
694
695
696 /* read info */
697 /* LOC_182 */
698 #ifdef GSCD_DEBUG
699 printk("LOC_182 ");
700 #endif
701
702 do {
703 read = inb(GSCDPORT(2));
704 if (count > 0) {
705 *pb = read;
706 pb++;
707 count--;
708 }
709
710 /* LOC_183 */
711 do {
712 result = wait_drv_ready();
713 } while (result == 0x0E);
714 } while (result == 6);
715
716 cmd_end();
717 return;
718 }
719
720
721 static void cmd_read_b(char *pb, int count, int size)
722 {
723 int result;
724 int i;
725
726
727 /* LOC_188 */
728 /* LOC_189 */
729 #ifdef GSCD_DEBUG
730 printk("LOC_189 ");
731 #endif
732
733 do {
734 do {
735 result = wait_drv_ready();
736 } while (result != 6 || result == 0x0E);
737
738 if (result != 6) {
739 cmd_end();
740 return;
741 }
742 #ifdef GSCD_DEBUG
743 printk("LOC_191 ");
744 #endif
745
746 for (i = 0; i < size; i++) {
747 *pb = inb(GSCDPORT(2));
748 pb++;
749 }
750 count--;
751 } while (count > 0);
752
753 cmd_end();
754 return;
755 }
756
757
758 static void cmd_end(void)
759 {
760 int result;
761
762
763 /* LOC_204 */
764 #ifdef GSCD_DEBUG
765 printk("LOC_204 ");
766 #endif
767
768 do {
769 result = wait_drv_ready();
770 if (result == drv_mode) {
771 return;
772 }
773 } while (result != 4);
774
775 /* LOC_205 */
776 #ifdef GSCD_DEBUG
777 printk("LOC_205 ");
778 #endif
779
780 disk_state = inb(GSCDPORT(2));
781
782 do {
783 result = wait_drv_ready();
784 } while (result != drv_mode);
785 return;
786
787 }
788
789
790 static void cmd_read_w(char *pb, int count, int size)
791 {
792 int result;
793 int i;
794
795
796 #ifdef GSCD_DEBUG
797 printk("LOC_185 ");
798 #endif
799
800 do {
801 /* LOC_185 */
802 do {
803 result = wait_drv_ready();
804 } while (result != 6 || result == 0x0E);
805
806 if (result != 6) {
807 cmd_end();
808 return;
809 }
810
811 for (i = 0; i < size; i++) {
812 /* na, hier muss ich noch mal drueber nachdenken */
813 *pb = inw(GSCDPORT(2));
814 pb++;
815 }
816 count--;
817 } while (count > 0);
818
819 cmd_end();
820 return;
821 }
822
823 int __init find_drives(void)
824 {
825 int *pdrv;
826 int drvnum;
827 int subdrv;
828 int i;
829
830 speed = 0;
831 pdrv = (int *) &drv_states;
832 curr_drv_state = 0xFE;
833 subdrv = 0;
834 drvnum = 0;
835
836 for (i = 0; i < 8; i++) {
837 subdrv++;
838 cmd_status();
839 disk_state &= ST_x08 | ST_x04 | ST_INVALID | ST_x01;
840 if (disk_state != (ST_x08 | ST_x04 | ST_INVALID)) {
841 /* LOC_240 */
842 *pdrv = curr_drv_state;
843 init_cd_drive(drvnum);
844 pdrv++;
845 drvnum++;
846 } else {
847 if (subdrv < 2) {
848 continue;
849 } else {
850 subdrv = 0;
851 }
852 }
853
854 /* curr_drv_state<<1; <-- das geht irgendwie nicht */
855 /* muss heissen: curr_drv_state <<= 1; (ist ja Wert-Zuweisung) */
856 curr_drv_state *= 2;
857 curr_drv_state |= 1;
858 #ifdef GSCD_DEBUG
859 printk("DriveState: %d\n", curr_drv_state);
860 #endif
861 }
862
863 ndrives = drvnum;
864 return drvnum;
865 }
866
867 void __init init_cd_drive(int num)
868 {
869 char resp[50];
870 int i;
871
872 printk("GSCD: init unit %d\n", num);
873 cc_Ident((char *) &resp);
874
875 printk("GSCD: identification: ");
876 for (i = 0; i < 0x1E; i++) {
877 printk("%c", resp[i]);
878 }
879 printk("\n");
880
881 cc_SetSpeed();
882
883 }
884
885 #ifdef FUTURE_WORK
886 /* return_done */
887 static void update_state(void)
888 {
889 unsigned int AX;
890
891
892 if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) == 0) {
893 if (disk_state == (ST_x08 | ST_x04 | ST_INVALID)) {
894 AX = ST_INVALID;
895 }
896
897 if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01))
898 == 0) {
899 invalidate();
900 f_drv_ok = 0;
901 }
902
903 AX |= 0x8000;
904 }
905
906 if (disk_state & ST_PLAYING) {
907 AX |= 0x200;
908 }
909
910 AX |= 0x100;
911 /* pkt_esbx = AX; */
912
913 disk_state = 0;
914
915 }
916 #endif
917
918 /* Init for the Module-Version */
919 int init_gscd(void)
920 {
921 long err;
922
923
924 /* call the GoldStar-init */
925 err = my_gscd_init();
926
927 if (err < 0) {
928 return err;
929 } else {
930 printk(KERN_INFO "Happy GoldStar !\n");
931 return 0;
932 }
933 }
934
935 void __exit exit_gscd(void)
936 {
937 CLEAR_TIMER;
938
939 devfs_unregister(devfs_find_handle
940 (NULL, "gscd", 0, 0, DEVFS_SPECIAL_BLK, 0));
941 if ((devfs_unregister_blkdev(MAJOR_NR, "gscd") == -EINVAL)) {
942 printk("What's that: can't unregister GoldStar-module\n");
943 return;
944 }
945 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
946 release_region(gscd_port, 4);
947 printk(KERN_INFO "GoldStar-module released.\n");
948 }
949
950 #ifdef MODULE
951 module_init(init_gscd);
952 #endif
953 module_exit(exit_gscd);
954
955
956 /* Test for presence of drive and initialize it. Called only at boot time. */
957 int __init gscd_init(void)
958 {
959 return my_gscd_init();
960 }
961
962
963 /* This is the common initialisation for the GoldStar drive. */
964 /* It is called at boot time AND for module init. */
965 int __init my_gscd_init(void)
966 {
967 int i;
968 int result;
969
970 printk(KERN_INFO "GSCD: version %s\n", GSCD_VERSION);
971 printk(KERN_INFO
972 "GSCD: Trying to detect a Goldstar R420 CD-ROM drive at 0x%X.\n",
973 gscd_port);
974
975 if (check_region(gscd_port, 4)) {
976 printk
977 ("GSCD: Init failed, I/O port (%X) already in use.\n",
978 gscd_port);
979 return -EIO;
980 }
981
982
983 /* check for card */
984 result = wait_drv_ready();
985 if (result == 0x09) {
986 printk("GSCD: DMA kann ich noch nicht!\n");
987 return -EIO;
988 }
989
990 if (result == 0x0b) {
991 drv_mode = result;
992 i = find_drives();
993 if (i == 0) {
994 printk
995 ("GSCD: GoldStar CD-ROM Drive is not found.\n");
996 return -EIO;
997 }
998 }
999
1000 if ((result != 0x0b) && (result != 0x09)) {
1001 printk
1002 ("GSCD: GoldStar Interface Adapter does not exist or H/W error\n");
1003 return -EIO;
1004 }
1005
1006 /* reset all drives */
1007 i = 0;
1008 while (drv_states[i] != 0) {
1009 curr_drv_state = drv_states[i];
1010 printk(KERN_INFO "GSCD: Reset unit %d ... ", i);
1011 cc_Reset();
1012 printk("done\n");
1013 i++;
1014 }
1015
1016 if (devfs_register_blkdev(MAJOR_NR, "gscd", &gscd_fops) != 0) {
1017 printk
1018 ("GSCD: Unable to get major %d for GoldStar CD-ROM\n",
1019 MAJOR_NR);
1020 return -EIO;
1021 }
1022 devfs_register(NULL, "gscd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
1023 S_IFBLK | S_IRUGO | S_IWUGO, &gscd_fops, NULL);
1024
1025 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
1026 blksize_size[MAJOR_NR] = gscd_blocksizes;
1027 read_ahead[MAJOR_NR] = 4;
1028
1029 disk_state = 0;
1030 gscdPresent = 1;
1031
1032 request_region(gscd_port, 4, "gscd");
1033 register_disk(NULL, MKDEV(MAJOR_NR, 0), 1, &gscd_fops, 0);
1034
1035 printk(KERN_INFO "GSCD: GoldStar CD-ROM Drive found.\n");
1036 return 0;
1037 }
1038
1039 static void gscd_hsg2msf(long hsg, struct msf *msf)
1040 {
1041 hsg += CD_MSF_OFFSET;
1042 msf->min = hsg / (CD_FRAMES * CD_SECS);
1043 hsg %= CD_FRAMES * CD_SECS;
1044 msf->sec = hsg / CD_FRAMES;
1045 msf->frame = hsg % CD_FRAMES;
1046
1047 gscd_bin2bcd(&msf->min); /* convert to BCD */
1048 gscd_bin2bcd(&msf->sec);
1049 gscd_bin2bcd(&msf->frame);
1050 }
1051
1052
1053 static void gscd_bin2bcd(unsigned char *p)
1054 {
1055 int u, t;
1056
1057 u = *p % 10;
1058 t = *p / 10;
1059 *p = u | (t << 4);
1060 }
1061
1062
1063 #ifdef FUTURE_WORK
1064 static long gscd_msf2hsg(struct msf *mp)
1065 {
1066 return gscd_bcd2bin(mp->frame)
1067 + gscd_bcd2bin(mp->sec) * CD_FRAMES
1068 + gscd_bcd2bin(mp->min) * CD_FRAMES * CD_SECS - CD_MSF_OFFSET;
1069 }
1070
1071 static int gscd_bcd2bin(unsigned char bcd)
1072 {
1073 return (bcd >> 4) * 10 + (bcd & 0xF);
1074 }
1075 #endif
1076
1077 MODULE_AUTHOR("Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>");
1078 MODULE_LICENSE("GPL");
1079 EXPORT_NO_SYMBOLS;
1080