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