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