diff options
Diffstat (limited to 'drivers/cdrom/sonycd535.c')
-rw-r--r-- | drivers/cdrom/sonycd535.c | 1692 |
1 files changed, 1692 insertions, 0 deletions
diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c new file mode 100644 index 000000000000..f4be7bfd6675 --- /dev/null +++ b/drivers/cdrom/sonycd535.c | |||
@@ -0,0 +1,1692 @@ | |||
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 | ||
325 | cdu535_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
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) */ | ||
1481 | set_current_state(TASK_INTERRUPTIBLE); | ||
1482 | schedule_timeout((HZ+17)*40/18); | ||
1483 | inb(result_reg); | ||
1484 | |||
1485 | outb(0, read_status_reg); /* does a reset? */ | ||
1486 | snap = jiffies; | ||
1487 | while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { | ||
1488 | select_unit(0); | ||
1489 | if (inb(result_reg) != 0xff) { | ||
1490 | got_result = 1; | ||
1491 | break; | ||
1492 | } | ||
1493 | sony_sleep(); | ||
1494 | } | ||
1495 | |||
1496 | if (!got_result || check_drive_status() == TIME_OUT) | ||
1497 | goto Enodev; | ||
1498 | |||
1499 | /* CD-ROM drive responded -- get the drive configuration */ | ||
1500 | cmd_buff[0] = SONY535_INQUIRY; | ||
1501 | if (do_sony_cmd(cmd_buff, 1, status, (Byte *)&drive_config, 28, 1) != 0) | ||
1502 | goto Enodev; | ||
1503 | |||
1504 | /* was able to get the configuration, | ||
1505 | * set drive mode as rest of init | ||
1506 | */ | ||
1507 | #if DEBUG > 0 | ||
1508 | /* 0x50 == CADDY_NOT_INSERTED | NOT_SPINNING */ | ||
1509 | if ( (status[0] & 0x7f) != 0 && (status[0] & 0x7f) != 0x50 ) | ||
1510 | printk(CDU535_MESSAGE_NAME | ||
1511 | "Inquiry command returned status = 0x%x\n", status[0]); | ||
1512 | #endif | ||
1513 | /* now ready to use interrupts, if available */ | ||
1514 | sony535_irq_used = tmp_irq; | ||
1515 | |||
1516 | /* A negative sony535_irq_used will attempt an autoirq. */ | ||
1517 | if (sony535_irq_used < 0) { | ||
1518 | unsigned long irq_mask, delay; | ||
1519 | |||
1520 | irq_mask = probe_irq_on(); | ||
1521 | enable_interrupts(); | ||
1522 | outb(0, read_status_reg); /* does a reset? */ | ||
1523 | delay = jiffies + HZ/10; | ||
1524 | while (time_before(jiffies, delay)) ; | ||
1525 | |||
1526 | sony535_irq_used = probe_irq_off(irq_mask); | ||
1527 | disable_interrupts(); | ||
1528 | } | ||
1529 | if (sony535_irq_used > 0) { | ||
1530 | if (request_irq(sony535_irq_used, cdu535_interrupt, | ||
1531 | SA_INTERRUPT, CDU535_HANDLE, NULL)) { | ||
1532 | printk("Unable to grab IRQ%d for the " CDU535_MESSAGE_NAME | ||
1533 | " driver; polling instead.\n", sony535_irq_used); | ||
1534 | sony535_irq_used = 0; | ||
1535 | } | ||
1536 | } | ||
1537 | cmd_buff[0] = SONY535_SET_DRIVE_MODE; | ||
1538 | cmd_buff[1] = 0x0; /* default audio */ | ||
1539 | if (do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1) != 0) | ||
1540 | goto Enodev_irq; | ||
1541 | |||
1542 | /* set the drive mode successful, we are set! */ | ||
1543 | sony_buffer_size = SONY535_BUFFER_SIZE; | ||
1544 | sony_buffer_sectors = sony_buffer_size / CDU535_BLOCK_SIZE; | ||
1545 | |||
1546 | printk(KERN_INFO CDU535_MESSAGE_NAME " I/F CDROM : %8.8s %16.16s %4.4s", | ||
1547 | drive_config.vendor_id, | ||
1548 | drive_config.product_id, | ||
1549 | drive_config.product_rev_level); | ||
1550 | printk(" base address %03X, ", sony535_cd_base_io); | ||
1551 | if (tmp_irq > 0) | ||
1552 | printk("IRQ%d, ", tmp_irq); | ||
1553 | printk("using %d byte buffer\n", sony_buffer_size); | ||
1554 | |||
1555 | if (register_blkdev(MAJOR_NR, CDU535_HANDLE)) { | ||
1556 | err = -EIO; | ||
1557 | goto out1; | ||
1558 | } | ||
1559 | sonycd535_queue = blk_init_queue(do_cdu535_request, &sonycd535_lock); | ||
1560 | if (!sonycd535_queue) { | ||
1561 | err = -ENOMEM; | ||
1562 | goto out1a; | ||
1563 | } | ||
1564 | |||
1565 | blk_queue_hardsect_size(sonycd535_queue, CDU535_BLOCK_SIZE); | ||
1566 | sony_toc = kmalloc(sizeof(struct s535_sony_toc), GFP_KERNEL); | ||
1567 | err = -ENOMEM; | ||
1568 | if (!sony_toc) | ||
1569 | goto out2; | ||
1570 | last_sony_subcode = kmalloc(sizeof(struct s535_sony_subcode), GFP_KERNEL); | ||
1571 | if (!last_sony_subcode) | ||
1572 | goto out3; | ||
1573 | sony_buffer = kmalloc(sizeof(Byte *) * sony_buffer_sectors, GFP_KERNEL); | ||
1574 | if (!sony_buffer) | ||
1575 | goto out4; | ||
1576 | for (i = 0; i < sony_buffer_sectors; i++) { | ||
1577 | sony_buffer[i] = kmalloc(CDU535_BLOCK_SIZE, GFP_KERNEL); | ||
1578 | if (!sony_buffer[i]) { | ||
1579 | while (--i>=0) | ||
1580 | kfree(sony_buffer[i]); | ||
1581 | goto out5; | ||
1582 | } | ||
1583 | } | ||
1584 | initialized = 1; | ||
1585 | |||
1586 | cdu_disk = alloc_disk(1); | ||
1587 | if (!cdu_disk) | ||
1588 | goto out6; | ||
1589 | cdu_disk->major = MAJOR_NR; | ||
1590 | cdu_disk->first_minor = 0; | ||
1591 | cdu_disk->fops = &cdu_fops; | ||
1592 | sprintf(cdu_disk->disk_name, "cdu"); | ||
1593 | sprintf(cdu_disk->devfs_name, "cdu535"); | ||
1594 | |||
1595 | if (!request_region(sony535_cd_base_io, 4, CDU535_HANDLE)) { | ||
1596 | printk(KERN_WARNING"sonycd535: Unable to request region 0x%x\n", | ||
1597 | sony535_cd_base_io); | ||
1598 | goto out7; | ||
1599 | } | ||
1600 | cdu_disk->queue = sonycd535_queue; | ||
1601 | add_disk(cdu_disk); | ||
1602 | return 0; | ||
1603 | |||
1604 | out7: | ||
1605 | put_disk(cdu_disk); | ||
1606 | out6: | ||
1607 | for (i = 0; i < sony_buffer_sectors; i++) | ||
1608 | if (sony_buffer[i]) | ||
1609 | kfree(sony_buffer[i]); | ||
1610 | out5: | ||
1611 | kfree(sony_buffer); | ||
1612 | out4: | ||
1613 | kfree(last_sony_subcode); | ||
1614 | out3: | ||
1615 | kfree(sony_toc); | ||
1616 | out2: | ||
1617 | blk_cleanup_queue(sonycd535_queue); | ||
1618 | out1a: | ||
1619 | unregister_blkdev(MAJOR_NR, CDU535_HANDLE); | ||
1620 | out1: | ||
1621 | if (sony535_irq_used) | ||
1622 | free_irq(sony535_irq_used, NULL); | ||
1623 | return err; | ||
1624 | Enodev_irq: | ||
1625 | if (sony535_irq_used) | ||
1626 | free_irq(sony535_irq_used, NULL); | ||
1627 | Enodev: | ||
1628 | printk("Did not find a " CDU535_MESSAGE_NAME " drive\n"); | ||
1629 | return -EIO; | ||
1630 | } | ||
1631 | |||
1632 | #ifndef MODULE | ||
1633 | |||
1634 | /* | ||
1635 | * accept "kernel command line" parameters | ||
1636 | * (added by emoenke@gwdg.de) | ||
1637 | * | ||
1638 | * use: tell LILO: | ||
1639 | * sonycd535=0x320 | ||
1640 | * | ||
1641 | * the address value has to be the existing CDROM port address. | ||
1642 | */ | ||
1643 | static int __init | ||
1644 | sonycd535_setup(char *strings) | ||
1645 | { | ||
1646 | int ints[3]; | ||
1647 | (void)get_options(strings, ARRAY_SIZE(ints), ints); | ||
1648 | /* if IRQ change and default io base desired, | ||
1649 | * then call with io base of 0 | ||
1650 | */ | ||
1651 | if (ints[0] > 0) | ||
1652 | if (ints[1] != 0) | ||
1653 | sony535_cd_base_io = ints[1]; | ||
1654 | if (ints[0] > 1) | ||
1655 | sony535_irq_used = ints[2]; | ||
1656 | if ((strings != NULL) && (*strings != '\0')) | ||
1657 | printk(CDU535_MESSAGE_NAME | ||
1658 | ": Warning: Unknown interface type: %s\n", strings); | ||
1659 | |||
1660 | return 1; | ||
1661 | } | ||
1662 | |||
1663 | __setup("sonycd535=", sonycd535_setup); | ||
1664 | |||
1665 | #endif /* MODULE */ | ||
1666 | |||
1667 | static void __exit | ||
1668 | sony535_exit(void) | ||
1669 | { | ||
1670 | int i; | ||
1671 | |||
1672 | release_region(sony535_cd_base_io, 4); | ||
1673 | for (i = 0; i < sony_buffer_sectors; i++) | ||
1674 | kfree(sony_buffer[i]); | ||
1675 | kfree(sony_buffer); | ||
1676 | kfree(last_sony_subcode); | ||
1677 | kfree(sony_toc); | ||
1678 | del_gendisk(cdu_disk); | ||
1679 | put_disk(cdu_disk); | ||
1680 | blk_cleanup_queue(sonycd535_queue); | ||
1681 | if (unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL) | ||
1682 | printk("Uh oh, couldn't unregister " CDU535_HANDLE "\n"); | ||
1683 | else | ||
1684 | printk(KERN_INFO CDU535_HANDLE " module released\n"); | ||
1685 | } | ||
1686 | |||
1687 | module_init(sony535_init); | ||
1688 | module_exit(sony535_exit); | ||
1689 | |||
1690 | |||
1691 | MODULE_LICENSE("GPL"); | ||
1692 | MODULE_ALIAS_BLOCKDEV_MAJOR(CDU535_CDROM_MAJOR); | ||