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