1 #define GSCD_VERSION "0.4a Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>"
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)
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.
37 /* These settings are for various debug-level. Leave they untouched ... */
39 #define NO_IOCTL_DEBUG
40 #define NO_MODULE_DEBUG
41 #define NO_FUTURE_WORK
42 /*------------------------*/
44 #include <linux/module.h>
46 #include <linux/malloc.h>
47 #include <linux/errno.h>
48 #include <linux/signal.h>
49 #include <linux/sched.h>
50 #include <linux/timer.h>
53 #include <linux/kernel.h>
54 #include <linux/cdrom.h>
55 #include <linux/ioport.h>
56 #include <linux/major.h>
57 #include <linux/string.h>
58 #include <linux/init.h>
60 #include <asm/system.h>
62 #include <asm/uaccess.h>
64 #define MAJOR_NR GOLDSTAR_CDROM_MAJOR
65 #include <linux/blk.h>
66 #define gscd_port gscd /* for compatible parameter passing with "insmod" */
69 static int gscd_blocksizes
[1] = {512};
71 static int gscdPresent
= 0;
73 static unsigned char gscd_buf
[2048]; /* buffer for block size conversion */
74 static int gscd_bn
= -1;
75 static short gscd_port
= GSCD_BASE_ADDR
;
76 MODULE_PARM(gscd
, "h");
78 /* Kommt spaeter vielleicht noch mal dran ...
79 * static DECLARE_WAIT_QUEUE_HEAD(gscd_waitq);
82 static void gscd_transfer (void);
83 static void gscd_read_cmd (void);
84 static void gscd_hsg2msf (long hsg
, struct msf
*msf
);
85 static void gscd_bin2bcd (unsigned char *p
);
87 /* Schnittstellen zum Kern/FS */
89 static void do_gscd_request (void);
90 static int gscd_ioctl (struct inode
*, struct file
*, unsigned int, unsigned long);
91 static int gscd_open (struct inode
*, struct file
*);
92 static int gscd_release (struct inode
*, struct file
*);
93 static int check_gscd_med_chg (kdev_t
);
95 /* GoldStar Funktionen */
97 static void cc_Reset (void);
98 static int wait_drv_ready (void);
99 static int find_drives (void);
100 static void cmd_out (int, char *, char *, int);
101 static void cmd_status (void);
102 static void cc_Ident (char *);
103 static void cc_SetSpeed (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 */
112 static void update_state (void);
113 static long gscd_msf2hsg (struct msf
*mp
);
114 static int gscd_bcd2bin (unsigned char bcd
);
117 /* common GoldStar Initialization */
119 static int my_gscd_init (void);
122 /* lo-level cmd-Funktionen */
124 static void cmd_info_in ( char *, int );
125 static void cmd_end ( void );
126 static void cmd_read_b ( char *, int, int );
127 static void cmd_read_w ( char *, int, int );
128 static int cmd_unit_alive ( void );
129 static void cmd_write_cmd ( char * );
132 /* GoldStar Variablen */
134 static int curr_drv_state
;
135 static int drv_states
[] = {0,0,0,0,0,0,0,0};
137 static int disk_state
;
141 static unsigned char drv_num_read
;
142 static unsigned char f_dsk_valid
;
143 static unsigned char current_drive
;
144 static unsigned char f_drv_ok
;
147 static char f_AudioPlay
;
148 static char f_AudioPause
;
149 static int AudioStart_m
;
150 static int AudioStart_f
;
151 static int AudioEnd_m
;
152 static int AudioEnd_f
;
155 static struct file_operations gscd_fops
= {
156 NULL
, /* lseek - default */
157 block_read
, /* read - general block-dev read */
158 block_write
, /* write - general block-dev write */
159 NULL
, /* readdir - bad */
161 gscd_ioctl
, /* ioctl */
163 gscd_open
, /* open */
165 gscd_release
, /* release */
168 check_gscd_med_chg
, /* media change */
169 NULL
/* revalidate */
173 * Checking if the media has been changed
174 * (not yet implemented)
176 static int check_gscd_med_chg (kdev_t full_dev
)
181 target
= MINOR(full_dev
);
185 printk("GSCD: GoldStar CD-ROM request error: invalid device.\n");
190 printk ("gscd: check_med_change\n");
197 void __init
gscd_setup (char *str
, int *ints
)
206 static int gscd_ioctl (struct inode
*ip
, struct file
*fp
, unsigned int cmd
, unsigned long arg
)
208 unsigned char to_do
[10];
214 case CDROMSTART
: /* Spin up the drive */
215 /* Don't think we can do this. Even if we could,
216 * I think the drive times out and stops after a while
217 * anyway. For now, ignore it.
221 case CDROMRESUME
: /* keine Ahnung was das ist */
227 to_do
[0] = CMD_TRAY_CTL
;
228 cmd_out (TYPE_INFO
, (char *)&to_do
, (char *)&dummy
, 0);
240 * Take care of the different block sizes between cdrom and Linux.
241 * When Linux gets variable block sizes this will probably go away.
244 static void gscd_transfer (void)
248 while (CURRENT
-> nr_sectors
> 0 && gscd_bn
== CURRENT
-> sector
/ 4)
250 offs
= (CURRENT
-> sector
& 3) * 512;
251 memcpy(CURRENT
-> buffer
, gscd_buf
+ offs
, 512);
252 CURRENT
-> nr_sectors
--;
254 CURRENT
-> buffer
+= 512;
260 * I/O request routine called from Linux kernel.
263 static void do_gscd_request (void)
265 unsigned int block
,dev
;
269 if (!(CURRENT
) || CURRENT
->rq_status
== RQ_INACTIVE
) return;
271 dev
= MINOR(CURRENT
->rq_dev
);
272 block
= CURRENT
->sector
;
273 nsect
= CURRENT
->nr_sectors
;
275 if (CURRENT
== NULL
|| CURRENT
-> sector
== -1)
278 if (CURRENT
-> cmd
!= READ
)
280 printk("GSCD: bad cmd %d\n", CURRENT
-> cmd
);
285 if (MINOR(CURRENT
-> rq_dev
) != 0)
287 printk("GSCD: this version supports only one device\n");
294 /* if we satisfied the request from the buffer, we're done. */
296 if (CURRENT
-> nr_sectors
== 0)
303 printk ("GSCD: dev %d, block %d, nsect %d\n", dev
, block
, nsect
);
312 * Check the result of the set-mode command. On success, send the
320 struct gscd_Play_msf gscdcmd
;
321 char cmd
[] = { CMD_READ
, 0x80, 0,0,0, 0,1 }; /* cmd mode M-S-F secth sectl */
326 if ( disk_state
& (ST_NO_DISK
| ST_DOOR_OPEN
) )
328 printk ( "GSCD: no disk or door open\n" );
333 if ( disk_state
& ST_INVALID
)
335 printk ( "GSCD: disk invalid\n" );
340 gscd_bn
= -1; /* purge our buffer */
341 block
= CURRENT
-> sector
/ 4;
342 gscd_hsg2msf(block
, &gscdcmd
.start
); /* cvt to msf format */
344 cmd
[2] = gscdcmd
.start
.min
;
345 cmd
[3] = gscdcmd
.start
.sec
;
346 cmd
[4] = gscdcmd
.start
.frame
;
349 printk ("GSCD: read msf %d:%d:%d\n", cmd
[2], cmd
[3], cmd
[4] );
351 cmd_out ( TYPE_DATA
, (char *)&cmd
, (char *)&gscd_buf
[0], 1 );
353 gscd_bn
= CURRENT
-> sector
/ 4;
358 SET_TIMER(do_gscd_request
, 1);
363 * Open the device special file. Check that a disk is in.
366 static int gscd_open (struct inode
*ip
, struct file
*fp
)
371 printk ( "GSCD: open\n" );
374 if (gscdPresent
== 0)
375 return -ENXIO
; /* no hardware */
380 st
= disk_state
& (ST_NO_DISK
| ST_DOOR_OPEN
);
383 printk ( "GSCD: no disk or door open\n" );
388 /* if (updateToc() < 0)
397 * On close, we flush all gscd blocks from the buffer cache.
400 static int gscd_release (struct inode
* inode
, struct file
* file
)
404 printk ( "GSCD: release\n" );
408 sync_dev(inode
->i_rdev
);
409 invalidate_buffers(inode
-> i_rdev
);
416 int get_status (void)
421 status
= disk_state
& (ST_x08
| ST_x04
| ST_INVALID
| ST_x01
);
423 if ( status
== (ST_x08
| ST_x04
| ST_INVALID
| ST_x01
) )
435 void cc_invalidate (void)
439 current_drive
= 0xFF;
446 void clear_Audio (void)
462 int wait_drv_ready (void)
468 found
= inb ( GSCDPORT(0) );
470 read
= inb ( GSCDPORT(0) );
472 } while ( read
!= found
);
475 printk ( "Wait for: %d\n", read
);
481 void cc_Ident (char * respons
)
483 char to_do
[] = {CMD_IDENT
, 0, 0};
485 cmd_out (TYPE_INFO
, (char *)&to_do
, (char *)respons
, (int)0x1E );
489 void cc_SetSpeed (void)
491 char to_do
[] = {CMD_SETSPEED
, 0, 0};
496 to_do
[1] = speed
& 0x0F;
497 cmd_out (TYPE_INFO
, (char *)&to_do
, (char *)&dummy
, 0);
504 char to_do
[] = {CMD_RESET
, 0};
507 cmd_out (TYPE_INFO
, (char *)&to_do
, (char *)&dummy
, 0);
512 void cmd_status (void)
514 char to_do
[] = {CMD_STATUS
, 0};
517 cmd_out (TYPE_INFO
, (char *)&to_do
, (char *)&dummy
, 0);
520 printk ("GSCD: Status: %d\n", disk_state
);
525 void cmd_out ( int cmd_type
, char * cmd
, char * respo_buf
, int respo_count
)
530 result
= wait_drv_ready ();
531 if ( result
!= drv_mode
)
533 unsigned long test_loops
= 0xFFFF;
536 outb ( curr_drv_state
, GSCDPORT(0));
541 result
= wait_drv_ready ();
543 } while ( (result
!= drv_mode
) && (test_loops
> 0) );
545 if ( result
!= drv_mode
)
547 disk_state
= ST_x08
| ST_x04
| ST_INVALID
;
552 for ( i
=1,dummy
=1 ; i
<0xFFFF ; i
++ )
561 if ( cmd_unit_alive () != 0x08 )
564 /* game over for this unit */
565 disk_state
= ST_x08
| ST_x04
| ST_INVALID
;
573 if ( drv_mode
== 0x09 )
576 printk ("GSCD: magic ...\n");
577 outb ( result
, GSCDPORT(2));
580 /* write the command to the drive */
586 result
= wait_drv_ready ();
587 if ( result
!= drv_mode
)
590 if ( result
== 0x04 ) /* Mode 4 */
596 disk_state
= inb ( GSCDPORT (2));
600 result
= wait_drv_ready ();
601 } while ( result
!= drv_mode
);
607 if ( result
== 0x06 ) /* Mode 6 */
614 if (cmd_type
== TYPE_DATA
)
620 /* read the data to the buffer (word) */
622 /* (*(cmd+1))?(CD_FRAMESIZE/2):(CD_FRAMESIZE_RAW/2) */
623 cmd_read_w ( respo_buf
, respo_count
, CD_FRAMESIZE
/2 );
628 /* read the data to the buffer (byte) */
630 /* (*(cmd+1))?(CD_FRAMESIZE):(CD_FRAMESIZE_RAW) */
631 cmd_read_b ( respo_buf
, respo_count
, CD_FRAMESIZE
);
637 /* read the info to the buffer */
638 cmd_info_in ( respo_buf
, respo_count
);
649 disk_state
= ST_x08
| ST_x04
| ST_INVALID
;
661 static void cmd_write_cmd ( char *pstr
)
670 /* calculate the number of parameter */
674 for ( i
=0 ; i
<j
; i
++ )
676 outb ( *pstr
, GSCDPORT(2) );
682 static int cmd_unit_alive ( void )
685 unsigned long max_test_loops
;
693 outb ( curr_drv_state
, GSCDPORT(0));
694 max_test_loops
= 0xFFFF;
698 result
= wait_drv_ready ();
700 } while ( (result
!= 0x08) && (max_test_loops
> 0) );
706 static void cmd_info_in ( char *pb
, int count
)
720 read
= inb (GSCDPORT(2));
731 result
= wait_drv_ready ();
732 } while ( result
== 0x0E );
733 } while ( result
== 6 );
740 static void cmd_read_b ( char *pb
, int count
, int size
)
756 result
= wait_drv_ready ();
757 } while ( result
!= 6 || result
== 0x0E );
769 for ( i
=0 ; i
< size
; i
++ )
771 *pb
= inb (GSCDPORT(2));
775 } while ( count
> 0 );
782 static void cmd_end (void)
794 result
= wait_drv_ready ();
795 if ( result
== drv_mode
)
799 } while ( result
!= 4 );
806 disk_state
= inb ( GSCDPORT (2));
810 result
= wait_drv_ready ();
811 } while ( result
!= drv_mode
);
817 static void cmd_read_w ( char *pb
, int count
, int size
)
832 result
= wait_drv_ready ();
833 } while ( result
!= 6 || result
== 0x0E );
841 for ( i
=0 ; i
<size
; i
++ )
843 /* na, hier muss ich noch mal drueber nachdenken */
844 *pb
= inw(GSCDPORT(2));
848 } while ( count
> 0 );
854 int __init
find_drives (void)
862 pdrv
= (int *)&drv_states
;
863 curr_drv_state
= 0xFE;
867 for ( i
=0 ; i
<8 ; i
++ )
871 disk_state
&= ST_x08
| ST_x04
| ST_INVALID
| ST_x01
;
872 if ( disk_state
!= (ST_x08
| ST_x04
| ST_INVALID
) )
875 *pdrv
= curr_drv_state
;
876 init_cd_drive (drvnum
);
892 /* curr_drv_state<<1; <-- das geht irgendwie nicht */
893 /* muss heissen: curr_drv_state <<= 1; (ist ja Wert-Zuweisung) */
897 printk ("DriveState: %d\n", curr_drv_state
);
905 void __init
init_cd_drive ( int num
)
910 printk ("GSCD: init unit %d\n", num
);
911 cc_Ident ((char *)&resp
);
913 printk ("GSCD: identification: ");
914 for ( i
=0 ; i
<0x1E; i
++ )
916 printk ( "%c", resp
[i
] );
926 static void update_state ( void )
931 if ( (disk_state
& (ST_x08
| ST_x04
| ST_INVALID
| ST_x01
)) == 0 )
933 if ( disk_state
== (ST_x08
| ST_x04
| ST_INVALID
))
938 if ( (disk_state
& (ST_x08
| ST_x04
| ST_INVALID
| ST_x01
)) == 0 )
947 if ( disk_state
& ST_PLAYING
)
961 /* Init for the Module-Version */
962 int init_module (void)
967 /* call the GoldStar-init */
968 err
= my_gscd_init ( );
976 printk (KERN_INFO
"Happy GoldStar !\n" );
981 void cleanup_module (void)
984 if ((unregister_blkdev(MAJOR_NR
, "gscd" ) == -EINVAL
))
986 printk("What's that: can't unregister GoldStar-module\n" );
990 release_region (gscd_port
,4);
991 printk(KERN_INFO
"GoldStar-module released.\n" );
996 /* Test for presence of drive and initialize it. Called only at boot time. */
997 int __init
gscd_init (void)
999 return my_gscd_init ();
1003 /* This is the common initialisation for the GoldStar drive. */
1004 /* It is called at boot time AND for module init. */
1005 int __init
my_gscd_init (void)
1010 printk (KERN_INFO
"GSCD: version %s\n", GSCD_VERSION
);
1011 printk (KERN_INFO
"GSCD: Trying to detect a Goldstar R420 CD-ROM drive at 0x%X.\n", gscd_port
);
1013 if (check_region(gscd_port
, 4))
1015 printk("GSCD: Init failed, I/O port (%X) already in use.\n", gscd_port
);
1020 /* check for card */
1021 result
= wait_drv_ready ();
1022 if ( result
== 0x09 )
1024 printk ("GSCD: DMA kann ich noch nicht!\n" );
1028 if ( result
== 0x0b )
1034 printk ( "GSCD: GoldStar CD-ROM Drive is not found.\n" );
1039 if ( (result
!= 0x0b) && (result
!= 0x09) )
1041 printk ("GSCD: GoldStar Interface Adapter does not exist or H/W error\n" );
1045 /* reset all drives */
1047 while ( drv_states
[i
] != 0 )
1049 curr_drv_state
= drv_states
[i
];
1050 printk (KERN_INFO
"GSCD: Reset unit %d ... ",i
);
1052 printk ( "done\n" );
1056 if (register_blkdev(MAJOR_NR
, "gscd", &gscd_fops
) != 0)
1058 printk("GSCD: Unable to get major %d for GoldStar CD-ROM\n",
1063 blk_dev
[MAJOR_NR
].request_fn
= DEVICE_REQUEST
;
1064 blksize_size
[MAJOR_NR
] = gscd_blocksizes
;
1065 read_ahead
[MAJOR_NR
] = 4;
1070 request_region(gscd_port
, 4, "gscd");
1072 printk (KERN_INFO
"GSCD: GoldStar CD-ROM Drive found.\n" );
1076 static void gscd_hsg2msf (long hsg
, struct msf
*msf
)
1078 hsg
+= CD_MSF_OFFSET
;
1079 msf
-> min
= hsg
/ (CD_FRAMES
*CD_SECS
);
1080 hsg
%= CD_FRAMES
*CD_SECS
;
1081 msf
-> sec
= hsg
/ CD_FRAMES
;
1082 msf
-> frame
= hsg
% CD_FRAMES
;
1084 gscd_bin2bcd(&msf
-> min
); /* convert to BCD */
1085 gscd_bin2bcd(&msf
-> sec
);
1086 gscd_bin2bcd(&msf
-> frame
);
1090 static void gscd_bin2bcd (unsigned char *p
)
1101 static long gscd_msf2hsg (struct msf
*mp
)
1103 return gscd_bcd2bin(mp
-> frame
)
1104 + gscd_bcd2bin(mp
-> sec
) * CD_FRAMES
1105 + gscd_bcd2bin(mp
-> min
) * CD_FRAMES
* CD_SECS
1109 static int gscd_bcd2bin (unsigned char bcd
)
1111 return (bcd
>> 4) * 10 + (bcd
& 0xF);