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