2005-04-17 02:20:36 +04:00
# 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 0213 9 , 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 ;
2005-09-10 00:10:40 +04:00
static DEFINE_TIMER ( gscd_timer , NULL , 0 , 0 ) ;
2005-04-17 02:20:36 +04:00
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 %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 ) {
/* 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 " ) ;
sprintf ( gscd_disk - > devfs_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 ) ;