diff options
Diffstat (limited to 'drivers/cdrom/sjcd.c')
-rw-r--r-- | drivers/cdrom/sjcd.c | 1817 |
1 files changed, 1817 insertions, 0 deletions
diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c new file mode 100644 index 000000000000..4e7a342ec36f --- /dev/null +++ b/drivers/cdrom/sjcd.c | |||
@@ -0,0 +1,1817 @@ | |||
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 | */ | ||
154 | static struct timer_list sjcd_delay_timer = TIMER_INITIALIZER(NULL, 0, 0); | ||
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"); | ||
1698 | sprintf(sjcd_disk->devfs_name, "sjcd"); | ||
1699 | |||
1700 | if (!request_region(sjcd_base, 4,"sjcd")) { | ||
1701 | printk | ||
1702 | ("SJCD: Init failed, I/O port (%X) is already in use\n", | ||
1703 | sjcd_base); | ||
1704 | goto out2; | ||
1705 | } | ||
1706 | |||
1707 | /* | ||
1708 | * Check for card. Since we are booting now, we can't use standard | ||
1709 | * wait algorithm. | ||
1710 | */ | ||
1711 | printk(KERN_INFO "SJCD: Resetting: "); | ||
1712 | sjcd_send_cmd(SCMD_RESET); | ||
1713 | for (i = 1000; i > 0 && !sjcd_status_valid; --i) { | ||
1714 | unsigned long timer; | ||
1715 | |||
1716 | /* | ||
1717 | * Wait 10ms approx. | ||
1718 | */ | ||
1719 | for (timer = jiffies; time_before_eq(jiffies, timer);); | ||
1720 | if ((i % 100) == 0) | ||
1721 | printk("."); | ||
1722 | (void) sjcd_check_status(); | ||
1723 | } | ||
1724 | if (i == 0 || sjcd_command_failed) { | ||
1725 | printk(" reset failed, no drive found.\n"); | ||
1726 | goto out3; | ||
1727 | } else | ||
1728 | printk("\n"); | ||
1729 | |||
1730 | /* | ||
1731 | * Get and print out cdrom version. | ||
1732 | */ | ||
1733 | printk(KERN_INFO "SJCD: Getting version: "); | ||
1734 | sjcd_send_cmd(SCMD_GET_VERSION); | ||
1735 | for (i = 1000; i > 0 && !sjcd_status_valid; --i) { | ||
1736 | unsigned long timer; | ||
1737 | |||
1738 | /* | ||
1739 | * Wait 10ms approx. | ||
1740 | */ | ||
1741 | for (timer = jiffies; time_before_eq(jiffies, timer);); | ||
1742 | if ((i % 100) == 0) | ||
1743 | printk("."); | ||
1744 | (void) sjcd_check_status(); | ||
1745 | } | ||
1746 | if (i == 0 || sjcd_command_failed) { | ||
1747 | printk(" get version failed, no drive found.\n"); | ||
1748 | goto out3; | ||
1749 | } | ||
1750 | |||
1751 | if (sjcd_load_response(&sjcd_version, sizeof(sjcd_version)) == 0) { | ||
1752 | printk(" %1x.%02x\n", (int) sjcd_version.major, | ||
1753 | (int) sjcd_version.minor); | ||
1754 | } else { | ||
1755 | printk(" read version failed, no drive found.\n"); | ||
1756 | goto out3; | ||
1757 | } | ||
1758 | |||
1759 | /* | ||
1760 | * Check and print out the tray state. (if it is needed?). | ||
1761 | */ | ||
1762 | if (!sjcd_status_valid) { | ||
1763 | printk(KERN_INFO "SJCD: Getting status: "); | ||
1764 | sjcd_send_cmd(SCMD_GET_STATUS); | ||
1765 | for (i = 1000; i > 0 && !sjcd_status_valid; --i) { | ||
1766 | unsigned long timer; | ||
1767 | |||
1768 | /* | ||
1769 | * Wait 10ms approx. | ||
1770 | */ | ||
1771 | for (timer = jiffies; | ||
1772 | time_before_eq(jiffies, timer);); | ||
1773 | if ((i % 100) == 0) | ||
1774 | printk("."); | ||
1775 | (void) sjcd_check_status(); | ||
1776 | } | ||
1777 | if (i == 0 || sjcd_command_failed) { | ||
1778 | printk(" get status failed, no drive found.\n"); | ||
1779 | goto out3; | ||
1780 | } else | ||
1781 | printk("\n"); | ||
1782 | } | ||
1783 | |||
1784 | printk(KERN_INFO "SJCD: Status: port=0x%x.\n", sjcd_base); | ||
1785 | sjcd_disk->queue = sjcd_queue; | ||
1786 | add_disk(sjcd_disk); | ||
1787 | |||
1788 | sjcd_present++; | ||
1789 | return (0); | ||
1790 | out3: | ||
1791 | release_region(sjcd_base, 4); | ||
1792 | out2: | ||
1793 | put_disk(sjcd_disk); | ||
1794 | out1: | ||
1795 | blk_cleanup_queue(sjcd_queue); | ||
1796 | out0: | ||
1797 | if ((unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL)) | ||
1798 | printk("SJCD: cannot unregister device.\n"); | ||
1799 | return (-EIO); | ||
1800 | } | ||
1801 | |||
1802 | static void __exit sjcd_exit(void) | ||
1803 | { | ||
1804 | del_gendisk(sjcd_disk); | ||
1805 | put_disk(sjcd_disk); | ||
1806 | release_region(sjcd_base, 4); | ||
1807 | blk_cleanup_queue(sjcd_queue); | ||
1808 | if ((unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL)) | ||
1809 | printk("SJCD: cannot unregister device.\n"); | ||
1810 | printk(KERN_INFO "SJCD: module: removed.\n"); | ||
1811 | } | ||
1812 | |||
1813 | module_init(sjcd_init); | ||
1814 | module_exit(sjcd_exit); | ||
1815 | |||
1816 | MODULE_LICENSE("GPL"); | ||
1817 | MODULE_ALIAS_BLOCKDEV_MAJOR(SANYO_CDROM_MAJOR); | ||