]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Sony CDU-535 interface device driver | |
3 | * | |
4 | * This is a modified version of the CDU-31A device driver (see below). | |
5 | * Changes were made using documentation for the CDU-531 (which Sony | |
6 | * assures me is very similar to the 535) and partial disassembly of the | |
7 | * DOS driver. I used Minyard's driver and replaced the CDU-31A | |
8 | * commands with the CDU-531 commands. This was complicated by a different | |
9 | * interface protocol with the drive. The driver is still polled. | |
10 | * | |
11 | * Data transfer rate is about 110 Kb/sec, theoretical maximum is 150 Kb/sec. | |
12 | * I tried polling without the sony_sleep during the data transfers but | |
13 | * it did not speed things up any. | |
14 | * | |
15 | * 1993-05-23 (rgj) changed the major number to 21 to get rid of conflict | |
16 | * with CDU-31A driver. This is the also the number from the Linux | |
17 | * Device Driver Registry for the Sony Drive. Hope nobody else is using it. | |
18 | * | |
19 | * 1993-08-29 (rgj) remove the configuring of the interface board address | |
20 | * from the top level configuration, you have to modify it in this file. | |
21 | * | |
22 | * 1995-01-26 Made module-capable (Joel Katz <Stimpson@Panix.COM>) | |
23 | * | |
24 | * 1995-05-20 | |
25 | * Modified to support CDU-510/515 series | |
26 | * (Claudio Porfiri<C.Porfiri@nisms.tei.ericsson.se>) | |
27 | * Fixed to report verify_area() failures | |
28 | * (Heiko Eissfeldt <heiko@colossus.escape.de>) | |
29 | * | |
30 | * 1995-06-01 | |
31 | * More changes to support CDU-510/515 series | |
32 | * (Claudio Porfiri<C.Porfiri@nisms.tei.ericsson.se>) | |
33 | * | |
34 | * November 1999 -- Make kernel-parameter implementation work with 2.3.x | |
35 | * Removed init_module & cleanup_module in favor of | |
36 | * module_init & module_exit. | |
37 | * Torben Mathiasen <tmm@image.dk> | |
38 | * | |
39 | * September 2003 - Fix SMP support by removing cli/sti calls. | |
40 | * Using spinlocks with a wait_queue instead. | |
41 | * Felipe Damasio <felipewd@terra.com.br> | |
42 | * | |
43 | * Things to do: | |
44 | * - handle errors and status better, put everything into a single word | |
45 | * - use interrupts (code mostly there, but a big hole still missing) | |
46 | * - handle multi-session CDs? | |
47 | * - use DMA? | |
48 | * | |
49 | * Known Bugs: | |
50 | * - | |
51 | * | |
52 | * Ken Pizzini (ken@halcyon.com) | |
53 | * | |
54 | * Original by: | |
55 | * Ron Jeppesen (ronj.an@site007.saic.com) | |
56 | * | |
57 | * | |
58 | *------------------------------------------------------------------------ | |
59 | * Sony CDROM interface device driver. | |
60 | * | |
61 | * Corey Minyard (minyard@wf-rch.cirr.com) (CDU-535 complaints to Ken above) | |
62 | * | |
63 | * Colossians 3:17 | |
64 | * | |
65 | * The Sony interface device driver handles Sony interface CDROM | |
66 | * drives and provides a complete block-level interface as well as an | |
67 | * ioctl() interface compatible with the Sun (as specified in | |
68 | * include/linux/cdrom.h). With this interface, CDROMs can be | |
69 | * accessed and standard audio CDs can be played back normally. | |
70 | * | |
71 | * This interface is (unfortunately) a polled interface. This is | |
72 | * because most Sony interfaces are set up with DMA and interrupts | |
73 | * disables. Some (like mine) do not even have the capability to | |
74 | * handle interrupts or DMA. For this reason you will see a bit of | |
75 | * the following: | |
76 | * | |
77 | * snap = jiffies; | |
78 | * while (jiffies-snap < SONY_JIFFIES_TIMEOUT) | |
79 | * { | |
80 | * if (some_condition()) | |
81 | * break; | |
82 | * sony_sleep(); | |
83 | * } | |
84 | * if (some_condition not met) | |
85 | * { | |
86 | * return an_error; | |
87 | * } | |
88 | * | |
89 | * This ugly hack waits for something to happen, sleeping a little | |
90 | * between every try. (The conditional is written so that jiffies | |
91 | * wrap-around is handled properly.) | |
92 | * | |
93 | * One thing about these drives: They talk in MSF (Minute Second Frame) format. | |
94 | * There are 75 frames a second, 60 seconds a minute, and up to 75 minutes on a | |
95 | * disk. The funny thing is that these are sent to the drive in BCD, but the | |
96 | * interface wants to see them in decimal. A lot of conversion goes on. | |
97 | * | |
98 | * Copyright (C) 1993 Corey Minyard | |
99 | * | |
100 | * This program is free software; you can redistribute it and/or modify | |
101 | * it under the terms of the GNU General Public License as published by | |
102 | * the Free Software Foundation; either version 2 of the License, or | |
103 | * (at your option) any later version. | |
104 | * | |
105 | * This program is distributed in the hope that it will be useful, | |
106 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
107 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
108 | * GNU General Public License for more details. | |
109 | * | |
110 | * You should have received a copy of the GNU General Public License | |
111 | * along with this program; if not, write to the Free Software | |
112 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
113 | * | |
114 | */ | |
115 | ||
116 | ||
117 | # include <linux/module.h> | |
118 | ||
119 | #include <linux/errno.h> | |
120 | #include <linux/signal.h> | |
121 | #include <linux/sched.h> | |
122 | #include <linux/timer.h> | |
123 | #include <linux/fs.h> | |
124 | #include <linux/kernel.h> | |
125 | #include <linux/interrupt.h> | |
126 | #include <linux/ioport.h> | |
127 | #include <linux/hdreg.h> | |
128 | #include <linux/genhd.h> | |
129 | #include <linux/mm.h> | |
130 | #include <linux/slab.h> | |
131 | #include <linux/init.h> | |
132 | ||
133 | #define REALLY_SLOW_IO | |
134 | #include <asm/system.h> | |
135 | #include <asm/io.h> | |
136 | #include <asm/uaccess.h> | |
137 | ||
138 | #include <linux/cdrom.h> | |
139 | ||
140 | #define MAJOR_NR CDU535_CDROM_MAJOR | |
141 | #include <linux/blkdev.h> | |
142 | ||
143 | #define sony535_cd_base_io sonycd535 /* for compatible parameter passing with "insmod" */ | |
144 | #include "sonycd535.h" | |
145 | ||
146 | /* | |
147 | * this is the base address of the interface card for the Sony CDU-535 | |
148 | * CDROM drive. If your jumpers are set for an address other than | |
149 | * this one (the default), change the following line to the | |
150 | * proper address. | |
151 | */ | |
152 | #ifndef CDU535_ADDRESS | |
153 | # define CDU535_ADDRESS 0x340 | |
154 | #endif | |
155 | #ifndef CDU535_INTERRUPT | |
156 | # define CDU535_INTERRUPT 0 | |
157 | #endif | |
158 | #ifndef CDU535_HANDLE | |
159 | # define CDU535_HANDLE "cdu535" | |
160 | #endif | |
161 | #ifndef CDU535_MESSAGE_NAME | |
162 | # define CDU535_MESSAGE_NAME "Sony CDU-535" | |
163 | #endif | |
164 | ||
165 | #define CDU535_BLOCK_SIZE 2048 | |
166 | ||
167 | #ifndef MAX_SPINUP_RETRY | |
168 | # define MAX_SPINUP_RETRY 3 /* 1 is sufficient for most drives... */ | |
169 | #endif | |
170 | #ifndef RETRY_FOR_BAD_STATUS | |
171 | # define RETRY_FOR_BAD_STATUS 100 /* in 10th of second */ | |
172 | #endif | |
173 | ||
174 | #ifndef DEBUG | |
175 | # define DEBUG 1 | |
176 | #endif | |
177 | ||
178 | /* | |
179 | * SONY535_BUFFER_SIZE determines the size of internal buffer used | |
180 | * by the drive. It must be at least 2K and the larger the buffer | |
181 | * the better the transfer rate. It does however take system memory. | |
182 | * On my system I get the following transfer rates using dd to read | |
183 | * 10 Mb off /dev/cdrom. | |
184 | * | |
185 | * 8K buffer 43 Kb/sec | |
186 | * 16K buffer 66 Kb/sec | |
187 | * 32K buffer 91 Kb/sec | |
188 | * 64K buffer 111 Kb/sec | |
189 | * 128K buffer 123 Kb/sec | |
190 | * 512K buffer 123 Kb/sec | |
191 | */ | |
192 | #define SONY535_BUFFER_SIZE (64*1024) | |
193 | ||
194 | /* | |
195 | * if LOCK_DOORS is defined then the eject button is disabled while | |
196 | * the device is open. | |
197 | */ | |
198 | #ifndef NO_LOCK_DOORS | |
199 | # define LOCK_DOORS | |
200 | #endif | |
201 | ||
202 | static int read_subcode(void); | |
203 | static void sony_get_toc(void); | |
204 | static int cdu_open(struct inode *inode, struct file *filp); | |
205 | static inline unsigned int int_to_bcd(unsigned int val); | |
206 | static unsigned int bcd_to_int(unsigned int bcd); | |
207 | static int do_sony_cmd(Byte * cmd, int nCmd, Byte status[2], | |
208 | Byte * response, int n_response, int ignoreStatusBit7); | |
209 | ||
210 | /* The base I/O address of the Sony Interface. This is a variable (not a | |
211 | #define) so it can be easily changed via some future ioctl() */ | |
212 | static unsigned int sony535_cd_base_io = CDU535_ADDRESS; | |
213 | module_param(sony535_cd_base_io, int, 0); | |
214 | ||
215 | /* | |
216 | * The following are I/O addresses of the various registers for the drive. The | |
217 | * comment for the base address also applies here. | |
218 | */ | |
219 | static unsigned short select_unit_reg; | |
220 | static unsigned short result_reg; | |
221 | static unsigned short command_reg; | |
222 | static unsigned short read_status_reg; | |
223 | static unsigned short data_reg; | |
224 | ||
225 | static DEFINE_SPINLOCK(sonycd535_lock); /* queue lock */ | |
226 | static struct request_queue *sonycd535_queue; | |
227 | ||
228 | static int initialized; /* Has the drive been initialized? */ | |
229 | static int sony_disc_changed = 1; /* Has the disk been changed | |
230 | since the last check? */ | |
231 | static int sony_toc_read; /* Has the table of contents been | |
232 | read? */ | |
233 | static unsigned int sony_buffer_size; /* Size in bytes of the read-ahead | |
234 | buffer. */ | |
235 | static unsigned int sony_buffer_sectors; /* Size (in 2048 byte records) of | |
236 | the read-ahead buffer. */ | |
237 | static unsigned int sony_usage; /* How many processes have the | |
238 | drive open. */ | |
239 | ||
240 | static int sony_first_block = -1; /* First OS block (512 byte) in | |
241 | the read-ahead buffer */ | |
242 | static int sony_last_block = -1; /* Last OS block (512 byte) in | |
243 | the read-ahead buffer */ | |
244 | ||
245 | static struct s535_sony_toc *sony_toc; /* Points to the table of | |
246 | contents. */ | |
247 | ||
248 | static struct s535_sony_subcode *last_sony_subcode; /* Points to the last | |
249 | subcode address read */ | |
250 | static Byte **sony_buffer; /* Points to the pointers | |
251 | to the sector buffers */ | |
252 | ||
253 | static int sony_inuse; /* is the drive in use? Only one | |
254 | open at a time allowed */ | |
255 | ||
256 | /* | |
257 | * The audio status uses the values from read subchannel data as specified | |
258 | * in include/linux/cdrom.h. | |
259 | */ | |
260 | static int sony_audio_status = CDROM_AUDIO_NO_STATUS; | |
261 | ||
262 | /* | |
263 | * The following are a hack for pausing and resuming audio play. The drive | |
264 | * does not work as I would expect it, if you stop it then start it again, | |
265 | * the drive seeks back to the beginning and starts over. This holds the | |
266 | * position during a pause so a resume can restart it. It uses the | |
267 | * audio status variable above to tell if it is paused. | |
268 | * I just kept the CDU-31A driver behavior rather than using the PAUSE | |
269 | * command on the CDU-535. | |
270 | */ | |
271 | static Byte cur_pos_msf[3]; | |
272 | static Byte final_pos_msf[3]; | |
273 | ||
274 | /* What IRQ is the drive using? 0 if none. */ | |
275 | static int sony535_irq_used = CDU535_INTERRUPT; | |
276 | ||
277 | /* The interrupt handler will wake this queue up when it gets an interrupt. */ | |
278 | static DECLARE_WAIT_QUEUE_HEAD(cdu535_irq_wait); | |
279 | ||
280 | ||
281 | /* | |
282 | * This routine returns 1 if the disk has been changed since the last | |
283 | * check or 0 if it hasn't. Setting flag to 0 resets the changed flag. | |
284 | */ | |
285 | static int | |
286 | cdu535_check_media_change(struct gendisk *disk) | |
287 | { | |
288 | /* if driver is not initialized, always return 0 */ | |
289 | int retval = initialized ? sony_disc_changed : 0; | |
290 | sony_disc_changed = 0; | |
291 | return retval; | |
292 | } | |
293 | ||
294 | static inline void | |
295 | enable_interrupts(void) | |
296 | { | |
297 | #ifdef USE_IRQ | |
298 | /* | |
299 | * This code was taken from cdu31a.c; it will not | |
300 | * directly work for the cdu535 as written... | |
301 | */ | |
302 | curr_control_reg |= ( SONY_ATTN_INT_EN_BIT | |
303 | | SONY_RES_RDY_INT_EN_BIT | |
304 | | SONY_DATA_RDY_INT_EN_BIT); | |
305 | outb(curr_control_reg, sony_cd_control_reg); | |
306 | #endif | |
307 | } | |
308 | ||
309 | static inline void | |
310 | disable_interrupts(void) | |
311 | { | |
312 | #ifdef USE_IRQ | |
313 | /* | |
314 | * This code was taken from cdu31a.c; it will not | |
315 | * directly work for the cdu535 as written... | |
316 | */ | |
317 | curr_control_reg &= ~(SONY_ATTN_INT_EN_BIT | |
318 | | SONY_RES_RDY_INT_EN_BIT | |
319 | | SONY_DATA_RDY_INT_EN_BIT); | |
320 | outb(curr_control_reg, sony_cd_control_reg); | |
321 | #endif | |
322 | } | |
323 | ||
324 | static irqreturn_t | |
7d12e780 | 325 | cdu535_interrupt(int irq, void *dev_id) |
1da177e4 LT |
326 | { |
327 | disable_interrupts(); | |
328 | if (waitqueue_active(&cdu535_irq_wait)) { | |
329 | wake_up(&cdu535_irq_wait); | |
330 | return IRQ_HANDLED; | |
331 | } | |
332 | printk(CDU535_MESSAGE_NAME | |
333 | ": Got an interrupt but nothing was waiting\n"); | |
334 | return IRQ_NONE; | |
335 | } | |
336 | ||
337 | ||
338 | /* | |
339 | * Wait a little while. | |
340 | */ | |
341 | static inline void | |
342 | sony_sleep(void) | |
343 | { | |
344 | if (sony535_irq_used <= 0) { /* poll */ | |
345 | yield(); | |
346 | } else { /* Interrupt driven */ | |
347 | DEFINE_WAIT(wait); | |
348 | ||
349 | spin_lock_irq(&sonycd535_lock); | |
350 | enable_interrupts(); | |
351 | prepare_to_wait(&cdu535_irq_wait, &wait, TASK_INTERRUPTIBLE); | |
352 | spin_unlock_irq(&sonycd535_lock); | |
353 | schedule(); | |
354 | finish_wait(&cdu535_irq_wait, &wait); | |
355 | } | |
356 | } | |
357 | ||
358 | /*------------------start of SONY CDU535 very specific ---------------------*/ | |
359 | ||
360 | /**************************************************************************** | |
361 | * void select_unit( int unit_no ) | |
362 | * | |
363 | * Select the specified unit (0-3) so that subsequent commands reference it | |
364 | ****************************************************************************/ | |
365 | static void | |
366 | select_unit(int unit_no) | |
367 | { | |
368 | unsigned int select_mask = ~(1 << unit_no); | |
369 | outb(select_mask, select_unit_reg); | |
370 | } | |
371 | ||
372 | /*************************************************************************** | |
373 | * int read_result_reg( Byte *data_ptr ) | |
374 | * | |
375 | * Read a result byte from the Sony CDU controller, store in location pointed | |
376 | * to by data_ptr. Return zero on success, TIME_OUT if we did not receive | |
377 | * data. | |
378 | ***************************************************************************/ | |
379 | static int | |
380 | read_result_reg(Byte *data_ptr) | |
381 | { | |
382 | unsigned long snap; | |
383 | int read_status; | |
384 | ||
385 | snap = jiffies; | |
386 | while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { | |
387 | read_status = inb(read_status_reg); | |
388 | if ((read_status & SONY535_RESULT_NOT_READY_BIT) == 0) { | |
389 | #if DEBUG > 1 | |
390 | printk(CDU535_MESSAGE_NAME | |
391 | ": read_result_reg(): readStatReg = 0x%x\n", read_status); | |
392 | #endif | |
393 | *data_ptr = inb(result_reg); | |
394 | return 0; | |
395 | } else { | |
396 | sony_sleep(); | |
397 | } | |
398 | } | |
399 | printk(CDU535_MESSAGE_NAME " read_result_reg: TIME OUT!\n"); | |
400 | return TIME_OUT; | |
401 | } | |
402 | ||
403 | /**************************************************************************** | |
404 | * int read_exec_status( Byte status[2] ) | |
405 | * | |
406 | * Read the execution status of the last command and put into status. | |
407 | * Handles reading second status word if available. Returns 0 on success, | |
408 | * TIME_OUT on failure. | |
409 | ****************************************************************************/ | |
410 | static int | |
411 | read_exec_status(Byte status[2]) | |
412 | { | |
413 | status[1] = 0; | |
414 | if (read_result_reg(&(status[0])) != 0) | |
415 | return TIME_OUT; | |
416 | if ((status[0] & 0x80) != 0) { /* byte two follows */ | |
417 | if (read_result_reg(&(status[1])) != 0) | |
418 | return TIME_OUT; | |
419 | } | |
420 | #if DEBUG > 1 | |
421 | printk(CDU535_MESSAGE_NAME ": read_exec_status: read 0x%x 0x%x\n", | |
422 | status[0], status[1]); | |
423 | #endif | |
424 | return 0; | |
425 | } | |
426 | ||
427 | /**************************************************************************** | |
428 | * int check_drive_status( void ) | |
429 | * | |
430 | * Check the current drive status. Using this before executing a command | |
431 | * takes care of the problem of unsolicited drive status-2 messages. | |
432 | * Add a check of the audio status if we think the disk is playing. | |
433 | ****************************************************************************/ | |
434 | static int | |
435 | check_drive_status(void) | |
436 | { | |
437 | Byte status, e_status[2]; | |
438 | int CDD, ATN; | |
439 | Byte cmd; | |
440 | ||
441 | select_unit(0); | |
442 | if (sony_audio_status == CDROM_AUDIO_PLAY) { /* check status */ | |
443 | outb(SONY535_REQUEST_AUDIO_STATUS, command_reg); | |
444 | if (read_result_reg(&status) == 0) { | |
445 | switch (status) { | |
446 | case 0x0: | |
447 | break; /* play in progress */ | |
448 | case 0x1: | |
449 | break; /* paused */ | |
450 | case 0x3: /* audio play completed */ | |
451 | case 0x5: /* play not requested */ | |
452 | sony_audio_status = CDROM_AUDIO_COMPLETED; | |
453 | read_subcode(); | |
454 | break; | |
455 | case 0x4: /* error during play */ | |
456 | sony_audio_status = CDROM_AUDIO_ERROR; | |
457 | break; | |
458 | } | |
459 | } | |
460 | } | |
461 | /* now check drive status */ | |
462 | outb(SONY535_REQUEST_DRIVE_STATUS_2, command_reg); | |
463 | if (read_result_reg(&status) != 0) | |
464 | return TIME_OUT; | |
465 | ||
466 | #if DEBUG > 1 | |
467 | printk(CDU535_MESSAGE_NAME ": check_drive_status() got 0x%x\n", status); | |
468 | #endif | |
469 | ||
470 | if (status == 0) | |
471 | return 0; | |
472 | ||
473 | ATN = status & 0xf; | |
474 | CDD = (status >> 4) & 0xf; | |
475 | ||
476 | switch (ATN) { | |
477 | case 0x0: | |
478 | break; /* go on to CDD stuff */ | |
479 | case SONY535_ATN_BUSY: | |
480 | if (initialized) | |
481 | printk(CDU535_MESSAGE_NAME " error: drive busy\n"); | |
482 | return CD_BUSY; | |
483 | case SONY535_ATN_EJECT_IN_PROGRESS: | |
484 | printk(CDU535_MESSAGE_NAME " error: eject in progress\n"); | |
485 | sony_audio_status = CDROM_AUDIO_INVALID; | |
486 | return CD_BUSY; | |
487 | case SONY535_ATN_RESET_OCCURRED: | |
488 | case SONY535_ATN_DISC_CHANGED: | |
489 | case SONY535_ATN_RESET_AND_DISC_CHANGED: | |
490 | #if DEBUG > 0 | |
491 | printk(CDU535_MESSAGE_NAME " notice: reset occurred or disc changed\n"); | |
492 | #endif | |
493 | sony_disc_changed = 1; | |
494 | sony_toc_read = 0; | |
495 | sony_audio_status = CDROM_AUDIO_NO_STATUS; | |
496 | sony_first_block = -1; | |
497 | sony_last_block = -1; | |
498 | if (initialized) { | |
499 | cmd = SONY535_SPIN_UP; | |
500 | do_sony_cmd(&cmd, 1, e_status, NULL, 0, 0); | |
501 | sony_get_toc(); | |
502 | } | |
503 | return 0; | |
504 | default: | |
505 | printk(CDU535_MESSAGE_NAME " error: drive busy (ATN=0x%x)\n", ATN); | |
506 | return CD_BUSY; | |
507 | } | |
508 | switch (CDD) { /* the 531 docs are not helpful in decoding this */ | |
509 | case 0x0: /* just use the values from the DOS driver */ | |
510 | case 0x2: | |
511 | case 0xa: | |
512 | break; /* no error */ | |
513 | case 0xc: | |
514 | printk(CDU535_MESSAGE_NAME | |
515 | ": check_drive_status(): CDD = 0xc! Not properly handled!\n"); | |
516 | return CD_BUSY; /* ? */ | |
517 | default: | |
518 | return CD_BUSY; | |
519 | } | |
520 | return 0; | |
521 | } /* check_drive_status() */ | |
522 | ||
523 | /***************************************************************************** | |
524 | * int do_sony_cmd( Byte *cmd, int n_cmd, Byte status[2], | |
525 | * Byte *response, int n_response, int ignore_status_bit7 ) | |
526 | * | |
527 | * Generic routine for executing commands. The command and its parameters | |
528 | * should be placed in the cmd[] array, number of bytes in the command is | |
529 | * stored in nCmd. The response from the command will be stored in the | |
530 | * response array. The number of bytes you expect back (excluding status) | |
531 | * should be passed in n_response. Finally, some | |
532 | * commands set bit 7 of the return status even when there is no second | |
533 | * status byte, on these commands set ignoreStatusBit7 TRUE. | |
534 | * If the command was sent and data received back, then we return 0, | |
535 | * else we return TIME_OUT. You still have to check the status yourself. | |
536 | * You should call check_drive_status() before calling this routine | |
537 | * so that you do not lose notifications of disk changes, etc. | |
538 | ****************************************************************************/ | |
539 | static int | |
540 | do_sony_cmd(Byte * cmd, int n_cmd, Byte status[2], | |
541 | Byte * response, int n_response, int ignore_status_bit7) | |
542 | { | |
543 | int i; | |
544 | ||
545 | /* write out the command */ | |
546 | for (i = 0; i < n_cmd; i++) | |
547 | outb(cmd[i], command_reg); | |
548 | ||
549 | /* read back the status */ | |
550 | if (read_result_reg(status) != 0) | |
551 | return TIME_OUT; | |
552 | if (!ignore_status_bit7 && ((status[0] & 0x80) != 0)) { | |
553 | /* get second status byte */ | |
554 | if (read_result_reg(status + 1) != 0) | |
555 | return TIME_OUT; | |
556 | } else { | |
557 | status[1] = 0; | |
558 | } | |
559 | #if DEBUG > 2 | |
560 | printk(CDU535_MESSAGE_NAME ": do_sony_cmd %x: %x %x\n", | |
561 | *cmd, status[0], status[1]); | |
562 | #endif | |
563 | ||
564 | /* do not know about when I should read set of data and when not to */ | |
565 | if ((status[0] & ((ignore_status_bit7 ? 0x7f : 0xff) & 0x8f)) != 0) | |
566 | return 0; | |
567 | ||
568 | /* else, read in rest of data */ | |
569 | for (i = 0; 0 < n_response; n_response--, i++) | |
570 | if (read_result_reg(response + i) != 0) | |
571 | return TIME_OUT; | |
572 | return 0; | |
573 | } /* do_sony_cmd() */ | |
574 | ||
575 | /************************************************************************** | |
576 | * int set_drive_mode( int mode, Byte status[2] ) | |
577 | * | |
578 | * Set the drive mode to the specified value (mode=0 is audio, mode=e0 | |
579 | * is mode-1 CDROM | |
580 | **************************************************************************/ | |
581 | static int | |
582 | set_drive_mode(int mode, Byte status[2]) | |
583 | { | |
584 | Byte cmd_buff[2]; | |
585 | Byte ret_buff[1]; | |
586 | ||
587 | cmd_buff[0] = SONY535_SET_DRIVE_MODE; | |
588 | cmd_buff[1] = mode; | |
589 | return do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1); | |
590 | } | |
591 | ||
592 | /*************************************************************************** | |
593 | * int seek_and_read_N_blocks( Byte params[], int n_blocks, Byte status[2], | |
594 | * Byte *data_buff, int buff_size ) | |
595 | * | |
596 | * Read n_blocks of data from the CDROM starting at position params[0:2], | |
597 | * number of blocks in stored in params[3:5] -- both these are already | |
598 | * int bcd format. | |
599 | * Transfer the data into the buffer pointed at by data_buff. buff_size | |
600 | * gives the number of bytes available in the buffer. | |
601 | * The routine returns number of bytes read in if successful, otherwise | |
602 | * it returns one of the standard error returns. | |
603 | ***************************************************************************/ | |
604 | static int | |
605 | seek_and_read_N_blocks(Byte params[], int n_blocks, Byte status[2], | |
606 | Byte **buff, int buf_size) | |
607 | { | |
608 | Byte cmd_buff[7]; | |
609 | int i; | |
610 | int read_status; | |
611 | unsigned long snap; | |
612 | Byte *data_buff; | |
613 | int sector_count = 0; | |
614 | ||
615 | if (buf_size < CDU535_BLOCK_SIZE * n_blocks) | |
616 | return NO_ROOM; | |
617 | ||
618 | set_drive_mode(SONY535_CDROM_DRIVE_MODE, status); | |
619 | ||
620 | /* send command to read the data */ | |
621 | cmd_buff[0] = SONY535_SEEK_AND_READ_N_BLOCKS_1; | |
622 | for (i = 0; i < 6; i++) | |
623 | cmd_buff[i + 1] = params[i]; | |
624 | for (i = 0; i < 7; i++) | |
625 | outb(cmd_buff[i], command_reg); | |
626 | ||
627 | /* read back the data one block at a time */ | |
628 | while (0 < n_blocks--) { | |
629 | /* wait for data to be ready */ | |
630 | int data_valid = 0; | |
631 | snap = jiffies; | |
632 | while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { | |
633 | read_status = inb(read_status_reg); | |
634 | if ((read_status & SONY535_RESULT_NOT_READY_BIT) == 0) { | |
635 | read_exec_status(status); | |
636 | return BAD_STATUS; | |
637 | } | |
638 | if ((read_status & SONY535_DATA_NOT_READY_BIT) == 0) { | |
639 | /* data is ready, read it */ | |
640 | data_buff = buff[sector_count++]; | |
641 | for (i = 0; i < CDU535_BLOCK_SIZE; i++) | |
642 | *data_buff++ = inb(data_reg); /* unrolling this loop does not seem to help */ | |
643 | data_valid = 1; | |
644 | break; /* exit the timeout loop */ | |
645 | } | |
646 | sony_sleep(); /* data not ready, sleep a while */ | |
647 | } | |
648 | if (!data_valid) | |
649 | return TIME_OUT; /* if we reach this stage */ | |
650 | } | |
651 | ||
652 | /* read all the data, now read the status */ | |
653 | if ((i = read_exec_status(status)) != 0) | |
654 | return i; | |
655 | return CDU535_BLOCK_SIZE * sector_count; | |
656 | } /* seek_and_read_N_blocks() */ | |
657 | ||
658 | /**************************************************************************** | |
659 | * int request_toc_data( Byte status[2], struct s535_sony_toc *toc ) | |
660 | * | |
661 | * Read in the table of contents data. Converts all the bcd data | |
662 | * into integers in the toc structure. | |
663 | ****************************************************************************/ | |
664 | static int | |
665 | request_toc_data(Byte status[2], struct s535_sony_toc *toc) | |
666 | { | |
667 | int to_status; | |
668 | int i, j, n_tracks, track_no; | |
669 | int first_track_num, last_track_num; | |
670 | Byte cmd_no = 0xb2; | |
671 | Byte track_address_buffer[5]; | |
672 | ||
673 | /* read the fixed portion of the table of contents */ | |
674 | if ((to_status = do_sony_cmd(&cmd_no, 1, status, (Byte *) toc, 15, 1)) != 0) | |
675 | return to_status; | |
676 | ||
677 | /* convert the data into integers so we can use them */ | |
678 | first_track_num = bcd_to_int(toc->first_track_num); | |
679 | last_track_num = bcd_to_int(toc->last_track_num); | |
680 | n_tracks = last_track_num - first_track_num + 1; | |
681 | ||
682 | /* read each of the track address descriptors */ | |
683 | for (i = 0; i < n_tracks; i++) { | |
684 | /* read the descriptor into a temporary buffer */ | |
685 | for (j = 0; j < 5; j++) { | |
686 | if (read_result_reg(track_address_buffer + j) != 0) | |
687 | return TIME_OUT; | |
688 | if (j == 1) /* need to convert from bcd */ | |
689 | track_no = bcd_to_int(track_address_buffer[j]); | |
690 | } | |
691 | /* copy the descriptor to proper location - sonycd.c just fills */ | |
692 | memcpy(toc->tracks + i, track_address_buffer, 5); | |
693 | } | |
694 | return 0; | |
695 | } /* request_toc_data() */ | |
696 | ||
697 | /*************************************************************************** | |
698 | * int spin_up_drive( Byte status[2] ) | |
699 | * | |
700 | * Spin up the drive (unless it is already spinning). | |
701 | ***************************************************************************/ | |
702 | static int | |
703 | spin_up_drive(Byte status[2]) | |
704 | { | |
705 | Byte cmd; | |
706 | ||
707 | /* first see if the drive is already spinning */ | |
708 | cmd = SONY535_REQUEST_DRIVE_STATUS_1; | |
709 | if (do_sony_cmd(&cmd, 1, status, NULL, 0, 0) != 0) | |
710 | return TIME_OUT; | |
711 | if ((status[0] & SONY535_STATUS1_NOT_SPINNING) == 0) | |
712 | return 0; /* it's already spinning */ | |
713 | ||
714 | /* otherwise, give the spin-up command */ | |
715 | cmd = SONY535_SPIN_UP; | |
716 | return do_sony_cmd(&cmd, 1, status, NULL, 0, 0); | |
717 | } | |
718 | ||
719 | /*--------------------end of SONY CDU535 very specific ---------------------*/ | |
720 | ||
721 | /* Convert from an integer 0-99 to BCD */ | |
722 | static inline unsigned int | |
723 | int_to_bcd(unsigned int val) | |
724 | { | |
725 | int retval; | |
726 | ||
727 | retval = (val / 10) << 4; | |
728 | retval = retval | val % 10; | |
729 | return retval; | |
730 | } | |
731 | ||
732 | ||
733 | /* Convert from BCD to an integer from 0-99 */ | |
734 | static unsigned int | |
735 | bcd_to_int(unsigned int bcd) | |
736 | { | |
737 | return (((bcd >> 4) & 0x0f) * 10) + (bcd & 0x0f); | |
738 | } | |
739 | ||
740 | ||
741 | /* | |
742 | * Convert a logical sector value (like the OS would want to use for | |
743 | * a block device) to an MSF format. | |
744 | */ | |
745 | static void | |
746 | log_to_msf(unsigned int log, Byte *msf) | |
747 | { | |
748 | log = log + LOG_START_OFFSET; | |
749 | msf[0] = int_to_bcd(log / 4500); | |
750 | log = log % 4500; | |
751 | msf[1] = int_to_bcd(log / 75); | |
752 | msf[2] = int_to_bcd(log % 75); | |
753 | } | |
754 | ||
755 | ||
756 | /* | |
757 | * Convert an MSF format to a logical sector. | |
758 | */ | |
759 | static unsigned int | |
760 | msf_to_log(Byte *msf) | |
761 | { | |
762 | unsigned int log; | |
763 | ||
764 | ||
765 | log = bcd_to_int(msf[2]); | |
766 | log += bcd_to_int(msf[1]) * 75; | |
767 | log += bcd_to_int(msf[0]) * 4500; | |
768 | log = log - LOG_START_OFFSET; | |
769 | ||
770 | return log; | |
771 | } | |
772 | ||
773 | ||
774 | /* | |
775 | * Take in integer size value and put it into a buffer like | |
776 | * the drive would want to see a number-of-sector value. | |
777 | */ | |
778 | static void | |
779 | size_to_buf(unsigned int size, Byte *buf) | |
780 | { | |
781 | buf[0] = size / 65536; | |
782 | size = size % 65536; | |
783 | buf[1] = size / 256; | |
784 | buf[2] = size % 256; | |
785 | } | |
786 | ||
787 | ||
788 | /* | |
789 | * The OS calls this to perform a read or write operation to the drive. | |
790 | * Write obviously fail. Reads to a read ahead of sony_buffer_size | |
791 | * bytes to help speed operations. This especially helps since the OS | |
792 | * may use 1024 byte blocks and the drive uses 2048 byte blocks. Since most | |
793 | * data access on a CD is done sequentially, this saves a lot of operations. | |
794 | */ | |
795 | static void | |
796 | do_cdu535_request(request_queue_t * q) | |
797 | { | |
798 | struct request *req; | |
799 | unsigned int read_size; | |
800 | int block; | |
801 | int nsect; | |
802 | int copyoff; | |
803 | int spin_up_retry; | |
804 | Byte params[10]; | |
805 | Byte status[2]; | |
806 | Byte cmd[2]; | |
807 | ||
808 | while (1) { | |
809 | req = elv_next_request(q); | |
810 | if (!req) | |
811 | return; | |
812 | ||
813 | block = req->sector; | |
814 | nsect = req->nr_sectors; | |
815 | if (!blk_fs_request(req)) { | |
816 | end_request(req, 0); | |
817 | continue; | |
818 | } | |
819 | if (rq_data_dir(req) == WRITE) { | |
820 | end_request(req, 0); | |
821 | continue; | |
822 | } | |
823 | /* | |
824 | * If the block address is invalid or the request goes beyond | |
825 | * the end of the media, return an error. | |
826 | */ | |
827 | if (sony_toc->lead_out_start_lba <= (block/4)) { | |
828 | end_request(req, 0); | |
829 | return; | |
830 | } | |
831 | if (sony_toc->lead_out_start_lba <= ((block + nsect) / 4)) { | |
832 | end_request(req, 0); | |
833 | return; | |
834 | } | |
835 | while (0 < nsect) { | |
836 | /* | |
837 | * If the requested sector is not currently in | |
838 | * the read-ahead buffer, it must be read in. | |
839 | */ | |
840 | if ((block < sony_first_block) || (sony_last_block < block)) { | |
841 | sony_first_block = (block / 4) * 4; | |
842 | log_to_msf(block / 4, params); | |
843 | ||
844 | /* | |
845 | * If the full read-ahead would go beyond the end of the media, trim | |
846 | * it back to read just till the end of the media. | |
847 | */ | |
848 | if (sony_toc->lead_out_start_lba <= ((block / 4) + sony_buffer_sectors)) { | |
849 | sony_last_block = (sony_toc->lead_out_start_lba * 4) - 1; | |
850 | read_size = sony_toc->lead_out_start_lba - (block / 4); | |
851 | } else { | |
852 | sony_last_block = sony_first_block + (sony_buffer_sectors * 4) - 1; | |
853 | read_size = sony_buffer_sectors; | |
854 | } | |
855 | size_to_buf(read_size, ¶ms[3]); | |
856 | ||
857 | /* | |
858 | * Read the data. If the drive was not spinning, | |
859 | * spin it up and try some more. | |
860 | */ | |
861 | for (spin_up_retry=0 ;; ++spin_up_retry) { | |
862 | /* This loop has been modified to support the Sony | |
863 | * CDU-510/515 series, thanks to Claudio Porfiri | |
864 | * <C.Porfiri@nisms.tei.ericsson.se>. | |
865 | */ | |
866 | /* | |
867 | * This part is to deal with very slow hardware. We | |
868 | * try at most MAX_SPINUP_RETRY times to read the same | |
869 | * block. A check for seek_and_read_N_blocks' result is | |
870 | * performed; if the result is wrong, the CDROM's engine | |
871 | * is restarted and the operation is tried again. | |
872 | */ | |
873 | /* | |
874 | * 1995-06-01: The system got problems when downloading | |
875 | * from Slackware CDROM, the problem seems to be: | |
876 | * seek_and_read_N_blocks returns BAD_STATUS and we | |
877 | * should wait for a while before retrying, so a new | |
878 | * part was added to discriminate the return value from | |
879 | * seek_and_read_N_blocks for the various cases. | |
880 | */ | |
881 | int readStatus = seek_and_read_N_blocks(params, read_size, | |
882 | status, sony_buffer, (read_size * CDU535_BLOCK_SIZE)); | |
883 | if (0 <= readStatus) /* Good data; common case, placed first */ | |
884 | break; | |
885 | if (readStatus == NO_ROOM || spin_up_retry == MAX_SPINUP_RETRY) { | |
886 | /* give up */ | |
887 | if (readStatus == NO_ROOM) | |
888 | printk(CDU535_MESSAGE_NAME " No room to read from CD\n"); | |
889 | else | |
890 | printk(CDU535_MESSAGE_NAME " Read error: 0x%.2x\n", | |
891 | status[0]); | |
892 | sony_first_block = -1; | |
893 | sony_last_block = -1; | |
894 | end_request(req, 0); | |
895 | return; | |
896 | } | |
897 | if (readStatus == BAD_STATUS) { | |
898 | /* Sleep for a while, then retry */ | |
899 | set_current_state(TASK_INTERRUPTIBLE); | |
900 | spin_unlock_irq(&sonycd535_lock); | |
901 | schedule_timeout(RETRY_FOR_BAD_STATUS*HZ/10); | |
902 | spin_lock_irq(&sonycd535_lock); | |
903 | } | |
904 | #if DEBUG > 0 | |
905 | printk(CDU535_MESSAGE_NAME | |
906 | " debug: calling spin up when reading data!\n"); | |
907 | #endif | |
908 | cmd[0] = SONY535_SPIN_UP; | |
909 | do_sony_cmd(cmd, 1, status, NULL, 0, 0); | |
910 | } | |
911 | } | |
912 | /* | |
913 | * The data is in memory now, copy it to the buffer and advance to the | |
914 | * next block to read. | |
915 | */ | |
916 | copyoff = block - sony_first_block; | |
917 | memcpy(req->buffer, | |
918 | sony_buffer[copyoff / 4] + 512 * (copyoff % 4), 512); | |
919 | ||
920 | block += 1; | |
921 | nsect -= 1; | |
922 | req->buffer += 512; | |
923 | } | |
924 | ||
925 | end_request(req, 1); | |
926 | } | |
927 | } | |
928 | ||
929 | /* | |
930 | * Read the table of contents from the drive and set sony_toc_read if | |
931 | * successful. | |
932 | */ | |
933 | static void | |
934 | sony_get_toc(void) | |
935 | { | |
936 | Byte status[2]; | |
937 | if (!sony_toc_read) { | |
938 | /* do not call check_drive_status() from here since it can call this routine */ | |
939 | if (request_toc_data(status, sony_toc) < 0) | |
940 | return; | |
941 | sony_toc->lead_out_start_lba = msf_to_log(sony_toc->lead_out_start_msf); | |
942 | sony_toc_read = 1; | |
943 | } | |
944 | } | |
945 | ||
946 | ||
947 | /* | |
948 | * Search for a specific track in the table of contents. track is | |
949 | * passed in bcd format | |
950 | */ | |
951 | static int | |
952 | find_track(int track) | |
953 | { | |
954 | int i; | |
955 | int num_tracks; | |
956 | ||
957 | ||
958 | num_tracks = bcd_to_int(sony_toc->last_track_num) - | |
959 | bcd_to_int(sony_toc->first_track_num) + 1; | |
960 | for (i = 0; i < num_tracks; i++) { | |
961 | if (sony_toc->tracks[i].track == track) { | |
962 | return i; | |
963 | } | |
964 | } | |
965 | ||
966 | return -1; | |
967 | } | |
968 | ||
969 | /* | |
970 | * Read the subcode and put it int last_sony_subcode for future use. | |
971 | */ | |
972 | static int | |
973 | read_subcode(void) | |
974 | { | |
975 | Byte cmd = SONY535_REQUEST_SUB_Q_DATA; | |
976 | Byte status[2]; | |
977 | int dsc_status; | |
978 | ||
979 | if (check_drive_status() != 0) | |
980 | return -EIO; | |
981 | ||
982 | if ((dsc_status = do_sony_cmd(&cmd, 1, status, (Byte *) last_sony_subcode, | |
983 | sizeof(struct s535_sony_subcode), 1)) != 0) { | |
984 | printk(CDU535_MESSAGE_NAME " error 0x%.2x, %d (read_subcode)\n", | |
985 | status[0], dsc_status); | |
986 | return -EIO; | |
987 | } | |
988 | return 0; | |
989 | } | |
990 | ||
991 | ||
992 | /* | |
993 | * Get the subchannel info like the CDROMSUBCHNL command wants to see it. If | |
994 | * the drive is playing, the subchannel needs to be read (since it would be | |
995 | * changing). If the drive is paused or completed, the subcode information has | |
996 | * already been stored, just use that. The ioctl call wants things in decimal | |
997 | * (not BCD), so all the conversions are done. | |
998 | */ | |
999 | static int | |
1000 | sony_get_subchnl_info(void __user *arg) | |
1001 | { | |
1002 | struct cdrom_subchnl schi; | |
1003 | ||
1004 | /* Get attention stuff */ | |
1005 | if (check_drive_status() != 0) | |
1006 | return -EIO; | |
1007 | ||
1008 | sony_get_toc(); | |
1009 | if (!sony_toc_read) { | |
1010 | return -EIO; | |
1011 | } | |
1012 | if (copy_from_user(&schi, arg, sizeof schi)) | |
1013 | return -EFAULT; | |
1014 | ||
1015 | switch (sony_audio_status) { | |
1016 | case CDROM_AUDIO_PLAY: | |
1017 | if (read_subcode() < 0) { | |
1018 | return -EIO; | |
1019 | } | |
1020 | break; | |
1021 | ||
1022 | case CDROM_AUDIO_PAUSED: | |
1023 | case CDROM_AUDIO_COMPLETED: | |
1024 | break; | |
1025 | ||
1026 | case CDROM_AUDIO_NO_STATUS: | |
1027 | schi.cdsc_audiostatus = sony_audio_status; | |
1028 | if (copy_to_user(arg, &schi, sizeof schi)) | |
1029 | return -EFAULT; | |
1030 | return 0; | |
1031 | break; | |
1032 | ||
1033 | case CDROM_AUDIO_INVALID: | |
1034 | case CDROM_AUDIO_ERROR: | |
1035 | default: | |
1036 | return -EIO; | |
1037 | } | |
1038 | ||
1039 | schi.cdsc_audiostatus = sony_audio_status; | |
1040 | schi.cdsc_adr = last_sony_subcode->address; | |
1041 | schi.cdsc_ctrl = last_sony_subcode->control; | |
1042 | schi.cdsc_trk = bcd_to_int(last_sony_subcode->track_num); | |
1043 | schi.cdsc_ind = bcd_to_int(last_sony_subcode->index_num); | |
1044 | if (schi.cdsc_format == CDROM_MSF) { | |
1045 | schi.cdsc_absaddr.msf.minute = bcd_to_int(last_sony_subcode->abs_msf[0]); | |
1046 | schi.cdsc_absaddr.msf.second = bcd_to_int(last_sony_subcode->abs_msf[1]); | |
1047 | schi.cdsc_absaddr.msf.frame = bcd_to_int(last_sony_subcode->abs_msf[2]); | |
1048 | ||
1049 | schi.cdsc_reladdr.msf.minute = bcd_to_int(last_sony_subcode->rel_msf[0]); | |
1050 | schi.cdsc_reladdr.msf.second = bcd_to_int(last_sony_subcode->rel_msf[1]); | |
1051 | schi.cdsc_reladdr.msf.frame = bcd_to_int(last_sony_subcode->rel_msf[2]); | |
1052 | } else if (schi.cdsc_format == CDROM_LBA) { | |
1053 | schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode->abs_msf); | |
1054 | schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode->rel_msf); | |
1055 | } | |
1056 | return copy_to_user(arg, &schi, sizeof schi) ? -EFAULT : 0; | |
1057 | } | |
1058 | ||
1059 | ||
1060 | /* | |
1061 | * The big ugly ioctl handler. | |
1062 | */ | |
1063 | static int | |
1064 | cdu_ioctl(struct inode *inode, | |
1065 | struct file *file, | |
1066 | unsigned int cmd, | |
1067 | unsigned long arg) | |
1068 | { | |
1069 | Byte status[2]; | |
1070 | Byte cmd_buff[10], params[10]; | |
1071 | int i; | |
1072 | int dsc_status; | |
1073 | void __user *argp = (void __user *)arg; | |
1074 | ||
1075 | if (check_drive_status() != 0) | |
1076 | return -EIO; | |
1077 | ||
1078 | switch (cmd) { | |
1079 | case CDROMSTART: /* Spin up the drive */ | |
1080 | if (spin_up_drive(status) < 0) { | |
1081 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTART)\n", | |
1082 | status[0]); | |
1083 | return -EIO; | |
1084 | } | |
1085 | return 0; | |
1086 | break; | |
1087 | ||
1088 | case CDROMSTOP: /* Spin down the drive */ | |
1089 | cmd_buff[0] = SONY535_HOLD; | |
1090 | do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | |
1091 | ||
1092 | /* | |
1093 | * Spin the drive down, ignoring the error if the disk was | |
1094 | * already not spinning. | |
1095 | */ | |
1096 | sony_audio_status = CDROM_AUDIO_NO_STATUS; | |
1097 | cmd_buff[0] = SONY535_SPIN_DOWN; | |
1098 | dsc_status = do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | |
1099 | if (((dsc_status < 0) && (dsc_status != BAD_STATUS)) || | |
1100 | ((status[0] & ~(SONY535_STATUS1_NOT_SPINNING)) != 0)) { | |
1101 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTOP)\n", | |
1102 | status[0]); | |
1103 | return -EIO; | |
1104 | } | |
1105 | return 0; | |
1106 | break; | |
1107 | ||
1108 | case CDROMPAUSE: /* Pause the drive */ | |
1109 | cmd_buff[0] = SONY535_HOLD; /* CDU-31 driver uses AUDIO_STOP, not pause */ | |
1110 | if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0) { | |
1111 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPAUSE)\n", | |
1112 | status[0]); | |
1113 | return -EIO; | |
1114 | } | |
1115 | /* Get the current position and save it for resuming */ | |
1116 | if (read_subcode() < 0) { | |
1117 | return -EIO; | |
1118 | } | |
1119 | cur_pos_msf[0] = last_sony_subcode->abs_msf[0]; | |
1120 | cur_pos_msf[1] = last_sony_subcode->abs_msf[1]; | |
1121 | cur_pos_msf[2] = last_sony_subcode->abs_msf[2]; | |
1122 | sony_audio_status = CDROM_AUDIO_PAUSED; | |
1123 | return 0; | |
1124 | break; | |
1125 | ||
1126 | case CDROMRESUME: /* Start the drive after being paused */ | |
1127 | set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status); | |
1128 | ||
1129 | if (sony_audio_status != CDROM_AUDIO_PAUSED) { | |
1130 | return -EINVAL; | |
1131 | } | |
1132 | spin_up_drive(status); | |
1133 | ||
1134 | /* Start the drive at the saved position. */ | |
1135 | cmd_buff[0] = SONY535_PLAY_AUDIO; | |
1136 | cmd_buff[1] = 0; /* play back starting at this address */ | |
1137 | cmd_buff[2] = cur_pos_msf[0]; | |
1138 | cmd_buff[3] = cur_pos_msf[1]; | |
1139 | cmd_buff[4] = cur_pos_msf[2]; | |
1140 | cmd_buff[5] = SONY535_PLAY_AUDIO; | |
1141 | cmd_buff[6] = 2; /* set ending address */ | |
1142 | cmd_buff[7] = final_pos_msf[0]; | |
1143 | cmd_buff[8] = final_pos_msf[1]; | |
1144 | cmd_buff[9] = final_pos_msf[2]; | |
1145 | if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) || | |
1146 | (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) { | |
1147 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMRESUME)\n", | |
1148 | status[0]); | |
1149 | return -EIO; | |
1150 | } | |
1151 | sony_audio_status = CDROM_AUDIO_PLAY; | |
1152 | return 0; | |
1153 | break; | |
1154 | ||
1155 | case CDROMPLAYMSF: /* Play starting at the given MSF address. */ | |
1156 | if (copy_from_user(params, argp, 6)) | |
1157 | return -EFAULT; | |
1158 | spin_up_drive(status); | |
1159 | set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status); | |
1160 | ||
1161 | /* The parameters are given in int, must be converted */ | |
1162 | for (i = 0; i < 3; i++) { | |
1163 | cmd_buff[2 + i] = int_to_bcd(params[i]); | |
1164 | cmd_buff[7 + i] = int_to_bcd(params[i + 3]); | |
1165 | } | |
1166 | cmd_buff[0] = SONY535_PLAY_AUDIO; | |
1167 | cmd_buff[1] = 0; /* play back starting at this address */ | |
1168 | /* cmd_buff[2-4] are filled in for loop above */ | |
1169 | cmd_buff[5] = SONY535_PLAY_AUDIO; | |
1170 | cmd_buff[6] = 2; /* set ending address */ | |
1171 | /* cmd_buff[7-9] are filled in for loop above */ | |
1172 | if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) || | |
1173 | (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) { | |
1174 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPLAYMSF)\n", | |
1175 | status[0]); | |
1176 | return -EIO; | |
1177 | } | |
1178 | /* Save the final position for pauses and resumes */ | |
1179 | final_pos_msf[0] = cmd_buff[7]; | |
1180 | final_pos_msf[1] = cmd_buff[8]; | |
1181 | final_pos_msf[2] = cmd_buff[9]; | |
1182 | sony_audio_status = CDROM_AUDIO_PLAY; | |
1183 | return 0; | |
1184 | break; | |
1185 | ||
1186 | case CDROMREADTOCHDR: /* Read the table of contents header */ | |
1187 | { | |
1188 | struct cdrom_tochdr __user *hdr = argp; | |
1189 | struct cdrom_tochdr loc_hdr; | |
1190 | ||
1191 | sony_get_toc(); | |
1192 | if (!sony_toc_read) | |
1193 | return -EIO; | |
1194 | loc_hdr.cdth_trk0 = bcd_to_int(sony_toc->first_track_num); | |
1195 | loc_hdr.cdth_trk1 = bcd_to_int(sony_toc->last_track_num); | |
1196 | if (copy_to_user(hdr, &loc_hdr, sizeof *hdr)) | |
1197 | return -EFAULT; | |
1198 | } | |
1199 | return 0; | |
1200 | break; | |
1201 | ||
1202 | case CDROMREADTOCENTRY: /* Read a given table of contents entry */ | |
1203 | { | |
1204 | struct cdrom_tocentry __user *entry = argp; | |
1205 | struct cdrom_tocentry loc_entry; | |
1206 | int track_idx; | |
1207 | Byte *msf_val = NULL; | |
1208 | ||
1209 | sony_get_toc(); | |
1210 | if (!sony_toc_read) { | |
1211 | return -EIO; | |
1212 | } | |
1213 | ||
1214 | if (copy_from_user(&loc_entry, entry, sizeof loc_entry)) | |
1215 | return -EFAULT; | |
1216 | ||
1217 | /* Lead out is handled separately since it is special. */ | |
1218 | if (loc_entry.cdte_track == CDROM_LEADOUT) { | |
1219 | loc_entry.cdte_adr = 0 /*sony_toc->address2 */ ; | |
1220 | loc_entry.cdte_ctrl = sony_toc->control2; | |
1221 | msf_val = sony_toc->lead_out_start_msf; | |
1222 | } else { | |
1223 | track_idx = find_track(int_to_bcd(loc_entry.cdte_track)); | |
1224 | if (track_idx < 0) | |
1225 | return -EINVAL; | |
1226 | loc_entry.cdte_adr = 0 /*sony_toc->tracks[track_idx].address */ ; | |
1227 | loc_entry.cdte_ctrl = sony_toc->tracks[track_idx].control; | |
1228 | msf_val = sony_toc->tracks[track_idx].track_start_msf; | |
1229 | } | |
1230 | ||
1231 | /* Logical buffer address or MSF format requested? */ | |
1232 | if (loc_entry.cdte_format == CDROM_LBA) { | |
1233 | loc_entry.cdte_addr.lba = msf_to_log(msf_val); | |
1234 | } else if (loc_entry.cdte_format == CDROM_MSF) { | |
1235 | loc_entry.cdte_addr.msf.minute = bcd_to_int(*msf_val); | |
1236 | loc_entry.cdte_addr.msf.second = bcd_to_int(*(msf_val + 1)); | |
1237 | loc_entry.cdte_addr.msf.frame = bcd_to_int(*(msf_val + 2)); | |
1238 | } | |
1239 | if (copy_to_user(entry, &loc_entry, sizeof *entry)) | |
1240 | return -EFAULT; | |
1241 | } | |
1242 | return 0; | |
1243 | break; | |
1244 | ||
1245 | case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ | |
1246 | { | |
1247 | struct cdrom_ti ti; | |
1248 | int track_idx; | |
1249 | ||
1250 | sony_get_toc(); | |
1251 | if (!sony_toc_read) | |
1252 | return -EIO; | |
1253 | ||
1254 | if (copy_from_user(&ti, argp, sizeof ti)) | |
1255 | return -EFAULT; | |
1256 | if ((ti.cdti_trk0 < sony_toc->first_track_num) | |
1257 | || (sony_toc->last_track_num < ti.cdti_trk0) | |
1258 | || (ti.cdti_trk1 < ti.cdti_trk0)) { | |
1259 | return -EINVAL; | |
1260 | } | |
1261 | track_idx = find_track(int_to_bcd(ti.cdti_trk0)); | |
1262 | if (track_idx < 0) | |
1263 | return -EINVAL; | |
1264 | params[1] = sony_toc->tracks[track_idx].track_start_msf[0]; | |
1265 | params[2] = sony_toc->tracks[track_idx].track_start_msf[1]; | |
1266 | params[3] = sony_toc->tracks[track_idx].track_start_msf[2]; | |
1267 | /* | |
1268 | * If we want to stop after the last track, use the lead-out | |
1269 | * MSF to do that. | |
1270 | */ | |
1271 | if (bcd_to_int(sony_toc->last_track_num) <= ti.cdti_trk1) { | |
1272 | log_to_msf(msf_to_log(sony_toc->lead_out_start_msf) - 1, | |
1273 | &(params[4])); | |
1274 | } else { | |
1275 | track_idx = find_track(int_to_bcd(ti.cdti_trk1 + 1)); | |
1276 | if (track_idx < 0) | |
1277 | return -EINVAL; | |
1278 | log_to_msf(msf_to_log(sony_toc->tracks[track_idx].track_start_msf) - 1, | |
1279 | &(params[4])); | |
1280 | } | |
1281 | params[0] = 0x03; | |
1282 | ||
1283 | spin_up_drive(status); | |
1284 | ||
1285 | set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status); | |
1286 | ||
1287 | /* Start the drive at the saved position. */ | |
1288 | cmd_buff[0] = SONY535_PLAY_AUDIO; | |
1289 | cmd_buff[1] = 0; /* play back starting at this address */ | |
1290 | cmd_buff[2] = params[1]; | |
1291 | cmd_buff[3] = params[2]; | |
1292 | cmd_buff[4] = params[3]; | |
1293 | cmd_buff[5] = SONY535_PLAY_AUDIO; | |
1294 | cmd_buff[6] = 2; /* set ending address */ | |
1295 | cmd_buff[7] = params[4]; | |
1296 | cmd_buff[8] = params[5]; | |
1297 | cmd_buff[9] = params[6]; | |
1298 | if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) || | |
1299 | (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) { | |
1300 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPLAYTRKIND)\n", | |
1301 | status[0]); | |
1302 | printk("... Params: %x %x %x %x %x %x %x\n", | |
1303 | params[0], params[1], params[2], | |
1304 | params[3], params[4], params[5], params[6]); | |
1305 | return -EIO; | |
1306 | } | |
1307 | /* Save the final position for pauses and resumes */ | |
1308 | final_pos_msf[0] = params[4]; | |
1309 | final_pos_msf[1] = params[5]; | |
1310 | final_pos_msf[2] = params[6]; | |
1311 | sony_audio_status = CDROM_AUDIO_PLAY; | |
1312 | return 0; | |
1313 | } | |
1314 | ||
1315 | case CDROMSUBCHNL: /* Get subchannel info */ | |
1316 | return sony_get_subchnl_info(argp); | |
1317 | ||
1318 | case CDROMVOLCTRL: /* Volume control. What volume does this change, anyway? */ | |
1319 | { | |
1320 | struct cdrom_volctrl volctrl; | |
1321 | ||
1322 | if (copy_from_user(&volctrl, argp, sizeof volctrl)) | |
1323 | return -EFAULT; | |
1324 | cmd_buff[0] = SONY535_SET_VOLUME; | |
1325 | cmd_buff[1] = volctrl.channel0; | |
1326 | cmd_buff[2] = volctrl.channel1; | |
1327 | if (do_sony_cmd(cmd_buff, 3, status, NULL, 0, 0) != 0) { | |
1328 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMVOLCTRL)\n", | |
1329 | status[0]); | |
1330 | return -EIO; | |
1331 | } | |
1332 | } | |
1333 | return 0; | |
1334 | ||
1335 | case CDROMEJECT: /* Eject the drive */ | |
1336 | cmd_buff[0] = SONY535_STOP; | |
1337 | do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | |
1338 | cmd_buff[0] = SONY535_SPIN_DOWN; | |
1339 | do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | |
1340 | ||
1341 | sony_audio_status = CDROM_AUDIO_INVALID; | |
1342 | cmd_buff[0] = SONY535_EJECT_CADDY; | |
1343 | if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0) { | |
1344 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMEJECT)\n", | |
1345 | status[0]); | |
1346 | return -EIO; | |
1347 | } | |
1348 | return 0; | |
1349 | break; | |
1350 | ||
1351 | default: | |
1352 | return -EINVAL; | |
1353 | } | |
1354 | } | |
1355 | ||
1356 | ||
1357 | /* | |
1358 | * Open the drive for operations. Spin the drive up and read the table of | |
1359 | * contents if these have not already been done. | |
1360 | */ | |
1361 | static int | |
1362 | cdu_open(struct inode *inode, | |
1363 | struct file *filp) | |
1364 | { | |
1365 | Byte status[2], cmd_buff[2]; | |
1366 | ||
1367 | if (sony_inuse) | |
1368 | return -EBUSY; | |
1369 | if (check_drive_status() != 0) | |
1370 | return -EIO; | |
1371 | sony_inuse = 1; | |
1372 | ||
1373 | if (spin_up_drive(status) != 0) { | |
1374 | printk(CDU535_MESSAGE_NAME " error 0x%.2x (cdu_open, spin up)\n", | |
1375 | status[0]); | |
1376 | sony_inuse = 0; | |
1377 | return -EIO; | |
1378 | } | |
1379 | sony_get_toc(); | |
1380 | if (!sony_toc_read) { | |
1381 | cmd_buff[0] = SONY535_SPIN_DOWN; | |
1382 | do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | |
1383 | sony_inuse = 0; | |
1384 | return -EIO; | |
1385 | } | |
1386 | check_disk_change(inode->i_bdev); | |
1387 | sony_usage++; | |
1388 | ||
1389 | #ifdef LOCK_DOORS | |
1390 | /* disable the eject button while mounted */ | |
1391 | cmd_buff[0] = SONY535_DISABLE_EJECT_BUTTON; | |
1392 | do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); | |
1393 | #endif | |
1394 | ||
1395 | return 0; | |
1396 | } | |
1397 | ||
1398 | ||
1399 | /* | |
1400 | * Close the drive. Spin it down if no task is using it. The spin | |
1401 | * down will fail if playing audio, so audio play is OK. | |
1402 | */ | |
1403 | static int | |
1404 | cdu_release(struct inode *inode, | |
1405 | struct file *filp) | |
1406 | { | |
1407 | Byte status[2], cmd_no; | |
1408 | ||
1409 | sony_inuse = 0; | |
1410 | ||
1411 | if (0 < sony_usage) { | |
1412 | sony_usage--; | |
1413 | } | |
1414 | if (sony_usage == 0) { | |
1415 | check_drive_status(); | |
1416 | ||
1417 | if (sony_audio_status != CDROM_AUDIO_PLAY) { | |
1418 | cmd_no = SONY535_SPIN_DOWN; | |
1419 | do_sony_cmd(&cmd_no, 1, status, NULL, 0, 0); | |
1420 | } | |
1421 | #ifdef LOCK_DOORS | |
1422 | /* enable the eject button after umount */ | |
1423 | cmd_no = SONY535_ENABLE_EJECT_BUTTON; | |
1424 | do_sony_cmd(&cmd_no, 1, status, NULL, 0, 0); | |
1425 | #endif | |
1426 | } | |
1427 | return 0; | |
1428 | } | |
1429 | ||
1430 | static struct block_device_operations cdu_fops = | |
1431 | { | |
1432 | .owner = THIS_MODULE, | |
1433 | .open = cdu_open, | |
1434 | .release = cdu_release, | |
1435 | .ioctl = cdu_ioctl, | |
1436 | .media_changed = cdu535_check_media_change, | |
1437 | }; | |
1438 | ||
1439 | static struct gendisk *cdu_disk; | |
1440 | ||
1441 | /* | |
1442 | * Initialize the driver. | |
1443 | */ | |
1444 | static int __init sony535_init(void) | |
1445 | { | |
1446 | struct s535_sony_drive_config drive_config; | |
1447 | Byte cmd_buff[3]; | |
1448 | Byte ret_buff[2]; | |
1449 | Byte status[2]; | |
1450 | unsigned long snap; | |
1451 | int got_result = 0; | |
1452 | int tmp_irq; | |
1453 | int i; | |
1454 | int err; | |
1455 | ||
1456 | /* Setting the base I/O address to 0 will disable it. */ | |
1457 | if ((sony535_cd_base_io == 0xffff)||(sony535_cd_base_io == 0)) | |
1458 | return 0; | |
1459 | ||
1460 | /* Set up all the register locations */ | |
1461 | result_reg = sony535_cd_base_io; | |
1462 | command_reg = sony535_cd_base_io; | |
1463 | data_reg = sony535_cd_base_io + 1; | |
1464 | read_status_reg = sony535_cd_base_io + 2; | |
1465 | select_unit_reg = sony535_cd_base_io + 3; | |
1466 | ||
1467 | #ifndef USE_IRQ | |
1468 | sony535_irq_used = 0; /* polling only until this is ready... */ | |
1469 | #endif | |
1470 | /* we need to poll until things get initialized */ | |
1471 | tmp_irq = sony535_irq_used; | |
1472 | sony535_irq_used = 0; | |
1473 | ||
1474 | #if DEBUG > 0 | |
1475 | printk(KERN_INFO CDU535_MESSAGE_NAME ": probing base address %03X\n", | |
1476 | sony535_cd_base_io); | |
1477 | #endif | |
1478 | /* look for the CD-ROM, follows the procedure in the DOS driver */ | |
1479 | inb(select_unit_reg); | |
1480 | /* wait for 40 18 Hz ticks (reverse-engineered from DOS driver) */ | |
2ddee1b7 | 1481 | schedule_timeout_interruptible((HZ+17)*40/18); |
1da177e4 LT |
1482 | inb(result_reg); |
1483 | ||
1484 | outb(0, read_status_reg); /* does a reset? */ | |
1485 | snap = jiffies; | |
1486 | while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { | |
1487 | select_unit(0); | |
1488 | if (inb(result_reg) != 0xff) { | |
1489 | got_result = 1; | |
1490 | break; | |
1491 | } | |
1492 | sony_sleep(); | |
1493 | } | |
1494 | ||
1495 | if (!got_result || check_drive_status() == TIME_OUT) | |
1496 | goto Enodev; | |
1497 | ||
1498 | /* CD-ROM drive responded -- get the drive configuration */ | |
1499 | cmd_buff[0] = SONY535_INQUIRY; | |
1500 | if (do_sony_cmd(cmd_buff, 1, status, (Byte *)&drive_config, 28, 1) != 0) | |
1501 | goto Enodev; | |
1502 | ||
1503 | /* was able to get the configuration, | |
1504 | * set drive mode as rest of init | |
1505 | */ | |
1506 | #if DEBUG > 0 | |
1507 | /* 0x50 == CADDY_NOT_INSERTED | NOT_SPINNING */ | |
1508 | if ( (status[0] & 0x7f) != 0 && (status[0] & 0x7f) != 0x50 ) | |
1509 | printk(CDU535_MESSAGE_NAME | |
1510 | "Inquiry command returned status = 0x%x\n", status[0]); | |
1511 | #endif | |
1512 | /* now ready to use interrupts, if available */ | |
1513 | sony535_irq_used = tmp_irq; | |
1514 | ||
1515 | /* A negative sony535_irq_used will attempt an autoirq. */ | |
1516 | if (sony535_irq_used < 0) { | |
1517 | unsigned long irq_mask, delay; | |
1518 | ||
1519 | irq_mask = probe_irq_on(); | |
1520 | enable_interrupts(); | |
1521 | outb(0, read_status_reg); /* does a reset? */ | |
1522 | delay = jiffies + HZ/10; | |
1523 | while (time_before(jiffies, delay)) ; | |
1524 | ||
1525 | sony535_irq_used = probe_irq_off(irq_mask); | |
1526 | disable_interrupts(); | |
1527 | } | |
1528 | if (sony535_irq_used > 0) { | |
1529 | if (request_irq(sony535_irq_used, cdu535_interrupt, | |
dace1453 | 1530 | IRQF_DISABLED, CDU535_HANDLE, NULL)) { |
1da177e4 LT |
1531 | printk("Unable to grab IRQ%d for the " CDU535_MESSAGE_NAME |
1532 | " driver; polling instead.\n", sony535_irq_used); | |
1533 | sony535_irq_used = 0; | |
1534 | } | |
1535 | } | |
1536 | cmd_buff[0] = SONY535_SET_DRIVE_MODE; | |
1537 | cmd_buff[1] = 0x0; /* default audio */ | |
1538 | if (do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1) != 0) | |
1539 | goto Enodev_irq; | |
1540 | ||
1541 | /* set the drive mode successful, we are set! */ | |
1542 | sony_buffer_size = SONY535_BUFFER_SIZE; | |
1543 | sony_buffer_sectors = sony_buffer_size / CDU535_BLOCK_SIZE; | |
1544 | ||
1545 | printk(KERN_INFO CDU535_MESSAGE_NAME " I/F CDROM : %8.8s %16.16s %4.4s", | |
1546 | drive_config.vendor_id, | |
1547 | drive_config.product_id, | |
1548 | drive_config.product_rev_level); | |
1549 | printk(" base address %03X, ", sony535_cd_base_io); | |
1550 | if (tmp_irq > 0) | |
1551 | printk("IRQ%d, ", tmp_irq); | |
1552 | printk("using %d byte buffer\n", sony_buffer_size); | |
1553 | ||
1554 | if (register_blkdev(MAJOR_NR, CDU535_HANDLE)) { | |
1555 | err = -EIO; | |
1556 | goto out1; | |
1557 | } | |
1558 | sonycd535_queue = blk_init_queue(do_cdu535_request, &sonycd535_lock); | |
1559 | if (!sonycd535_queue) { | |
1560 | err = -ENOMEM; | |
1561 | goto out1a; | |
1562 | } | |
1563 | ||
1564 | blk_queue_hardsect_size(sonycd535_queue, CDU535_BLOCK_SIZE); | |
1565 | sony_toc = kmalloc(sizeof(struct s535_sony_toc), GFP_KERNEL); | |
1566 | err = -ENOMEM; | |
1567 | if (!sony_toc) | |
1568 | goto out2; | |
1569 | last_sony_subcode = kmalloc(sizeof(struct s535_sony_subcode), GFP_KERNEL); | |
1570 | if (!last_sony_subcode) | |
1571 | goto out3; | |
1572 | sony_buffer = kmalloc(sizeof(Byte *) * sony_buffer_sectors, GFP_KERNEL); | |
1573 | if (!sony_buffer) | |
1574 | goto out4; | |
1575 | for (i = 0; i < sony_buffer_sectors; i++) { | |
1576 | sony_buffer[i] = kmalloc(CDU535_BLOCK_SIZE, GFP_KERNEL); | |
1577 | if (!sony_buffer[i]) { | |
1578 | while (--i>=0) | |
1579 | kfree(sony_buffer[i]); | |
1580 | goto out5; | |
1581 | } | |
1582 | } | |
1583 | initialized = 1; | |
1584 | ||
1585 | cdu_disk = alloc_disk(1); | |
1586 | if (!cdu_disk) | |
1587 | goto out6; | |
1588 | cdu_disk->major = MAJOR_NR; | |
1589 | cdu_disk->first_minor = 0; | |
1590 | cdu_disk->fops = &cdu_fops; | |
1591 | sprintf(cdu_disk->disk_name, "cdu"); | |
1da177e4 LT |
1592 | |
1593 | if (!request_region(sony535_cd_base_io, 4, CDU535_HANDLE)) { | |
1594 | printk(KERN_WARNING"sonycd535: Unable to request region 0x%x\n", | |
1595 | sony535_cd_base_io); | |
1596 | goto out7; | |
1597 | } | |
1598 | cdu_disk->queue = sonycd535_queue; | |
1599 | add_disk(cdu_disk); | |
1600 | return 0; | |
1601 | ||
1602 | out7: | |
1603 | put_disk(cdu_disk); | |
1604 | out6: | |
1605 | for (i = 0; i < sony_buffer_sectors; i++) | |
89e0b113 | 1606 | kfree(sony_buffer[i]); |
1da177e4 LT |
1607 | out5: |
1608 | kfree(sony_buffer); | |
1609 | out4: | |
1610 | kfree(last_sony_subcode); | |
1611 | out3: | |
1612 | kfree(sony_toc); | |
1613 | out2: | |
1614 | blk_cleanup_queue(sonycd535_queue); | |
1615 | out1a: | |
1616 | unregister_blkdev(MAJOR_NR, CDU535_HANDLE); | |
1617 | out1: | |
1618 | if (sony535_irq_used) | |
1619 | free_irq(sony535_irq_used, NULL); | |
1620 | return err; | |
1621 | Enodev_irq: | |
1622 | if (sony535_irq_used) | |
1623 | free_irq(sony535_irq_used, NULL); | |
1624 | Enodev: | |
1625 | printk("Did not find a " CDU535_MESSAGE_NAME " drive\n"); | |
1626 | return -EIO; | |
1627 | } | |
1628 | ||
1629 | #ifndef MODULE | |
1630 | ||
1631 | /* | |
1632 | * accept "kernel command line" parameters | |
1633 | * (added by emoenke@gwdg.de) | |
1634 | * | |
1635 | * use: tell LILO: | |
1636 | * sonycd535=0x320 | |
1637 | * | |
1638 | * the address value has to be the existing CDROM port address. | |
1639 | */ | |
1640 | static int __init | |
1641 | sonycd535_setup(char *strings) | |
1642 | { | |
1643 | int ints[3]; | |
1644 | (void)get_options(strings, ARRAY_SIZE(ints), ints); | |
1645 | /* if IRQ change and default io base desired, | |
1646 | * then call with io base of 0 | |
1647 | */ | |
1648 | if (ints[0] > 0) | |
1649 | if (ints[1] != 0) | |
1650 | sony535_cd_base_io = ints[1]; | |
1651 | if (ints[0] > 1) | |
1652 | sony535_irq_used = ints[2]; | |
1653 | if ((strings != NULL) && (*strings != '\0')) | |
1654 | printk(CDU535_MESSAGE_NAME | |
1655 | ": Warning: Unknown interface type: %s\n", strings); | |
1656 | ||
1657 | return 1; | |
1658 | } | |
1659 | ||
1660 | __setup("sonycd535=", sonycd535_setup); | |
1661 | ||
1662 | #endif /* MODULE */ | |
1663 | ||
1664 | static void __exit | |
1665 | sony535_exit(void) | |
1666 | { | |
1667 | int i; | |
1668 | ||
1669 | release_region(sony535_cd_base_io, 4); | |
1670 | for (i = 0; i < sony_buffer_sectors; i++) | |
1671 | kfree(sony_buffer[i]); | |
1672 | kfree(sony_buffer); | |
1673 | kfree(last_sony_subcode); | |
1674 | kfree(sony_toc); | |
1675 | del_gendisk(cdu_disk); | |
1676 | put_disk(cdu_disk); | |
1677 | blk_cleanup_queue(sonycd535_queue); | |
1678 | if (unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL) | |
1679 | printk("Uh oh, couldn't unregister " CDU535_HANDLE "\n"); | |
1680 | else | |
1681 | printk(KERN_INFO CDU535_HANDLE " module released\n"); | |
1682 | } | |
1683 | ||
1684 | module_init(sony535_init); | |
1685 | module_exit(sony535_exit); | |
1686 | ||
1687 | ||
1688 | MODULE_LICENSE("GPL"); | |
1689 | MODULE_ALIAS_BLOCKDEV_MAJOR(CDU535_CDROM_MAJOR); |