MOXA linux-2.6.x / linux-2.6.9-uc0 from sdlinux-moxaart.tgz
[linux-2.6.9-moxart.git] / drivers / cdrom / gscd.c
bloba89cc98c12b463f9b59815e63740f9c5e167f010
1 #define GSCD_VERSION "0.4a Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>"
3 /*
4 linux/drivers/block/gscd.c - GoldStar R420 CDROM driver
6 Copyright (C) 1995 Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>
7 based upon pre-works by Eberhard Moenkeberg <emoenke@gwdg.de>
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
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.
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.
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.
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.
35 --------------------------------------------------------------------
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>
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 /*------------------------*/
51 #include <linux/module.h>
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>
67 #include <asm/system.h>
68 #include <asm/io.h>
69 #include <asm/uaccess.h>
71 #define MAJOR_NR GOLDSTAR_CDROM_MAJOR
72 #include <linux/blkdev.h>
73 #define gscd_port gscd /* for compatible parameter passing with "insmod" */
74 #include "gscd.h"
76 static int gscdPresent = 0;
78 static unsigned char gscd_buf[2048]; /* buffer for block size conversion */
79 static int gscd_bn = -1;
80 static short gscd_port = GSCD_BASE_ADDR;
81 MODULE_PARM(gscd, "h");
83 /* Kommt spaeter vielleicht noch mal dran ...
84 * static DECLARE_WAIT_QUEUE_HEAD(gscd_waitq);
87 static void gscd_read_cmd(struct request *req);
88 static void gscd_hsg2msf(long hsg, struct msf *msf);
89 static void gscd_bin2bcd(unsigned char *p);
91 /* Schnittstellen zum Kern/FS */
93 static void __do_gscd_request(unsigned long dummy);
94 static int gscd_ioctl(struct inode *, struct file *, unsigned int,
95 unsigned long);
96 static int gscd_open(struct inode *, struct file *);
97 static int gscd_release(struct inode *, struct file *);
98 static int check_gscd_med_chg(struct gendisk *disk);
100 /* GoldStar Funktionen */
102 static void cmd_out(int, char *, char *, int);
103 static void cmd_status(void);
104 static void init_cd_drive(int);
106 static int get_status(void);
107 static void clear_Audio(void);
108 static void cc_invalidate(void);
110 /* some things for the next version */
111 #ifdef FUTURE_WORK
112 static void update_state(void);
113 static long gscd_msf2hsg(struct msf *mp);
114 static int gscd_bcd2bin(unsigned char bcd);
115 #endif
118 /* lo-level cmd-Funktionen */
120 static void cmd_info_in(char *, int);
121 static void cmd_end(void);
122 static void cmd_read_b(char *, int, int);
123 static void cmd_read_w(char *, int, int);
124 static int cmd_unit_alive(void);
125 static void cmd_write_cmd(char *);
128 /* GoldStar Variablen */
130 static int curr_drv_state;
131 static int drv_states[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
132 static int drv_mode;
133 static int disk_state;
134 static int speed;
135 static int ndrives;
137 static unsigned char drv_num_read;
138 static unsigned char f_dsk_valid;
139 static unsigned char current_drive;
140 static unsigned char f_drv_ok;
143 static char f_AudioPlay;
144 static char f_AudioPause;
145 static int AudioStart_m;
146 static int AudioStart_f;
147 static int AudioEnd_m;
148 static int AudioEnd_f;
150 static struct timer_list gscd_timer = TIMER_INITIALIZER(NULL, 0, 0);
151 static spinlock_t gscd_lock = SPIN_LOCK_UNLOCKED;
152 static struct request_queue *gscd_queue;
154 static struct block_device_operations gscd_fops = {
155 .owner = THIS_MODULE,
156 .open = gscd_open,
157 .release = gscd_release,
158 .ioctl = gscd_ioctl,
159 .media_changed = check_gscd_med_chg,
163 * Checking if the media has been changed
164 * (not yet implemented)
166 static int check_gscd_med_chg(struct gendisk *disk)
168 #ifdef GSCD_DEBUG
169 printk("gscd: check_med_change\n");
170 #endif
171 return 0;
175 #ifndef MODULE
176 /* Using new interface for kernel-parameters */
178 static int __init gscd_setup(char *str)
180 int ints[2];
181 (void) get_options(str, ARRAY_SIZE(ints), ints);
183 if (ints[0] > 0) {
184 gscd_port = ints[1];
186 return 1;
189 __setup("gscd=", gscd_setup);
191 #endif
193 static int gscd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
194 unsigned long arg)
196 unsigned char to_do[10];
197 unsigned char dummy;
200 switch (cmd) {
201 case CDROMSTART: /* Spin up the drive */
202 /* Don't think we can do this. Even if we could,
203 * I think the drive times out and stops after a while
204 * anyway. For now, ignore it.
206 return 0;
208 case CDROMRESUME: /* keine Ahnung was das ist */
209 return 0;
212 case CDROMEJECT:
213 cmd_status();
214 to_do[0] = CMD_TRAY_CTL;
215 cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0);
217 return 0;
219 default:
220 return -EINVAL;
227 * Take care of the different block sizes between cdrom and Linux.
228 * When Linux gets variable block sizes this will probably go away.
231 static void gscd_transfer(struct request *req)
233 while (req->nr_sectors > 0 && gscd_bn == req->sector / 4) {
234 long offs = (req->sector & 3) * 512;
235 memcpy(req->buffer, gscd_buf + offs, 512);
236 req->nr_sectors--;
237 req->sector++;
238 req->buffer += 512;
244 * I/O request routine called from Linux kernel.
247 static void do_gscd_request(request_queue_t * q)
249 __do_gscd_request(0);
252 static void __do_gscd_request(unsigned long dummy)
254 struct request *req;
255 unsigned int block;
256 unsigned int nsect;
258 repeat:
259 req = elv_next_request(gscd_queue);
260 if (!req)
261 return;
263 block = req->sector;
264 nsect = req->nr_sectors;
266 if (req->sector == -1)
267 goto out;
269 if (req->cmd != READ) {
270 printk("GSCD: bad cmd %lu\n", rq_data_dir(req));
271 end_request(req, 0);
272 goto repeat;
275 gscd_transfer(req);
277 /* if we satisfied the request from the buffer, we're done. */
279 if (req->nr_sectors == 0) {
280 end_request(req, 1);
281 goto repeat;
283 #ifdef GSCD_DEBUG
284 printk("GSCD: block %d, nsect %d\n", block, nsect);
285 #endif
286 gscd_read_cmd(req);
287 out:
288 return;
294 * Check the result of the set-mode command. On success, send the
295 * read-data command.
298 static void gscd_read_cmd(struct request *req)
300 long block;
301 struct gscd_Play_msf gscdcmd;
302 char cmd[] = { CMD_READ, 0x80, 0, 0, 0, 0, 1 }; /* cmd mode M-S-F secth sectl */
304 cmd_status();
305 if (disk_state & (ST_NO_DISK | ST_DOOR_OPEN)) {
306 printk("GSCD: no disk or door open\n");
307 end_request(req, 0);
308 } else {
309 if (disk_state & ST_INVALID) {
310 printk("GSCD: disk invalid\n");
311 end_request(req, 0);
312 } else {
313 gscd_bn = -1; /* purge our buffer */
314 block = req->sector / 4;
315 gscd_hsg2msf(block, &gscdcmd.start); /* cvt to msf format */
317 cmd[2] = gscdcmd.start.min;
318 cmd[3] = gscdcmd.start.sec;
319 cmd[4] = gscdcmd.start.frame;
321 #ifdef GSCD_DEBUG
322 printk("GSCD: read msf %d:%d:%d\n", cmd[2], cmd[3],
323 cmd[4]);
324 #endif
325 cmd_out(TYPE_DATA, (char *) &cmd,
326 (char *) &gscd_buf[0], 1);
328 gscd_bn = req->sector / 4;
329 gscd_transfer(req);
330 end_request(req, 1);
333 SET_TIMER(__do_gscd_request, 1);
338 * Open the device special file. Check that a disk is in.
341 static int gscd_open(struct inode *ip, struct file *fp)
343 int st;
345 #ifdef GSCD_DEBUG
346 printk("GSCD: open\n");
347 #endif
349 if (gscdPresent == 0)
350 return -ENXIO; /* no hardware */
352 get_status();
353 st = disk_state & (ST_NO_DISK | ST_DOOR_OPEN);
354 if (st) {
355 printk("GSCD: no disk or door open\n");
356 return -ENXIO;
359 /* if (updateToc() < 0)
360 return -EIO;
363 return 0;
368 * On close, we flush all gscd blocks from the buffer cache.
371 static int gscd_release(struct inode *inode, struct file *file)
374 #ifdef GSCD_DEBUG
375 printk("GSCD: release\n");
376 #endif
378 gscd_bn = -1;
380 return 0;
384 static int get_status(void)
386 int status;
388 cmd_status();
389 status = disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01);
391 if (status == (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) {
392 cc_invalidate();
393 return 1;
394 } else {
395 return 0;
400 static void cc_invalidate(void)
402 drv_num_read = 0xFF;
403 f_dsk_valid = 0xFF;
404 current_drive = 0xFF;
405 f_drv_ok = 0xFF;
407 clear_Audio();
411 static void clear_Audio(void)
414 f_AudioPlay = 0;
415 f_AudioPause = 0;
416 AudioStart_m = 0;
417 AudioStart_f = 0;
418 AudioEnd_m = 0;
419 AudioEnd_f = 0;
424 * waiting ?
427 static int wait_drv_ready(void)
429 int found, read;
431 do {
432 found = inb(GSCDPORT(0));
433 found &= 0x0f;
434 read = inb(GSCDPORT(0));
435 read &= 0x0f;
436 } while (read != found);
438 #ifdef GSCD_DEBUG
439 printk("Wait for: %d\n", read);
440 #endif
442 return read;
445 static void cc_Ident(char *respons)
447 char to_do[] = { CMD_IDENT, 0, 0 };
449 cmd_out(TYPE_INFO, (char *) &to_do, (char *) respons, (int) 0x1E);
453 static void cc_SetSpeed(void)
455 char to_do[] = { CMD_SETSPEED, 0, 0 };
456 char dummy;
458 if (speed > 0) {
459 to_do[1] = speed & 0x0F;
460 cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0);
464 static void cc_Reset(void)
466 char to_do[] = { CMD_RESET, 0 };
467 char dummy;
469 cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0);
472 static void cmd_status(void)
474 char to_do[] = { CMD_STATUS, 0 };
475 char dummy;
477 cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0);
479 #ifdef GSCD_DEBUG
480 printk("GSCD: Status: %d\n", disk_state);
481 #endif
485 static void cmd_out(int cmd_type, char *cmd, char *respo_buf, int respo_count)
487 int result;
490 result = wait_drv_ready();
491 if (result != drv_mode) {
492 unsigned long test_loops = 0xFFFF;
493 int i, dummy;
495 outb(curr_drv_state, GSCDPORT(0));
497 /* LOCLOOP_170 */
498 do {
499 result = wait_drv_ready();
500 test_loops--;
501 } while ((result != drv_mode) && (test_loops > 0));
503 if (result != drv_mode) {
504 disk_state = ST_x08 | ST_x04 | ST_INVALID;
505 return;
508 /* ...and waiting */
509 for (i = 1, dummy = 1; i < 0xFFFF; i++) {
510 dummy *= i;
514 /* LOC_172 */
515 /* check the unit */
516 /* and wake it up */
517 if (cmd_unit_alive() != 0x08) {
518 /* LOC_174 */
519 /* game over for this unit */
520 disk_state = ST_x08 | ST_x04 | ST_INVALID;
521 return;
524 /* LOC_176 */
525 #ifdef GSCD_DEBUG
526 printk("LOC_176 ");
527 #endif
528 if (drv_mode == 0x09) {
529 /* magic... */
530 printk("GSCD: magic ...\n");
531 outb(result, GSCDPORT(2));
534 /* write the command to the drive */
535 cmd_write_cmd(cmd);
537 /* LOC_178 */
538 for (;;) {
539 result = wait_drv_ready();
540 if (result != drv_mode) {
541 /* LOC_179 */
542 if (result == 0x04) { /* Mode 4 */
543 /* LOC_205 */
544 #ifdef GSCD_DEBUG
545 printk("LOC_205 ");
546 #endif
547 disk_state = inb(GSCDPORT(2));
549 do {
550 result = wait_drv_ready();
551 } while (result != drv_mode);
552 return;
554 } else {
555 if (result == 0x06) { /* Mode 6 */
556 /* LOC_181 */
557 #ifdef GSCD_DEBUG
558 printk("LOC_181 ");
559 #endif
561 if (cmd_type == TYPE_DATA) {
562 /* read data */
563 /* LOC_184 */
564 if (drv_mode == 9) {
565 /* read the data to the buffer (word) */
567 /* (*(cmd+1))?(CD_FRAMESIZE/2):(CD_FRAMESIZE_RAW/2) */
568 cmd_read_w
569 (respo_buf,
570 respo_count,
571 CD_FRAMESIZE /
573 return;
574 } else {
575 /* read the data to the buffer (byte) */
577 /* (*(cmd+1))?(CD_FRAMESIZE):(CD_FRAMESIZE_RAW) */
578 cmd_read_b
579 (respo_buf,
580 respo_count,
581 CD_FRAMESIZE);
582 return;
584 } else {
585 /* read the info to the buffer */
586 cmd_info_in(respo_buf,
587 respo_count);
588 return;
591 return;
595 } else {
596 disk_state = ST_x08 | ST_x04 | ST_INVALID;
597 return;
599 } /* for (;;) */
602 #ifdef GSCD_DEBUG
603 printk("\n");
604 #endif
608 static void cmd_write_cmd(char *pstr)
610 int i, j;
612 /* LOC_177 */
613 #ifdef GSCD_DEBUG
614 printk("LOC_177 ");
615 #endif
617 /* calculate the number of parameter */
618 j = *pstr & 0x0F;
620 /* shift it out */
621 for (i = 0; i < j; i++) {
622 outb(*pstr, GSCDPORT(2));
623 pstr++;
628 static int cmd_unit_alive(void)
630 int result;
631 unsigned long max_test_loops;
634 /* LOC_172 */
635 #ifdef GSCD_DEBUG
636 printk("LOC_172 ");
637 #endif
639 outb(curr_drv_state, GSCDPORT(0));
640 max_test_loops = 0xFFFF;
642 do {
643 result = wait_drv_ready();
644 max_test_loops--;
645 } while ((result != 0x08) && (max_test_loops > 0));
647 return result;
651 static void cmd_info_in(char *pb, int count)
653 int result;
654 char read;
657 /* read info */
658 /* LOC_182 */
659 #ifdef GSCD_DEBUG
660 printk("LOC_182 ");
661 #endif
663 do {
664 read = inb(GSCDPORT(2));
665 if (count > 0) {
666 *pb = read;
667 pb++;
668 count--;
671 /* LOC_183 */
672 do {
673 result = wait_drv_ready();
674 } while (result == 0x0E);
675 } while (result == 6);
677 cmd_end();
678 return;
682 static void cmd_read_b(char *pb, int count, int size)
684 int result;
685 int i;
688 /* LOC_188 */
689 /* LOC_189 */
690 #ifdef GSCD_DEBUG
691 printk("LOC_189 ");
692 #endif
694 do {
695 do {
696 result = wait_drv_ready();
697 } while (result != 6 || result == 0x0E);
699 if (result != 6) {
700 cmd_end();
701 return;
703 #ifdef GSCD_DEBUG
704 printk("LOC_191 ");
705 #endif
707 for (i = 0; i < size; i++) {
708 *pb = inb(GSCDPORT(2));
709 pb++;
711 count--;
712 } while (count > 0);
714 cmd_end();
715 return;
719 static void cmd_end(void)
721 int result;
724 /* LOC_204 */
725 #ifdef GSCD_DEBUG
726 printk("LOC_204 ");
727 #endif
729 do {
730 result = wait_drv_ready();
731 if (result == drv_mode) {
732 return;
734 } while (result != 4);
736 /* LOC_205 */
737 #ifdef GSCD_DEBUG
738 printk("LOC_205 ");
739 #endif
741 disk_state = inb(GSCDPORT(2));
743 do {
744 result = wait_drv_ready();
745 } while (result != drv_mode);
746 return;
751 static void cmd_read_w(char *pb, int count, int size)
753 int result;
754 int i;
757 #ifdef GSCD_DEBUG
758 printk("LOC_185 ");
759 #endif
761 do {
762 /* LOC_185 */
763 do {
764 result = wait_drv_ready();
765 } while (result != 6 || result == 0x0E);
767 if (result != 6) {
768 cmd_end();
769 return;
772 for (i = 0; i < size; i++) {
773 /* na, hier muss ich noch mal drueber nachdenken */
774 *pb = inw(GSCDPORT(2));
775 pb++;
777 count--;
778 } while (count > 0);
780 cmd_end();
781 return;
784 static int __init find_drives(void)
786 int *pdrv;
787 int drvnum;
788 int subdrv;
789 int i;
791 speed = 0;
792 pdrv = (int *) &drv_states;
793 curr_drv_state = 0xFE;
794 subdrv = 0;
795 drvnum = 0;
797 for (i = 0; i < 8; i++) {
798 subdrv++;
799 cmd_status();
800 disk_state &= ST_x08 | ST_x04 | ST_INVALID | ST_x01;
801 if (disk_state != (ST_x08 | ST_x04 | ST_INVALID)) {
802 /* LOC_240 */
803 *pdrv = curr_drv_state;
804 init_cd_drive(drvnum);
805 pdrv++;
806 drvnum++;
807 } else {
808 if (subdrv < 2) {
809 continue;
810 } else {
811 subdrv = 0;
815 /* curr_drv_state<<1; <-- das geht irgendwie nicht */
816 /* muss heissen: curr_drv_state <<= 1; (ist ja Wert-Zuweisung) */
817 curr_drv_state *= 2;
818 curr_drv_state |= 1;
819 #ifdef GSCD_DEBUG
820 printk("DriveState: %d\n", curr_drv_state);
821 #endif
824 ndrives = drvnum;
825 return drvnum;
828 static void __init init_cd_drive(int num)
830 char resp[50];
831 int i;
833 printk("GSCD: init unit %d\n", num);
834 cc_Ident((char *) &resp);
836 printk("GSCD: identification: ");
837 for (i = 0; i < 0x1E; i++) {
838 printk("%c", resp[i]);
840 printk("\n");
842 cc_SetSpeed();
846 #ifdef FUTURE_WORK
847 /* return_done */
848 static void update_state(void)
850 unsigned int AX;
853 if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) == 0) {
854 if (disk_state == (ST_x08 | ST_x04 | ST_INVALID)) {
855 AX = ST_INVALID;
858 if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01))
859 == 0) {
860 invalidate();
861 f_drv_ok = 0;
864 AX |= 0x8000;
867 if (disk_state & ST_PLAYING) {
868 AX |= 0x200;
871 AX |= 0x100;
872 /* pkt_esbx = AX; */
874 disk_state = 0;
877 #endif
879 static struct gendisk *gscd_disk;
881 static void __exit gscd_exit(void)
883 CLEAR_TIMER;
885 del_gendisk(gscd_disk);
886 put_disk(gscd_disk);
887 if ((unregister_blkdev(MAJOR_NR, "gscd") == -EINVAL)) {
888 printk("What's that: can't unregister GoldStar-module\n");
889 return;
891 blk_cleanup_queue(gscd_queue);
892 release_region(gscd_port, GSCD_IO_EXTENT);
893 printk(KERN_INFO "GoldStar-module released.\n");
896 /* This is the common initialisation for the GoldStar drive. */
897 /* It is called at boot time AND for module init. */
898 static int __init gscd_init(void)
900 int i;
901 int result;
902 int ret=0;
904 printk(KERN_INFO "GSCD: version %s\n", GSCD_VERSION);
905 printk(KERN_INFO
906 "GSCD: Trying to detect a Goldstar R420 CD-ROM drive at 0x%X.\n",
907 gscd_port);
909 if (!request_region(gscd_port, GSCD_IO_EXTENT, "gscd")) {
910 printk(KERN_WARNING "GSCD: Init failed, I/O port (%X) already"
911 " in use.\n", gscd_port);
912 return -EIO;
916 /* check for card */
917 result = wait_drv_ready();
918 if (result == 0x09) {
919 printk(KERN_WARNING "GSCD: DMA kann ich noch nicht!\n");
920 ret = -EIO;
921 goto err_out1;
924 if (result == 0x0b) {
925 drv_mode = result;
926 i = find_drives();
927 if (i == 0) {
928 printk(KERN_WARNING "GSCD: GoldStar CD-ROM Drive is"
929 " not found.\n");
930 ret = -EIO;
931 goto err_out1;
935 if ((result != 0x0b) && (result != 0x09)) {
936 printk(KERN_WARNING "GSCD: GoldStar Interface Adapter does not "
937 "exist or H/W error\n");
938 ret = -EIO;
939 goto err_out1;
942 /* reset all drives */
943 i = 0;
944 while (drv_states[i] != 0) {
945 curr_drv_state = drv_states[i];
946 printk(KERN_INFO "GSCD: Reset unit %d ... ", i);
947 cc_Reset();
948 printk("done\n");
949 i++;
952 gscd_disk = alloc_disk(1);
953 if (!gscd_disk)
954 goto err_out1;
955 gscd_disk->major = MAJOR_NR;
956 gscd_disk->first_minor = 0;
957 gscd_disk->fops = &gscd_fops;
958 sprintf(gscd_disk->disk_name, "gscd");
959 sprintf(gscd_disk->devfs_name, "gscd");
961 if (register_blkdev(MAJOR_NR, "gscd")) {
962 ret = -EIO;
963 goto err_out2;
966 gscd_queue = blk_init_queue(do_gscd_request, &gscd_lock);
967 if (!gscd_queue) {
968 ret = -ENOMEM;
969 goto err_out3;
972 disk_state = 0;
973 gscdPresent = 1;
975 gscd_disk->queue = gscd_queue;
976 add_disk(gscd_disk);
978 printk(KERN_INFO "GSCD: GoldStar CD-ROM Drive found.\n");
979 return 0;
981 err_out3:
982 unregister_blkdev(MAJOR_NR, "gscd");
983 err_out2:
984 put_disk(gscd_disk);
985 err_out1:
986 release_region(gscd_port, GSCD_IO_EXTENT);
987 return ret;
990 static void gscd_hsg2msf(long hsg, struct msf *msf)
992 hsg += CD_MSF_OFFSET;
993 msf->min = hsg / (CD_FRAMES * CD_SECS);
994 hsg %= CD_FRAMES * CD_SECS;
995 msf->sec = hsg / CD_FRAMES;
996 msf->frame = hsg % CD_FRAMES;
998 gscd_bin2bcd(&msf->min); /* convert to BCD */
999 gscd_bin2bcd(&msf->sec);
1000 gscd_bin2bcd(&msf->frame);
1004 static void gscd_bin2bcd(unsigned char *p)
1006 int u, t;
1008 u = *p % 10;
1009 t = *p / 10;
1010 *p = u | (t << 4);
1014 #ifdef FUTURE_WORK
1015 static long gscd_msf2hsg(struct msf *mp)
1017 return gscd_bcd2bin(mp->frame)
1018 + gscd_bcd2bin(mp->sec) * CD_FRAMES
1019 + gscd_bcd2bin(mp->min) * CD_FRAMES * CD_SECS - CD_MSF_OFFSET;
1022 static int gscd_bcd2bin(unsigned char bcd)
1024 return (bcd >> 4) * 10 + (bcd & 0xF);
1026 #endif
1028 MODULE_AUTHOR("Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>");
1029 MODULE_LICENSE("GPL");
1030 module_init(gscd_init);
1031 module_exit(gscd_exit);
1032 MODULE_ALIAS_BLOCKDEV_MAJOR(GOLDSTAR_CDROM_MAJOR);