gscd.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,033 行 · 第 1/2 页
C
1,033 行
#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>#define gscd_port gscd /* for compatible parameter passing with "insmod" */#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_PARM(gscd, "h");/* 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_WORKstatic 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 struct timer_list gscd_timer = TIMER_INITIALIZER(NULL, 0, 0);static spinlock_t gscd_lock = SPIN_LOCK_UNLOCKED;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);#endifstatic 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 %lu\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) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?