📄 gscd.c
字号:
#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.*//* 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/malloc.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/blk.h>#define gscd_port gscd /* for compatible parameter passing with "insmod" */#include "gscd.h"static int gscd_blocksizes[1] = {512};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_PARM(gscd, "h");/* Kommt spaeter vielleicht noch mal dran ... * static struct wait_queue *gscd_waitq = NULL; */ static void gscd_transfer (void);static void gscd_read_cmd (void);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 (void);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 (kdev_t);/* GoldStar Funktionen */static void cc_Reset (void);static int wait_drv_ready (void);static int find_drives (void);static void cmd_out (int, char *, char *, int);static void cmd_status (void);static void cc_Ident (char *);static void cc_SetSpeed (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_WORKstatic void update_state (void);static long gscd_msf2hsg (struct msf *mp);static int gscd_bcd2bin (unsigned char bcd);#endif/* common GoldStar Initialization */static int my_gscd_init (void);/* 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 struct file_operations gscd_fops = { NULL, /* lseek - default */ block_read, /* read - general block-dev read */ block_write, /* write - general block-dev write */ NULL, /* readdir - bad */ NULL, /* poll */ gscd_ioctl, /* ioctl */ NULL, /* mmap */ gscd_open, /* open */ NULL, /* flush */ gscd_release, /* release */ NULL, /* fsync */ NULL, /* fasync*/ check_gscd_med_chg, /* media change */ NULL /* revalidate */};/* * Checking if the media has been changed * (not yet implemented) */static int check_gscd_med_chg (kdev_t full_dev){ int target; target = MINOR(full_dev); if (target > 0) { printk("GSCD: GoldStar CD-ROM request error: invalid device.\n"); return 0; } #ifdef GSCD_DEBUG printk ("gscd: check_med_change\n"); #endif return 0;}__initfunc(void gscd_setup (char *str, int *ints)){ if (ints[0] > 0) { gscd_port = ints[1]; }}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 (void){long offs; while (CURRENT -> nr_sectors > 0 && gscd_bn == CURRENT -> sector / 4) { offs = (CURRENT -> sector & 3) * 512; memcpy(CURRENT -> buffer, gscd_buf + offs, 512); CURRENT -> nr_sectors--; CURRENT -> sector++; CURRENT -> buffer += 512; }}/* * I/O request routine called from Linux kernel. */static void do_gscd_request (void){unsigned int block,dev;unsigned int nsect;repeat: if (!(CURRENT) || CURRENT->rq_status == RQ_INACTIVE) return; INIT_REQUEST; dev = MINOR(CURRENT->rq_dev); block = CURRENT->sector; nsect = CURRENT->nr_sectors; if (CURRENT == NULL || CURRENT -> sector == -1) return; if (CURRENT -> cmd != READ) { printk("GSCD: bad cmd %d\n", CURRENT -> cmd); end_request(0); goto repeat; } if (MINOR(CURRENT -> rq_dev) != 0) { printk("GSCD: this version supports only one device\n"); end_request(0); goto repeat; } gscd_transfer(); /* if we satisfied the request from the buffer, we're done. */ if (CURRENT -> nr_sectors == 0) { end_request(1); goto repeat; }#ifdef GSCD_DEBUG printk ("GSCD: dev %d, block %d, nsect %d\n", dev, block, nsect );#endif gscd_read_cmd ();}/* * Check the result of the set-mode command. On success, send the * read-data command. */static voidgscd_read_cmd (void){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 (0); } else { if ( disk_state & ST_INVALID ) { printk ( "GSCD: disk invalid\n" ); end_request (0); } else { gscd_bn = -1; /* purge our buffer */ block = CURRENT -> 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 = CURRENT -> sector / 4; gscd_transfer(); end_request(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_DEBUGprintk ( "GSCD: open\n" );#endif if (gscdPresent == 0) return -ENXIO; /* no hardware */ MOD_INC_USE_COUNT; get_status (); st = disk_state & (ST_NO_DISK | ST_DOOR_OPEN); if ( st ) { printk ( "GSCD: no disk or door open\n" ); MOD_DEC_USE_COUNT; 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_DEBUGprintk ( "GSCD: release\n" );#endif gscd_bn = -1; sync_dev(inode->i_rdev); invalidate_buffers(inode -> i_rdev); MOD_DEC_USE_COUNT; return 0;}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; }}void cc_invalidate (void){ drv_num_read = 0xFF; f_dsk_valid = 0xFF; current_drive = 0xFF; f_drv_ok = 0xFF; clear_Audio (); } void clear_Audio (void){ f_AudioPlay = 0; f_AudioPause = 0; AudioStart_m = 0; AudioStart_f = 0; AudioEnd_m = 0; AudioEnd_f = 0; }/* * waiting ? */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_DEBUGprintk ( "Wait for: %d\n", read );#endif return read;}void cc_Ident (char * respons){char to_do [] = {CMD_IDENT, 0, 0}; cmd_out (TYPE_INFO, (char *)&to_do, (char *)respons, (int)0x1E );}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); }}void cc_Reset (void){char to_do [] = {CMD_RESET, 0};char dummy; cmd_out (TYPE_INFO, (char *)&to_do, (char *)&dummy, 0);}void cmd_status (void){char to_do [] = {CMD_STATUS, 0};char dummy; cmd_out (TYPE_INFO, (char *)&to_do, (char *)&dummy, 0);#ifdef GSCD_DEBUGprintk ("GSCD: Status: %d\n", disk_state );#endif}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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -