Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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++) |
Jesper Juhl | 89e0b11 | 2005-06-25 14:59:14 -0700 | [diff] [blame^] | 1608 | kfree(sony_buffer[i]); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1609 | out5: |
| 1610 | kfree(sony_buffer); |
| 1611 | out4: |
| 1612 | kfree(last_sony_subcode); |
| 1613 | out3: |
| 1614 | kfree(sony_toc); |
| 1615 | out2: |
| 1616 | blk_cleanup_queue(sonycd535_queue); |
| 1617 | out1a: |
| 1618 | unregister_blkdev(MAJOR_NR, CDU535_HANDLE); |
| 1619 | out1: |
| 1620 | if (sony535_irq_used) |
| 1621 | free_irq(sony535_irq_used, NULL); |
| 1622 | return err; |
| 1623 | Enodev_irq: |
| 1624 | if (sony535_irq_used) |
| 1625 | free_irq(sony535_irq_used, NULL); |
| 1626 | Enodev: |
| 1627 | printk("Did not find a " CDU535_MESSAGE_NAME " drive\n"); |
| 1628 | return -EIO; |
| 1629 | } |
| 1630 | |
| 1631 | #ifndef MODULE |
| 1632 | |
| 1633 | /* |
| 1634 | * accept "kernel command line" parameters |
| 1635 | * (added by emoenke@gwdg.de) |
| 1636 | * |
| 1637 | * use: tell LILO: |
| 1638 | * sonycd535=0x320 |
| 1639 | * |
| 1640 | * the address value has to be the existing CDROM port address. |
| 1641 | */ |
| 1642 | static int __init |
| 1643 | sonycd535_setup(char *strings) |
| 1644 | { |
| 1645 | int ints[3]; |
| 1646 | (void)get_options(strings, ARRAY_SIZE(ints), ints); |
| 1647 | /* if IRQ change and default io base desired, |
| 1648 | * then call with io base of 0 |
| 1649 | */ |
| 1650 | if (ints[0] > 0) |
| 1651 | if (ints[1] != 0) |
| 1652 | sony535_cd_base_io = ints[1]; |
| 1653 | if (ints[0] > 1) |
| 1654 | sony535_irq_used = ints[2]; |
| 1655 | if ((strings != NULL) && (*strings != '\0')) |
| 1656 | printk(CDU535_MESSAGE_NAME |
| 1657 | ": Warning: Unknown interface type: %s\n", strings); |
| 1658 | |
| 1659 | return 1; |
| 1660 | } |
| 1661 | |
| 1662 | __setup("sonycd535=", sonycd535_setup); |
| 1663 | |
| 1664 | #endif /* MODULE */ |
| 1665 | |
| 1666 | static void __exit |
| 1667 | sony535_exit(void) |
| 1668 | { |
| 1669 | int i; |
| 1670 | |
| 1671 | release_region(sony535_cd_base_io, 4); |
| 1672 | for (i = 0; i < sony_buffer_sectors; i++) |
| 1673 | kfree(sony_buffer[i]); |
| 1674 | kfree(sony_buffer); |
| 1675 | kfree(last_sony_subcode); |
| 1676 | kfree(sony_toc); |
| 1677 | del_gendisk(cdu_disk); |
| 1678 | put_disk(cdu_disk); |
| 1679 | blk_cleanup_queue(sonycd535_queue); |
| 1680 | if (unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL) |
| 1681 | printk("Uh oh, couldn't unregister " CDU535_HANDLE "\n"); |
| 1682 | else |
| 1683 | printk(KERN_INFO CDU535_HANDLE " module released\n"); |
| 1684 | } |
| 1685 | |
| 1686 | module_init(sony535_init); |
| 1687 | module_exit(sony535_exit); |
| 1688 | |
| 1689 | |
| 1690 | MODULE_LICENSE("GPL"); |
| 1691 | MODULE_ALIAS_BLOCKDEV_MAJOR(CDU535_CDROM_MAJOR); |