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" */
70 static int gscdPresent
= 0;
72 static unsigned char gscd_buf
[2048]; /* buffer for block size conversion */
73 static int gscd_bn
= -1;
74 static short gscd_port
= GSCD_BASE_ADDR
;
75 MODULE_PARM(gscd
, "h");
77 /* Kommt spaeter vielleicht noch mal dran ...
78 * static struct wait_queue *gscd_waitq = NULL;
81 static void gscd_transfer (void);
82 static void gscd_read_cmd (void);
83 static void gscd_hsg2msf (long hsg
, struct msf
*msf
);
84 static void gscd_bin2bcd (unsigned char *p
);
86 /* Schnittstellen zum Kern/FS */
88 static void do_gscd_request (void);
89 static int gscd_ioctl (struct inode
*, struct file
*, unsigned int, unsigned long);
90 static int gscd_open (struct inode
*, struct file
*);
91 static int gscd_release (struct inode
*, struct file
*);
92 static int check_gscd_med_chg (kdev_t
);
94 /* GoldStar Funktionen */
96 static void cc_Reset (void);
97 static int wait_drv_ready (void);
98 static int find_drives (void);
99 static void cmd_out (int, char *, char *, int);
100 static void cmd_status (void);
101 static void cc_Ident (char *);
102 static void cc_SetSpeed (void);
103 static void init_cd_drive (int);
105 static int get_status (void);
106 static void clear_Audio (void);
107 static void cc_invalidate (void);
109 /* some things for the next version */
111 static void update_state (void);
112 static long gscd_msf2hsg (struct msf
*mp
);
113 static int gscd_bcd2bin (unsigned char bcd
);
116 /* common GoldStar Initialization */
118 static int my_gscd_init (void);
121 /* lo-level cmd-Funktionen */
123 static void cmd_info_in ( char *, int );
124 static void cmd_end ( void );
125 static void cmd_read_b ( char *, int, int );
126 static void cmd_read_w ( char *, int, int );
127 static int cmd_unit_alive ( void );
128 static void cmd_write_cmd ( char * );
131 /* GoldStar Variablen */
133 static int curr_drv_state
;
134 static int drv_states
[] = {0,0,0,0,0,0,0,0};
136 static int disk_state
;
140 static unsigned char drv_num_read
;
141 static unsigned char f_dsk_valid
;
142 static unsigned char current_drive
;
143 static unsigned char f_drv_ok
;
146 static char f_AudioPlay
;
147 static char f_AudioPause
;
148 static int AudioStart_m
;
149 static int AudioStart_f
;
150 static int AudioEnd_m
;
151 static int AudioEnd_f
;
154 static struct file_operations gscd_fops
= {
155 NULL
, /* lseek - default */
156 block_read
, /* read - general block-dev read */
157 block_write
, /* write - general block-dev write */
158 NULL
, /* readdir - bad */
160 gscd_ioctl
, /* ioctl */
162 gscd_open
, /* open */
164 gscd_release
, /* release */
167 check_gscd_med_chg
, /* media change */
168 NULL
/* revalidate */
172 * Checking if the media has been changed
173 * (not yet implemented)
175 static int check_gscd_med_chg (kdev_t full_dev
)
180 target
= MINOR(full_dev
);
184 printk("GSCD: GoldStar CD-ROM request error: invalid device.\n");
189 printk ("gscd: check_med_change\n");
196 __initfunc(void gscd_setup (char *str
, int *ints
))
205 static int gscd_ioctl (struct inode
*ip
, struct file
*fp
, unsigned int cmd
, unsigned long arg
)
207 unsigned char to_do
[10];
213 case CDROMSTART
: /* Spin up the drive */
214 /* Don't think we can do this. Even if we could,
215 * I think the drive times out and stops after a while
216 * anyway. For now, ignore it.
220 case CDROMRESUME
: /* keine Ahnung was das ist */
226 to_do
[0] = CMD_TRAY_CTL
;
227 cmd_out (TYPE_INFO
, (char *)&to_do
, (char *)&dummy
, 0);
239 * Take care of the different block sizes between cdrom and Linux.
240 * When Linux gets variable block sizes this will probably go away.
243 static void gscd_transfer (void)
247 while (CURRENT
-> nr_sectors
> 0 && gscd_bn
== CURRENT
-> sector
/ 4)
249 offs
= (CURRENT
-> sector
& 3) * 512;
250 memcpy(CURRENT
-> buffer
, gscd_buf
+ offs
, 512);
251 CURRENT
-> nr_sectors
--;
253 CURRENT
-> buffer
+= 512;
259 * I/O request routine called from Linux kernel.
262 static void do_gscd_request (void)
264 unsigned int block
,dev
;
268 if (!(CURRENT
) || CURRENT
->rq_status
== RQ_INACTIVE
) return;
270 dev
= MINOR(CURRENT
->rq_dev
);
271 block
= CURRENT
->sector
;
272 nsect
= CURRENT
->nr_sectors
;
274 if (CURRENT
== NULL
|| CURRENT
-> sector
== -1)
277 if (CURRENT
-> cmd
!= READ
)
279 printk("GSCD: bad cmd %d\n", CURRENT
-> cmd
);
284 if (MINOR(CURRENT
-> rq_dev
) != 0)
286 printk("GSCD: this version supports only one device\n");
293 /* if we satisfied the request from the buffer, we're done. */
295 if (CURRENT
-> nr_sectors
== 0)
302 printk ("GSCD: dev %d, block %d, nsect %d\n", dev
, block
, nsect
);
311 * Check the result of the set-mode command. On success, send the
319 struct gscd_Play_msf gscdcmd
;
320 char cmd
[] = { CMD_READ
, 0x80, 0,0,0, 0,1 }; /* cmd mode M-S-F secth sectl */
325 if ( disk_state
& (ST_NO_DISK
| ST_DOOR_OPEN
) )
327 printk ( "GSCD: no disk or door open\n" );
332 if ( disk_state
& ST_INVALID
)
334 printk ( "GSCD: disk invalid\n" );
339 gscd_bn
= -1; /* purge our buffer */
340 block
= CURRENT
-> sector
/ 4;
341 gscd_hsg2msf(block
, &gscdcmd
.start
); /* cvt to msf format */
343 cmd
[2] = gscdcmd
.start
.min
;
344 cmd
[3] = gscdcmd
.start
.sec
;
345 cmd
[4] = gscdcmd
.start
.frame
;
348 printk ("GSCD: read msf %d:%d:%d\n", cmd
[2], cmd
[3], cmd
[4] );
350 cmd_out ( TYPE_DATA
, (char *)&cmd
, (char *)&gscd_buf
[0], 1 );
352 gscd_bn
= CURRENT
-> sector
/ 4;
357 SET_TIMER(do_gscd_request
, 1);
362 * Open the device special file. Check that a disk is in.
365 static int gscd_open (struct inode
*ip
, struct file
*fp
)
370 printk ( "GSCD: open\n" );
373 if (gscdPresent
== 0)
374 return -ENXIO
; /* no hardware */
379 st
= disk_state
& (ST_NO_DISK
| ST_DOOR_OPEN
);
382 printk ( "GSCD: no disk or door open\n" );
387 /* if (updateToc() < 0)
396 * On close, we flush all gscd blocks from the buffer cache.
399 static int gscd_release (struct inode
* inode
, struct file
* file
)
403 printk ( "GSCD: release\n" );
407 sync_dev(inode
->i_rdev
);
408 invalidate_buffers(inode
-> i_rdev
);
415 int get_status (void)
420 status
= disk_state
& (ST_x08
| ST_x04
| ST_INVALID
| ST_x01
);
422 if ( status
== (ST_x08
| ST_x04
| ST_INVALID
| ST_x01
) )
434 void cc_invalidate (void)
438 current_drive
= 0xFF;
445 void clear_Audio (void)
461 int wait_drv_ready (void)
467 found
= inb ( GSCDPORT(0) );
469 read
= inb ( GSCDPORT(0) );
471 } while ( read
!= found
);
474 printk ( "Wait for: %d\n", read
);
480 void cc_Ident (char * respons
)
482 char to_do
[] = {CMD_IDENT
, 0, 0};
484 cmd_out (TYPE_INFO
, (char *)&to_do
, (char *)respons
, (int)0x1E );
488 void cc_SetSpeed (void)
490 char to_do
[] = {CMD_SETSPEED
, 0, 0};
495 to_do
[1] = speed
& 0x0F;
496 cmd_out (TYPE_INFO
, (char *)&to_do
, (char *)&dummy
, 0);
503 char to_do
[] = {CMD_RESET
, 0};
506 cmd_out (TYPE_INFO
, (char *)&to_do
, (char *)&dummy
, 0);
511 void cmd_status (void)
513 char to_do
[] = {CMD_STATUS
, 0};
516 cmd_out (TYPE_INFO
, (char *)&to_do
, (char *)&dummy
, 0);
519 printk ("GSCD: Status: %d\n", disk_state
);
524 void cmd_out ( int cmd_type
, char * cmd
, char * respo_buf
, int respo_count
)
529 result
= wait_drv_ready ();
530 if ( result
!= drv_mode
)
532 unsigned long test_loops
= 0xFFFF;
535 outb ( curr_drv_state
, GSCDPORT(0));
540 result
= wait_drv_ready ();
542 } while ( (result
!= drv_mode
) && (test_loops
> 0) );
544 if ( result
!= drv_mode
)
546 disk_state
= ST_x08
| ST_x04
| ST_INVALID
;
551 for ( i
=1,dummy
=1 ; i
<0xFFFF ; i
++ )
560 if ( cmd_unit_alive () != 0x08 )
563 /* game over for this unit */
564 disk_state
= ST_x08
| ST_x04
| ST_INVALID
;
572 if ( drv_mode
== 0x09 )
575 printk ("GSCD: magic ...\n");
576 outb ( result
, GSCDPORT(2));
579 /* write the command to the drive */
585 result
= wait_drv_ready ();
586 if ( result
!= drv_mode
)
589 if ( result
== 0x04 ) /* Mode 4 */
595 disk_state
= inb ( GSCDPORT (2));
599 result
= wait_drv_ready ();
600 } while ( result
!= drv_mode
);
606 if ( result
== 0x06 ) /* Mode 6 */
613 if (cmd_type
== TYPE_DATA
)
619 /* read the data to the buffer (word) */
621 /* (*(cmd+1))?(CD_FRAMESIZE/2):(CD_FRAMESIZE_RAW/2) */
622 cmd_read_w ( respo_buf
, respo_count
, CD_FRAMESIZE
/2 );
627 /* read the data to the buffer (byte) */
629 /* (*(cmd+1))?(CD_FRAMESIZE):(CD_FRAMESIZE_RAW) */
630 cmd_read_b ( respo_buf
, respo_count
, CD_FRAMESIZE
);
636 /* read the info to the buffer */
637 cmd_info_in ( respo_buf
, respo_count
);
648 disk_state
= ST_x08
| ST_x04
| ST_INVALID
;
660 static void cmd_write_cmd ( char *pstr
)
669 /* calculate the number of parameter */
673 for ( i
=0 ; i
<j
; i
++ )
675 outb ( *pstr
, GSCDPORT(2) );
681 static int cmd_unit_alive ( void )
684 unsigned long max_test_loops
;
692 outb ( curr_drv_state
, GSCDPORT(0));
693 max_test_loops
= 0xFFFF;
697 result
= wait_drv_ready ();
699 } while ( (result
!= 0x08) && (max_test_loops
> 0) );
705 static void cmd_info_in ( char *pb
, int count
)
719 read
= inb (GSCDPORT(2));
730 result
= wait_drv_ready ();
731 } while ( result
== 0x0E );
732 } while ( result
== 6 );
739 static void cmd_read_b ( char *pb
, int count
, int size
)
755 result
= wait_drv_ready ();
756 } while ( result
!= 6 || result
== 0x0E );
768 for ( i
=0 ; i
< size
; i
++ )
770 *pb
= inb (GSCDPORT(2));
774 } while ( count
> 0 );
781 static void cmd_end (void)
793 result
= wait_drv_ready ();
794 if ( result
== drv_mode
)
798 } while ( result
!= 4 );
805 disk_state
= inb ( GSCDPORT (2));
809 result
= wait_drv_ready ();
810 } while ( result
!= drv_mode
);
816 static void cmd_read_w ( char *pb
, int count
, int size
)
831 result
= wait_drv_ready ();
832 } while ( result
!= 6 || result
== 0x0E );
840 for ( i
=0 ; i
<size
; i
++ )
842 /* na, hier muss ich noch mal drueber nachdenken */
843 *pb
= inw(GSCDPORT(2));
847 } while ( count
> 0 );
853 __initfunc(int find_drives (void))
861 pdrv
= (int *)&drv_states
;
862 curr_drv_state
= 0xFE;
866 for ( i
=0 ; i
<8 ; i
++ )
870 disk_state
&= ST_x08
| ST_x04
| ST_INVALID
| ST_x01
;
871 if ( disk_state
!= (ST_x08
| ST_x04
| ST_INVALID
) )
874 *pdrv
= curr_drv_state
;
875 init_cd_drive (drvnum
);
891 /* curr_drv_state<<1; <-- das geht irgendwie nicht */
892 /* muss heissen: curr_drv_state <<= 1; (ist ja Wert-Zuweisung) */
896 printk ("DriveState: %d\n", curr_drv_state
);
904 __initfunc(void init_cd_drive ( int num
))
909 printk ("GSCD: init unit %d\n", num
);
910 cc_Ident ((char *)&resp
);
912 printk ("GSCD: identification: ");
913 for ( i
=0 ; i
<0x1E; i
++ )
915 printk ( "%c", resp
[i
] );
925 static void update_state ( void )
930 if ( (disk_state
& (ST_x08
| ST_x04
| ST_INVALID
| ST_x01
)) == 0 )
932 if ( disk_state
== (ST_x08
| ST_x04
| ST_INVALID
))
937 if ( (disk_state
& (ST_x08
| ST_x04
| ST_INVALID
| ST_x01
)) == 0 )
946 if ( disk_state
& ST_PLAYING
)
960 /* Init for the Module-Version */
961 int init_module (void)
966 /* call the GoldStar-init */
967 err
= my_gscd_init ( );
975 printk (KERN_INFO
"Happy GoldStar !\n" );
980 void cleanup_module (void)
983 if ((unregister_blkdev(MAJOR_NR
, "gscd" ) == -EINVAL
))
985 printk("What's that: can't unregister GoldStar-module\n" );
989 release_region (gscd_port
,4);
990 printk(KERN_INFO
"GoldStar-module released.\n" );
995 /* Test for presence of drive and initialize it. Called only at boot time. */
996 __initfunc(int gscd_init (void))
998 return my_gscd_init ();
1002 /* This is the common initialisation for the GoldStar drive. */
1003 /* It is called at boot time AND for module init. */
1004 __initfunc(int my_gscd_init (void))
1009 printk (KERN_INFO
"GSCD: version %s\n", GSCD_VERSION
);
1010 printk (KERN_INFO
"GSCD: Trying to detect a Goldstar R420 CD-ROM drive at 0x%X.\n", gscd_port
);
1012 if (check_region(gscd_port
, 4))
1014 printk("GSCD: Init failed, I/O port (%X) already in use.\n", gscd_port
);
1019 /* check for card */
1020 result
= wait_drv_ready ();
1021 if ( result
== 0x09 )
1023 printk ("GSCD: DMA kann ich noch nicht!\n" );
1027 if ( result
== 0x0b )
1033 printk ( "GSCD: GoldStar CD-ROM Drive is not found.\n" );
1038 if ( (result
!= 0x0b) && (result
!= 0x09) )
1040 printk ("GSCD: GoldStar Interface Adapter does not exist or H/W error\n" );
1044 /* reset all drives */
1046 while ( drv_states
[i
] != 0 )
1048 curr_drv_state
= drv_states
[i
];
1049 printk (KERN_INFO
"GSCD: Reset unit %d ... ",i
);
1051 printk ( "done\n" );
1055 if (register_blkdev(MAJOR_NR
, "gscd", &gscd_fops
) != 0)
1057 printk("GSCD: Unable to get major %d for GoldStar CD-ROM\n",
1062 blk_dev
[MAJOR_NR
].request_fn
= DEVICE_REQUEST
;
1063 read_ahead
[MAJOR_NR
] = 4;
1068 request_region(gscd_port
, 4, "gscd");
1070 printk (KERN_INFO
"GSCD: GoldStar CD-ROM Drive found.\n" );
1074 static void gscd_hsg2msf (long hsg
, struct msf
*msf
)
1076 hsg
+= CD_MSF_OFFSET
;
1077 msf
-> min
= hsg
/ (CD_FRAMES
*CD_SECS
);
1078 hsg
%= CD_FRAMES
*CD_SECS
;
1079 msf
-> sec
= hsg
/ CD_FRAMES
;
1080 msf
-> frame
= hsg
% CD_FRAMES
;
1082 gscd_bin2bcd(&msf
-> min
); /* convert to BCD */
1083 gscd_bin2bcd(&msf
-> sec
);
1084 gscd_bin2bcd(&msf
-> frame
);
1088 static void gscd_bin2bcd (unsigned char *p
)
1099 static long gscd_msf2hsg (struct msf
*mp
)
1101 return gscd_bcd2bin(mp
-> frame
)
1102 + gscd_bcd2bin(mp
-> sec
) * CD_FRAMES
1103 + gscd_bcd2bin(mp
-> min
) * CD_FRAMES
* CD_SECS
1107 static int gscd_bcd2bin (unsigned char bcd
)
1109 return (bcd
>> 4) * 10 + (bcd
& 0xF);