blob: b6ee50a2916d79b6a8c9c4e9f46b6ef6443f035d [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001#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
75static int gscdPresent = 0;
76
77static unsigned char gscd_buf[2048]; /* buffer for block size conversion */
78static int gscd_bn = -1;
79static short gscd_port = GSCD_BASE_ADDR;
80module_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
86static void gscd_read_cmd(struct request *req);
87static void gscd_hsg2msf(long hsg, struct msf *msf);
88static void gscd_bin2bcd(unsigned char *p);
89
90/* Schnittstellen zum Kern/FS */
91
92static void __do_gscd_request(unsigned long dummy);
93static int gscd_ioctl(struct inode *, struct file *, unsigned int,
94 unsigned long);
95static int gscd_open(struct inode *, struct file *);
96static int gscd_release(struct inode *, struct file *);
97static int check_gscd_med_chg(struct gendisk *disk);
98
99/* GoldStar Funktionen */
100
101static void cmd_out(int, char *, char *, int);
102static void cmd_status(void);
103static void init_cd_drive(int);
104
105static int get_status(void);
106static void clear_Audio(void);
107static void cc_invalidate(void);
108
109/* some things for the next version */
110#ifdef FUTURE_WORK
111static void update_state(void);
112static long gscd_msf2hsg(struct msf *mp);
113static int gscd_bcd2bin(unsigned char bcd);
114#endif
115
116
117/* lo-level cmd-Funktionen */
118
119static void cmd_info_in(char *, int);
120static void cmd_end(void);
121static void cmd_read_b(char *, int, int);
122static void cmd_read_w(char *, int, int);
123static int cmd_unit_alive(void);
124static void cmd_write_cmd(char *);
125
126
127/* GoldStar Variablen */
128
129static int curr_drv_state;
130static int drv_states[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
131static int drv_mode;
132static int disk_state;
133static int speed;
134static int ndrives;
135
136static unsigned char drv_num_read;
137static unsigned char f_dsk_valid;
138static unsigned char current_drive;
139static unsigned char f_drv_ok;
140
141
142static char f_AudioPlay;
143static char f_AudioPause;
144static int AudioStart_m;
145static int AudioStart_f;
146static int AudioEnd_m;
147static int AudioEnd_f;
148
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700149static DEFINE_TIMER(gscd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150static DEFINE_SPINLOCK(gscd_lock);
151static struct request_queue *gscd_queue;
152
153static 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 */
165static 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
177static 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
192static 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
230static 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
246static void do_gscd_request(request_queue_t * q)
247{
248 __do_gscd_request(0);
249}
250
251static void __do_gscd_request(unsigned long dummy)
252{
253 struct request *req;
254 unsigned int block;
255 unsigned int nsect;
256
257repeat:
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);
286out:
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
297static 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
340static 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
370static 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
383static 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
399static 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
410static 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
426static 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
444static 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
452static 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
463static 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
471static 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
484static 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
607static 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
627static 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
650static 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
681static 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
718static 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
750static 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
783static 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
827static 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 */
847static 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
878static struct gendisk *gscd_disk;
879
880static 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. */
897static 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");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958
959 if (register_blkdev(MAJOR_NR, "gscd")) {
960 ret = -EIO;
961 goto err_out2;
962 }
963
964 gscd_queue = blk_init_queue(do_gscd_request, &gscd_lock);
965 if (!gscd_queue) {
966 ret = -ENOMEM;
967 goto err_out3;
968 }
969
970 disk_state = 0;
971 gscdPresent = 1;
972
973 gscd_disk->queue = gscd_queue;
974 add_disk(gscd_disk);
975
976 printk(KERN_INFO "GSCD: GoldStar CD-ROM Drive found.\n");
977 return 0;
978
979err_out3:
980 unregister_blkdev(MAJOR_NR, "gscd");
981err_out2:
982 put_disk(gscd_disk);
983err_out1:
984 release_region(gscd_port, GSCD_IO_EXTENT);
985 return ret;
986}
987
988static void gscd_hsg2msf(long hsg, struct msf *msf)
989{
990 hsg += CD_MSF_OFFSET;
991 msf->min = hsg / (CD_FRAMES * CD_SECS);
992 hsg %= CD_FRAMES * CD_SECS;
993 msf->sec = hsg / CD_FRAMES;
994 msf->frame = hsg % CD_FRAMES;
995
996 gscd_bin2bcd(&msf->min); /* convert to BCD */
997 gscd_bin2bcd(&msf->sec);
998 gscd_bin2bcd(&msf->frame);
999}
1000
1001
1002static void gscd_bin2bcd(unsigned char *p)
1003{
1004 int u, t;
1005
1006 u = *p % 10;
1007 t = *p / 10;
1008 *p = u | (t << 4);
1009}
1010
1011
1012#ifdef FUTURE_WORK
1013static long gscd_msf2hsg(struct msf *mp)
1014{
1015 return gscd_bcd2bin(mp->frame)
1016 + gscd_bcd2bin(mp->sec) * CD_FRAMES
1017 + gscd_bcd2bin(mp->min) * CD_FRAMES * CD_SECS - CD_MSF_OFFSET;
1018}
1019
1020static int gscd_bcd2bin(unsigned char bcd)
1021{
1022 return (bcd >> 4) * 10 + (bcd & 0xF);
1023}
1024#endif
1025
1026MODULE_AUTHOR("Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>");
1027MODULE_LICENSE("GPL");
1028module_init(gscd_init);
1029module_exit(gscd_exit);
1030MODULE_ALIAS_BLOCKDEV_MAJOR(GOLDSTAR_CDROM_MAJOR);