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