Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* -- sjcd.c |
2 | * | |
3 | * Sanyo CD-ROM device driver implementation, Version 1.6 | |
4 | * Copyright (C) 1995 Vadim V. Model | |
5 | * | |
6 | * model@cecmow.enet.dec.com | |
7 | * vadim@rbrf.ru | |
8 | * vadim@ipsun.ras.ru | |
9 | * | |
10 | * | |
11 | * This driver is based on pre-works by Eberhard Moenkeberg (emoenke@gwdg.de); | |
12 | * it was developed under use of mcd.c from Martin Harriss, with help of | |
13 | * Eric van der Maarel (H.T.M.v.d.Maarel@marin.nl). | |
14 | * | |
15 | * It is planned to include these routines into sbpcd.c later - to make | |
16 | * a "mixed use" on one cable possible for all kinds of drives which use | |
17 | * the SoundBlaster/Panasonic style CDROM interface. But today, the | |
18 | * ability to install directly from CDROM is more important than flexibility. | |
19 | * | |
20 | * This program is free software; you can redistribute it and/or modify | |
21 | * it under the terms of the GNU General Public License as published by | |
22 | * the Free Software Foundation; either version 2 of the License, or | |
23 | * (at your option) any later version. | |
24 | * | |
25 | * This program is distributed in the hope that it will be useful, | |
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 | * GNU General Public License for more details. | |
29 | * | |
30 | * You should have received a copy of the GNU General Public License | |
31 | * along with this program; if not, write to the Free Software | |
32 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
33 | * | |
34 | * History: | |
35 | * 1.1 First public release with kernel version 1.3.7. | |
36 | * Written by Vadim Model. | |
37 | * 1.2 Added detection and configuration of cdrom interface | |
38 | * on ISP16 soundcard. | |
39 | * Allow for command line options: sjcd=<io_base>,<irq>,<dma> | |
40 | * 1.3 Some minor changes to README.sjcd. | |
41 | * 1.4 MSS Sound support!! Listen to a CD through the speakers. | |
42 | * 1.5 Module support and bugfixes. | |
43 | * Tray locking. | |
44 | * 1.6 Removed ISP16 code from this driver. | |
45 | * Allow only to set io base address on command line: sjcd=<io_base> | |
46 | * Changes to Documentation/cdrom/sjcd | |
47 | * Added cleanup after any error in the initialisation. | |
48 | * 1.7 Added code to set the sector size tables to prevent the bug present in | |
49 | * the previous version of this driver. Coded added by Anthony Barbachan | |
50 | * from bugfix tip originally suggested by Alan Cox. | |
51 | * | |
52 | * November 1999 -- Make kernel-parameter implementation work with 2.3.x | |
53 | * Removed init_module & cleanup_module in favor of | |
54 | * module_init & module_exit. | |
55 | * Torben Mathiasen <tmm@image.dk> | |
56 | */ | |
57 | ||
58 | #define SJCD_VERSION_MAJOR 1 | |
59 | #define SJCD_VERSION_MINOR 7 | |
60 | ||
61 | #include <linux/module.h> | |
62 | #include <linux/errno.h> | |
63 | #include <linux/sched.h> | |
64 | #include <linux/mm.h> | |
65 | #include <linux/timer.h> | |
66 | #include <linux/fs.h> | |
67 | #include <linux/kernel.h> | |
68 | #include <linux/cdrom.h> | |
69 | #include <linux/ioport.h> | |
70 | #include <linux/string.h> | |
71 | #include <linux/major.h> | |
72 | #include <linux/init.h> | |
73 | ||
74 | #include <asm/system.h> | |
75 | #include <asm/io.h> | |
76 | #include <asm/uaccess.h> | |
77 | #include <linux/blkdev.h> | |
78 | #include "sjcd.h" | |
79 | ||
80 | static int sjcd_present = 0; | |
81 | static struct request_queue *sjcd_queue; | |
82 | ||
83 | #define MAJOR_NR SANYO_CDROM_MAJOR | |
84 | #define QUEUE (sjcd_queue) | |
85 | #define CURRENT elv_next_request(sjcd_queue) | |
86 | ||
87 | #define SJCD_BUF_SIZ 32 /* cdr-h94a has internal 64K buffer */ | |
88 | ||
89 | /* | |
90 | * buffer for block size conversion | |
91 | */ | |
92 | static char sjcd_buf[2048 * SJCD_BUF_SIZ]; | |
93 | static volatile int sjcd_buf_bn[SJCD_BUF_SIZ], sjcd_next_bn; | |
94 | static volatile int sjcd_buf_in, sjcd_buf_out = -1; | |
95 | ||
96 | /* | |
97 | * Status. | |
98 | */ | |
99 | static unsigned short sjcd_status_valid = 0; | |
100 | static unsigned short sjcd_door_closed; | |
101 | static unsigned short sjcd_door_was_open; | |
102 | static unsigned short sjcd_media_is_available; | |
103 | static unsigned short sjcd_media_is_changed; | |
104 | static unsigned short sjcd_toc_uptodate = 0; | |
105 | static unsigned short sjcd_command_failed; | |
106 | static volatile unsigned char sjcd_completion_status = 0; | |
107 | static volatile unsigned char sjcd_completion_error = 0; | |
108 | static unsigned short sjcd_command_is_in_progress = 0; | |
109 | static unsigned short sjcd_error_reported = 0; | |
110 | static DEFINE_SPINLOCK(sjcd_lock); | |
111 | ||
112 | static int sjcd_open_count; | |
113 | ||
114 | static int sjcd_audio_status; | |
115 | static struct sjcd_play_msf sjcd_playing; | |
116 | ||
117 | static int sjcd_base = SJCD_BASE_ADDR; | |
118 | ||
119 | module_param(sjcd_base, int, 0); | |
120 | ||
121 | static DECLARE_WAIT_QUEUE_HEAD(sjcd_waitq); | |
122 | ||
123 | /* | |
124 | * Data transfer. | |
125 | */ | |
126 | static volatile unsigned short sjcd_transfer_is_active = 0; | |
127 | ||
128 | enum sjcd_transfer_state { | |
129 | SJCD_S_IDLE = 0, | |
130 | SJCD_S_START = 1, | |
131 | SJCD_S_MODE = 2, | |
132 | SJCD_S_READ = 3, | |
133 | SJCD_S_DATA = 4, | |
134 | SJCD_S_STOP = 5, | |
135 | SJCD_S_STOPPING = 6 | |
136 | }; | |
137 | static enum sjcd_transfer_state sjcd_transfer_state = SJCD_S_IDLE; | |
138 | static long sjcd_transfer_timeout = 0; | |
139 | static int sjcd_read_count = 0; | |
140 | static unsigned char sjcd_mode = 0; | |
141 | ||
142 | #define SJCD_READ_TIMEOUT 5000 | |
143 | ||
144 | #if defined( SJCD_GATHER_STAT ) | |
145 | /* | |
146 | * Statistic. | |
147 | */ | |
148 | static struct sjcd_stat statistic; | |
149 | #endif | |
150 | ||
151 | /* | |
152 | * Timer. | |
153 | */ | |
8d06afab | 154 | static DEFINE_TIMER(sjcd_delay_timer, NULL, 0, 0); |
1da177e4 LT |
155 | |
156 | #define SJCD_SET_TIMER( func, tmout ) \ | |
157 | ( sjcd_delay_timer.expires = jiffies+tmout, \ | |
158 | sjcd_delay_timer.function = ( void * )func, \ | |
159 | add_timer( &sjcd_delay_timer ) ) | |
160 | ||
161 | #define CLEAR_TIMER del_timer( &sjcd_delay_timer ) | |
162 | ||
163 | /* | |
164 | * Set up device, i.e., use command line data to set | |
165 | * base address. | |
166 | */ | |
167 | #ifndef MODULE | |
168 | static int __init sjcd_setup(char *str) | |
169 | { | |
170 | int ints[2]; | |
171 | (void) get_options(str, ARRAY_SIZE(ints), ints); | |
172 | if (ints[0] > 0) | |
173 | sjcd_base = ints[1]; | |
174 | ||
175 | return 1; | |
176 | } | |
177 | ||
178 | __setup("sjcd=", sjcd_setup); | |
179 | ||
180 | #endif | |
181 | ||
182 | /* | |
183 | * Special converters. | |
184 | */ | |
185 | static unsigned char bin2bcd(int bin) | |
186 | { | |
187 | int u, v; | |
188 | ||
189 | u = bin % 10; | |
190 | v = bin / 10; | |
191 | return (u | (v << 4)); | |
192 | } | |
193 | ||
194 | static int bcd2bin(unsigned char bcd) | |
195 | { | |
196 | return ((bcd >> 4) * 10 + (bcd & 0x0F)); | |
197 | } | |
198 | ||
199 | static long msf2hsg(struct msf *mp) | |
200 | { | |
201 | return (bcd2bin(mp->frame) + bcd2bin(mp->sec) * 75 | |
202 | + bcd2bin(mp->min) * 4500 - 150); | |
203 | } | |
204 | ||
205 | static void hsg2msf(long hsg, struct msf *msf) | |
206 | { | |
207 | hsg += 150; | |
208 | msf->min = hsg / 4500; | |
209 | hsg %= 4500; | |
210 | msf->sec = hsg / 75; | |
211 | msf->frame = hsg % 75; | |
212 | msf->min = bin2bcd(msf->min); /* convert to BCD */ | |
213 | msf->sec = bin2bcd(msf->sec); | |
214 | msf->frame = bin2bcd(msf->frame); | |
215 | } | |
216 | ||
217 | /* | |
218 | * Send a command to cdrom. Invalidate status. | |
219 | */ | |
220 | static void sjcd_send_cmd(unsigned char cmd) | |
221 | { | |
222 | #if defined( SJCD_TRACE ) | |
223 | printk("SJCD: send_cmd( 0x%x )\n", cmd); | |
224 | #endif | |
225 | outb(cmd, SJCDPORT(0)); | |
226 | sjcd_command_is_in_progress = 1; | |
227 | sjcd_status_valid = 0; | |
228 | sjcd_command_failed = 0; | |
229 | } | |
230 | ||
231 | /* | |
232 | * Send a command with one arg to cdrom. Invalidate status. | |
233 | */ | |
234 | static void sjcd_send_1_cmd(unsigned char cmd, unsigned char a) | |
235 | { | |
236 | #if defined( SJCD_TRACE ) | |
237 | printk("SJCD: send_1_cmd( 0x%x, 0x%x )\n", cmd, a); | |
238 | #endif | |
239 | outb(cmd, SJCDPORT(0)); | |
240 | outb(a, SJCDPORT(0)); | |
241 | sjcd_command_is_in_progress = 1; | |
242 | sjcd_status_valid = 0; | |
243 | sjcd_command_failed = 0; | |
244 | } | |
245 | ||
246 | /* | |
247 | * Send a command with four args to cdrom. Invalidate status. | |
248 | */ | |
249 | static void sjcd_send_4_cmd(unsigned char cmd, unsigned char a, | |
250 | unsigned char b, unsigned char c, | |
251 | unsigned char d) | |
252 | { | |
253 | #if defined( SJCD_TRACE ) | |
254 | printk("SJCD: send_4_cmd( 0x%x )\n", cmd); | |
255 | #endif | |
256 | outb(cmd, SJCDPORT(0)); | |
257 | outb(a, SJCDPORT(0)); | |
258 | outb(b, SJCDPORT(0)); | |
259 | outb(c, SJCDPORT(0)); | |
260 | outb(d, SJCDPORT(0)); | |
261 | sjcd_command_is_in_progress = 1; | |
262 | sjcd_status_valid = 0; | |
263 | sjcd_command_failed = 0; | |
264 | } | |
265 | ||
266 | /* | |
267 | * Send a play or read command to cdrom. Invalidate Status. | |
268 | */ | |
269 | static void sjcd_send_6_cmd(unsigned char cmd, struct sjcd_play_msf *pms) | |
270 | { | |
271 | #if defined( SJCD_TRACE ) | |
272 | printk("SJCD: send_long_cmd( 0x%x )\n", cmd); | |
273 | #endif | |
274 | outb(cmd, SJCDPORT(0)); | |
275 | outb(pms->start.min, SJCDPORT(0)); | |
276 | outb(pms->start.sec, SJCDPORT(0)); | |
277 | outb(pms->start.frame, SJCDPORT(0)); | |
278 | outb(pms->end.min, SJCDPORT(0)); | |
279 | outb(pms->end.sec, SJCDPORT(0)); | |
280 | outb(pms->end.frame, SJCDPORT(0)); | |
281 | sjcd_command_is_in_progress = 1; | |
282 | sjcd_status_valid = 0; | |
283 | sjcd_command_failed = 0; | |
284 | } | |
285 | ||
286 | /* | |
287 | * Get a value from the data port. Should not block, so we use a little | |
288 | * wait for a while. Returns 0 if OK. | |
289 | */ | |
290 | static int sjcd_load_response(void *buf, int len) | |
291 | { | |
292 | unsigned char *resp = (unsigned char *) buf; | |
293 | ||
294 | for (; len; --len) { | |
295 | int i; | |
296 | for (i = 200; | |
297 | i-- && !SJCD_STATUS_AVAILABLE(inb(SJCDPORT(1)));); | |
298 | if (i > 0) | |
299 | *resp++ = (unsigned char) inb(SJCDPORT(0)); | |
300 | else | |
301 | break; | |
302 | } | |
303 | return (len); | |
304 | } | |
305 | ||
306 | /* | |
307 | * Load and parse command completion status (drive info byte and maybe error). | |
308 | * Sorry, no error classification yet. | |
309 | */ | |
310 | static void sjcd_load_status(void) | |
311 | { | |
312 | sjcd_media_is_changed = 0; | |
313 | sjcd_completion_error = 0; | |
314 | sjcd_completion_status = inb(SJCDPORT(0)); | |
315 | if (sjcd_completion_status & SST_DOOR_OPENED) { | |
316 | sjcd_door_closed = sjcd_media_is_available = 0; | |
317 | } else { | |
318 | sjcd_door_closed = 1; | |
319 | if (sjcd_completion_status & SST_MEDIA_CHANGED) | |
320 | sjcd_media_is_available = sjcd_media_is_changed = | |
321 | 1; | |
322 | else if (sjcd_completion_status & 0x0F) { | |
323 | /* | |
324 | * OK, we seem to catch an error ... | |
325 | */ | |
326 | while (!SJCD_STATUS_AVAILABLE(inb(SJCDPORT(1)))); | |
327 | sjcd_completion_error = inb(SJCDPORT(0)); | |
328 | if ((sjcd_completion_status & 0x08) && | |
329 | (sjcd_completion_error & 0x40)) | |
330 | sjcd_media_is_available = 0; | |
331 | else | |
332 | sjcd_command_failed = 1; | |
333 | } else | |
334 | sjcd_media_is_available = 1; | |
335 | } | |
336 | /* | |
337 | * Ok, status loaded successfully. | |
338 | */ | |
339 | sjcd_status_valid = 1, sjcd_error_reported = 0; | |
340 | sjcd_command_is_in_progress = 0; | |
341 | ||
342 | /* | |
343 | * If the disk is changed, the TOC is not valid. | |
344 | */ | |
345 | if (sjcd_media_is_changed) | |
346 | sjcd_toc_uptodate = 0; | |
347 | #if defined( SJCD_TRACE ) | |
348 | printk("SJCD: status %02x.%02x loaded.\n", | |
349 | (int) sjcd_completion_status, (int) sjcd_completion_error); | |
350 | #endif | |
351 | } | |
352 | ||
353 | /* | |
354 | * Read status from cdrom. Check to see if the status is available. | |
355 | */ | |
356 | static int sjcd_check_status(void) | |
357 | { | |
358 | /* | |
359 | * Try to load the response from cdrom into buffer. | |
360 | */ | |
361 | if (SJCD_STATUS_AVAILABLE(inb(SJCDPORT(1)))) { | |
362 | sjcd_load_status(); | |
363 | return (1); | |
364 | } else { | |
365 | /* | |
366 | * No status is available. | |
367 | */ | |
368 | return (0); | |
369 | } | |
370 | } | |
371 | ||
372 | /* | |
373 | * This is just timeout counter, and nothing more. Surprised ? :-) | |
374 | */ | |
375 | static volatile long sjcd_status_timeout; | |
376 | ||
377 | /* | |
378 | * We need about 10 seconds to wait. The longest command takes about 5 seconds | |
379 | * to probe the disk (usually after tray closed or drive reset). Other values | |
380 | * should be thought of for other commands. | |
381 | */ | |
382 | #define SJCD_WAIT_FOR_STATUS_TIMEOUT 1000 | |
383 | ||
384 | static void sjcd_status_timer(void) | |
385 | { | |
386 | if (sjcd_check_status()) { | |
387 | /* | |
388 | * The command completed and status is loaded, stop waiting. | |
389 | */ | |
390 | wake_up(&sjcd_waitq); | |
391 | } else if (--sjcd_status_timeout <= 0) { | |
392 | /* | |
393 | * We are timed out. | |
394 | */ | |
395 | wake_up(&sjcd_waitq); | |
396 | } else { | |
397 | /* | |
398 | * We have still some time to wait. Try again. | |
399 | */ | |
400 | SJCD_SET_TIMER(sjcd_status_timer, 1); | |
401 | } | |
402 | } | |
403 | ||
404 | /* | |
405 | * Wait for status for 10 sec approx. Returns non-positive when timed out. | |
406 | * Should not be used while reading data CDs. | |
407 | */ | |
408 | static int sjcd_wait_for_status(void) | |
409 | { | |
410 | sjcd_status_timeout = SJCD_WAIT_FOR_STATUS_TIMEOUT; | |
411 | SJCD_SET_TIMER(sjcd_status_timer, 1); | |
412 | sleep_on(&sjcd_waitq); | |
413 | #if defined( SJCD_DIAGNOSTIC ) || defined ( SJCD_TRACE ) | |
414 | if (sjcd_status_timeout <= 0) | |
415 | printk("SJCD: Error Wait For Status.\n"); | |
416 | #endif | |
417 | return (sjcd_status_timeout); | |
418 | } | |
419 | ||
420 | static int sjcd_receive_status(void) | |
421 | { | |
422 | int i; | |
423 | #if defined( SJCD_TRACE ) | |
424 | printk("SJCD: receive_status\n"); | |
425 | #endif | |
426 | /* | |
427 | * Wait a bit for status available. | |
428 | */ | |
429 | for (i = 200; i-- && (sjcd_check_status() == 0);); | |
430 | if (i < 0) { | |
431 | #if defined( SJCD_TRACE ) | |
432 | printk("SJCD: long wait for status\n"); | |
433 | #endif | |
434 | if (sjcd_wait_for_status() <= 0) | |
435 | printk("SJCD: Timeout when read status.\n"); | |
436 | else | |
437 | i = 0; | |
438 | } | |
439 | return (i); | |
440 | } | |
441 | ||
442 | /* | |
443 | * Load the status. Issue get status command and wait for status available. | |
444 | */ | |
445 | static void sjcd_get_status(void) | |
446 | { | |
447 | #if defined( SJCD_TRACE ) | |
448 | printk("SJCD: get_status\n"); | |
449 | #endif | |
450 | sjcd_send_cmd(SCMD_GET_STATUS); | |
451 | sjcd_receive_status(); | |
452 | } | |
453 | ||
454 | /* | |
455 | * Check the drive if the disk is changed. Should be revised. | |
456 | */ | |
457 | static int sjcd_disk_change(struct gendisk *disk) | |
458 | { | |
459 | #if 0 | |
460 | printk("SJCD: sjcd_disk_change(%s)\n", disk->disk_name); | |
461 | #endif | |
462 | if (!sjcd_command_is_in_progress) | |
463 | sjcd_get_status(); | |
464 | return (sjcd_status_valid ? sjcd_media_is_changed : 0); | |
465 | } | |
466 | ||
467 | /* | |
468 | * Read the table of contents (TOC) and TOC header if necessary. | |
469 | * We assume that the drive contains no more than 99 toc entries. | |
470 | */ | |
471 | static struct sjcd_hw_disk_info sjcd_table_of_contents[SJCD_MAX_TRACKS]; | |
472 | static unsigned char sjcd_first_track_no, sjcd_last_track_no; | |
473 | #define sjcd_disk_length sjcd_table_of_contents[0].un.track_msf | |
474 | ||
475 | static int sjcd_update_toc(void) | |
476 | { | |
477 | struct sjcd_hw_disk_info info; | |
478 | int i; | |
479 | #if defined( SJCD_TRACE ) | |
480 | printk("SJCD: update toc:\n"); | |
481 | #endif | |
482 | /* | |
483 | * check to see if we need to do anything | |
484 | */ | |
485 | if (sjcd_toc_uptodate) | |
486 | return (0); | |
487 | ||
488 | /* | |
489 | * Get the TOC start information. | |
490 | */ | |
491 | sjcd_send_1_cmd(SCMD_GET_DISK_INFO, SCMD_GET_1_TRACK); | |
492 | sjcd_receive_status(); | |
493 | ||
494 | if (!sjcd_status_valid) { | |
495 | printk("SJCD: cannot load status.\n"); | |
496 | return (-1); | |
497 | } | |
498 | ||
499 | if (!sjcd_media_is_available) { | |
500 | printk("SJCD: no disk in drive\n"); | |
501 | return (-1); | |
502 | } | |
503 | ||
504 | if (!sjcd_command_failed) { | |
505 | if (sjcd_load_response(&info, sizeof(info)) != 0) { | |
506 | printk | |
507 | ("SJCD: cannot load response about TOC start.\n"); | |
508 | return (-1); | |
509 | } | |
510 | sjcd_first_track_no = bcd2bin(info.un.track_no); | |
511 | } else { | |
512 | printk("SJCD: get first failed\n"); | |
513 | return (-1); | |
514 | } | |
515 | #if defined( SJCD_TRACE ) | |
516 | printk("SJCD: TOC start 0x%02x ", sjcd_first_track_no); | |
517 | #endif | |
518 | /* | |
519 | * Get the TOC finish information. | |
520 | */ | |
521 | sjcd_send_1_cmd(SCMD_GET_DISK_INFO, SCMD_GET_L_TRACK); | |
522 | sjcd_receive_status(); | |
523 | ||
524 | if (!sjcd_status_valid) { | |
525 | printk("SJCD: cannot load status.\n"); | |
526 | return (-1); | |
527 | } | |
528 | ||
529 | if (!sjcd_media_is_available) { | |
530 | printk("SJCD: no disk in drive\n"); | |
531 | return (-1); | |
532 | } | |
533 | ||
534 | if (!sjcd_command_failed) { | |
535 | if (sjcd_load_response(&info, sizeof(info)) != 0) { | |
536 | printk | |
537 | ("SJCD: cannot load response about TOC finish.\n"); | |
538 | return (-1); | |
539 | } | |
540 | sjcd_last_track_no = bcd2bin(info.un.track_no); | |
541 | } else { | |
542 | printk("SJCD: get last failed\n"); | |
543 | return (-1); | |
544 | } | |
545 | #if defined( SJCD_TRACE ) | |
546 | printk("SJCD: TOC finish 0x%02x ", sjcd_last_track_no); | |
547 | #endif | |
548 | for (i = sjcd_first_track_no; i <= sjcd_last_track_no; i++) { | |
549 | /* | |
550 | * Get the first track information. | |
551 | */ | |
552 | sjcd_send_1_cmd(SCMD_GET_DISK_INFO, bin2bcd(i)); | |
553 | sjcd_receive_status(); | |
554 | ||
555 | if (!sjcd_status_valid) { | |
556 | printk("SJCD: cannot load status.\n"); | |
557 | return (-1); | |
558 | } | |
559 | ||
560 | if (!sjcd_media_is_available) { | |
561 | printk("SJCD: no disk in drive\n"); | |
562 | return (-1); | |
563 | } | |
564 | ||
565 | if (!sjcd_command_failed) { | |
566 | if (sjcd_load_response(&sjcd_table_of_contents[i], | |
567 | sizeof(struct | |
568 | sjcd_hw_disk_info)) | |
569 | != 0) { | |
570 | printk | |
571 | ("SJCD: cannot load info for %d track\n", | |
572 | i); | |
573 | return (-1); | |
574 | } | |
575 | } else { | |
576 | printk("SJCD: get info %d failed\n", i); | |
577 | return (-1); | |
578 | } | |
579 | } | |
580 | ||
581 | /* | |
582 | * Get the disk length info. | |
583 | */ | |
584 | sjcd_send_1_cmd(SCMD_GET_DISK_INFO, SCMD_GET_D_SIZE); | |
585 | sjcd_receive_status(); | |
586 | ||
587 | if (!sjcd_status_valid) { | |
588 | printk("SJCD: cannot load status.\n"); | |
589 | return (-1); | |
590 | } | |
591 | ||
592 | if (!sjcd_media_is_available) { | |
593 | printk("SJCD: no disk in drive\n"); | |
594 | return (-1); | |
595 | } | |
596 | ||
597 | if (!sjcd_command_failed) { | |
598 | if (sjcd_load_response(&info, sizeof(info)) != 0) { | |
599 | printk | |
600 | ("SJCD: cannot load response about disk size.\n"); | |
601 | return (-1); | |
602 | } | |
603 | sjcd_disk_length.min = info.un.track_msf.min; | |
604 | sjcd_disk_length.sec = info.un.track_msf.sec; | |
605 | sjcd_disk_length.frame = info.un.track_msf.frame; | |
606 | } else { | |
607 | printk("SJCD: get size failed\n"); | |
608 | return (1); | |
609 | } | |
610 | #if defined( SJCD_TRACE ) | |
611 | printk("SJCD: (%02x:%02x.%02x)\n", sjcd_disk_length.min, | |
612 | sjcd_disk_length.sec, sjcd_disk_length.frame); | |
613 | #endif | |
614 | return (0); | |
615 | } | |
616 | ||
617 | /* | |
618 | * Load subchannel information. | |
619 | */ | |
620 | static int sjcd_get_q_info(struct sjcd_hw_qinfo *qp) | |
621 | { | |
622 | int s; | |
623 | #if defined( SJCD_TRACE ) | |
624 | printk("SJCD: load sub q\n"); | |
625 | #endif | |
626 | sjcd_send_cmd(SCMD_GET_QINFO); | |
627 | s = sjcd_receive_status(); | |
628 | if (s < 0 || sjcd_command_failed || !sjcd_status_valid) { | |
629 | sjcd_send_cmd(0xF2); | |
630 | s = sjcd_receive_status(); | |
631 | if (s < 0 || sjcd_command_failed || !sjcd_status_valid) | |
632 | return (-1); | |
633 | sjcd_send_cmd(SCMD_GET_QINFO); | |
634 | s = sjcd_receive_status(); | |
635 | if (s < 0 || sjcd_command_failed || !sjcd_status_valid) | |
636 | return (-1); | |
637 | } | |
638 | if (sjcd_media_is_available) | |
639 | if (sjcd_load_response(qp, sizeof(*qp)) == 0) | |
640 | return (0); | |
641 | return (-1); | |
642 | } | |
643 | ||
644 | /* | |
645 | * Start playing from the specified position. | |
646 | */ | |
647 | static int sjcd_play(struct sjcd_play_msf *mp) | |
648 | { | |
649 | struct sjcd_play_msf msf; | |
650 | ||
651 | /* | |
652 | * Turn the device to play mode. | |
653 | */ | |
654 | sjcd_send_1_cmd(SCMD_SET_MODE, SCMD_MODE_PLAY); | |
655 | if (sjcd_receive_status() < 0) | |
656 | return (-1); | |
657 | ||
658 | /* | |
659 | * Seek to the starting point. | |
660 | */ | |
661 | msf.start = mp->start; | |
662 | msf.end.min = msf.end.sec = msf.end.frame = 0x00; | |
663 | sjcd_send_6_cmd(SCMD_SEEK, &msf); | |
664 | if (sjcd_receive_status() < 0) | |
665 | return (-1); | |
666 | ||
667 | /* | |
668 | * Start playing. | |
669 | */ | |
670 | sjcd_send_6_cmd(SCMD_PLAY, mp); | |
671 | return (sjcd_receive_status()); | |
672 | } | |
673 | ||
674 | /* | |
675 | * Tray control functions. | |
676 | */ | |
677 | static int sjcd_tray_close(void) | |
678 | { | |
679 | #if defined( SJCD_TRACE ) | |
680 | printk("SJCD: tray_close\n"); | |
681 | #endif | |
682 | sjcd_send_cmd(SCMD_CLOSE_TRAY); | |
683 | return (sjcd_receive_status()); | |
684 | } | |
685 | ||
686 | static int sjcd_tray_lock(void) | |
687 | { | |
688 | #if defined( SJCD_TRACE ) | |
689 | printk("SJCD: tray_lock\n"); | |
690 | #endif | |
691 | sjcd_send_cmd(SCMD_LOCK_TRAY); | |
692 | return (sjcd_receive_status()); | |
693 | } | |
694 | ||
695 | static int sjcd_tray_unlock(void) | |
696 | { | |
697 | #if defined( SJCD_TRACE ) | |
698 | printk("SJCD: tray_unlock\n"); | |
699 | #endif | |
700 | sjcd_send_cmd(SCMD_UNLOCK_TRAY); | |
701 | return (sjcd_receive_status()); | |
702 | } | |
703 | ||
704 | static int sjcd_tray_open(void) | |
705 | { | |
706 | #if defined( SJCD_TRACE ) | |
707 | printk("SJCD: tray_open\n"); | |
708 | #endif | |
709 | sjcd_send_cmd(SCMD_EJECT_TRAY); | |
710 | return (sjcd_receive_status()); | |
711 | } | |
712 | ||
713 | /* | |
714 | * Do some user commands. | |
715 | */ | |
716 | static int sjcd_ioctl(struct inode *ip, struct file *fp, | |
717 | unsigned int cmd, unsigned long arg) | |
718 | { | |
719 | void __user *argp = (void __user *)arg; | |
720 | #if defined( SJCD_TRACE ) | |
721 | printk("SJCD:ioctl\n"); | |
722 | #endif | |
723 | ||
724 | sjcd_get_status(); | |
725 | if (!sjcd_status_valid) | |
726 | return (-EIO); | |
727 | if (sjcd_update_toc() < 0) | |
728 | return (-EIO); | |
729 | ||
730 | switch (cmd) { | |
731 | case CDROMSTART:{ | |
732 | #if defined( SJCD_TRACE ) | |
733 | printk("SJCD: ioctl: start\n"); | |
734 | #endif | |
735 | return (0); | |
736 | } | |
737 | ||
738 | case CDROMSTOP:{ | |
739 | #if defined( SJCD_TRACE ) | |
740 | printk("SJCD: ioctl: stop\n"); | |
741 | #endif | |
742 | sjcd_send_cmd(SCMD_PAUSE); | |
743 | (void) sjcd_receive_status(); | |
744 | sjcd_audio_status = CDROM_AUDIO_NO_STATUS; | |
745 | return (0); | |
746 | } | |
747 | ||
748 | case CDROMPAUSE:{ | |
749 | struct sjcd_hw_qinfo q_info; | |
750 | #if defined( SJCD_TRACE ) | |
751 | printk("SJCD: ioctl: pause\n"); | |
752 | #endif | |
753 | if (sjcd_audio_status == CDROM_AUDIO_PLAY) { | |
754 | sjcd_send_cmd(SCMD_PAUSE); | |
755 | (void) sjcd_receive_status(); | |
756 | if (sjcd_get_q_info(&q_info) < 0) { | |
757 | sjcd_audio_status = | |
758 | CDROM_AUDIO_NO_STATUS; | |
759 | } else { | |
760 | sjcd_audio_status = | |
761 | CDROM_AUDIO_PAUSED; | |
762 | sjcd_playing.start = q_info.abs; | |
763 | } | |
764 | return (0); | |
765 | } else | |
766 | return (-EINVAL); | |
767 | } | |
768 | ||
769 | case CDROMRESUME:{ | |
770 | #if defined( SJCD_TRACE ) | |
771 | printk("SJCD: ioctl: resume\n"); | |
772 | #endif | |
773 | if (sjcd_audio_status == CDROM_AUDIO_PAUSED) { | |
774 | /* | |
775 | * continue play starting at saved location | |
776 | */ | |
777 | if (sjcd_play(&sjcd_playing) < 0) { | |
778 | sjcd_audio_status = | |
779 | CDROM_AUDIO_ERROR; | |
780 | return (-EIO); | |
781 | } else { | |
782 | sjcd_audio_status = | |
783 | CDROM_AUDIO_PLAY; | |
784 | return (0); | |
785 | } | |
786 | } else | |
787 | return (-EINVAL); | |
788 | } | |
789 | ||
790 | case CDROMPLAYTRKIND:{ | |
791 | struct cdrom_ti ti; | |
792 | int s = -EFAULT; | |
793 | #if defined( SJCD_TRACE ) | |
794 | printk("SJCD: ioctl: playtrkind\n"); | |
795 | #endif | |
796 | if (!copy_from_user(&ti, argp, sizeof(ti))) { | |
797 | s = 0; | |
798 | if (ti.cdti_trk0 < sjcd_first_track_no) | |
799 | return (-EINVAL); | |
800 | if (ti.cdti_trk1 > sjcd_last_track_no) | |
801 | ti.cdti_trk1 = sjcd_last_track_no; | |
802 | if (ti.cdti_trk0 > ti.cdti_trk1) | |
803 | return (-EINVAL); | |
804 | ||
805 | sjcd_playing.start = | |
806 | sjcd_table_of_contents[ti.cdti_trk0]. | |
807 | un.track_msf; | |
808 | sjcd_playing.end = | |
809 | (ti.cdti_trk1 < | |
810 | sjcd_last_track_no) ? | |
811 | sjcd_table_of_contents[ti.cdti_trk1 + | |
812 | 1].un. | |
813 | track_msf : sjcd_table_of_contents[0]. | |
814 | un.track_msf; | |
815 | ||
816 | if (sjcd_play(&sjcd_playing) < 0) { | |
817 | sjcd_audio_status = | |
818 | CDROM_AUDIO_ERROR; | |
819 | return (-EIO); | |
820 | } else | |
821 | sjcd_audio_status = | |
822 | CDROM_AUDIO_PLAY; | |
823 | } | |
824 | return (s); | |
825 | } | |
826 | ||
827 | case CDROMPLAYMSF:{ | |
828 | struct cdrom_msf sjcd_msf; | |
829 | int s; | |
830 | #if defined( SJCD_TRACE ) | |
831 | printk("SJCD: ioctl: playmsf\n"); | |
832 | #endif | |
833 | if ((s = | |
834 | access_ok(VERIFY_READ, argp, sizeof(sjcd_msf)) | |
835 | ? 0 : -EFAULT) == 0) { | |
836 | if (sjcd_audio_status == CDROM_AUDIO_PLAY) { | |
837 | sjcd_send_cmd(SCMD_PAUSE); | |
838 | (void) sjcd_receive_status(); | |
839 | sjcd_audio_status = | |
840 | CDROM_AUDIO_NO_STATUS; | |
841 | } | |
842 | ||
843 | if (copy_from_user(&sjcd_msf, argp, | |
844 | sizeof(sjcd_msf))) | |
845 | return (-EFAULT); | |
846 | ||
847 | sjcd_playing.start.min = | |
848 | bin2bcd(sjcd_msf.cdmsf_min0); | |
849 | sjcd_playing.start.sec = | |
850 | bin2bcd(sjcd_msf.cdmsf_sec0); | |
851 | sjcd_playing.start.frame = | |
852 | bin2bcd(sjcd_msf.cdmsf_frame0); | |
853 | sjcd_playing.end.min = | |
854 | bin2bcd(sjcd_msf.cdmsf_min1); | |
855 | sjcd_playing.end.sec = | |
856 | bin2bcd(sjcd_msf.cdmsf_sec1); | |
857 | sjcd_playing.end.frame = | |
858 | bin2bcd(sjcd_msf.cdmsf_frame1); | |
859 | ||
860 | if (sjcd_play(&sjcd_playing) < 0) { | |
861 | sjcd_audio_status = | |
862 | CDROM_AUDIO_ERROR; | |
863 | return (-EIO); | |
864 | } else | |
865 | sjcd_audio_status = | |
866 | CDROM_AUDIO_PLAY; | |
867 | } | |
868 | return (s); | |
869 | } | |
870 | ||
871 | case CDROMREADTOCHDR:{ | |
872 | struct cdrom_tochdr toc_header; | |
873 | #if defined (SJCD_TRACE ) | |
874 | printk("SJCD: ioctl: readtocheader\n"); | |
875 | #endif | |
876 | toc_header.cdth_trk0 = sjcd_first_track_no; | |
877 | toc_header.cdth_trk1 = sjcd_last_track_no; | |
878 | if (copy_to_user(argp, &toc_header, | |
879 | sizeof(toc_header))) | |
880 | return -EFAULT; | |
881 | return 0; | |
882 | } | |
883 | ||
884 | case CDROMREADTOCENTRY:{ | |
885 | struct cdrom_tocentry toc_entry; | |
886 | int s; | |
887 | #if defined( SJCD_TRACE ) | |
888 | printk("SJCD: ioctl: readtocentry\n"); | |
889 | #endif | |
890 | if ((s = | |
891 | access_ok(VERIFY_WRITE, argp, sizeof(toc_entry)) | |
892 | ? 0 : -EFAULT) == 0) { | |
893 | struct sjcd_hw_disk_info *tp; | |
894 | ||
895 | if (copy_from_user(&toc_entry, argp, | |
896 | sizeof(toc_entry))) | |
897 | return (-EFAULT); | |
898 | if (toc_entry.cdte_track == CDROM_LEADOUT) | |
899 | tp = &sjcd_table_of_contents[0]; | |
900 | else if (toc_entry.cdte_track < | |
901 | sjcd_first_track_no) | |
902 | return (-EINVAL); | |
903 | else if (toc_entry.cdte_track > | |
904 | sjcd_last_track_no) | |
905 | return (-EINVAL); | |
906 | else | |
907 | tp = &sjcd_table_of_contents | |
908 | [toc_entry.cdte_track]; | |
909 | ||
910 | toc_entry.cdte_adr = | |
911 | tp->track_control & 0x0F; | |
912 | toc_entry.cdte_ctrl = | |
913 | tp->track_control >> 4; | |
914 | ||
915 | switch (toc_entry.cdte_format) { | |
916 | case CDROM_LBA: | |
917 | toc_entry.cdte_addr.lba = | |
918 | msf2hsg(&(tp->un.track_msf)); | |
919 | break; | |
920 | case CDROM_MSF: | |
921 | toc_entry.cdte_addr.msf.minute = | |
922 | bcd2bin(tp->un.track_msf.min); | |
923 | toc_entry.cdte_addr.msf.second = | |
924 | bcd2bin(tp->un.track_msf.sec); | |
925 | toc_entry.cdte_addr.msf.frame = | |
926 | bcd2bin(tp->un.track_msf. | |
927 | frame); | |
928 | break; | |
929 | default: | |
930 | return (-EINVAL); | |
931 | } | |
932 | if (copy_to_user(argp, &toc_entry, | |
933 | sizeof(toc_entry))) | |
934 | s = -EFAULT; | |
935 | } | |
936 | return (s); | |
937 | } | |
938 | ||
939 | case CDROMSUBCHNL:{ | |
940 | struct cdrom_subchnl subchnl; | |
941 | int s; | |
942 | #if defined( SJCD_TRACE ) | |
943 | printk("SJCD: ioctl: subchnl\n"); | |
944 | #endif | |
945 | if ((s = | |
946 | access_ok(VERIFY_WRITE, argp, sizeof(subchnl)) | |
947 | ? 0 : -EFAULT) == 0) { | |
948 | struct sjcd_hw_qinfo q_info; | |
949 | ||
950 | if (copy_from_user(&subchnl, argp, | |
951 | sizeof(subchnl))) | |
952 | return (-EFAULT); | |
953 | ||
954 | if (sjcd_get_q_info(&q_info) < 0) | |
955 | return (-EIO); | |
956 | ||
957 | subchnl.cdsc_audiostatus = | |
958 | sjcd_audio_status; | |
959 | subchnl.cdsc_adr = | |
960 | q_info.track_control & 0x0F; | |
961 | subchnl.cdsc_ctrl = | |
962 | q_info.track_control >> 4; | |
963 | subchnl.cdsc_trk = | |
964 | bcd2bin(q_info.track_no); | |
965 | subchnl.cdsc_ind = bcd2bin(q_info.x); | |
966 | ||
967 | switch (subchnl.cdsc_format) { | |
968 | case CDROM_LBA: | |
969 | subchnl.cdsc_absaddr.lba = | |
970 | msf2hsg(&(q_info.abs)); | |
971 | subchnl.cdsc_reladdr.lba = | |
972 | msf2hsg(&(q_info.rel)); | |
973 | break; | |
974 | case CDROM_MSF: | |
975 | subchnl.cdsc_absaddr.msf.minute = | |
976 | bcd2bin(q_info.abs.min); | |
977 | subchnl.cdsc_absaddr.msf.second = | |
978 | bcd2bin(q_info.abs.sec); | |
979 | subchnl.cdsc_absaddr.msf.frame = | |
980 | bcd2bin(q_info.abs.frame); | |
981 | subchnl.cdsc_reladdr.msf.minute = | |
982 | bcd2bin(q_info.rel.min); | |
983 | subchnl.cdsc_reladdr.msf.second = | |
984 | bcd2bin(q_info.rel.sec); | |
985 | subchnl.cdsc_reladdr.msf.frame = | |
986 | bcd2bin(q_info.rel.frame); | |
987 | break; | |
988 | default: | |
989 | return (-EINVAL); | |
990 | } | |
991 | if (copy_to_user(argp, &subchnl, | |
992 | sizeof(subchnl))) | |
993 | s = -EFAULT; | |
994 | } | |
995 | return (s); | |
996 | } | |
997 | ||
998 | case CDROMVOLCTRL:{ | |
999 | struct cdrom_volctrl vol_ctrl; | |
1000 | int s; | |
1001 | #if defined( SJCD_TRACE ) | |
1002 | printk("SJCD: ioctl: volctrl\n"); | |
1003 | #endif | |
1004 | if ((s = | |
1005 | access_ok(VERIFY_READ, argp, sizeof(vol_ctrl)) | |
1006 | ? 0 : -EFAULT) == 0) { | |
1007 | unsigned char dummy[4]; | |
1008 | ||
1009 | if (copy_from_user(&vol_ctrl, argp, | |
1010 | sizeof(vol_ctrl))) | |
1011 | return (-EFAULT); | |
1012 | sjcd_send_4_cmd(SCMD_SET_VOLUME, | |
1013 | vol_ctrl.channel0, 0xFF, | |
1014 | vol_ctrl.channel1, 0xFF); | |
1015 | if (sjcd_receive_status() < 0) | |
1016 | return (-EIO); | |
1017 | (void) sjcd_load_response(dummy, 4); | |
1018 | } | |
1019 | return (s); | |
1020 | } | |
1021 | ||
1022 | case CDROMEJECT:{ | |
1023 | #if defined( SJCD_TRACE ) | |
1024 | printk("SJCD: ioctl: eject\n"); | |
1025 | #endif | |
1026 | if (!sjcd_command_is_in_progress) { | |
1027 | sjcd_tray_unlock(); | |
1028 | sjcd_send_cmd(SCMD_EJECT_TRAY); | |
1029 | (void) sjcd_receive_status(); | |
1030 | } | |
1031 | return (0); | |
1032 | } | |
1033 | ||
1034 | #if defined( SJCD_GATHER_STAT ) | |
1035 | case 0xABCD:{ | |
1036 | #if defined( SJCD_TRACE ) | |
1037 | printk("SJCD: ioctl: statistic\n"); | |
1038 | #endif | |
1039 | if (copy_to_user(argp, &statistic, sizeof(statistic))) | |
1040 | return -EFAULT; | |
1041 | return 0; | |
1042 | } | |
1043 | #endif | |
1044 | ||
1045 | default: | |
1046 | return (-EINVAL); | |
1047 | } | |
1048 | } | |
1049 | ||
1050 | /* | |
1051 | * Invalidate internal buffers of the driver. | |
1052 | */ | |
1053 | static void sjcd_invalidate_buffers(void) | |
1054 | { | |
1055 | int i; | |
1056 | for (i = 0; i < SJCD_BUF_SIZ; sjcd_buf_bn[i++] = -1); | |
1057 | sjcd_buf_out = -1; | |
1058 | } | |
1059 | ||
1060 | /* | |
1061 | * Take care of the different block sizes between cdrom and Linux. | |
1062 | * When Linux gets variable block sizes this will probably go away. | |
1063 | */ | |
1064 | ||
1065 | static int current_valid(void) | |
1066 | { | |
1067 | return CURRENT && | |
1068 | CURRENT->cmd == READ && | |
1069 | CURRENT->sector != -1; | |
1070 | } | |
1071 | ||
1072 | static void sjcd_transfer(void) | |
1073 | { | |
1074 | #if defined( SJCD_TRACE ) | |
1075 | printk("SJCD: transfer:\n"); | |
1076 | #endif | |
1077 | if (current_valid()) { | |
1078 | while (CURRENT->nr_sectors) { | |
1079 | int i, bn = CURRENT->sector / 4; | |
1080 | for (i = 0; | |
1081 | i < SJCD_BUF_SIZ && sjcd_buf_bn[i] != bn; | |
1082 | i++); | |
1083 | if (i < SJCD_BUF_SIZ) { | |
1084 | int offs = | |
1085 | (i * 4 + (CURRENT->sector & 3)) * 512; | |
1086 | int nr_sectors = 4 - (CURRENT->sector & 3); | |
1087 | if (sjcd_buf_out != i) { | |
1088 | sjcd_buf_out = i; | |
1089 | if (sjcd_buf_bn[i] != bn) { | |
1090 | sjcd_buf_out = -1; | |
1091 | continue; | |
1092 | } | |
1093 | } | |
1094 | if (nr_sectors > CURRENT->nr_sectors) | |
1095 | nr_sectors = CURRENT->nr_sectors; | |
1096 | #if defined( SJCD_TRACE ) | |
1097 | printk("SJCD: copy out\n"); | |
1098 | #endif | |
1099 | memcpy(CURRENT->buffer, sjcd_buf + offs, | |
1100 | nr_sectors * 512); | |
1101 | CURRENT->nr_sectors -= nr_sectors; | |
1102 | CURRENT->sector += nr_sectors; | |
1103 | CURRENT->buffer += nr_sectors * 512; | |
1104 | } else { | |
1105 | sjcd_buf_out = -1; | |
1106 | break; | |
1107 | } | |
1108 | } | |
1109 | } | |
1110 | #if defined( SJCD_TRACE ) | |
1111 | printk("SJCD: transfer: done\n"); | |
1112 | #endif | |
1113 | } | |
1114 | ||
1115 | static void sjcd_poll(void) | |
1116 | { | |
1117 | #if defined( SJCD_GATHER_STAT ) | |
1118 | /* | |
1119 | * Update total number of ticks. | |
1120 | */ | |
1121 | statistic.ticks++; | |
1122 | statistic.tticks[sjcd_transfer_state]++; | |
1123 | #endif | |
1124 | ||
1125 | ReSwitch:switch (sjcd_transfer_state) { | |
1126 | ||
1127 | case SJCD_S_IDLE:{ | |
1128 | #if defined( SJCD_GATHER_STAT ) | |
1129 | statistic.idle_ticks++; | |
1130 | #endif | |
1131 | #if defined( SJCD_TRACE ) | |
1132 | printk("SJCD_S_IDLE\n"); | |
1133 | #endif | |
1134 | return; | |
1135 | } | |
1136 | ||
1137 | case SJCD_S_START:{ | |
1138 | #if defined( SJCD_GATHER_STAT ) | |
1139 | statistic.start_ticks++; | |
1140 | #endif | |
1141 | sjcd_send_cmd(SCMD_GET_STATUS); | |
1142 | sjcd_transfer_state = | |
1143 | sjcd_mode == | |
1144 | SCMD_MODE_COOKED ? SJCD_S_READ : SJCD_S_MODE; | |
1145 | sjcd_transfer_timeout = 500; | |
1146 | #if defined( SJCD_TRACE ) | |
1147 | printk("SJCD_S_START: goto SJCD_S_%s mode\n", | |
1148 | sjcd_transfer_state == | |
1149 | SJCD_S_READ ? "READ" : "MODE"); | |
1150 | #endif | |
1151 | break; | |
1152 | } | |
1153 | ||
1154 | case SJCD_S_MODE:{ | |
1155 | if (sjcd_check_status()) { | |
1156 | /* | |
1157 | * Previous command is completed. | |
1158 | */ | |
1159 | if (!sjcd_status_valid | |
1160 | || sjcd_command_failed) { | |
1161 | #if defined( SJCD_TRACE ) | |
1162 | printk | |
1163 | ("SJCD_S_MODE: pre-cmd failed: goto to SJCD_S_STOP mode\n"); | |
1164 | #endif | |
1165 | sjcd_transfer_state = SJCD_S_STOP; | |
1166 | goto ReSwitch; | |
1167 | } | |
1168 | ||
1169 | sjcd_mode = 0; /* unknown mode; should not be valid when failed */ | |
1170 | sjcd_send_1_cmd(SCMD_SET_MODE, | |
1171 | SCMD_MODE_COOKED); | |
1172 | sjcd_transfer_state = SJCD_S_READ; | |
1173 | sjcd_transfer_timeout = 1000; | |
1174 | #if defined( SJCD_TRACE ) | |
1175 | printk | |
1176 | ("SJCD_S_MODE: goto SJCD_S_READ mode\n"); | |
1177 | #endif | |
1178 | } | |
1179 | #if defined( SJCD_GATHER_STAT ) | |
1180 | else | |
1181 | statistic.mode_ticks++; | |
1182 | #endif | |
1183 | break; | |
1184 | } | |
1185 | ||
1186 | case SJCD_S_READ:{ | |
1187 | if (sjcd_status_valid ? 1 : sjcd_check_status()) { | |
1188 | /* | |
1189 | * Previous command is completed. | |
1190 | */ | |
1191 | if (!sjcd_status_valid | |
1192 | || sjcd_command_failed) { | |
1193 | #if defined( SJCD_TRACE ) | |
1194 | printk | |
1195 | ("SJCD_S_READ: pre-cmd failed: goto to SJCD_S_STOP mode\n"); | |
1196 | #endif | |
1197 | sjcd_transfer_state = SJCD_S_STOP; | |
1198 | goto ReSwitch; | |
1199 | } | |
1200 | if (!sjcd_media_is_available) { | |
1201 | #if defined( SJCD_TRACE ) | |
1202 | printk | |
1203 | ("SJCD_S_READ: no disk: goto to SJCD_S_STOP mode\n"); | |
1204 | #endif | |
1205 | sjcd_transfer_state = SJCD_S_STOP; | |
1206 | goto ReSwitch; | |
1207 | } | |
1208 | if (sjcd_mode != SCMD_MODE_COOKED) { | |
1209 | /* | |
1210 | * We seem to come from set mode. So discard one byte of result. | |
1211 | */ | |
1212 | if (sjcd_load_response | |
1213 | (&sjcd_mode, 1) != 0) { | |
1214 | #if defined( SJCD_TRACE ) | |
1215 | printk | |
1216 | ("SJCD_S_READ: load failed: goto to SJCD_S_STOP mode\n"); | |
1217 | #endif | |
1218 | sjcd_transfer_state = | |
1219 | SJCD_S_STOP; | |
1220 | goto ReSwitch; | |
1221 | } | |
1222 | if (sjcd_mode != SCMD_MODE_COOKED) { | |
1223 | #if defined( SJCD_TRACE ) | |
1224 | printk | |
1225 | ("SJCD_S_READ: mode failed: goto to SJCD_S_STOP mode\n"); | |
1226 | #endif | |
1227 | sjcd_transfer_state = | |
1228 | SJCD_S_STOP; | |
1229 | goto ReSwitch; | |
1230 | } | |
1231 | } | |
1232 | ||
1233 | if (current_valid()) { | |
1234 | struct sjcd_play_msf msf; | |
1235 | ||
1236 | sjcd_next_bn = CURRENT->sector / 4; | |
1237 | hsg2msf(sjcd_next_bn, &msf.start); | |
1238 | msf.end.min = 0; | |
1239 | msf.end.sec = 0; | |
1240 | msf.end.frame = sjcd_read_count = | |
1241 | SJCD_BUF_SIZ; | |
1242 | #if defined( SJCD_TRACE ) | |
1243 | printk | |
1244 | ("SJCD: ---reading msf-address %x:%x:%x %x:%x:%x\n", | |
1245 | msf.start.min, msf.start.sec, | |
1246 | msf.start.frame, msf.end.min, | |
1247 | msf.end.sec, msf.end.frame); | |
1248 | printk | |
1249 | ("sjcd_next_bn:%x buf_in:%x buf_out:%x buf_bn:%x\n", | |
1250 | sjcd_next_bn, sjcd_buf_in, | |
1251 | sjcd_buf_out, | |
1252 | sjcd_buf_bn[sjcd_buf_in]); | |
1253 | #endif | |
1254 | sjcd_send_6_cmd(SCMD_DATA_READ, | |
1255 | &msf); | |
1256 | sjcd_transfer_state = SJCD_S_DATA; | |
1257 | sjcd_transfer_timeout = 500; | |
1258 | #if defined( SJCD_TRACE ) | |
1259 | printk | |
1260 | ("SJCD_S_READ: go to SJCD_S_DATA mode\n"); | |
1261 | #endif | |
1262 | } else { | |
1263 | #if defined( SJCD_TRACE ) | |
1264 | printk | |
1265 | ("SJCD_S_READ: nothing to read: go to SJCD_S_STOP mode\n"); | |
1266 | #endif | |
1267 | sjcd_transfer_state = SJCD_S_STOP; | |
1268 | goto ReSwitch; | |
1269 | } | |
1270 | } | |
1271 | #if defined( SJCD_GATHER_STAT ) | |
1272 | else | |
1273 | statistic.read_ticks++; | |
1274 | #endif | |
1275 | break; | |
1276 | } | |
1277 | ||
1278 | case SJCD_S_DATA:{ | |
1279 | unsigned char stat; | |
1280 | ||
1281 | sjcd_s_data:stat = | |
1282 | inb(SJCDPORT | |
1283 | (1)); | |
1284 | #if defined( SJCD_TRACE ) | |
1285 | printk("SJCD_S_DATA: status = 0x%02x\n", stat); | |
1286 | #endif | |
1287 | if (SJCD_STATUS_AVAILABLE(stat)) { | |
1288 | /* | |
1289 | * No data is waiting for us in the drive buffer. Status of operation | |
1290 | * completion is available. Read and parse it. | |
1291 | */ | |
1292 | sjcd_load_status(); | |
1293 | ||
1294 | if (!sjcd_status_valid | |
1295 | || sjcd_command_failed) { | |
1296 | #if defined( SJCD_TRACE ) | |
1297 | printk | |
1298 | ("SJCD: read block %d failed, maybe audio disk? Giving up\n", | |
1299 | sjcd_next_bn); | |
1300 | #endif | |
1301 | if (current_valid()) | |
1302 | end_request(CURRENT, 0); | |
1303 | #if defined( SJCD_TRACE ) | |
1304 | printk | |
1305 | ("SJCD_S_DATA: pre-cmd failed: go to SJCD_S_STOP mode\n"); | |
1306 | #endif | |
1307 | sjcd_transfer_state = SJCD_S_STOP; | |
1308 | goto ReSwitch; | |
1309 | } | |
1310 | ||
1311 | if (!sjcd_media_is_available) { | |
1312 | printk | |
1313 | ("SJCD_S_DATA: no disk: go to SJCD_S_STOP mode\n"); | |
1314 | sjcd_transfer_state = SJCD_S_STOP; | |
1315 | goto ReSwitch; | |
1316 | } | |
1317 | ||
1318 | sjcd_transfer_state = SJCD_S_READ; | |
1319 | goto ReSwitch; | |
1320 | } else if (SJCD_DATA_AVAILABLE(stat)) { | |
1321 | /* | |
1322 | * One frame is read into device buffer. We must copy it to our memory. | |
1323 | * Otherwise cdrom hangs up. Check to see if we have something to copy | |
1324 | * to. | |
1325 | */ | |
1326 | if (!current_valid() | |
1327 | && sjcd_buf_in == sjcd_buf_out) { | |
1328 | #if defined( SJCD_TRACE ) | |
1329 | printk | |
1330 | ("SJCD_S_DATA: nothing to read: go to SJCD_S_STOP mode\n"); | |
1331 | printk | |
1332 | (" ... all the date would be discarded\n"); | |
1333 | #endif | |
1334 | sjcd_transfer_state = SJCD_S_STOP; | |
1335 | goto ReSwitch; | |
1336 | } | |
1337 | ||
1338 | /* | |
1339 | * Everything seems to be OK. Just read the frame and recalculate | |
1340 | * indices. | |
1341 | */ | |
1342 | sjcd_buf_bn[sjcd_buf_in] = -1; /* ??? */ | |
1343 | insb(SJCDPORT(2), | |
1344 | sjcd_buf + 2048 * sjcd_buf_in, 2048); | |
1345 | #if defined( SJCD_TRACE ) | |
1346 | printk | |
1347 | ("SJCD_S_DATA: next_bn=%d, buf_in=%d, buf_out=%d, buf_bn=%d\n", | |
1348 | sjcd_next_bn, sjcd_buf_in, | |
1349 | sjcd_buf_out, | |
1350 | sjcd_buf_bn[sjcd_buf_in]); | |
1351 | #endif | |
1352 | sjcd_buf_bn[sjcd_buf_in] = sjcd_next_bn++; | |
1353 | if (sjcd_buf_out == -1) | |
1354 | sjcd_buf_out = sjcd_buf_in; | |
1355 | if (++sjcd_buf_in == SJCD_BUF_SIZ) | |
1356 | sjcd_buf_in = 0; | |
1357 | ||
1358 | /* | |
1359 | * Only one frame is ready at time. So we should turn over to wait for | |
1360 | * another frame. If we need that, of course. | |
1361 | */ | |
1362 | if (--sjcd_read_count == 0) { | |
1363 | /* | |
1364 | * OK, request seems to be precessed. Continue transferring... | |
1365 | */ | |
1366 | if (!sjcd_transfer_is_active) { | |
1367 | while (current_valid()) { | |
1368 | /* | |
1369 | * Continue transferring. | |
1370 | */ | |
1371 | sjcd_transfer(); | |
1372 | if (CURRENT-> | |
1373 | nr_sectors == | |
1374 | 0) | |
1375 | end_request | |
1376 | (CURRENT, 1); | |
1377 | else | |
1378 | break; | |
1379 | } | |
1380 | } | |
1381 | if (current_valid() && | |
1382 | (CURRENT->sector / 4 < | |
1383 | sjcd_next_bn | |
1384 | || CURRENT->sector / 4 > | |
1385 | sjcd_next_bn + | |
1386 | SJCD_BUF_SIZ)) { | |
1387 | #if defined( SJCD_TRACE ) | |
1388 | printk | |
1389 | ("SJCD_S_DATA: can't read: go to SJCD_S_STOP mode\n"); | |
1390 | #endif | |
1391 | sjcd_transfer_state = | |
1392 | SJCD_S_STOP; | |
1393 | goto ReSwitch; | |
1394 | } | |
1395 | } | |
1396 | /* | |
1397 | * Now we should turn around rather than wait for while. | |
1398 | */ | |
1399 | goto sjcd_s_data; | |
1400 | } | |
1401 | #if defined( SJCD_GATHER_STAT ) | |
1402 | else | |
1403 | statistic.data_ticks++; | |
1404 | #endif | |
1405 | break; | |
1406 | } | |
1407 | ||
1408 | case SJCD_S_STOP:{ | |
1409 | sjcd_read_count = 0; | |
1410 | sjcd_send_cmd(SCMD_STOP); | |
1411 | sjcd_transfer_state = SJCD_S_STOPPING; | |
1412 | sjcd_transfer_timeout = 500; | |
1413 | #if defined( SJCD_GATHER_STAT ) | |
1414 | statistic.stop_ticks++; | |
1415 | #endif | |
1416 | break; | |
1417 | } | |
1418 | ||
1419 | case SJCD_S_STOPPING:{ | |
1420 | unsigned char stat; | |
1421 | ||
1422 | stat = inb(SJCDPORT(1)); | |
1423 | #if defined( SJCD_TRACE ) | |
1424 | printk("SJCD_S_STOP: status = 0x%02x\n", stat); | |
1425 | #endif | |
1426 | if (SJCD_DATA_AVAILABLE(stat)) { | |
1427 | int i; | |
1428 | #if defined( SJCD_TRACE ) | |
1429 | printk("SJCD_S_STOP: discard data\n"); | |
1430 | #endif | |
1431 | /* | |
1432 | * Discard all the data from the pipe. Foolish method. | |
1433 | */ | |
1434 | for (i = 2048; i--; | |
1435 | (void) inb(SJCDPORT(2))); | |
1436 | sjcd_transfer_timeout = 500; | |
1437 | } else if (SJCD_STATUS_AVAILABLE(stat)) { | |
1438 | sjcd_load_status(); | |
1439 | if (sjcd_status_valid | |
1440 | && sjcd_media_is_changed) { | |
1441 | sjcd_toc_uptodate = 0; | |
1442 | sjcd_invalidate_buffers(); | |
1443 | } | |
1444 | if (current_valid()) { | |
1445 | if (sjcd_status_valid) | |
1446 | sjcd_transfer_state = | |
1447 | SJCD_S_READ; | |
1448 | else | |
1449 | sjcd_transfer_state = | |
1450 | SJCD_S_START; | |
1451 | } else | |
1452 | sjcd_transfer_state = SJCD_S_IDLE; | |
1453 | goto ReSwitch; | |
1454 | } | |
1455 | #if defined( SJCD_GATHER_STAT ) | |
1456 | else | |
1457 | statistic.stopping_ticks++; | |
1458 | #endif | |
1459 | break; | |
1460 | } | |
1461 | ||
1462 | default: | |
1463 | printk("SJCD: poll: invalid state %d\n", | |
1464 | sjcd_transfer_state); | |
1465 | return; | |
1466 | } | |
1467 | ||
1468 | if (--sjcd_transfer_timeout == 0) { | |
1469 | printk("SJCD: timeout in state %d\n", sjcd_transfer_state); | |
1470 | while (current_valid()) | |
1471 | end_request(CURRENT, 0); | |
1472 | sjcd_send_cmd(SCMD_STOP); | |
1473 | sjcd_transfer_state = SJCD_S_IDLE; | |
1474 | goto ReSwitch; | |
1475 | } | |
1476 | ||
1477 | /* | |
1478 | * Get back in some time. 1 should be replaced with count variable to | |
1479 | * avoid unnecessary testings. | |
1480 | */ | |
1481 | SJCD_SET_TIMER(sjcd_poll, 1); | |
1482 | } | |
1483 | ||
1484 | static void do_sjcd_request(request_queue_t * q) | |
1485 | { | |
1486 | #if defined( SJCD_TRACE ) | |
1487 | printk("SJCD: do_sjcd_request(%ld+%ld)\n", | |
1488 | CURRENT->sector, CURRENT->nr_sectors); | |
1489 | #endif | |
1490 | sjcd_transfer_is_active = 1; | |
1491 | while (current_valid()) { | |
1492 | sjcd_transfer(); | |
1493 | if (CURRENT->nr_sectors == 0) | |
1494 | end_request(CURRENT, 1); | |
1495 | else { | |
1496 | sjcd_buf_out = -1; /* Want to read a block not in buffer */ | |
1497 | if (sjcd_transfer_state == SJCD_S_IDLE) { | |
1498 | if (!sjcd_toc_uptodate) { | |
1499 | if (sjcd_update_toc() < 0) { | |
1500 | printk | |
1501 | ("SJCD: transfer: discard\n"); | |
1502 | while (current_valid()) | |
1503 | end_request(CURRENT, 0); | |
1504 | break; | |
1505 | } | |
1506 | } | |
1507 | sjcd_transfer_state = SJCD_S_START; | |
1508 | SJCD_SET_TIMER(sjcd_poll, HZ / 100); | |
1509 | } | |
1510 | break; | |
1511 | } | |
1512 | } | |
1513 | sjcd_transfer_is_active = 0; | |
1514 | #if defined( SJCD_TRACE ) | |
1515 | printk | |
1516 | ("sjcd_next_bn:%x sjcd_buf_in:%x sjcd_buf_out:%x sjcd_buf_bn:%x\n", | |
1517 | sjcd_next_bn, sjcd_buf_in, sjcd_buf_out, | |
1518 | sjcd_buf_bn[sjcd_buf_in]); | |
1519 | printk("do_sjcd_request ends\n"); | |
1520 | #endif | |
1521 | } | |
1522 | ||
1523 | /* | |
1524 | * Open the device special file. Check disk is in. | |
1525 | */ | |
1526 | static int sjcd_open(struct inode *ip, struct file *fp) | |
1527 | { | |
1528 | /* | |
1529 | * Check the presence of device. | |
1530 | */ | |
1531 | if (!sjcd_present) | |
1532 | return (-ENXIO); | |
1533 | ||
1534 | /* | |
1535 | * Only read operations are allowed. Really? (:-) | |
1536 | */ | |
1537 | if (fp->f_mode & 2) | |
1538 | return (-EROFS); | |
1539 | ||
1540 | if (sjcd_open_count == 0) { | |
1541 | int s, sjcd_open_tries; | |
1542 | /* We don't know that, do we? */ | |
1543 | /* | |
1544 | sjcd_audio_status = CDROM_AUDIO_NO_STATUS; | |
1545 | */ | |
1546 | sjcd_mode = 0; | |
1547 | sjcd_door_was_open = 0; | |
1548 | sjcd_transfer_state = SJCD_S_IDLE; | |
1549 | sjcd_invalidate_buffers(); | |
1550 | sjcd_status_valid = 0; | |
1551 | ||
1552 | /* | |
1553 | * Strict status checking. | |
1554 | */ | |
1555 | for (sjcd_open_tries = 4; --sjcd_open_tries;) { | |
1556 | if (!sjcd_status_valid) | |
1557 | sjcd_get_status(); | |
1558 | if (!sjcd_status_valid) { | |
1559 | #if defined( SJCD_DIAGNOSTIC ) | |
1560 | printk | |
1561 | ("SJCD: open: timed out when check status.\n"); | |
1562 | #endif | |
1563 | goto err_out; | |
1564 | } else if (!sjcd_media_is_available) { | |
1565 | #if defined( SJCD_DIAGNOSTIC ) | |
1566 | printk("SJCD: open: no disk in drive\n"); | |
1567 | #endif | |
1568 | if (!sjcd_door_closed) { | |
1569 | sjcd_door_was_open = 1; | |
1570 | #if defined( SJCD_TRACE ) | |
1571 | printk | |
1572 | ("SJCD: open: close the tray\n"); | |
1573 | #endif | |
1574 | s = sjcd_tray_close(); | |
1575 | if (s < 0 || !sjcd_status_valid | |
1576 | || sjcd_command_failed) { | |
1577 | #if defined( SJCD_DIAGNOSTIC ) | |
1578 | printk | |
1579 | ("SJCD: open: tray close attempt failed\n"); | |
1580 | #endif | |
1581 | goto err_out; | |
1582 | } | |
1583 | continue; | |
1584 | } else | |
1585 | goto err_out; | |
1586 | } | |
1587 | break; | |
1588 | } | |
1589 | s = sjcd_tray_lock(); | |
1590 | if (s < 0 || !sjcd_status_valid || sjcd_command_failed) { | |
1591 | #if defined( SJCD_DIAGNOSTIC ) | |
1592 | printk("SJCD: open: tray lock attempt failed\n"); | |
1593 | #endif | |
1594 | goto err_out; | |
1595 | } | |
1596 | #if defined( SJCD_TRACE ) | |
1597 | printk("SJCD: open: done\n"); | |
1598 | #endif | |
1599 | } | |
1600 | ||
1601 | ++sjcd_open_count; | |
1602 | return (0); | |
1603 | ||
1604 | err_out: | |
1605 | return (-EIO); | |
1606 | } | |
1607 | ||
1608 | /* | |
1609 | * On close, we flush all sjcd blocks from the buffer cache. | |
1610 | */ | |
1611 | static int sjcd_release(struct inode *inode, struct file *file) | |
1612 | { | |
1613 | int s; | |
1614 | ||
1615 | #if defined( SJCD_TRACE ) | |
1616 | printk("SJCD: release\n"); | |
1617 | #endif | |
1618 | if (--sjcd_open_count == 0) { | |
1619 | sjcd_invalidate_buffers(); | |
1620 | s = sjcd_tray_unlock(); | |
1621 | if (s < 0 || !sjcd_status_valid || sjcd_command_failed) { | |
1622 | #if defined( SJCD_DIAGNOSTIC ) | |
1623 | printk | |
1624 | ("SJCD: release: tray unlock attempt failed.\n"); | |
1625 | #endif | |
1626 | } | |
1627 | if (sjcd_door_was_open) { | |
1628 | s = sjcd_tray_open(); | |
1629 | if (s < 0 || !sjcd_status_valid | |
1630 | || sjcd_command_failed) { | |
1631 | #if defined( SJCD_DIAGNOSTIC ) | |
1632 | printk | |
1633 | ("SJCD: release: tray unload attempt failed.\n"); | |
1634 | #endif | |
1635 | } | |
1636 | } | |
1637 | } | |
1638 | return 0; | |
1639 | } | |
1640 | ||
1641 | /* | |
1642 | * A list of file operations allowed for this cdrom. | |
1643 | */ | |
1644 | static struct block_device_operations sjcd_fops = { | |
1645 | .owner = THIS_MODULE, | |
1646 | .open = sjcd_open, | |
1647 | .release = sjcd_release, | |
1648 | .ioctl = sjcd_ioctl, | |
1649 | .media_changed = sjcd_disk_change, | |
1650 | }; | |
1651 | ||
1652 | /* | |
1653 | * Following stuff is intended for initialization of the cdrom. It | |
1654 | * first looks for presence of device. If the device is present, it | |
1655 | * will be reset. Then read the version of the drive and load status. | |
1656 | * The version is two BCD-coded bytes. | |
1657 | */ | |
1658 | static struct { | |
1659 | unsigned char major, minor; | |
1660 | } sjcd_version; | |
1661 | ||
1662 | static struct gendisk *sjcd_disk; | |
1663 | ||
1664 | /* | |
1665 | * Test for presence of drive and initialize it. Called at boot time. | |
1666 | * Probe cdrom, find out version and status. | |
1667 | */ | |
1668 | static int __init sjcd_init(void) | |
1669 | { | |
1670 | int i; | |
1671 | ||
1672 | printk(KERN_INFO | |
1673 | "SJCD: Sanyo CDR-H94A cdrom driver version %d.%d.\n", | |
1674 | SJCD_VERSION_MAJOR, SJCD_VERSION_MINOR); | |
1675 | ||
1676 | #if defined( SJCD_TRACE ) | |
1677 | printk("SJCD: sjcd=0x%x: ", sjcd_base); | |
1678 | #endif | |
1679 | ||
1680 | if (register_blkdev(MAJOR_NR, "sjcd")) | |
1681 | return -EIO; | |
1682 | ||
1683 | sjcd_queue = blk_init_queue(do_sjcd_request, &sjcd_lock); | |
1684 | if (!sjcd_queue) | |
1685 | goto out0; | |
1686 | ||
1687 | blk_queue_hardsect_size(sjcd_queue, 2048); | |
1688 | ||
1689 | sjcd_disk = alloc_disk(1); | |
1690 | if (!sjcd_disk) { | |
1691 | printk(KERN_ERR "SJCD: can't allocate disk"); | |
1692 | goto out1; | |
1693 | } | |
1694 | sjcd_disk->major = MAJOR_NR, | |
1695 | sjcd_disk->first_minor = 0, | |
1696 | sjcd_disk->fops = &sjcd_fops, | |
1697 | sprintf(sjcd_disk->disk_name, "sjcd"); | |
1da177e4 LT |
1698 | |
1699 | if (!request_region(sjcd_base, 4,"sjcd")) { | |
1700 | printk | |
1701 | ("SJCD: Init failed, I/O port (%X) is already in use\n", | |
1702 | sjcd_base); | |
1703 | goto out2; | |
1704 | } | |
1705 | ||
1706 | /* | |
1707 | * Check for card. Since we are booting now, we can't use standard | |
1708 | * wait algorithm. | |
1709 | */ | |
1710 | printk(KERN_INFO "SJCD: Resetting: "); | |
1711 | sjcd_send_cmd(SCMD_RESET); | |
1712 | for (i = 1000; i > 0 && !sjcd_status_valid; --i) { | |
1713 | unsigned long timer; | |
1714 | ||
1715 | /* | |
1716 | * Wait 10ms approx. | |
1717 | */ | |
1718 | for (timer = jiffies; time_before_eq(jiffies, timer);); | |
1719 | if ((i % 100) == 0) | |
1720 | printk("."); | |
1721 | (void) sjcd_check_status(); | |
1722 | } | |
1723 | if (i == 0 || sjcd_command_failed) { | |
1724 | printk(" reset failed, no drive found.\n"); | |
1725 | goto out3; | |
1726 | } else | |
1727 | printk("\n"); | |
1728 | ||
1729 | /* | |
1730 | * Get and print out cdrom version. | |
1731 | */ | |
1732 | printk(KERN_INFO "SJCD: Getting version: "); | |
1733 | sjcd_send_cmd(SCMD_GET_VERSION); | |
1734 | for (i = 1000; i > 0 && !sjcd_status_valid; --i) { | |
1735 | unsigned long timer; | |
1736 | ||
1737 | /* | |
1738 | * Wait 10ms approx. | |
1739 | */ | |
1740 | for (timer = jiffies; time_before_eq(jiffies, timer);); | |
1741 | if ((i % 100) == 0) | |
1742 | printk("."); | |
1743 | (void) sjcd_check_status(); | |
1744 | } | |
1745 | if (i == 0 || sjcd_command_failed) { | |
1746 | printk(" get version failed, no drive found.\n"); | |
1747 | goto out3; | |
1748 | } | |
1749 | ||
1750 | if (sjcd_load_response(&sjcd_version, sizeof(sjcd_version)) == 0) { | |
1751 | printk(" %1x.%02x\n", (int) sjcd_version.major, | |
1752 | (int) sjcd_version.minor); | |
1753 | } else { | |
1754 | printk(" read version failed, no drive found.\n"); | |
1755 | goto out3; | |
1756 | } | |
1757 | ||
1758 | /* | |
1759 | * Check and print out the tray state. (if it is needed?). | |
1760 | */ | |
1761 | if (!sjcd_status_valid) { | |
1762 | printk(KERN_INFO "SJCD: Getting status: "); | |
1763 | sjcd_send_cmd(SCMD_GET_STATUS); | |
1764 | for (i = 1000; i > 0 && !sjcd_status_valid; --i) { | |
1765 | unsigned long timer; | |
1766 | ||
1767 | /* | |
1768 | * Wait 10ms approx. | |
1769 | */ | |
1770 | for (timer = jiffies; | |
1771 | time_before_eq(jiffies, timer);); | |
1772 | if ((i % 100) == 0) | |
1773 | printk("."); | |
1774 | (void) sjcd_check_status(); | |
1775 | } | |
1776 | if (i == 0 || sjcd_command_failed) { | |
1777 | printk(" get status failed, no drive found.\n"); | |
1778 | goto out3; | |
1779 | } else | |
1780 | printk("\n"); | |
1781 | } | |
1782 | ||
1783 | printk(KERN_INFO "SJCD: Status: port=0x%x.\n", sjcd_base); | |
1784 | sjcd_disk->queue = sjcd_queue; | |
1785 | add_disk(sjcd_disk); | |
1786 | ||
1787 | sjcd_present++; | |
1788 | return (0); | |
1789 | out3: | |
1790 | release_region(sjcd_base, 4); | |
1791 | out2: | |
1792 | put_disk(sjcd_disk); | |
1793 | out1: | |
1794 | blk_cleanup_queue(sjcd_queue); | |
1795 | out0: | |
1796 | if ((unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL)) | |
1797 | printk("SJCD: cannot unregister device.\n"); | |
1798 | return (-EIO); | |
1799 | } | |
1800 | ||
1801 | static void __exit sjcd_exit(void) | |
1802 | { | |
1803 | del_gendisk(sjcd_disk); | |
1804 | put_disk(sjcd_disk); | |
1805 | release_region(sjcd_base, 4); | |
1806 | blk_cleanup_queue(sjcd_queue); | |
1807 | if ((unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL)) | |
1808 | printk("SJCD: cannot unregister device.\n"); | |
1809 | printk(KERN_INFO "SJCD: module: removed.\n"); | |
1810 | } | |
1811 | ||
1812 | module_init(sjcd_init); | |
1813 | module_exit(sjcd_exit); | |
1814 | ||
1815 | MODULE_LICENSE("GPL"); | |
1816 | MODULE_ALIAS_BLOCKDEV_MAJOR(SANYO_CDROM_MAJOR); |