| #define GSCD_VERSION "0.4a Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>" | |
| /* | |
| linux/drivers/block/gscd.c - GoldStar R420 CDROM driver | |
| Copyright (C) 1995 Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de> | |
| based upon pre-works by Eberhard Moenkeberg <emoenke@gwdg.de> | |
| For all kind of other information about the GoldStar CDROM | |
| and this Linux device driver I installed a WWW-URL: | |
| http://linux.rz.fh-hannover.de/~raupach | |
| If you are the editor of a Linux CD, you should | |
| enable gscd.c within your boot floppy kernel and | |
| send me one of your CDs for free. | |
| -------------------------------------------------------------------- | |
| This program is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2, or (at your option) | |
| any later version. | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with this program; if not, write to the Free Software | |
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
| -------------------------------------------------------------------- | |
| 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x | |
| Removed init_module & cleanup_module in favor of | |
| module_init & module_exit. | |
| Torben Mathiasen <tmm@image.dk> | |
| */ | |
| /* These settings are for various debug-level. Leave they untouched ... */ | |
| #define NO_GSCD_DEBUG | |
| #define NO_IOCTL_DEBUG | |
| #define NO_MODULE_DEBUG | |
| #define NO_FUTURE_WORK | |
| /*------------------------*/ | |
| #include <linux/module.h> | |
| #include <linux/slab.h> | |
| #include <linux/errno.h> | |
| #include <linux/signal.h> | |
| #include <linux/sched.h> | |
| #include <linux/timer.h> | |
| #include <linux/fs.h> | |
| #include <linux/mm.h> | |
| #include <linux/kernel.h> | |
| #include <linux/cdrom.h> | |
| #include <linux/ioport.h> | |
| #include <linux/major.h> | |
| #include <linux/string.h> | |
| #include <linux/init.h> | |
| #include <asm/system.h> | |
| #include <asm/io.h> | |
| #include <asm/uaccess.h> | |
| #define MAJOR_NR GOLDSTAR_CDROM_MAJOR | |
| #include <linux/blkdev.h> | |
| #include "gscd.h" | |
| static int gscdPresent = 0; | |
| static unsigned char gscd_buf[2048]; /* buffer for block size conversion */ | |
| static int gscd_bn = -1; | |
| static short gscd_port = GSCD_BASE_ADDR; | |
| module_param_named(gscd, gscd_port, short, 0); | |
| /* Kommt spaeter vielleicht noch mal dran ... | |
| * static DECLARE_WAIT_QUEUE_HEAD(gscd_waitq); | |
| */ | |
| static void gscd_read_cmd(struct request *req); | |
| static void gscd_hsg2msf(long hsg, struct msf *msf); | |
| static void gscd_bin2bcd(unsigned char *p); | |
| /* Schnittstellen zum Kern/FS */ | |
| static void __do_gscd_request(unsigned long dummy); | |
| static int gscd_ioctl(struct inode *, struct file *, unsigned int, | |
| unsigned long); | |
| static int gscd_open(struct inode *, struct file *); | |
| static int gscd_release(struct inode *, struct file *); | |
| static int check_gscd_med_chg(struct gendisk *disk); | |
| /* GoldStar Funktionen */ | |
| static void cmd_out(int, char *, char *, int); | |
| static void cmd_status(void); | |
| static void init_cd_drive(int); | |
| static int get_status(void); | |
| static void clear_Audio(void); | |
| static void cc_invalidate(void); | |
| /* some things for the next version */ | |
| #ifdef FUTURE_WORK | |
| static void update_state(void); | |
| static long gscd_msf2hsg(struct msf *mp); | |
| static int gscd_bcd2bin(unsigned char bcd); | |
| #endif | |
| /* lo-level cmd-Funktionen */ | |
| static void cmd_info_in(char *, int); | |
| static void cmd_end(void); | |
| static void cmd_read_b(char *, int, int); | |
| static void cmd_read_w(char *, int, int); | |
| static int cmd_unit_alive(void); | |
| static void cmd_write_cmd(char *); | |
| /* GoldStar Variablen */ | |
| static int curr_drv_state; | |
| static int drv_states[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | |
| static int drv_mode; | |
| static int disk_state; | |
| static int speed; | |
| static int ndrives; | |
| static unsigned char drv_num_read; | |
| static unsigned char f_dsk_valid; | |
| static unsigned char current_drive; | |
| static unsigned char f_drv_ok; | |
| static char f_AudioPlay; | |
| static char f_AudioPause; | |
| static int AudioStart_m; | |
| static int AudioStart_f; | |
| static int AudioEnd_m; | |
| static int AudioEnd_f; | |
| static DEFINE_TIMER(gscd_timer, NULL, 0, 0); | |
| static DEFINE_SPINLOCK(gscd_lock); | |
| static struct request_queue *gscd_queue; | |
| static struct block_device_operations gscd_fops = { | |
| .owner = THIS_MODULE, | |
| .open = gscd_open, | |
| .release = gscd_release, | |
| .ioctl = gscd_ioctl, | |
| .media_changed = check_gscd_med_chg, | |
| }; | |
| /* | |
| * Checking if the media has been changed | |
| * (not yet implemented) | |
| */ | |
| static int check_gscd_med_chg(struct gendisk *disk) | |
| { | |
| #ifdef GSCD_DEBUG | |
| printk("gscd: check_med_change\n"); | |
| #endif | |
| return 0; | |
| } | |
| #ifndef MODULE | |
| /* Using new interface for kernel-parameters */ | |
| static int __init gscd_setup(char *str) | |
| { | |
| int ints[2]; | |
| (void) get_options(str, ARRAY_SIZE(ints), ints); | |
| if (ints[0] > 0) { | |
| gscd_port = ints[1]; | |
| } | |
| return 1; | |
| } | |
| __setup("gscd=", gscd_setup); | |
| #endif | |
| static int gscd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, | |
| unsigned long arg) | |
| { | |
| unsigned char to_do[10]; | |
| unsigned char dummy; | |
| switch (cmd) { | |
| case CDROMSTART: /* Spin up the drive */ | |
| /* Don't think we can do this. Even if we could, | |
| * I think the drive times out and stops after a while | |
| * anyway. For now, ignore it. | |
| */ | |
| return 0; | |
| case CDROMRESUME: /* keine Ahnung was das ist */ | |
| return 0; | |
| case CDROMEJECT: | |
| cmd_status(); | |
| to_do[0] = CMD_TRAY_CTL; | |
| cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); | |
| return 0; | |
| default: | |
| return -EINVAL; | |
| } | |
| } | |
| /* | |
| * Take care of the different block sizes between cdrom and Linux. | |
| * When Linux gets variable block sizes this will probably go away. | |
| */ | |
| static void gscd_transfer(struct request *req) | |
| { | |
| while (req->nr_sectors > 0 && gscd_bn == req->sector / 4) { | |
| long offs = (req->sector & 3) * 512; | |
| memcpy(req->buffer, gscd_buf + offs, 512); | |
| req->nr_sectors--; | |
| req->sector++; | |
| req->buffer += 512; | |
| } | |
| } | |
| /* | |
| * I/O request routine called from Linux kernel. | |
| */ | |
| static void do_gscd_request(request_queue_t * q) | |
| { | |
| __do_gscd_request(0); | |
| } | |
| static void __do_gscd_request(unsigned long dummy) | |
| { | |
| struct request *req; | |
| unsigned int block; | |
| unsigned int nsect; | |
| repeat: | |
| req = elv_next_request(gscd_queue); | |
| if (!req) | |
| return; | |
| block = req->sector; | |
| nsect = req->nr_sectors; | |
| if (req->sector == -1) | |
| goto out; | |
| if (req->cmd != READ) { | |
| printk("GSCD: bad cmd %u\n", rq_data_dir(req)); | |
| end_request(req, 0); | |
| goto repeat; | |
| } | |
| gscd_transfer(req); | |
| /* if we satisfied the request from the buffer, we're done. */ | |
| if (req->nr_sectors == 0) { | |
| end_request(req, 1); | |
| goto repeat; | |
| } | |
| #ifdef GSCD_DEBUG | |
| printk("GSCD: block %d, nsect %d\n", block, nsect); | |
| #endif | |
| gscd_read_cmd(req); | |
| out: | |
| return; | |
| } | |
| /* | |
| * Check the result of the set-mode command. On success, send the | |
| * read-data command. | |
| */ | |
| static void gscd_read_cmd(struct request *req) | |
| { | |
| long block; | |
| struct gscd_Play_msf gscdcmd; | |
| char cmd[] = { CMD_READ, 0x80, 0, 0, 0, 0, 1 }; /* cmd mode M-S-F secth sectl */ | |
| cmd_status(); | |
| if (disk_state & (ST_NO_DISK | ST_DOOR_OPEN)) { | |
| printk("GSCD: no disk or door open\n"); | |
| end_request(req, 0); | |
| } else { | |
| if (disk_state & ST_INVALID) { | |
| printk("GSCD: disk invalid\n"); | |
| end_request(req, 0); | |
| } else { | |
| gscd_bn = -1; /* purge our buffer */ | |
| block = req->sector / 4; | |
| gscd_hsg2msf(block, &gscdcmd.start); /* cvt to msf format */ | |
| cmd[2] = gscdcmd.start.min; | |
| cmd[3] = gscdcmd.start.sec; | |
| cmd[4] = gscdcmd.start.frame; | |
| #ifdef GSCD_DEBUG | |
| printk("GSCD: read msf %d:%d:%d\n", cmd[2], cmd[3], | |
| cmd[4]); | |
| #endif | |
| cmd_out(TYPE_DATA, (char *) &cmd, | |
| (char *) &gscd_buf[0], 1); | |
| gscd_bn = req->sector / 4; | |
| gscd_transfer(req); | |
| end_request(req, 1); | |
| } | |
| } | |
| SET_TIMER(__do_gscd_request, 1); | |
| } | |
| /* | |
| * Open the device special file. Check that a disk is in. | |
| */ | |
| static int gscd_open(struct inode *ip, struct file *fp) | |
| { | |
| int st; | |
| #ifdef GSCD_DEBUG | |
| printk("GSCD: open\n"); | |
| #endif | |
| if (gscdPresent == 0) | |
| return -ENXIO; /* no hardware */ | |
| get_status(); | |
| st = disk_state & (ST_NO_DISK | ST_DOOR_OPEN); | |
| if (st) { | |
| printk("GSCD: no disk or door open\n"); | |
| return -ENXIO; | |
| } | |
| /* if (updateToc() < 0) | |
| return -EIO; | |
| */ | |
| return 0; | |
| } | |
| /* | |
| * On close, we flush all gscd blocks from the buffer cache. | |
| */ | |
| static int gscd_release(struct inode *inode, struct file *file) | |
| { | |
| #ifdef GSCD_DEBUG | |
| printk("GSCD: release\n"); | |
| #endif | |
| gscd_bn = -1; | |
| return 0; | |
| } | |
| static int get_status(void) | |
| { | |
| int status; | |
| cmd_status(); | |
| status = disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01); | |
| if (status == (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) { | |
| cc_invalidate(); | |
| return 1; | |
| } else { | |
| return 0; | |
| } | |
| } | |
| static void cc_invalidate(void) | |
| { | |
| drv_num_read = 0xFF; | |
| f_dsk_valid = 0xFF; | |
| current_drive = 0xFF; | |
| f_drv_ok = 0xFF; | |
| clear_Audio(); | |
| } | |
| static void clear_Audio(void) | |
| { | |
| f_AudioPlay = 0; | |
| f_AudioPause = 0; | |
| AudioStart_m = 0; | |
| AudioStart_f = 0; | |
| AudioEnd_m = 0; | |
| AudioEnd_f = 0; | |
| } | |
| /* | |
| * waiting ? | |
| */ | |
| static int wait_drv_ready(void) | |
| { | |
| int found, read; | |
| do { | |
| found = inb(GSCDPORT(0)); | |
| found &= 0x0f; | |
| read = inb(GSCDPORT(0)); | |
| read &= 0x0f; | |
| } while (read != found); | |
| #ifdef GSCD_DEBUG | |
| printk("Wait for: %d\n", read); | |
| #endif | |
| return read; | |
| } | |
| static void cc_Ident(char *respons) | |
| { | |
| char to_do[] = { CMD_IDENT, 0, 0 }; | |
| cmd_out(TYPE_INFO, (char *) &to_do, (char *) respons, (int) 0x1E); | |
| } | |
| static void cc_SetSpeed(void) | |
| { | |
| char to_do[] = { CMD_SETSPEED, 0, 0 }; | |
| char dummy; | |
| if (speed > 0) { | |
| to_do[1] = speed & 0x0F; | |
| cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); | |
| } | |
| } | |
| static void cc_Reset(void) | |
| { | |
| char to_do[] = { CMD_RESET, 0 }; | |
| char dummy; | |
| cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); | |
| } | |
| static void cmd_status(void) | |
| { | |
| char to_do[] = { CMD_STATUS, 0 }; | |
| char dummy; | |
| cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); | |
| #ifdef GSCD_DEBUG | |
| printk("GSCD: Status: %d\n", disk_state); | |
| #endif | |
| } | |
| static void cmd_out(int cmd_type, char *cmd, char *respo_buf, int respo_count) | |
| { | |
| int result; | |
| result = wait_drv_ready(); | |
| if (result != drv_mode) { | |
| unsigned long test_loops = 0xFFFF; | |
| int i, dummy; | |
| outb(curr_drv_state, GSCDPORT(0)); | |
| /* LOCLOOP_170 */ | |
| do { | |
| result = wait_drv_ready(); | |
| test_loops--; | |
| } while ((result != drv_mode) && (test_loops > 0)); | |
| if (result != drv_mode) { | |
| disk_state = ST_x08 | ST_x04 | ST_INVALID; | |
| return; | |
| } | |
| /* ...and waiting */ | |
| for (i = 1, dummy = 1; i < 0xFFFF; i++) { | |
| dummy *= i; | |
| } | |
| } | |
| /* LOC_172 */ | |
| /* check the unit */ | |
| /* and wake it up */ | |
| if (cmd_unit_alive() != 0x08) { | |
| /* LOC_174 */ | |
| /* game over for this unit */ | |
| disk_state = ST_x08 | ST_x04 | ST_INVALID; | |
| return; | |
| } | |
| /* LOC_176 */ | |
| #ifdef GSCD_DEBUG | |
| printk("LOC_176 "); | |
| #endif | |
| if (drv_mode == 0x09) { | |
| /* magic... */ | |
| printk("GSCD: magic ...\n"); | |
| outb(result, GSCDPORT(2)); | |
| } | |
| /* write the command to the drive */ | |
| cmd_write_cmd(cmd); | |
| /* LOC_178 */ | |
| for (;;) { | |
| result = wait_drv_ready(); | |
| if (result != drv_mode) { | |
| /* LOC_179 */ | |
| if (result == 0x04) { /* Mode 4 */ | |
| /* LOC_205 */ | |
| #ifdef GSCD_DEBUG | |
| printk("LOC_205 "); | |
| #endif | |
| disk_state = inb(GSCDPORT(2)); | |
| do { | |
| result = wait_drv_ready(); | |
| } while (result != drv_mode); | |
| return; | |
| } else { | |
| if (result == 0x06) { /* Mode 6 */ | |
| /* LOC_181 */ | |
| #ifdef GSCD_DEBUG | |
| printk("LOC_181 "); | |
| #endif | |
| if (cmd_type == TYPE_DATA) { | |
| /* read data */ | |
| /* LOC_184 */ | |
| if (drv_mode == 9) { | |
| /* read the data to the buffer (word) */ | |
| /* (*(cmd+1))?(CD_FRAMESIZE/2):(CD_FRAMESIZE_RAW/2) */ | |
| cmd_read_w | |
| (respo_buf, | |
| respo_count, | |
| CD_FRAMESIZE / | |
| 2); | |
| return; | |
| } else { | |
| /* read the data to the buffer (byte) */ | |
| /* (*(cmd+1))?(CD_FRAMESIZE):(CD_FRAMESIZE_RAW) */ | |
| cmd_read_b | |
| (respo_buf, | |
| respo_count, | |
| CD_FRAMESIZE); | |
| return; | |
| } | |
| } else { | |
| /* read the info to the buffer */ | |
| cmd_info_in(respo_buf, | |
| respo_count); | |
| return; | |
| } | |
| return; | |
| } | |
| } | |
| } else { | |
| disk_state = ST_x08 | ST_x04 | ST_INVALID; | |
| return; | |
| } | |
| } /* for (;;) */ | |
| #ifdef GSCD_DEBUG | |
| printk("\n"); | |
| #endif | |
| } | |
| static void cmd_write_cmd(char *pstr) | |
| { | |
| int i, j; | |
| /* LOC_177 */ | |
| #ifdef GSCD_DEBUG | |
| printk("LOC_177 "); | |
| #endif | |
| /* calculate the number of parameter */ | |
| j = *pstr & 0x0F; | |
| /* shift it out */ | |
| for (i = 0; i < j; i++) { | |
| outb(*pstr, GSCDPORT(2)); | |
| pstr++; | |
| } | |
| } | |
| static int cmd_unit_alive(void) | |
| { | |
| int result; | |
| unsigned long max_test_loops; | |
| /* LOC_172 */ | |
| #ifdef GSCD_DEBUG | |
| printk("LOC_172 "); | |
| #endif | |
| outb(curr_drv_state, GSCDPORT(0)); | |
| max_test_loops = 0xFFFF; | |
| do { | |
| result = wait_drv_ready(); | |
| max_test_loops--; | |
| } while ((result != 0x08) && (max_test_loops > 0)); | |
| return result; | |
| } | |
| static void cmd_info_in(char *pb, int count) | |
| { | |
| int result; | |
| char read; | |
| /* read info */ | |
| /* LOC_182 */ | |
| #ifdef GSCD_DEBUG | |
| printk("LOC_182 "); | |
| #endif | |
| do { | |
| read = inb(GSCDPORT(2)); | |
| if (count > 0) { | |
| *pb = read; | |
| pb++; | |
| count--; | |
| } | |
| /* LOC_183 */ | |
| do { | |
| result = wait_drv_ready(); | |
| } while (result == 0x0E); | |
| } while (result == 6); | |
| cmd_end(); | |
| return; | |
| } | |
| static void cmd_read_b(char *pb, int count, int size) | |
| { | |
| int result; | |
| int i; | |
| /* LOC_188 */ | |
| /* LOC_189 */ | |
| #ifdef GSCD_DEBUG | |
| printk("LOC_189 "); | |
| #endif | |
| do { | |
| do { | |
| result = wait_drv_ready(); | |
| } while (result != 6 || result == 0x0E); | |
| if (result != 6) { | |
| cmd_end(); | |
| return; | |
| } | |
| #ifdef GSCD_DEBUG | |
| printk("LOC_191 "); | |
| #endif | |
| for (i = 0; i < size; i++) { | |
| *pb = inb(GSCDPORT(2)); | |
| pb++; | |
| } | |
| count--; | |
| } while (count > 0); | |
| cmd_end(); | |
| return; | |
| } | |
| static void cmd_end(void) | |
| { | |
| int result; | |
| /* LOC_204 */ | |
| #ifdef GSCD_DEBUG | |
| printk("LOC_204 "); | |
| #endif | |
| do { | |
| result = wait_drv_ready(); | |
| if (result == drv_mode) { | |
| return; | |
| } | |
| } while (result != 4); | |
| /* LOC_205 */ | |
| #ifdef GSCD_DEBUG | |
| printk("LOC_205 "); | |
| #endif | |
| disk_state = inb(GSCDPORT(2)); | |
| do { | |
| result = wait_drv_ready(); | |
| } while (result != drv_mode); | |
| return; | |
| } | |
| static void cmd_read_w(char *pb, int count, int size) | |
| { | |
| int result; | |
| int i; | |
| #ifdef GSCD_DEBUG | |
| printk("LOC_185 "); | |
| #endif | |
| do { | |
| /* LOC_185 */ | |
| do { | |
| result = wait_drv_ready(); | |
| } while (result != 6 || result == 0x0E); | |
| if (result != 6) { | |
| cmd_end(); | |
| return; | |
| } | |
| for (i = 0; i < size; i++) { | |
| /* na, hier muss ich noch mal drueber nachdenken */ | |
| *pb = inw(GSCDPORT(2)); | |
| pb++; | |
| } | |
| count--; | |
| } while (count > 0); | |
| cmd_end(); | |
| return; | |
| } | |
| static int __init find_drives(void) | |
| { | |
| int *pdrv; | |
| int drvnum; | |
| int subdrv; | |
| int i; | |
| speed = 0; | |
| pdrv = (int *) &drv_states; | |
| curr_drv_state = 0xFE; | |
| subdrv = 0; | |
| drvnum = 0; | |
| for (i = 0; i < 8; i++) { | |
| subdrv++; | |
| cmd_status(); | |
| disk_state &= ST_x08 | ST_x04 | ST_INVALID | ST_x01; | |
| if (disk_state != (ST_x08 | ST_x04 | ST_INVALID)) { | |
| /* LOC_240 */ | |
| *pdrv = curr_drv_state; | |
| init_cd_drive(drvnum); | |
| pdrv++; | |
| drvnum++; | |
| } else { | |
| if (subdrv < 2) { | |
| continue; | |
| } else { | |
| subdrv = 0; | |
| } | |
| } | |
| /* curr_drv_state<<1; <-- das geht irgendwie nicht */ | |
| /* muss heissen: curr_drv_state <<= 1; (ist ja Wert-Zuweisung) */ | |
| curr_drv_state *= 2; | |
| curr_drv_state |= 1; | |
| #ifdef GSCD_DEBUG | |
| printk("DriveState: %d\n", curr_drv_state); | |
| #endif | |
| } | |
| ndrives = drvnum; | |
| return drvnum; | |
| } | |
| static void __init init_cd_drive(int num) | |
| { | |
| char resp[50]; | |
| int i; | |
| printk("GSCD: init unit %d\n", num); | |
| cc_Ident((char *) &resp); | |
| printk("GSCD: identification: "); | |
| for (i = 0; i < 0x1E; i++) { | |
| printk("%c", resp[i]); | |
| } | |
| printk("\n"); | |
| cc_SetSpeed(); | |
| } | |
| #ifdef FUTURE_WORK | |
| /* return_done */ | |
| static void update_state(void) | |
| { | |
| unsigned int AX; | |
| if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) == 0) { | |
| if (disk_state == (ST_x08 | ST_x04 | ST_INVALID)) { | |
| AX = ST_INVALID; | |
| } | |
| if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) | |
| == 0) { | |
| invalidate(); | |
| f_drv_ok = 0; | |
| } | |
| AX |= 0x8000; | |
| } | |
| if (disk_state & ST_PLAYING) { | |
| AX |= 0x200; | |
| } | |
| AX |= 0x100; | |
| /* pkt_esbx = AX; */ | |
| disk_state = 0; | |
| } | |
| #endif | |
| static struct gendisk *gscd_disk; | |
| static void __exit gscd_exit(void) | |
| { | |
| CLEAR_TIMER; | |
| del_gendisk(gscd_disk); | |
| put_disk(gscd_disk); | |
| if ((unregister_blkdev(MAJOR_NR, "gscd") == -EINVAL)) { | |
| printk("What's that: can't unregister GoldStar-module\n"); | |
| return; | |
| } | |
| blk_cleanup_queue(gscd_queue); | |
| release_region(gscd_port, GSCD_IO_EXTENT); | |
| printk(KERN_INFO "GoldStar-module released.\n"); | |
| } | |
| /* This is the common initialisation for the GoldStar drive. */ | |
| /* It is called at boot time AND for module init. */ | |
| static int __init gscd_init(void) | |
| { | |
| int i; | |
| int result; | |
| int ret=0; | |
| printk(KERN_INFO "GSCD: version %s\n", GSCD_VERSION); | |
| printk(KERN_INFO | |
| "GSCD: Trying to detect a Goldstar R420 CD-ROM drive at 0x%X.\n", | |
| gscd_port); | |
| if (!request_region(gscd_port, GSCD_IO_EXTENT, "gscd")) { | |
| printk(KERN_WARNING "GSCD: Init failed, I/O port (%X) already" | |
| " in use.\n", gscd_port); | |
| return -EIO; | |
| } | |
| /* check for card */ | |
| result = wait_drv_ready(); | |
| if (result == 0x09) { | |
| printk(KERN_WARNING "GSCD: DMA kann ich noch nicht!\n"); | |
| ret = -EIO; | |
| goto err_out1; | |
| } | |
| if (result == 0x0b) { | |
| drv_mode = result; | |
| i = find_drives(); | |
| if (i == 0) { | |
| printk(KERN_WARNING "GSCD: GoldStar CD-ROM Drive is" | |
| " not found.\n"); | |
| ret = -EIO; | |
| goto err_out1; | |
| } | |
| } | |
| if ((result != 0x0b) && (result != 0x09)) { | |
| printk(KERN_WARNING "GSCD: GoldStar Interface Adapter does not " | |
| "exist or H/W error\n"); | |
| ret = -EIO; | |
| goto err_out1; | |
| } | |
| /* reset all drives */ | |
| i = 0; | |
| while (drv_states[i] != 0) { | |
| curr_drv_state = drv_states[i]; | |
| printk(KERN_INFO "GSCD: Reset unit %d ... ", i); | |
| cc_Reset(); | |
| printk("done\n"); | |
| i++; | |
| } | |
| gscd_disk = alloc_disk(1); | |
| if (!gscd_disk) | |
| goto err_out1; | |
| gscd_disk->major = MAJOR_NR; | |
| gscd_disk->first_minor = 0; | |
| gscd_disk->fops = &gscd_fops; | |
| sprintf(gscd_disk->disk_name, "gscd"); | |
| if (register_blkdev(MAJOR_NR, "gscd")) { | |
| ret = -EIO; | |
| goto err_out2; | |
| } | |
| gscd_queue = blk_init_queue(do_gscd_request, &gscd_lock); | |
| if (!gscd_queue) { | |
| ret = -ENOMEM; | |
| goto err_out3; | |
| } | |
| disk_state = 0; | |
| gscdPresent = 1; | |
| gscd_disk->queue = gscd_queue; | |
| add_disk(gscd_disk); | |
| printk(KERN_INFO "GSCD: GoldStar CD-ROM Drive found.\n"); | |
| return 0; | |
| err_out3: | |
| unregister_blkdev(MAJOR_NR, "gscd"); | |
| err_out2: | |
| put_disk(gscd_disk); | |
| err_out1: | |
| release_region(gscd_port, GSCD_IO_EXTENT); | |
| return ret; | |
| } | |
| static void gscd_hsg2msf(long hsg, struct msf *msf) | |
| { | |
| hsg += CD_MSF_OFFSET; | |
| msf->min = hsg / (CD_FRAMES * CD_SECS); | |
| hsg %= CD_FRAMES * CD_SECS; | |
| msf->sec = hsg / CD_FRAMES; | |
| msf->frame = hsg % CD_FRAMES; | |
| gscd_bin2bcd(&msf->min); /* convert to BCD */ | |
| gscd_bin2bcd(&msf->sec); | |
| gscd_bin2bcd(&msf->frame); | |
| } | |
| static void gscd_bin2bcd(unsigned char *p) | |
| { | |
| int u, t; | |
| u = *p % 10; | |
| t = *p / 10; | |
| *p = u | (t << 4); | |
| } | |
| #ifdef FUTURE_WORK | |
| static long gscd_msf2hsg(struct msf *mp) | |
| { | |
| return gscd_bcd2bin(mp->frame) | |
| + gscd_bcd2bin(mp->sec) * CD_FRAMES | |
| + gscd_bcd2bin(mp->min) * CD_FRAMES * CD_SECS - CD_MSF_OFFSET; | |
| } | |
| static int gscd_bcd2bin(unsigned char bcd) | |
| { | |
| return (bcd >> 4) * 10 + (bcd & 0xF); | |
| } | |
| #endif | |
| MODULE_AUTHOR("Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>"); | |
| MODULE_LICENSE("GPL"); | |
| module_init(gscd_init); | |
| module_exit(gscd_exit); | |
| MODULE_ALIAS_BLOCKDEV_MAJOR(GOLDSTAR_CDROM_MAJOR); |