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