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