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.
35 --------------------------------------------------------------------
37 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x
38 Removed init_module & cleanup_module in favor of
39 module_init & module_exit.
40 Torben Mathiasen <tmm@image.dk>
44 /* These settings are for various debug-level. Leave they untouched ... */
46 #define NO_IOCTL_DEBUG
47 #define NO_MODULE_DEBUG
48 #define NO_FUTURE_WORK
49 /*------------------------*/
51 #include <linux/module.h>
53 #include <linux/malloc.h>
54 #include <linux/errno.h>
55 #include <linux/signal.h>
56 #include <linux/sched.h>
57 #include <linux/timer.h>
60 #include <linux/kernel.h>
61 #include <linux/cdrom.h>
62 #include <linux/ioport.h>
63 #include <linux/major.h>
64 #include <linux/string.h>
65 #include <linux/init.h>
66 #include <linux/devfs_fs_kernel.h>
68 #include <asm/system.h>
70 #include <asm/uaccess.h>
72 #define MAJOR_NR GOLDSTAR_CDROM_MAJOR
73 #include <linux/blk.h>
74 #define gscd_port gscd /* for compatible parameter passing with "insmod" */
77 static int gscd_blocksizes
[1] = {512};
79 static int gscdPresent
= 0;
81 static unsigned char gscd_buf
[2048]; /* buffer for block size conversion */
82 static int gscd_bn
= -1;
83 static short gscd_port
= GSCD_BASE_ADDR
;
84 MODULE_PARM(gscd
, "h");
86 /* Kommt spaeter vielleicht noch mal dran ...
87 * static DECLARE_WAIT_QUEUE_HEAD(gscd_waitq);
90 static void gscd_transfer (void);
91 static void gscd_read_cmd (void);
92 static void gscd_hsg2msf (long hsg
, struct msf
*msf
);
93 static void gscd_bin2bcd (unsigned char *p
);
95 /* Schnittstellen zum Kern/FS */
97 static void do_gscd_request (request_queue_t
*);
98 static void __do_gscd_request (unsigned long dummy
);
99 static int gscd_ioctl (struct inode
*, struct file
*, unsigned int, unsigned long);
100 static int gscd_open (struct inode
*, struct file
*);
101 static int gscd_release (struct inode
*, struct file
*);
102 static int check_gscd_med_chg (kdev_t
);
104 /* GoldStar Funktionen */
106 static void cc_Reset (void);
107 static int wait_drv_ready (void);
108 static int find_drives (void);
109 static void cmd_out (int, char *, char *, int);
110 static void cmd_status (void);
111 static void cc_Ident (char *);
112 static void cc_SetSpeed (void);
113 static void init_cd_drive (int);
115 static int get_status (void);
116 static void clear_Audio (void);
117 static void cc_invalidate (void);
119 /* some things for the next version */
121 static void update_state (void);
122 static long gscd_msf2hsg (struct msf
*mp
);
123 static int gscd_bcd2bin (unsigned char bcd
);
126 /* common GoldStar Initialization */
128 static int my_gscd_init (void);
131 /* lo-level cmd-Funktionen */
133 static void cmd_info_in ( char *, int );
134 static void cmd_end ( void );
135 static void cmd_read_b ( char *, int, int );
136 static void cmd_read_w ( char *, int, int );
137 static int cmd_unit_alive ( void );
138 static void cmd_write_cmd ( char * );
141 /* GoldStar Variablen */
143 static int curr_drv_state
;
144 static int drv_states
[] = {0,0,0,0,0,0,0,0};
146 static int disk_state
;
150 static unsigned char drv_num_read
;
151 static unsigned char f_dsk_valid
;
152 static unsigned char current_drive
;
153 static unsigned char f_drv_ok
;
156 static char f_AudioPlay
;
157 static char f_AudioPause
;
158 static int AudioStart_m
;
159 static int AudioStart_f
;
160 static int AudioEnd_m
;
161 static int AudioEnd_f
;
163 static struct timer_list gscd_timer
;
165 static struct block_device_operations gscd_fops
= {
167 release
: gscd_release
,
169 check_media_change
: check_gscd_med_chg
,
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");
198 /* Using new interface for kernel-parameters */
200 static int __init
gscd_setup (char *str
)
203 (void)get_options(str
, ARRAY_SIZE(ints
), ints
);
212 __setup("gscd=", gscd_setup
);
216 static int gscd_ioctl (struct inode
*ip
, struct file
*fp
, unsigned int cmd
, unsigned long arg
)
218 unsigned char to_do
[10];
224 case CDROMSTART
: /* Spin up the drive */
225 /* Don't think we can do this. Even if we could,
226 * I think the drive times out and stops after a while
227 * anyway. For now, ignore it.
231 case CDROMRESUME
: /* keine Ahnung was das ist */
237 to_do
[0] = CMD_TRAY_CTL
;
238 cmd_out (TYPE_INFO
, (char *)&to_do
, (char *)&dummy
, 0);
250 * Take care of the different block sizes between cdrom and Linux.
251 * When Linux gets variable block sizes this will probably go away.
254 static void gscd_transfer (void)
258 while (CURRENT
-> nr_sectors
> 0 && gscd_bn
== CURRENT
-> sector
/ 4)
260 offs
= (CURRENT
-> sector
& 3) * 512;
261 memcpy(CURRENT
-> buffer
, gscd_buf
+ offs
, 512);
262 CURRENT
-> nr_sectors
--;
264 CURRENT
-> buffer
+= 512;
270 * I/O request routine called from Linux kernel.
273 static void do_gscd_request (request_queue_t
* q
)
275 __do_gscd_request(0);
278 static void __do_gscd_request (unsigned long dummy
)
280 unsigned int block
,dev
;
284 if (QUEUE_EMPTY
|| CURRENT
->rq_status
== RQ_INACTIVE
)
287 dev
= MINOR(CURRENT
->rq_dev
);
288 block
= CURRENT
->sector
;
289 nsect
= CURRENT
->nr_sectors
;
291 if (QUEUE_EMPTY
|| CURRENT
-> sector
== -1)
294 if (CURRENT
-> cmd
!= READ
)
296 printk("GSCD: bad cmd %d\n", CURRENT
-> cmd
);
301 if (MINOR(CURRENT
-> rq_dev
) != 0)
303 printk("GSCD: this version supports only one device\n");
310 /* if we satisfied the request from the buffer, we're done. */
312 if (CURRENT
-> nr_sectors
== 0)
319 printk ("GSCD: dev %d, block %d, nsect %d\n", dev
, block
, nsect
);
330 * Check the result of the set-mode command. On success, send the
338 struct gscd_Play_msf gscdcmd
;
339 char cmd
[] = { CMD_READ
, 0x80, 0,0,0, 0,1 }; /* cmd mode M-S-F secth sectl */
344 if ( disk_state
& (ST_NO_DISK
| ST_DOOR_OPEN
) )
346 printk ( "GSCD: no disk or door open\n" );
351 if ( disk_state
& ST_INVALID
)
353 printk ( "GSCD: disk invalid\n" );
358 gscd_bn
= -1; /* purge our buffer */
359 block
= CURRENT
-> sector
/ 4;
360 gscd_hsg2msf(block
, &gscdcmd
.start
); /* cvt to msf format */
362 cmd
[2] = gscdcmd
.start
.min
;
363 cmd
[3] = gscdcmd
.start
.sec
;
364 cmd
[4] = gscdcmd
.start
.frame
;
367 printk ("GSCD: read msf %d:%d:%d\n", cmd
[2], cmd
[3], cmd
[4] );
369 cmd_out ( TYPE_DATA
, (char *)&cmd
, (char *)&gscd_buf
[0], 1 );
371 gscd_bn
= CURRENT
-> sector
/ 4;
376 SET_TIMER(__do_gscd_request
, 1);
381 * Open the device special file. Check that a disk is in.
384 static int gscd_open (struct inode
*ip
, struct file
*fp
)
389 printk ( "GSCD: open\n" );
392 if (gscdPresent
== 0)
393 return -ENXIO
; /* no hardware */
398 st
= disk_state
& (ST_NO_DISK
| ST_DOOR_OPEN
);
401 printk ( "GSCD: no disk or door open\n" );
406 /* if (updateToc() < 0)
415 * On close, we flush all gscd blocks from the buffer cache.
418 static int gscd_release (struct inode
* inode
, struct file
* file
)
422 printk ( "GSCD: release\n" );
432 int get_status (void)
437 status
= disk_state
& (ST_x08
| ST_x04
| ST_INVALID
| ST_x01
);
439 if ( status
== (ST_x08
| ST_x04
| ST_INVALID
| ST_x01
) )
451 void cc_invalidate (void)
455 current_drive
= 0xFF;
462 void clear_Audio (void)
478 int wait_drv_ready (void)
484 found
= inb ( GSCDPORT(0) );
486 read
= inb ( GSCDPORT(0) );
488 } while ( read
!= found
);
491 printk ( "Wait for: %d\n", read
);
497 void cc_Ident (char * respons
)
499 char to_do
[] = {CMD_IDENT
, 0, 0};
501 cmd_out (TYPE_INFO
, (char *)&to_do
, (char *)respons
, (int)0x1E );
505 void cc_SetSpeed (void)
507 char to_do
[] = {CMD_SETSPEED
, 0, 0};
512 to_do
[1] = speed
& 0x0F;
513 cmd_out (TYPE_INFO
, (char *)&to_do
, (char *)&dummy
, 0);
520 char to_do
[] = {CMD_RESET
, 0};
523 cmd_out (TYPE_INFO
, (char *)&to_do
, (char *)&dummy
, 0);
528 void cmd_status (void)
530 char to_do
[] = {CMD_STATUS
, 0};
533 cmd_out (TYPE_INFO
, (char *)&to_do
, (char *)&dummy
, 0);
536 printk ("GSCD: Status: %d\n", disk_state
);
541 void cmd_out ( int cmd_type
, char * cmd
, char * respo_buf
, int respo_count
)
546 result
= wait_drv_ready ();
547 if ( result
!= drv_mode
)
549 unsigned long test_loops
= 0xFFFF;
552 outb ( curr_drv_state
, GSCDPORT(0));
557 result
= wait_drv_ready ();
559 } while ( (result
!= drv_mode
) && (test_loops
> 0) );
561 if ( result
!= drv_mode
)
563 disk_state
= ST_x08
| ST_x04
| ST_INVALID
;
568 for ( i
=1,dummy
=1 ; i
<0xFFFF ; i
++ )
577 if ( cmd_unit_alive () != 0x08 )
580 /* game over for this unit */
581 disk_state
= ST_x08
| ST_x04
| ST_INVALID
;
589 if ( drv_mode
== 0x09 )
592 printk ("GSCD: magic ...\n");
593 outb ( result
, GSCDPORT(2));
596 /* write the command to the drive */
602 result
= wait_drv_ready ();
603 if ( result
!= drv_mode
)
606 if ( result
== 0x04 ) /* Mode 4 */
612 disk_state
= inb ( GSCDPORT (2));
616 result
= wait_drv_ready ();
617 } while ( result
!= drv_mode
);
623 if ( result
== 0x06 ) /* Mode 6 */
630 if (cmd_type
== TYPE_DATA
)
636 /* read the data to the buffer (word) */
638 /* (*(cmd+1))?(CD_FRAMESIZE/2):(CD_FRAMESIZE_RAW/2) */
639 cmd_read_w ( respo_buf
, respo_count
, CD_FRAMESIZE
/2 );
644 /* read the data to the buffer (byte) */
646 /* (*(cmd+1))?(CD_FRAMESIZE):(CD_FRAMESIZE_RAW) */
647 cmd_read_b ( respo_buf
, respo_count
, CD_FRAMESIZE
);
653 /* read the info to the buffer */
654 cmd_info_in ( respo_buf
, respo_count
);
665 disk_state
= ST_x08
| ST_x04
| ST_INVALID
;
677 static void cmd_write_cmd ( char *pstr
)
686 /* calculate the number of parameter */
690 for ( i
=0 ; i
<j
; i
++ )
692 outb ( *pstr
, GSCDPORT(2) );
698 static int cmd_unit_alive ( void )
701 unsigned long max_test_loops
;
709 outb ( curr_drv_state
, GSCDPORT(0));
710 max_test_loops
= 0xFFFF;
714 result
= wait_drv_ready ();
716 } while ( (result
!= 0x08) && (max_test_loops
> 0) );
722 static void cmd_info_in ( char *pb
, int count
)
736 read
= inb (GSCDPORT(2));
747 result
= wait_drv_ready ();
748 } while ( result
== 0x0E );
749 } while ( result
== 6 );
756 static void cmd_read_b ( char *pb
, int count
, int size
)
772 result
= wait_drv_ready ();
773 } while ( result
!= 6 || result
== 0x0E );
785 for ( i
=0 ; i
< size
; i
++ )
787 *pb
= inb (GSCDPORT(2));
791 } while ( count
> 0 );
798 static void cmd_end (void)
810 result
= wait_drv_ready ();
811 if ( result
== drv_mode
)
815 } while ( result
!= 4 );
822 disk_state
= inb ( GSCDPORT (2));
826 result
= wait_drv_ready ();
827 } while ( result
!= drv_mode
);
833 static void cmd_read_w ( char *pb
, int count
, int size
)
848 result
= wait_drv_ready ();
849 } while ( result
!= 6 || result
== 0x0E );
857 for ( i
=0 ; i
<size
; i
++ )
859 /* na, hier muss ich noch mal drueber nachdenken */
860 *pb
= inw(GSCDPORT(2));
864 } while ( count
> 0 );
870 int __init
find_drives (void)
878 pdrv
= (int *)&drv_states
;
879 curr_drv_state
= 0xFE;
883 for ( i
=0 ; i
<8 ; i
++ )
887 disk_state
&= ST_x08
| ST_x04
| ST_INVALID
| ST_x01
;
888 if ( disk_state
!= (ST_x08
| ST_x04
| ST_INVALID
) )
891 *pdrv
= curr_drv_state
;
892 init_cd_drive (drvnum
);
908 /* curr_drv_state<<1; <-- das geht irgendwie nicht */
909 /* muss heissen: curr_drv_state <<= 1; (ist ja Wert-Zuweisung) */
913 printk ("DriveState: %d\n", curr_drv_state
);
921 void __init
init_cd_drive ( int num
)
926 printk ("GSCD: init unit %d\n", num
);
927 cc_Ident ((char *)&resp
);
929 printk ("GSCD: identification: ");
930 for ( i
=0 ; i
<0x1E; i
++ )
932 printk ( "%c", resp
[i
] );
942 static void update_state ( void )
947 if ( (disk_state
& (ST_x08
| ST_x04
| ST_INVALID
| ST_x01
)) == 0 )
949 if ( disk_state
== (ST_x08
| ST_x04
| ST_INVALID
))
954 if ( (disk_state
& (ST_x08
| ST_x04
| ST_INVALID
| ST_x01
)) == 0 )
963 if ( disk_state
& ST_PLAYING
)
976 /* Init for the Module-Version */
982 /* call the GoldStar-init */
983 err
= my_gscd_init ( );
991 printk (KERN_INFO
"Happy GoldStar !\n" );
996 void __exit
exit_gscd(void)
999 del_timer_async(&gscd_timer
);
1001 devfs_unregister(devfs_find_handle(NULL
, "gscd", 0, 0, DEVFS_SPECIAL_BLK
,
1003 if ((devfs_unregister_blkdev(MAJOR_NR
, "gscd" ) == -EINVAL
))
1005 printk("What's that: can't unregister GoldStar-module\n" );
1008 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR
));
1009 release_region (gscd_port
,4);
1010 printk(KERN_INFO
"GoldStar-module released.\n" );
1014 module_init(init_gscd
);
1016 module_exit(exit_gscd
);
1019 /* Test for presence of drive and initialize it. Called only at boot time. */
1020 int __init
gscd_init (void)
1022 return my_gscd_init ();
1026 /* This is the common initialisation for the GoldStar drive. */
1027 /* It is called at boot time AND for module init. */
1028 int __init
my_gscd_init (void)
1033 printk (KERN_INFO
"GSCD: version %s\n", GSCD_VERSION
);
1034 printk (KERN_INFO
"GSCD: Trying to detect a Goldstar R420 CD-ROM drive at 0x%X.\n", gscd_port
);
1036 if (check_region(gscd_port
, 4))
1038 printk("GSCD: Init failed, I/O port (%X) already in use.\n", gscd_port
);
1043 /* check for card */
1044 result
= wait_drv_ready ();
1045 if ( result
== 0x09 )
1047 printk ("GSCD: DMA kann ich noch nicht!\n" );
1051 if ( result
== 0x0b )
1057 printk ( "GSCD: GoldStar CD-ROM Drive is not found.\n" );
1062 if ( (result
!= 0x0b) && (result
!= 0x09) )
1064 printk ("GSCD: GoldStar Interface Adapter does not exist or H/W error\n" );
1068 /* reset all drives */
1070 while ( drv_states
[i
] != 0 )
1072 curr_drv_state
= drv_states
[i
];
1073 printk (KERN_INFO
"GSCD: Reset unit %d ... ",i
);
1075 printk ( "done\n" );
1079 if (devfs_register_blkdev(MAJOR_NR
, "gscd", &gscd_fops
) != 0)
1081 printk("GSCD: Unable to get major %d for GoldStar CD-ROM\n",
1085 devfs_register (NULL
, "gscd", DEVFS_FL_DEFAULT
, MAJOR_NR
, 0,
1086 S_IFBLK
| S_IRUGO
| S_IWUGO
, &gscd_fops
, NULL
);
1088 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR
), DEVICE_REQUEST
);
1089 blksize_size
[MAJOR_NR
] = gscd_blocksizes
;
1090 read_ahead
[MAJOR_NR
] = 4;
1095 request_region(gscd_port
, 4, "gscd");
1096 register_disk(NULL
, MKDEV(MAJOR_NR
,0), 1, &gscd_fops
, 0);
1098 printk (KERN_INFO
"GSCD: GoldStar CD-ROM Drive found.\n" );
1102 static void gscd_hsg2msf (long hsg
, struct msf
*msf
)
1104 hsg
+= CD_MSF_OFFSET
;
1105 msf
-> min
= hsg
/ (CD_FRAMES
*CD_SECS
);
1106 hsg
%= CD_FRAMES
*CD_SECS
;
1107 msf
-> sec
= hsg
/ CD_FRAMES
;
1108 msf
-> frame
= hsg
% CD_FRAMES
;
1110 gscd_bin2bcd(&msf
-> min
); /* convert to BCD */
1111 gscd_bin2bcd(&msf
-> sec
);
1112 gscd_bin2bcd(&msf
-> frame
);
1116 static void gscd_bin2bcd (unsigned char *p
)
1127 static long gscd_msf2hsg (struct msf
*mp
)
1129 return gscd_bcd2bin(mp
-> frame
)
1130 + gscd_bcd2bin(mp
-> sec
) * CD_FRAMES
1131 + gscd_bcd2bin(mp
-> min
) * CD_FRAMES
* CD_SECS
1135 static int gscd_bcd2bin (unsigned char bcd
)
1137 return (bcd
>> 4) * 10 + (bcd
& 0xF);