From: Jens Axboe Following patch adds mt rainier support to the cdrom uniform layer (it works with atapi and scsi/usb). 25-akpm/drivers/cdrom/cdrom.c | 364 ++++++++++++++++++++++++++++++++++++++++-- 25-akpm/drivers/ide/ide-cd.c | 197 ++++++++++++++-------- 25-akpm/drivers/ide/ide-cd.h | 11 + 25-akpm/drivers/scsi/sr.c | 24 ++ 25-akpm/include/linux/cdrom.h | 285 +++++++++++++++++++++----------- 5 files changed, 699 insertions(+), 182 deletions(-) diff -puN drivers/cdrom/cdrom.c~mt-ranier-support drivers/cdrom/cdrom.c --- 25/drivers/cdrom/cdrom.c~mt-ranier-support Sat Dec 20 21:11:23 2003 +++ 25-akpm/drivers/cdrom/cdrom.c Sat Dec 20 21:11:23 2003 @@ -228,10 +228,16 @@ 3.12 Oct 18, 2000 - Jens Axboe -- Use quiet bit on packet commands not known to work + 3.20 Dec 17, 2003 - Jens Axboe + -- Various fixes and lots of cleanups not listed :-) + -- Locking fixes + -- Mt Rainier support + -- DVD-RAM write open fixes + -------------------------------------------------------------------------*/ -#define REVISION "Revision: 3.12" -#define VERSION "Id: cdrom.c 3.12 2000/10/18" +#define REVISION "Revision: 3.20" +#define VERSION "Id: cdrom.c 3.20 2003/12/17" /* I use an error-log mask to give fine grain control over the type of messages dumped to the system logs. The available masks include: */ @@ -282,11 +288,25 @@ static int autoeject; static int lockdoor = 1; /* will we ever get to use this... sigh. */ static int check_media_type; +/* automatically restart mrw format */ +static int mrw_format_restart = 1; MODULE_PARM(debug, "i"); MODULE_PARM(autoclose, "i"); MODULE_PARM(autoeject, "i"); MODULE_PARM(lockdoor, "i"); MODULE_PARM(check_media_type, "i"); +MODULE_PARM(mrw_format_restart, "i"); + +static spinlock_t cdrom_lock = SPIN_LOCK_UNLOCKED; + +static const char *mrw_format_status[] = { + "not mrw", + "bgformat inactive", + "bgformat active", + "mrw complete", +}; + +static const char *mrw_address_space[] = { "DMA", "GAA" }; #if (ERRLOGMASK!=CD_NOTHING) #define cdinfo(type, fmt, args...) \ @@ -325,6 +345,10 @@ int cdrom_get_last_written(struct cdrom_ static int cdrom_get_next_writable(struct cdrom_device_info *, long *); static void cdrom_count_tracks(struct cdrom_device_info *, tracktype*); +static int cdrom_mrw_exit(struct cdrom_device_info *cdi); + +static int cdrom_get_disc_info(struct cdrom_device_info *cdi, disc_information *di); + #ifdef CONFIG_SYSCTL static void cdrom_sysctl_register(void); #endif /* CONFIG_SYSCTL */ @@ -347,13 +371,14 @@ int register_cdrom(struct cdrom_device_i if (cdo->open == NULL || cdo->release == NULL) return -2; - if ( !banner_printed ) { + if (!banner_printed) { printk(KERN_INFO "Uniform CD-ROM driver " REVISION "\n"); banner_printed = 1; #ifdef CONFIG_SYSCTL cdrom_sysctl_register(); #endif /* CONFIG_SYSCTL */ } + ENSURE(drive_status, CDC_DRIVE_STATUS ); ENSURE(media_changed, CDC_MEDIA_CHANGED); ENSURE(tray_move, CDC_CLOSE_TRAY | CDC_OPEN_TRAY); @@ -379,9 +404,14 @@ int register_cdrom(struct cdrom_device_i if (check_media_type==1) cdi->options |= (int) CDO_CHECK_TYPE; + if (CDROM_CAN(CDC_MRW_W)) + cdi->exit = cdrom_mrw_exit; + cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); + spin_lock(&cdrom_lock); cdi->next = topCdromPtr; topCdromPtr = cdi; + spin_unlock(&cdrom_lock); return 0; } #undef ENSURE @@ -392,23 +422,305 @@ int unregister_cdrom(struct cdrom_device cdinfo(CD_OPEN, "entering unregister_cdrom\n"); prev = NULL; + spin_lock(&cdrom_lock); cdi = topCdromPtr; while (cdi && cdi != unreg) { prev = cdi; cdi = cdi->next; } - if (cdi == NULL) + if (cdi == NULL) { + spin_unlock(&cdrom_lock); return -2; + } if (prev) prev->next = cdi->next; else topCdromPtr = cdi->next; + + spin_unlock(&cdrom_lock); + + if (cdi->exit) + cdi->exit(cdi); + cdi->ops->n_minors--; cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name); return 0; } +int cdrom_get_media_event(struct cdrom_device_info *cdi, + struct media_event_desc *med) +{ + struct cdrom_generic_command cgc; + unsigned char buffer[8]; + struct event_header *eh = (struct event_header *) buffer; + + init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION; + cgc.cmd[1] = 1; /* IMMED */ + cgc.cmd[4] = 1 << 4; /* media event */ + cgc.cmd[8] = sizeof(buffer); + cgc.quiet = 1; + + if (cdi->ops->generic_packet(cdi, &cgc)) + return 1; + + if (be16_to_cpu(eh->data_len) < sizeof(*med)) + return 1; + + memcpy(med, &buffer[sizeof(*eh)], sizeof(*med)); + return 0; +} + +/* + * the first prototypes used 0x2c as the page code for the mrw mode page, + * subsequently this was changed to 0x03. probe the one used by this drive + */ +int cdrom_mrw_probe_pc(struct cdrom_device_info *cdi) +{ + struct cdrom_generic_command cgc; + char buffer[16]; + + init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + + cgc.timeout = HZ; + cgc.quiet = 1; + + if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC, 0)) { + cdi->mrw_mode_page = MRW_MODE_PC; + return 0; + } else if (!cdrom_mode_sense(cdi, &cgc, MRW_MODE_PC_PRE1, 0)) { + cdi->mrw_mode_page = MRW_MODE_PC_PRE1; + return 0; + } + + printk(KERN_ERR "cdrom: %s: unknown mrw mode page\n", cdi->name); + return 1; +} + +int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write) +{ + struct cdrom_generic_command cgc; + struct mrw_feature_desc *mfd; + unsigned char buffer[16]; + int ret; + + init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + + cgc.cmd[0] = GPCMD_GET_CONFIGURATION; + cgc.cmd[3] = CDF_MRW; + cgc.cmd[8] = sizeof(buffer); + cgc.quiet = 1; + + if ((ret = cdi->ops->generic_packet(cdi, &cgc))) + return ret; + + mfd = (struct mrw_feature_desc *)&buffer[sizeof(struct feature_header)]; + *write = mfd->write; + + if ((ret = cdrom_mrw_probe_pc(cdi))) + return ret; + + return 0; +} + +static int cdrom_mrw_bgformat(struct cdrom_device_info *cdi, int cont) +{ + struct cdrom_generic_command cgc; + unsigned char buffer[12]; + int ret; + + printk(KERN_INFO "cdrom: %sstarting format\n", cont ? "Re" : ""); + + /* + * FmtData bit set (bit 4), format type is 1 + */ + init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_WRITE); + cgc.cmd[0] = GPCMD_FORMAT_UNIT; + cgc.cmd[1] = (1 << 4) | 1; + + cgc.timeout = 5 * 60 * HZ; + + /* + * 4 byte format list header, 8 byte format list descriptor + */ + buffer[1] = 1 << 1; + buffer[3] = 8; + + /* + * nr_blocks field + */ + buffer[4] = 0xff; + buffer[5] = 0xff; + buffer[6] = 0xff; + buffer[7] = 0xff; + + buffer[8] = 0x24 << 2; + buffer[11] = cont; + + ret = cdi->ops->generic_packet(cdi, &cgc); + if (ret) + printk(KERN_INFO "cdrom: bgformat failed\n"); + + return ret; +} + +static int cdrom_mrw_bgformat_susp(struct cdrom_device_info *cdi, int immed) +{ + struct cdrom_generic_command cgc; + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.cmd[0] = GPCMD_CLOSE_TRACK; + + /* + * Session = 1, Track = 0 + */ + cgc.cmd[1] = !!immed; + cgc.cmd[2] = 1 << 1; + + cgc.timeout = 5 * 60 * HZ; + + return cdi->ops->generic_packet(cdi, &cgc); +} + +static int cdrom_flush_cache(struct cdrom_device_info *cdi) +{ + struct cdrom_generic_command cgc; + + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); + cgc.cmd[0] = GPCMD_FLUSH_CACHE; + + cgc.timeout = 5 * 60 * HZ; + + return cdi->ops->generic_packet(cdi, &cgc); +} + +static int cdrom_mrw_exit(struct cdrom_device_info *cdi) +{ + disc_information di; + int ret = 0; + + if (cdrom_get_disc_info(cdi, &di)) + return 1; + + if (di.mrw_status == CDM_MRW_BGFORMAT_ACTIVE) { + printk(KERN_INFO "cdrom: issuing MRW back ground format suspend\n"); + ret = cdrom_mrw_bgformat_susp(cdi, 0); + } + + if (!ret) + ret = cdrom_flush_cache(cdi); + + return ret; +} + +static int cdrom_mrw_set_lba_space(struct cdrom_device_info *cdi, int space) +{ + struct cdrom_generic_command cgc; + struct mode_page_header *mph; + char buffer[16]; + int ret, offset, size; + + init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ); + + cgc.buffer = buffer; + cgc.buflen = sizeof(buffer); + + if ((ret = cdrom_mode_sense(cdi, &cgc, cdi->mrw_mode_page, 0))) + return ret; + + mph = (struct mode_page_header *) buffer; + offset = be16_to_cpu(mph->desc_length); + size = be16_to_cpu(mph->mode_data_length) + 2; + + buffer[offset + 3] = space; + cgc.buflen = size; + + if ((ret = cdrom_mode_select(cdi, &cgc))) + return ret; + + printk(KERN_INFO "cdrom: %s: mrw address space %s selected\n", cdi->name, mrw_address_space[space]); + return 0; +} + +static int cdrom_media_erasable(struct cdrom_device_info *cdi) +{ + disc_information di; + + if (cdrom_get_disc_info(cdi, &di)) + return 0; + + return di.erasable; +} + +/* + * FIXME: check RO bit + */ +static int cdrom_dvdram_open_write(struct cdrom_device_info *cdi) +{ + return !cdrom_media_erasable(cdi); +} + +static int cdrom_mrw_open_write(struct cdrom_device_info *cdi) +{ + disc_information di; + int ret; + + /* + * always reset to DMA lba space on open + */ + if (cdrom_mrw_set_lba_space(cdi, MRW_LBA_DMA)) { + printk(KERN_ERR "cdrom: failed setting lba address space\n"); + return 1; + } + + if (cdrom_get_disc_info(cdi, &di)) + return 1; + + if (!di.erasable) + return 1; + + /* + * mrw_status + * 0 - not MRW formatted + * 1 - MRW bgformat started, but not running or complete + * 2 - MRW bgformat in progress + * 3 - MRW formatting complete + */ + ret = 0; + printk(KERN_INFO "cdrom open: mrw_status '%s'\n", mrw_format_status[di.mrw_status]); + if (!di.mrw_status) + ret = 1; + else if (di.mrw_status == CDM_MRW_BGFORMAT_INACTIVE && mrw_format_restart) + ret = cdrom_mrw_bgformat(cdi, 1); + + return ret; +} + +/* + * returns 0 for ok to open write, non-0 to disallow + */ +static int cdrom_open_write(struct cdrom_device_info *cdi) +{ + int ret = 1; + + if (CDROM_CAN(CDC_MRW_W)) + ret = cdrom_mrw_open_write(cdi); + else if (CDROM_CAN(CDC_DVD_RAM)) + ret = cdrom_dvdram_open_write(cdi); + + return ret; +} + +static int cdrom_close_write(struct cdrom_device_info *cdi) +{ +#if 0 + return cdrom_flush_cache(cdi); +#else + return 0; +#endif +} + /* We use the open-option O_NONBLOCK to indicate that the * purpose of opening is only for subsequent ioctl() calls; no device * integrity checks are performed. @@ -422,17 +734,21 @@ int cdrom_open(struct cdrom_device_info int ret; cdinfo(CD_OPEN, "entering cdrom_open\n"); + cdi->use_count++; + ret = -EROFS; + if (fp->f_mode & FMODE_WRITE) { + if (!(CDROM_CAN(CDC_RAM) || CDROM_CAN(CDC_MO_DRIVE))) + goto out; + if (cdrom_open_write(cdi)) + goto out; + } + /* if this was a O_NONBLOCK open and we should honor the flags, * do a quick open without drive/disc integrity checks. */ if ((fp->f_flags & O_NONBLOCK) && (cdi->options & CDO_USE_FFLAGS)) ret = cdi->ops->open(cdi, 1); - else { - if ((fp->f_mode & FMODE_WRITE) && - !(CDROM_CAN(CDC_DVD_RAM) || CDROM_CAN(CDC_MO_DRIVE))) - return -EROFS; - + else ret = open_for_data(cdi); - } if (!ret) cdi->use_count++; @@ -440,6 +756,9 @@ int cdrom_open(struct cdrom_device_info /* Do this on open. Don't wait for mount, because they might not be mounting, but opening with O_NONBLOCK */ check_disk_change(bdev); +out: + if (ret) + cdi->use_count--; return ret; } @@ -527,7 +846,7 @@ int open_for_data(struct cdrom_device_in cdinfo(CD_OPEN, "open device failed.\n"); goto clean_up_and_return; } - if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { + if (CDROM_CAN(CDC_LOCK) && (cdi->options & CDO_LOCK)) { cdo->lock_door(cdi, 1); cdinfo(CD_OPEN, "door locked.\n"); } @@ -606,7 +925,6 @@ int check_for_audio_disc(struct cdrom_de return 0; } - /* Admittedly, the logic below could be performed in a nicer way. */ int cdrom_release(struct cdrom_device_info *cdi) { @@ -616,20 +934,29 @@ int cdrom_release(struct cdrom_device_in if (cdi->use_count > 0) cdi->use_count--; + if (cdi->use_count) { cdo->release(cdi); return 0; } cdinfo(CD_CLOSE, "Use count for \"/dev/%s\" now zero\n", cdi->name); - if (cdo->capability & CDC_LOCK && !keeplocked) { + if ((cdo->capability & CDC_LOCK) && !keeplocked) { cdinfo(CD_CLOSE, "Unlocking door!\n"); cdo->lock_door(cdi, 0); } + + /* + * flush cache on last write release + */ + if (CDROM_CAN(CDC_RAM) && !cdi->use_count && cdi->for_data) + cdrom_close_write(cdi); + cdo->release(cdi); if (cdi->for_data && cdi->options & CDO_AUTO_EJECT && CDROM_CAN(CDC_OPEN_TRAY)) cdo->tray_move(cdi, 1); + cdi->for_data = 0; return 0; } @@ -2205,7 +2532,6 @@ static int cdrom_get_disc_info(struct cd return cdo->generic_packet(cdi, &cgc); } - /* return the last written block on the CD-R media. this is for the udf file system. */ int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written) @@ -2312,6 +2638,8 @@ EXPORT_SYMBOL(cdrom_number_of_slots); EXPORT_SYMBOL(cdrom_mode_select); EXPORT_SYMBOL(cdrom_mode_sense); EXPORT_SYMBOL(init_cdrom_command); +EXPORT_SYMBOL(cdrom_get_media_event); +EXPORT_SYMBOL(cdrom_is_mrw); #ifdef CONFIG_SYSCTL @@ -2408,6 +2736,14 @@ int cdrom_sysctl_info(ctl_table *ctl, in for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_RAM) != 0); + pos += sprintf(info+pos, "\nCan read MRW:"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(info+pos, "\t\t%d", CDROM_CAN(CDC_MRW) != 0); + + pos += sprintf(info+pos, "\nCan write MRW:"); + for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) + pos += sprintf(info+pos, "\t\t%d", CDROM_CAN(CDC_MRW_W) != 0); + strcpy(info+pos,"\n\n"); return proc_dostring(ctl, write, filp, buffer, lenp); diff -puN drivers/ide/ide-cd.c~mt-ranier-support drivers/ide/ide-cd.c --- 25/drivers/ide/ide-cd.c~mt-ranier-support Sat Dec 20 21:11:23 2003 +++ 25-akpm/drivers/ide/ide-cd.c Sat Dec 20 21:33:48 2003 @@ -291,10 +291,13 @@ * - Use extended sense on drives that support it for * correctly reporting tray status -- from * Michael D Johnson + * 4.60 Dec 17, 2003 - Add mt rainier support + * - Bump timeout for packet commands, matches sr + * - Odd stuff * *************************************************************************/ -#define IDECD_VERSION "4.59-ac1" +#define IDECD_VERSION "4.60" #include #include @@ -774,11 +777,36 @@ static int cdrom_decode_status(ide_drive if (sense_key == NOT_READY) { /* Tray open. */ - cdrom_saw_media_change (drive); + if (rq_data_dir(rq) == READ) { + cdrom_saw_media_change (drive); - /* Fail the request. */ - printk ("%s: tray open\n", drive->name); - do_end_request = 1; + /* Fail the request. */ + printk ("%s: tray open\n", drive->name); + do_end_request = 1; + } else { + struct cdrom_info *info = drive->driver_data; + + /* allow the drive 5 seconds to recover, some + * devices will return this error while flushing + * data from cache */ + if (!rq->errors) + info->write_timeout = jiffies + ATAPI_WAIT_BUSY; + rq->errors = 1; + if (time_after(jiffies, info->write_timeout)) + do_end_request = 1; + else { + unsigned long flags; + + /* + * take a breather relying on the + * unplug timer to kick us again + */ + spin_lock_irqsave(&ide_lock, flags); + blk_plug_device(drive->queue); + spin_unlock_irqrestore(&ide_lock,flags); + return 1; + } + } } else if (sense_key == UNIT_ATTENTION) { /* Media change. */ cdrom_saw_media_change (drive); @@ -844,9 +872,13 @@ static int cdrom_timer_expiry(ide_drive_ case GPCMD_BLANK: case GPCMD_FORMAT_UNIT: case GPCMD_RESERVE_RZONE_TRACK: - wait = WAIT_CMD; + case GPCMD_CLOSE_TRACK: + case GPCMD_FLUSH_CACHE: + wait = ATAPI_WAIT_PC; break; default: + if (!(rq->flags & REQ_QUIET)) + printk(KERN_INFO "ide-cd: cmd 0x%x timed out\n", rq->cmd[0]); wait = 0; break; } @@ -894,7 +926,7 @@ static ide_startstop_t cdrom_start_packe if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { /* packet command */ - ide_execute_command(drive, WIN_PACKETCMD, handler, WAIT_CMD, cdrom_timer_expiry); + ide_execute_command(drive, WIN_PACKETCMD, handler, ATAPI_WAIT_PC, cdrom_timer_expiry); return ide_started; } else { /* packet command */ @@ -1167,7 +1199,7 @@ static ide_startstop_t cdrom_read_intr ( } /* Done moving data! Wait for another interrupt. */ - ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL); + ide_set_handler(drive, &cdrom_read_intr, ATAPI_WAIT_PC, NULL); return ide_started; } @@ -1277,7 +1309,7 @@ static ide_startstop_t cdrom_start_read_ (65534 / CD_FRAMESIZE) : 65535); /* Set up the command */ - rq->timeout = WAIT_CMD; + rq->timeout = ATAPI_WAIT_PC; /* Send the command to the drive and return. */ return cdrom_transfer_packet_command(drive, rq, &cdrom_read_intr); @@ -1286,7 +1318,7 @@ static ide_startstop_t cdrom_start_read_ #define IDECD_SEEK_THRESHOLD (1000) /* 1000 blocks */ #define IDECD_SEEK_TIMER (5 * WAIT_MIN_SLEEP) /* 100 ms */ -#define IDECD_SEEK_TIMEOUT WAIT_CMD /* 10 sec */ +#define IDECD_SEEK_TIMEOUT (2 * WAIT_CMD) /* 20 sec */ static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive) { @@ -1326,7 +1358,7 @@ static ide_startstop_t cdrom_start_seek_ rq->cmd[0] = GPCMD_SEEK; put_unaligned(cpu_to_be32(frame), (unsigned int *) &rq->cmd[2]); - rq->timeout = WAIT_CMD; + rq->timeout = ATAPI_WAIT_PC; return cdrom_transfer_packet_command(drive, rq, &cdrom_seek_intr); } @@ -1502,7 +1534,7 @@ confused: } /* Now we wait for another interrupt. */ - ide_set_handler(drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry); + ide_set_handler(drive, &cdrom_pc_intr, ATAPI_WAIT_PC, cdrom_timer_expiry); return ide_started; } @@ -1511,7 +1543,7 @@ static ide_startstop_t cdrom_do_pc_conti struct request *rq = HWGROUP(drive)->rq; if (!rq->timeout) - rq->timeout = WAIT_CMD; + rq->timeout = ATAPI_WAIT_PC; /* Send the command to the drive and return. */ return cdrom_transfer_packet_command(drive, rq, &cdrom_pc_intr); @@ -1716,11 +1748,8 @@ static ide_startstop_t cdrom_newpc_intr( /* * If DRQ is clear, the command has completed. */ - if ((stat & DRQ_STAT) == 0) { - if (rq->data_len) - printk("%s: %u residual after xfer\n", __FUNCTION__, rq->data_len); + if ((stat & DRQ_STAT) == 0) goto end_request; - } /* * check which way to transfer data @@ -1826,10 +1855,8 @@ static ide_startstop_t cdrom_write_intr( } } - if (cdrom_decode_status(drive, 0, &stat)) { - printk("ide-cd: write_intr decode_status bad\n"); + if (cdrom_decode_status(drive, 0, &stat)) return ide_stopped; - } /* * using dma, transfer is complete now @@ -1904,7 +1931,7 @@ static ide_startstop_t cdrom_write_intr( } /* re-arm handler */ - ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL); + ide_set_handler(drive, &cdrom_write_intr, ATAPI_WAIT_PC, NULL); return ide_started; } @@ -1915,7 +1942,7 @@ static ide_startstop_t cdrom_start_write #if 0 /* the immediate bit */ rq->cmd[1] = 1 << 3; #endif - rq->timeout = 2 * WAIT_CMD; + rq->timeout = ATAPI_WAIT_PC; return cdrom_transfer_packet_command(drive, rq, cdrom_write_intr); } @@ -1956,7 +1983,7 @@ static ide_startstop_t cdrom_do_newpc_co struct request *rq = HWGROUP(drive)->rq; if (!rq->timeout) - rq->timeout = WAIT_CMD; + rq->timeout = ATAPI_WAIT_PC; return cdrom_transfer_packet_command(drive, rq, cdrom_newpc_intr); } @@ -2489,7 +2516,7 @@ static int ide_cdrom_packet(struct cdrom ide_drive_t *drive = (ide_drive_t*) cdi->handle; if (cgc->timeout <= 0) - cgc->timeout = WAIT_CMD; + cgc->timeout = ATAPI_WAIT_PC; /* here we queue the commands from the uniform CD-ROM layer. the packet must be complete, as we do not @@ -2694,37 +2721,49 @@ int ide_cdrom_select_speed (struct cdrom return 0; } +/* + * add logic to try GET_EVENT command first to check for media and tray + * status. this should be supported by newer cd-r/w and all DVD etc + * drives + */ static int ide_cdrom_drive_status (struct cdrom_device_info *cdi, int slot_nr) { ide_drive_t *drive = (ide_drive_t*) cdi->handle; + struct media_event_desc med; + struct request_sense sense; + int stat; - if (slot_nr == CDSL_CURRENT) { - struct request_sense sense; - int stat = cdrom_check_status(drive, &sense); - if (stat == 0 || sense.sense_key == UNIT_ATTENTION) - return CDS_DISC_OK; + if (slot_nr != CDSL_CURRENT) + return -EINVAL; - if (sense.sense_key == NOT_READY && sense.asc == 0x04 && - sense.ascq == 0x04) + stat = cdrom_check_status(drive, &sense); + if (!stat || sense.sense_key == UNIT_ATTENTION) + return CDS_DISC_OK; + + if (!cdrom_get_media_event(cdi, &med)) { + if (med.media_present) return CDS_DISC_OK; + if (med.door_open) + return CDS_TRAY_OPEN; + } + if (sense.sense_key == NOT_READY && sense.asc == 0x04 && sense.ascq == 0x04) + return CDS_DISC_OK; - /* - * If not using Mt Fuji extended media tray reports, - * just return TRAY_OPEN since ATAPI doesn't provide - * any other way to detect this... - */ - if (sense.sense_key == NOT_READY) { - if (sense.asc == 0x3a && sense.ascq == 1) - return CDS_NO_DISC; - else - return CDS_TRAY_OPEN; - } - - return CDS_DRIVE_NOT_READY; + /* + * If not using Mt Fuji extended media tray reports, + * just return TRAY_OPEN since ATAPI doesn't provide + * any other way to detect this... + */ + if (sense.sense_key == NOT_READY) { + if (sense.asc == 0x3a && sense.ascq == 1) + return CDS_NO_DISC; + else + return CDS_TRAY_OPEN; } - return -EINVAL; + + return CDS_DRIVE_NOT_READY; } static @@ -2832,7 +2871,8 @@ static struct cdrom_device_ops ide_cdrom CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_IOCTLS | CDC_DRIVE_STATUS | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R| CDC_DVD_RAM | - CDC_GENERIC_PACKET | CDC_MO_DRIVE, + CDC_GENERIC_PACKET | CDC_MO_DRIVE | CDC_MRW | + CDC_MRW_W | CDC_RAM, .generic_packet = ide_cdrom_packet, }; @@ -2867,6 +2907,10 @@ static int ide_cdrom_register (ide_drive devinfo->mask |= CDC_CLOSE_TRAY; if (!CDROM_CONFIG_FLAGS(drive)->mo_drive) devinfo->mask |= CDC_MO_DRIVE; + if (!CDROM_CONFIG_FLAGS(drive)->mrw) + devinfo->mask |= CDC_MRW; + if (!CDROM_CONFIG_FLAGS(drive)->mrw_w) + devinfo->mask |= CDC_MRW_W; return register_cdrom(devinfo); } @@ -2887,14 +2931,6 @@ int ide_cdrom_get_capabilities(ide_drive !strcmp(drive->id->model, "WPI CDS-32X"))) size -= sizeof(cap->pad); - /* we have to cheat a little here. the packet will eventually - * be queued with ide_cdrom_packet(), which extracts the - * drive from cdi->handle. Since this device hasn't been - * registered with the Uniform layer yet, it can't do this. - * Same goes for cdi->ops. - */ - cdi->handle = (ide_drive_t *) drive; - cdi->ops = &ide_cdrom_dops; init_cdrom_command(&cgc, cap, size, CGC_DATA_UNKNOWN); do { /* we seem to get stat=0x01,err=0x00 the first time (??) */ stat = cdrom_mode_sense(cdi, &cgc, GPMODE_CAPABILITIES_PAGE, 0); @@ -2910,7 +2946,7 @@ int ide_cdrom_probe_capabilities (ide_dr struct cdrom_info *info = drive->driver_data; struct cdrom_device_info *cdi = &info->devinfo; struct atapi_capabilities_page cap; - int nslots = 1; + int nslots = 1, mrw_write = 0; if (drive->media == ide_optical) { CDROM_CONFIG_FLAGS(drive)->mo_drive = 1; @@ -2918,15 +2954,34 @@ int ide_cdrom_probe_capabilities (ide_dr return nslots; } - if (CDROM_CONFIG_FLAGS(drive)->nec260) { - CDROM_CONFIG_FLAGS(drive)->no_eject = 0; - CDROM_CONFIG_FLAGS(drive)->audio_play = 1; + if (CDROM_CONFIG_FLAGS(drive)->nec260 || + !strcmp(drive->id->model,"STINGRAY 8422 IDE 8X CD-ROM 7-27-95")) { + CDROM_CONFIG_FLAGS(drive)->no_eject = 0; + CDROM_CONFIG_FLAGS(drive)->audio_play = 1; return nslots; } + /* + * we have to cheat a little here. the packet will eventually + * be queued with ide_cdrom_packet(), which extracts the + * drive from cdi->handle. Since this device hasn't been + * registered with the Uniform layer yet, it can't do this. + * Same goes for cdi->ops. + */ + cdi->handle = (ide_drive_t *) drive; + cdi->ops = &ide_cdrom_dops; + if (ide_cdrom_get_capabilities(drive, &cap)) return 0; + if (!cdrom_is_mrw(cdi, &mrw_write)) { + CDROM_CONFIG_FLAGS(drive)->mrw = 1; + if (mrw_write) { + CDROM_CONFIG_FLAGS(drive)->mrw_w = 1; + CDROM_CONFIG_FLAGS(drive)->ram = 1; + } + } + if (cap.lock == 0) CDROM_CONFIG_FLAGS(drive)->no_doorlock = 1; if (cap.eject) @@ -2939,8 +2994,10 @@ int ide_cdrom_probe_capabilities (ide_dr CDROM_CONFIG_FLAGS(drive)->test_write = 1; if (cap.dvd_ram_read || cap.dvd_r_read || cap.dvd_rom) CDROM_CONFIG_FLAGS(drive)->dvd = 1; - if (cap.dvd_ram_write) + if (cap.dvd_ram_write) { CDROM_CONFIG_FLAGS(drive)->dvd_ram = 1; + CDROM_CONFIG_FLAGS(drive)->ram = 1; + } if (cap.dvd_r_write) CDROM_CONFIG_FLAGS(drive)->dvd_r = 1; if (cap.audio_play) @@ -3004,6 +3061,9 @@ int ide_cdrom_probe_capabilities (ide_dr (CDROM_CONFIG_FLAGS(drive)->cd_r)? "-R" : "", (CDROM_CONFIG_FLAGS(drive)->cd_rw)? "/RW" : ""); + if (CDROM_CONFIG_FLAGS(drive)->mrw || CDROM_CONFIG_FLAGS(drive)->mrw_w) + printk(" CD-MR%s", CDROM_CONFIG_FLAGS(drive)->mrw_w ? "W" : ""); + if (CDROM_CONFIG_FLAGS(drive)->is_changer) printk(" changer w/%d slots", nslots); else @@ -3111,14 +3171,11 @@ int ide_cdrom_setup (ide_drive_t *drive) struct cdrom_device_info *cdi = &info->devinfo; int nslots; - /* - * default to read-only always and fix latter at the bottom - */ - set_disk_ro(drive->disk, 1); - blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE); - blk_queue_prep_rq(drive->queue, ide_cdrom_prep_fn); blk_queue_dma_alignment(drive->queue, 3); + drive->queue->unplug_delay = (1 * HZ) / 1000; + if (!drive->queue->unplug_delay) + drive->queue->unplug_delay = 1; drive->special.all = 0; drive->ready_stat = 0; @@ -3221,9 +3278,13 @@ int ide_cdrom_setup (ide_drive_t *drive) nslots = ide_cdrom_probe_capabilities (drive); - if (CDROM_CONFIG_FLAGS(drive)->dvd_ram || - CDROM_CONFIG_FLAGS(drive)->mo_drive) - set_disk_ro(drive->disk, 0); + /* + * set correct block size and read-only for non-ram media + */ + set_disk_ro(drive->disk, + !(CDROM_CONFIG_FLAGS(drive)->ram || + CDROM_CONFIG_FLAGS(drive)->mo_drive)); + blk_queue_hardsect_size(drive->queue, CD_FRAMESIZE); #if 0 drive->dsc_overlap = (HWIF(drive)->no_dsc) ? 0 : 1; diff -puN drivers/ide/ide-cd.h~mt-ranier-support drivers/ide/ide-cd.h --- 25/drivers/ide/ide-cd.h~mt-ranier-support Sat Dec 20 21:11:23 2003 +++ 25-akpm/drivers/ide/ide-cd.h Sat Dec 20 21:11:23 2003 @@ -35,6 +35,12 @@ #define NO_DOOR_LOCKING 0 #endif +/* + * typical timeout for packet command + */ +#define ATAPI_WAIT_PC (60 * HZ) +#define ATAPI_WAIT_BUSY (5 * HZ) + /************************************************************************/ #define SECTOR_BITS 9 @@ -75,6 +81,9 @@ struct ide_cd_config_flags { __u8 dvd : 1; /* Drive is a DVD-ROM */ __u8 dvd_r : 1; /* Drive can write DVD-R */ __u8 dvd_ram : 1; /* Drive can write DVD-RAM */ + __u8 mrw : 1; /* drive can read mrw */ + __u8 mrw_w : 1; /* drive can write mrw */ + __u8 ram : 1; /* generic WRITE (dvd-ram/mrw) */ __u8 test_write : 1; /* Drive can fake writes */ __u8 supp_disc_present : 1; /* Changer can report exact contents of slots. */ @@ -482,6 +491,8 @@ struct cdrom_info { /* Per-device info needed by cdrom.c generic driver. */ struct cdrom_device_info devinfo; + + unsigned long write_timeout; }; /**************************************************************************** diff -puN drivers/scsi/sr.c~mt-ranier-support drivers/scsi/sr.c --- 25/drivers/scsi/sr.c~mt-ranier-support Sat Dec 20 21:11:23 2003 +++ 25-akpm/drivers/scsi/sr.c Sat Dec 20 21:11:23 2003 @@ -67,7 +67,8 @@ MODULE_PARM(xa_test, "i"); /* see sr_ioc (CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|CDC_SELECT_SPEED| \ CDC_SELECT_DISC|CDC_MULTI_SESSION|CDC_MCN|CDC_MEDIA_CHANGED| \ CDC_PLAY_AUDIO|CDC_RESET|CDC_IOCTLS|CDC_DRIVE_STATUS| \ - CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_DVD_RAM|CDC_GENERIC_PACKET) + CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_DVD_RAM|CDC_GENERIC_PACKET| \ + CDC_MRW|CDC_MRW_W|CDC_RAM) static int sr_probe(struct device *); static int sr_remove(struct device *); @@ -692,7 +693,7 @@ Enomem: static void get_capabilities(struct scsi_cd *cd) { unsigned char *buffer; - int rc, n; + int rc, n, mrw_write = 0, mrw = 1; struct scsi_mode_data data; struct scsi_request *SRpnt; unsigned char cmd[MAX_COMMAND_SIZE]; @@ -765,6 +766,15 @@ static void get_capabilities(struct scsi printk("%s: scsi-1 drive\n", cd->cdi.name); return; } + + if (cdrom_is_mrw(&cd->cdi, &mrw_write)) { + mrw = 0; + cd->cdi.mask |= CDC_MRW; + cd->cdi.mask |= CDC_MRW_W; + } + if (!mrw_write) + cd->cdi.mask |= CDC_MRW_W; + n = data.header_length + data.block_descriptor_length; cd->cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176; cd->readcd_known = 1; @@ -788,9 +798,7 @@ static void get_capabilities(struct scsi if ((buffer[n + 3] & 0x20) == 0) { /* can't write DVD-RAM media */ cd->cdi.mask |= CDC_DVD_RAM; - } else { - cd->device->writeable = 1; - } + } else if ((buffer[n + 3] & 0x10) == 0) /* can't write DVD-R media */ cd->cdi.mask |= CDC_DVD_R; @@ -814,6 +822,12 @@ static void get_capabilities(struct scsi /*else I don't think it can close its tray cd->cdi.mask |= CDC_CLOSE_TRAY; */ + /* + * if DVD-RAM of MRW-W, we are randomly writeable + */ + if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W)) != (CDC_DVD_RAM | CDC_MRW_W)) + cd->device->writeable = 1; + scsi_release_request(SRpnt); kfree(buffer); } diff -puN include/linux/cdrom.h~mt-ranier-support include/linux/cdrom.h --- 25/include/linux/cdrom.h~mt-ranier-support Sat Dec 20 21:11:23 2003 +++ 25-akpm/include/linux/cdrom.h Sat Dec 20 21:11:23 2003 @@ -5,7 +5,7 @@ * 1994, 1995 Eberhard Moenkeberg, emoenke@gwdg.de * 1996 David van Leeuwen, david@tm.tno.nl * 1997, 1998 Erik Andersen, andersee@debian.org - * 1998-2000 Jens Axboe, axboe@suse.de + * 1998-2002 Jens Axboe, axboe@suse.de */ #ifndef _LINUX_CDROM_H @@ -388,6 +388,9 @@ struct cdrom_generic_command #define CDC_DVD_R 0x10000 /* drive can write DVD-R */ #define CDC_DVD_RAM 0x20000 /* drive can write DVD-RAM */ #define CDC_MO_DRIVE 0x40000 /* drive is an MO device */ +#define CDC_MRW 0x80000 /* drive can read MRW */ +#define CDC_MRW_W 0x100000 /* drive can write MRW */ +#define CDC_RAM 0x200000 /* ok to open for WRITE */ /* drive status possibilities returned by CDROM_DRIVE_STATUS ioctl */ #define CDS_NO_INFO 0 /* if not implemented */ @@ -715,93 +718,57 @@ struct request_sense { __u8 asb[46]; }; -#ifdef __KERNEL__ -#include /* not really needed, later.. */ -#include - -struct cdrom_write_settings { - unsigned char fpacket; /* fixed/variable packets */ - unsigned long packet_size; /* write out this number of packets */ - unsigned long nwa; /* next writeable address */ - unsigned char writeable; /* cdrom is writeable */ -}; - -/* Uniform cdrom data structures for cdrom.c */ -struct cdrom_device_info { - struct cdrom_device_ops *ops; /* link to device_ops */ - struct cdrom_device_info *next; /* next device_info for this major */ - void *handle; /* driver-dependent data */ -/* specifications */ - int mask; /* mask of capability: disables them */ - int speed; /* maximum speed for reading data */ - int capacity; /* number of discs in jukebox */ -/* device-related storage */ - int options : 30; /* options flags */ - unsigned mc_flags : 2; /* media change buffer flags */ - int use_count; /* number of times device opened */ - char name[20]; /* name of the device type */ -/* per-device flags */ - __u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */ - __u8 reserved : 6; /* not used yet */ - int for_data; - struct cdrom_write_settings write; -}; - -struct cdrom_device_ops { -/* routines */ - int (*open) (struct cdrom_device_info *, int); - void (*release) (struct cdrom_device_info *); - int (*drive_status) (struct cdrom_device_info *, int); - int (*media_changed) (struct cdrom_device_info *, int); - int (*tray_move) (struct cdrom_device_info *, int); - int (*lock_door) (struct cdrom_device_info *, int); - int (*select_speed) (struct cdrom_device_info *, int); - int (*select_disc) (struct cdrom_device_info *, int); - int (*get_last_session) (struct cdrom_device_info *, - struct cdrom_multisession *); - int (*get_mcn) (struct cdrom_device_info *, - struct cdrom_mcn *); - /* hard reset device */ - int (*reset) (struct cdrom_device_info *); - /* play stuff */ - int (*audio_ioctl) (struct cdrom_device_info *,unsigned int, void *); - /* dev-specific */ - int (*dev_ioctl) (struct cdrom_device_info *, - unsigned int, unsigned long); -/* driver specifications */ - const int capability; /* capability flags */ - int n_minors; /* number of active minor devices */ - /* handle uniform packets for scsi type devices (scsi,atapi) */ - int (*generic_packet) (struct cdrom_device_info *, - struct cdrom_generic_command *); -}; +/* + * feature profile + */ +#define CDF_MRW 0x28 -/* the general block_device operations structure: */ -extern int cdrom_open(struct cdrom_device_info *, struct block_device *, struct file *); -extern int cdrom_release(struct cdrom_device_info *); -extern int cdrom_ioctl(struct cdrom_device_info *, struct block_device *, unsigned, unsigned long); -extern int cdrom_media_changed(struct cdrom_device_info *); +/* + * media status bits + */ +#define CDM_MRW_NOTMRW 0 +#define CDM_MRW_BGFORMAT_INACTIVE 1 +#define CDM_MRW_BGFORMAT_ACTIVE 2 +#define CDM_MRW_BGFORMAT_COMPLETE 3 -extern int register_cdrom(struct cdrom_device_info *cdi); -extern int unregister_cdrom(struct cdrom_device_info *cdi); +/* + * mrw address spaces + */ +#define MRW_LBA_DMA 0 +#define MRW_LBA_GAA 1 -typedef struct { - int data; - int audio; - int cdi; - int xa; - long error; -} tracktype; +/* + * mrw mode pages (first is deprecated) -- probed at init time and + * cdi->mrw_mode_page is set + */ +#define MRW_MODE_PC_PRE1 0x2c +#define MRW_MODE_PC 0x03 -extern int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written); -extern int cdrom_number_of_slots(struct cdrom_device_info *cdi); -extern int cdrom_mode_select(struct cdrom_device_info *cdi, - struct cdrom_generic_command *cgc); -extern int cdrom_mode_sense(struct cdrom_device_info *cdi, - struct cdrom_generic_command *cgc, - int page_code, int page_control); -extern void init_cdrom_command(struct cdrom_generic_command *cgc, - void *buffer, int len, int type); +struct mrw_feature_desc { + __u16 feature_code; +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 reserved1 : 2; + __u8 feature_version : 4; + __u8 persistent : 1; + __u8 curr : 1; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 curr : 1; + __u8 persistent : 1; + __u8 feature_version : 4; + __u8 reserved1 : 2; +#endif + __u8 add_len; +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 reserved2 : 7; + __u8 write : 1; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 write : 1; + __u8 reserved2 : 7; +#endif + __u8 reserved3; + __u8 reserved4; + __u8 reserved5; +}; typedef struct { __u16 disc_information_length; @@ -826,9 +793,13 @@ typedef struct { __u8 did_v : 1; __u8 dbc_v : 1; __u8 uru : 1; - __u8 reserved2 : 5; + __u8 reserved2 : 2; + __u8 dbit : 1; + __u8 mrw_status : 2; #elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 reserved2 : 5; + __u8 mrw_status : 2; + __u8 dbit : 1; + __u8 reserved2 : 2; __u8 uru : 1; __u8 dbc_v : 1; __u8 did_v : 1; @@ -885,6 +856,104 @@ typedef struct { __u32 last_rec_address; } track_information; +struct feature_header { + __u32 data_len; + __u8 reserved1; + __u8 reserved2; + __u16 curr_profile; +}; + +struct mode_page_header { + __u16 mode_data_length; + __u8 medium_type; + __u8 reserved1; + __u8 reserved2; + __u8 reserved3; + __u16 desc_length; +}; + +#ifdef __KERNEL__ +#include /* not really needed, later.. */ +#include + +/* Uniform cdrom data structures for cdrom.c */ +struct cdrom_device_info { + struct cdrom_device_ops *ops; /* link to device_ops */ + struct cdrom_device_info *next; /* next device_info for this major */ + void *handle; /* driver-dependent data */ +/* specifications */ + int mask; /* mask of capability: disables them */ + int speed; /* maximum speed for reading data */ + int capacity; /* number of discs in jukebox */ +/* device-related storage */ + int options : 30; /* options flags */ + unsigned mc_flags : 2; /* media change buffer flags */ + int use_count; /* number of times device opened */ + char name[20]; /* name of the device type */ +/* per-device flags */ + __u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */ + __u8 reserved : 6; /* not used yet */ + int for_data; + int (*exit)(struct cdrom_device_info *); + int mrw_mode_page; +}; + +struct cdrom_device_ops { +/* routines */ + int (*open) (struct cdrom_device_info *, int); + void (*release) (struct cdrom_device_info *); + int (*drive_status) (struct cdrom_device_info *, int); + int (*media_changed) (struct cdrom_device_info *, int); + int (*tray_move) (struct cdrom_device_info *, int); + int (*lock_door) (struct cdrom_device_info *, int); + int (*select_speed) (struct cdrom_device_info *, int); + int (*select_disc) (struct cdrom_device_info *, int); + int (*get_last_session) (struct cdrom_device_info *, + struct cdrom_multisession *); + int (*get_mcn) (struct cdrom_device_info *, + struct cdrom_mcn *); + /* hard reset device */ + int (*reset) (struct cdrom_device_info *); + /* play stuff */ + int (*audio_ioctl) (struct cdrom_device_info *,unsigned int, void *); + /* dev-specific */ + int (*dev_ioctl) (struct cdrom_device_info *, + unsigned int, unsigned long); +/* driver specifications */ + const int capability; /* capability flags */ + int n_minors; /* number of active minor devices */ + /* handle uniform packets for scsi type devices (scsi,atapi) */ + int (*generic_packet) (struct cdrom_device_info *, + struct cdrom_generic_command *); +}; + +/* the general block_device operations structure: */ +extern int cdrom_open(struct cdrom_device_info *, struct block_device *, struct file *); +extern int cdrom_release(struct cdrom_device_info *); +extern int cdrom_ioctl(struct cdrom_device_info *, struct block_device *, unsigned, unsigned long); +extern int cdrom_media_changed(struct cdrom_device_info *); + +extern int register_cdrom(struct cdrom_device_info *cdi); +extern int unregister_cdrom(struct cdrom_device_info *cdi); + +typedef struct { + int data; + int audio; + int cdi; + int xa; + long error; +} tracktype; + +extern int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written); +extern int cdrom_number_of_slots(struct cdrom_device_info *cdi); +extern int cdrom_mode_select(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc); +extern int cdrom_mode_sense(struct cdrom_device_info *cdi, + struct cdrom_generic_command *cgc, + int page_code, int page_control); +extern void init_cdrom_command(struct cdrom_generic_command *cgc, + void *buffer, int len, int type); + /* The SCSI spec says there could be 256 slots. */ #define CDROM_MAX_SLOTS 256 @@ -935,15 +1004,6 @@ typedef enum { mechtype_cartridge_changer = 5 } mechtype_t; -struct mode_page_header { - __u16 mode_data_length; - __u8 medium_type; - __u8 reserved1; - __u8 reserved2; - __u8 reserved3; - __u16 desc_length; -}; - typedef struct { #if defined(__BIG_ENDIAN_BITFIELD) __u8 ps : 1; @@ -1033,6 +1093,41 @@ typedef struct { __u8 reserved3; } rpc_state_t; +struct event_header { + __u16 data_len; +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 nea : 1; + __u8 reserved1 : 4; + __u8 notification_class : 3; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 notification_class : 3; + __u8 reserved1 : 4; + __u8 nea : 1; +#endif + __u8 supp_event_class; +}; + +struct media_event_desc { +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 reserved1 : 4; + __u8 media_event_code : 4; + __u8 reserved2 : 6; + __u8 media_present : 1; + __u8 door_open : 1; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 media_event_code : 4; + __u8 reserved1 : 4; + __u8 door_open : 1; + __u8 media_present : 1; + __u8 reserved2 : 6; +#endif + __u8 start_slot; + __u8 end_slot; +}; + +extern int cdrom_get_media_event(struct cdrom_device_info *cdi, struct media_event_desc *med); +extern int cdrom_is_mrw(struct cdrom_device_info *cdi, int *write); + #endif /* End of kernel only stuff */ #endif /* _LINUX_CDROM_H */ _