blob: b3ab6e9b8df182ac4017940140edc456cb029a25 [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>
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#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
74static int gscdPresent = 0;
75
76static unsigned char gscd_buf[2048]; /* buffer for block size conversion */
77static int gscd_bn = -1;
78static short gscd_port = GSCD_BASE_ADDR;
79module_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
85static void gscd_read_cmd(struct request *req);
86static void gscd_hsg2msf(long hsg, struct msf *msf);
87static void gscd_bin2bcd(unsigned char *p);
88
89/* Schnittstellen zum Kern/FS */
90
91static void __do_gscd_request(unsigned long dummy);
92static int gscd_ioctl(struct inode *, struct file *, unsigned int,
93 unsigned long);
94static int gscd_open(struct inode *, struct file *);
95static int gscd_release(struct inode *, struct file *);
96static int check_gscd_med_chg(struct gendisk *disk);
97
98/* GoldStar Funktionen */
99
100static void cmd_out(int, char *, char *, int);
101static void cmd_status(void);
102static void init_cd_drive(int);
103
104static int get_status(void);
105static void clear_Audio(void);
106static void cc_invalidate(void);
107
108/* some things for the next version */
109#ifdef FUTURE_WORK
110static void update_state(void);
111static long gscd_msf2hsg(struct msf *mp);
112static int gscd_bcd2bin(unsigned char bcd);
113#endif
114
115
116/* lo-level cmd-Funktionen */
117
118static void cmd_info_in(char *, int);
119static void cmd_end(void);
120static void cmd_read_b(char *, int, int);
121static void cmd_read_w(char *, int, int);
122static int cmd_unit_alive(void);
123static void cmd_write_cmd(char *);
124
125
126/* GoldStar Variablen */
127
128static int curr_drv_state;
129static int drv_states[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
130static int drv_mode;
131static int disk_state;
132static int speed;
133static int ndrives;
134
135static unsigned char drv_num_read;
136static unsigned char f_dsk_valid;
137static unsigned char current_drive;
138static unsigned char f_drv_ok;
139
140
141static char f_AudioPlay;
142static char f_AudioPause;
143static int AudioStart_m;
144static int AudioStart_f;
145static int AudioEnd_m;
146static int AudioEnd_f;
147
Ingo Molnar8d06afa2005-09-09 13:10:40 -0700148static DEFINE_TIMER(gscd_timer, NULL, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149static DEFINE_SPINLOCK(gscd_lock);
150static struct request_queue *gscd_queue;
151
152static 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 */
164static 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
176static 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
191static 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
229static 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
245static void do_gscd_request(request_queue_t * q)
246{
247 __do_gscd_request(0);
248}
249
250static void __do_gscd_request(unsigned long dummy)
251{
252 struct request *req;
253 unsigned int block;
254 unsigned int nsect;
255
256repeat:
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) {
Randy Dunlap9c275a82006-08-27 01:24:00 -0700268 printk("GSCD: bad cmd %u\n", rq_data_dir(req));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 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);
285out:
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
296static 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
339static 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
369static 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
382static 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
398static 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
409static 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
425static 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
443static 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
451static 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
462static 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
470static 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
483static 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
606static 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
626static 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
649static 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
680static 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
717static 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
749static 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
782static 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
826static 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 */
846static 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
877static struct gendisk *gscd_disk;
878
879static 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. */
896static 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");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957
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
978err_out3:
979 unregister_blkdev(MAJOR_NR, "gscd");
980err_out2:
981 put_disk(gscd_disk);
982err_out1:
983 release_region(gscd_port, GSCD_IO_EXTENT);
984 return ret;
985}
986
987static 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
1001static 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
1012static 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
1019static int gscd_bcd2bin(unsigned char bcd)
1020{
1021 return (bcd >> 4) * 10 + (bcd & 0xF);
1022}
1023#endif
1024
1025MODULE_AUTHOR("Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>");
1026MODULE_LICENSE("GPL");
1027module_init(gscd_init);
1028module_exit(gscd_exit);
1029MODULE_ALIAS_BLOCKDEV_MAJOR(GOLDSTAR_CDROM_MAJOR);