1 #define GSCD_VERSION "0.4a Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>"
2 
3 /*
4 	linux/drivers/block/gscd.c - GoldStar R420 CDROM driver
5 
6         Copyright (C) 1995  Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>
7         based upon pre-works by   Eberhard Moenkeberg <emoenke@gwdg.de>
8 
9 
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
13 
14 
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.
18 
19 
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)
24 	any later version.
25 
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.
30 
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.
34 
35 	--------------------------------------------------------------------
36 
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>
41 
42 */
43 
44 /* These settings are for various debug-level. Leave they untouched ... */
45 #define  NO_GSCD_DEBUG
46 #define  NO_IOCTL_DEBUG
47 #define  NO_MODULE_DEBUG
48 #define  NO_FUTURE_WORK
49 /*------------------------*/
50 
51 #include <linux/module.h>
52 
53 #include <linux/slab.h>
54 #include <linux/errno.h>
55 #include <linux/signal.h>
56 #include <linux/sched.h>
57 #include <linux/timer.h>
58 #include <linux/fs.h>
59 #include <linux/mm.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>
67 
68 #include <asm/system.h>
69 #include <asm/io.h>
70 #include <asm/uaccess.h>
71 
72 #define MAJOR_NR GOLDSTAR_CDROM_MAJOR
73 #include <linux/blk.h>
74 #define gscd_port gscd		/* for compatible parameter passing with "insmod" */
75 #include "gscd.h"
76 
77 static int gscd_blocksizes[1] = { 512 };
78 
79 static int gscdPresent = 0;
80 
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");
85 
86 /* Kommt spaeter vielleicht noch mal dran ...
87  *    static DECLARE_WAIT_QUEUE_HEAD(gscd_waitq);
88  */
89 
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);
94 
95 /* Schnittstellen zum Kern/FS */
96 
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,
100 		      unsigned long);
101 static int gscd_open(struct inode *, struct file *);
102 static int gscd_release(struct inode *, struct file *);
103 static int check_gscd_med_chg(kdev_t);
104 
105 /*      GoldStar Funktionen    */
106 
107 static void cc_Reset(void);
108 static int wait_drv_ready(void);
109 static int find_drives(void);
110 static void cmd_out(int, char *, char *, int);
111 static void cmd_status(void);
112 static void cc_Ident(char *);
113 static void cc_SetSpeed(void);
114 static void init_cd_drive(int);
115 
116 static int get_status(void);
117 static void clear_Audio(void);
118 static void cc_invalidate(void);
119 
120 /* some things for the next version */
121 #ifdef FUTURE_WORK
122 static void update_state(void);
123 static long gscd_msf2hsg(struct msf *mp);
124 static int gscd_bcd2bin(unsigned char bcd);
125 #endif
126 
127 /*    common GoldStar Initialization    */
128 
129 static int my_gscd_init(void);
130 
131 
132 /*      lo-level cmd-Funktionen    */
133 
134 static void cmd_info_in(char *, int);
135 static void cmd_end(void);
136 static void cmd_read_b(char *, int, int);
137 static void cmd_read_w(char *, int, int);
138 static int cmd_unit_alive(void);
139 static void cmd_write_cmd(char *);
140 
141 
142 /*      GoldStar Variablen     */
143 
144 static int curr_drv_state;
145 static int drv_states[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
146 static int drv_mode;
147 static int disk_state;
148 static int speed;
149 static int ndrives;
150 
151 static unsigned char drv_num_read;
152 static unsigned char f_dsk_valid;
153 static unsigned char current_drive;
154 static unsigned char f_drv_ok;
155 
156 
157 static char f_AudioPlay;
158 static char f_AudioPause;
159 static int AudioStart_m;
160 static int AudioStart_f;
161 static int AudioEnd_m;
162 static int AudioEnd_f;
163 
164 static struct timer_list gscd_timer;
165 
166 static struct block_device_operations gscd_fops = {
167 	owner:THIS_MODULE,
168 	open:gscd_open,
169 	release:gscd_release,
170 	ioctl:gscd_ioctl,
171 	check_media_change:check_gscd_med_chg,
172 };
173 
174 /*
175  * Checking if the media has been changed
176  * (not yet implemented)
177  */
check_gscd_med_chg(kdev_t full_dev)178 static int check_gscd_med_chg(kdev_t full_dev)
179 {
180 	int target;
181 
182 
183 	target = MINOR(full_dev);
184 
185 	if (target > 0) {
186 		printk
187 		    ("GSCD: GoldStar CD-ROM request error: invalid device.\n");
188 		return 0;
189 	}
190 #ifdef GSCD_DEBUG
191 	printk("gscd: check_med_change\n");
192 #endif
193 
194 	return 0;
195 }
196 
197 
198 #ifndef MODULE
199 /* Using new interface for kernel-parameters */
200 
gscd_setup(char * str)201 static int __init gscd_setup(char *str)
202 {
203 	int ints[2];
204 	(void) get_options(str, ARRAY_SIZE(ints), ints);
205 
206 	if (ints[0] > 0) {
207 		gscd_port = ints[1];
208 	}
209 	return 1;
210 }
211 
212 __setup("gscd=", gscd_setup);
213 
214 #endif
215 
gscd_ioctl(struct inode * ip,struct file * fp,unsigned int cmd,unsigned long arg)216 static int gscd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
217 		      unsigned long arg)
218 {
219 	unsigned char to_do[10];
220 	unsigned char dummy;
221 
222 
223 	switch (cmd) {
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.
228 		 */
229 		return 0;
230 
231 	case CDROMRESUME:	/* keine Ahnung was das ist */
232 		return 0;
233 
234 
235 	case CDROMEJECT:
236 		cmd_status();
237 		to_do[0] = CMD_TRAY_CTL;
238 		cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0);
239 
240 		return 0;
241 
242 	default:
243 		return -EINVAL;
244 	}
245 
246 }
247 
248 
249 /*
250  * Take care of the different block sizes between cdrom and Linux.
251  * When Linux gets variable block sizes this will probably go away.
252  */
253 
gscd_transfer(void)254 static void gscd_transfer(void)
255 {
256 	long offs;
257 
258 	while (CURRENT->nr_sectors > 0 && gscd_bn == CURRENT->sector / 4) {
259 		offs = (CURRENT->sector & 3) * 512;
260 		memcpy(CURRENT->buffer, gscd_buf + offs, 512);
261 		CURRENT->nr_sectors--;
262 		CURRENT->sector++;
263 		CURRENT->buffer += 512;
264 	}
265 }
266 
267 
268 /*
269  * I/O request routine called from Linux kernel.
270  */
271 
do_gscd_request(request_queue_t * q)272 static void do_gscd_request(request_queue_t * q)
273 {
274 	__do_gscd_request(0);
275 }
276 
__do_gscd_request(unsigned long dummy)277 static void __do_gscd_request(unsigned long dummy)
278 {
279 	unsigned int block, dev;
280 	unsigned int nsect;
281 
282       repeat:
283 	if (QUEUE_EMPTY || CURRENT->rq_status == RQ_INACTIVE)
284 		goto out;
285 	INIT_REQUEST;
286 	dev = MINOR(CURRENT->rq_dev);
287 	block = CURRENT->sector;
288 	nsect = CURRENT->nr_sectors;
289 
290 	if (QUEUE_EMPTY || CURRENT->sector == -1)
291 		goto out;
292 
293 	if (CURRENT->cmd != READ) {
294 		printk("GSCD: bad cmd %d\n", CURRENT->cmd);
295 		end_request(0);
296 		goto repeat;
297 	}
298 
299 	if (MINOR(CURRENT->rq_dev) != 0) {
300 		printk("GSCD: this version supports only one device\n");
301 		end_request(0);
302 		goto repeat;
303 	}
304 
305 	gscd_transfer();
306 
307 	/* if we satisfied the request from the buffer, we're done. */
308 
309 	if (CURRENT->nr_sectors == 0) {
310 		end_request(1);
311 		goto repeat;
312 	}
313 #ifdef GSCD_DEBUG
314 	printk("GSCD: dev %d, block %d, nsect %d\n", dev, block, nsect);
315 #endif
316 
317 	gscd_read_cmd();
318       out:
319 	return;
320 }
321 
322 
323 
324 /*
325  * Check the result of the set-mode command.  On success, send the
326  * read-data command.
327  */
328 
gscd_read_cmd(void)329 static void gscd_read_cmd(void)
330 {
331 	long block;
332 	struct gscd_Play_msf gscdcmd;
333 	char cmd[] = { CMD_READ, 0x80, 0, 0, 0, 0, 1 };	/* cmd mode M-S-F secth sectl */
334 
335 
336 
337 	cmd_status();
338 	if (disk_state & (ST_NO_DISK | ST_DOOR_OPEN)) {
339 		printk("GSCD: no disk or door open\n");
340 		end_request(0);
341 	} else {
342 		if (disk_state & ST_INVALID) {
343 			printk("GSCD: disk invalid\n");
344 			end_request(0);
345 		} else {
346 			gscd_bn = -1;	/* purge our buffer */
347 			block = CURRENT->sector / 4;
348 			gscd_hsg2msf(block, &gscdcmd.start);	/* cvt to msf format */
349 
350 			cmd[2] = gscdcmd.start.min;
351 			cmd[3] = gscdcmd.start.sec;
352 			cmd[4] = gscdcmd.start.frame;
353 
354 #ifdef GSCD_DEBUG
355 			printk("GSCD: read msf %d:%d:%d\n", cmd[2], cmd[3],
356 			       cmd[4]);
357 #endif
358 			cmd_out(TYPE_DATA, (char *) &cmd,
359 				(char *) &gscd_buf[0], 1);
360 
361 			gscd_bn = CURRENT->sector / 4;
362 			gscd_transfer();
363 			end_request(1);
364 		}
365 	}
366 	SET_TIMER(__do_gscd_request, 1);
367 }
368 
369 
370 /*
371  * Open the device special file.  Check that a disk is in.
372  */
373 
gscd_open(struct inode * ip,struct file * fp)374 static int gscd_open(struct inode *ip, struct file *fp)
375 {
376 	int st;
377 
378 #ifdef GSCD_DEBUG
379 	printk("GSCD: open\n");
380 #endif
381 
382 	if (gscdPresent == 0)
383 		return -ENXIO;	/* no hardware */
384 
385 	get_status();
386 	st = disk_state & (ST_NO_DISK | ST_DOOR_OPEN);
387 	if (st) {
388 		printk("GSCD: no disk or door open\n");
389 		return -ENXIO;
390 	}
391 
392 /*	if (updateToc() < 0)
393 		return -EIO;
394 */
395 
396 	return 0;
397 }
398 
399 
400 /*
401  * On close, we flush all gscd blocks from the buffer cache.
402  */
403 
gscd_release(struct inode * inode,struct file * file)404 static int gscd_release(struct inode *inode, struct file *file)
405 {
406 
407 #ifdef GSCD_DEBUG
408 	printk("GSCD: release\n");
409 #endif
410 
411 	gscd_bn = -1;
412 
413 	return 0;
414 }
415 
416 
get_status(void)417 int get_status(void)
418 {
419 	int status;
420 
421 	cmd_status();
422 	status = disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01);
423 
424 	if (status == (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) {
425 		cc_invalidate();
426 		return 1;
427 	} else {
428 		return 0;
429 	}
430 }
431 
432 
cc_invalidate(void)433 void cc_invalidate(void)
434 {
435 	drv_num_read = 0xFF;
436 	f_dsk_valid = 0xFF;
437 	current_drive = 0xFF;
438 	f_drv_ok = 0xFF;
439 
440 	clear_Audio();
441 
442 }
443 
clear_Audio(void)444 void clear_Audio(void)
445 {
446 
447 	f_AudioPlay = 0;
448 	f_AudioPause = 0;
449 	AudioStart_m = 0;
450 	AudioStart_f = 0;
451 	AudioEnd_m = 0;
452 	AudioEnd_f = 0;
453 
454 }
455 
456 /*
457  *   waiting ?
458  */
459 
wait_drv_ready(void)460 int wait_drv_ready(void)
461 {
462 	int found, read;
463 
464 	do {
465 		found = inb(GSCDPORT(0));
466 		found &= 0x0f;
467 		read = inb(GSCDPORT(0));
468 		read &= 0x0f;
469 	} while (read != found);
470 
471 #ifdef GSCD_DEBUG
472 	printk("Wait for: %d\n", read);
473 #endif
474 
475 	return read;
476 }
477 
cc_Ident(char * respons)478 void cc_Ident(char *respons)
479 {
480 	char to_do[] = { CMD_IDENT, 0, 0 };
481 
482 	cmd_out(TYPE_INFO, (char *) &to_do, (char *) respons, (int) 0x1E);
483 
484 }
485 
cc_SetSpeed(void)486 void cc_SetSpeed(void)
487 {
488 	char to_do[] = { CMD_SETSPEED, 0, 0 };
489 	char dummy;
490 
491 	if (speed > 0) {
492 		to_do[1] = speed & 0x0F;
493 		cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0);
494 	}
495 }
496 
497 
cc_Reset(void)498 void cc_Reset(void)
499 {
500 	char to_do[] = { CMD_RESET, 0 };
501 	char dummy;
502 
503 	cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0);
504 }
505 
506 
507 
cmd_status(void)508 void cmd_status(void)
509 {
510 	char to_do[] = { CMD_STATUS, 0 };
511 	char dummy;
512 
513 	cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0);
514 
515 #ifdef GSCD_DEBUG
516 	printk("GSCD: Status: %d\n", disk_state);
517 #endif
518 
519 }
520 
cmd_out(int cmd_type,char * cmd,char * respo_buf,int respo_count)521 void cmd_out(int cmd_type, char *cmd, char *respo_buf, int respo_count)
522 {
523 	int result;
524 
525 
526 	result = wait_drv_ready();
527 	if (result != drv_mode) {
528 		unsigned long test_loops = 0xFFFF;
529 		int i, dummy;
530 
531 		outb(curr_drv_state, GSCDPORT(0));
532 
533 		/* LOCLOOP_170 */
534 		do {
535 			result = wait_drv_ready();
536 			test_loops--;
537 		} while ((result != drv_mode) && (test_loops > 0));
538 
539 		if (result != drv_mode) {
540 			disk_state = ST_x08 | ST_x04 | ST_INVALID;
541 			return;
542 		}
543 
544 		/* ...and waiting */
545 		for (i = 1, dummy = 1; i < 0xFFFF; i++) {
546 			dummy *= i;
547 		}
548 	}
549 
550 	/* LOC_172 */
551 	/* check the unit */
552 	/* and wake it up */
553 	if (cmd_unit_alive() != 0x08) {
554 		/* LOC_174 */
555 		/* game over for this unit */
556 		disk_state = ST_x08 | ST_x04 | ST_INVALID;
557 		return;
558 	}
559 
560 	/* LOC_176 */
561 #ifdef GSCD_DEBUG
562 	printk("LOC_176 ");
563 #endif
564 	if (drv_mode == 0x09) {
565 		/* magic... */
566 		printk("GSCD: magic ...\n");
567 		outb(result, GSCDPORT(2));
568 	}
569 
570 	/* write the command to the drive */
571 	cmd_write_cmd(cmd);
572 
573 	/* LOC_178 */
574 	for (;;) {
575 		result = wait_drv_ready();
576 		if (result != drv_mode) {
577 			/* LOC_179 */
578 			if (result == 0x04) {	/* Mode 4 */
579 				/* LOC_205 */
580 #ifdef GSCD_DEBUG
581 				printk("LOC_205 ");
582 #endif
583 				disk_state = inb(GSCDPORT(2));
584 
585 				do {
586 					result = wait_drv_ready();
587 				} while (result != drv_mode);
588 				return;
589 
590 			} else {
591 				if (result == 0x06) {	/* Mode 6 */
592 					/* LOC_181 */
593 #ifdef GSCD_DEBUG
594 					printk("LOC_181 ");
595 #endif
596 
597 					if (cmd_type == TYPE_DATA) {
598 						/* read data */
599 						/* LOC_184 */
600 						if (drv_mode == 9) {
601 							/* read the data to the buffer (word) */
602 
603 							/* (*(cmd+1))?(CD_FRAMESIZE/2):(CD_FRAMESIZE_RAW/2) */
604 							cmd_read_w
605 							    (respo_buf,
606 							     respo_count,
607 							     CD_FRAMESIZE /
608 							     2);
609 							return;
610 						} else {
611 							/* read the data to the buffer (byte) */
612 
613 							/* (*(cmd+1))?(CD_FRAMESIZE):(CD_FRAMESIZE_RAW)    */
614 							cmd_read_b
615 							    (respo_buf,
616 							     respo_count,
617 							     CD_FRAMESIZE);
618 							return;
619 						}
620 					} else {
621 						/* read the info to the buffer */
622 						cmd_info_in(respo_buf,
623 							    respo_count);
624 						return;
625 					}
626 
627 					return;
628 				}
629 			}
630 
631 		} else {
632 			disk_state = ST_x08 | ST_x04 | ST_INVALID;
633 			return;
634 		}
635 	}			/* for (;;) */
636 
637 
638 #ifdef GSCD_DEBUG
639 	printk("\n");
640 #endif
641 }
642 
643 
cmd_write_cmd(char * pstr)644 static void cmd_write_cmd(char *pstr)
645 {
646 	int i, j;
647 
648 	/* LOC_177 */
649 #ifdef GSCD_DEBUG
650 	printk("LOC_177 ");
651 #endif
652 
653 	/* calculate the number of parameter */
654 	j = *pstr & 0x0F;
655 
656 	/* shift it out */
657 	for (i = 0; i < j; i++) {
658 		outb(*pstr, GSCDPORT(2));
659 		pstr++;
660 	}
661 }
662 
663 
cmd_unit_alive(void)664 static int cmd_unit_alive(void)
665 {
666 	int result;
667 	unsigned long max_test_loops;
668 
669 
670 	/* LOC_172 */
671 #ifdef GSCD_DEBUG
672 	printk("LOC_172 ");
673 #endif
674 
675 	outb(curr_drv_state, GSCDPORT(0));
676 	max_test_loops = 0xFFFF;
677 
678 	do {
679 		result = wait_drv_ready();
680 		max_test_loops--;
681 	} while ((result != 0x08) && (max_test_loops > 0));
682 
683 	return result;
684 }
685 
686 
cmd_info_in(char * pb,int count)687 static void cmd_info_in(char *pb, int count)
688 {
689 	int result;
690 	char read;
691 
692 
693 	/* read info */
694 	/* LOC_182 */
695 #ifdef GSCD_DEBUG
696 	printk("LOC_182 ");
697 #endif
698 
699 	do {
700 		read = inb(GSCDPORT(2));
701 		if (count > 0) {
702 			*pb = read;
703 			pb++;
704 			count--;
705 		}
706 
707 		/* LOC_183 */
708 		do {
709 			result = wait_drv_ready();
710 		} while (result == 0x0E);
711 	} while (result == 6);
712 
713 	cmd_end();
714 	return;
715 }
716 
717 
cmd_read_b(char * pb,int count,int size)718 static void cmd_read_b(char *pb, int count, int size)
719 {
720 	int result;
721 	int i;
722 
723 
724 	/* LOC_188 */
725 	/* LOC_189 */
726 #ifdef GSCD_DEBUG
727 	printk("LOC_189 ");
728 #endif
729 
730 	do {
731 		do {
732 			result = wait_drv_ready();
733 		} while (result != 6 || result == 0x0E);
734 
735 		if (result != 6) {
736 			cmd_end();
737 			return;
738 		}
739 #ifdef GSCD_DEBUG
740 		printk("LOC_191 ");
741 #endif
742 
743 		for (i = 0; i < size; i++) {
744 			*pb = inb(GSCDPORT(2));
745 			pb++;
746 		}
747 		count--;
748 	} while (count > 0);
749 
750 	cmd_end();
751 	return;
752 }
753 
754 
cmd_end(void)755 static void cmd_end(void)
756 {
757 	int result;
758 
759 
760 	/* LOC_204 */
761 #ifdef GSCD_DEBUG
762 	printk("LOC_204 ");
763 #endif
764 
765 	do {
766 		result = wait_drv_ready();
767 		if (result == drv_mode) {
768 			return;
769 		}
770 	} while (result != 4);
771 
772 	/* LOC_205 */
773 #ifdef GSCD_DEBUG
774 	printk("LOC_205 ");
775 #endif
776 
777 	disk_state = inb(GSCDPORT(2));
778 
779 	do {
780 		result = wait_drv_ready();
781 	} while (result != drv_mode);
782 	return;
783 
784 }
785 
786 
cmd_read_w(char * pb,int count,int size)787 static void cmd_read_w(char *pb, int count, int size)
788 {
789 	int result;
790 	int i;
791 
792 
793 #ifdef GSCD_DEBUG
794 	printk("LOC_185 ");
795 #endif
796 
797 	do {
798 		/* LOC_185 */
799 		do {
800 			result = wait_drv_ready();
801 		} while (result != 6 || result == 0x0E);
802 
803 		if (result != 6) {
804 			cmd_end();
805 			return;
806 		}
807 
808 		for (i = 0; i < size; i++) {
809 			/* na, hier muss ich noch mal drueber nachdenken */
810 			*pb = inw(GSCDPORT(2));
811 			pb++;
812 		}
813 		count--;
814 	} while (count > 0);
815 
816 	cmd_end();
817 	return;
818 }
819 
find_drives(void)820 int __init find_drives(void)
821 {
822 	int *pdrv;
823 	int drvnum;
824 	int subdrv;
825 	int i;
826 
827 	speed = 0;
828 	pdrv = (int *) &drv_states;
829 	curr_drv_state = 0xFE;
830 	subdrv = 0;
831 	drvnum = 0;
832 
833 	for (i = 0; i < 8; i++) {
834 		subdrv++;
835 		cmd_status();
836 		disk_state &= ST_x08 | ST_x04 | ST_INVALID | ST_x01;
837 		if (disk_state != (ST_x08 | ST_x04 | ST_INVALID)) {
838 			/* LOC_240 */
839 			*pdrv = curr_drv_state;
840 			init_cd_drive(drvnum);
841 			pdrv++;
842 			drvnum++;
843 		} else {
844 			if (subdrv < 2) {
845 				continue;
846 			} else {
847 				subdrv = 0;
848 			}
849 		}
850 
851 /*       curr_drv_state<<1;         <-- das geht irgendwie nicht */
852 /* muss heissen:    curr_drv_state <<= 1; (ist ja Wert-Zuweisung) */
853 		curr_drv_state *= 2;
854 		curr_drv_state |= 1;
855 #ifdef GSCD_DEBUG
856 		printk("DriveState: %d\n", curr_drv_state);
857 #endif
858 	}
859 
860 	ndrives = drvnum;
861 	return drvnum;
862 }
863 
init_cd_drive(int num)864 void __init init_cd_drive(int num)
865 {
866 	char resp[50];
867 	int i;
868 
869 	printk("GSCD: init unit %d\n", num);
870 	cc_Ident((char *) &resp);
871 
872 	printk("GSCD: identification: ");
873 	for (i = 0; i < 0x1E; i++) {
874 		printk("%c", resp[i]);
875 	}
876 	printk("\n");
877 
878 	cc_SetSpeed();
879 
880 }
881 
882 #ifdef FUTURE_WORK
883 /* return_done */
update_state(void)884 static void update_state(void)
885 {
886 	unsigned int AX;
887 
888 
889 	if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) == 0) {
890 		if (disk_state == (ST_x08 | ST_x04 | ST_INVALID)) {
891 			AX = ST_INVALID;
892 		}
893 
894 		if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01))
895 		    == 0) {
896 			invalidate();
897 			f_drv_ok = 0;
898 		}
899 
900 		AX |= 0x8000;
901 	}
902 
903 	if (disk_state & ST_PLAYING) {
904 		AX |= 0x200;
905 	}
906 
907 	AX |= 0x100;
908 	/* pkt_esbx = AX; */
909 
910 	disk_state = 0;
911 
912 }
913 #endif
914 
915 /* Init for the Module-Version */
init_gscd(void)916 int init_gscd(void)
917 {
918 	long err;
919 
920 
921 	/* call the GoldStar-init */
922 	err = my_gscd_init();
923 
924 	if (err < 0) {
925 		return err;
926 	} else {
927 		printk(KERN_INFO "Happy GoldStar !\n");
928 		return 0;
929 	}
930 }
931 
exit_gscd(void)932 void __exit exit_gscd(void)
933 {
934 	CLEAR_TIMER;
935 
936 	devfs_unregister(devfs_find_handle
937 			 (NULL, "gscd", 0, 0, DEVFS_SPECIAL_BLK, 0));
938 	if ((devfs_unregister_blkdev(MAJOR_NR, "gscd") == -EINVAL)) {
939 		printk("What's that: can't unregister GoldStar-module\n");
940 		return;
941 	}
942 	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
943 	release_region(gscd_port, 4);
944 	printk(KERN_INFO "GoldStar-module released.\n");
945 }
946 
947 #ifdef MODULE
948 module_init(init_gscd);
949 #endif
950 module_exit(exit_gscd);
951 
952 
953 /* Test for presence of drive and initialize it.  Called only at boot time. */
gscd_init(void)954 int __init gscd_init(void)
955 {
956 	return my_gscd_init();
957 }
958 
959 
960 /* This is the common initialisation for the GoldStar drive. */
961 /* It is called at boot time AND for module init.           */
my_gscd_init(void)962 int __init my_gscd_init(void)
963 {
964 	int i;
965 	int result;
966 
967 	printk(KERN_INFO "GSCD: version %s\n", GSCD_VERSION);
968 	printk(KERN_INFO
969 	       "GSCD: Trying to detect a Goldstar R420 CD-ROM drive at 0x%X.\n",
970 	       gscd_port);
971 
972 	if (check_region(gscd_port, 4)) {
973 		printk
974 		    ("GSCD: Init failed, I/O port (%X) already in use.\n",
975 		     gscd_port);
976 		return -EIO;
977 	}
978 
979 
980 	/* check for card */
981 	result = wait_drv_ready();
982 	if (result == 0x09) {
983 		printk("GSCD: DMA kann ich noch nicht!\n");
984 		return -EIO;
985 	}
986 
987 	if (result == 0x0b) {
988 		drv_mode = result;
989 		i = find_drives();
990 		if (i == 0) {
991 			printk
992 			    ("GSCD: GoldStar CD-ROM Drive is not found.\n");
993 			return -EIO;
994 		}
995 	}
996 
997 	if ((result != 0x0b) && (result != 0x09)) {
998 		printk
999 		    ("GSCD: GoldStar Interface Adapter does not exist or H/W error\n");
1000 		return -EIO;
1001 	}
1002 
1003 	/* reset all drives */
1004 	i = 0;
1005 	while (drv_states[i] != 0) {
1006 		curr_drv_state = drv_states[i];
1007 		printk(KERN_INFO "GSCD: Reset unit %d ... ", i);
1008 		cc_Reset();
1009 		printk("done\n");
1010 		i++;
1011 	}
1012 
1013 	if (devfs_register_blkdev(MAJOR_NR, "gscd", &gscd_fops) != 0) {
1014 		printk
1015 		    ("GSCD: Unable to get major %d for GoldStar CD-ROM\n",
1016 		     MAJOR_NR);
1017 		return -EIO;
1018 	}
1019 	devfs_register(NULL, "gscd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
1020 		       S_IFBLK | S_IRUGO | S_IWUGO, &gscd_fops, NULL);
1021 
1022 	blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST);
1023 	blksize_size[MAJOR_NR] = gscd_blocksizes;
1024 	read_ahead[MAJOR_NR] = 4;
1025 
1026 	disk_state = 0;
1027 	gscdPresent = 1;
1028 
1029 	request_region(gscd_port, 4, "gscd");
1030 	register_disk(NULL, MKDEV(MAJOR_NR, 0), 1, &gscd_fops, 0);
1031 
1032 	printk(KERN_INFO "GSCD: GoldStar CD-ROM Drive found.\n");
1033 	return 0;
1034 }
1035 
gscd_hsg2msf(long hsg,struct msf * msf)1036 static void gscd_hsg2msf(long hsg, struct msf *msf)
1037 {
1038 	hsg += CD_MSF_OFFSET;
1039 	msf->min = hsg / (CD_FRAMES * CD_SECS);
1040 	hsg %= CD_FRAMES * CD_SECS;
1041 	msf->sec = hsg / CD_FRAMES;
1042 	msf->frame = hsg % CD_FRAMES;
1043 
1044 	gscd_bin2bcd(&msf->min);	/* convert to BCD */
1045 	gscd_bin2bcd(&msf->sec);
1046 	gscd_bin2bcd(&msf->frame);
1047 }
1048 
1049 
gscd_bin2bcd(unsigned char * p)1050 static void gscd_bin2bcd(unsigned char *p)
1051 {
1052 	int u, t;
1053 
1054 	u = *p % 10;
1055 	t = *p / 10;
1056 	*p = u | (t << 4);
1057 }
1058 
1059 
1060 #ifdef FUTURE_WORK
gscd_msf2hsg(struct msf * mp)1061 static long gscd_msf2hsg(struct msf *mp)
1062 {
1063 	return gscd_bcd2bin(mp->frame)
1064 	    + gscd_bcd2bin(mp->sec) * CD_FRAMES
1065 	    + gscd_bcd2bin(mp->min) * CD_FRAMES * CD_SECS - CD_MSF_OFFSET;
1066 }
1067 
gscd_bcd2bin(unsigned char bcd)1068 static int gscd_bcd2bin(unsigned char bcd)
1069 {
1070 	return (bcd >> 4) * 10 + (bcd & 0xF);
1071 }
1072 #endif
1073 
1074 MODULE_AUTHOR("Oliver Raupach <raupach@nwfs1.rz.fh-hannover.de>");
1075 MODULE_LICENSE("GPL");
1076 EXPORT_NO_SYMBOLS;
1077