From 7deeed13170e634adc4552ff94588d6301a3da83 Mon Sep 17 00:00:00 2001 From: Benjamin Gilbert Date: Tue, 19 Jun 2007 09:05:21 +0200 Subject: [TRIVIAL PATCH] Kill blk_congestion_wait() stub for !CONFIG_BLOCK blk_congestion_wait() doesn't exist anymore, but there's still a stub in blkdev.h for the !CONFIG_BLOCK case. Kill it. Signed-off-by: Benjamin Gilbert Signed-off-by: Jens Axboe --- include/linux/blkdev.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index db5b00a792f5..fae138bd2207 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -868,11 +868,6 @@ void kblockd_flush_work(struct work_struct *work); */ #define buffer_heads_over_limit 0 -static inline long blk_congestion_wait(int rw, long timeout) -{ - return io_schedule_timeout(timeout); -} - static inline long nr_blockdev_pages(void) { return 0; -- cgit v1.2.3-59-g8ed1b From 32eef964110985c5845472e07fa0a18838a970c4 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 19 Jun 2007 09:09:27 +0200 Subject: blk_hw_contig_segment(): bad segment size checks Two bugs in there: - The virt oversize check should use the current bio hardware back size and the next bio front size, not the same bio. Spotted by Neil Brown. - The segment size check should add hw front sizes, not total bio sizes. Spotted by James Bottomley Acked-by: James Bottomley Acked-by: NeilBrown Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index c99b46354859..3e7801e49033 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -1304,9 +1304,9 @@ static int blk_hw_contig_segment(request_queue_t *q, struct bio *bio, if (unlikely(!bio_flagged(nxt, BIO_SEG_VALID))) blk_recount_segments(q, nxt); if (!BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt)) || - BIOVEC_VIRT_OVERSIZE(bio->bi_hw_front_size + bio->bi_hw_back_size)) + BIOVEC_VIRT_OVERSIZE(bio->bi_hw_back_size + nxt->bi_hw_front_size)) return 0; - if (bio->bi_size + nxt->bi_size > q->max_segment_size) + if (bio->bi_hw_back_size + nxt->bi_hw_front_size > q->max_segment_size) return 0; return 1; -- cgit v1.2.3-59-g8ed1b From 554988d6fe369719ae5b41255c577569ecf47c30 Mon Sep 17 00:00:00 2001 From: Dave Young Date: Tue, 19 Jun 2007 09:14:26 +0200 Subject: [PATCH] cdrom_sysctl_info fix Fix the cdrom_sysctl_info possible buffer overwrite bug. Also fix the locking of accessing topCdromPtr pointer. Signed-off-by: Dave Young Signed-off-by: Jens Axboe --- drivers/cdrom/cdrom.c | 216 +++++++++++++++++++++++++++++--------------------- 1 file changed, 125 insertions(+), 91 deletions(-) diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 3625a05bc3d3..aa5468f487ba 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -302,7 +302,7 @@ module_param(lockdoor, bool, 0); module_param(check_media_type, bool, 0); module_param(mrw_format_restart, bool, 0); -static DEFINE_SPINLOCK(cdrom_lock); +static DEFINE_MUTEX(cdrom_mutex); static const char *mrw_format_status[] = { "not mrw", @@ -438,10 +438,10 @@ int register_cdrom(struct cdrom_device_info *cdi) cdo->generic_packet = cdrom_dummy_generic_packet; cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name); - spin_lock(&cdrom_lock); + mutex_lock(&cdrom_mutex); cdi->next = topCdromPtr; topCdromPtr = cdi; - spin_unlock(&cdrom_lock); + mutex_unlock(&cdrom_mutex); return 0; } #undef ENSURE @@ -452,7 +452,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg) cdinfo(CD_OPEN, "entering unregister_cdrom\n"); prev = NULL; - spin_lock(&cdrom_lock); + mutex_lock(&cdrom_mutex); cdi = topCdromPtr; while (cdi && cdi != unreg) { prev = cdi; @@ -460,7 +460,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg) } if (cdi == NULL) { - spin_unlock(&cdrom_lock); + mutex_unlock(&cdrom_mutex); return -2; } if (prev) @@ -468,7 +468,7 @@ int unregister_cdrom(struct cdrom_device_info *unreg) else topCdromPtr = cdi->next; - spin_unlock(&cdrom_lock); + mutex_unlock(&cdrom_mutex); if (cdi->exit) cdi->exit(cdi); @@ -3289,103 +3289,137 @@ static struct cdrom_sysctl_settings { int check; /* check media type */ } cdrom_sysctl_settings; +enum cdrom_print_option { + CTL_NAME, + CTL_SPEED, + CTL_SLOTS, + CTL_CAPABILITY +}; + +static int cdrom_print_info(const char *header, int val, char *info, + int *pos, enum cdrom_print_option option) +{ + const int max_size = sizeof(cdrom_sysctl_settings.info); + struct cdrom_device_info *cdi; + int ret; + + ret = scnprintf(info + *pos, max_size - *pos, header); + if (!ret) + return 1; + + *pos += ret; + + for (cdi = topCdromPtr; cdi; cdi = cdi->next) { + switch (option) { + case CTL_NAME: + ret = scnprintf(info + *pos, max_size - *pos, + "\t%s", cdi->name); + break; + case CTL_SPEED: + ret = scnprintf(info + *pos, max_size - *pos, + "\t%d", cdi->speed); + break; + case CTL_SLOTS: + ret = scnprintf(info + *pos, max_size - *pos, + "\t%d", cdi->capacity); + break; + case CTL_CAPABILITY: + ret = scnprintf(info + *pos, max_size - *pos, + "\t%d", CDROM_CAN(val) != 0); + break; + default: + printk(KERN_INFO "cdrom: invalid option%d\n", option); + return 1; + } + if (!ret) + return 1; + *pos += ret; + } + + return 0; +} + static int cdrom_sysctl_info(ctl_table *ctl, int write, struct file * filp, void __user *buffer, size_t *lenp, loff_t *ppos) { - int pos; - struct cdrom_device_info *cdi; + int pos; char *info = cdrom_sysctl_settings.info; + const int max_size = sizeof(cdrom_sysctl_settings.info); if (!*lenp || (*ppos && !write)) { *lenp = 0; return 0; } + mutex_lock(&cdrom_mutex); + pos = sprintf(info, "CD-ROM information, " VERSION "\n"); - pos += sprintf(info+pos, "\ndrive name:\t"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%s", cdi->name); - - pos += sprintf(info+pos, "\ndrive speed:\t"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", cdi->speed); - - pos += sprintf(info+pos, "\ndrive # of slots:"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", cdi->capacity); - - pos += sprintf(info+pos, "\nCan close tray:\t"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CLOSE_TRAY) != 0); - - pos += sprintf(info+pos, "\nCan open tray:\t"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_OPEN_TRAY) != 0); - - pos += sprintf(info+pos, "\nCan lock tray:\t"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_LOCK) != 0); - - pos += sprintf(info+pos, "\nCan change speed:"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_SPEED) != 0); - - pos += sprintf(info+pos, "\nCan select disk:"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_SELECT_DISC) != 0); - - pos += sprintf(info+pos, "\nCan read multisession:"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MULTI_SESSION) != 0); - - pos += sprintf(info+pos, "\nCan read MCN:\t"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MCN) != 0); - - pos += sprintf(info+pos, "\nReports media changed:"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MEDIA_CHANGED) != 0); - - pos += sprintf(info+pos, "\nCan play audio:\t"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_PLAY_AUDIO) != 0); - - pos += sprintf(info+pos, "\nCan write CD-R:\t"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_R) != 0); - - pos += sprintf(info+pos, "\nCan write CD-RW:"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_CD_RW) != 0); - - pos += sprintf(info+pos, "\nCan read DVD:\t"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD) != 0); - - pos += sprintf(info+pos, "\nCan write DVD-R:"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_DVD_R) != 0); - - pos += sprintf(info+pos, "\nCan write DVD-RAM:"); - 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:\t"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW) != 0); - - pos += sprintf(info+pos, "\nCan write MRW:\t"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_MRW_W) != 0); - - pos += sprintf(info+pos, "\nCan write RAM:\t"); - for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next) - pos += sprintf(info+pos, "\t%d", CDROM_CAN(CDC_RAM) != 0); - - strcpy(info+pos,"\n\n"); - - return proc_dostring(ctl, write, filp, buffer, lenp, ppos); + if (cdrom_print_info("\ndrive name:\t", 0, info, &pos, CTL_NAME)) + goto done; + if (cdrom_print_info("\ndrive speed:\t", 0, info, &pos, CTL_SPEED)) + goto done; + if (cdrom_print_info("\ndrive # of slots:", 0, info, &pos, CTL_SLOTS)) + goto done; + if (cdrom_print_info("\nCan close tray:\t", + CDC_CLOSE_TRAY, info, &pos, CTL_CAPABILITY)) + goto done; + if (cdrom_print_info("\nCan open tray:\t", + CDC_OPEN_TRAY, info, &pos, CTL_CAPABILITY)) + goto done; + if (cdrom_print_info("\nCan lock tray:\t", + CDC_LOCK, info, &pos, CTL_CAPABILITY)) + goto done; + if (cdrom_print_info("\nCan change speed:", + CDC_SELECT_SPEED, info, &pos, CTL_CAPABILITY)) + goto done; + if (cdrom_print_info("\nCan select disk:", + CDC_SELECT_DISC, info, &pos, CTL_CAPABILITY)) + goto done; + if (cdrom_print_info("\nCan read multisession:", + CDC_MULTI_SESSION, info, &pos, CTL_CAPABILITY)) + goto done; + if (cdrom_print_info("\nCan read MCN:\t", + CDC_MCN, info, &pos, CTL_CAPABILITY)) + goto done; + if (cdrom_print_info("\nReports media changed:", + CDC_MEDIA_CHANGED, info, &pos, CTL_CAPABILITY)) + goto done; + if (cdrom_print_info("\nCan play audio:\t", + CDC_PLAY_AUDIO, info, &pos, CTL_CAPABILITY)) + goto done; + if (cdrom_print_info("\nCan write CD-R:\t", + CDC_CD_R, info, &pos, CTL_CAPABILITY)) + goto done; + if (cdrom_print_info("\nCan write CD-RW:", + CDC_CD_RW, info, &pos, CTL_CAPABILITY)) + goto done; + if (cdrom_print_info("\nCan read DVD:\t", + CDC_DVD, info, &pos, CTL_CAPABILITY)) + goto done; + if (cdrom_print_info("\nCan write DVD-R:", + CDC_DVD_R, info, &pos, CTL_CAPABILITY)) + goto done; + if (cdrom_print_info("\nCan write DVD-RAM:", + CDC_DVD_RAM, info, &pos, CTL_CAPABILITY)) + goto done; + if (cdrom_print_info("\nCan read MRW:\t", + CDC_MRW, info, &pos, CTL_CAPABILITY)) + goto done; + if (cdrom_print_info("\nCan write MRW:\t", + CDC_MRW_W, info, &pos, CTL_CAPABILITY)) + goto done; + if (cdrom_print_info("\nCan write RAM:\t", + CDC_RAM, info, &pos, CTL_CAPABILITY)) + goto done; + if (!scnprintf(info + pos, max_size - pos, "\n\n")) + goto done; +doit: + mutex_unlock(&cdrom_mutex); + return proc_dostring(ctl, write, filp, buffer, lenp, ppos); +done: + printk(KERN_INFO "cdrom: info buffer too small\n"); + goto doit; } /* Unfortunately, per device settings are not implemented through -- cgit v1.2.3-59-g8ed1b From f4b09303d00212ead0619db58d8ec8a0a7a94882 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 19 Jun 2007 09:18:13 +0200 Subject: [BLOCK] drop unnecessary bvec rewinding from flush_dry_bio_endio Barrier bios are completed twice - once after the barrier write itself is done and again after the whole sequence is complete. flush_dry_bio_endio() is for the first completion. It doesn't really complete the bio. It rewinds bvec and resets bio so that it can be completed again when the whole barrier sequence is complete. The bvec rewinding code has the following problems. 1. The rewinding code is wrong because filesystems may pass bvec with non zero bv_offset. 2. The block layer doesn't guarantee anything about the state of bvec array on request completion. bv_offset and len are updated iff __end_that_request_first() completes the bvec partially. Because of #2, #1 doesn't really matter (nobody cares whether bvec is re-wound correctly or not) but then again by not doing unwinding at all, we'll always give back the same bvec to the caller as full bvec completion doesn't alter bvecs and the final completion is always full completion. Drop unnecessary rewinding code. This is spotted by Neil Brown. Signed-off-by: Tejun Heo Cc: Neil Brown Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index 3e7801e49033..ef42bb2b12b6 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c @@ -527,8 +527,6 @@ int blk_do_ordered(request_queue_t *q, struct request **rqp) static int flush_dry_bio_endio(struct bio *bio, unsigned int bytes, int error) { request_queue_t *q = bio->bi_private; - struct bio_vec *bvec; - int i; /* * This is dry run, restore bio_sector and size. We'll finish @@ -540,13 +538,6 @@ static int flush_dry_bio_endio(struct bio *bio, unsigned int bytes, int error) if (bio->bi_size) return 1; - /* Rewind bvec's */ - bio->bi_idx = 0; - bio_for_each_segment(bvec, bio, i) { - bvec->bv_len += bvec->bv_offset; - bvec->bv_offset = 0; - } - /* Reset bio */ set_bit(BIO_UPTODATE, &bio->bi_flags); bio->bi_size = q->bi_size; -- cgit v1.2.3-59-g8ed1b From c2bcf3b8978c291e1b7f6499475c8403a259d4d6 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 19 Jun 2007 19:13:36 +0200 Subject: [PATCH] Remove acsi.c Originally from Boaz Harrosh It hasn't been working in 2.5 or 2.6 ever, since it's still buffer_head based. Signed-off-by: Jens Axboe --- drivers/block/Kconfig | 33 +- drivers/block/Makefile | 1 - drivers/block/acsi.c | 1825 ------------------------------------------------ 3 files changed, 1 insertion(+), 1858 deletions(-) delete mode 100644 drivers/block/acsi.c diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index b4c8319138b2..d6ad7b3ea0dc 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -56,40 +56,9 @@ config AMIGA_Z2RAM To compile this driver as a module, choose M here: the module will be called z2ram. -config ATARI_ACSI - tristate "Atari ACSI support" - depends on ATARI && BROKEN - ---help--- - This enables support for the Atari ACSI interface. The driver - supports hard disks and CD-ROMs, which have 512-byte sectors, or can - be switched to that mode. Due to the ACSI command format, only disks - up to 1 GB are supported. Special support for certain ACSI to SCSI - adapters, which could relax that, isn't included yet. The ACSI - driver is also the basis for certain other drivers for devices - attached to the ACSI bus: Atari SLM laser printer, BioNet-100 - Ethernet, and PAMsNet Ethernet. If you want to use one of these - devices, you need ACSI support, too. - - To compile this driver as a module, choose M here: the - module will be called acsi. - -comment "Some devices (e.g. CD jukebox) support multiple LUNs" - depends on ATARI && ATARI_ACSI - -config ACSI_MULTI_LUN - bool "Probe all LUNs on each ACSI device" - depends on ATARI_ACSI - help - If you have a ACSI device that supports more than one LUN (Logical - Unit Number), e.g. a CD jukebox, you should say Y here so that all - will be found by the ACSI driver. An ACSI device with multiple LUNs - acts logically like multiple ACSI devices. The vast majority of ACSI - devices have only one LUN, and so most people can say N here and - should in fact do so, because it is safer. - config ATARI_SLM tristate "Atari SLM laser printer support" - depends on ATARI && ATARI_ACSI!=n + depends on ATARI help If you have an Atari SLM laser printer, say Y to include support for it in the kernel. Otherwise, say N. This driver is also available as diff --git a/drivers/block/Makefile b/drivers/block/Makefile index dd88e33c1eb1..e5f98acc5d52 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_MAC_FLOPPY) += swim3.o obj-$(CONFIG_BLK_DEV_FD) += floppy.o obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o -obj-$(CONFIG_ATARI_ACSI) += acsi.o obj-$(CONFIG_ATARI_SLM) += acsi_slm.o obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o obj-$(CONFIG_BLK_DEV_RAM) += rd.o diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c deleted file mode 100644 index e3d9152e231a..000000000000 --- a/drivers/block/acsi.c +++ /dev/null @@ -1,1825 +0,0 @@ -/* - * acsi.c -- Device driver for Atari ACSI hard disks - * - * Copyright 1994 Roman Hodek - * - * Some parts are based on hd.c by Linus Torvalds - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - * - */ - -/* - * Still to in this file: - * - If a command ends with an error status (!= 0), the following - * REQUEST SENSE commands (4 to fill the ST-DMA FIFO) are done by - * polling the _IRQ signal (not interrupt-driven). This should be - * avoided in future because it takes up a non-neglectible time in - * the interrupt service routine while interrupts are disabled. - * Maybe a timer interrupt will get lost :-( - */ - -/* - * General notes: - * - * - All ACSI devices (disks, CD-ROMs, ...) use major number 28. - * Minors are organized like it is with SCSI: The upper 4 bits - * identify the device, the lower 4 bits the partition. - * The device numbers (the upper 4 bits) are given in the same - * order as the devices are found on the bus. - * - Up to 8 LUNs are supported for each target (if CONFIG_ACSI_MULTI_LUN - * is defined), but only a total of 16 devices (due to minor - * numbers...). Note that Atari allows only a maximum of 4 targets - * (i.e. controllers, not devices) on the ACSI bus! - * - A optimizing scheme similar to SCSI scatter-gather is implemented. - * - Removable media are supported. After a medium change to device - * is reinitialized (partition check etc.). Also, if the device - * knows the PREVENT/ALLOW MEDIUM REMOVAL command, the door should - * be locked and unlocked when mounting the first or unmounting the - * last filesystem on the device. The code is untested, because I - * don't have a removable hard disk. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for SCSI_IOCTL_GET_IDLUN */ -#include -#include /* for HDIO_GETGEO */ -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void (*do_acsi)(void) = NULL; -static struct request_queue *acsi_queue; -#define QUEUE (acsi_queue) -#define CURRENT elv_next_request(acsi_queue) - -#define DEBUG -#undef DEBUG_DETECT -#undef NO_WRITE - -#define MAX_ERRORS 8 /* Max read/write errors/sector */ -#define MAX_LUN 8 /* Max LUNs per target */ -#define MAX_DEV 16 - -#define ACSI_BUFFER_SIZE (16*1024) /* "normal" ACSI buffer size */ -#define ACSI_BUFFER_MINSIZE (2048) /* min. buf size if ext. DMA */ -#define ACSI_BUFFER_SIZE_ORDER 2 /* order size for above */ -#define ACSI_BUFFER_MINSIZE_ORDER 0 /* order size for above */ -#define ACSI_BUFFER_SECTORS (ACSI_BUFFER_SIZE/512) - -#define ACSI_BUFFER_ORDER \ - (ATARIHW_PRESENT(EXTD_DMA) ? \ - ACSI_BUFFER_MINSIZE_ORDER : \ - ACSI_BUFFER_SIZE_ORDER) - -#define ACSI_TIMEOUT (4*HZ) - -/* minimum delay between two commands */ - -#define COMMAND_DELAY 500 - -typedef enum { - NONE, HARDDISK, CDROM -} ACSI_TYPE; - -struct acsi_info_struct { - ACSI_TYPE type; /* type of device */ - unsigned target; /* target number */ - unsigned lun; /* LUN in target controller */ - unsigned removable : 1; /* Flag for removable media */ - unsigned read_only : 1; /* Flag for read only devices */ - unsigned old_atari_disk : 1; /* Is an old Atari disk */ - unsigned changed : 1; /* Medium has been changed */ - unsigned long size; /* #blocks */ - int access_count; -} acsi_info[MAX_DEV]; - -/* - * SENSE KEYS - */ - -#define NO_SENSE 0x00 -#define RECOVERED_ERROR 0x01 -#define NOT_READY 0x02 -#define MEDIUM_ERROR 0x03 -#define HARDWARE_ERROR 0x04 -#define ILLEGAL_REQUEST 0x05 -#define UNIT_ATTENTION 0x06 -#define DATA_PROTECT 0x07 -#define BLANK_CHECK 0x08 -#define COPY_ABORTED 0x0a -#define ABORTED_COMMAND 0x0b -#define VOLUME_OVERFLOW 0x0d -#define MISCOMPARE 0x0e - - -/* - * DEVICE TYPES - */ - -#define TYPE_DISK 0x00 -#define TYPE_TAPE 0x01 -#define TYPE_WORM 0x04 -#define TYPE_ROM 0x05 -#define TYPE_MOD 0x07 -#define TYPE_NO_LUN 0x7f - -/* The data returned by MODE SENSE differ between the old Atari - * hard disks and SCSI disks connected to ACSI. In the following, both - * formats are defined and some macros to operate on them potably. - */ - -typedef struct { - unsigned long dummy[2]; - unsigned long sector_size; - unsigned char format_code; -#define ATARI_SENSE_FORMAT_FIX 1 -#define ATARI_SENSE_FORMAT_CHNG 2 - unsigned char cylinders_h; - unsigned char cylinders_l; - unsigned char heads; - unsigned char reduced_h; - unsigned char reduced_l; - unsigned char precomp_h; - unsigned char precomp_l; - unsigned char landing_zone; - unsigned char steprate; - unsigned char type; -#define ATARI_SENSE_TYPE_FIXCHNG_MASK 4 -#define ATARI_SENSE_TYPE_SOFTHARD_MASK 8 -#define ATARI_SENSE_TYPE_FIX 4 -#define ATARI_SENSE_TYPE_CHNG 0 -#define ATARI_SENSE_TYPE_SOFT 0 -#define ATARI_SENSE_TYPE_HARD 8 - unsigned char sectors; -} ATARI_SENSE_DATA; - -#define ATARI_CAPACITY(sd) \ - (((int)((sd).cylinders_h<<8)|(sd).cylinders_l) * \ - (sd).heads * (sd).sectors) - - -typedef struct { - unsigned char dummy1; - unsigned char medium_type; - unsigned char dummy2; - unsigned char descriptor_size; - unsigned long block_count; - unsigned long sector_size; - /* Page 0 data */ - unsigned char page_code; - unsigned char page_size; - unsigned char page_flags; - unsigned char qualifier; -} SCSI_SENSE_DATA; - -#define SCSI_CAPACITY(sd) ((sd).block_count & 0xffffff) - - -typedef union { - ATARI_SENSE_DATA atari; - SCSI_SENSE_DATA scsi; -} SENSE_DATA; - -#define SENSE_TYPE_UNKNOWN 0 -#define SENSE_TYPE_ATARI 1 -#define SENSE_TYPE_SCSI 2 - -#define SENSE_TYPE(sd) \ - (((sd).atari.dummy[0] == 8 && \ - ((sd).atari.format_code == 1 || \ - (sd).atari.format_code == 2)) ? SENSE_TYPE_ATARI : \ - ((sd).scsi.dummy1 >= 11) ? SENSE_TYPE_SCSI : \ - SENSE_TYPE_UNKNOWN) - -#define CAPACITY(sd) \ - (SENSE_TYPE(sd) == SENSE_TYPE_ATARI ? \ - ATARI_CAPACITY((sd).atari) : \ - SCSI_CAPACITY((sd).scsi)) - -#define SECTOR_SIZE(sd) \ - (SENSE_TYPE(sd) == SENSE_TYPE_ATARI ? \ - (sd).atari.sector_size : \ - (sd).scsi.sector_size & 0xffffff) - -/* Default size if capacity cannot be determined (1 GByte) */ -#define DEFAULT_SIZE 0x1fffff - -#define CARTRCH_STAT(aip,buf) \ - (aip->old_atari_disk ? \ - (((buf)[0] & 0x7f) == 0x28) : \ - ((((buf)[0] & 0x70) == 0x70) ? \ - (((buf)[2] & 0x0f) == 0x06) : \ - (((buf)[0] & 0x0f) == 0x06))) \ - -/* These two are also exported to other drivers that work on the ACSI bus and - * need an ST-RAM buffer. */ -char *acsi_buffer; -unsigned long phys_acsi_buffer; - -static int NDevices; - -static int CurrentNReq; -static int CurrentNSect; -static char *CurrentBuffer; - -static DEFINE_SPINLOCK(acsi_lock); - - -#define SET_TIMER() mod_timer(&acsi_timer, jiffies + ACSI_TIMEOUT) -#define CLEAR_TIMER() del_timer(&acsi_timer) - -static unsigned long STramMask; -#define STRAM_ADDR(a) (((a) & STramMask) == 0) - - - -/* ACSI commands */ - -static char tur_cmd[6] = { 0x00, 0, 0, 0, 0, 0 }; -static char modesense_cmd[6] = { 0x1a, 0, 0, 0, 24, 0 }; -static char modeselect_cmd[6] = { 0x15, 0, 0, 0, 12, 0 }; -static char inquiry_cmd[6] = { 0x12, 0, 0, 0,255, 0 }; -static char reqsense_cmd[6] = { 0x03, 0, 0, 0, 4, 0 }; -static char read_cmd[6] = { 0x08, 0, 0, 0, 0, 0 }; -static char write_cmd[6] = { 0x0a, 0, 0, 0, 0, 0 }; -static char pa_med_rem_cmd[6] = { 0x1e, 0, 0, 0, 0, 0 }; - -#define CMDSET_TARG_LUN(cmd,targ,lun) \ - do { \ - cmd[0] = (cmd[0] & ~0xe0) | (targ)<<5; \ - cmd[1] = (cmd[1] & ~0xe0) | (lun)<<5; \ - } while(0) - -#define CMDSET_BLOCK(cmd,blk) \ - do { \ - unsigned long __blk = (blk); \ - cmd[3] = __blk; __blk >>= 8; \ - cmd[2] = __blk; __blk >>= 8; \ - cmd[1] = (cmd[1] & 0xe0) | (__blk & 0x1f); \ - } while(0) - -#define CMDSET_LEN(cmd,len) \ - do { \ - cmd[4] = (len); \ - } while(0) - -/* ACSI errors (from REQUEST SENSE); There are two tables, one for the - * old Atari disks and one for SCSI on ACSI disks. - */ - -struct acsi_error { - unsigned char code; - const char *text; -} atari_acsi_errors[] = { - { 0x00, "No error (??)" }, - { 0x01, "No index pulses" }, - { 0x02, "Seek not complete" }, - { 0x03, "Write fault" }, - { 0x04, "Drive not ready" }, - { 0x06, "No Track 00 signal" }, - { 0x10, "ECC error in ID field" }, - { 0x11, "Uncorrectable data error" }, - { 0x12, "ID field address mark not found" }, - { 0x13, "Data field address mark not found" }, - { 0x14, "Record not found" }, - { 0x15, "Seek error" }, - { 0x18, "Data check in no retry mode" }, - { 0x19, "ECC error during verify" }, - { 0x1a, "Access to bad block" }, - { 0x1c, "Unformatted or bad format" }, - { 0x20, "Invalid command" }, - { 0x21, "Invalid block address" }, - { 0x23, "Volume overflow" }, - { 0x24, "Invalid argument" }, - { 0x25, "Invalid drive number" }, - { 0x26, "Byte zero parity check" }, - { 0x28, "Cartride changed" }, - { 0x2c, "Error count overflow" }, - { 0x30, "Controller selftest failed" } -}, - - scsi_acsi_errors[] = { - { 0x00, "No error (??)" }, - { 0x01, "Recovered error" }, - { 0x02, "Drive not ready" }, - { 0x03, "Uncorrectable medium error" }, - { 0x04, "Hardware error" }, - { 0x05, "Illegal request" }, - { 0x06, "Unit attention (Reset or cartridge changed)" }, - { 0x07, "Data protection" }, - { 0x08, "Blank check" }, - { 0x0b, "Aborted Command" }, - { 0x0d, "Volume overflow" } -}; - - - -/***************************** Prototypes *****************************/ - -static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int - rwflag, int enable); -static int acsi_reqsense( char *buffer, int targ, int lun); -static void acsi_print_error(const unsigned char *errblk, struct acsi_info_struct *aip); -static irqreturn_t acsi_interrupt (int irq, void *data); -static void unexpected_acsi_interrupt( void ); -static void bad_rw_intr( void ); -static void read_intr( void ); -static void write_intr( void); -static void acsi_times_out( unsigned long dummy ); -static void copy_to_acsibuffer( void ); -static void copy_from_acsibuffer( void ); -static void do_end_requests( void ); -static void do_acsi_request( request_queue_t * ); -static void redo_acsi_request( void ); -static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int - cmd, unsigned long arg ); -static int acsi_open( struct inode * inode, struct file * filp ); -static int acsi_release( struct inode * inode, struct file * file ); -static void acsi_prevent_removal(struct acsi_info_struct *aip, int flag ); -static int acsi_change_blk_size( int target, int lun); -static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd ); -static int acsi_revalidate (struct gendisk *disk); - -/************************* End of Prototypes **************************/ - - -DEFINE_TIMER(acsi_timer, acsi_times_out, 0, 0); - - -#ifdef CONFIG_ATARI_SLM - -extern int attach_slm( int target, int lun ); -extern int slm_init( void ); - -#endif - - - -/*********************************************************************** - * - * ACSI primitives - * - **********************************************************************/ - - -/* - * The following two functions wait for _IRQ to become Low or High, - * resp., with a timeout. The 'timeout' parameter is in jiffies - * (10ms). - * If the functions are called with timer interrupts on (int level < - * 6), the timeout is based on the 'jiffies' variable to provide exact - * timeouts for device probing etc. - * If interrupts are disabled, the number of tries is based on the - * 'loops_per_jiffy' variable. A rough estimation is sufficient here... - */ - -#define INT_LEVEL \ - ({ unsigned __sr; \ - __asm__ __volatile__ ( "movew %/sr,%0" : "=dm" (__sr) ); \ - (__sr >> 8) & 7; \ - }) - -int acsi_wait_for_IRQ( unsigned timeout ) - -{ - if (INT_LEVEL < 6) { - unsigned long maxjif = jiffies + timeout; - while (time_before(jiffies, maxjif)) - if (!(mfp.par_dt_reg & 0x20)) return( 1 ); - } - else { - long tries = loops_per_jiffy / 8 * timeout; - while( --tries >= 0 ) - if (!(mfp.par_dt_reg & 0x20)) return( 1 ); - } - return( 0 ); /* timeout! */ -} - - -int acsi_wait_for_noIRQ( unsigned timeout ) - -{ - if (INT_LEVEL < 6) { - unsigned long maxjif = jiffies + timeout; - while (time_before(jiffies, maxjif)) - if (mfp.par_dt_reg & 0x20) return( 1 ); - } - else { - long tries = loops_per_jiffy * timeout / 8; - while( tries-- >= 0 ) - if (mfp.par_dt_reg & 0x20) return( 1 ); - } - return( 0 ); /* timeout! */ -} - -static struct timeval start_time; - -void -acsi_delay_start(void) -{ - do_gettimeofday(&start_time); -} - -/* wait from acsi_delay_start to now usec (<1E6) usec */ - -void -acsi_delay_end(long usec) -{ - struct timeval end_time; - long deltau,deltas; - do_gettimeofday(&end_time); - deltau=end_time.tv_usec - start_time.tv_usec; - deltas=end_time.tv_sec - start_time.tv_sec; - if (deltas > 1 || deltas < 0) - return; - if (deltas > 0) - deltau += 1000*1000; - if (deltau >= usec) - return; - udelay(usec-deltau); -} - -/* acsicmd_dma() sends an ACSI command and sets up the DMA to transfer - * 'blocks' blocks of 512 bytes from/to 'buffer'. - * Because the _IRQ signal is used for handshaking the command bytes, - * the ACSI interrupt has to be disabled in this function. If the end - * of the operation should be signalled by a real interrupt, it has to be - * reenabled afterwards. - */ - -static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int rwflag, int enable) - -{ unsigned long flags, paddr; - int i; - -#ifdef NO_WRITE - if (rwflag || *cmd == 0x0a) { - printk( "ACSI: Write commands disabled!\n" ); - return( 0 ); - } -#endif - - rwflag = rwflag ? 0x100 : 0; - paddr = virt_to_phys( buffer ); - - acsi_delay_end(COMMAND_DELAY); - DISABLE_IRQ(); - - local_irq_save(flags); - /* Low on A1 */ - dma_wd.dma_mode_status = 0x88 | rwflag; - MFPDELAY(); - - /* set DMA address */ - dma_wd.dma_lo = (unsigned char)paddr; - paddr >>= 8; - MFPDELAY(); - dma_wd.dma_md = (unsigned char)paddr; - paddr >>= 8; - MFPDELAY(); - if (ATARIHW_PRESENT(EXTD_DMA)) - st_dma_ext_dmahi = (unsigned short)paddr; - else - dma_wd.dma_hi = (unsigned char)paddr; - MFPDELAY(); - local_irq_restore(flags); - - /* send the command bytes except the last */ - for( i = 0; i < 5; ++i ) { - DMA_LONG_WRITE( *cmd++, 0x8a | rwflag ); - udelay(20); - if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */ - } - - /* Clear FIFO and switch DMA to correct direction */ - dma_wd.dma_mode_status = 0x92 | (rwflag ^ 0x100); - MFPDELAY(); - dma_wd.dma_mode_status = 0x92 | rwflag; - MFPDELAY(); - - /* How many sectors for DMA */ - dma_wd.fdc_acces_seccount = blocks; - MFPDELAY(); - - /* send last command byte */ - dma_wd.dma_mode_status = 0x8a | rwflag; - MFPDELAY(); - DMA_LONG_WRITE( *cmd++, 0x0a | rwflag ); - if (enable) - ENABLE_IRQ(); - udelay(80); - - return( 1 ); -} - - -/* - * acsicmd_nodma() sends an ACSI command that requires no DMA. - */ - -int acsicmd_nodma( const char *cmd, int enable) - -{ int i; - - acsi_delay_end(COMMAND_DELAY); - DISABLE_IRQ(); - - /* send first command byte */ - dma_wd.dma_mode_status = 0x88; - MFPDELAY(); - DMA_LONG_WRITE( *cmd++, 0x8a ); - udelay(20); - if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */ - - /* send the intermediate command bytes */ - for( i = 0; i < 4; ++i ) { - DMA_LONG_WRITE( *cmd++, 0x8a ); - udelay(20); - if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */ - } - - /* send last command byte */ - DMA_LONG_WRITE( *cmd++, 0x0a ); - if (enable) - ENABLE_IRQ(); - udelay(80); - - return( 1 ); - /* Note that the ACSI interrupt is still disabled after this - * function. If you want to get the IRQ delivered, enable it manually! - */ -} - - -static int acsi_reqsense( char *buffer, int targ, int lun) - -{ - CMDSET_TARG_LUN( reqsense_cmd, targ, lun); - if (!acsicmd_dma( reqsense_cmd, buffer, 1, 0, 0 )) return( 0 ); - if (!acsi_wait_for_IRQ( 10 )) return( 0 ); - acsi_getstatus(); - if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 ); - if (!acsi_wait_for_IRQ( 10 )) return( 0 ); - acsi_getstatus(); - if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 ); - if (!acsi_wait_for_IRQ( 10 )) return( 0 ); - acsi_getstatus(); - if (!acsicmd_nodma( reqsense_cmd, 0 )) return( 0 ); - if (!acsi_wait_for_IRQ( 10 )) return( 0 ); - acsi_getstatus(); - dma_cache_maintenance( virt_to_phys(buffer), 16, 0 ); - - return( 1 ); -} - - -/* - * ACSI status phase: get the status byte from the bus - * - * I've seen several times that a 0xff status is read, propably due to - * a timing error. In this case, the procedure is repeated after the - * next _IRQ edge. - */ - -int acsi_getstatus( void ) - -{ int status; - - DISABLE_IRQ(); - for(;;) { - if (!acsi_wait_for_IRQ( 100 )) { - acsi_delay_start(); - return( -1 ); - } - dma_wd.dma_mode_status = 0x8a; - MFPDELAY(); - status = dma_wd.fdc_acces_seccount; - if (status != 0xff) break; -#ifdef DEBUG - printk("ACSI: skipping 0xff status byte\n" ); -#endif - udelay(40); - acsi_wait_for_noIRQ( 20 ); - } - dma_wd.dma_mode_status = 0x80; - udelay(40); - acsi_wait_for_noIRQ( 20 ); - - acsi_delay_start(); - return( status & 0x1f ); /* mask of the device# */ -} - - -#if (defined(CONFIG_ATARI_SLM) || defined(CONFIG_ATARI_SLM_MODULE)) - -/* Receive data in an extended status phase. Needed by SLM printer. */ - -int acsi_extstatus( char *buffer, int cnt ) - -{ int status; - - DISABLE_IRQ(); - udelay(80); - while( cnt-- > 0 ) { - if (!acsi_wait_for_IRQ( 40 )) return( 0 ); - dma_wd.dma_mode_status = 0x8a; - MFPDELAY(); - status = dma_wd.fdc_acces_seccount; - MFPDELAY(); - *buffer++ = status & 0xff; - udelay(40); - } - return( 1 ); -} - - -/* Finish an extended status phase */ - -void acsi_end_extstatus( void ) - -{ - dma_wd.dma_mode_status = 0x80; - udelay(40); - acsi_wait_for_noIRQ( 20 ); - acsi_delay_start(); -} - - -/* Send data in an extended command phase */ - -int acsi_extcmd( unsigned char *buffer, int cnt ) - -{ - while( cnt-- > 0 ) { - DMA_LONG_WRITE( *buffer++, 0x8a ); - udelay(20); - if (!acsi_wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */ - } - return( 1 ); -} - -#endif - - -static void acsi_print_error(const unsigned char *errblk, struct acsi_info_struct *aip) - -{ int atari_err, i, errcode; - struct acsi_error *arr; - - atari_err = aip->old_atari_disk; - if (atari_err) - errcode = errblk[0] & 0x7f; - else - if ((errblk[0] & 0x70) == 0x70) - errcode = errblk[2] & 0x0f; - else - errcode = errblk[0] & 0x0f; - - printk( KERN_ERR "ACSI error 0x%02x", errcode ); - - if (errblk[0] & 0x80) - printk( " for sector %d", - ((errblk[1] & 0x1f) << 16) | - (errblk[2] << 8) | errblk[0] ); - - arr = atari_err ? atari_acsi_errors : scsi_acsi_errors; - i = atari_err ? sizeof(atari_acsi_errors)/sizeof(*atari_acsi_errors) : - sizeof(scsi_acsi_errors)/sizeof(*scsi_acsi_errors); - - for( --i; i >= 0; --i ) - if (arr[i].code == errcode) break; - if (i >= 0) - printk( ": %s\n", arr[i].text ); -} - -/******************************************************************* - * - * ACSI interrupt routine - * Test, if this is a ACSI interrupt and call the irq handler - * Otherwise ignore this interrupt. - * - *******************************************************************/ - -static irqreturn_t acsi_interrupt(int irq, void *data ) - -{ void (*acsi_irq_handler)(void) = do_acsi; - - do_acsi = NULL; - CLEAR_TIMER(); - - if (!acsi_irq_handler) - acsi_irq_handler = unexpected_acsi_interrupt; - acsi_irq_handler(); - return IRQ_HANDLED; -} - - -/****************************************************************** - * - * The Interrupt handlers - * - *******************************************************************/ - - -static void unexpected_acsi_interrupt( void ) - -{ - printk( KERN_WARNING "Unexpected ACSI interrupt\n" ); -} - - -/* This function is called in case of errors. Because we cannot reset - * the ACSI bus or a single device, there is no other choice than - * retrying several times :-( - */ - -static void bad_rw_intr( void ) - -{ - if (!CURRENT) - return; - - if (++CURRENT->errors >= MAX_ERRORS) - end_request(CURRENT, 0); - /* Otherwise just retry */ -} - - -static void read_intr( void ) - -{ int status; - - status = acsi_getstatus(); - if (status != 0) { - struct gendisk *disk = CURRENT->rq_disk; - struct acsi_info_struct *aip = disk->private_data; - printk(KERN_ERR "%s: ", disk->disk_name); - if (!acsi_reqsense(acsi_buffer, aip->target, aip->lun)) - printk( "ACSI error and REQUEST SENSE failed (status=0x%02x)\n", status ); - else { - acsi_print_error(acsi_buffer, aip); - if (CARTRCH_STAT(aip, acsi_buffer)) - aip->changed = 1; - } - ENABLE_IRQ(); - bad_rw_intr(); - redo_acsi_request(); - return; - } - - dma_cache_maintenance( virt_to_phys(CurrentBuffer), CurrentNSect*512, 0 ); - if (CurrentBuffer == acsi_buffer) - copy_from_acsibuffer(); - - do_end_requests(); - redo_acsi_request(); -} - - -static void write_intr(void) - -{ int status; - - status = acsi_getstatus(); - if (status != 0) { - struct gendisk *disk = CURRENT->rq_disk; - struct acsi_info_struct *aip = disk->private_data; - printk( KERN_ERR "%s: ", disk->disk_name); - if (!acsi_reqsense( acsi_buffer, aip->target, aip->lun)) - printk( "ACSI error and REQUEST SENSE failed (status=0x%02x)\n", status ); - else { - acsi_print_error(acsi_buffer, aip); - if (CARTRCH_STAT(aip, acsi_buffer)) - aip->changed = 1; - } - bad_rw_intr(); - redo_acsi_request(); - return; - } - - do_end_requests(); - redo_acsi_request(); -} - - -static void acsi_times_out( unsigned long dummy ) - -{ - DISABLE_IRQ(); - if (!do_acsi) return; - - do_acsi = NULL; - printk( KERN_ERR "ACSI timeout\n" ); - if (!CURRENT) - return; - if (++CURRENT->errors >= MAX_ERRORS) { -#ifdef DEBUG - printk( KERN_ERR "ACSI: too many errors.\n" ); -#endif - end_request(CURRENT, 0); - } - - redo_acsi_request(); -} - - - -/*********************************************************************** - * - * Scatter-gather utility functions - * - ***********************************************************************/ - - -static void copy_to_acsibuffer( void ) - -{ int i; - char *src, *dst; - struct buffer_head *bh; - - src = CURRENT->buffer; - dst = acsi_buffer; - bh = CURRENT->bh; - - if (!bh) - memcpy( dst, src, CurrentNSect*512 ); - else - for( i = 0; i < CurrentNReq; ++i ) { - memcpy( dst, src, bh->b_size ); - dst += bh->b_size; - if ((bh = bh->b_reqnext)) - src = bh->b_data; - } -} - - -static void copy_from_acsibuffer( void ) - -{ int i; - char *src, *dst; - struct buffer_head *bh; - - dst = CURRENT->buffer; - src = acsi_buffer; - bh = CURRENT->bh; - - if (!bh) - memcpy( dst, src, CurrentNSect*512 ); - else - for( i = 0; i < CurrentNReq; ++i ) { - memcpy( dst, src, bh->b_size ); - src += bh->b_size; - if ((bh = bh->b_reqnext)) - dst = bh->b_data; - } -} - - -static void do_end_requests( void ) - -{ int i, n; - - if (!CURRENT->bh) { - CURRENT->nr_sectors -= CurrentNSect; - CURRENT->current_nr_sectors -= CurrentNSect; - CURRENT->sector += CurrentNSect; - if (CURRENT->nr_sectors == 0) - end_request(CURRENT, 1); - } - else { - for( i = 0; i < CurrentNReq; ++i ) { - n = CURRENT->bh->b_size >> 9; - CURRENT->nr_sectors -= n; - CURRENT->current_nr_sectors -= n; - CURRENT->sector += n; - end_request(CURRENT, 1); - } - } -} - - - - -/*********************************************************************** - * - * do_acsi_request and friends - * - ***********************************************************************/ - -static void do_acsi_request( request_queue_t * q ) - -{ - stdma_lock( acsi_interrupt, NULL ); - redo_acsi_request(); -} - - -static void redo_acsi_request( void ) -{ - unsigned block, target, lun, nsect; - char *buffer; - unsigned long pbuffer; - struct buffer_head *bh; - struct gendisk *disk; - struct acsi_info_struct *aip; - - repeat: - CLEAR_TIMER(); - - if (do_acsi) - return; - - if (!CURRENT) { - do_acsi = NULL; - ENABLE_IRQ(); - stdma_release(); - return; - } - - disk = CURRENT->rq_disk; - aip = disk->private_data; - if (CURRENT->bh) { - if (!CURRENT->bh && !buffer_locked(CURRENT->bh)) - panic("ACSI: block not locked"); - } - - block = CURRENT->sector; - if (block+CURRENT->nr_sectors >= get_capacity(disk)) { -#ifdef DEBUG - printk( "%s: attempted access for blocks %d...%ld past end of device at block %ld.\n", - disk->disk_name, - block, block + CURRENT->nr_sectors - 1, - get_capacity(disk)); -#endif - end_request(CURRENT, 0); - goto repeat; - } - if (aip->changed) { - printk( KERN_NOTICE "%s: request denied because cartridge has " - "been changed.\n", disk->disk_name); - end_request(CURRENT, 0); - goto repeat; - } - - target = aip->target; - lun = aip->lun; - - /* Find out how many sectors should be transferred from/to - * consecutive buffers and thus can be done with a single command. - */ - buffer = CURRENT->buffer; - pbuffer = virt_to_phys(buffer); - nsect = CURRENT->current_nr_sectors; - CurrentNReq = 1; - - if ((bh = CURRENT->bh) && bh != CURRENT->bhtail) { - if (!STRAM_ADDR(pbuffer)) { - /* If transfer is done via the ACSI buffer anyway, we can - * assemble as much bh's as fit in the buffer. - */ - while( (bh = bh->b_reqnext) ) { - if (nsect + (bh->b_size>>9) > ACSI_BUFFER_SECTORS) break; - nsect += bh->b_size >> 9; - ++CurrentNReq; - if (bh == CURRENT->bhtail) break; - } - buffer = acsi_buffer; - pbuffer = phys_acsi_buffer; - } - else { - unsigned long pendadr, pnewadr; - pendadr = pbuffer + nsect*512; - while( (bh = bh->b_reqnext) ) { - pnewadr = virt_to_phys(bh->b_data); - if (!STRAM_ADDR(pnewadr) || pendadr != pnewadr) break; - nsect += bh->b_size >> 9; - pendadr = pnewadr + bh->b_size; - ++CurrentNReq; - if (bh == CURRENT->bhtail) break; - } - } - } - else { - if (!STRAM_ADDR(pbuffer)) { - buffer = acsi_buffer; - pbuffer = phys_acsi_buffer; - if (nsect > ACSI_BUFFER_SECTORS) - nsect = ACSI_BUFFER_SECTORS; - } - } - CurrentBuffer = buffer; - CurrentNSect = nsect; - - if (rq_data_dir(CURRENT) == WRITE) { - CMDSET_TARG_LUN( write_cmd, target, lun ); - CMDSET_BLOCK( write_cmd, block ); - CMDSET_LEN( write_cmd, nsect ); - if (buffer == acsi_buffer) - copy_to_acsibuffer(); - dma_cache_maintenance( pbuffer, nsect*512, 1 ); - do_acsi = write_intr; - if (!acsicmd_dma( write_cmd, buffer, nsect, 1, 1)) { - do_acsi = NULL; - printk( KERN_ERR "ACSI (write): Timeout in command block\n" ); - bad_rw_intr(); - goto repeat; - } - SET_TIMER(); - return; - } - if (rq_data_dir(CURRENT) == READ) { - CMDSET_TARG_LUN( read_cmd, target, lun ); - CMDSET_BLOCK( read_cmd, block ); - CMDSET_LEN( read_cmd, nsect ); - do_acsi = read_intr; - if (!acsicmd_dma( read_cmd, buffer, nsect, 0, 1)) { - do_acsi = NULL; - printk( KERN_ERR "ACSI (read): Timeout in command block\n" ); - bad_rw_intr(); - goto repeat; - } - SET_TIMER(); - return; - } - panic("unknown ACSI command"); -} - - - -/*********************************************************************** - * - * Misc functions: ioctl, open, release, check_change, ... - * - ***********************************************************************/ - -static int acsi_getgeo(struct block_device *bdev, struct hd_geometry *geo) -{ - struct acsi_info_struct *aip = bdev->bd_disk->private_data; - - /* - * Just fake some geometry here, it's nonsense anyway - * To make it easy, use Adaptec's usual 64/32 mapping - */ - geo->heads = 64; - geo->sectors = 32; - geo->cylinders = aip->size >> 11; - return 0; -} - -static int acsi_ioctl( struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg ) -{ - struct gendisk *disk = inode->i_bdev->bd_disk; - struct acsi_info_struct *aip = disk->private_data; - switch (cmd) { - case SCSI_IOCTL_GET_IDLUN: - /* SCSI compatible GET_IDLUN call to get target's ID and LUN number */ - put_user( aip->target | (aip->lun << 8), - &((Scsi_Idlun *) arg)->dev_id ); - put_user( 0, &((Scsi_Idlun *) arg)->host_unique_id ); - return 0; - default: - return -EINVAL; - } -} - - -/* - * Open a device, check for read-only and lock the medium if it is - * removable. - * - * Changes by Martin Rogge, 9th Aug 1995: - * Check whether check_disk_change (and therefore revalidate_acsidisk) - * was successful. They fail when there is no medium in the drive. - * - * The problem of media being changed during an operation can be - * ignored because of the prevent_removal code. - * - * Added check for the validity of the device number. - * - */ - -static int acsi_open( struct inode * inode, struct file * filp ) -{ - struct gendisk *disk = inode->i_bdev->bd_disk; - struct acsi_info_struct *aip = disk->private_data; - - if (aip->access_count == 0 && aip->removable) { -#if 0 - aip->changed = 1; /* safety first */ -#endif - check_disk_change( inode->i_bdev ); - if (aip->changed) /* revalidate was not successful (no medium) */ - return -ENXIO; - acsi_prevent_removal(aip, 1); - } - aip->access_count++; - - if (filp && filp->f_mode) { - check_disk_change( inode->i_bdev ); - if (filp->f_mode & 2) { - if (aip->read_only) { - acsi_release( inode, filp ); - return -EROFS; - } - } - } - - return 0; -} - -/* - * Releasing a block device means we sync() it, so that it can safely - * be forgotten about... - */ - -static int acsi_release( struct inode * inode, struct file * file ) -{ - struct gendisk *disk = inode->i_bdev->bd_disk; - struct acsi_info_struct *aip = disk->private_data; - if (--aip->access_count == 0 && aip->removable) - acsi_prevent_removal(aip, 0); - return( 0 ); -} - -/* - * Prevent or allow a media change for removable devices. - */ - -static void acsi_prevent_removal(struct acsi_info_struct *aip, int flag) -{ - stdma_lock( NULL, NULL ); - - CMDSET_TARG_LUN(pa_med_rem_cmd, aip->target, aip->lun); - CMDSET_LEN( pa_med_rem_cmd, flag ); - - if (acsicmd_nodma(pa_med_rem_cmd, 0) && acsi_wait_for_IRQ(3*HZ)) - acsi_getstatus(); - /* Do not report errors -- some devices may not know this command. */ - - ENABLE_IRQ(); - stdma_release(); -} - -static int acsi_media_change(struct gendisk *disk) -{ - struct acsi_info_struct *aip = disk->private_data; - - if (!aip->removable) - return 0; - - if (aip->changed) - /* We can be sure that the medium has been changed -- REQUEST - * SENSE has reported this earlier. - */ - return 1; - - /* If the flag isn't set, make a test by reading block 0. - * If errors happen, it seems to be better to say "changed"... - */ - stdma_lock( NULL, NULL ); - CMDSET_TARG_LUN(read_cmd, aip->target, aip->lun); - CMDSET_BLOCK( read_cmd, 0 ); - CMDSET_LEN( read_cmd, 1 ); - if (acsicmd_dma(read_cmd, acsi_buffer, 1, 0, 0) && - acsi_wait_for_IRQ(3*HZ)) { - if (acsi_getstatus()) { - if (acsi_reqsense(acsi_buffer, aip->target, aip->lun)) { - if (CARTRCH_STAT(aip, acsi_buffer)) - aip->changed = 1; - } - else { - printk( KERN_ERR "%s: REQUEST SENSE failed in test for " - "medium change; assuming a change\n", disk->disk_name ); - aip->changed = 1; - } - } - } - else { - printk( KERN_ERR "%s: Test for medium changed timed out; " - "assuming a change\n", disk->disk_name); - aip->changed = 1; - } - ENABLE_IRQ(); - stdma_release(); - - /* Now, after reading a block, the changed status is surely valid. */ - return aip->changed; -} - - -static int acsi_change_blk_size( int target, int lun) - -{ int i; - - for (i=0; i<12; i++) - acsi_buffer[i] = 0; - - acsi_buffer[3] = 8; - acsi_buffer[10] = 2; - CMDSET_TARG_LUN( modeselect_cmd, target, lun); - - if (!acsicmd_dma( modeselect_cmd, acsi_buffer, 1,1,0) || - !acsi_wait_for_IRQ( 3*HZ ) || - acsi_getstatus() != 0 ) { - return(0); - } - return(1); -} - - -static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd ) - -{ - int page; - - CMDSET_TARG_LUN( modesense_cmd, target, lun ); - for (page=0; page<4; page++) { - modesense_cmd[2] = page; - if (!acsicmd_dma( modesense_cmd, acsi_buffer, 1, 0, 0 ) || - !acsi_wait_for_IRQ( 3*HZ ) || - acsi_getstatus()) - continue; - - /* read twice to jump over the second 16-byte border! */ - udelay(300); - if (acsi_wait_for_noIRQ( 20 ) && - acsicmd_nodma( modesense_cmd, 0 ) && - acsi_wait_for_IRQ( 3*HZ ) && - acsi_getstatus() == 0) - break; - } - if (page == 4) { - return(0); - } - - dma_cache_maintenance( phys_acsi_buffer, sizeof(SENSE_DATA), 0 ); - *sd = *(SENSE_DATA *)acsi_buffer; - - /* Validity check, depending on type of data */ - - switch( SENSE_TYPE(*sd) ) { - - case SENSE_TYPE_ATARI: - if (CAPACITY(*sd) == 0) - goto invalid_sense; - break; - - case SENSE_TYPE_SCSI: - if (sd->scsi.descriptor_size != 8) - goto invalid_sense; - break; - - case SENSE_TYPE_UNKNOWN: - - printk( KERN_ERR "ACSI target %d, lun %d: Cannot interpret " - "sense data\n", target, lun ); - - invalid_sense: - -#ifdef DEBUG - { int i; - printk( "Mode sense data for ACSI target %d, lun %d seem not valid:", - target, lun ); - for( i = 0; i < sizeof(SENSE_DATA); ++i ) - printk( "%02x ", (unsigned char)acsi_buffer[i] ); - printk( "\n" ); - } -#endif - return( 0 ); - } - - return( 1 ); -} - - - -/******************************************************************* - * - * Initialization - * - ********************************************************************/ - - -extern struct block_device_operations acsi_fops; - -static struct gendisk *acsi_gendisk[MAX_DEV]; - -#define MAX_SCSI_DEVICE_CODE 10 - -static const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = -{ - "Direct-Access ", - "Sequential-Access", - "Printer ", - "Processor ", - "WORM ", - "CD-ROM ", - "Scanner ", - "Optical Device ", - "Medium Changer ", - "Communications " -}; - -static void print_inquiry(unsigned char *data) -{ - int i; - - printk(KERN_INFO " Vendor: "); - for (i = 8; i < 16; i++) - { - if (data[i] >= 0x20 && i < data[4] + 5) - printk("%c", data[i]); - else - printk(" "); - } - - printk(" Model: "); - for (i = 16; i < 32; i++) - { - if (data[i] >= 0x20 && i < data[4] + 5) - printk("%c", data[i]); - else - printk(" "); - } - - printk(" Rev: "); - for (i = 32; i < 36; i++) - { - if (data[i] >= 0x20 && i < data[4] + 5) - printk("%c", data[i]); - else - printk(" "); - } - - printk("\n"); - - i = data[0] & 0x1f; - - printk(KERN_INFO " Type: %s ", (i < MAX_SCSI_DEVICE_CODE - ? scsi_device_types[i] - : "Unknown ")); - printk(" ANSI SCSI revision: %02x", data[2] & 0x07); - if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1) - printk(" CCS\n"); - else - printk("\n"); -} - - -/* - * Changes by Martin Rogge, 9th Aug 1995: - * acsi_devinit has been taken out of acsi_geninit, because it needs - * to be called from revalidate_acsidisk. The result of request sense - * is now checked for DRIVE NOT READY. - * - * The structure *aip is only valid when acsi_devinit returns - * DEV_SUPPORTED. - * - */ - -#define DEV_NONE 0 -#define DEV_UNKNOWN 1 -#define DEV_SUPPORTED 2 -#define DEV_SLM 3 - -static int acsi_devinit(struct acsi_info_struct *aip) -{ - int status, got_inquiry; - SENSE_DATA sense; - unsigned char reqsense, extsense; - - /*****************************************************************/ - /* Do a TEST UNIT READY command to test the presence of a device */ - /*****************************************************************/ - - CMDSET_TARG_LUN(tur_cmd, aip->target, aip->lun); - if (!acsicmd_nodma(tur_cmd, 0)) { - /* timed out -> no device here */ -#ifdef DEBUG_DETECT - printk("target %d lun %d: timeout\n", aip->target, aip->lun); -#endif - return DEV_NONE; - } - - /*************************/ - /* Read the ACSI status. */ - /*************************/ - - status = acsi_getstatus(); - if (status) { - if (status == 0x12) { - /* The SLM printer should be the only device that - * responds with the error code in the status byte. In - * correct status bytes, bit 4 is never set. - */ - printk( KERN_INFO "Detected SLM printer at id %d lun %d\n", - aip->target, aip->lun); - return DEV_SLM; - } - /* ignore CHECK CONDITION, since some devices send a - UNIT ATTENTION */ - if ((status & 0x1e) != 0x2) { -#ifdef DEBUG_DETECT - printk("target %d lun %d: status %d\n", - aip->target, aip->lun, status); -#endif - return DEV_UNKNOWN; - } - } - - /*******************************/ - /* Do a REQUEST SENSE command. */ - /*******************************/ - - if (!acsi_reqsense(acsi_buffer, aip->target, aip->lun)) { - printk( KERN_WARNING "acsi_reqsense failed\n"); - acsi_buffer[0] = 0; - acsi_buffer[2] = UNIT_ATTENTION; - } - reqsense = acsi_buffer[0]; - extsense = acsi_buffer[2] & 0xf; - if (status) { - if ((reqsense & 0x70) == 0x70) { /* extended sense */ - if (extsense != UNIT_ATTENTION && - extsense != NOT_READY) { -#ifdef DEBUG_DETECT - printk("target %d lun %d: extended sense %d\n", - aip->target, aip->lun, extsense); -#endif - return DEV_UNKNOWN; - } - } - else { - if (reqsense & 0x7f) { -#ifdef DEBUG_DETECT - printk("target %d lun %d: sense %d\n", - aip->target, aip->lun, reqsense); -#endif - return DEV_UNKNOWN; - } - } - } - else - if (reqsense == 0x4) { /* SH204 Bug workaround */ -#ifdef DEBUG_DETECT - printk("target %d lun %d status=0 sense=4\n", - aip->target, aip->lun); -#endif - return DEV_UNKNOWN; - } - - /***********************************************************/ - /* Do an INQUIRY command to get more infos on this device. */ - /***********************************************************/ - - /* Assume default values */ - aip->removable = 1; - aip->read_only = 0; - aip->old_atari_disk = 0; - aip->changed = (extsense == NOT_READY); /* medium inserted? */ - aip->size = DEFAULT_SIZE; - got_inquiry = 0; - /* Fake inquiry result for old atari disks */ - memcpy(acsi_buffer, "\000\000\001\000 Adaptec 40xx" - " ", 40); - CMDSET_TARG_LUN(inquiry_cmd, aip->target, aip->lun); - if (acsicmd_dma(inquiry_cmd, acsi_buffer, 1, 0, 0) && - acsi_getstatus() == 0) { - acsicmd_nodma(inquiry_cmd, 0); - acsi_getstatus(); - dma_cache_maintenance( phys_acsi_buffer, 256, 0 ); - got_inquiry = 1; - aip->removable = !!(acsi_buffer[1] & 0x80); - } - if (aip->type == NONE) /* only at boot time */ - print_inquiry(acsi_buffer); - switch(acsi_buffer[0]) { - case TYPE_DISK: - aip->type = HARDDISK; - break; - case TYPE_ROM: - aip->type = CDROM; - aip->read_only = 1; - break; - default: - return DEV_UNKNOWN; - } - /****************************/ - /* Do a MODE SENSE command. */ - /****************************/ - - if (!acsi_mode_sense(aip->target, aip->lun, &sense)) { - printk( KERN_WARNING "No mode sense data.\n" ); - return DEV_UNKNOWN; - } - if ((SECTOR_SIZE(sense) != 512) && - ((aip->type != CDROM) || - !acsi_change_blk_size(aip->target, aip->lun) || - !acsi_mode_sense(aip->target, aip->lun, &sense) || - (SECTOR_SIZE(sense) != 512))) { - printk( KERN_WARNING "Sector size != 512 not supported.\n" ); - return DEV_UNKNOWN; - } - /* There are disks out there that claim to have 0 sectors... */ - if (CAPACITY(sense)) - aip->size = CAPACITY(sense); /* else keep DEFAULT_SIZE */ - if (!got_inquiry && SENSE_TYPE(sense) == SENSE_TYPE_ATARI) { - /* If INQUIRY failed and the sense data suggest an old - * Atari disk (SH20x, Megafile), the disk is not removable - */ - aip->removable = 0; - aip->old_atari_disk = 1; - } - - /******************/ - /* We've done it. */ - /******************/ - - return DEV_SUPPORTED; -} - -EXPORT_SYMBOL(acsi_delay_start); -EXPORT_SYMBOL(acsi_delay_end); -EXPORT_SYMBOL(acsi_wait_for_IRQ); -EXPORT_SYMBOL(acsi_wait_for_noIRQ); -EXPORT_SYMBOL(acsicmd_nodma); -EXPORT_SYMBOL(acsi_getstatus); -EXPORT_SYMBOL(acsi_buffer); -EXPORT_SYMBOL(phys_acsi_buffer); - -#ifdef CONFIG_ATARI_SLM_MODULE -void acsi_attach_SLMs( int (*attach_func)( int, int ) ); - -EXPORT_SYMBOL(acsi_extstatus); -EXPORT_SYMBOL(acsi_end_extstatus); -EXPORT_SYMBOL(acsi_extcmd); -EXPORT_SYMBOL(acsi_attach_SLMs); - -/* to remember IDs of SLM devices, SLM module is loaded later - * (index is target#, contents is lun#, -1 means "no SLM") */ -int SLM_devices[8]; -#endif - -static struct block_device_operations acsi_fops = { - .owner = THIS_MODULE, - .open = acsi_open, - .release = acsi_release, - .ioctl = acsi_ioctl, - .getgeo = acsi_getgeo, - .media_changed = acsi_media_change, - .revalidate_disk= acsi_revalidate, -}; - -#ifdef CONFIG_ATARI_SLM_MODULE -/* call attach_slm() for each device that is a printer; needed for init of SLM - * driver as a module, since it's not yet present if acsi.c is inited and thus - * the bus gets scanned. */ -void acsi_attach_SLMs( int (*attach_func)( int, int ) ) -{ - int i, n = 0; - - for( i = 0; i < 8; ++i ) - if (SLM_devices[i] >= 0) - n += (*attach_func)( i, SLM_devices[i] ); - printk( KERN_INFO "Found %d SLM printer(s) total.\n", n ); -} -#endif /* CONFIG_ATARI_SLM_MODULE */ - - -int acsi_init( void ) -{ - int err = 0; - int i, target, lun; - struct acsi_info_struct *aip; -#ifdef CONFIG_ATARI_SLM - int n_slm = 0; -#endif - if (!MACH_IS_ATARI || !ATARIHW_PRESENT(ACSI)) - return 0; - if (register_blkdev(ACSI_MAJOR, "ad")) { - err = -EBUSY; - goto out1; - } - if (!(acsi_buffer = - (char *)atari_stram_alloc(ACSI_BUFFER_SIZE, "acsi"))) { - err = -ENOMEM; - printk( KERN_ERR "Unable to get ACSI ST-Ram buffer.\n" ); - goto out2; - } - phys_acsi_buffer = virt_to_phys( acsi_buffer ); - STramMask = ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 : 0xff000000; - - acsi_queue = blk_init_queue(do_acsi_request, &acsi_lock); - if (!acsi_queue) { - err = -ENOMEM; - goto out2a; - } -#ifdef CONFIG_ATARI_SLM - err = slm_init(); -#endif - if (err) - goto out3; - - printk( KERN_INFO "Probing ACSI devices:\n" ); - NDevices = 0; -#ifdef CONFIG_ATARI_SLM_MODULE - for( i = 0; i < 8; ++i ) - SLM_devices[i] = -1; -#endif - stdma_lock(NULL, NULL); - - for (target = 0; target < 8 && NDevices < MAX_DEV; ++target) { - lun = 0; - do { - aip = &acsi_info[NDevices]; - aip->type = NONE; - aip->target = target; - aip->lun = lun; - i = acsi_devinit(aip); - switch (i) { - case DEV_SUPPORTED: - printk( KERN_INFO "Detected "); - switch (aip->type) { - case HARDDISK: - printk("disk"); - break; - case CDROM: - printk("cdrom"); - break; - default: - } - printk(" ad%c at id %d lun %d ", - 'a' + NDevices, target, lun); - if (aip->removable) - printk("(removable) "); - if (aip->read_only) - printk("(read-only) "); - if (aip->size == DEFAULT_SIZE) - printk(" unkown size, using default "); - printk("%ld MByte\n", - (aip->size*512+1024*1024/2)/(1024*1024)); - NDevices++; - break; - case DEV_SLM: -#ifdef CONFIG_ATARI_SLM - n_slm += attach_slm( target, lun ); - break; -#endif -#ifdef CONFIG_ATARI_SLM_MODULE - SLM_devices[target] = lun; - break; -#endif - /* neither of the above: fall through to unknown device */ - case DEV_UNKNOWN: - printk( KERN_INFO "Detected unsupported device at " - "id %d lun %d\n", target, lun); - break; - } - } -#ifdef CONFIG_ACSI_MULTI_LUN - while (i != DEV_NONE && ++lun < MAX_LUN); -#else - while (0); -#endif - } - - /* reenable interrupt */ - ENABLE_IRQ(); - stdma_release(); - -#ifndef CONFIG_ATARI_SLM - printk( KERN_INFO "Found %d ACSI device(s) total.\n", NDevices ); -#else - printk( KERN_INFO "Found %d ACSI device(s) and %d SLM printer(s) total.\n", - NDevices, n_slm ); -#endif - err = -ENOMEM; - for( i = 0; i < NDevices; ++i ) { - acsi_gendisk[i] = alloc_disk(16); - if (!acsi_gendisk[i]) - goto out4; - } - - for( i = 0; i < NDevices; ++i ) { - struct gendisk *disk = acsi_gendisk[i]; - sprintf(disk->disk_name, "ad%c", 'a'+i); - aip = &acsi_info[NDevices]; - disk->major = ACSI_MAJOR; - disk->first_minor = i << 4; - if (acsi_info[i].type != HARDDISK) - disk->minors = 1; - disk->fops = &acsi_fops; - disk->private_data = &acsi_info[i]; - set_capacity(disk, acsi_info[i].size); - disk->queue = acsi_queue; - add_disk(disk); - } - return 0; -out4: - while (i--) - put_disk(acsi_gendisk[i]); -out3: - blk_cleanup_queue(acsi_queue); -out2a: - atari_stram_free( acsi_buffer ); -out2: - unregister_blkdev( ACSI_MAJOR, "ad" ); -out1: - return err; -} - - -#ifdef MODULE - -MODULE_LICENSE("GPL"); - -int init_module(void) -{ - int err; - - if ((err = acsi_init())) - return( err ); - printk( KERN_INFO "ACSI driver loaded as module.\n"); - return( 0 ); -} - -void cleanup_module(void) -{ - int i; - del_timer( &acsi_timer ); - blk_cleanup_queue(acsi_queue); - atari_stram_free( acsi_buffer ); - - if (unregister_blkdev( ACSI_MAJOR, "ad" ) != 0) - printk( KERN_ERR "acsi: cleanup_module failed\n"); - - for (i = 0; i < NDevices; i++) { - del_gendisk(acsi_gendisk[i]); - put_disk(acsi_gendisk[i]); - } -} -#endif - -/* - * This routine is called to flush all partitions and partition tables - * for a changed scsi disk, and then re-read the new partition table. - * If we are revalidating a disk because of a media change, then we - * enter with usage == 0. If we are using an ioctl, we automatically have - * usage == 1 (we need an open channel to use an ioctl :-), so this - * is our limit. - * - * Changes by Martin Rogge, 9th Aug 1995: - * got cd-roms to work by calling acsi_devinit. There are only two problems: - * First, if there is no medium inserted, the status will remain "changed". - * That is no problem at all, but our design of three-valued logic (medium - * changed, medium not changed, no medium inserted). - * Secondly the check could fail completely and the drive could deliver - * nonsensical data, which could mess up the acsi_info[] structure. In - * that case we try to make the entry safe. - * - */ - -static int acsi_revalidate(struct gendisk *disk) -{ - struct acsi_info_struct *aip = disk->private_data; - stdma_lock( NULL, NULL ); - if (acsi_devinit(aip) != DEV_SUPPORTED) { - printk( KERN_ERR "ACSI: revalidate failed for target %d lun %d\n", - aip->target, aip->lun); - aip->size = 0; - aip->read_only = 1; - aip->removable = 1; - aip->changed = 1; /* next acsi_open will try again... */ - } - - ENABLE_IRQ(); - stdma_release(); - set_capacity(disk, aip->size); - return 0; -} -- cgit v1.2.3-59-g8ed1b From 9cff3b383dad193b0762c27278a16237e10b53dc Mon Sep 17 00:00:00 2001 From: "Mike Miller (OS Dev" Date: Tue, 19 Jun 2007 20:52:18 +0200 Subject: cciss: add new controller support for P700m This patch adds support for the Smart Array P700m SAS controller. This new controller will ship Fall 2007. Signed-off-by: Mike Miller Signed-off-by: Jens Axboe --- drivers/block/cciss.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 5acc6c44aead..0fcad430474e 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -87,6 +87,7 @@ static const struct pci_device_id cciss_pci_device_id[] = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3214}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSD, 0x103C, 0x3215}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x3237}, + {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC, 0x103C, 0x323D}, {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0}, {0,} @@ -119,6 +120,7 @@ static struct board_type products[] = { {0x3214103C, "Smart Array E200i", &SA5_access, 120}, {0x3215103C, "Smart Array E200i", &SA5_access, 120}, {0x3237103C, "Smart Array E500", &SA5_access, 512}, + {0x323D103C, "Smart Array P700m", &SA5_access, 512}, {0xFFFF103C, "Unknown Smart Array", &SA5_access, 120}, }; -- cgit v1.2.3-59-g8ed1b From e654bc4393e85e326993256d80b9710a4d6411ff Mon Sep 17 00:00:00 2001 From: Boaz Harrosh Date: Wed, 20 Jun 2007 13:53:23 +0200 Subject: [PATCH] fix request->cmd == INT cases - I have unearthed very old bugs in stale drivers that still used request->cmd as a READ|WRITE int - This patch is maybe a proof that these drivers have not been used for a long time. Should they be removed completely? Drivers that currently do not work for sure: drivers/acorn/block/fd1772.c | 2 +- drivers/acorn/block/mfmhd.c | 8 ++++---- drivers/cdrom/aztcd.c | 2 +- drivers/cdrom/cm206.c | 2 +- drivers/cdrom/gscd.c | 2 +- drivers/cdrom/mcdx.c | 2 +- drivers/cdrom/optcd.c | 2 +- drivers/cdrom/sjcd.c | 2 +- Drivers with cosmetic fixes only: b/drivers/block/amiflop.c b/drivers/block/nbd.c b/drivers/ide/legacy/hd.c Signed-off-by: Boaz Harrosh Signed-off-by: Jens Axboe --- drivers/acorn/block/fd1772.c | 2 +- drivers/acorn/block/mfmhd.c | 13 +++---------- drivers/block/amiflop.c | 2 +- drivers/block/nbd.c | 2 +- drivers/cdrom/aztcd.c | 2 +- drivers/cdrom/cm206.c | 2 +- drivers/cdrom/gscd.c | 2 +- drivers/cdrom/mcdx.c | 2 +- drivers/cdrom/optcd.c | 2 +- drivers/cdrom/sjcd.c | 2 +- drivers/ide/legacy/hd.c | 3 ++- 11 files changed, 14 insertions(+), 20 deletions(-) diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c index 674bf81c6e66..423ed08fb6f7 100644 --- a/drivers/acorn/block/fd1772.c +++ b/drivers/acorn/block/fd1772.c @@ -1246,7 +1246,7 @@ repeat: del_timer(&motor_off_timer); ReqCnt = 0; - ReqCmd = CURRENT->cmd; + ReqCmd = rq_data_dir(CURRENT); ReqBlock = CURRENT->sector; ReqBuffer = CURRENT->buffer; setup_req_params(drive); diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c index 689a4c3542ba..d85520f78e68 100644 --- a/drivers/acorn/block/mfmhd.c +++ b/drivers/acorn/block/mfmhd.c @@ -439,7 +439,7 @@ static void mfm_rw_intr(void) a choice of command end or some data which is ready to be collected */ /* I think we have to transfer data while the interrupt line is on and its not any other type of interrupt */ - if (CURRENT->cmd == WRITE) { + if (rq_data_dir(CURRENT) == WRITE) { extern void hdc63463_writedma(void); if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) { printk("mfm_rw_intr: Apparent DMA write request when no more to DMA\n"); @@ -799,7 +799,7 @@ static void issue_request(unsigned int block, unsigned int nsect, raw_cmd.head = start_head; raw_cmd.cylinder = track / p->heads; raw_cmd.cmdtype = CURRENT->cmd; - raw_cmd.cmdcode = CURRENT->cmd == WRITE ? CMD_WD : CMD_RD; + raw_cmd.cmdcode = rq_data_dir(CURRENT) == WRITE ? CMD_WD : CMD_RD; raw_cmd.cmddata[0] = dev + 1; /* DAG: +1 to get US */ raw_cmd.cmddata[1] = raw_cmd.head; raw_cmd.cmddata[2] = raw_cmd.cylinder >> 8; @@ -830,7 +830,7 @@ static void issue_request(unsigned int block, unsigned int nsect, hdc63463_dataleft = nsect * 256; /* Better way? */ DBG("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n", - raw_cmd.dev + 'a', (CURRENT->cmd == READ) ? "read" : "writ", + raw_cmd.dev + 'a', rq_data_dir(CURRENT) == READ ? "read" : "writ", raw_cmd.cylinder, raw_cmd.head, raw_cmd.sector, nsect, (unsigned long) Copy_buffer, CURRENT); @@ -917,13 +917,6 @@ static void mfm_request(void) DBG("mfm_request: block after offset=%d\n", block); - if (CURRENT->cmd != READ && CURRENT->cmd != WRITE) { - printk("unknown mfm-command %d\n", CURRENT->cmd); - end_request(CURRENT, 0); - Busy = 0; - printk("mfm: continue 4\n"); - continue; - } issue_request(block, nsect, CURRENT); break; diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 27a139025ced..6ce8b897e262 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1363,7 +1363,7 @@ static void redo_fd_request(void) #ifdef DEBUG printk("fd: sector %ld + %d requested for %s\n", CURRENT->sector,cnt, - (CURRENT->cmd==READ)?"read":"write"); + (rq_data_dir(CURRENT) == READ) ? "read" : "write"); #endif block = CURRENT->sector + cnt; if ((int)block > floppy->blocks) { diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 069ae39a9cd9..c575fb1d585f 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -416,7 +416,7 @@ static void nbd_clear_que(struct nbd_device *lo) /* * We always wait for result of write, for now. It would be nice to make it optional * in future - * if ((req->cmd == WRITE) && (lo->flags & NBD_WRITE_NOCHK)) + * if ((rq_data_dir(req) == WRITE) && (lo->flags & NBD_WRITE_NOCHK)) * { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); } */ diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c index 1f9fb7a96703..d7fbfaae2449 100644 --- a/drivers/cdrom/aztcd.c +++ b/drivers/cdrom/aztcd.c @@ -229,7 +229,7 @@ static struct request_queue *azt_queue; static int current_valid(void) { return CURRENT && - CURRENT->cmd == READ && + rq_data_dir(CURRENT) == READ && CURRENT->sector != -1; } diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c index 230131163240..2f8fe3b6bbd0 100644 --- a/drivers/cdrom/cm206.c +++ b/drivers/cdrom/cm206.c @@ -851,7 +851,7 @@ static void do_cm206_request(request_queue_t * q) if (!req) return; - if (req->cmd != READ) { + if (rq_data_dir(req) != READ) { debug(("Non-read command %d on cdrom\n", req->cmd)); end_request(req, 0); continue; diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c index b3ab6e9b8df1..176742ed007b 100644 --- a/drivers/cdrom/gscd.c +++ b/drivers/cdrom/gscd.c @@ -264,7 +264,7 @@ repeat: if (req->sector == -1) goto out; - if (req->cmd != READ) { + if (rq_data_dir(req) != READ) { printk("GSCD: bad cmd %u\n", rq_data_dir(req)); end_request(req, 0); goto repeat; diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c index 4310cc84dfed..972ee9c8247c 100644 --- a/drivers/cdrom/mcdx.c +++ b/drivers/cdrom/mcdx.c @@ -596,7 +596,7 @@ static void do_mcdx_request(request_queue_t * q) xtrace(REQUEST, "do_request() (%lu + %lu)\n", req->sector, req->nr_sectors); - if (req->cmd != READ) { + if (rq_data_dir(req) != READ) { xwarn("do_request(): non-read command to cd!!\n"); xtrace(REQUEST, "end_request(0): write\n"); end_request(req, 0); diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c index 3541690a77d4..efd619c0fe10 100644 --- a/drivers/cdrom/optcd.c +++ b/drivers/cdrom/optcd.c @@ -977,7 +977,7 @@ static int update_toc(void) static int current_valid(void) { return CURRENT && - CURRENT->cmd == READ && + rq_data_dir(CURRENT) == READ && CURRENT->sector != -1; } diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c index 5409fca5bbfc..76c24e679e68 100644 --- a/drivers/cdrom/sjcd.c +++ b/drivers/cdrom/sjcd.c @@ -1064,7 +1064,7 @@ static void sjcd_invalidate_buffers(void) static int current_valid(void) { return CURRENT && - CURRENT->cmd == READ && + rq_data_dir(CURRENT) == READ && CURRENT->sector != -1; } diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c index 661c12f6dda6..7f4c0a5050a1 100644 --- a/drivers/ide/legacy/hd.c +++ b/drivers/ide/legacy/hd.c @@ -623,7 +623,8 @@ repeat: cyl = track / disk->head; #ifdef DEBUG printk("%s: %sing: CHS=%d/%d/%d, sectors=%d, buffer=%p\n", - req->rq_disk->disk_name, (req->cmd == READ)?"read":"writ", + req->rq_disk->disk_name, + req_data_dir(req) == READ ? "read" : "writ", cyl, head, sec, nsect, req->buffer); #endif if (blk_fs_request(req)) { -- cgit v1.2.3-59-g8ed1b From f3f541f9ded9dd37edca103dd3be49bfbd9e730d Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 21 Jun 2007 08:29:34 +0200 Subject: Remove legacy CDROM drivers They are all broken beyond repair. Given that nobody has complained about them (most haven't worked in 2.6 AT ALL), remove them from the tree. A new mitsumi driver that actually works is in progress, it'll get added when completed. Signed-off-by: Jens Axboe --- drivers/Kconfig | 2 - drivers/cdrom/Kconfig | 213 -- drivers/cdrom/Makefile | 10 - drivers/cdrom/aztcd.c | 2492 ------------------- drivers/cdrom/aztcd.h | 162 -- drivers/cdrom/cdu31a.c | 3251 ------------------------ drivers/cdrom/cdu31a.h | 411 ---- drivers/cdrom/cm206.c | 1594 ------------ drivers/cdrom/cm206.h | 171 -- drivers/cdrom/gscd.c | 1029 -------- drivers/cdrom/gscd.h | 108 - drivers/cdrom/isp16.c | 374 --- drivers/cdrom/isp16.h | 72 - drivers/cdrom/mcdx.c | 1943 --------------- drivers/cdrom/mcdx.h | 185 -- drivers/cdrom/optcd.c | 2105 ---------------- drivers/cdrom/optcd.h | 52 - drivers/cdrom/sbpcd.c | 5966 --------------------------------------------- drivers/cdrom/sbpcd.h | 839 ------- drivers/cdrom/sjcd.c | 1815 -------------- drivers/cdrom/sjcd.h | 181 -- drivers/cdrom/sonycd535.c | 1689 ------------- drivers/cdrom/sonycd535.h | 183 -- 23 files changed, 24847 deletions(-) delete mode 100644 drivers/cdrom/Kconfig delete mode 100644 drivers/cdrom/aztcd.c delete mode 100644 drivers/cdrom/aztcd.h delete mode 100644 drivers/cdrom/cdu31a.c delete mode 100644 drivers/cdrom/cdu31a.h delete mode 100644 drivers/cdrom/cm206.c delete mode 100644 drivers/cdrom/cm206.h delete mode 100644 drivers/cdrom/gscd.c delete mode 100644 drivers/cdrom/gscd.h delete mode 100644 drivers/cdrom/isp16.c delete mode 100644 drivers/cdrom/isp16.h delete mode 100644 drivers/cdrom/mcdx.c delete mode 100644 drivers/cdrom/mcdx.h delete mode 100644 drivers/cdrom/optcd.c delete mode 100644 drivers/cdrom/optcd.h delete mode 100644 drivers/cdrom/sbpcd.c delete mode 100644 drivers/cdrom/sbpcd.h delete mode 100644 drivers/cdrom/sjcd.c delete mode 100644 drivers/cdrom/sjcd.h delete mode 100644 drivers/cdrom/sonycd535.c delete mode 100644 drivers/cdrom/sonycd535.h diff --git a/drivers/Kconfig b/drivers/Kconfig index 050323fd79e9..4e6487d461f3 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -24,8 +24,6 @@ source "drivers/scsi/Kconfig" source "drivers/ata/Kconfig" -source "drivers/cdrom/Kconfig" - source "drivers/md/Kconfig" source "drivers/message/fusion/Kconfig" diff --git a/drivers/cdrom/Kconfig b/drivers/cdrom/Kconfig deleted file mode 100644 index 4b12e9031fb3..000000000000 --- a/drivers/cdrom/Kconfig +++ /dev/null @@ -1,213 +0,0 @@ -# -# CDROM driver configuration -# - -menu "Old CD-ROM drivers (not SCSI, not IDE)" - depends on ISA && BLOCK - -config CD_NO_IDESCSI - bool "Support non-SCSI/IDE/ATAPI CDROM drives" - ---help--- - If you have a CD-ROM drive that is neither SCSI nor IDE/ATAPI, say Y - here, otherwise N. Read the CD-ROM-HOWTO, available from - . - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about these CD-ROM drives. If you are unsure what you - have, say Y and find out whether you have one of the following - drives. - - For each of these drivers, a - exists. Especially in cases where you do not know exactly which kind - of drive you have you should read there. Most of these drivers use a - file drivers/cdrom/{driver_name}.h where you can define your - interface parameters and switch some internal goodies. - - To compile these CD-ROM drivers as a module, choose M instead of Y. - - If you want to use any of these CD-ROM drivers, you also have to - answer Y or M to "ISO 9660 CD-ROM file system support" below (this - answer will get "defaulted" for you if you enable any of the Linux - CD-ROM drivers). - -config AZTCD - tristate "Aztech/Orchid/Okano/Wearnes/TXC/CyDROM CDROM support" - depends on CD_NO_IDESCSI - ---help--- - This is your driver if you have an Aztech CDA268-01A, Orchid - CD-3110, Okano or Wearnes CDD110, Conrad TXC, or CyCD-ROM CR520 or - CR540 CD-ROM drive. This driver -- just like all these CD-ROM - drivers -- is NOT for CD-ROM drives with IDE/ATAPI interfaces, such - as Aztech CDA269-031SE. Please read the file - . - - If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM - file system support" below, because that's the file system used on - CD-ROMs. - - To compile this driver as a module, choose M here: the - module will be called aztcd. - -config GSCD - tristate "Goldstar R420 CDROM support" - depends on CD_NO_IDESCSI - ---help--- - If this is your CD-ROM drive, say Y here. As described in the file - , you might have to change a setting - in the file before compiling the - kernel. Please read the file . - - If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM - file system support" below, because that's the file system used on - CD-ROMs. - - To compile this driver as a module, choose M here: the - module will be called gscd. - -config SBPCD - tristate "Matsushita/Panasonic/Creative, Longshine, TEAC CDROM support" - depends on CD_NO_IDESCSI && BROKEN_ON_SMP - ---help--- - This driver supports most of the drives which use the Panasonic or - Sound Blaster interface. Please read the file - . - - The Matsushita CR-521, CR-522, CR-523, CR-562, CR-563 drives - (sometimes labeled "Creative"), the Creative Labs CD200, the - Longshine LCS-7260, the "IBM External ISA CD-ROM" (in fact a CR-56x - model), the TEAC CD-55A fall under this category. Some other - "electrically compatible" drives (Vertos, Genoa, some Funai models) - are currently not supported; for the Sanyo H94A drive currently a - separate driver (asked later) is responsible. Most drives have a - uniquely shaped faceplate, with a caddyless motorized drawer, but - without external brand markings. The older CR-52x drives have a - caddy and manual loading/eject, but still no external markings. The - driver is able to do an extended auto-probing for interface - addresses and drive types; this can help to find facts in cases you - are not sure, but can consume some time during the boot process if - none of the supported drives gets found. Once your drive got found, - you should enter the reported parameters into - and set "DISTRIBUTION 0" there. - - This driver can support up to four CD-ROM controller cards, and each - card can support up to four CD-ROM drives; if you say Y here, you - will be asked how many controller cards you have. If compiled as a - module, only one controller card (but with up to four drives) is - usable. - - If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM - file system support" below, because that's the file system used on - CD-ROMs. - - To compile this driver as a module, choose M here: the - module will be called sbpcd. - -config MCDX - tristate "Mitsumi CDROM support" - depends on CD_NO_IDESCSI - ---help--- - Use this driver if you want to be able to use your Mitsumi LU-005, - FX-001 or FX-001D CD-ROM drive. - - Please read the file . - - If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM - file system support" below, because that's the file system used on - CD-ROMs. - - To compile this driver as a module, choose M here: the - module will be called mcdx. - -config OPTCD - tristate "Optics Storage DOLPHIN 8000AT CDROM support" - depends on CD_NO_IDESCSI - ---help--- - This is the driver for the 'DOLPHIN' drive with a 34-pin Sony - compatible interface. It also works with the Lasermate CR328A. If - you have one of those, say Y. This driver does not work for the - Optics Storage 8001 drive; use the IDE-ATAPI CD-ROM driver for that - one. Please read the file . - - If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM - file system support" below, because that's the file system used on - CD-ROMs. - - To compile this driver as a module, choose M here: the - module will be called optcd. - -config CM206 - tristate "Philips/LMS CM206 CDROM support" - depends on CD_NO_IDESCSI && BROKEN_ON_SMP - ---help--- - If you have a Philips/LMS CD-ROM drive cm206 in combination with a - cm260 host adapter card, say Y here. Please also read the file - . - - If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM - file system support" below, because that's the file system used on - CD-ROMs. - - To compile this driver as a module, choose M here: the - module will be called cm206. - -config SJCD - tristate "Sanyo CDR-H94A CDROM support" - depends on CD_NO_IDESCSI - help - If this is your CD-ROM drive, say Y here and read the file - . You should then also say Y or M to - "ISO 9660 CD-ROM file system support" below, because that's the - file system used on CD-ROMs. - - To compile this driver as a module, choose M here: the - module will be called sjcd. - -config ISP16_CDI - tristate "ISP16/MAD16/Mozart soft configurable cdrom interface support" - depends on CD_NO_IDESCSI - ---help--- - These are sound cards with built-in cdrom interfaces using the OPTi - 82C928 or 82C929 chips. Say Y here to have them detected and - possibly configured at boot time. In addition, You'll have to say Y - to a driver for the particular cdrom drive you have attached to the - card. Read for details. - - To compile this driver as a module, choose M here: the - module will be called isp16. - -config CDU31A - tristate "Sony CDU31A/CDU33A CDROM support" - depends on CD_NO_IDESCSI && BROKEN_ON_SMP - ---help--- - These CD-ROM drives have a spring-pop-out caddyless drawer, and a - rectangular green LED centered beneath it. NOTE: these CD-ROM - drives will not be auto detected by the kernel at boot time; you - have to provide the interface address as an option to the kernel at - boot time as described in or fill - in your parameters into . Try "man - bootparam" or see the documentation of your boot loader (lilo or - loadlin) about how to pass options to the kernel. - - If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM - file system support" below, because that's the file system used on - CD-ROMs. - - To compile this driver as a module, choose M here: the - module will be called cdu31a. - -config CDU535 - tristate "Sony CDU535 CDROM support" - depends on CD_NO_IDESCSI - ---help--- - This is the driver for the older Sony CDU-535 and CDU-531 CD-ROM - drives. Please read the file . - - If you say Y here, you should also say Y or M to "ISO 9660 CD-ROM - file system support" below, because that's the file system used on - CD-ROMs. - - To compile this driver as a module, choose M here: the - module will be called sonycd535. - -endmenu diff --git a/drivers/cdrom/Makefile b/drivers/cdrom/Makefile index d1d1e5a4be73..774c180a4e11 100644 --- a/drivers/cdrom/Makefile +++ b/drivers/cdrom/Makefile @@ -10,14 +10,4 @@ obj-$(CONFIG_BLK_DEV_SR) += cdrom.o obj-$(CONFIG_PARIDE_PCD) += cdrom.o obj-$(CONFIG_CDROM_PKTCDVD) += cdrom.o -obj-$(CONFIG_AZTCD) += aztcd.o -obj-$(CONFIG_CDU31A) += cdu31a.o cdrom.o -obj-$(CONFIG_CM206) += cm206.o cdrom.o -obj-$(CONFIG_GSCD) += gscd.o -obj-$(CONFIG_ISP16_CDI) += isp16.o -obj-$(CONFIG_MCDX) += mcdx.o cdrom.o -obj-$(CONFIG_OPTCD) += optcd.o -obj-$(CONFIG_SBPCD) += sbpcd.o cdrom.o -obj-$(CONFIG_SJCD) += sjcd.o -obj-$(CONFIG_CDU535) += sonycd535.o obj-$(CONFIG_VIOCD) += viocd.o cdrom.o diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c deleted file mode 100644 index d7fbfaae2449..000000000000 --- a/drivers/cdrom/aztcd.c +++ /dev/null @@ -1,2492 +0,0 @@ -#define AZT_VERSION "2.60" - -/* $Id: aztcd.c,v 2.60 1997/11/29 09:51:19 root Exp root $ - linux/drivers/block/aztcd.c - Aztech CD268 CDROM driver - - Copyright (C) 1994-98 Werner Zimmermann(Werner.Zimmermann@fht-esslingen.de) - - based on Mitsumi CDROM driver by Martin Hariss and preworks by - Eberhard Moenkeberg; contains contributions by Joe Nardone and Robby - Schirmer. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - HISTORY - V0.0 Adaption to Aztech CD268-01A Version 1.3 - Version is PRE_ALPHA, unresolved points: - 1. I use busy wait instead of timer wait in STEN_LOW,DTEN_LOW - thus driver causes CPU overhead and is very slow - 2. could not find a way to stop the drive, when it is - in data read mode, therefore I had to set - msf.end.min/sec/frame to 0:0:1 (in azt_poll); so only one - frame can be read in sequence, this is also the reason for - 3. getting 'timeout in state 4' messages, but nevertheless - it works - W.Zimmermann, Oct. 31, 1994 - V0.1 Version is ALPHA, problems #2 and #3 resolved. - W.Zimmermann, Nov. 3, 1994 - V0.2 Modification to some comments, debugging aids for partial test - with Borland C under DOS eliminated. Timer interrupt wait - STEN_LOW_WAIT additionally to busy wait for STEN_LOW implemented; - use it only for the 'slow' commands (ACMD_GET_Q_CHANNEL, ACMD_ - SEEK_TO_LEAD_IN), all other commands are so 'fast', that busy - waiting seems better to me than interrupt rescheduling. - Besides that, when used in the wrong place, STEN_LOW_WAIT causes - kernel panic. - In function aztPlay command ACMD_PLAY_AUDIO added, should make - audio functions work. The Aztech drive needs different commands - to read data tracks and play audio tracks. - W.Zimmermann, Nov. 8, 1994 - V0.3 Recognition of missing drive during boot up improved (speeded up). - W.Zimmermann, Nov. 13, 1994 - V0.35 Rewrote the control mechanism in azt_poll (formerly mcd_poll) - including removal of all 'goto' commands. :-); - J. Nardone, Nov. 14, 1994 - V0.4 Renamed variables and constants to 'azt' instead of 'mcd'; had - to make some "compatibility" defines in azt.h; please note, - that the source file was renamed to azt.c, the include file to - azt.h - Speeded up drive recognition during init (will be a little bit - slower than before if no drive is installed!); suggested by - Robby Schirmer. - read_count declared volatile and set to AZT_BUF_SIZ to make - drive faster (now 300kB/sec, was 60kB/sec before, measured - by 'time dd if=/dev/cdrom of=/dev/null bs=2048 count=4096'; - different AZT_BUF_SIZes were test, above 16 no further im- - provement seems to be possible; suggested by E.Moenkeberg. - W.Zimmermann, Nov. 18, 1994 - V0.42 Included getAztStatus command in GetQChannelInfo() to allow - reading Q-channel info on audio disks, if drive is stopped, - and some other bug fixes in the audio stuff, suggested by - Robby Schirmer. - Added more ioctls (reading data in mode 1 and mode 2). - Completely removed the old azt_poll() routine. - Detection of ORCHID CDS-3110 in aztcd_init implemented. - Additional debugging aids (see the readme file). - W.Zimmermann, Dec. 9, 1994 - V0.50 Autodetection of drives implemented. - W.Zimmermann, Dec. 12, 1994 - V0.52 Prepared for including in the standard kernel, renamed most - variables to contain 'azt', included autoconf.h - W.Zimmermann, Dec. 16, 1994 - V0.6 Version for being included in the standard Linux kernel. - Renamed source and header file to aztcd.c and aztcd.h - W.Zimmermann, Dec. 24, 1994 - V0.7 Changed VERIFY_READ to VERIFY_WRITE in aztcd_ioctl, case - CDROMREADMODE1 and CDROMREADMODE2; bug fix in the ioctl, - which causes kernel crashes when playing audio, changed - include-files (config.h instead of autoconf.h, removed - delay.h) - W.Zimmermann, Jan. 8, 1995 - V0.72 Some more modifications for adaption to the standard kernel. - W.Zimmermann, Jan. 16, 1995 - V0.80 aztcd is now part of the standard kernel since version 1.1.83. - Modified the SET_TIMER and CLEAR_TIMER macros to comply with - the new timer scheme. - W.Zimmermann, Jan. 21, 1995 - V0.90 Included CDROMVOLCTRL, but with my Aztech drive I can only turn - the channels on and off. If it works better with your drive, - please mail me. Also implemented ACMD_CLOSE for CDROMSTART. - W.Zimmermann, Jan. 24, 1995 - V1.00 Implemented close and lock tray commands. Patches supplied by - Frank Racis - Added support for loadable MODULEs, so aztcd can now also be - loaded by insmod and removed by rmmod during run time - Werner Zimmermann, Mar. 24, 95 - V1.10 Implemented soundcard configuration for Orchid CDS-3110 drives - connected to Soundwave32 cards. Release for LST 2.1. - (still experimental) - Werner Zimmermann, May 8, 95 - V1.20 Implemented limited support for DOSEMU0.60's cdrom.c. Now it works, but - sometimes DOSEMU may hang for 30 seconds or so. A fully functional ver- - sion needs an update of Dosemu0.60's cdrom.c, which will come with the - next revision of Dosemu. - Also Soundwave32 support now works. - Werner Zimmermann, May 22, 95 - V1.30 Auto-eject feature. Inspired by Franc Racis (racis@psu.edu) - Werner Zimmermann, July 4, 95 - V1.40 Started multisession support. Implementation copied from mcdx.c - by Heiko Schlittermann. Not tested yet. - Werner Zimmermann, July 15, 95 - V1.50 Implementation of ioctl CDROMRESET, continued multisession, began - XA, but still untested. Heavy modifications to drive status de- - tection. - Werner Zimmermann, July 25, 95 - V1.60 XA support now should work. Speeded up drive recognition in cases, - where no drive is installed. - Werner Zimmermann, August 8, 1995 - V1.70 Multisession support now is completed, but there is still not - enough testing done. If you can test it, please contact me. For - details please read Documentation/cdrom/aztcd - Werner Zimmermann, August 19, 1995 - V1.80 Modification to suit the new kernel boot procedure introduced - with kernel 1.3.33. Will definitely not work with older kernels. - Programming done by Linus himself. - Werner Zimmermann, October 11, 1995 - V1.90 Support for Conrad TXC drives, thank's to Jochen Kunz and Olaf Kaluza. - Werner Zimmermann, October 21, 1995 - V2.00 Changed #include "blk.h" to as the directory - structure was changed. README.aztcd is now /usr/src/docu- - mentation/cdrom/aztcd - Werner Zimmermann, November 10, 95 - V2.10 Started to modify azt_poll to prevent reading beyond end of - tracks. - Werner Zimmermann, December 3, 95 - V2.20 Changed some comments - Werner Zimmermann, April 1, 96 - V2.30 Implemented support for CyCDROM CR520, CR940, Code for CR520 - delivered by H.Berger with preworks by E.Moenkeberg. - Werner Zimmermann, April 29, 96 - V2.40 Reorganized the placement of functions in the source code file - to reflect the layered approach; did not actually change code - Werner Zimmermann, May 1, 96 - V2.50 Heiko Eissfeldt suggested to remove some VERIFY_READs in - aztcd_ioctl; check_aztcd_media_change modified - Werner Zimmermann, May 16, 96 - V2.60 Implemented Auto-Probing; made changes for kernel's 2.1.xx blocksize - Adaption to linux kernel > 2.1.0 - Werner Zimmermann, Nov 29, 97 - - November 1999 -- Make kernel-parameter implementation work with 2.3.x - Removed init_module & cleanup_module in favor of - module_init & module_exit. - Torben Mathiasen -*/ - -#include -#include "aztcd.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include - -/*########################################################################### - Defines - ########################################################################### -*/ - -#define MAJOR_NR AZTECH_CDROM_MAJOR -#define QUEUE (azt_queue) -#define CURRENT elv_next_request(azt_queue) -#define SET_TIMER(func, jifs) delay_timer.expires = jiffies + (jifs); \ - delay_timer.function = (void *) (func); \ - add_timer(&delay_timer); - -#define CLEAR_TIMER del_timer(&delay_timer); - -#define RETURNM(message,value) {printk("aztcd: Warning: %s failed\n",message);\ - return value;} -#define RETURN(message) {printk("aztcd: Warning: %s failed\n",message);\ - return;} - -/* Macros to switch the IDE-interface to the slave device and back to the master*/ -#define SWITCH_IDE_SLAVE outb_p(0xa0,azt_port+6); \ - outb_p(0x10,azt_port+6); \ - outb_p(0x00,azt_port+7); \ - outb_p(0x10,azt_port+6); -#define SWITCH_IDE_MASTER outb_p(0xa0,azt_port+6); - - -#if 0 -#define AZT_TEST -#define AZT_TEST1 /* */ -#define AZT_TEST2 /* do_aztcd_request */ -#define AZT_TEST3 /* AZT_S_state */ -#define AZT_TEST4 /* QUICK_LOOP-counter */ -#define AZT_TEST5 /* port(1) state */ -#define AZT_DEBUG -#define AZT_DEBUG_MULTISESSION -#endif - -static struct request_queue *azt_queue; - -static int current_valid(void) -{ - return CURRENT && - rq_data_dir(CURRENT) == READ && - CURRENT->sector != -1; -} - -#define AFL_STATUSorDATA (AFL_STATUS | AFL_DATA) -#define AZT_BUF_SIZ 16 - -#define READ_TIMEOUT 3000 - -#define azt_port aztcd /*needed for the modutils */ - -/*########################################################################## - Type Definitions - ########################################################################## -*/ -enum azt_state_e { AZT_S_IDLE, /* 0 */ - AZT_S_START, /* 1 */ - AZT_S_MODE, /* 2 */ - AZT_S_READ, /* 3 */ - AZT_S_DATA, /* 4 */ - AZT_S_STOP, /* 5 */ - AZT_S_STOPPING /* 6 */ -}; -enum azt_read_modes { AZT_MODE_0, /*read mode for audio disks, not supported by Aztech firmware */ - AZT_MODE_1, /*read mode for normal CD-ROMs */ - AZT_MODE_2 /*read mode for XA CD-ROMs */ -}; - -/*########################################################################## - Global Variables - ########################################################################## -*/ -static int aztPresent = 0; - -static volatile int azt_transfer_is_active = 0; - -static char azt_buf[CD_FRAMESIZE_RAW * AZT_BUF_SIZ]; /*buffer for block size conversion */ -#if AZT_PRIVATE_IOCTLS -static char buf[CD_FRAMESIZE_RAW]; /*separate buffer for the ioctls */ -#endif - -static volatile int azt_buf_bn[AZT_BUF_SIZ], azt_next_bn; -static volatile int azt_buf_in, azt_buf_out = -1; -static volatile int azt_error = 0; -static int azt_open_count = 0; -static volatile enum azt_state_e azt_state = AZT_S_IDLE; -#ifdef AZT_TEST3 -static volatile enum azt_state_e azt_state_old = AZT_S_STOP; -static volatile int azt_st_old = 0; -#endif -static volatile enum azt_read_modes azt_read_mode = AZT_MODE_1; - -static int azt_mode = -1; -static volatile int azt_read_count = 1; - -static int azt_port = AZT_BASE_ADDR; - -module_param(azt_port, int, 0); - -static int azt_port_auto[16] = AZT_BASE_AUTO; - -static char azt_cont = 0; -static char azt_init_end = 0; -static char azt_auto_eject = AZT_AUTO_EJECT; - -static int AztTimeout, AztTries; -static DECLARE_WAIT_QUEUE_HEAD(azt_waitq); -static DEFINE_TIMER(delay_timer, NULL, 0, 0); - -static struct azt_DiskInfo DiskInfo; -static struct azt_Toc Toc[MAX_TRACKS]; -static struct azt_Play_msf azt_Play; - -static int aztAudioStatus = CDROM_AUDIO_NO_STATUS; -static char aztDiskChanged = 1; -static char aztTocUpToDate = 0; - -static unsigned char aztIndatum; -static unsigned long aztTimeOutCount; -static int aztCmd = 0; - -static DEFINE_SPINLOCK(aztSpin); - -/*########################################################################### - Function Prototypes - ########################################################################### -*/ -/* CDROM Drive Low Level I/O Functions */ -static void aztStatTimer(void); - -/* CDROM Drive Command Functions */ -static int aztGetDiskInfo(void); -#if AZT_MULTISESSION -static int aztGetMultiDiskInfo(void); -#endif -static int aztGetToc(int multi); - -/* Kernel Interface Functions */ -static int check_aztcd_media_change(struct gendisk *disk); -static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, - unsigned long arg); -static int aztcd_open(struct inode *ip, struct file *fp); -static int aztcd_release(struct inode *inode, struct file *file); - -static struct block_device_operations azt_fops = { - .owner = THIS_MODULE, - .open = aztcd_open, - .release = aztcd_release, - .ioctl = aztcd_ioctl, - .media_changed = check_aztcd_media_change, -}; - -/* Aztcd State Machine: Controls Drive Operating State */ -static void azt_poll(void); - -/* Miscellaneous support functions */ -static void azt_hsg2msf(long hsg, struct msf *msf); -static long azt_msf2hsg(struct msf *mp); -static void azt_bin2bcd(unsigned char *p); -static int azt_bcd2bin(unsigned char bcd); - -/*########################################################################## - CDROM Drive Low Level I/O Functions - ########################################################################## -*/ -/* Macros for the drive hardware interface handshake, these macros use - busy waiting */ -/* Wait for OP_OK = drive answers with AFL_OP_OK after receiving a command*/ -# define OP_OK op_ok() -static void op_ok(void) -{ - aztTimeOutCount = 0; - do { - aztIndatum = inb(DATA_PORT); - aztTimeOutCount++; - if (aztTimeOutCount >= AZT_TIMEOUT) { - printk("aztcd: Error Wait OP_OK\n"); - break; - } - } while (aztIndatum != AFL_OP_OK); -} - -/* Wait for PA_OK = drive answers with AFL_PA_OK after receiving parameters*/ -#if 0 -# define PA_OK pa_ok() -static void pa_ok(void) -{ - aztTimeOutCount = 0; - do { - aztIndatum = inb(DATA_PORT); - aztTimeOutCount++; - if (aztTimeOutCount >= AZT_TIMEOUT) { - printk("aztcd: Error Wait PA_OK\n"); - break; - } - } while (aztIndatum != AFL_PA_OK); -} -#endif - -/* Wait for STEN=Low = handshake signal 'AFL_.._OK available or command executed*/ -# define STEN_LOW sten_low() -static void sten_low(void) -{ - aztTimeOutCount = 0; - do { - aztIndatum = inb(STATUS_PORT); - aztTimeOutCount++; - if (aztTimeOutCount >= AZT_TIMEOUT) { - if (azt_init_end) - printk - ("aztcd: Error Wait STEN_LOW commands:%x\n", - aztCmd); - break; - } - } while (aztIndatum & AFL_STATUS); -} - -/* Wait for DTEN=Low = handshake signal 'Data available'*/ -# define DTEN_LOW dten_low() -static void dten_low(void) -{ - aztTimeOutCount = 0; - do { - aztIndatum = inb(STATUS_PORT); - aztTimeOutCount++; - if (aztTimeOutCount >= AZT_TIMEOUT) { - printk("aztcd: Error Wait DTEN_OK\n"); - break; - } - } while (aztIndatum & AFL_DATA); -} - -/* - * Macro for timer wait on STEN=Low, should only be used for 'slow' commands; - * may cause kernel panic when used in the wrong place -*/ -#define STEN_LOW_WAIT statusAzt() -static void statusAzt(void) -{ - AztTimeout = AZT_STATUS_DELAY; - SET_TIMER(aztStatTimer, HZ / 100); - sleep_on(&azt_waitq); - if (AztTimeout <= 0) - printk("aztcd: Error Wait STEN_LOW_WAIT command:%x\n", - aztCmd); - return; -} - -static void aztStatTimer(void) -{ - if (!(inb(STATUS_PORT) & AFL_STATUS)) { - wake_up(&azt_waitq); - return; - } - AztTimeout--; - if (AztTimeout <= 0) { - wake_up(&azt_waitq); - printk("aztcd: Error aztStatTimer: Timeout\n"); - return; - } - SET_TIMER(aztStatTimer, HZ / 100); -} - -/*########################################################################## - CDROM Drive Command Functions - ########################################################################## -*/ -/* - * Send a single command, return -1 on error, else 0 -*/ -static int aztSendCmd(int cmd) -{ - unsigned char data; - int retry; - -#ifdef AZT_DEBUG - printk("aztcd: Executing command %x\n", cmd); -#endif - - if ((azt_port == 0x1f0) || (azt_port == 0x170)) - SWITCH_IDE_SLAVE; /*switch IDE interface to slave configuration */ - - aztCmd = cmd; - outb(POLLED, MODE_PORT); - do { - if (inb(STATUS_PORT) & AFL_STATUS) - break; - inb(DATA_PORT); /* if status left from last command, read and */ - } while (1); /* discard it */ - do { - if (inb(STATUS_PORT) & AFL_DATA) - break; - inb(DATA_PORT); /* if data left from last command, read and */ - } while (1); /* discard it */ - for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) { - outb((unsigned char) cmd, CMD_PORT); - STEN_LOW; - data = inb(DATA_PORT); - if (data == AFL_OP_OK) { - return 0; - } /*OP_OK? */ - if (data == AFL_OP_ERR) { - STEN_LOW; - data = inb(DATA_PORT); - printk - ("### Error 1 aztcd: aztSendCmd %x Error Code %x\n", - cmd, data); - } - } - if (retry >= AZT_RETRY_ATTEMPTS) { - printk("### Error 2 aztcd: aztSendCmd %x \n", cmd); - azt_error = 0xA5; - } - RETURNM("aztSendCmd", -1); -} - -/* - * Send a play or read command to the drive, return -1 on error, else 0 -*/ -static int sendAztCmd(int cmd, struct azt_Play_msf *params) -{ - unsigned char data; - int retry; - -#ifdef AZT_DEBUG - printk("aztcd: play start=%02x:%02x:%02x end=%02x:%02x:%02x\n", - params->start.min, params->start.sec, params->start.frame, - params->end.min, params->end.sec, params->end.frame); -#endif - for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) { - aztSendCmd(cmd); - outb(params->start.min, CMD_PORT); - outb(params->start.sec, CMD_PORT); - outb(params->start.frame, CMD_PORT); - outb(params->end.min, CMD_PORT); - outb(params->end.sec, CMD_PORT); - outb(params->end.frame, CMD_PORT); - STEN_LOW; - data = inb(DATA_PORT); - if (data == AFL_PA_OK) { - return 0; - } /*PA_OK ? */ - if (data == AFL_PA_ERR) { - STEN_LOW; - data = inb(DATA_PORT); - printk - ("### Error 1 aztcd: sendAztCmd %x Error Code %x\n", - cmd, data); - } - } - if (retry >= AZT_RETRY_ATTEMPTS) { - printk("### Error 2 aztcd: sendAztCmd %x\n ", cmd); - azt_error = 0xA5; - } - RETURNM("sendAztCmd", -1); -} - -/* - * Send a seek command to the drive, return -1 on error, else 0 -*/ -static int aztSeek(struct azt_Play_msf *params) -{ - unsigned char data; - int retry; - -#ifdef AZT_DEBUG - printk("aztcd: aztSeek %02x:%02x:%02x\n", - params->start.min, params->start.sec, params->start.frame); -#endif - for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) { - aztSendCmd(ACMD_SEEK); - outb(params->start.min, CMD_PORT); - outb(params->start.sec, CMD_PORT); - outb(params->start.frame, CMD_PORT); - STEN_LOW; - data = inb(DATA_PORT); - if (data == AFL_PA_OK) { - return 0; - } /*PA_OK ? */ - if (data == AFL_PA_ERR) { - STEN_LOW; - data = inb(DATA_PORT); - printk("### Error 1 aztcd: aztSeek\n"); - } - } - if (retry >= AZT_RETRY_ATTEMPTS) { - printk("### Error 2 aztcd: aztSeek\n "); - azt_error = 0xA5; - } - RETURNM("aztSeek", -1); -} - -/* Send a Set Disk Type command - does not seem to work with Aztech drives, behavior is completely indepen- - dent on which mode is set ??? -*/ -static int aztSetDiskType(int type) -{ - unsigned char data; - int retry; - -#ifdef AZT_DEBUG - printk("aztcd: set disk type command: type= %i\n", type); -#endif - for (retry = 0; retry < AZT_RETRY_ATTEMPTS; retry++) { - aztSendCmd(ACMD_SET_DISK_TYPE); - outb(type, CMD_PORT); - STEN_LOW; - data = inb(DATA_PORT); - if (data == AFL_PA_OK) { /*PA_OK ? */ - azt_read_mode = type; - return 0; - } - if (data == AFL_PA_ERR) { - STEN_LOW; - data = inb(DATA_PORT); - printk - ("### Error 1 aztcd: aztSetDiskType %x Error Code %x\n", - type, data); - } - } - if (retry >= AZT_RETRY_ATTEMPTS) { - printk("### Error 2 aztcd: aztSetDiskType %x\n ", type); - azt_error = 0xA5; - } - RETURNM("aztSetDiskType", -1); -} - - -/* used in azt_poll to poll the status, expects another program to issue a - * ACMD_GET_STATUS directly before - */ -static int aztStatus(void) -{ - int st; -/* int i; - - i = inb(STATUS_PORT) & AFL_STATUS; is STEN=0? ??? - if (!i) -*/ STEN_LOW; - if (aztTimeOutCount < AZT_TIMEOUT) { - st = inb(DATA_PORT) & 0xFF; - return st; - } else - RETURNM("aztStatus", -1); -} - -/* - * Get the drive status - */ -static int getAztStatus(void) -{ - int st; - - if (aztSendCmd(ACMD_GET_STATUS)) - RETURNM("getAztStatus 1", -1); - STEN_LOW; - st = inb(DATA_PORT) & 0xFF; -#ifdef AZT_DEBUG - printk("aztcd: Status = %x\n", st); -#endif - if ((st == 0xFF) || (st & AST_CMD_CHECK)) { - printk - ("aztcd: AST_CMD_CHECK error or no status available\n"); - return -1; - } - - if (((st & AST_MODE_BITS) != AST_BUSY) - && (aztAudioStatus == CDROM_AUDIO_PLAY)) - /* XXX might be an error? look at q-channel? */ - aztAudioStatus = CDROM_AUDIO_COMPLETED; - - if ((st & AST_DSK_CHG) || (st & AST_NOT_READY)) { - aztDiskChanged = 1; - aztTocUpToDate = 0; - aztAudioStatus = CDROM_AUDIO_NO_STATUS; - } - return st; -} - - -/* - * Send a 'Play' command and get the status. Use only from the top half. - */ -static int aztPlay(struct azt_Play_msf *arg) -{ - if (sendAztCmd(ACMD_PLAY_AUDIO, arg) < 0) - RETURNM("aztPlay", -1); - return 0; -} - -/* - * Subroutines to automatically close the door (tray) and - * lock it closed when the cd is mounted. Leave the tray - * locking as an option - */ -static void aztCloseDoor(void) -{ - aztSendCmd(ACMD_CLOSE); - STEN_LOW; - return; -} - -static void aztLockDoor(void) -{ -#if AZT_ALLOW_TRAY_LOCK - aztSendCmd(ACMD_LOCK); - STEN_LOW; -#endif - return; -} - -static void aztUnlockDoor(void) -{ -#if AZT_ALLOW_TRAY_LOCK - aztSendCmd(ACMD_UNLOCK); - STEN_LOW; -#endif - return; -} - -/* - * Read a value from the drive. Should return quickly, so a busy wait - * is used to avoid excessive rescheduling. The read command itself must - * be issued with aztSendCmd() directly before - */ -static int aztGetValue(unsigned char *result) -{ - int s; - - STEN_LOW; - if (aztTimeOutCount >= AZT_TIMEOUT) { - printk("aztcd: aztGetValue timeout\n"); - return -1; - } - s = inb(DATA_PORT) & 0xFF; - *result = (unsigned char) s; - return 0; -} - -/* - * Read the current Q-channel info. Also used for reading the - * table of contents. - */ -static int aztGetQChannelInfo(struct azt_Toc *qp) -{ - unsigned char notUsed; - int st; - -#ifdef AZT_DEBUG - printk("aztcd: starting aztGetQChannelInfo Time:%li\n", jiffies); -#endif - if ((st = getAztStatus()) == -1) - RETURNM("aztGetQChannelInfo 1", -1); - if (aztSendCmd(ACMD_GET_Q_CHANNEL)) - RETURNM("aztGetQChannelInfo 2", -1); - /*STEN_LOW_WAIT; ??? Dosemu0.60's cdrom.c does not like STEN_LOW_WAIT here */ - if (aztGetValue(¬Used)) - RETURNM("aztGetQChannelInfo 3", -1); /*??? Nullbyte einlesen */ - if ((st & AST_MODE_BITS) == AST_INITIAL) { - qp->ctrl_addr = 0; /* when audio stop ACMD_GET_Q_CHANNEL returns */ - qp->track = 0; /* only one byte with Aztech drives */ - qp->pointIndex = 0; - qp->trackTime.min = 0; - qp->trackTime.sec = 0; - qp->trackTime.frame = 0; - qp->diskTime.min = 0; - qp->diskTime.sec = 0; - qp->diskTime.frame = 0; - return 0; - } else { - if (aztGetValue(&qp->ctrl_addr) < 0) - RETURNM("aztGetQChannelInfo 4", -1); - if (aztGetValue(&qp->track) < 0) - RETURNM("aztGetQChannelInfo 4", -1); - if (aztGetValue(&qp->pointIndex) < 0) - RETURNM("aztGetQChannelInfo 4", -1); - if (aztGetValue(&qp->trackTime.min) < 0) - RETURNM("aztGetQChannelInfo 4", -1); - if (aztGetValue(&qp->trackTime.sec) < 0) - RETURNM("aztGetQChannelInfo 4", -1); - if (aztGetValue(&qp->trackTime.frame) < 0) - RETURNM("aztGetQChannelInfo 4", -1); - if (aztGetValue(¬Used) < 0) - RETURNM("aztGetQChannelInfo 4", -1); - if (aztGetValue(&qp->diskTime.min) < 0) - RETURNM("aztGetQChannelInfo 4", -1); - if (aztGetValue(&qp->diskTime.sec) < 0) - RETURNM("aztGetQChannelInfo 4", -1); - if (aztGetValue(&qp->diskTime.frame) < 0) - RETURNM("aztGetQChannelInfo 4", -1); - } -#ifdef AZT_DEBUG - printk("aztcd: exiting aztGetQChannelInfo Time:%li\n", jiffies); -#endif - return 0; -} - -/* - * Read the table of contents (TOC) and TOC header if necessary - */ -static int aztUpdateToc(void) -{ - int st; - -#ifdef AZT_DEBUG - printk("aztcd: starting aztUpdateToc Time:%li\n", jiffies); -#endif - if (aztTocUpToDate) - return 0; - - if (aztGetDiskInfo() < 0) - return -EIO; - - if (aztGetToc(0) < 0) - return -EIO; - - /*audio disk detection - with my Aztech drive there is no audio status bit, so I use the copy - protection bit of the first track. If this track is copy protected - (copy bit = 0), I assume, it's an audio disk. Strange, but works ??? */ - if (!(Toc[DiskInfo.first].ctrl_addr & 0x40)) - DiskInfo.audio = 1; - else - DiskInfo.audio = 0; - - /* XA detection */ - if (!DiskInfo.audio) { - azt_Play.start.min = 0; /*XA detection only seems to work */ - azt_Play.start.sec = 2; /*when we play a track */ - azt_Play.start.frame = 0; - azt_Play.end.min = 0; - azt_Play.end.sec = 0; - azt_Play.end.frame = 1; - if (sendAztCmd(ACMD_PLAY_READ, &azt_Play)) - return -1; - DTEN_LOW; - for (st = 0; st < CD_FRAMESIZE; st++) - inb(DATA_PORT); - } - DiskInfo.xa = getAztStatus() & AST_MODE; - if (DiskInfo.xa) { - printk - ("aztcd: XA support experimental - mail results to Werner.Zimmermann@fht-esslingen.de\n"); - } - - /*multisession detection - support for multisession CDs is done automatically with Aztech drives, - we don't have to take care about TOC redirection; if we want the isofs - to take care about redirection, we have to set AZT_MULTISESSION to 1 */ - DiskInfo.multi = 0; -#if AZT_MULTISESSION - if (DiskInfo.xa) { - aztGetMultiDiskInfo(); /*here Disk.Info.multi is set */ - } -#endif - if (DiskInfo.multi) { - DiskInfo.lastSession.min = Toc[DiskInfo.next].diskTime.min; - DiskInfo.lastSession.sec = Toc[DiskInfo.next].diskTime.sec; - DiskInfo.lastSession.frame = - Toc[DiskInfo.next].diskTime.frame; - printk("aztcd: Multisession support experimental\n"); - } else { - DiskInfo.lastSession.min = - Toc[DiskInfo.first].diskTime.min; - DiskInfo.lastSession.sec = - Toc[DiskInfo.first].diskTime.sec; - DiskInfo.lastSession.frame = - Toc[DiskInfo.first].diskTime.frame; - } - - aztTocUpToDate = 1; -#ifdef AZT_DEBUG - printk("aztcd: exiting aztUpdateToc Time:%li\n", jiffies); -#endif - return 0; -} - - -/* Read the table of contents header, i.e. no. of tracks and start of first - * track - */ -static int aztGetDiskInfo(void) -{ - int limit; - unsigned char test; - struct azt_Toc qInfo; - -#ifdef AZT_DEBUG - printk("aztcd: starting aztGetDiskInfo Time:%li\n", jiffies); -#endif - if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) - RETURNM("aztGetDiskInfo 1", -1); - STEN_LOW_WAIT; - test = 0; - for (limit = 300; limit > 0; limit--) { - if (aztGetQChannelInfo(&qInfo) < 0) - RETURNM("aztGetDiskInfo 2", -1); - if (qInfo.pointIndex == 0xA0) { /*Number of FirstTrack */ - DiskInfo.first = qInfo.diskTime.min; - DiskInfo.first = azt_bcd2bin(DiskInfo.first); - test = test | 0x01; - } - if (qInfo.pointIndex == 0xA1) { /*Number of LastTrack */ - DiskInfo.last = qInfo.diskTime.min; - DiskInfo.last = azt_bcd2bin(DiskInfo.last); - test = test | 0x02; - } - if (qInfo.pointIndex == 0xA2) { /*DiskLength */ - DiskInfo.diskLength.min = qInfo.diskTime.min; - DiskInfo.diskLength.sec = qInfo.diskTime.sec; - DiskInfo.diskLength.frame = qInfo.diskTime.frame; - test = test | 0x04; - } - if ((qInfo.pointIndex == DiskInfo.first) && (test & 0x01)) { /*StartTime of First Track */ - DiskInfo.firstTrack.min = qInfo.diskTime.min; - DiskInfo.firstTrack.sec = qInfo.diskTime.sec; - DiskInfo.firstTrack.frame = qInfo.diskTime.frame; - test = test | 0x08; - } - if (test == 0x0F) - break; - } -#ifdef AZT_DEBUG - printk("aztcd: exiting aztGetDiskInfo Time:%li\n", jiffies); - printk - ("Disk Info: first %d last %d length %02X:%02X.%02X dez first %02X:%02X.%02X dez\n", - DiskInfo.first, DiskInfo.last, DiskInfo.diskLength.min, - DiskInfo.diskLength.sec, DiskInfo.diskLength.frame, - DiskInfo.firstTrack.min, DiskInfo.firstTrack.sec, - DiskInfo.firstTrack.frame); -#endif - if (test != 0x0F) - return -1; - return 0; -} - -#if AZT_MULTISESSION -/* - * Get Multisession Disk Info - */ -static int aztGetMultiDiskInfo(void) -{ - int limit, k = 5; - unsigned char test; - struct azt_Toc qInfo; - -#ifdef AZT_DEBUG - printk("aztcd: starting aztGetMultiDiskInfo\n"); -#endif - - do { - azt_Play.start.min = Toc[DiskInfo.last + 1].diskTime.min; - azt_Play.start.sec = Toc[DiskInfo.last + 1].diskTime.sec; - azt_Play.start.frame = - Toc[DiskInfo.last + 1].diskTime.frame; - test = 0; - - for (limit = 30; limit > 0; limit--) { /*Seek for LeadIn of next session */ - if (aztSeek(&azt_Play)) - RETURNM("aztGetMultiDiskInfo 1", -1); - if (aztGetQChannelInfo(&qInfo) < 0) - RETURNM("aztGetMultiDiskInfo 2", -1); - if ((qInfo.track == 0) && (qInfo.pointIndex)) - break; /*LeadIn found */ - if ((azt_Play.start.sec += 10) > 59) { - azt_Play.start.sec = 0; - azt_Play.start.min++; - } - } - if (!limit) - break; /*Check, if a leadin track was found, if not we're - at the end of the disk */ -#ifdef AZT_DEBUG_MULTISESSION - printk("leadin found track %d pointIndex %x limit %d\n", - qInfo.track, qInfo.pointIndex, limit); -#endif - for (limit = 300; limit > 0; limit--) { - if (++azt_Play.start.frame > 74) { - azt_Play.start.frame = 0; - if (azt_Play.start.sec > 59) { - azt_Play.start.sec = 0; - azt_Play.start.min++; - } - } - if (aztSeek(&azt_Play)) - RETURNM("aztGetMultiDiskInfo 3", -1); - if (aztGetQChannelInfo(&qInfo) < 0) - RETURNM("aztGetMultiDiskInfo 4", -1); - if (qInfo.pointIndex == 0xA0) { /*Number of NextTrack */ - DiskInfo.next = qInfo.diskTime.min; - DiskInfo.next = azt_bcd2bin(DiskInfo.next); - test = test | 0x01; - } - if (qInfo.pointIndex == 0xA1) { /*Number of LastTrack */ - DiskInfo.last = qInfo.diskTime.min; - DiskInfo.last = azt_bcd2bin(DiskInfo.last); - test = test | 0x02; - } - if (qInfo.pointIndex == 0xA2) { /*DiskLength */ - DiskInfo.diskLength.min = - qInfo.diskTime.min; - DiskInfo.diskLength.sec = - qInfo.diskTime.sec; - DiskInfo.diskLength.frame = - qInfo.diskTime.frame; - test = test | 0x04; - } - if ((qInfo.pointIndex == DiskInfo.next) && (test & 0x01)) { /*StartTime of Next Track */ - DiskInfo.nextSession.min = - qInfo.diskTime.min; - DiskInfo.nextSession.sec = - qInfo.diskTime.sec; - DiskInfo.nextSession.frame = - qInfo.diskTime.frame; - test = test | 0x08; - } - if (test == 0x0F) - break; - } -#ifdef AZT_DEBUG_MULTISESSION - printk - ("MultiDisk Info: first %d next %d last %d length %02x:%02x.%02x dez first %02x:%02x.%02x dez next %02x:%02x.%02x dez\n", - DiskInfo.first, DiskInfo.next, DiskInfo.last, - DiskInfo.diskLength.min, DiskInfo.diskLength.sec, - DiskInfo.diskLength.frame, DiskInfo.firstTrack.min, - DiskInfo.firstTrack.sec, DiskInfo.firstTrack.frame, - DiskInfo.nextSession.min, DiskInfo.nextSession.sec, - DiskInfo.nextSession.frame); -#endif - if (test != 0x0F) - break; - else - DiskInfo.multi = 1; /*found TOC of more than one session */ - aztGetToc(1); - } while (--k); - -#ifdef AZT_DEBUG - printk("aztcd: exiting aztGetMultiDiskInfo Time:%li\n", jiffies); -#endif - return 0; -} -#endif - -/* - * Read the table of contents (TOC) - */ -static int aztGetToc(int multi) -{ - int i, px; - int limit; - struct azt_Toc qInfo; - -#ifdef AZT_DEBUG - printk("aztcd: starting aztGetToc Time:%li\n", jiffies); -#endif - if (!multi) { - for (i = 0; i < MAX_TRACKS; i++) - Toc[i].pointIndex = 0; - i = DiskInfo.last + 3; - } else { - for (i = DiskInfo.next; i < MAX_TRACKS; i++) - Toc[i].pointIndex = 0; - i = DiskInfo.last + 4 - DiskInfo.next; - } - -/*Is there a good reason to stop motor before TOC read? - if (aztSendCmd(ACMD_STOP)) RETURNM("aztGetToc 1",-1); - STEN_LOW_WAIT; -*/ - - if (!multi) { - azt_mode = 0x05; - if (aztSendCmd(ACMD_SEEK_TO_LEADIN)) - RETURNM("aztGetToc 2", -1); - STEN_LOW_WAIT; - } - for (limit = 300; limit > 0; limit--) { - if (multi) { - if (++azt_Play.start.sec > 59) { - azt_Play.start.sec = 0; - azt_Play.start.min++; - } - if (aztSeek(&azt_Play)) - RETURNM("aztGetToc 3", -1); - } - if (aztGetQChannelInfo(&qInfo) < 0) - break; - - px = azt_bcd2bin(qInfo.pointIndex); - - if (px > 0 && px < MAX_TRACKS && qInfo.track == 0) - if (Toc[px].pointIndex == 0) { - Toc[px] = qInfo; - i--; - } - - if (i <= 0) - break; - } - - Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength; - Toc[DiskInfo.last].trackTime = DiskInfo.diskLength; - -#ifdef AZT_DEBUG_MULTISESSION - printk("aztcd: exiting aztGetToc\n"); - for (i = 1; i <= DiskInfo.last + 1; i++) - printk - ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez %02X:%02X.%02X dez\n", - i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex, - Toc[i].trackTime.min, Toc[i].trackTime.sec, - Toc[i].trackTime.frame, Toc[i].diskTime.min, - Toc[i].diskTime.sec, Toc[i].diskTime.frame); - for (i = 100; i < 103; i++) - printk - ("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X dez %02X:%02X.%02X dez\n", - i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex, - Toc[i].trackTime.min, Toc[i].trackTime.sec, - Toc[i].trackTime.frame, Toc[i].diskTime.min, - Toc[i].diskTime.sec, Toc[i].diskTime.frame); -#endif - - return limit > 0 ? 0 : -1; -} - - -/*########################################################################## - Kernel Interface Functions - ########################################################################## -*/ - -#ifndef MODULE -static int __init aztcd_setup(char *str) -{ - int ints[4]; - - (void) get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) - azt_port = ints[1]; - if (ints[1] > 1) - azt_cont = ints[2]; - return 1; -} - -__setup("aztcd=", aztcd_setup); - -#endif /* !MODULE */ - -/* - * Checking if the media has been changed -*/ -static int check_aztcd_media_change(struct gendisk *disk) -{ - if (aztDiskChanged) { /* disk changed */ - aztDiskChanged = 0; - return 1; - } else - return 0; /* no change */ -} - -/* - * Kernel IO-controls -*/ -static int aztcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, - unsigned long arg) -{ - int i; - struct azt_Toc qInfo; - struct cdrom_ti ti; - struct cdrom_tochdr tocHdr; - struct cdrom_msf msf; - struct cdrom_tocentry entry; - struct azt_Toc *tocPtr; - struct cdrom_subchnl subchnl; - struct cdrom_volctrl volctrl; - void __user *argp = (void __user *)arg; - -#ifdef AZT_DEBUG - printk("aztcd: starting aztcd_ioctl - Command:%x Time: %li\n", - cmd, jiffies); - printk("aztcd Status %x\n", getAztStatus()); -#endif - if (!ip) - RETURNM("aztcd_ioctl 1", -EINVAL); - if (getAztStatus() < 0) - RETURNM("aztcd_ioctl 2", -EIO); - if ((!aztTocUpToDate) || (aztDiskChanged)) { - if ((i = aztUpdateToc()) < 0) - RETURNM("aztcd_ioctl 3", i); /* error reading TOC */ - } - - switch (cmd) { - case CDROMSTART: /* Spin up the drive. Don't know, what to do, - at least close the tray */ -#if AZT_PRIVATE_IOCTLS - if (aztSendCmd(ACMD_CLOSE)) - RETURNM("aztcd_ioctl 4", -1); - STEN_LOW_WAIT; -#endif - break; - case CDROMSTOP: /* Spin down the drive */ - if (aztSendCmd(ACMD_STOP)) - RETURNM("aztcd_ioctl 5", -1); - STEN_LOW_WAIT; - /* should we do anything if it fails? */ - aztAudioStatus = CDROM_AUDIO_NO_STATUS; - break; - case CDROMPAUSE: /* Pause the drive */ - if (aztAudioStatus != CDROM_AUDIO_PLAY) - return -EINVAL; - - if (aztGetQChannelInfo(&qInfo) < 0) { /* didn't get q channel info */ - aztAudioStatus = CDROM_AUDIO_NO_STATUS; - RETURNM("aztcd_ioctl 7", 0); - } - azt_Play.start = qInfo.diskTime; /* remember restart point */ - - if (aztSendCmd(ACMD_PAUSE)) - RETURNM("aztcd_ioctl 8", -1); - STEN_LOW_WAIT; - aztAudioStatus = CDROM_AUDIO_PAUSED; - break; - case CDROMRESUME: /* Play it again, Sam */ - if (aztAudioStatus != CDROM_AUDIO_PAUSED) - return -EINVAL; - /* restart the drive at the saved position. */ - i = aztPlay(&azt_Play); - if (i < 0) { - aztAudioStatus = CDROM_AUDIO_ERROR; - return -EIO; - } - aztAudioStatus = CDROM_AUDIO_PLAY; - break; - case CDROMMULTISESSION: /*multisession support -- experimental */ - { - struct cdrom_multisession ms; -#ifdef AZT_DEBUG - printk("aztcd ioctl MULTISESSION\n"); -#endif - if (copy_from_user(&ms, argp, - sizeof(struct cdrom_multisession))) - return -EFAULT; - if (ms.addr_format == CDROM_MSF) { - ms.addr.msf.minute = - azt_bcd2bin(DiskInfo.lastSession.min); - ms.addr.msf.second = - azt_bcd2bin(DiskInfo.lastSession.sec); - ms.addr.msf.frame = - azt_bcd2bin(DiskInfo.lastSession. - frame); - } else if (ms.addr_format == CDROM_LBA) - ms.addr.lba = - azt_msf2hsg(&DiskInfo.lastSession); - else - return -EINVAL; - ms.xa_flag = DiskInfo.xa; - if (copy_to_user(argp, &ms, - sizeof(struct cdrom_multisession))) - return -EFAULT; -#ifdef AZT_DEBUG - if (ms.addr_format == CDROM_MSF) - printk - ("aztcd multisession xa:%d, msf:%02x:%02x.%02x [%02x:%02x.%02x])\n", - ms.xa_flag, ms.addr.msf.minute, - ms.addr.msf.second, ms.addr.msf.frame, - DiskInfo.lastSession.min, - DiskInfo.lastSession.sec, - DiskInfo.lastSession.frame); - else - printk - ("aztcd multisession %d, lba:0x%08x [%02x:%02x.%02x])\n", - ms.xa_flag, ms.addr.lba, - DiskInfo.lastSession.min, - DiskInfo.lastSession.sec, - DiskInfo.lastSession.frame); -#endif - return 0; - } - case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ - if (copy_from_user(&ti, argp, sizeof ti)) - return -EFAULT; - if (ti.cdti_trk0 < DiskInfo.first - || ti.cdti_trk0 > DiskInfo.last - || ti.cdti_trk1 < ti.cdti_trk0) { - return -EINVAL; - } - if (ti.cdti_trk1 > DiskInfo.last) - ti.cdti_trk1 = DiskInfo.last; - azt_Play.start = Toc[ti.cdti_trk0].diskTime; - azt_Play.end = Toc[ti.cdti_trk1 + 1].diskTime; -#ifdef AZT_DEBUG - printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n", - azt_Play.start.min, azt_Play.start.sec, - azt_Play.start.frame, azt_Play.end.min, - azt_Play.end.sec, azt_Play.end.frame); -#endif - i = aztPlay(&azt_Play); - if (i < 0) { - aztAudioStatus = CDROM_AUDIO_ERROR; - return -EIO; - } - aztAudioStatus = CDROM_AUDIO_PLAY; - break; - case CDROMPLAYMSF: /* Play starting at the given MSF address. */ -/* if (aztAudioStatus == CDROM_AUDIO_PLAY) - { if (aztSendCmd(ACMD_STOP)) RETURNM("aztcd_ioctl 9",-1); - STEN_LOW; - aztAudioStatus = CDROM_AUDIO_NO_STATUS; - } -*/ - if (copy_from_user(&msf, argp, sizeof msf)) - return -EFAULT; - /* convert to bcd */ - azt_bin2bcd(&msf.cdmsf_min0); - azt_bin2bcd(&msf.cdmsf_sec0); - azt_bin2bcd(&msf.cdmsf_frame0); - azt_bin2bcd(&msf.cdmsf_min1); - azt_bin2bcd(&msf.cdmsf_sec1); - azt_bin2bcd(&msf.cdmsf_frame1); - azt_Play.start.min = msf.cdmsf_min0; - azt_Play.start.sec = msf.cdmsf_sec0; - azt_Play.start.frame = msf.cdmsf_frame0; - azt_Play.end.min = msf.cdmsf_min1; - azt_Play.end.sec = msf.cdmsf_sec1; - azt_Play.end.frame = msf.cdmsf_frame1; -#ifdef AZT_DEBUG - printk("aztcd play: %02x:%02x.%02x to %02x:%02x.%02x\n", - azt_Play.start.min, azt_Play.start.sec, - azt_Play.start.frame, azt_Play.end.min, - azt_Play.end.sec, azt_Play.end.frame); -#endif - i = aztPlay(&azt_Play); - if (i < 0) { - aztAudioStatus = CDROM_AUDIO_ERROR; - return -EIO; - } - aztAudioStatus = CDROM_AUDIO_PLAY; - break; - - case CDROMREADTOCHDR: /* Read the table of contents header */ - tocHdr.cdth_trk0 = DiskInfo.first; - tocHdr.cdth_trk1 = DiskInfo.last; - if (copy_to_user(argp, &tocHdr, sizeof tocHdr)) - return -EFAULT; - break; - case CDROMREADTOCENTRY: /* Read an entry in the table of contents */ - if (copy_from_user(&entry, argp, sizeof entry)) - return -EFAULT; - if ((!aztTocUpToDate) || aztDiskChanged) - aztUpdateToc(); - if (entry.cdte_track == CDROM_LEADOUT) - tocPtr = &Toc[DiskInfo.last + 1]; - else if (entry.cdte_track > DiskInfo.last - || entry.cdte_track < DiskInfo.first) { - return -EINVAL; - } else - tocPtr = &Toc[entry.cdte_track]; - entry.cdte_adr = tocPtr->ctrl_addr; - entry.cdte_ctrl = tocPtr->ctrl_addr >> 4; - if (entry.cdte_format == CDROM_LBA) - entry.cdte_addr.lba = - azt_msf2hsg(&tocPtr->diskTime); - else if (entry.cdte_format == CDROM_MSF) { - entry.cdte_addr.msf.minute = - azt_bcd2bin(tocPtr->diskTime.min); - entry.cdte_addr.msf.second = - azt_bcd2bin(tocPtr->diskTime.sec); - entry.cdte_addr.msf.frame = - azt_bcd2bin(tocPtr->diskTime.frame); - } else { - return -EINVAL; - } - if (copy_to_user(argp, &entry, sizeof entry)) - return -EFAULT; - break; - case CDROMSUBCHNL: /* Get subchannel info */ - if (copy_from_user - (&subchnl, argp, sizeof(struct cdrom_subchnl))) - return -EFAULT; - if (aztGetQChannelInfo(&qInfo) < 0) { -#ifdef AZT_DEBUG - printk - ("aztcd: exiting aztcd_ioctl - Error 3 - Command:%x\n", - cmd); -#endif - return -EIO; - } - subchnl.cdsc_audiostatus = aztAudioStatus; - subchnl.cdsc_adr = qInfo.ctrl_addr; - subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4; - subchnl.cdsc_trk = azt_bcd2bin(qInfo.track); - subchnl.cdsc_ind = azt_bcd2bin(qInfo.pointIndex); - if (subchnl.cdsc_format == CDROM_LBA) { - subchnl.cdsc_absaddr.lba = - azt_msf2hsg(&qInfo.diskTime); - subchnl.cdsc_reladdr.lba = - azt_msf2hsg(&qInfo.trackTime); - } else { /*default */ - subchnl.cdsc_format = CDROM_MSF; - subchnl.cdsc_absaddr.msf.minute = - azt_bcd2bin(qInfo.diskTime.min); - subchnl.cdsc_absaddr.msf.second = - azt_bcd2bin(qInfo.diskTime.sec); - subchnl.cdsc_absaddr.msf.frame = - azt_bcd2bin(qInfo.diskTime.frame); - subchnl.cdsc_reladdr.msf.minute = - azt_bcd2bin(qInfo.trackTime.min); - subchnl.cdsc_reladdr.msf.second = - azt_bcd2bin(qInfo.trackTime.sec); - subchnl.cdsc_reladdr.msf.frame = - azt_bcd2bin(qInfo.trackTime.frame); - } - if (copy_to_user(argp, &subchnl, sizeof(struct cdrom_subchnl))) - return -EFAULT; - break; - case CDROMVOLCTRL: /* Volume control - * With my Aztech CD268-01A volume control does not work, I can only - turn the channels on (any value !=0) or off (value==0). Maybe it - works better with your drive */ - if (copy_from_user(&volctrl, argp, sizeof(volctrl))) - return -EFAULT; - azt_Play.start.min = 0x21; - azt_Play.start.sec = 0x84; - azt_Play.start.frame = volctrl.channel0; - azt_Play.end.min = volctrl.channel1; - azt_Play.end.sec = volctrl.channel2; - azt_Play.end.frame = volctrl.channel3; - sendAztCmd(ACMD_SET_VOLUME, &azt_Play); - STEN_LOW_WAIT; - break; - case CDROMEJECT: - aztUnlockDoor(); /* Assume user knows what they're doing */ - /* all drives can at least stop! */ - if (aztAudioStatus == CDROM_AUDIO_PLAY) { - if (aztSendCmd(ACMD_STOP)) - RETURNM("azt_ioctl 10", -1); - STEN_LOW_WAIT; - } - if (aztSendCmd(ACMD_EJECT)) - RETURNM("azt_ioctl 11", -1); - STEN_LOW_WAIT; - aztAudioStatus = CDROM_AUDIO_NO_STATUS; - break; - case CDROMEJECT_SW: - azt_auto_eject = (char) arg; - break; - case CDROMRESET: - outb(ACMD_SOFT_RESET, CMD_PORT); /*send reset */ - STEN_LOW; - if (inb(DATA_PORT) != AFL_OP_OK) { /*OP_OK? */ - printk - ("aztcd: AZTECH CD-ROM drive does not respond\n"); - } - break; -/*Take care, the following code is not compatible with other CD-ROM drivers, - use it at your own risk with cdplay.c. Set AZT_PRIVATE_IOCTLS to 0 in aztcd.h, - if you do not want to use it! -*/ -#if AZT_PRIVATE_IOCTLS - case CDROMREADCOOKED: /*read data in mode 1 (2048 Bytes) */ - case CDROMREADRAW: /*read data in mode 2 (2336 Bytes) */ - { - if (copy_from_user(&msf, argp, sizeof msf)) - return -EFAULT; - /* convert to bcd */ - azt_bin2bcd(&msf.cdmsf_min0); - azt_bin2bcd(&msf.cdmsf_sec0); - azt_bin2bcd(&msf.cdmsf_frame0); - msf.cdmsf_min1 = 0; - msf.cdmsf_sec1 = 0; - msf.cdmsf_frame1 = 1; /*read only one frame */ - azt_Play.start.min = msf.cdmsf_min0; - azt_Play.start.sec = msf.cdmsf_sec0; - azt_Play.start.frame = msf.cdmsf_frame0; - azt_Play.end.min = msf.cdmsf_min1; - azt_Play.end.sec = msf.cdmsf_sec1; - azt_Play.end.frame = msf.cdmsf_frame1; - if (cmd == CDROMREADRAW) { - if (DiskInfo.xa) { - return -1; /*XA Disks can't be read raw */ - } else { - if (sendAztCmd(ACMD_PLAY_READ_RAW, &azt_Play)) - return -1; - DTEN_LOW; - insb(DATA_PORT, buf, CD_FRAMESIZE_RAW); - if (copy_to_user(argp, &buf, CD_FRAMESIZE_RAW)) - return -EFAULT; - } - } else - /*CDROMREADCOOKED*/ { - if (sendAztCmd(ACMD_PLAY_READ, &azt_Play)) - return -1; - DTEN_LOW; - insb(DATA_PORT, buf, CD_FRAMESIZE); - if (copy_to_user(argp, &buf, CD_FRAMESIZE)) - return -EFAULT; - } - } - break; - case CDROMSEEK: /*seek msf address */ - if (copy_from_user(&msf, argp, sizeof msf)) - return -EFAULT; - /* convert to bcd */ - azt_bin2bcd(&msf.cdmsf_min0); - azt_bin2bcd(&msf.cdmsf_sec0); - azt_bin2bcd(&msf.cdmsf_frame0); - azt_Play.start.min = msf.cdmsf_min0; - azt_Play.start.sec = msf.cdmsf_sec0; - azt_Play.start.frame = msf.cdmsf_frame0; - if (aztSeek(&azt_Play)) - return -1; - break; -#endif /*end of incompatible code */ - case CDROMREADMODE1: /*set read data in mode 1 */ - return aztSetDiskType(AZT_MODE_1); - case CDROMREADMODE2: /*set read data in mode 2 */ - return aztSetDiskType(AZT_MODE_2); - default: - return -EINVAL; - } -#ifdef AZT_DEBUG - printk("aztcd: exiting aztcd_ioctl Command:%x Time:%li\n", cmd, - jiffies); -#endif - return 0; -} - -/* - * Take care of the different block sizes between cdrom and Linux. - * When Linux gets variable block sizes this will probably go away. - */ -static void azt_transfer(void) -{ -#ifdef AZT_TEST - printk("aztcd: executing azt_transfer Time:%li\n", jiffies); -#endif - if (!current_valid()) - return; - - while (CURRENT->nr_sectors) { - int bn = CURRENT->sector / 4; - int i; - for (i = 0; i < AZT_BUF_SIZ && azt_buf_bn[i] != bn; ++i); - if (i < AZT_BUF_SIZ) { - int offs = (i * 4 + (CURRENT->sector & 3)) * 512; - int nr_sectors = 4 - (CURRENT->sector & 3); - if (azt_buf_out != i) { - azt_buf_out = i; - if (azt_buf_bn[i] != bn) { - azt_buf_out = -1; - continue; - } - } - if (nr_sectors > CURRENT->nr_sectors) - nr_sectors = CURRENT->nr_sectors; - memcpy(CURRENT->buffer, azt_buf + offs, - nr_sectors * 512); - CURRENT->nr_sectors -= nr_sectors; - CURRENT->sector += nr_sectors; - CURRENT->buffer += nr_sectors * 512; - } else { - azt_buf_out = -1; - break; - } - } -} - -static void do_aztcd_request(request_queue_t * q) -{ -#ifdef AZT_TEST - printk(" do_aztcd_request(%ld+%ld) Time:%li\n", CURRENT->sector, - CURRENT->nr_sectors, jiffies); -#endif - if (DiskInfo.audio) { - printk("aztcd: Error, tried to mount an Audio CD\n"); - end_request(CURRENT, 0); - return; - } - azt_transfer_is_active = 1; - while (current_valid()) { - azt_transfer(); - if (CURRENT->nr_sectors == 0) { - end_request(CURRENT, 1); - } else { - azt_buf_out = -1; /* Want to read a block not in buffer */ - if (azt_state == AZT_S_IDLE) { - if ((!aztTocUpToDate) || aztDiskChanged) { - if (aztUpdateToc() < 0) { - while (current_valid()) - end_request(CURRENT, 0); - break; - } - } - azt_state = AZT_S_START; - AztTries = 5; - SET_TIMER(azt_poll, HZ / 100); - } - break; - } - } - azt_transfer_is_active = 0; -#ifdef AZT_TEST2 - printk - ("azt_next_bn:%x azt_buf_in:%x azt_buf_out:%x azt_buf_bn:%x\n", - azt_next_bn, azt_buf_in, azt_buf_out, azt_buf_bn[azt_buf_in]); - printk(" do_aztcd_request ends Time:%li\n", jiffies); -#endif -} - - -static void azt_invalidate_buffers(void) -{ - int i; - -#ifdef AZT_DEBUG - printk("aztcd: executing azt_invalidate_buffers\n"); -#endif - for (i = 0; i < AZT_BUF_SIZ; ++i) - azt_buf_bn[i] = -1; - azt_buf_out = -1; -} - -/* - * Open the device special file. Check that a disk is in. - */ -static int aztcd_open(struct inode *ip, struct file *fp) -{ - int st; - -#ifdef AZT_DEBUG - printk("aztcd: starting aztcd_open\n"); -#endif - - if (aztPresent == 0) - return -ENXIO; /* no hardware */ - - if (!azt_open_count && azt_state == AZT_S_IDLE) { - azt_invalidate_buffers(); - - st = getAztStatus(); /* check drive status */ - if (st == -1) - goto err_out; /* drive doesn't respond */ - - if (st & AST_DOOR_OPEN) { /* close door, then get the status again. */ - printk("aztcd: Door Open?\n"); - aztCloseDoor(); - st = getAztStatus(); - } - - if ((st & AST_NOT_READY) || (st & AST_DSK_CHG)) { /*no disk in drive or changed */ - printk - ("aztcd: Disk Changed or No Disk in Drive?\n"); - aztTocUpToDate = 0; - } - if (aztUpdateToc()) - goto err_out; - - } - ++azt_open_count; - aztLockDoor(); - -#ifdef AZT_DEBUG - printk("aztcd: exiting aztcd_open\n"); -#endif - return 0; - - err_out: - return -EIO; -} - - -/* - * On close, we flush all azt blocks from the buffer cache. - */ -static int aztcd_release(struct inode *inode, struct file *file) -{ -#ifdef AZT_DEBUG - printk("aztcd: executing aztcd_release\n"); - printk("inode: %p, device: %s file: %p\n", inode, - inode->i_bdev->bd_disk->disk_name, file); -#endif - if (!--azt_open_count) { - azt_invalidate_buffers(); - aztUnlockDoor(); - if (azt_auto_eject) - aztSendCmd(ACMD_EJECT); - CLEAR_TIMER; - } - return 0; -} - -static struct gendisk *azt_disk; - -/* - * Test for presence of drive and initialize it. Called at boot time. - */ - -static int __init aztcd_init(void) -{ - long int count, max_count; - unsigned char result[50]; - int st; - void* status = NULL; - int i = 0; - int ret = 0; - - if (azt_port == 0) { - printk(KERN_INFO "aztcd: no Aztech CD-ROM Initialization"); - return -EIO; - } - - printk(KERN_INFO "aztcd: AZTECH, ORCHID, OKANO, WEARNES, TXC, CyDROM " - "CD-ROM Driver\n"); - printk(KERN_INFO "aztcd: (C) 1994-98 W.Zimmermann\n"); - if (azt_port == -1) { - printk - ("aztcd: DriverVersion=%s For IDE/ATAPI-drives use ide-cd.c\n", - AZT_VERSION); - } else - printk - ("aztcd: DriverVersion=%s BaseAddress=0x%x For IDE/ATAPI-drives use ide-cd.c\n", - AZT_VERSION, azt_port); - printk(KERN_INFO "aztcd: If you have problems, read /usr/src/linux/" - "Documentation/cdrom/aztcd\n"); - - -#ifdef AZT_SW32 /*CDROM connected to Soundwave32 card */ - if ((0xFF00 & inw(AZT_SW32_ID_REG)) != 0x4500) { - printk - ("aztcd: no Soundwave32 card detected at base:%x init:%x config:%x id:%x\n", - AZT_SW32_BASE_ADDR, AZT_SW32_INIT, - AZT_SW32_CONFIG_REG, AZT_SW32_ID_REG); - return -EIO; - } else { - printk(KERN_INFO - "aztcd: Soundwave32 card detected at %x Version %x\n", - AZT_SW32_BASE_ADDR, inw(AZT_SW32_ID_REG)); - outw(AZT_SW32_INIT, AZT_SW32_CONFIG_REG); - for (count = 0; count < 10000; count++); /*delay a bit */ - } -#endif - - /* check for presence of drive */ - - if (azt_port == -1) { /* autoprobing for proprietary interface */ - for (i = 0; (azt_port_auto[i] != 0) && (i < 16); i++) { - azt_port = azt_port_auto[i]; - printk(KERN_INFO "aztcd: Autoprobing BaseAddress=0x%x" - "\n", azt_port); - /*proprietary interfaces need 4 bytes */ - if (!request_region(azt_port, 4, "aztcd")) { - continue; - } - outb(POLLED, MODE_PORT); - inb(CMD_PORT); - inb(CMD_PORT); - outb(ACMD_GET_VERSION, CMD_PORT); /*Try to get version info */ - - aztTimeOutCount = 0; - do { - aztIndatum = inb(STATUS_PORT); - aztTimeOutCount++; - if (aztTimeOutCount >= AZT_FAST_TIMEOUT) - break; - } while (aztIndatum & AFL_STATUS); - if (inb(DATA_PORT) == AFL_OP_OK) { /* OK drive found */ - break; - } - else { /* Drive not found on this port - try next one */ - release_region(azt_port, 4); - } - } - if ((i == 16) || (azt_port_auto[i] == 0)) { - printk(KERN_INFO "aztcd: no AZTECH CD-ROM drive found\n"); - return -EIO; - } - } else { /* no autoprobing */ - if ((azt_port == 0x1f0) || (azt_port == 0x170)) - status = request_region(azt_port, 8, "aztcd"); /*IDE-interfaces need 8 bytes */ - else - status = request_region(azt_port, 4, "aztcd"); /*proprietary interfaces need 4 bytes */ - if (!status) { - printk(KERN_WARNING "aztcd: conflict, I/O port (%X) " - "already used\n", azt_port); - return -EIO; - } - - if ((azt_port == 0x1f0) || (azt_port == 0x170)) - SWITCH_IDE_SLAVE; /*switch IDE interface to slave configuration */ - - outb(POLLED, MODE_PORT); - inb(CMD_PORT); - inb(CMD_PORT); - outb(ACMD_GET_VERSION, CMD_PORT); /*Try to get version info */ - - aztTimeOutCount = 0; - do { - aztIndatum = inb(STATUS_PORT); - aztTimeOutCount++; - if (aztTimeOutCount >= AZT_FAST_TIMEOUT) - break; - } while (aztIndatum & AFL_STATUS); - - if (inb(DATA_PORT) != AFL_OP_OK) { /*OP_OK? If not, reset and try again */ -#ifndef MODULE - if (azt_cont != 0x79) { - printk(KERN_WARNING "aztcd: no AZTECH CD-ROM " - "drive found-Try boot parameter aztcd=" - ",0x79\n"); - ret = -EIO; - goto err_out; - } -#else - if (0) { - } -#endif - else { - printk(KERN_INFO "aztcd: drive reset - " - "please wait\n"); - for (count = 0; count < 50; count++) { - inb(STATUS_PORT); /*removing all data from earlier tries */ - inb(DATA_PORT); - } - outb(POLLED, MODE_PORT); - inb(CMD_PORT); - inb(CMD_PORT); - getAztStatus(); /*trap errors */ - outb(ACMD_SOFT_RESET, CMD_PORT); /*send reset */ - STEN_LOW; - if (inb(DATA_PORT) != AFL_OP_OK) { /*OP_OK? */ - printk(KERN_WARNING "aztcd: no AZTECH " - "CD-ROM drive found\n"); - ret = -EIO; - goto err_out; - } - - for (count = 0; count < AZT_TIMEOUT; - count++) - barrier(); /* Stop gcc 2.96 being smart */ - /* use udelay(), damnit -- AV */ - - if ((st = getAztStatus()) == -1) { - printk(KERN_WARNING "aztcd: Drive Status" - " Error Status=%x\n", st); - ret = -EIO; - goto err_out; - } -#ifdef AZT_DEBUG - printk(KERN_DEBUG "aztcd: Status = %x\n", st); -#endif - outb(POLLED, MODE_PORT); - inb(CMD_PORT); - inb(CMD_PORT); - outb(ACMD_GET_VERSION, CMD_PORT); /*GetVersion */ - STEN_LOW; - OP_OK; - } - } - } - - azt_init_end = 1; - STEN_LOW; - result[0] = inb(DATA_PORT); /*reading in a null byte??? */ - for (count = 1; count < 50; count++) { /*Reading version string */ - aztTimeOutCount = 0; /*here we must implement STEN_LOW differently */ - do { - aztIndatum = inb(STATUS_PORT); /*because we want to exit by timeout */ - aztTimeOutCount++; - if (aztTimeOutCount >= AZT_FAST_TIMEOUT) - break; - } while (aztIndatum & AFL_STATUS); - if (aztTimeOutCount >= AZT_FAST_TIMEOUT) - break; /*all chars read? */ - result[count] = inb(DATA_PORT); - } - if (count > 30) - max_count = 30; /*print max.30 chars of the version string */ - else - max_count = count; - printk(KERN_INFO "aztcd: FirmwareVersion="); - for (count = 1; count < max_count; count++) - printk("%c", result[count]); - printk("<<>> "); - - if ((result[1] == 'A') && (result[2] == 'Z') && (result[3] == 'T')) { - printk("AZTECH drive detected\n"); - /*AZTECH*/} - else if ((result[2] == 'C') && (result[3] == 'D') - && (result[4] == 'D')) { - printk("ORCHID or WEARNES drive detected\n"); /*ORCHID or WEARNES */ - } else if ((result[1] == 0x03) && (result[2] == '5')) { - printk("TXC or CyCDROM drive detected\n"); /*Conrad TXC, CyCDROM */ - } else { /*OTHERS or none */ - printk("\nunknown drive or firmware version detected\n"); - printk - ("aztcd may not run stable, if you want to try anyhow,\n"); - printk("boot with: aztcd=,0x79\n"); - if ((azt_cont != 0x79)) { - printk("aztcd: FirmwareVersion="); - for (count = 1; count < 5; count++) - printk("%c", result[count]); - printk("<<>> "); - printk("Aborted\n"); - ret = -EIO; - goto err_out; - } - } - azt_disk = alloc_disk(1); - if (!azt_disk) - goto err_out; - - if (register_blkdev(MAJOR_NR, "aztcd")) { - ret = -EIO; - goto err_out2; - } - - azt_queue = blk_init_queue(do_aztcd_request, &aztSpin); - if (!azt_queue) { - ret = -ENOMEM; - goto err_out3; - } - - blk_queue_hardsect_size(azt_queue, 2048); - azt_disk->major = MAJOR_NR; - azt_disk->first_minor = 0; - azt_disk->fops = &azt_fops; - sprintf(azt_disk->disk_name, "aztcd"); - azt_disk->queue = azt_queue; - add_disk(azt_disk); - azt_invalidate_buffers(); - aztPresent = 1; - aztCloseDoor(); - return 0; -err_out3: - unregister_blkdev(MAJOR_NR, "aztcd"); -err_out2: - put_disk(azt_disk); -err_out: - if ((azt_port == 0x1f0) || (azt_port == 0x170)) { - SWITCH_IDE_MASTER; - release_region(azt_port, 8); /*IDE-interface */ - } else - release_region(azt_port, 4); /*proprietary interface */ - return ret; - -} - -static void __exit aztcd_exit(void) -{ - del_gendisk(azt_disk); - put_disk(azt_disk); - if ((unregister_blkdev(MAJOR_NR, "aztcd") == -EINVAL)) { - printk("What's that: can't unregister aztcd\n"); - return; - } - blk_cleanup_queue(azt_queue); - if ((azt_port == 0x1f0) || (azt_port == 0x170)) { - SWITCH_IDE_MASTER; - release_region(azt_port, 8); /*IDE-interface */ - } else - release_region(azt_port, 4); /*proprietary interface */ - printk(KERN_INFO "aztcd module released.\n"); -} - -module_init(aztcd_init); -module_exit(aztcd_exit); - -/*########################################################################## - Aztcd State Machine: Controls Drive Operating State - ########################################################################## -*/ -static void azt_poll(void) -{ - int st = 0; - int loop_ctl = 1; - int skip = 0; - - if (azt_error) { - if (aztSendCmd(ACMD_GET_ERROR)) - RETURN("azt_poll 1"); - STEN_LOW; - azt_error = inb(DATA_PORT) & 0xFF; - printk("aztcd: I/O error 0x%02x\n", azt_error); - azt_invalidate_buffers(); -#ifdef WARN_IF_READ_FAILURE - if (AztTries == 5) - printk - ("aztcd: Read of Block %d Failed - Maybe Audio Disk?\n", - azt_next_bn); -#endif - if (!AztTries--) { - printk - ("aztcd: Read of Block %d Failed, Maybe Audio Disk? Giving up\n", - azt_next_bn); - if (azt_transfer_is_active) { - AztTries = 0; - loop_ctl = 0; - } - if (current_valid()) - end_request(CURRENT, 0); - AztTries = 5; - } - azt_error = 0; - azt_state = AZT_S_STOP; - } - - while (loop_ctl) { - loop_ctl = 0; /* each case must flip this back to 1 if we want - to come back up here */ - switch (azt_state) { - - case AZT_S_IDLE: -#ifdef AZT_TEST3 - if (azt_state != azt_state_old) { - azt_state_old = azt_state; - printk("AZT_S_IDLE\n"); - } -#endif - return; - - case AZT_S_START: -#ifdef AZT_TEST3 - if (azt_state != azt_state_old) { - azt_state_old = azt_state; - printk("AZT_S_START\n"); - } -#endif - if (aztSendCmd(ACMD_GET_STATUS)) - RETURN("azt_poll 2"); /*result will be checked by aztStatus() */ - azt_state = - azt_mode == 1 ? AZT_S_READ : AZT_S_MODE; - AztTimeout = 3000; - break; - - case AZT_S_MODE: -#ifdef AZT_TEST3 - if (azt_state != azt_state_old) { - azt_state_old = azt_state; - printk("AZT_S_MODE\n"); - } -#endif - if (!skip) { - if ((st = aztStatus()) != -1) { - if ((st & AST_DSK_CHG) - || (st & AST_NOT_READY)) { - aztDiskChanged = 1; - aztTocUpToDate = 0; - azt_invalidate_buffers(); - end_request(CURRENT, 0); - printk - ("aztcd: Disk Changed or Not Ready 1 - Unmount Disk!\n"); - } - } else - break; - } - skip = 0; - - if ((st & AST_DOOR_OPEN) || (st & AST_NOT_READY)) { - aztDiskChanged = 1; - aztTocUpToDate = 0; - printk - ("aztcd: Disk Changed or Not Ready 2 - Unmount Disk!\n"); - end_request(CURRENT, 0); - printk((st & AST_DOOR_OPEN) ? - "aztcd: door open\n" : - "aztcd: disk removed\n"); - if (azt_transfer_is_active) { - azt_state = AZT_S_START; - loop_ctl = 1; /* goto immediately */ - break; - } - azt_state = AZT_S_IDLE; - while (current_valid()) - end_request(CURRENT, 0); - return; - } - -/* if (aztSendCmd(ACMD_SET_MODE)) RETURN("azt_poll 3"); - outb(0x01, DATA_PORT); - PA_OK; - STEN_LOW; -*/ - if (aztSendCmd(ACMD_GET_STATUS)) - RETURN("azt_poll 4"); - STEN_LOW; - azt_mode = 1; - azt_state = AZT_S_READ; - AztTimeout = 3000; - - break; - - - case AZT_S_READ: -#ifdef AZT_TEST3 - if (azt_state != azt_state_old) { - azt_state_old = azt_state; - printk("AZT_S_READ\n"); - } -#endif - if (!skip) { - if ((st = aztStatus()) != -1) { - if ((st & AST_DSK_CHG) - || (st & AST_NOT_READY)) { - aztDiskChanged = 1; - aztTocUpToDate = 0; - azt_invalidate_buffers(); - printk - ("aztcd: Disk Changed or Not Ready 3 - Unmount Disk!\n"); - end_request(CURRENT, 0); - } - } else - break; - } - - skip = 0; - if ((st & AST_DOOR_OPEN) || (st & AST_NOT_READY)) { - aztDiskChanged = 1; - aztTocUpToDate = 0; - printk((st & AST_DOOR_OPEN) ? - "aztcd: door open\n" : - "aztcd: disk removed\n"); - if (azt_transfer_is_active) { - azt_state = AZT_S_START; - loop_ctl = 1; - break; - } - azt_state = AZT_S_IDLE; - while (current_valid()) - end_request(CURRENT, 0); - return; - } - - if (current_valid()) { - struct azt_Play_msf msf; - int i; - azt_next_bn = CURRENT->sector / 4; - azt_hsg2msf(azt_next_bn, &msf.start); - i = 0; - /* find out in which track we are */ - while (azt_msf2hsg(&msf.start) > - azt_msf2hsg(&Toc[++i].trackTime)) { - }; - if (azt_msf2hsg(&msf.start) < - azt_msf2hsg(&Toc[i].trackTime) - - AZT_BUF_SIZ) { - azt_read_count = AZT_BUF_SIZ; /*fast, because we read ahead */ - /*azt_read_count=CURRENT->nr_sectors; slow, no read ahead */ - } else /* don't read beyond end of track */ -#if AZT_MULTISESSION - { - azt_read_count = - (azt_msf2hsg(&Toc[i].trackTime) - / 4) * 4 - - azt_msf2hsg(&msf.start); - if (azt_read_count < 0) - azt_read_count = 0; - if (azt_read_count > AZT_BUF_SIZ) - azt_read_count = - AZT_BUF_SIZ; - printk - ("aztcd: warning - trying to read beyond end of track\n"); -/* printk("%i %i %li %li\n",i,azt_read_count,azt_msf2hsg(&msf.start),azt_msf2hsg(&Toc[i].trackTime)); -*/ } -#else - { - azt_read_count = AZT_BUF_SIZ; - } -#endif - msf.end.min = 0; - msf.end.sec = 0; - msf.end.frame = azt_read_count; /*Mitsumi here reads 0xffffff sectors */ -#ifdef AZT_TEST3 - printk - ("---reading msf-address %x:%x:%x %x:%x:%x\n", - msf.start.min, msf.start.sec, - msf.start.frame, msf.end.min, - msf.end.sec, msf.end.frame); - printk - ("azt_next_bn:%x azt_buf_in:%x azt_buf_out:%x azt_buf_bn:%x\n", - azt_next_bn, azt_buf_in, azt_buf_out, - azt_buf_bn[azt_buf_in]); -#endif - if (azt_read_mode == AZT_MODE_2) { - sendAztCmd(ACMD_PLAY_READ_RAW, &msf); /*XA disks in raw mode */ - } else { - sendAztCmd(ACMD_PLAY_READ, &msf); /*others in cooked mode */ - } - azt_state = AZT_S_DATA; - AztTimeout = READ_TIMEOUT; - } else { - azt_state = AZT_S_STOP; - loop_ctl = 1; - break; - } - - break; - - - case AZT_S_DATA: -#ifdef AZT_TEST3 - if (azt_state != azt_state_old) { - azt_state_old = azt_state; - printk("AZT_S_DATA\n"); - } -#endif - - st = inb(STATUS_PORT) & AFL_STATUSorDATA; - - switch (st) { - - case AFL_DATA: -#ifdef AZT_TEST3 - if (st != azt_st_old) { - azt_st_old = st; - printk("---AFL_DATA st:%x\n", st); - } -#endif - if (!AztTries--) { - printk - ("aztcd: Read of Block %d Failed, Maybe Audio Disk ? Giving up\n", - azt_next_bn); - if (azt_transfer_is_active) { - AztTries = 0; - break; - } - if (current_valid()) - end_request(CURRENT, 0); - AztTries = 5; - } - azt_state = AZT_S_START; - AztTimeout = READ_TIMEOUT; - loop_ctl = 1; - break; - - case AFL_STATUSorDATA: -#ifdef AZT_TEST3 - if (st != azt_st_old) { - azt_st_old = st; - printk - ("---AFL_STATUSorDATA st:%x\n", - st); - } -#endif - break; - - default: -#ifdef AZT_TEST3 - if (st != azt_st_old) { - azt_st_old = st; - printk("---default: st:%x\n", st); - } -#endif - AztTries = 5; - if (!current_valid() && azt_buf_in == azt_buf_out) { - azt_state = AZT_S_STOP; - loop_ctl = 1; - break; - } - if (azt_read_count <= 0) - printk - ("aztcd: warning - try to read 0 frames\n"); - while (azt_read_count) { /*??? fast read ahead loop */ - azt_buf_bn[azt_buf_in] = -1; - DTEN_LOW; /*??? unsolved problem, very - seldom we get timeouts - here, don't now the real - reason. With my drive this - sometimes also happens with - Aztech's original driver under - DOS. Is it a hardware bug? - I tried to recover from such - situations here. Zimmermann */ - if (aztTimeOutCount >= AZT_TIMEOUT) { - printk - ("read_count:%d CURRENT->nr_sectors:%ld azt_buf_in:%d\n", - azt_read_count, - CURRENT->nr_sectors, - azt_buf_in); - printk - ("azt_transfer_is_active:%x\n", - azt_transfer_is_active); - azt_read_count = 0; - azt_state = AZT_S_STOP; - loop_ctl = 1; - end_request(CURRENT, 1); /*should we have here (1) or (0)? */ - } else { - if (azt_read_mode == - AZT_MODE_2) { - insb(DATA_PORT, - azt_buf + - CD_FRAMESIZE_RAW - * azt_buf_in, - CD_FRAMESIZE_RAW); - } else { - insb(DATA_PORT, - azt_buf + - CD_FRAMESIZE * - azt_buf_in, - CD_FRAMESIZE); - } - azt_read_count--; -#ifdef AZT_TEST3 - printk - ("AZT_S_DATA; ---I've read data- read_count: %d\n", - azt_read_count); - printk - ("azt_next_bn:%d azt_buf_in:%d azt_buf_out:%d azt_buf_bn:%d\n", - azt_next_bn, - azt_buf_in, - azt_buf_out, - azt_buf_bn - [azt_buf_in]); -#endif - azt_buf_bn[azt_buf_in] = - azt_next_bn++; - if (azt_buf_out == -1) - azt_buf_out = - azt_buf_in; - azt_buf_in = - azt_buf_in + 1 == - AZT_BUF_SIZ ? 0 : - azt_buf_in + 1; - } - } - if (!azt_transfer_is_active) { - while (current_valid()) { - azt_transfer(); - if (CURRENT->nr_sectors == - 0) - end_request(CURRENT, 1); - else - break; - } - } - - if (current_valid() - && (CURRENT->sector / 4 < azt_next_bn - || CURRENT->sector / 4 > - azt_next_bn + AZT_BUF_SIZ)) { - azt_state = AZT_S_STOP; - loop_ctl = 1; - break; - } - AztTimeout = READ_TIMEOUT; - if (azt_read_count == 0) { - azt_state = AZT_S_STOP; - loop_ctl = 1; - break; - } - break; - } - break; - - - case AZT_S_STOP: -#ifdef AZT_TEST3 - if (azt_state != azt_state_old) { - azt_state_old = azt_state; - printk("AZT_S_STOP\n"); - } -#endif - if (azt_read_count != 0) - printk("aztcd: discard data=%x frames\n", - azt_read_count); - while (azt_read_count != 0) { - int i; - if (!(inb(STATUS_PORT) & AFL_DATA)) { - if (azt_read_mode == AZT_MODE_2) - for (i = 0; - i < CD_FRAMESIZE_RAW; - i++) - inb(DATA_PORT); - else - for (i = 0; - i < CD_FRAMESIZE; i++) - inb(DATA_PORT); - } - azt_read_count--; - } - if (aztSendCmd(ACMD_GET_STATUS)) - RETURN("azt_poll 5"); - azt_state = AZT_S_STOPPING; - AztTimeout = 1000; - break; - - case AZT_S_STOPPING: -#ifdef AZT_TEST3 - if (azt_state != azt_state_old) { - azt_state_old = azt_state; - printk("AZT_S_STOPPING\n"); - } -#endif - - if ((st = aztStatus()) == -1 && AztTimeout) - break; - - if ((st != -1) - && ((st & AST_DSK_CHG) - || (st & AST_NOT_READY))) { - aztDiskChanged = 1; - aztTocUpToDate = 0; - azt_invalidate_buffers(); - printk - ("aztcd: Disk Changed or Not Ready 4 - Unmount Disk!\n"); - end_request(CURRENT, 0); - } - -#ifdef AZT_TEST3 - printk("CURRENT_VALID %d azt_mode %d\n", - current_valid(), azt_mode); -#endif - - if (current_valid()) { - if (st != -1) { - if (azt_mode == 1) { - azt_state = AZT_S_READ; - loop_ctl = 1; - skip = 1; - break; - } else { - azt_state = AZT_S_MODE; - loop_ctl = 1; - skip = 1; - break; - } - } else { - azt_state = AZT_S_START; - AztTimeout = 1; - } - } else { - azt_state = AZT_S_IDLE; - return; - } - break; - - default: - printk("aztcd: invalid state %d\n", azt_state); - return; - } /* case */ - } /* while */ - - - if (!AztTimeout--) { - printk("aztcd: timeout in state %d\n", azt_state); - azt_state = AZT_S_STOP; - if (aztSendCmd(ACMD_STOP)) - RETURN("azt_poll 6"); - STEN_LOW_WAIT; - }; - - SET_TIMER(azt_poll, HZ / 100); -} - - -/*########################################################################### - * Miscellaneous support functions - ########################################################################### -*/ -static void azt_hsg2msf(long hsg, struct msf *msf) -{ - hsg += 150; - msf->min = hsg / 4500; - hsg %= 4500; - msf->sec = hsg / 75; - msf->frame = hsg % 75; -#ifdef AZT_DEBUG - if (msf->min >= 70) - printk("aztcd: Error hsg2msf address Minutes\n"); - if (msf->sec >= 60) - printk("aztcd: Error hsg2msf address Seconds\n"); - if (msf->frame >= 75) - printk("aztcd: Error hsg2msf address Frames\n"); -#endif - azt_bin2bcd(&msf->min); /* convert to BCD */ - azt_bin2bcd(&msf->sec); - azt_bin2bcd(&msf->frame); -} - -static long azt_msf2hsg(struct msf *mp) -{ - return azt_bcd2bin(mp->frame) + azt_bcd2bin(mp->sec) * 75 - + azt_bcd2bin(mp->min) * 4500 - CD_MSF_OFFSET; -} - -static void azt_bin2bcd(unsigned char *p) -{ - int u, t; - - u = *p % 10; - t = *p / 10; - *p = u | (t << 4); -} - -static int azt_bcd2bin(unsigned char bcd) -{ - return (bcd >> 4) * 10 + (bcd & 0xF); -} - -MODULE_LICENSE("GPL"); -MODULE_ALIAS_BLOCKDEV_MAJOR(AZTECH_CDROM_MAJOR); diff --git a/drivers/cdrom/aztcd.h b/drivers/cdrom/aztcd.h deleted file mode 100644 index 057501e31628..000000000000 --- a/drivers/cdrom/aztcd.h +++ /dev/null @@ -1,162 +0,0 @@ -/* $Id: aztcd.h,v 2.60 1997/11/29 09:51:22 root Exp root $ - * - * Definitions for a AztechCD268 CD-ROM interface - * Copyright (C) 1994-98 Werner Zimmermann - * - * based on Mitsumi CDROM driver by Martin Harriss - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * History: W.Zimmermann adaption to Aztech CD268-01A Version 1.3 - * October 1994 Email: Werner.Zimmermann@fht-esslingen.de - */ - -/* *** change this to set the I/O port address of your CD-ROM drive, - set to '-1', if you want autoprobing */ -#define AZT_BASE_ADDR -1 - -/* list of autoprobing addresses (not more than 15), last value must be 0x000 - Note: Autoprobing is only enabled, if AZT_BASE_ADDR is set to '-1' ! */ -#define AZT_BASE_AUTO { 0x320, 0x300, 0x310, 0x330, 0x000 } - -/* Uncomment this, if your CDROM is connected to a Soundwave32-soundcard - and configure AZT_BASE_ADDR and AZT_SW32_BASE_ADDR */ -/*#define AZT_SW32 1 -*/ - -#ifdef AZT_SW32 -#define AZT_SW32_BASE_ADDR 0x220 /*I/O port base address of your soundcard*/ -#endif - -/* Set this to 1, if you want your tray to be locked, set to 0 to prevent tray - from locking */ -#define AZT_ALLOW_TRAY_LOCK 1 - -/*Set this to 1 to allow auto-eject when unmounting a disk, set to 0, if you - don't want the auto-eject feature*/ -#define AZT_AUTO_EJECT 0 - -/*Set this to 1, if you want to use incompatible ioctls for reading in raw and - cooked mode */ -#define AZT_PRIVATE_IOCTLS 1 - -/*Set this to 1, if you want multisession support by the ISO fs. Even if you set - this value to '0' you can use multisession CDs. In that case the drive's firm- - ware will do the appropriate redirection automatically. The CD will then look - like a single session CD (but nevertheless all data may be read). Please read - chapter '5.1 Multisession support' in README.aztcd for details. Normally it's - uncritical to leave this setting untouched */ -#define AZT_MULTISESSION 1 - -/*Uncomment this, if you are using a linux kernel version prior to 2.1.0 */ -/*#define AZT_KERNEL_PRIOR_2_1 */ - -/*---------------------------------------------------------------------------*/ -/*-----nothing to be configured for normal applications below this line------*/ - - -/* Increase this if you get lots of timeouts; if you get kernel panic, replace - STEN_LOW_WAIT by STEN_LOW in the source code */ -#define AZT_STATUS_DELAY 400 /*for timer wait, STEN_LOW_WAIT*/ -#define AZT_TIMEOUT 8000000 /*for busy wait STEN_LOW, DTEN_LOW*/ -#define AZT_FAST_TIMEOUT 10000 /*for reading the version string*/ - -/* number of times to retry a command before giving up */ -#define AZT_RETRY_ATTEMPTS 3 - -/* port access macros */ -#define CMD_PORT azt_port -#define DATA_PORT azt_port -#define STATUS_PORT azt_port+1 -#define MODE_PORT azt_port+2 -#ifdef AZT_SW32 - #define AZT_SW32_INIT (unsigned int) (0xFF00 & (AZT_BASE_ADDR*16)) - #define AZT_SW32_CONFIG_REG AZT_SW32_BASE_ADDR+0x16 /*Soundwave32 Config. Register*/ - #define AZT_SW32_ID_REG AZT_SW32_BASE_ADDR+0x04 /*Soundwave32 ID Version Register*/ -#endif - -/* status bits */ -#define AST_CMD_CHECK 0x80 /* 1 = command error */ -#define AST_DOOR_OPEN 0x40 /* 1 = door is open */ -#define AST_NOT_READY 0x20 /* 1 = no disk in the drive */ -#define AST_DSK_CHG 0x02 /* 1 = disk removed or changed */ -#define AST_MODE 0x01 /* 0=MODE1, 1=MODE2 */ -#define AST_MODE_BITS 0x1C /* Mode Bits */ -#define AST_INITIAL 0x0C /* initial, only valid ... */ -#define AST_BUSY 0x04 /* now playing, only valid - in combination with mode - bits */ -/* flag bits */ -#define AFL_DATA 0x02 /* data available if low */ -#define AFL_STATUS 0x04 /* status available if low */ -#define AFL_OP_OK 0x01 /* OP_OK command correct*/ -#define AFL_PA_OK 0x02 /* PA_OK parameter correct*/ -#define AFL_OP_ERR 0x05 /* error in command*/ -#define AFL_PA_ERR 0x06 /* error in parameters*/ -#define POLLED 0x04 /* polled mode */ - -/* commands */ -#define ACMD_SOFT_RESET 0x10 /* reset drive */ -#define ACMD_PLAY_READ 0x20 /* read data track in cooked mode */ -#define ACMD_PLAY_READ_RAW 0x21 /* reading in raw mode*/ -#define ACMD_SEEK 0x30 /* seek msf address*/ -#define ACMD_SEEK_TO_LEADIN 0x31 /* seek to leadin track*/ -#define ACMD_GET_ERROR 0x40 /* get error code */ -#define ACMD_GET_STATUS 0x41 /* get status */ -#define ACMD_GET_Q_CHANNEL 0x50 /* read info from q channel */ -#define ACMD_EJECT 0x60 /* eject/open tray */ -#define ACMD_CLOSE 0x61 /* close tray */ -#define ACMD_LOCK 0x71 /* lock tray closed */ -#define ACMD_UNLOCK 0x72 /* unlock tray */ -#define ACMD_PAUSE 0x80 /* pause */ -#define ACMD_STOP 0x81 /* stop play */ -#define ACMD_PLAY_AUDIO 0x90 /* play audio track */ -#define ACMD_SET_VOLUME 0x93 /* set audio level */ -#define ACMD_GET_VERSION 0xA0 /* get firmware version */ -#define ACMD_SET_DISK_TYPE 0xA1 /* set disk data mode */ - -#define MAX_TRACKS 104 - -struct msf { - unsigned char min; - unsigned char sec; - unsigned char frame; -}; - -struct azt_Play_msf { - struct msf start; - struct msf end; -}; - -struct azt_DiskInfo { - unsigned char first; - unsigned char next; - unsigned char last; - struct msf diskLength; - struct msf firstTrack; - unsigned char multi; - struct msf nextSession; - struct msf lastSession; - unsigned char xa; - unsigned char audio; -}; - -struct azt_Toc { - unsigned char ctrl_addr; - unsigned char track; - unsigned char pointIndex; - struct msf trackTime; - struct msf diskTime; -}; diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c deleted file mode 100644 index 2157c58755e0..000000000000 --- a/drivers/cdrom/cdu31a.c +++ /dev/null @@ -1,3251 +0,0 @@ -/* -* Sony CDU-31A CDROM interface device driver. -* -* Corey Minyard (minyard@wf-rch.cirr.com) -* -* Colossians 3:17 -* -* See Documentation/cdrom/cdu31a for additional details about this driver. -* -* The Sony interface device driver handles Sony interface CDROM -* drives and provides a complete block-level interface as well as an -* ioctl() interface compatible with the Sun (as specified in -* include/linux/cdrom.h). With this interface, CDROMs can be -* accessed and standard audio CDs can be played back normally. -* -* WARNING - All autoprobes have been removed from the driver. -* You MUST configure the CDU31A via a LILO config -* at boot time or in lilo.conf. I have the -* following in my lilo.conf: -* -* append="cdu31a=0x1f88,0,PAS" -* -* The first number is the I/O base address of the -* card. The second is the interrupt (0 means none). - * The third should be "PAS" if on a Pro-Audio - * spectrum, or nothing if on something else. - * - * This interface is (unfortunately) a polled interface. This is - * because most Sony interfaces are set up with DMA and interrupts - * disables. Some (like mine) do not even have the capability to - * handle interrupts or DMA. For this reason you will see a lot of - * the following: - * - * retry_count = jiffies+ SONY_JIFFIES_TIMEOUT; - * while (time_before(jiffies, retry_count) && (! - * For finding abug in the return of the track numbers. - * TOC processing redone for proper multisession support. - * - * - * It probably a little late to be adding a history, but I guess I - * will start. - * - * 10/24/95 - Added support for disabling the eject button when the - * drive is open. Note that there is a small problem - * still here, if the eject button is pushed while the - * drive light is flashing, the drive will return a bad - * status and be reset. It recovers, though. - * - * 03/07/97 - Fixed a problem with timers. - * - * - * 18 Spetember 1997 -- Ported to Uniform CD-ROM driver by - * Heiko Eissfeldt with additional - * changes by Erik Andersen - * - * 24 January 1998 -- Removed the scd_disc_status() function, which was now - * just dead code left over from the port. - * Erik Andersen - * - * 16 July 1998 -- Drive donated to Erik Andersen by John Kodis - * . Work begun on fixing driver to - * work under 2.1.X. Added temporary extra printks - * which seem to slow it down enough to work. - * - * 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x - * Removed init_module & cleanup_module in favor of - * module_init & module_exit. - * Torben Mathiasen - * - * 22 October 2004 -- Make the driver work in 2.6.X - * Added workaround to fix hard lockups on eject - * Fixed door locking problem after mounting empty drive - * Set double-speed drives to double speed by default - * Removed all readahead things - not needed anymore - * Ondrej Zary -*/ - -#define DEBUG 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "cdu31a.h" - -#define MAJOR_NR CDU31A_CDROM_MAJOR -#include - -#define CDU31A_MAX_CONSECUTIVE_ATTENTIONS 10 - -#define PFX "CDU31A: " - -/* -** Edit the following data to change interrupts, DMA channels, etc. -** Default is polled and no DMA. DMA is not recommended for double-speed -** drives. -*/ -static struct { - unsigned short base; /* I/O Base Address */ - short int_num; /* Interrupt Number (-1 means scan for it, - 0 means don't use) */ -} cdu31a_addresses[] __initdata = { - {0} -}; - -static int handle_sony_cd_attention(void); -static int read_subcode(void); -static void sony_get_toc(void); -static int scd_spinup(void); -/*static int scd_open(struct inode *inode, struct file *filp);*/ -static int scd_open(struct cdrom_device_info *, int); -static void do_sony_cd_cmd(unsigned char cmd, - unsigned char *params, - unsigned int num_params, - unsigned char *result_buffer, - unsigned int *result_size); -static void size_to_buf(unsigned int size, unsigned char *buf); - -/* Parameters for the read-ahead. */ -static unsigned int sony_next_block; /* Next 512 byte block offset */ -static unsigned int sony_blocks_left = 0; /* Number of 512 byte blocks left - in the current read command. */ - - -/* The base I/O address of the Sony Interface. This is a variable (not a - #define) so it can be easily changed via some future ioctl() */ -static unsigned int cdu31a_port = 0; -module_param(cdu31a_port, uint, 0); - -/* - * The following are I/O addresses of the various registers for the drive. The - * comment for the base address also applies here. - */ -static volatile unsigned short sony_cd_cmd_reg; -static volatile unsigned short sony_cd_param_reg; -static volatile unsigned short sony_cd_write_reg; -static volatile unsigned short sony_cd_control_reg; -static volatile unsigned short sony_cd_status_reg; -static volatile unsigned short sony_cd_result_reg; -static volatile unsigned short sony_cd_read_reg; -static volatile unsigned short sony_cd_fifost_reg; - -static struct request_queue *cdu31a_queue; -static DEFINE_SPINLOCK(cdu31a_lock); /* queue lock */ - -static int sony_spun_up = 0; /* Has the drive been spun up? */ - -static int sony_speed = 0; /* Last wanted speed */ - -static int sony_xa_mode = 0; /* Is an XA disk in the drive - and the drive a CDU31A? */ - -static int sony_raw_data_mode = 1; /* 1 if data tracks, 0 if audio. - For raw data reads. */ - -static unsigned int sony_usage = 0; /* How many processes have the - drive open. */ - -static int sony_pas_init = 0; /* Initialize the Pro-Audio - Spectrum card? */ - -static struct s_sony_session_toc single_toc; /* Holds the - table of - contents. */ - -static struct s_all_sessions_toc sony_toc; /* entries gathered from all - sessions */ - -static int sony_toc_read = 0; /* Has the TOC been read for - the drive? */ - -static struct s_sony_subcode last_sony_subcode; /* Points to the last - subcode address read */ - -static DECLARE_MUTEX(sony_sem); /* Semaphore for drive hardware access */ - -static int is_double_speed = 0; /* does the drive support double speed ? */ - -static int is_auto_eject = 1; /* Door has been locked? 1=No/0=Yes */ - -/* - * The audio status uses the values from read subchannel data as specified - * in include/linux/cdrom.h. - */ -static volatile int sony_audio_status = CDROM_AUDIO_NO_STATUS; - -/* - * The following are a hack for pausing and resuming audio play. The drive - * does not work as I would expect it, if you stop it then start it again, - * the drive seeks back to the beginning and starts over. This holds the - * position during a pause so a resume can restart it. It uses the - * audio status variable above to tell if it is paused. - */ -static unsigned volatile char cur_pos_msf[3] = { 0, 0, 0 }; -static unsigned volatile char final_pos_msf[3] = { 0, 0, 0 }; - -/* What IRQ is the drive using? 0 if none. */ -static int cdu31a_irq = 0; -module_param(cdu31a_irq, int, 0); - -/* The interrupt handler will wake this queue up when it gets an - interrupts. */ -static DECLARE_WAIT_QUEUE_HEAD(cdu31a_irq_wait); -static int irq_flag = 0; - -static int curr_control_reg = 0; /* Current value of the control register */ - -/* A disk changed variable. When a disk change is detected, it will - all be set to TRUE. As the upper layers ask for disk_changed status - it will be cleared. */ -static char disk_changed; - -/* This was readahead_buffer once... Now it's used only for audio reads */ -static char audio_buffer[CD_FRAMESIZE_RAW]; - -/* Used to time a short period to abort an operation after the - drive has been idle for a while. This keeps the light on - the drive from flashing for very long. */ -static struct timer_list cdu31a_abort_timer; - -/* Marks if the timeout has started an abort read. This is used - on entry to the drive to tell the code to read out the status - from the abort read. */ -static int abort_read_started = 0; - -/* - * Uniform cdrom interface function - * report back, if disc has changed from time of last request. - */ -static int scd_media_changed(struct cdrom_device_info *cdi, int disc_nr) -{ - int retval; - - retval = disk_changed; - disk_changed = 0; - - return retval; -} - -/* - * Uniform cdrom interface function - * report back, if drive is ready - */ -static int scd_drive_status(struct cdrom_device_info *cdi, int slot_nr) -{ - if (CDSL_CURRENT != slot_nr) - /* we have no changer support */ - return -EINVAL; - if (sony_spun_up) - return CDS_DISC_OK; - if (down_interruptible(&sony_sem)) - return -ERESTARTSYS; - if (scd_spinup() == 0) - sony_spun_up = 1; - up(&sony_sem); - return sony_spun_up ? CDS_DISC_OK : CDS_DRIVE_NOT_READY; -} - -static inline void enable_interrupts(void) -{ - curr_control_reg |= (SONY_ATTN_INT_EN_BIT - | SONY_RES_RDY_INT_EN_BIT - | SONY_DATA_RDY_INT_EN_BIT); - outb(curr_control_reg, sony_cd_control_reg); -} - -static inline void disable_interrupts(void) -{ - curr_control_reg &= ~(SONY_ATTN_INT_EN_BIT - | SONY_RES_RDY_INT_EN_BIT - | SONY_DATA_RDY_INT_EN_BIT); - outb(curr_control_reg, sony_cd_control_reg); -} - -/* - * Wait a little while (used for polling the drive). If in initialization, - * setting a timeout doesn't work, so just loop for a while. - */ -static inline void sony_sleep(void) -{ - if (cdu31a_irq <= 0) { - yield(); - } else { /* Interrupt driven */ - DEFINE_WAIT(w); - int first = 1; - - while (1) { - prepare_to_wait(&cdu31a_irq_wait, &w, - TASK_INTERRUPTIBLE); - if (first) { - enable_interrupts(); - first = 0; - } - - if (irq_flag != 0) - break; - if (!signal_pending(current)) { - schedule(); - continue; - } else - disable_interrupts(); - break; - } - finish_wait(&cdu31a_irq_wait, &w); - irq_flag = 0; - } -} - - -/* - * The following are convenience routine to read various status and set - * various conditions in the drive. - */ -static inline int is_attention(void) -{ - return (inb(sony_cd_status_reg) & SONY_ATTN_BIT) != 0; -} - -static inline int is_busy(void) -{ - return (inb(sony_cd_status_reg) & SONY_BUSY_BIT) != 0; -} - -static inline int is_data_ready(void) -{ - return (inb(sony_cd_status_reg) & SONY_DATA_RDY_BIT) != 0; -} - -static inline int is_data_requested(void) -{ - return (inb(sony_cd_status_reg) & SONY_DATA_REQUEST_BIT) != 0; -} - -static inline int is_result_ready(void) -{ - return (inb(sony_cd_status_reg) & SONY_RES_RDY_BIT) != 0; -} - -static inline int is_param_write_rdy(void) -{ - return (inb(sony_cd_fifost_reg) & SONY_PARAM_WRITE_RDY_BIT) != 0; -} - -static inline int is_result_reg_not_empty(void) -{ - return (inb(sony_cd_fifost_reg) & SONY_RES_REG_NOT_EMP_BIT) != 0; -} - -static inline void reset_drive(void) -{ - curr_control_reg = 0; - sony_toc_read = 0; - outb(SONY_DRIVE_RESET_BIT, sony_cd_control_reg); -} - -/* - * Uniform cdrom interface function - * reset drive and return when it is ready - */ -static int scd_reset(struct cdrom_device_info *cdi) -{ - unsigned long retry_count; - - if (down_interruptible(&sony_sem)) - return -ERESTARTSYS; - reset_drive(); - - retry_count = jiffies + SONY_RESET_TIMEOUT; - while (time_before(jiffies, retry_count) && (!is_attention())) { - sony_sleep(); - } - - up(&sony_sem); - return 0; -} - -static inline void clear_attention(void) -{ - outb(curr_control_reg | SONY_ATTN_CLR_BIT, sony_cd_control_reg); -} - -static inline void clear_result_ready(void) -{ - outb(curr_control_reg | SONY_RES_RDY_CLR_BIT, sony_cd_control_reg); -} - -static inline void clear_data_ready(void) -{ - outb(curr_control_reg | SONY_DATA_RDY_CLR_BIT, - sony_cd_control_reg); -} - -static inline void clear_param_reg(void) -{ - outb(curr_control_reg | SONY_PARAM_CLR_BIT, sony_cd_control_reg); -} - -static inline unsigned char read_status_register(void) -{ - return inb(sony_cd_status_reg); -} - -static inline unsigned char read_result_register(void) -{ - return inb(sony_cd_result_reg); -} - -static inline unsigned char read_data_register(void) -{ - return inb(sony_cd_read_reg); -} - -static inline void write_param(unsigned char param) -{ - outb(param, sony_cd_param_reg); -} - -static inline void write_cmd(unsigned char cmd) -{ - outb(curr_control_reg | SONY_RES_RDY_INT_EN_BIT, - sony_cd_control_reg); - outb(cmd, sony_cd_cmd_reg); -} - -static irqreturn_t cdu31a_interrupt(int irq, void *dev_id) -{ - unsigned char val; - - if (abort_read_started) { - /* We might be waiting for an abort to finish. Don't - disable interrupts yet, though, because we handle - this one here. */ - /* Clear out the result registers. */ - while (is_result_reg_not_empty()) { - val = read_result_register(); - } - clear_data_ready(); - clear_result_ready(); - - /* Clear out the data */ - while (is_data_requested()) { - val = read_data_register(); - } - abort_read_started = 0; - - /* If something was waiting, wake it up now. */ - if (waitqueue_active(&cdu31a_irq_wait)) { - disable_interrupts(); - irq_flag = 1; - wake_up_interruptible(&cdu31a_irq_wait); - } - } else if (waitqueue_active(&cdu31a_irq_wait)) { - disable_interrupts(); - irq_flag = 1; - wake_up_interruptible(&cdu31a_irq_wait); - } else { - disable_interrupts(); - printk(KERN_NOTICE PFX - "Got an interrupt but nothing was waiting\n"); - } - return IRQ_HANDLED; -} - -/* - * give more verbose error messages - */ -static unsigned char *translate_error(unsigned char err_code) -{ - static unsigned char errbuf[80]; - - switch (err_code) { - case 0x10: return "illegal command "; - case 0x11: return "illegal parameter "; - - case 0x20: return "not loaded "; - case 0x21: return "no disc "; - case 0x22: return "not spinning "; - case 0x23: return "spinning "; - case 0x25: return "spindle servo "; - case 0x26: return "focus servo "; - case 0x29: return "eject mechanism "; - case 0x2a: return "audio playing "; - case 0x2c: return "emergency eject "; - - case 0x30: return "focus "; - case 0x31: return "frame sync "; - case 0x32: return "subcode address "; - case 0x33: return "block sync "; - case 0x34: return "header address "; - - case 0x40: return "illegal track read "; - case 0x41: return "mode 0 read "; - case 0x42: return "illegal mode read "; - case 0x43: return "illegal block size read "; - case 0x44: return "mode read "; - case 0x45: return "form read "; - case 0x46: return "leadout read "; - case 0x47: return "buffer overrun "; - - case 0x53: return "unrecoverable CIRC "; - case 0x57: return "unrecoverable LECC "; - - case 0x60: return "no TOC "; - case 0x61: return "invalid subcode data "; - case 0x63: return "focus on TOC read "; - case 0x64: return "frame sync on TOC read "; - case 0x65: return "TOC data "; - - case 0x70: return "hardware failure "; - case 0x91: return "leadin "; - case 0x92: return "leadout "; - case 0x93: return "data track "; - } - sprintf(errbuf, "unknown 0x%02x ", err_code); - return errbuf; -} - -/* - * Set the drive parameters so the drive will auto-spin-up when a - * disk is inserted. - */ -static void set_drive_params(int want_doublespeed) -{ - unsigned char res_reg[12]; - unsigned int res_size; - unsigned char params[3]; - - - params[0] = SONY_SD_AUTO_SPIN_DOWN_TIME; - params[1] = 0x00; /* Never spin down the drive. */ - do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, - params, 2, res_reg, &res_size); - if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) { - printk(KERN_NOTICE PFX - "Unable to set spin-down time: 0x%2.2x\n", res_reg[1]); - } - - params[0] = SONY_SD_MECH_CONTROL; - params[1] = SONY_AUTO_SPIN_UP_BIT; /* Set auto spin up */ - - if (is_auto_eject) - params[1] |= SONY_AUTO_EJECT_BIT; - - if (is_double_speed && want_doublespeed) { - params[1] |= SONY_DOUBLE_SPEED_BIT; /* Set the drive to double speed if - possible */ - } - do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, - params, 2, res_reg, &res_size); - if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) { - printk(KERN_NOTICE PFX "Unable to set mechanical " - "parameters: 0x%2.2x\n", res_reg[1]); - } -} - -/* - * Uniform cdrom interface function - * select reading speed for data access - */ -static int scd_select_speed(struct cdrom_device_info *cdi, int speed) -{ - if (speed == 0) - sony_speed = 1; - else - sony_speed = speed - 1; - - if (down_interruptible(&sony_sem)) - return -ERESTARTSYS; - set_drive_params(sony_speed); - up(&sony_sem); - return 0; -} - -/* - * Uniform cdrom interface function - * lock or unlock eject button - */ -static int scd_lock_door(struct cdrom_device_info *cdi, int lock) -{ - if (lock == 0) { - is_auto_eject = 1; - } else { - is_auto_eject = 0; - } - if (down_interruptible(&sony_sem)) - return -ERESTARTSYS; - set_drive_params(sony_speed); - up(&sony_sem); - return 0; -} - -/* - * This code will reset the drive and attempt to restore sane parameters. - */ -static void restart_on_error(void) -{ - unsigned char res_reg[12]; - unsigned int res_size; - unsigned long retry_count; - - - printk(KERN_NOTICE PFX "Resetting drive on error\n"); - reset_drive(); - retry_count = jiffies + SONY_RESET_TIMEOUT; - while (time_before(jiffies, retry_count) && (!is_attention())) { - sony_sleep(); - } - set_drive_params(sony_speed); - do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size); - if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) { - printk(KERN_NOTICE PFX "Unable to spin up drive: 0x%2.2x\n", - res_reg[1]); - } - - msleep(2000); - - sony_get_toc(); -} - -/* - * This routine writes data to the parameter register. Since this should - * happen fairly fast, it is polled with no OS waits between. - */ -static int write_params(unsigned char *params, int num_params) -{ - unsigned int retry_count; - - - retry_count = SONY_READY_RETRIES; - while ((retry_count > 0) && (!is_param_write_rdy())) { - retry_count--; - } - if (!is_param_write_rdy()) { - return -EIO; - } - - while (num_params > 0) { - write_param(*params); - params++; - num_params--; - } - - return 0; -} - - -/* - * The following reads data from the command result register. It is a - * fairly complex routine, all status info flows back through this - * interface. The algorithm is stolen directly from the flowcharts in - * the drive manual. - */ -static void -get_result(unsigned char *result_buffer, unsigned int *result_size) -{ - unsigned char a, b; - int i; - unsigned long retry_count; - - - while (handle_sony_cd_attention()); - /* Wait for the result data to be ready */ - retry_count = jiffies + SONY_JIFFIES_TIMEOUT; - while (time_before(jiffies, retry_count) - && (is_busy() || (!(is_result_ready())))) { - sony_sleep(); - - while (handle_sony_cd_attention()); - } - if (is_busy() || (!(is_result_ready()))) { - pr_debug(PFX "timeout out %d\n", __LINE__); - result_buffer[0] = 0x20; - result_buffer[1] = SONY_TIMEOUT_OP_ERR; - *result_size = 2; - return; - } - - /* - * Get the first two bytes. This determines what else needs - * to be done. - */ - clear_result_ready(); - a = read_result_register(); - *result_buffer = a; - result_buffer++; - - /* Check for block error status result. */ - if ((a & 0xf0) == 0x50) { - *result_size = 1; - return; - } - - b = read_result_register(); - *result_buffer = b; - result_buffer++; - *result_size = 2; - - /* - * 0x20 means an error occurred. Byte 2 will have the error code. - * Otherwise, the command succeeded, byte 2 will have the count of - * how many more status bytes are coming. - * - * The result register can be read 10 bytes at a time, a wait for - * result ready to be asserted must be done between every 10 bytes. - */ - if ((a & 0xf0) != 0x20) { - if (b > 8) { - for (i = 0; i < 8; i++) { - *result_buffer = read_result_register(); - result_buffer++; - (*result_size)++; - } - b = b - 8; - - while (b > 10) { - retry_count = SONY_READY_RETRIES; - while ((retry_count > 0) - && (!is_result_ready())) { - retry_count--; - } - if (!is_result_ready()) { - pr_debug(PFX "timeout out %d\n", - __LINE__); - result_buffer[0] = 0x20; - result_buffer[1] = - SONY_TIMEOUT_OP_ERR; - *result_size = 2; - return; - } - - clear_result_ready(); - - for (i = 0; i < 10; i++) { - *result_buffer = - read_result_register(); - result_buffer++; - (*result_size)++; - } - b = b - 10; - } - - if (b > 0) { - retry_count = SONY_READY_RETRIES; - while ((retry_count > 0) - && (!is_result_ready())) { - retry_count--; - } - if (!is_result_ready()) { - pr_debug(PFX "timeout out %d\n", - __LINE__); - result_buffer[0] = 0x20; - result_buffer[1] = - SONY_TIMEOUT_OP_ERR; - *result_size = 2; - return; - } - } - } - - while (b > 0) { - *result_buffer = read_result_register(); - result_buffer++; - (*result_size)++; - b--; - } - } -} - -/* - * Do a command that does not involve data transfer. This routine must - * be re-entrant from the same task to support being called from the - * data operation code when an error occurs. - */ -static void -do_sony_cd_cmd(unsigned char cmd, - unsigned char *params, - unsigned int num_params, - unsigned char *result_buffer, unsigned int *result_size) -{ - unsigned long retry_count; - int num_retries = 0; - -retry_cd_operation: - - while (handle_sony_cd_attention()); - - retry_count = jiffies + SONY_JIFFIES_TIMEOUT; - while (time_before(jiffies, retry_count) && (is_busy())) { - sony_sleep(); - - while (handle_sony_cd_attention()); - } - if (is_busy()) { - pr_debug(PFX "timeout out %d\n", __LINE__); - result_buffer[0] = 0x20; - result_buffer[1] = SONY_TIMEOUT_OP_ERR; - *result_size = 2; - } else { - clear_result_ready(); - clear_param_reg(); - - write_params(params, num_params); - write_cmd(cmd); - - get_result(result_buffer, result_size); - } - - if (((result_buffer[0] & 0xf0) == 0x20) - && (num_retries < MAX_CDU31A_RETRIES)) { - num_retries++; - msleep(100); - goto retry_cd_operation; - } -} - - -/* - * Handle an attention from the drive. This will return 1 if it found one - * or 0 if not (if one is found, the caller might want to call again). - * - * This routine counts the number of consecutive times it is called - * (since this is always called from a while loop until it returns - * a 0), and returns a 0 if it happens too many times. This will help - * prevent a lockup. - */ -static int handle_sony_cd_attention(void) -{ - unsigned char atten_code; - static int num_consecutive_attentions = 0; - volatile int val; - - -#if 0 - pr_debug(PFX "Entering %s\n", __FUNCTION__); -#endif - if (is_attention()) { - if (num_consecutive_attentions > - CDU31A_MAX_CONSECUTIVE_ATTENTIONS) { - printk(KERN_NOTICE PFX "Too many consecutive " - "attentions: %d\n", num_consecutive_attentions); - num_consecutive_attentions = 0; - pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, - __LINE__); - return 0; - } - - clear_attention(); - atten_code = read_result_register(); - - switch (atten_code) { - /* Someone changed the CD. Mark it as changed */ - case SONY_MECH_LOADED_ATTN: - disk_changed = 1; - sony_toc_read = 0; - sony_audio_status = CDROM_AUDIO_NO_STATUS; - sony_blocks_left = 0; - break; - - case SONY_SPIN_DOWN_COMPLETE_ATTN: - /* Mark the disk as spun down. */ - sony_spun_up = 0; - break; - - case SONY_AUDIO_PLAY_DONE_ATTN: - sony_audio_status = CDROM_AUDIO_COMPLETED; - read_subcode(); - break; - - case SONY_EJECT_PUSHED_ATTN: - if (is_auto_eject) { - sony_audio_status = CDROM_AUDIO_INVALID; - } - break; - - case SONY_LEAD_IN_ERR_ATTN: - case SONY_LEAD_OUT_ERR_ATTN: - case SONY_DATA_TRACK_ERR_ATTN: - case SONY_AUDIO_PLAYBACK_ERR_ATTN: - sony_audio_status = CDROM_AUDIO_ERROR; - break; - } - - num_consecutive_attentions++; - pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); - return 1; - } else if (abort_read_started) { - while (is_result_reg_not_empty()) { - val = read_result_register(); - } - clear_data_ready(); - clear_result_ready(); - /* Clear out the data */ - while (is_data_requested()) { - val = read_data_register(); - } - abort_read_started = 0; - pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); - return 1; - } - - num_consecutive_attentions = 0; -#if 0 - pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); -#endif - return 0; -} - - -/* Convert from an integer 0-99 to BCD */ -static inline unsigned int int_to_bcd(unsigned int val) -{ - int retval; - - - retval = (val / 10) << 4; - retval = retval | val % 10; - return retval; -} - - -/* Convert from BCD to an integer from 0-99 */ -static unsigned int bcd_to_int(unsigned int bcd) -{ - return (((bcd >> 4) & 0x0f) * 10) + (bcd & 0x0f); -} - - -/* - * Convert a logical sector value (like the OS would want to use for - * a block device) to an MSF format. - */ -static void log_to_msf(unsigned int log, unsigned char *msf) -{ - log = log + LOG_START_OFFSET; - msf[0] = int_to_bcd(log / 4500); - log = log % 4500; - msf[1] = int_to_bcd(log / 75); - msf[2] = int_to_bcd(log % 75); -} - - -/* - * Convert an MSF format to a logical sector. - */ -static unsigned int msf_to_log(unsigned char *msf) -{ - unsigned int log; - - - log = msf[2]; - log += msf[1] * 75; - log += msf[0] * 4500; - log = log - LOG_START_OFFSET; - - return log; -} - - -/* - * Take in integer size value and put it into a buffer like - * the drive would want to see a number-of-sector value. - */ -static void size_to_buf(unsigned int size, unsigned char *buf) -{ - buf[0] = size / 65536; - size = size % 65536; - buf[1] = size / 256; - buf[2] = size % 256; -} - -/* Starts a read operation. Returns 0 on success and 1 on failure. - The read operation used here allows multiple sequential sectors - to be read and status returned for each sector. The driver will - read the output one at a time as the requests come and abort the - operation if the requested sector is not the next one from the - drive. */ -static int -start_request(unsigned int sector, unsigned int nsect) -{ - unsigned char params[6]; - unsigned long retry_count; - - - pr_debug(PFX "Entering %s\n", __FUNCTION__); - log_to_msf(sector, params); - size_to_buf(nsect, ¶ms[3]); - - /* - * Clear any outstanding attentions and wait for the drive to - * complete any pending operations. - */ - while (handle_sony_cd_attention()); - - retry_count = jiffies + SONY_JIFFIES_TIMEOUT; - while (time_before(jiffies, retry_count) && (is_busy())) { - sony_sleep(); - - while (handle_sony_cd_attention()); - } - - if (is_busy()) { - printk(KERN_NOTICE PFX "Timeout while waiting " - "to issue command\n"); - pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); - return 1; - } else { - /* Issue the command */ - clear_result_ready(); - clear_param_reg(); - - write_params(params, 6); - write_cmd(SONY_READ_BLKERR_STAT_CMD); - - sony_blocks_left = nsect * 4; - sony_next_block = sector * 4; - pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); - return 0; - } - pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); -} - -/* Abort a pending read operation. Clear all the drive status variables. */ -static void abort_read(void) -{ - unsigned char result_reg[2]; - int result_size; - volatile int val; - - - do_sony_cd_cmd(SONY_ABORT_CMD, NULL, 0, result_reg, &result_size); - if ((result_reg[0] & 0xf0) == 0x20) { - printk(KERN_ERR PFX "Aborting read, %s error\n", - translate_error(result_reg[1])); - } - - while (is_result_reg_not_empty()) { - val = read_result_register(); - } - clear_data_ready(); - clear_result_ready(); - /* Clear out the data */ - while (is_data_requested()) { - val = read_data_register(); - } - - sony_blocks_left = 0; -} - -/* Called when the timer times out. This will abort the - pending read operation. */ -static void handle_abort_timeout(unsigned long data) -{ - pr_debug(PFX "Entering %s\n", __FUNCTION__); - /* If it is in use, ignore it. */ - if (down_trylock(&sony_sem) == 0) { - /* We can't use abort_read(), because it will sleep - or schedule in the timer interrupt. Just start - the operation, finish it on the next access to - the drive. */ - clear_result_ready(); - clear_param_reg(); - write_cmd(SONY_ABORT_CMD); - - sony_blocks_left = 0; - abort_read_started = 1; - up(&sony_sem); - } - pr_debug(PFX "Leaving %s\n", __FUNCTION__); -} - -/* Actually get one sector of data from the drive. */ -static void -input_data_sector(char *buffer) -{ - pr_debug(PFX "Entering %s\n", __FUNCTION__); - - /* If an XA disk on a CDU31A, skip the first 12 bytes of data from - the disk. The real data is after that. We can use audio_buffer. */ - if (sony_xa_mode) - insb(sony_cd_read_reg, audio_buffer, CD_XA_HEAD); - - clear_data_ready(); - - insb(sony_cd_read_reg, buffer, 2048); - - /* If an XA disk, we have to clear out the rest of the unused - error correction data. We can use audio_buffer for that. */ - if (sony_xa_mode) - insb(sony_cd_read_reg, audio_buffer, CD_XA_TAIL); - - pr_debug(PFX "Leaving %s\n", __FUNCTION__); -} - -/* read data from the drive. Note the nsect must be <= 4. */ -static void -read_data_block(char *buffer, - unsigned int block, - unsigned int nblocks, - unsigned char res_reg[], int *res_size) -{ - unsigned long retry_count; - - pr_debug(PFX "Entering %s\n", __FUNCTION__); - - res_reg[0] = 0; - res_reg[1] = 0; - *res_size = 0; - - /* Wait for the drive to tell us we have something */ - retry_count = jiffies + SONY_JIFFIES_TIMEOUT; - while (time_before(jiffies, retry_count) && !(is_data_ready())) { - while (handle_sony_cd_attention()); - - sony_sleep(); - } - if (!(is_data_ready())) { - if (is_result_ready()) { - get_result(res_reg, res_size); - if ((res_reg[0] & 0xf0) != 0x20) { - printk(KERN_NOTICE PFX "Got result that should" - " have been error: %d\n", res_reg[0]); - res_reg[0] = 0x20; - res_reg[1] = SONY_BAD_DATA_ERR; - *res_size = 2; - } - abort_read(); - } else { - pr_debug(PFX "timeout out %d\n", __LINE__); - res_reg[0] = 0x20; - res_reg[1] = SONY_TIMEOUT_OP_ERR; - *res_size = 2; - abort_read(); - } - } else { - input_data_sector(buffer); - sony_blocks_left -= nblocks; - sony_next_block += nblocks; - - /* Wait for the status from the drive. */ - retry_count = jiffies + SONY_JIFFIES_TIMEOUT; - while (time_before(jiffies, retry_count) - && !(is_result_ready())) { - while (handle_sony_cd_attention()); - - sony_sleep(); - } - - if (!is_result_ready()) { - pr_debug(PFX "timeout out %d\n", __LINE__); - res_reg[0] = 0x20; - res_reg[1] = SONY_TIMEOUT_OP_ERR; - *res_size = 2; - abort_read(); - } else { - get_result(res_reg, res_size); - - /* If we got a buffer status, handle that. */ - if ((res_reg[0] & 0xf0) == 0x50) { - - if ((res_reg[0] == - SONY_NO_CIRC_ERR_BLK_STAT) - || (res_reg[0] == - SONY_NO_LECC_ERR_BLK_STAT) - || (res_reg[0] == - SONY_RECOV_LECC_ERR_BLK_STAT)) { - /* nothing here */ - } else { - printk(KERN_ERR PFX "Data block " - "error: 0x%x\n", res_reg[0]); - res_reg[0] = 0x20; - res_reg[1] = SONY_BAD_DATA_ERR; - *res_size = 2; - } - - /* Final transfer is done for read command, get final result. */ - if (sony_blocks_left == 0) { - get_result(res_reg, res_size); - } - } else if ((res_reg[0] & 0xf0) != 0x20) { - /* The drive gave me bad status, I don't know what to do. - Reset the driver and return an error. */ - printk(KERN_ERR PFX "Invalid block " - "status: 0x%x\n", res_reg[0]); - restart_on_error(); - res_reg[0] = 0x20; - res_reg[1] = SONY_BAD_DATA_ERR; - *res_size = 2; - } - } - } - pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); -} - - -/* - * The OS calls this to perform a read or write operation to the drive. - * Write obviously fail. Reads to a read ahead of sony_buffer_size - * bytes to help speed operations. This especially helps since the OS - * uses 1024 byte blocks and the drive uses 2048 byte blocks. Since most - * data access on a CD is done sequentially, this saves a lot of operations. - */ -static void do_cdu31a_request(request_queue_t * q) -{ - struct request *req; - int block, nblock, num_retries; - unsigned char res_reg[12]; - unsigned int res_size; - - pr_debug(PFX "Entering %s\n", __FUNCTION__); - - spin_unlock_irq(q->queue_lock); - if (down_interruptible(&sony_sem)) { - spin_lock_irq(q->queue_lock); - return; - } - - /* Get drive status before doing anything. */ - while (handle_sony_cd_attention()); - - /* Make sure we have a valid TOC. */ - sony_get_toc(); - - - /* Make sure the timer is cancelled. */ - del_timer(&cdu31a_abort_timer); - - while (1) { - /* - * The beginning here is stolen from the hard disk driver. I hope - * it's right. - */ - req = elv_next_request(q); - if (!req) - goto end_do_cdu31a_request; - - if (!sony_spun_up) - scd_spinup(); - - block = req->sector; - nblock = req->nr_sectors; - pr_debug(PFX "request at block %d, length %d blocks\n", - block, nblock); - if (!sony_toc_read) { - printk(KERN_NOTICE PFX "TOC not read\n"); - end_request(req, 0); - continue; - } - - /* WTF??? */ - if (!blk_fs_request(req)) { - end_request(req, 0); - continue; - } - if (rq_data_dir(req) == WRITE) { - end_request(req, 0); - continue; - } - - /* - * If the block address is invalid or the request goes beyond the end of - * the media, return an error. - */ - if (((block + nblock) / 4) >= sony_toc.lead_out_start_lba) { - printk(KERN_NOTICE PFX "Request past end of media\n"); - end_request(req, 0); - continue; - } - - if (nblock > 4) - nblock = 4; - num_retries = 0; - - try_read_again: - while (handle_sony_cd_attention()); - - if (!sony_toc_read) { - printk(KERN_NOTICE PFX "TOC not read\n"); - end_request(req, 0); - continue; - } - - /* If no data is left to be read from the drive, start the - next request. */ - if (sony_blocks_left == 0) { - if (start_request(block / 4, nblock / 4)) { - end_request(req, 0); - continue; - } - } - /* If the requested block is not the next one waiting in - the driver, abort the current operation and start a - new one. */ - else if (block != sony_next_block) { - pr_debug(PFX "Read for block %d, expected %d\n", - block, sony_next_block); - abort_read(); - if (!sony_toc_read) { - printk(KERN_NOTICE PFX "TOC not read\n"); - end_request(req, 0); - continue; - } - if (start_request(block / 4, nblock / 4)) { - printk(KERN_NOTICE PFX "start request failed\n"); - end_request(req, 0); - continue; - } - } - - read_data_block(req->buffer, block, nblock, res_reg, &res_size); - - if (res_reg[0] != 0x20) { - if (!end_that_request_first(req, 1, nblock)) { - spin_lock_irq(q->queue_lock); - blkdev_dequeue_request(req); - end_that_request_last(req, 1); - spin_unlock_irq(q->queue_lock); - } - continue; - } - - if (num_retries > MAX_CDU31A_RETRIES) { - end_request(req, 0); - continue; - } - - num_retries++; - if (res_reg[1] == SONY_NOT_SPIN_ERR) { - do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, - &res_size); - } else { - printk(KERN_NOTICE PFX "%s error for block %d, nblock %d\n", - translate_error(res_reg[1]), block, nblock); - } - goto try_read_again; - } - end_do_cdu31a_request: -#if 0 - /* After finished, cancel any pending operations. */ - abort_read(); -#else - /* Start a timer to time out after a while to disable - the read. */ - cdu31a_abort_timer.expires = jiffies + 2 * HZ; /* Wait 2 seconds */ - add_timer(&cdu31a_abort_timer); -#endif - - up(&sony_sem); - spin_lock_irq(q->queue_lock); - pr_debug(PFX "Leaving %s at %d\n", __FUNCTION__, __LINE__); -} - - -/* - * Read the table of contents from the drive and set up TOC if - * successful. - */ -static void sony_get_toc(void) -{ - unsigned char res_reg[2]; - unsigned int res_size; - unsigned char parms[1]; - int session; - int num_spin_ups; - int totaltracks = 0; - int mint = 99; - int maxt = 0; - - pr_debug(PFX "Entering %s\n", __FUNCTION__); - - num_spin_ups = 0; - if (!sony_toc_read) { - respinup_on_gettoc: - /* Ignore the result, since it might error if spinning already. */ - do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, - &res_size); - - do_sony_cd_cmd(SONY_READ_TOC_CMD, NULL, 0, res_reg, - &res_size); - - /* The drive sometimes returns error 0. I don't know why, but ignore - it. It seems to mean the drive has already done the operation. */ - if ((res_size < 2) - || ((res_reg[0] != 0) && (res_reg[1] != 0))) { - /* If the drive is already playing, it's ok. */ - if ((res_reg[1] == SONY_AUDIO_PLAYING_ERR) - || (res_reg[1] == 0)) { - goto gettoc_drive_spinning; - } - - /* If the drive says it is not spun up (even though we just did it!) - then retry the operation at least a few times. */ - if ((res_reg[1] == SONY_NOT_SPIN_ERR) - && (num_spin_ups < MAX_CDU31A_RETRIES)) { - num_spin_ups++; - goto respinup_on_gettoc; - } - - printk("cdu31a: Error reading TOC: %x %s\n", - res_reg[0], translate_error(res_reg[1])); - return; - } - - gettoc_drive_spinning: - - /* The idea here is we keep asking for sessions until the command - fails. Then we know what the last valid session on the disk is. - No need to check session 0, since session 0 is the same as session - 1; the command returns different information if you give it 0. - */ -#if DEBUG - memset(&sony_toc, 0x0e, sizeof(sony_toc)); - memset(&single_toc, 0x0f, sizeof(single_toc)); -#endif - session = 1; - while (1) { -/* This seems to slow things down enough to make it work. This - * appears to be a problem in do_sony_cd_cmd. This printk seems - * to address the symptoms... -Erik */ - pr_debug(PFX "Trying session %d\n", session); - parms[0] = session; - do_sony_cd_cmd(SONY_READ_TOC_SPEC_CMD, - parms, 1, res_reg, &res_size); - - pr_debug(PFX "%2.2x %2.2x\n", res_reg[0], res_reg[1]); - - if ((res_size < 2) - || ((res_reg[0] & 0xf0) == 0x20)) { - /* An error reading the TOC, this must be past the last session. */ - if (session == 1) - printk - ("Yikes! Couldn't read any sessions!"); - break; - } - pr_debug(PFX "Reading session %d\n", session); - - parms[0] = session; - do_sony_cd_cmd(SONY_REQ_TOC_DATA_SPEC_CMD, - parms, - 1, - (unsigned char *) &single_toc, - &res_size); - if ((res_size < 2) - || ((single_toc.exec_status[0] & 0xf0) == - 0x20)) { - printk(KERN_ERR PFX "Error reading " - "session %d: %x %s\n", - session, single_toc.exec_status[0], - translate_error(single_toc. - exec_status[1])); - /* An error reading the TOC. Return without sony_toc_read - set. */ - return; - } - pr_debug(PFX "add0 %01x, con0 %01x, poi0 %02x, " - "1st trk %d, dsktyp %x, dum0 %x\n", - single_toc.address0, single_toc.control0, - single_toc.point0, - bcd_to_int(single_toc.first_track_num), - single_toc.disk_type, single_toc.dummy0); - pr_debug(PFX "add1 %01x, con1 %01x, poi1 %02x, " - "lst trk %d, dummy1 %x, dum2 %x\n", - single_toc.address1, single_toc.control1, - single_toc.point1, - bcd_to_int(single_toc.last_track_num), - single_toc.dummy1, single_toc.dummy2); - pr_debug(PFX "add2 %01x, con2 %01x, poi2 %02x " - "leadout start min %d, sec %d, frame %d\n", - single_toc.address2, single_toc.control2, - single_toc.point2, - bcd_to_int(single_toc.lead_out_start_msf[0]), - bcd_to_int(single_toc.lead_out_start_msf[1]), - bcd_to_int(single_toc.lead_out_start_msf[2])); - if (res_size > 18 && single_toc.pointb0 > 0xaf) - pr_debug(PFX "addb0 %01x, conb0 %01x, poib0 %02x, nextsession min %d, sec %d, frame %d\n" - "#mode5_ptrs %02d, max_start_outer_leadout_msf min %d, sec %d, frame %d\n", - single_toc.addressb0, - single_toc.controlb0, - single_toc.pointb0, - bcd_to_int(single_toc. - next_poss_prog_area_msf - [0]), - bcd_to_int(single_toc. - next_poss_prog_area_msf - [1]), - bcd_to_int(single_toc. - next_poss_prog_area_msf - [2]), - single_toc.num_mode_5_pointers, - bcd_to_int(single_toc. - max_start_outer_leadout_msf - [0]), - bcd_to_int(single_toc. - max_start_outer_leadout_msf - [1]), - bcd_to_int(single_toc. - max_start_outer_leadout_msf - [2])); - if (res_size > 27 && single_toc.pointb1 > 0xaf) - pr_debug(PFX "addb1 %01x, conb1 %01x, poib1 %02x, %x %x %x %x #skipint_ptrs %d, #skiptrkassign %d %x\n", - single_toc.addressb1, - single_toc.controlb1, - single_toc.pointb1, - single_toc.dummyb0_1[0], - single_toc.dummyb0_1[1], - single_toc.dummyb0_1[2], - single_toc.dummyb0_1[3], - single_toc.num_skip_interval_pointers, - single_toc.num_skip_track_assignments, - single_toc.dummyb0_2); - if (res_size > 36 && single_toc.pointb2 > 0xaf) - pr_debug(PFX "addb2 %01x, conb2 %01x, poib2 %02x, %02x %02x %02x %02x %02x %02x %02x\n", - single_toc.addressb2, - single_toc.controlb2, - single_toc.pointb2, - single_toc.tracksb2[0], - single_toc.tracksb2[1], - single_toc.tracksb2[2], - single_toc.tracksb2[3], - single_toc.tracksb2[4], - single_toc.tracksb2[5], - single_toc.tracksb2[6]); - if (res_size > 45 && single_toc.pointb3 > 0xaf) - pr_debug(PFX "addb3 %01x, conb3 %01x, poib3 %02x, %02x %02x %02x %02x %02x %02x %02x\n", - single_toc.addressb3, - single_toc.controlb3, - single_toc.pointb3, - single_toc.tracksb3[0], - single_toc.tracksb3[1], - single_toc.tracksb3[2], - single_toc.tracksb3[3], - single_toc.tracksb3[4], - single_toc.tracksb3[5], - single_toc.tracksb3[6]); - if (res_size > 54 && single_toc.pointb4 > 0xaf) - pr_debug(PFX "addb4 %01x, conb4 %01x, poib4 %02x, %02x %02x %02x %02x %02x %02x %02x\n", - single_toc.addressb4, - single_toc.controlb4, - single_toc.pointb4, - single_toc.tracksb4[0], - single_toc.tracksb4[1], - single_toc.tracksb4[2], - single_toc.tracksb4[3], - single_toc.tracksb4[4], - single_toc.tracksb4[5], - single_toc.tracksb4[6]); - if (res_size > 63 && single_toc.pointc0 > 0xaf) - pr_debug(PFX "addc0 %01x, conc0 %01x, poic0 %02x, %02x %02x %02x %02x %02x %02x %02x\n", - single_toc.addressc0, - single_toc.controlc0, - single_toc.pointc0, - single_toc.dummyc0[0], - single_toc.dummyc0[1], - single_toc.dummyc0[2], - single_toc.dummyc0[3], - single_toc.dummyc0[4], - single_toc.dummyc0[5], - single_toc.dummyc0[6]); -#undef DEBUG -#define DEBUG 0 - - sony_toc.lead_out_start_msf[0] = - bcd_to_int(single_toc.lead_out_start_msf[0]); - sony_toc.lead_out_start_msf[1] = - bcd_to_int(single_toc.lead_out_start_msf[1]); - sony_toc.lead_out_start_msf[2] = - bcd_to_int(single_toc.lead_out_start_msf[2]); - sony_toc.lead_out_start_lba = - single_toc.lead_out_start_lba = - msf_to_log(sony_toc.lead_out_start_msf); - - /* For points that do not exist, move the data over them - to the right location. */ - if (single_toc.pointb0 != 0xb0) { - memmove(((char *) &single_toc) + 27, - ((char *) &single_toc) + 18, - res_size - 18); - res_size += 9; - } else if (res_size > 18) { - sony_toc.lead_out_start_msf[0] = - bcd_to_int(single_toc. - max_start_outer_leadout_msf - [0]); - sony_toc.lead_out_start_msf[1] = - bcd_to_int(single_toc. - max_start_outer_leadout_msf - [1]); - sony_toc.lead_out_start_msf[2] = - bcd_to_int(single_toc. - max_start_outer_leadout_msf - [2]); - sony_toc.lead_out_start_lba = - msf_to_log(sony_toc. - lead_out_start_msf); - } - if (single_toc.pointb1 != 0xb1) { - memmove(((char *) &single_toc) + 36, - ((char *) &single_toc) + 27, - res_size - 27); - res_size += 9; - } - if (single_toc.pointb2 != 0xb2) { - memmove(((char *) &single_toc) + 45, - ((char *) &single_toc) + 36, - res_size - 36); - res_size += 9; - } - if (single_toc.pointb3 != 0xb3) { - memmove(((char *) &single_toc) + 54, - ((char *) &single_toc) + 45, - res_size - 45); - res_size += 9; - } - if (single_toc.pointb4 != 0xb4) { - memmove(((char *) &single_toc) + 63, - ((char *) &single_toc) + 54, - res_size - 54); - res_size += 9; - } - if (single_toc.pointc0 != 0xc0) { - memmove(((char *) &single_toc) + 72, - ((char *) &single_toc) + 63, - res_size - 63); - res_size += 9; - } -#if DEBUG - printk(PRINT_INFO PFX "start track lba %u, " - "leadout start lba %u\n", - single_toc.start_track_lba, - single_toc.lead_out_start_lba); - { - int i; - for (i = 0; - i < - 1 + - bcd_to_int(single_toc.last_track_num) - - - bcd_to_int(single_toc. - first_track_num); i++) { - printk(KERN_INFO PFX "trk %02d: add 0x%01x, con 0x%01x, track %02d, start min %02d, sec %02d, frame %02d\n", - i, - single_toc.tracks[i].address, - single_toc.tracks[i].control, - bcd_to_int(single_toc. - tracks[i].track), - bcd_to_int(single_toc. - tracks[i]. - track_start_msf - [0]), - bcd_to_int(single_toc. - tracks[i]. - track_start_msf - [1]), - bcd_to_int(single_toc. - tracks[i]. - track_start_msf - [2])); - if (mint > - bcd_to_int(single_toc. - tracks[i].track)) - mint = - bcd_to_int(single_toc. - tracks[i]. - track); - if (maxt < - bcd_to_int(single_toc. - tracks[i].track)) - maxt = - bcd_to_int(single_toc. - tracks[i]. - track); - } - printk(KERN_INFO PFX "min track number %d, " - "max track number %d\n", - mint, maxt); - } -#endif - - /* prepare a special table of contents for a CD-I disc. They don't have one. */ - if (single_toc.disk_type == 0x10 && - single_toc.first_track_num == 2 && - single_toc.last_track_num == 2 /* CD-I */ ) { - sony_toc.tracks[totaltracks].address = 1; - sony_toc.tracks[totaltracks].control = 4; /* force data tracks */ - sony_toc.tracks[totaltracks].track = 1; - sony_toc.tracks[totaltracks]. - track_start_msf[0] = 0; - sony_toc.tracks[totaltracks]. - track_start_msf[1] = 2; - sony_toc.tracks[totaltracks]. - track_start_msf[2] = 0; - mint = maxt = 1; - totaltracks++; - } else - /* gather track entries from this session */ - { - int i; - for (i = 0; - i < - 1 + - bcd_to_int(single_toc.last_track_num) - - - bcd_to_int(single_toc. - first_track_num); - i++, totaltracks++) { - sony_toc.tracks[totaltracks]. - address = - single_toc.tracks[i].address; - sony_toc.tracks[totaltracks]. - control = - single_toc.tracks[i].control; - sony_toc.tracks[totaltracks]. - track = - bcd_to_int(single_toc. - tracks[i].track); - sony_toc.tracks[totaltracks]. - track_start_msf[0] = - bcd_to_int(single_toc. - tracks[i]. - track_start_msf[0]); - sony_toc.tracks[totaltracks]. - track_start_msf[1] = - bcd_to_int(single_toc. - tracks[i]. - track_start_msf[1]); - sony_toc.tracks[totaltracks]. - track_start_msf[2] = - bcd_to_int(single_toc. - tracks[i]. - track_start_msf[2]); - if (i == 0) - single_toc. - start_track_lba = - msf_to_log(sony_toc. - tracks - [totaltracks]. - track_start_msf); - if (mint > - sony_toc.tracks[totaltracks]. - track) - mint = - sony_toc. - tracks[totaltracks]. - track; - if (maxt < - sony_toc.tracks[totaltracks]. - track) - maxt = - sony_toc. - tracks[totaltracks]. - track; - } - } - sony_toc.first_track_num = mint; - sony_toc.last_track_num = maxt; - /* Disk type of last session wins. For example: - CD-Extra has disk type 0 for the first session, so - a dumb HiFi CD player thinks it is a plain audio CD. - We are interested in the disk type of the last session, - which is 0x20 (XA) for CD-Extra, so we can access the - data track ... */ - sony_toc.disk_type = single_toc.disk_type; - sony_toc.sessions = session; - - /* don't believe everything :-) */ - if (session == 1) - single_toc.start_track_lba = 0; - sony_toc.start_track_lba = - single_toc.start_track_lba; - - if (session > 1 && single_toc.pointb0 == 0xb0 && - sony_toc.lead_out_start_lba == - single_toc.lead_out_start_lba) { - break; - } - - /* Let's not get carried away... */ - if (session > 40) { - printk(KERN_NOTICE PFX "too many sessions: " - "%d\n", session); - break; - } - session++; - } - sony_toc.track_entries = totaltracks; - /* add one entry for the LAST track with track number CDROM_LEADOUT */ - sony_toc.tracks[totaltracks].address = single_toc.address2; - sony_toc.tracks[totaltracks].control = single_toc.control2; - sony_toc.tracks[totaltracks].track = CDROM_LEADOUT; - sony_toc.tracks[totaltracks].track_start_msf[0] = - sony_toc.lead_out_start_msf[0]; - sony_toc.tracks[totaltracks].track_start_msf[1] = - sony_toc.lead_out_start_msf[1]; - sony_toc.tracks[totaltracks].track_start_msf[2] = - sony_toc.lead_out_start_msf[2]; - - sony_toc_read = 1; - - pr_debug(PFX "Disk session %d, start track: %d, " - "stop track: %d\n", - session, single_toc.start_track_lba, - single_toc.lead_out_start_lba); - } - pr_debug(PFX "Leaving %s\n", __FUNCTION__); -} - - -/* - * Uniform cdrom interface function - * return multisession offset and sector information - */ -static int scd_get_last_session(struct cdrom_device_info *cdi, - struct cdrom_multisession *ms_info) -{ - if (ms_info == NULL) - return 1; - - if (!sony_toc_read) { - if (down_interruptible(&sony_sem)) - return -ERESTARTSYS; - sony_get_toc(); - up(&sony_sem); - } - - ms_info->addr_format = CDROM_LBA; - ms_info->addr.lba = sony_toc.start_track_lba; - ms_info->xa_flag = sony_toc.disk_type == SONY_XA_DISK_TYPE || - sony_toc.disk_type == 0x10 /* CDI */ ; - - return 0; -} - -/* - * Search for a specific track in the table of contents. - */ -static int find_track(int track) -{ - int i; - - for (i = 0; i <= sony_toc.track_entries; i++) { - if (sony_toc.tracks[i].track == track) { - return i; - } - } - - return -1; -} - - -/* - * Read the subcode and put it in last_sony_subcode for future use. - */ -static int read_subcode(void) -{ - unsigned int res_size; - - - do_sony_cd_cmd(SONY_REQ_SUBCODE_ADDRESS_CMD, - NULL, - 0, (unsigned char *) &last_sony_subcode, &res_size); - if ((res_size < 2) - || ((last_sony_subcode.exec_status[0] & 0xf0) == 0x20)) { - printk(KERN_ERR PFX "Sony CDROM error %s (read_subcode)\n", - translate_error(last_sony_subcode.exec_status[1])); - return -EIO; - } - - last_sony_subcode.track_num = - bcd_to_int(last_sony_subcode.track_num); - last_sony_subcode.index_num = - bcd_to_int(last_sony_subcode.index_num); - last_sony_subcode.abs_msf[0] = - bcd_to_int(last_sony_subcode.abs_msf[0]); - last_sony_subcode.abs_msf[1] = - bcd_to_int(last_sony_subcode.abs_msf[1]); - last_sony_subcode.abs_msf[2] = - bcd_to_int(last_sony_subcode.abs_msf[2]); - - last_sony_subcode.rel_msf[0] = - bcd_to_int(last_sony_subcode.rel_msf[0]); - last_sony_subcode.rel_msf[1] = - bcd_to_int(last_sony_subcode.rel_msf[1]); - last_sony_subcode.rel_msf[2] = - bcd_to_int(last_sony_subcode.rel_msf[2]); - return 0; -} - -/* - * Uniform cdrom interface function - * return the media catalog number found on some older audio cds - */ -static int -scd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) -{ - unsigned char resbuffer[2 + 14]; - unsigned char *mcnp = mcn->medium_catalog_number; - unsigned char *resp = resbuffer + 3; - unsigned int res_size; - - memset(mcn->medium_catalog_number, 0, 14); - if (down_interruptible(&sony_sem)) - return -ERESTARTSYS; - do_sony_cd_cmd(SONY_REQ_UPC_EAN_CMD, - NULL, 0, resbuffer, &res_size); - up(&sony_sem); - if ((res_size < 2) || ((resbuffer[0] & 0xf0) == 0x20)); - else { - /* packed bcd to single ASCII digits */ - *mcnp++ = (*resp >> 4) + '0'; - *mcnp++ = (*resp++ & 0x0f) + '0'; - *mcnp++ = (*resp >> 4) + '0'; - *mcnp++ = (*resp++ & 0x0f) + '0'; - *mcnp++ = (*resp >> 4) + '0'; - *mcnp++ = (*resp++ & 0x0f) + '0'; - *mcnp++ = (*resp >> 4) + '0'; - *mcnp++ = (*resp++ & 0x0f) + '0'; - *mcnp++ = (*resp >> 4) + '0'; - *mcnp++ = (*resp++ & 0x0f) + '0'; - *mcnp++ = (*resp >> 4) + '0'; - *mcnp++ = (*resp++ & 0x0f) + '0'; - *mcnp++ = (*resp >> 4) + '0'; - } - *mcnp = '\0'; - return 0; -} - - -/* - * Get the subchannel info like the CDROMSUBCHNL command wants to see it. If - * the drive is playing, the subchannel needs to be read (since it would be - * changing). If the drive is paused or completed, the subcode information has - * already been stored, just use that. The ioctl call wants things in decimal - * (not BCD), so all the conversions are done. - */ -static int sony_get_subchnl_info(struct cdrom_subchnl *schi) -{ - /* Get attention stuff */ - while (handle_sony_cd_attention()); - - sony_get_toc(); - if (!sony_toc_read) { - return -EIO; - } - - switch (sony_audio_status) { - case CDROM_AUDIO_NO_STATUS: - case CDROM_AUDIO_PLAY: - if (read_subcode() < 0) { - return -EIO; - } - break; - - case CDROM_AUDIO_PAUSED: - case CDROM_AUDIO_COMPLETED: - break; - -#if 0 - case CDROM_AUDIO_NO_STATUS: - schi->cdsc_audiostatus = sony_audio_status; - return 0; - break; -#endif - case CDROM_AUDIO_INVALID: - case CDROM_AUDIO_ERROR: - default: - return -EIO; - } - - schi->cdsc_audiostatus = sony_audio_status; - schi->cdsc_adr = last_sony_subcode.address; - schi->cdsc_ctrl = last_sony_subcode.control; - schi->cdsc_trk = last_sony_subcode.track_num; - schi->cdsc_ind = last_sony_subcode.index_num; - if (schi->cdsc_format == CDROM_MSF) { - schi->cdsc_absaddr.msf.minute = - last_sony_subcode.abs_msf[0]; - schi->cdsc_absaddr.msf.second = - last_sony_subcode.abs_msf[1]; - schi->cdsc_absaddr.msf.frame = - last_sony_subcode.abs_msf[2]; - - schi->cdsc_reladdr.msf.minute = - last_sony_subcode.rel_msf[0]; - schi->cdsc_reladdr.msf.second = - last_sony_subcode.rel_msf[1]; - schi->cdsc_reladdr.msf.frame = - last_sony_subcode.rel_msf[2]; - } else if (schi->cdsc_format == CDROM_LBA) { - schi->cdsc_absaddr.lba = - msf_to_log(last_sony_subcode.abs_msf); - schi->cdsc_reladdr.lba = - msf_to_log(last_sony_subcode.rel_msf); - } - - return 0; -} - -/* Get audio data from the drive. This is fairly complex because I - am looking for status and data at the same time, but if I get status - then I just look for data. I need to get the status immediately so - the switch from audio to data tracks will happen quickly. */ -static void -read_audio_data(char *buffer, unsigned char res_reg[], int *res_size) -{ - unsigned long retry_count; - int result_read; - - - res_reg[0] = 0; - res_reg[1] = 0; - *res_size = 0; - result_read = 0; - - /* Wait for the drive to tell us we have something */ - retry_count = jiffies + SONY_JIFFIES_TIMEOUT; - continue_read_audio_wait: - while (time_before(jiffies, retry_count) && !(is_data_ready()) - && !(is_result_ready() || result_read)) { - while (handle_sony_cd_attention()); - - sony_sleep(); - } - if (!(is_data_ready())) { - if (is_result_ready() && !result_read) { - get_result(res_reg, res_size); - - /* Read block status and continue waiting for data. */ - if ((res_reg[0] & 0xf0) == 0x50) { - result_read = 1; - goto continue_read_audio_wait; - } - /* Invalid data from the drive. Shut down the operation. */ - else if ((res_reg[0] & 0xf0) != 0x20) { - printk(KERN_WARNING PFX "Got result that " - "should have been error: %d\n", - res_reg[0]); - res_reg[0] = 0x20; - res_reg[1] = SONY_BAD_DATA_ERR; - *res_size = 2; - } - abort_read(); - } else { - pr_debug(PFX "timeout out %d\n", __LINE__); - res_reg[0] = 0x20; - res_reg[1] = SONY_TIMEOUT_OP_ERR; - *res_size = 2; - abort_read(); - } - } else { - clear_data_ready(); - - /* If data block, then get 2340 bytes offset by 12. */ - if (sony_raw_data_mode) { - insb(sony_cd_read_reg, buffer + CD_XA_HEAD, - CD_FRAMESIZE_RAW1); - } else { - /* Audio gets the whole 2352 bytes. */ - insb(sony_cd_read_reg, buffer, CD_FRAMESIZE_RAW); - } - - /* If I haven't already gotten the result, get it now. */ - if (!result_read) { - /* Wait for the drive to tell us we have something */ - retry_count = jiffies + SONY_JIFFIES_TIMEOUT; - while (time_before(jiffies, retry_count) - && !(is_result_ready())) { - while (handle_sony_cd_attention()); - - sony_sleep(); - } - - if (!is_result_ready()) { - pr_debug(PFX "timeout out %d\n", __LINE__); - res_reg[0] = 0x20; - res_reg[1] = SONY_TIMEOUT_OP_ERR; - *res_size = 2; - abort_read(); - return; - } else { - get_result(res_reg, res_size); - } - } - - if ((res_reg[0] & 0xf0) == 0x50) { - if ((res_reg[0] == SONY_NO_CIRC_ERR_BLK_STAT) - || (res_reg[0] == SONY_NO_LECC_ERR_BLK_STAT) - || (res_reg[0] == SONY_RECOV_LECC_ERR_BLK_STAT) - || (res_reg[0] == SONY_NO_ERR_DETECTION_STAT)) { - /* Ok, nothing to do. */ - } else { - printk(KERN_ERR PFX "Data block error: 0x%x\n", - res_reg[0]); - res_reg[0] = 0x20; - res_reg[1] = SONY_BAD_DATA_ERR; - *res_size = 2; - } - } else if ((res_reg[0] & 0xf0) != 0x20) { - /* The drive gave me bad status, I don't know what to do. - Reset the driver and return an error. */ - printk(KERN_NOTICE PFX "Invalid block status: 0x%x\n", - res_reg[0]); - restart_on_error(); - res_reg[0] = 0x20; - res_reg[1] = SONY_BAD_DATA_ERR; - *res_size = 2; - } - } -} - -/* Perform a raw data read. This will automatically detect the - track type and read the proper data (audio or data). */ -static int read_audio(struct cdrom_read_audio *ra) -{ - int retval; - unsigned char params[2]; - unsigned char res_reg[12]; - unsigned int res_size; - unsigned int cframe; - - if (down_interruptible(&sony_sem)) - return -ERESTARTSYS; - if (!sony_spun_up) - scd_spinup(); - - /* Set the drive to do raw operations. */ - params[0] = SONY_SD_DECODE_PARAM; - params[1] = 0x06 | sony_raw_data_mode; - do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, - params, 2, res_reg, &res_size); - if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) { - printk(KERN_ERR PFX "Unable to set decode params: 0x%2.2x\n", - res_reg[1]); - retval = -EIO; - goto out_up; - } - - /* From here down, we have to goto exit_read_audio instead of returning - because the drive parameters have to be set back to data before - return. */ - - retval = 0; - if (start_request(ra->addr.lba, ra->nframes)) { - retval = -EIO; - goto exit_read_audio; - } - - /* For every requested frame. */ - cframe = 0; - while (cframe < ra->nframes) { - read_audio_data(audio_buffer, res_reg, &res_size); - if ((res_reg[0] & 0xf0) == 0x20) { - if (res_reg[1] == SONY_BAD_DATA_ERR) { - printk(KERN_ERR PFX "Data error on audio " - "sector %d\n", - ra->addr.lba + cframe); - } else if (res_reg[1] == SONY_ILL_TRACK_R_ERR) { - /* Illegal track type, change track types and start over. */ - sony_raw_data_mode = - (sony_raw_data_mode) ? 0 : 1; - - /* Set the drive mode. */ - params[0] = SONY_SD_DECODE_PARAM; - params[1] = 0x06 | sony_raw_data_mode; - do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, - params, - 2, res_reg, &res_size); - if ((res_size < 2) - || ((res_reg[0] & 0xf0) == 0x20)) { - printk(KERN_ERR PFX "Unable to set " - "decode params: 0x%2.2x\n", - res_reg[1]); - retval = -EIO; - goto exit_read_audio; - } - - /* Restart the request on the current frame. */ - if (start_request - (ra->addr.lba + cframe, - ra->nframes - cframe)) { - retval = -EIO; - goto exit_read_audio; - } - - /* Don't go back to the top because don't want to get into - and infinite loop. A lot of code gets duplicated, but - that's no big deal, I don't guess. */ - read_audio_data(audio_buffer, res_reg, - &res_size); - if ((res_reg[0] & 0xf0) == 0x20) { - if (res_reg[1] == - SONY_BAD_DATA_ERR) { - printk(KERN_ERR PFX "Data error" - " on audio sector %d\n", - ra->addr.lba + - cframe); - } else { - printk(KERN_ERR PFX "Error reading audio data on sector %d: %s\n", - ra->addr.lba + cframe, - translate_error - (res_reg[1])); - retval = -EIO; - goto exit_read_audio; - } - } else if (copy_to_user(ra->buf + - (CD_FRAMESIZE_RAW - * cframe), - audio_buffer, - CD_FRAMESIZE_RAW)) { - retval = -EFAULT; - goto exit_read_audio; - } - } else { - printk(KERN_ERR PFX "Error reading audio " - "data on sector %d: %s\n", - ra->addr.lba + cframe, - translate_error(res_reg[1])); - retval = -EIO; - goto exit_read_audio; - } - } else if (copy_to_user(ra->buf + (CD_FRAMESIZE_RAW * cframe), - (char *)audio_buffer, - CD_FRAMESIZE_RAW)) { - retval = -EFAULT; - goto exit_read_audio; - } - - cframe++; - } - - get_result(res_reg, &res_size); - if ((res_reg[0] & 0xf0) == 0x20) { - printk(KERN_ERR PFX "Error return from audio read: %s\n", - translate_error(res_reg[1])); - retval = -EIO; - goto exit_read_audio; - } - - exit_read_audio: - - /* Set the drive mode back to the proper one for the disk. */ - params[0] = SONY_SD_DECODE_PARAM; - if (!sony_xa_mode) { - params[1] = 0x0f; - } else { - params[1] = 0x07; - } - do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, - params, 2, res_reg, &res_size); - if ((res_size < 2) || ((res_reg[0] & 0xf0) == 0x20)) { - printk(KERN_ERR PFX "Unable to reset decode params: 0x%2.2x\n", - res_reg[1]); - retval = -EIO; - } - - out_up: - up(&sony_sem); - - return retval; -} - -static int -do_sony_cd_cmd_chk(const char *name, - unsigned char cmd, - unsigned char *params, - unsigned int num_params, - unsigned char *result_buffer, unsigned int *result_size) -{ - do_sony_cd_cmd(cmd, params, num_params, result_buffer, - result_size); - if ((*result_size < 2) || ((result_buffer[0] & 0xf0) == 0x20)) { - printk(KERN_ERR PFX "Error %s (CDROM%s)\n", - translate_error(result_buffer[1]), name); - return -EIO; - } - return 0; -} - -/* - * Uniform cdrom interface function - * open the tray - */ -static int scd_tray_move(struct cdrom_device_info *cdi, int position) -{ - int retval; - - if (down_interruptible(&sony_sem)) - return -ERESTARTSYS; - if (position == 1 /* open tray */ ) { - unsigned char res_reg[12]; - unsigned int res_size; - - do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, - &res_size); - do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, - &res_size); - - sony_audio_status = CDROM_AUDIO_INVALID; - retval = do_sony_cd_cmd_chk("EJECT", SONY_EJECT_CMD, NULL, 0, - res_reg, &res_size); - } else { - if (0 == scd_spinup()) - sony_spun_up = 1; - retval = 0; - } - up(&sony_sem); - return retval; -} - -/* - * The big ugly ioctl handler. - */ -static int scd_audio_ioctl(struct cdrom_device_info *cdi, - unsigned int cmd, void *arg) -{ - unsigned char res_reg[12]; - unsigned int res_size; - unsigned char params[7]; - int i, retval; - - if (down_interruptible(&sony_sem)) - return -ERESTARTSYS; - switch (cmd) { - case CDROMSTART: /* Spin up the drive */ - retval = do_sony_cd_cmd_chk("START", SONY_SPIN_UP_CMD, NULL, - 0, res_reg, &res_size); - break; - - case CDROMSTOP: /* Spin down the drive */ - do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, - &res_size); - - /* - * Spin the drive down, ignoring the error if the disk was - * already not spinning. - */ - sony_audio_status = CDROM_AUDIO_NO_STATUS; - retval = do_sony_cd_cmd_chk("STOP", SONY_SPIN_DOWN_CMD, NULL, - 0, res_reg, &res_size); - break; - - case CDROMPAUSE: /* Pause the drive */ - if (do_sony_cd_cmd_chk - ("PAUSE", SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, - &res_size)) { - retval = -EIO; - break; - } - /* Get the current position and save it for resuming */ - if (read_subcode() < 0) { - retval = -EIO; - break; - } - cur_pos_msf[0] = last_sony_subcode.abs_msf[0]; - cur_pos_msf[1] = last_sony_subcode.abs_msf[1]; - cur_pos_msf[2] = last_sony_subcode.abs_msf[2]; - sony_audio_status = CDROM_AUDIO_PAUSED; - retval = 0; - break; - - case CDROMRESUME: /* Start the drive after being paused */ - if (sony_audio_status != CDROM_AUDIO_PAUSED) { - retval = -EINVAL; - break; - } - - do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, - &res_size); - - /* Start the drive at the saved position. */ - params[1] = int_to_bcd(cur_pos_msf[0]); - params[2] = int_to_bcd(cur_pos_msf[1]); - params[3] = int_to_bcd(cur_pos_msf[2]); - params[4] = int_to_bcd(final_pos_msf[0]); - params[5] = int_to_bcd(final_pos_msf[1]); - params[6] = int_to_bcd(final_pos_msf[2]); - params[0] = 0x03; - if (do_sony_cd_cmd_chk - ("RESUME", SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, - &res_size) < 0) { - retval = -EIO; - break; - } - sony_audio_status = CDROM_AUDIO_PLAY; - retval = 0; - break; - - case CDROMPLAYMSF: /* Play starting at the given MSF address. */ - do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, - &res_size); - - /* The parameters are given in int, must be converted */ - for (i = 1; i < 7; i++) { - params[i] = - int_to_bcd(((unsigned char *) arg)[i - 1]); - } - params[0] = 0x03; - if (do_sony_cd_cmd_chk - ("PLAYMSF", SONY_AUDIO_PLAYBACK_CMD, params, 7, - res_reg, &res_size) < 0) { - retval = -EIO; - break; - } - - /* Save the final position for pauses and resumes */ - final_pos_msf[0] = bcd_to_int(params[4]); - final_pos_msf[1] = bcd_to_int(params[5]); - final_pos_msf[2] = bcd_to_int(params[6]); - sony_audio_status = CDROM_AUDIO_PLAY; - retval = 0; - break; - - case CDROMREADTOCHDR: /* Read the table of contents header */ - { - struct cdrom_tochdr *hdr; - - sony_get_toc(); - if (!sony_toc_read) { - retval = -EIO; - break; - } - - hdr = (struct cdrom_tochdr *) arg; - hdr->cdth_trk0 = sony_toc.first_track_num; - hdr->cdth_trk1 = sony_toc.last_track_num; - } - retval = 0; - break; - - case CDROMREADTOCENTRY: /* Read a given table of contents entry */ - { - struct cdrom_tocentry *entry; - int track_idx; - unsigned char *msf_val = NULL; - - sony_get_toc(); - if (!sony_toc_read) { - retval = -EIO; - break; - } - - entry = (struct cdrom_tocentry *) arg; - - track_idx = find_track(entry->cdte_track); - if (track_idx < 0) { - retval = -EINVAL; - break; - } - - entry->cdte_adr = - sony_toc.tracks[track_idx].address; - entry->cdte_ctrl = - sony_toc.tracks[track_idx].control; - msf_val = - sony_toc.tracks[track_idx].track_start_msf; - - /* Logical buffer address or MSF format requested? */ - if (entry->cdte_format == CDROM_LBA) { - entry->cdte_addr.lba = msf_to_log(msf_val); - } else if (entry->cdte_format == CDROM_MSF) { - entry->cdte_addr.msf.minute = *msf_val; - entry->cdte_addr.msf.second = - *(msf_val + 1); - entry->cdte_addr.msf.frame = - *(msf_val + 2); - } - } - retval = 0; - break; - - case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ - { - struct cdrom_ti *ti = (struct cdrom_ti *) arg; - int track_idx; - - sony_get_toc(); - if (!sony_toc_read) { - retval = -EIO; - break; - } - - if ((ti->cdti_trk0 < sony_toc.first_track_num) - || (ti->cdti_trk0 > sony_toc.last_track_num) - || (ti->cdti_trk1 < ti->cdti_trk0)) { - retval = -EINVAL; - break; - } - - track_idx = find_track(ti->cdti_trk0); - if (track_idx < 0) { - retval = -EINVAL; - break; - } - params[1] = - int_to_bcd(sony_toc.tracks[track_idx]. - track_start_msf[0]); - params[2] = - int_to_bcd(sony_toc.tracks[track_idx]. - track_start_msf[1]); - params[3] = - int_to_bcd(sony_toc.tracks[track_idx]. - track_start_msf[2]); - - /* - * If we want to stop after the last track, use the lead-out - * MSF to do that. - */ - if (ti->cdti_trk1 >= sony_toc.last_track_num) { - track_idx = find_track(CDROM_LEADOUT); - } else { - track_idx = find_track(ti->cdti_trk1 + 1); - } - if (track_idx < 0) { - retval = -EINVAL; - break; - } - params[4] = - int_to_bcd(sony_toc.tracks[track_idx]. - track_start_msf[0]); - params[5] = - int_to_bcd(sony_toc.tracks[track_idx]. - track_start_msf[1]); - params[6] = - int_to_bcd(sony_toc.tracks[track_idx]. - track_start_msf[2]); - params[0] = 0x03; - - do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, - &res_size); - - do_sony_cd_cmd(SONY_AUDIO_PLAYBACK_CMD, params, 7, - res_reg, &res_size); - - if ((res_size < 2) - || ((res_reg[0] & 0xf0) == 0x20)) { - printk(KERN_ERR PFX - "Params: %x %x %x %x %x %x %x\n", - params[0], params[1], params[2], - params[3], params[4], params[5], - params[6]); - printk(KERN_ERR PFX - "Error %s (CDROMPLAYTRKIND)\n", - translate_error(res_reg[1])); - retval = -EIO; - break; - } - - /* Save the final position for pauses and resumes */ - final_pos_msf[0] = bcd_to_int(params[4]); - final_pos_msf[1] = bcd_to_int(params[5]); - final_pos_msf[2] = bcd_to_int(params[6]); - sony_audio_status = CDROM_AUDIO_PLAY; - retval = 0; - break; - } - - case CDROMVOLCTRL: /* Volume control. What volume does this change, anyway? */ - { - struct cdrom_volctrl *volctrl = - (struct cdrom_volctrl *) arg; - - params[0] = SONY_SD_AUDIO_VOLUME; - params[1] = volctrl->channel0; - params[2] = volctrl->channel1; - retval = do_sony_cd_cmd_chk("VOLCTRL", - SONY_SET_DRIVE_PARAM_CMD, - params, 3, res_reg, - &res_size); - break; - } - case CDROMSUBCHNL: /* Get subchannel info */ - retval = sony_get_subchnl_info((struct cdrom_subchnl *) arg); - break; - - default: - retval = -EINVAL; - break; - } - up(&sony_sem); - return retval; -} - -static int scd_read_audio(struct cdrom_device_info *cdi, - unsigned int cmd, unsigned long arg) -{ - void __user *argp = (void __user *)arg; - int retval; - - if (down_interruptible(&sony_sem)) - return -ERESTARTSYS; - switch (cmd) { - case CDROMREADAUDIO: /* Read 2352 byte audio tracks and 2340 byte - raw data tracks. */ - { - struct cdrom_read_audio ra; - - - sony_get_toc(); - if (!sony_toc_read) { - retval = -EIO; - break; - } - - if (copy_from_user(&ra, argp, sizeof(ra))) { - retval = -EFAULT; - break; - } - - if (ra.nframes == 0) { - retval = 0; - break; - } - - if (!access_ok(VERIFY_WRITE, ra.buf, - CD_FRAMESIZE_RAW * ra.nframes)) - return -EFAULT; - - if (ra.addr_format == CDROM_LBA) { - if ((ra.addr.lba >= - sony_toc.lead_out_start_lba) - || (ra.addr.lba + ra.nframes >= - sony_toc.lead_out_start_lba)) { - retval = -EINVAL; - break; - } - } else if (ra.addr_format == CDROM_MSF) { - if ((ra.addr.msf.minute >= 75) - || (ra.addr.msf.second >= 60) - || (ra.addr.msf.frame >= 75)) { - retval = -EINVAL; - break; - } - - ra.addr.lba = ((ra.addr.msf.minute * 4500) - + (ra.addr.msf.second * 75) - + ra.addr.msf.frame); - if ((ra.addr.lba >= - sony_toc.lead_out_start_lba) - || (ra.addr.lba + ra.nframes >= - sony_toc.lead_out_start_lba)) { - retval = -EINVAL; - break; - } - - /* I know, this can go negative on an unsigned. However, - the first thing done to the data is to add this value, - so this should compensate and allow direct msf access. */ - ra.addr.lba -= LOG_START_OFFSET; - } else { - retval = -EINVAL; - break; - } - - retval = read_audio(&ra); - break; - } - retval = 0; - break; - - default: - retval = -EINVAL; - } - up(&sony_sem); - return retval; -} - -static int scd_spinup(void) -{ - unsigned char res_reg[12]; - unsigned int res_size; - int num_spin_ups; - - num_spin_ups = 0; - - respinup_on_open: - do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size); - - /* The drive sometimes returns error 0. I don't know why, but ignore - it. It seems to mean the drive has already done the operation. */ - if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0))) { - printk(KERN_ERR PFX "%s error (scd_open, spin up)\n", - translate_error(res_reg[1])); - return 1; - } - - do_sony_cd_cmd(SONY_READ_TOC_CMD, NULL, 0, res_reg, &res_size); - - /* The drive sometimes returns error 0. I don't know why, but ignore - it. It seems to mean the drive has already done the operation. */ - if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0))) { - /* If the drive is already playing, it's ok. */ - if ((res_reg[1] == SONY_AUDIO_PLAYING_ERR) - || (res_reg[1] == 0)) { - return 0; - } - - /* If the drive says it is not spun up (even though we just did it!) - then retry the operation at least a few times. */ - if ((res_reg[1] == SONY_NOT_SPIN_ERR) - && (num_spin_ups < MAX_CDU31A_RETRIES)) { - num_spin_ups++; - goto respinup_on_open; - } - - printk(KERN_ERR PFX "Error %s (scd_open, read toc)\n", - translate_error(res_reg[1])); - do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, - &res_size); - return 1; - } - return 0; -} - -/* - * Open the drive for operations. Spin the drive up and read the table of - * contents if these have not already been done. - */ -static int scd_open(struct cdrom_device_info *cdi, int purpose) -{ - unsigned char res_reg[12]; - unsigned int res_size; - unsigned char params[2]; - - if (purpose == 1) { - /* Open for IOCTLs only - no media check */ - sony_usage++; - return 0; - } - - if (sony_usage == 0) { - if (scd_spinup() != 0) - return -EIO; - sony_get_toc(); - if (!sony_toc_read) { - do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, - res_reg, &res_size); - return -EIO; - } - - /* For XA on the CDU31A only, we have to do special reads. - The CDU33A handles XA automagically. */ - /* if ( (sony_toc.disk_type == SONY_XA_DISK_TYPE) */ - if ((sony_toc.disk_type != 0x00) - && (!is_double_speed)) { - params[0] = SONY_SD_DECODE_PARAM; - params[1] = 0x07; - do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, - params, 2, res_reg, &res_size); - if ((res_size < 2) - || ((res_reg[0] & 0xf0) == 0x20)) { - printk(KERN_WARNING PFX "Unable to set " - "XA params: 0x%2.2x\n", res_reg[1]); - } - sony_xa_mode = 1; - } - /* A non-XA disk. Set the parms back if necessary. */ - else if (sony_xa_mode) { - params[0] = SONY_SD_DECODE_PARAM; - params[1] = 0x0f; - do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, - params, 2, res_reg, &res_size); - if ((res_size < 2) - || ((res_reg[0] & 0xf0) == 0x20)) { - printk(KERN_WARNING PFX "Unable to reset " - "XA params: 0x%2.2x\n", res_reg[1]); - } - sony_xa_mode = 0; - } - - sony_spun_up = 1; - } - - sony_usage++; - - return 0; -} - - -/* - * Close the drive. Spin it down if no task is using it. The spin - * down will fail if playing audio, so audio play is OK. - */ -static void scd_release(struct cdrom_device_info *cdi) -{ - if (sony_usage == 1) { - unsigned char res_reg[12]; - unsigned int res_size; - - do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, - &res_size); - - sony_spun_up = 0; - } - sony_usage--; -} - -static struct cdrom_device_ops scd_dops = { - .open = scd_open, - .release = scd_release, - .drive_status = scd_drive_status, - .media_changed = scd_media_changed, - .tray_move = scd_tray_move, - .lock_door = scd_lock_door, - .select_speed = scd_select_speed, - .get_last_session = scd_get_last_session, - .get_mcn = scd_get_mcn, - .reset = scd_reset, - .audio_ioctl = scd_audio_ioctl, - .capability = CDC_OPEN_TRAY | CDC_CLOSE_TRAY | CDC_LOCK | - CDC_SELECT_SPEED | CDC_MULTI_SESSION | - CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | - CDC_RESET | CDC_DRIVE_STATUS, - .n_minors = 1, -}; - -static struct cdrom_device_info scd_info = { - .ops = &scd_dops, - .speed = 2, - .capacity = 1, - .name = "cdu31a" -}; - -static int scd_block_open(struct inode *inode, struct file *file) -{ - return cdrom_open(&scd_info, inode, file); -} - -static int scd_block_release(struct inode *inode, struct file *file) -{ - return cdrom_release(&scd_info, file); -} - -static int scd_block_ioctl(struct inode *inode, struct file *file, - unsigned cmd, unsigned long arg) -{ - int retval; - - /* The eject and close commands should be handled by Uniform CD-ROM - * driver - but I always got hard lockup instead of eject - * until I put this here. - */ - switch (cmd) { - case CDROMEJECT: - scd_lock_door(&scd_info, 0); - retval = scd_tray_move(&scd_info, 1); - break; - case CDROMCLOSETRAY: - retval = scd_tray_move(&scd_info, 0); - break; - case CDROMREADAUDIO: - retval = scd_read_audio(&scd_info, CDROMREADAUDIO, arg); - break; - default: - retval = cdrom_ioctl(file, &scd_info, inode, cmd, arg); - } - return retval; -} - -static int scd_block_media_changed(struct gendisk *disk) -{ - return cdrom_media_changed(&scd_info); -} - -static struct block_device_operations scd_bdops = -{ - .owner = THIS_MODULE, - .open = scd_block_open, - .release = scd_block_release, - .ioctl = scd_block_ioctl, - .media_changed = scd_block_media_changed, -}; - -static struct gendisk *scd_gendisk; - -/* The different types of disc loading mechanisms supported */ -static char *load_mech[] __initdata = - { "caddy", "tray", "pop-up", "unknown" }; - -static int __init -get_drive_configuration(unsigned short base_io, - unsigned char res_reg[], unsigned int *res_size) -{ - unsigned long retry_count; - - - if (!request_region(base_io, 4, "cdu31a")) - return 0; - - /* Set the base address */ - cdu31a_port = base_io; - - /* Set up all the register locations */ - sony_cd_cmd_reg = cdu31a_port + SONY_CMD_REG_OFFSET; - sony_cd_param_reg = cdu31a_port + SONY_PARAM_REG_OFFSET; - sony_cd_write_reg = cdu31a_port + SONY_WRITE_REG_OFFSET; - sony_cd_control_reg = cdu31a_port + SONY_CONTROL_REG_OFFSET; - sony_cd_status_reg = cdu31a_port + SONY_STATUS_REG_OFFSET; - sony_cd_result_reg = cdu31a_port + SONY_RESULT_REG_OFFSET; - sony_cd_read_reg = cdu31a_port + SONY_READ_REG_OFFSET; - sony_cd_fifost_reg = cdu31a_port + SONY_FIFOST_REG_OFFSET; - - /* - * Check to see if anything exists at the status register location. - * I don't know if this is a good way to check, but it seems to work - * ok for me. - */ - if (read_status_register() != 0xff) { - /* - * Reset the drive and wait for attention from it (to say it's reset). - * If you don't wait, the next operation will probably fail. - */ - reset_drive(); - retry_count = jiffies + SONY_RESET_TIMEOUT; - while (time_before(jiffies, retry_count) - && (!is_attention())) { - sony_sleep(); - } - -#if 0 - /* If attention is never seen probably not a CDU31a present */ - if (!is_attention()) { - res_reg[0] = 0x20; - goto out_err; - } -#endif - - /* - * Get the drive configuration. - */ - do_sony_cd_cmd(SONY_REQ_DRIVE_CONFIG_CMD, - NULL, - 0, (unsigned char *) res_reg, res_size); - if (*res_size <= 2 || (res_reg[0] & 0xf0) != 0) - goto out_err; - return 1; - } - - /* Return an error */ - res_reg[0] = 0x20; -out_err: - release_region(cdu31a_port, 4); - cdu31a_port = 0; - return 0; -} - -#ifndef MODULE -/* - * Set up base I/O and interrupts, called from main.c. - */ - -static int __init cdu31a_setup(char *strings) -{ - int ints[4]; - - (void) get_options(strings, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) { - cdu31a_port = ints[1]; - } - if (ints[0] > 1) { - cdu31a_irq = ints[2]; - } - if ((strings != NULL) && (*strings != '\0')) { - if (strcmp(strings, "PAS") == 0) { - sony_pas_init = 1; - } else { - printk(KERN_NOTICE PFX "Unknown interface type: %s\n", - strings); - } - } - - return 1; -} - -__setup("cdu31a=", cdu31a_setup); - -#endif - -/* - * Initialize the driver. - */ -int __init cdu31a_init(void) -{ - struct s_sony_drive_config drive_config; - struct gendisk *disk; - int deficiency = 0; - unsigned int res_size; - char msg[255]; - char buf[40]; - int i; - int tmp_irq; - - /* - * According to Alex Freed (freed@europa.orion.adobe.com), this is - * required for the Fusion CD-16 package. If the sound driver is - * loaded, it should work fine, but just in case... - * - * The following turn on the CD-ROM interface for a Fusion CD-16. - */ - if (sony_pas_init) { - outb(0xbc, 0x9a01); - outb(0xe2, 0x9a01); - } - - /* Setting the base I/O address to 0xffff will disable it. */ - if (cdu31a_port == 0xffff) - goto errout3; - - if (cdu31a_port != 0) { - /* Need IRQ 0 because we can't sleep here. */ - tmp_irq = cdu31a_irq; - cdu31a_irq = 0; - if (!get_drive_configuration(cdu31a_port, - drive_config.exec_status, - &res_size)) - goto errout3; - cdu31a_irq = tmp_irq; - } else { - cdu31a_irq = 0; - for (i = 0; cdu31a_addresses[i].base; i++) { - if (get_drive_configuration(cdu31a_addresses[i].base, - drive_config.exec_status, - &res_size)) { - cdu31a_irq = cdu31a_addresses[i].int_num; - break; - } - } - if (!cdu31a_port) - goto errout3; - } - - if (register_blkdev(MAJOR_NR, "cdu31a")) - goto errout2; - - disk = alloc_disk(1); - if (!disk) - goto errout1; - disk->major = MAJOR_NR; - disk->first_minor = 0; - sprintf(disk->disk_name, "cdu31a"); - disk->fops = &scd_bdops; - disk->flags = GENHD_FL_CD; - - if (SONY_HWC_DOUBLE_SPEED(drive_config)) - is_double_speed = 1; - - tmp_irq = cdu31a_irq; /* Need IRQ 0 because we can't sleep here. */ - cdu31a_irq = 0; - - sony_speed = is_double_speed; /* Set 2X drives to 2X by default */ - set_drive_params(sony_speed); - - cdu31a_irq = tmp_irq; - - if (cdu31a_irq > 0) { - if (request_irq - (cdu31a_irq, cdu31a_interrupt, IRQF_DISABLED, - "cdu31a", NULL)) { - printk(KERN_WARNING PFX "Unable to grab IRQ%d for " - "the CDU31A driver\n", cdu31a_irq); - cdu31a_irq = 0; - } - } - - sprintf(msg, "Sony I/F CDROM : %8.8s %16.16s %8.8s\n", - drive_config.vendor_id, - drive_config.product_id, - drive_config.product_rev_level); - sprintf(buf, " Capabilities: %s", - load_mech[SONY_HWC_GET_LOAD_MECH(drive_config)]); - strcat(msg, buf); - if (SONY_HWC_AUDIO_PLAYBACK(drive_config)) - strcat(msg, ", audio"); - else - deficiency |= CDC_PLAY_AUDIO; - if (SONY_HWC_EJECT(drive_config)) - strcat(msg, ", eject"); - else - deficiency |= CDC_OPEN_TRAY; - if (SONY_HWC_LED_SUPPORT(drive_config)) - strcat(msg, ", LED"); - if (SONY_HWC_ELECTRIC_VOLUME(drive_config)) - strcat(msg, ", elec. Vol"); - if (SONY_HWC_ELECTRIC_VOLUME_CTL(drive_config)) - strcat(msg, ", sep. Vol"); - if (is_double_speed) - strcat(msg, ", double speed"); - else - deficiency |= CDC_SELECT_SPEED; - if (cdu31a_irq > 0) { - sprintf(buf, ", irq %d", cdu31a_irq); - strcat(msg, buf); - } - strcat(msg, "\n"); - printk(KERN_INFO PFX "%s",msg); - - cdu31a_queue = blk_init_queue(do_cdu31a_request, &cdu31a_lock); - if (!cdu31a_queue) - goto errout0; - blk_queue_hardsect_size(cdu31a_queue, 2048); - - init_timer(&cdu31a_abort_timer); - cdu31a_abort_timer.function = handle_abort_timeout; - - scd_info.mask = deficiency; - scd_gendisk = disk; - if (register_cdrom(&scd_info)) - goto err; - disk->queue = cdu31a_queue; - add_disk(disk); - - disk_changed = 1; - return 0; - -err: - blk_cleanup_queue(cdu31a_queue); -errout0: - if (cdu31a_irq) - free_irq(cdu31a_irq, NULL); - printk(KERN_ERR PFX "Unable to register with Uniform cdrom driver\n"); - put_disk(disk); -errout1: - if (unregister_blkdev(MAJOR_NR, "cdu31a")) { - printk(KERN_WARNING PFX "Can't unregister block device\n"); - } -errout2: - release_region(cdu31a_port, 4); -errout3: - return -EIO; -} - - -static void __exit cdu31a_exit(void) -{ - del_gendisk(scd_gendisk); - put_disk(scd_gendisk); - if (unregister_cdrom(&scd_info)) { - printk(KERN_WARNING PFX "Can't unregister from Uniform " - "cdrom driver\n"); - return; - } - if ((unregister_blkdev(MAJOR_NR, "cdu31a") == -EINVAL)) { - printk(KERN_WARNING PFX "Can't unregister\n"); - return; - } - - blk_cleanup_queue(cdu31a_queue); - - if (cdu31a_irq > 0) - free_irq(cdu31a_irq, NULL); - - release_region(cdu31a_port, 4); - printk(KERN_INFO PFX "module released.\n"); -} - -#ifdef MODULE -module_init(cdu31a_init); -#endif -module_exit(cdu31a_exit); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS_BLOCKDEV_MAJOR(CDU31A_CDROM_MAJOR); diff --git a/drivers/cdrom/cdu31a.h b/drivers/cdrom/cdu31a.h deleted file mode 100644 index 61d4768c412e..000000000000 --- a/drivers/cdrom/cdu31a.h +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Definitions for a Sony interface CDROM drive. - * - * Corey Minyard (minyard@wf-rch.cirr.com) - * - * Copyright (C) 1993 Corey Minyard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -/* - * General defines. - */ -#define SONY_XA_DISK_TYPE 0x20 - -/* - * Offsets (from the base address) and bits for the various write registers - * of the drive. - */ -#define SONY_CMD_REG_OFFSET 0 -#define SONY_PARAM_REG_OFFSET 1 -#define SONY_WRITE_REG_OFFSET 2 -#define SONY_CONTROL_REG_OFFSET 3 -# define SONY_ATTN_CLR_BIT 0x01 -# define SONY_RES_RDY_CLR_BIT 0x02 -# define SONY_DATA_RDY_CLR_BIT 0x04 -# define SONY_ATTN_INT_EN_BIT 0x08 -# define SONY_RES_RDY_INT_EN_BIT 0x10 -# define SONY_DATA_RDY_INT_EN_BIT 0x20 -# define SONY_PARAM_CLR_BIT 0x40 -# define SONY_DRIVE_RESET_BIT 0x80 - -/* - * Offsets (from the base address) and bits for the various read registers - * of the drive. - */ -#define SONY_STATUS_REG_OFFSET 0 -# define SONY_ATTN_BIT 0x01 -# define SONY_RES_RDY_BIT 0x02 -# define SONY_DATA_RDY_BIT 0x04 -# define SONY_ATTN_INT_ST_BIT 0x08 -# define SONY_RES_RDY_INT_ST_BIT 0x10 -# define SONY_DATA_RDY_INT_ST_BIT 0x20 -# define SONY_DATA_REQUEST_BIT 0x40 -# define SONY_BUSY_BIT 0x80 -#define SONY_RESULT_REG_OFFSET 1 -#define SONY_READ_REG_OFFSET 2 -#define SONY_FIFOST_REG_OFFSET 3 -# define SONY_PARAM_WRITE_RDY_BIT 0x01 -# define SONY_PARAM_REG_EMPTY_BIT 0x02 -# define SONY_RES_REG_NOT_EMP_BIT 0x04 -# define SONY_RES_REG_FULL_BIT 0x08 - -#define LOG_START_OFFSET 150 /* Offset of first logical sector */ - -#define SONY_DETECT_TIMEOUT (8*HZ/10) /* Maximum amount of time - that drive detection code - will wait for response - from drive (in 1/100th's - of seconds). */ - -#define SONY_JIFFIES_TIMEOUT (10*HZ) /* Maximum number of times the - drive will wait/try for an - operation */ -#define SONY_RESET_TIMEOUT HZ /* Maximum number of times the - drive will wait/try a reset - operation */ -#define SONY_READY_RETRIES 20000 /* How many times to retry a - spin waiting for a register - to come ready */ - -#define MAX_CDU31A_RETRIES 3 /* How many times to retry an - operation */ - -/* Commands to request or set drive control parameters and disc information */ -#define SONY_REQ_DRIVE_CONFIG_CMD 0x00 /* Returns s_sony_drive_config */ -#define SONY_REQ_DRIVE_MODE_CMD 0x01 -#define SONY_REQ_DRIVE_PARAM_CMD 0x02 -#define SONY_REQ_MECH_STATUS_CMD 0x03 -#define SONY_REQ_AUDIO_STATUS_CMD 0x04 -#define SONY_SET_DRIVE_PARAM_CMD 0x10 -#define SONY_REQ_TOC_DATA_CMD 0x20 /* Returns s_sony_toc */ -#define SONY_REQ_SUBCODE_ADDRESS_CMD 0x21 /* Returns s_sony_subcode */ -#define SONY_REQ_UPC_EAN_CMD 0x22 -#define SONY_REQ_ISRC_CMD 0x23 -#define SONY_REQ_TOC_DATA_SPEC_CMD 0x24 /* Returns s_sony_session_toc */ - -/* Commands to request information from the drive */ -#define SONY_READ_TOC_CMD 0x30 /* let the drive firmware grab the TOC */ -#define SONY_SEEK_CMD 0x31 -#define SONY_READ_CMD 0x32 -#define SONY_READ_BLKERR_STAT_CMD 0x34 -#define SONY_ABORT_CMD 0x35 -#define SONY_READ_TOC_SPEC_CMD 0x36 - -/* Commands to control audio */ -#define SONY_AUDIO_PLAYBACK_CMD 0x40 -#define SONY_AUDIO_STOP_CMD 0x41 -#define SONY_AUDIO_SCAN_CMD 0x42 - -/* Miscellaneous control commands */ -#define SONY_EJECT_CMD 0x50 -#define SONY_SPIN_UP_CMD 0x51 -#define SONY_SPIN_DOWN_CMD 0x52 - -/* Diagnostic commands */ -#define SONY_WRITE_BUFFER_CMD 0x60 -#define SONY_READ_BUFFER_CMD 0x61 -#define SONY_DIAGNOSTICS_CMD 0x62 - - -/* - * The following are command parameters for the set drive parameter command - */ -#define SONY_SD_DECODE_PARAM 0x00 -#define SONY_SD_INTERFACE_PARAM 0x01 -#define SONY_SD_BUFFERING_PARAM 0x02 -#define SONY_SD_AUDIO_PARAM 0x03 -#define SONY_SD_AUDIO_VOLUME 0x04 -#define SONY_SD_MECH_CONTROL 0x05 -#define SONY_SD_AUTO_SPIN_DOWN_TIME 0x06 - -/* - * The following are parameter bits for the mechanical control command - */ -#define SONY_AUTO_SPIN_UP_BIT 0x01 -#define SONY_AUTO_EJECT_BIT 0x02 -#define SONY_DOUBLE_SPEED_BIT 0x04 - -/* - * The following extract information from the drive configuration about - * the drive itself. - */ -#define SONY_HWC_GET_LOAD_MECH(c) (c.hw_config[0] & 0x03) -#define SONY_HWC_EJECT(c) (c.hw_config[0] & 0x04) -#define SONY_HWC_LED_SUPPORT(c) (c.hw_config[0] & 0x08) -#define SONY_HWC_DOUBLE_SPEED(c) (c.hw_config[0] & 0x10) -#define SONY_HWC_GET_BUF_MEM_SIZE(c) ((c.hw_config[0] & 0xc0) >> 6) -#define SONY_HWC_AUDIO_PLAYBACK(c) (c.hw_config[1] & 0x01) -#define SONY_HWC_ELECTRIC_VOLUME(c) (c.hw_config[1] & 0x02) -#define SONY_HWC_ELECTRIC_VOLUME_CTL(c) (c.hw_config[1] & 0x04) - -#define SONY_HWC_CADDY_LOAD_MECH 0x00 -#define SONY_HWC_TRAY_LOAD_MECH 0x01 -#define SONY_HWC_POPUP_LOAD_MECH 0x02 -#define SONY_HWC_UNKWN_LOAD_MECH 0x03 - -#define SONY_HWC_8KB_BUFFER 0x00 -#define SONY_HWC_32KB_BUFFER 0x01 -#define SONY_HWC_64KB_BUFFER 0x02 -#define SONY_HWC_UNKWN_BUFFER 0x03 - -/* - * This is the complete status returned from the drive configuration request - * command. - */ -struct s_sony_drive_config -{ - unsigned char exec_status[2]; - char vendor_id[8]; - char product_id[16]; - char product_rev_level[8]; - unsigned char hw_config[2]; -}; - -/* The following is returned from the request subcode address command */ -struct s_sony_subcode -{ - unsigned char exec_status[2]; - unsigned char address :4; - unsigned char control :4; - unsigned char track_num; - unsigned char index_num; - unsigned char rel_msf[3]; - unsigned char reserved1; - unsigned char abs_msf[3]; -}; - -#define MAX_TRACKS 100 /* The maximum tracks a disk may have. */ -/* - * The following is returned from the request TOC (Table Of Contents) command. - * (last_track_num-first_track_num+1) values are valid in tracks. - */ -struct s_sony_toc -{ - unsigned char exec_status[2]; - unsigned char address0 :4; - unsigned char control0 :4; - unsigned char point0; - unsigned char first_track_num; - unsigned char disk_type; - unsigned char dummy0; - unsigned char address1 :4; - unsigned char control1 :4; - unsigned char point1; - unsigned char last_track_num; - unsigned char dummy1; - unsigned char dummy2; - unsigned char address2 :4; - unsigned char control2 :4; - unsigned char point2; - unsigned char lead_out_start_msf[3]; - struct - { - unsigned char address :4; - unsigned char control :4; - unsigned char track; - unsigned char track_start_msf[3]; - } tracks[MAX_TRACKS]; - - unsigned int lead_out_start_lba; -}; - -struct s_sony_session_toc -{ - unsigned char exec_status[2]; - unsigned char session_number; - unsigned char address0 :4; - unsigned char control0 :4; - unsigned char point0; - unsigned char first_track_num; - unsigned char disk_type; - unsigned char dummy0; - unsigned char address1 :4; - unsigned char control1 :4; - unsigned char point1; - unsigned char last_track_num; - unsigned char dummy1; - unsigned char dummy2; - unsigned char address2 :4; - unsigned char control2 :4; - unsigned char point2; - unsigned char lead_out_start_msf[3]; - unsigned char addressb0 :4; - unsigned char controlb0 :4; - unsigned char pointb0; - unsigned char next_poss_prog_area_msf[3]; - unsigned char num_mode_5_pointers; - unsigned char max_start_outer_leadout_msf[3]; - unsigned char addressb1 :4; - unsigned char controlb1 :4; - unsigned char pointb1; - unsigned char dummyb0_1[4]; - unsigned char num_skip_interval_pointers; - unsigned char num_skip_track_assignments; - unsigned char dummyb0_2; - unsigned char addressb2 :4; - unsigned char controlb2 :4; - unsigned char pointb2; - unsigned char tracksb2[7]; - unsigned char addressb3 :4; - unsigned char controlb3 :4; - unsigned char pointb3; - unsigned char tracksb3[7]; - unsigned char addressb4 :4; - unsigned char controlb4 :4; - unsigned char pointb4; - unsigned char tracksb4[7]; - unsigned char addressc0 :4; - unsigned char controlc0 :4; - unsigned char pointc0; - unsigned char dummyc0[7]; - struct - { - unsigned char address :4; - unsigned char control :4; - unsigned char track; - unsigned char track_start_msf[3]; - } tracks[MAX_TRACKS]; - - unsigned int start_track_lba; - unsigned int lead_out_start_lba; - unsigned int mint; - unsigned int maxt; -}; - -struct s_all_sessions_toc -{ - unsigned char sessions; - unsigned int track_entries; - unsigned char first_track_num; - unsigned char last_track_num; - unsigned char disk_type; - unsigned char lead_out_start_msf[3]; - struct - { - unsigned char address :4; - unsigned char control :4; - unsigned char track; - unsigned char track_start_msf[3]; - } tracks[MAX_TRACKS]; - - unsigned int start_track_lba; - unsigned int lead_out_start_lba; -}; - - -/* - * The following are errors returned from the drive. - */ - -/* Command error group */ -#define SONY_ILL_CMD_ERR 0x10 -#define SONY_ILL_PARAM_ERR 0x11 - -/* Mechanism group */ -#define SONY_NOT_LOAD_ERR 0x20 -#define SONY_NO_DISK_ERR 0x21 -#define SONY_NOT_SPIN_ERR 0x22 -#define SONY_SPIN_ERR 0x23 -#define SONY_SPINDLE_SERVO_ERR 0x25 -#define SONY_FOCUS_SERVO_ERR 0x26 -#define SONY_EJECT_MECH_ERR 0x29 -#define SONY_AUDIO_PLAYING_ERR 0x2a -#define SONY_EMERGENCY_EJECT_ERR 0x2c - -/* Seek error group */ -#define SONY_FOCUS_ERR 0x30 -#define SONY_FRAME_SYNC_ERR 0x31 -#define SONY_SUBCODE_ADDR_ERR 0x32 -#define SONY_BLOCK_SYNC_ERR 0x33 -#define SONY_HEADER_ADDR_ERR 0x34 - -/* Read error group */ -#define SONY_ILL_TRACK_R_ERR 0x40 -#define SONY_MODE_0_R_ERR 0x41 -#define SONY_ILL_MODE_R_ERR 0x42 -#define SONY_ILL_BLOCK_SIZE_R_ERR 0x43 -#define SONY_MODE_R_ERR 0x44 -#define SONY_FORM_R_ERR 0x45 -#define SONY_LEAD_OUT_R_ERR 0x46 -#define SONY_BUFFER_OVERRUN_R_ERR 0x47 - -/* Data error group */ -#define SONY_UNREC_CIRC_ERR 0x53 -#define SONY_UNREC_LECC_ERR 0x57 - -/* Subcode error group */ -#define SONY_NO_TOC_ERR 0x60 -#define SONY_SUBCODE_DATA_NVAL_ERR 0x61 -#define SONY_FOCUS_ON_TOC_READ_ERR 0x63 -#define SONY_FRAME_SYNC_ON_TOC_READ_ERR 0x64 -#define SONY_TOC_DATA_ERR 0x65 - -/* Hardware failure group */ -#define SONY_HW_FAILURE_ERR 0x70 -#define SONY_LEAD_IN_A_ERR 0x91 -#define SONY_LEAD_OUT_A_ERR 0x92 -#define SONY_DATA_TRACK_A_ERR 0x93 - -/* - * The following are returned from the Read With Block Error Status command. - * They are not errors but information (Errors from the 0x5x group above may - * also be returned - */ -#define SONY_NO_CIRC_ERR_BLK_STAT 0x50 -#define SONY_NO_LECC_ERR_BLK_STAT 0x54 -#define SONY_RECOV_LECC_ERR_BLK_STAT 0x55 -#define SONY_NO_ERR_DETECTION_STAT 0x59 - -/* - * The following is not an error returned by the drive, but by the code - * that talks to the drive. It is returned because of a timeout. - */ -#define SONY_TIMEOUT_OP_ERR 0x01 -#define SONY_SIGNAL_OP_ERR 0x02 -#define SONY_BAD_DATA_ERR 0x03 - - -/* - * The following are attention code for asynchronous events from the drive. - */ - -/* Standard attention group */ -#define SONY_EMER_EJECT_ATTN 0x2c -#define SONY_HW_FAILURE_ATTN 0x70 -#define SONY_MECH_LOADED_ATTN 0x80 -#define SONY_EJECT_PUSHED_ATTN 0x81 - -/* Audio attention group */ -#define SONY_AUDIO_PLAY_DONE_ATTN 0x90 -#define SONY_LEAD_IN_ERR_ATTN 0x91 -#define SONY_LEAD_OUT_ERR_ATTN 0x92 -#define SONY_DATA_TRACK_ERR_ATTN 0x93 -#define SONY_AUDIO_PLAYBACK_ERR_ATTN 0x94 - -/* Auto spin up group */ -#define SONY_SPIN_UP_COMPLETE_ATTN 0x24 -#define SONY_SPINDLE_SERVO_ERR_ATTN 0x25 -#define SONY_FOCUS_SERVO_ERR_ATTN 0x26 -#define SONY_TOC_READ_DONE_ATTN 0x62 -#define SONY_FOCUS_ON_TOC_READ_ERR_ATTN 0x63 -#define SONY_SYNC_ON_TOC_READ_ERR_ATTN 0x65 - -/* Auto eject group */ -#define SONY_SPIN_DOWN_COMPLETE_ATTN 0x27 -#define SONY_EJECT_COMPLETE_ATTN 0x28 -#define SONY_EJECT_MECH_ERR_ATTN 0x29 diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c deleted file mode 100644 index 2f8fe3b6bbd0..000000000000 --- a/drivers/cdrom/cm206.c +++ /dev/null @@ -1,1594 +0,0 @@ -/* cm206.c. A linux-driver for the cm206 cdrom player with cm260 adapter card. - Copyright (c) 1995--1997 David A. van Leeuwen. - $Id: cm206.c,v 1.5 1997/12/26 11:02:51 david Exp $ - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -History: - Started 25 jan 1994. Waiting for documentation... - 22 feb 1995: 0.1a first reasonably safe polling driver. - Two major bugs, one in read_sector and one in - do_cm206_request, happened to cancel! - 25 feb 1995: 0.2a first reasonable interrupt driven version of above. - uart writes are still done in polling mode. - 25 feb 1995: 0.21a writes also in interrupt mode, still some - small bugs to be found... Larger buffer. - 2 mrt 1995: 0.22 Bug found (cd-> nowhere, interrupt was called in - initialization), read_ahead of 16. Timeouts implemented. - unclear if they do something... - 7 mrt 1995: 0.23 Start of background read-ahead. - 18 mrt 1995: 0.24 Working background read-ahead. (still problems) - 26 mrt 1995: 0.25 Multi-session ioctl added (kernel v1.2). - Statistics implemented, though separate stats206.h. - Accessible through ioctl 0x1000 (just a number). - Hard to choose between v1.2 development and 1.1.75. - Bottom-half doesn't work with 1.2... - 0.25a: fixed... typo. Still problems... - 1 apr 1995: 0.26 Module support added. Most bugs found. Use kernel 1.2.n. - 5 apr 1995: 0.27 Auto-probe for the adapter card base address. - Auto-probe for the adaptor card irq line. - 7 apr 1995: 0.28 Added lilo setup support for base address and irq. - Use major number 32 (not in this source), officially - assigned to this driver. - 9 apr 1995: 0.29 Added very limited audio support. Toc_header, stop, pause, - resume, eject. Play_track ignores track info, because we can't - read a table-of-contents entry. Toc_entry is implemented - as a `placebo' function: always returns start of disc. - 3 may 1995: 0.30 Audio support completed. The get_toc_entry function - is implemented as a binary search. - 15 may 1995: 0.31 More work on audio stuff. Workman is not easy to - satisfy; changed binary search into linear search. - Auto-probe for base address somewhat relaxed. - 1 jun 1995: 0.32 Removed probe_irq_on/off for module version. - 10 jun 1995: 0.33 Workman still behaves funny, but you should be - able to eject and substitute another disc. - - An adaptation of 0.33 is included in linux-1.3.7 by Eberhard Moenkeberg - - 18 jul 1995: 0.34 Patch by Heiko Eissfeldt included, mainly considering - verify_area's in the ioctls. Some bugs introduced by - EM considering the base port and irq fixed. - - 18 dec 1995: 0.35 Add some code for error checking... no luck... - - We jump to reach our goal: version 1.0 in the next stable linux kernel. - - 19 mar 1996: 0.95 Different implementation of CDROM_GET_UPC, on - request of Thomas Quinot. - 25 mar 1996: 0.96 Interpretation of opening with O_WRONLY or O_RDWR: - open only for ioctl operation, e.g., for operation of - tray etc. - 4 apr 1996: 0.97 First implementation of layer between VFS and cdrom - driver, a generic interface. Much of the functionality - of cm206_open() and cm206_ioctl() is transferred to a - new file cdrom.c and its header ucdrom.h. - - Upgrade to Linux kernel 1.3.78. - - 11 apr 1996 0.98 Upgrade to Linux kernel 1.3.85 - More code moved to cdrom.c - - 0.99 Some more small changes to decrease number - of oopses at module load; - - 27 jul 1996 0.100 Many hours of debugging, kernel change from 1.2.13 - to 2.0.7 seems to have introduced some weird behavior - in (interruptible_)sleep_on(&cd->data): the process - seems to be woken without any explicit wake_up in my own - code. Patch to try 100x in case such untriggered wake_up's - occur. - - 28 jul 1996 0.101 Rewriting of the code that receives the command echo, - using a fifo to store echoed bytes. - - Branch from 0.99: - - 0.99.1.0 Update to kernel release 2.0.10 dev_t -> kdev_t - (emoenke) various typos found by others. extra - module-load oops protection. - - 0.99.1.1 Initialization constant cdrom_dops.speed - changed from float (2.0) to int (2); Cli()-sti() pair - around cm260_reset() in module initialization code. - - 0.99.1.2 Changes literally as proposed by Scott Snyder - for the 2.1 kernel line, which - have to do mainly with the poor minor support i had. The - major new concept is to change a cdrom driver's - operations struct from the capabilities struct. This - reflects the fact that there is one major for a driver, - whilst there can be many minors whith completely - different capabilities. - - 0.99.1.3 More changes for operations/info separation. - - 0.99.1.4 Added speed selection (someone had to do this - first). - - 23 jan 1997 0.99.1.5 MODULE_PARMS call added. - - 23 jan 1997 0.100.1.2--0.100.1.5 following similar lines as - 0.99.1.1--0.99.1.5. I get too many complaints about the - drive making read errors. What't wrong with the 2.0+ - kernel line? Why get i (and othe cm206 owners) weird - results? Why were things good in the good old 1.1--1.2 - era? Why don't i throw away the drive? - - 2 feb 1997 0.102 Added `volatile' to values in cm206_struct. Seems to - reduce many of the problems. Rewrote polling routines - to use fixed delays between polls. - 0.103 Changed printk behavior. - 0.104 Added a 0.100 -> 0.100.1.1 change - -11 feb 1997 0.105 Allow auto_probe during module load, disable - with module option "auto_probe=0". Moved some debugging - statements to lower priority. Implemented select_speed() - function. - -13 feb 1997 1.0 Final version for 2.0 kernel line. - - All following changes will be for the 2.1 kernel line. - -15 feb 1997 1.1 Keep up with kernel 2.1.26, merge in changes from - cdrom.c 0.100.1.1--1.0. Add some more MODULE_PARMS. - -14 sep 1997 1.2 Upgrade to Linux 2.1.55. Added blksize_size[], patch - sent by James Bottomley . - -21 dec 1997 1.4 Upgrade to Linux 2.1.72. - -24 jan 1998 Removed the cm206_disc_status() function, as it was now dead - code. The Uniform CDROM driver now provides this functionality. - -9 Nov. 1999 Make kernel-parameter implementation work with 2.3.x - Removed init_module & cleanup_module in favor of - module_init & module_exit. - Torben Mathiasen - * - * Parts of the code are based upon lmscd.c written by Kai Petzke, - * sbpcd.c written by Eberhard Moenkeberg, and mcd.c by Martin - * Harriss, but any off-the-shelf dynamic programming algorithm won't - * be able to find them. - * - * The cm206 drive interface and the cm260 adapter card seem to be - * sufficiently different from their cm205/cm250 counterparts - * in order to write a complete new driver. - * - * I call all routines connected to the Linux kernel something - * with `cm206' in it, as this stuff is too series-dependent. - * - * Currently, my limited knowledge is based on: - * - The Linux Kernel Hacker's guide, v. 0.5, by Michael K. Johnson - * - Linux Kernel Programmierung, by Michael Beck and others - * - Philips/LMS cm206 and cm226 product specification - * - Philips/LMS cm260 product specification - * - * David van Leeuwen, david@tm.tno.nl. */ -#define REVISION "$Revision: 1.5 $" - -#include - -#include /* These include what we really need */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* #include */ - -#include - -#define MAJOR_NR CM206_CDROM_MAJOR - -#include - -#undef DEBUG -#define STATISTICS /* record times and frequencies of events */ -#define AUTO_PROBE_MODULE -#define USE_INSW - -#include "cm206.h" - -/* This variable defines whether or not to probe for adapter base port - address and interrupt request. It can be overridden by the boot - parameter `auto'. -*/ -static int auto_probe = 1; /* Yes, why not? */ - -static int cm206_base = CM206_BASE; -static int cm206_irq = CM206_IRQ; -#ifdef MODULE -static int cm206[2] = { 0, 0 }; /* for compatible `insmod' parameter passing */ -module_param_array(cm206, int, NULL, 0); /* base,irq or irq,base */ -#endif - -module_param(cm206_base, int, 0); /* base */ -module_param(cm206_irq, int, 0); /* irq */ -module_param(auto_probe, bool, 0); /* auto probe base and irq */ -MODULE_LICENSE("GPL"); - -#define POLLOOP 100 /* milliseconds */ -#define READ_AHEAD 1 /* defines private buffer, waste! */ -#define BACK_AHEAD 1 /* defines adapter-read ahead */ -#define DATA_TIMEOUT (3*HZ) /* measured in jiffies (10 ms) */ -#define UART_TIMEOUT (5*HZ/100) -#define DSB_TIMEOUT (7*HZ) /* time for the slowest command to finish */ -#define UR_SIZE 4 /* uart receive buffer fifo size */ - -#define LINUX_BLOCK_SIZE 512 /* WHERE is this defined? */ -#define RAW_SECTOR_SIZE 2352 /* ok, is also defined in cdrom.h */ -#define ISO_SECTOR_SIZE 2048 -#define BLOCKS_ISO (ISO_SECTOR_SIZE/LINUX_BLOCK_SIZE) /* 4 */ -#define CD_SYNC_HEAD 16 /* CD_SYNC + CD_HEAD */ - -#ifdef STATISTICS /* keep track of errors in counters */ -#define stats(i) { ++cd->stats[st_ ## i]; \ - cd->last_stat[st_ ## i] = cd->stat_counter++; \ - } -#else -#define stats(i) (void) 0; -#endif - -#define Debug(a) {printk (KERN_DEBUG); printk a;} -#ifdef DEBUG -#define debug(a) Debug(a) -#else -#define debug(a) (void) 0; -#endif - -typedef unsigned char uch; /* 8-bits */ -typedef unsigned short ush; /* 16-bits */ - -struct toc_struct { /* private copy of Table of Contents */ - uch track, fsm[3], q0; -}; - -struct cm206_struct { - volatile ush intr_ds; /* data status read on last interrupt */ - volatile ush intr_ls; /* uart line status read on last interrupt */ - volatile uch ur[UR_SIZE]; /* uart receive buffer fifo */ - volatile uch ur_w, ur_r; /* write/read buffer index */ - volatile uch dsb, cc; /* drive status byte and condition (error) code */ - int command; /* command to be written to the uart */ - int openfiles; - ush sector[READ_AHEAD * RAW_SECTOR_SIZE / 2]; /* buffered cd-sector */ - int sector_first, sector_last; /* range of these sectors */ - wait_queue_head_t uart; /* wait queues for interrupt */ - wait_queue_head_t data; - struct timer_list timer; /* time-out */ - char timed_out; - signed char max_sectors; /* number of sectors that fit in adapter mem */ - char wait_back; /* we're waiting for a background-read */ - char background; /* is a read going on in the background? */ - int adapter_first; /* if so, that's the starting sector */ - int adapter_last; - char fifo_overflowed; - uch disc_status[7]; /* result of get_disc_status command */ -#ifdef STATISTICS - int stats[NR_STATS]; - int last_stat[NR_STATS]; /* `time' at which stat was stat */ - int stat_counter; -#endif - struct toc_struct toc[101]; /* The whole table of contents + lead-out */ - uch q[10]; /* Last read q-channel info */ - uch audio_status[5]; /* last read position on pause */ - uch media_changed; /* record if media changed */ -}; - -#define DISC_STATUS cd->disc_status[0] -#define FIRST_TRACK cd->disc_status[1] -#define LAST_TRACK cd->disc_status[2] -#define PAUSED cd->audio_status[0] /* misuse this memory byte! */ -#define PLAY_TO cd->toc[0] /* toc[0] records end-time in play */ - -static struct cm206_struct *cd; /* the main memory structure */ -static struct request_queue *cm206_queue; -static DEFINE_SPINLOCK(cm206_lock); - -/* First, we define some polling functions. These are actually - only being used in the initialization. */ - -static void send_command_polled(int command) -{ - int loop = POLLOOP; - while (!(inw(r_line_status) & ls_transmitter_buffer_empty) - && loop > 0) { - mdelay(1); /* one millisec delay */ - --loop; - } - outw(command, r_uart_transmit); -} - -static uch receive_echo_polled(void) -{ - int loop = POLLOOP; - while (!(inw(r_line_status) & ls_receive_buffer_full) && loop > 0) { - mdelay(1); - --loop; - } - return ((uch) inw(r_uart_receive)); -} - -static uch send_receive_polled(int command) -{ - send_command_polled(command); - return receive_echo_polled(); -} - -static inline void clear_ur(void) -{ - if (cd->ur_r != cd->ur_w) { - debug(("Deleting bytes from fifo:")); - for (; cd->ur_r != cd->ur_w; - cd->ur_r++, cd->ur_r %= UR_SIZE) - debug((" 0x%x", cd->ur[cd->ur_r])); - debug(("\n")); - } -} - -static struct tasklet_struct cm206_tasklet; - -/* The interrupt handler. When the cm260 generates an interrupt, very - much care has to be taken in reading out the registers in the right - order; in case of a receive_buffer_full interrupt, first the - uart_receive must be read, and then the line status again to - de-assert the interrupt line. It took me a couple of hours to find - this out:-( - - The function reset_cm206 appears to cause an interrupt, because - pulling up the INIT line clears both the uart-write-buffer /and/ - the uart-write-buffer-empty mask. We call this a `lost interrupt,' - as there seems so reason for this to happen. -*/ - -static irqreturn_t cm206_interrupt(int sig, void *dev_id) -{ - volatile ush fool; - cd->intr_ds = inw(r_data_status); /* resets data_ready, data_error, - crc_error, sync_error, toc_ready - interrupts */ - cd->intr_ls = inw(r_line_status); /* resets overrun bit */ - debug(("Intr, 0x%x 0x%x, %d\n", cd->intr_ds, cd->intr_ls, - cd->background)); - if (cd->intr_ls & ls_attention) - stats(attention); - /* receive buffer full? */ - if (cd->intr_ls & ls_receive_buffer_full) { - cd->ur[cd->ur_w] = inb(r_uart_receive); /* get order right! */ - cd->intr_ls = inw(r_line_status); /* resets rbf interrupt */ - debug(("receiving #%d: 0x%x\n", cd->ur_w, - cd->ur[cd->ur_w])); - cd->ur_w++; - cd->ur_w %= UR_SIZE; - if (cd->ur_w == cd->ur_r) - debug(("cd->ur overflow!\n")); - if (waitqueue_active(&cd->uart) && cd->background < 2) { - del_timer(&cd->timer); - wake_up_interruptible(&cd->uart); - } - } - /* data ready in fifo? */ - else if (cd->intr_ds & ds_data_ready) { - if (cd->background) - ++cd->adapter_last; - if (waitqueue_active(&cd->data) - && (cd->wait_back || !cd->background)) { - del_timer(&cd->timer); - wake_up_interruptible(&cd->data); - } - stats(data_ready); - } - /* ready to issue a write command? */ - else if (cd->command && cd->intr_ls & ls_transmitter_buffer_empty) { - outw(dc_normal | (inw(r_data_status) & 0x7f), - r_data_control); - outw(cd->command, r_uart_transmit); - cd->command = 0; - if (!cd->background) - wake_up_interruptible(&cd->uart); - } - /* now treat errors (at least, identify them for debugging) */ - else if (cd->intr_ds & ds_fifo_overflow) { - debug(("Fifo overflow at sectors 0x%x\n", - cd->sector_first)); - fool = inw(r_fifo_output_buffer); /* de-assert the interrupt */ - cd->fifo_overflowed = 1; /* signal one word less should be read */ - stats(fifo_overflow); - } else if (cd->intr_ds & ds_data_error) { - debug(("Data error at sector 0x%x\n", cd->sector_first)); - stats(data_error); - } else if (cd->intr_ds & ds_crc_error) { - debug(("CRC error at sector 0x%x\n", cd->sector_first)); - stats(crc_error); - } else if (cd->intr_ds & ds_sync_error) { - debug(("Sync at sector 0x%x\n", cd->sector_first)); - stats(sync_error); - } else if (cd->intr_ds & ds_toc_ready) { - /* do something appropriate */ - } - /* couldn't see why this interrupt, maybe due to init */ - else { - outw(dc_normal | READ_AHEAD, r_data_control); - stats(lost_intr); - } - if (cd->background - && (cd->adapter_last - cd->adapter_first == cd->max_sectors - || cd->fifo_overflowed)) - tasklet_schedule(&cm206_tasklet); /* issue a stop read command */ - stats(interrupt); - return IRQ_HANDLED; -} - -/* we have put the address of the wait queue in who */ -static void cm206_timeout(unsigned long who) -{ - cd->timed_out = 1; - debug(("Timing out\n")); - wake_up_interruptible((wait_queue_head_t *) who); -} - -/* This function returns 1 if a timeout occurred, 0 if an interrupt - happened */ -static int sleep_or_timeout(wait_queue_head_t * wait, int timeout) -{ - cd->timed_out = 0; - init_timer(&cd->timer); - cd->timer.data = (unsigned long) wait; - cd->timer.expires = jiffies + timeout; - add_timer(&cd->timer); - debug(("going to sleep\n")); - interruptible_sleep_on(wait); - del_timer(&cd->timer); - if (cd->timed_out) { - cd->timed_out = 0; - return 1; - } else - return 0; -} - -static void send_command(int command) -{ - debug(("Sending 0x%x\n", command)); - if (!(inw(r_line_status) & ls_transmitter_buffer_empty)) { - cd->command = command; - cli(); /* don't interrupt before sleep */ - outw(dc_mask_sync_error | dc_no_stop_on_error | - (inw(r_data_status) & 0x7f), r_data_control); - /* interrupt routine sends command */ - if (sleep_or_timeout(&cd->uart, UART_TIMEOUT)) { - debug(("Time out on write-buffer\n")); - stats(write_timeout); - outw(command, r_uart_transmit); - } - debug(("Write commmand delayed\n")); - } else - outw(command, r_uart_transmit); -} - -static uch receive_byte(int timeout) -{ - uch ret; - cli(); - debug(("cli\n")); - ret = cd->ur[cd->ur_r]; - if (cd->ur_r != cd->ur_w) { - sti(); - debug(("returning #%d: 0x%x\n", cd->ur_r, - cd->ur[cd->ur_r])); - cd->ur_r++; - cd->ur_r %= UR_SIZE; - return ret; - } else if (sleep_or_timeout(&cd->uart, timeout)) { /* does sti() */ - debug(("Time out on receive-buffer\n")); -#ifdef STATISTICS - if (timeout == UART_TIMEOUT) - stats(receive_timeout) /* no `;'! */ - else - stats(dsb_timeout); -#endif - return 0xda; - } - ret = cd->ur[cd->ur_r]; - debug(("slept; returning #%d: 0x%x\n", cd->ur_r, - cd->ur[cd->ur_r])); - cd->ur_r++; - cd->ur_r %= UR_SIZE; - return ret; -} - -static inline uch receive_echo(void) -{ - return receive_byte(UART_TIMEOUT); -} - -static inline uch send_receive(int command) -{ - send_command(command); - return receive_echo(); -} - -static inline uch wait_dsb(void) -{ - return receive_byte(DSB_TIMEOUT); -} - -static int type_0_command(int command, int expect_dsb) -{ - int e; - clear_ur(); - if (command != (e = send_receive(command))) { - debug(("command 0x%x echoed as 0x%x\n", command, e)); - stats(echo); - return -1; - } - if (expect_dsb) { - cd->dsb = wait_dsb(); /* wait for command to finish */ - } - return 0; -} - -static int type_1_command(int command, int bytes, uch * status) -{ /* returns info */ - int i; - if (type_0_command(command, 0)) - return -1; - for (i = 0; i < bytes; i++) - status[i] = send_receive(c_gimme); - return 0; -} - -/* This function resets the adapter card. We'd better not do this too - * often, because it tends to generate `lost interrupts.' */ -static void reset_cm260(void) -{ - outw(dc_normal | dc_initialize | READ_AHEAD, r_data_control); - udelay(10); /* 3.3 mu sec minimum */ - outw(dc_normal | READ_AHEAD, r_data_control); -} - -/* fsm: frame-sec-min from linear address; one of many */ -static void fsm(int lba, uch * fsm) -{ - fsm[0] = lba % 75; - lba /= 75; - lba += 2; - fsm[1] = lba % 60; - fsm[2] = lba / 60; -} - -static inline int fsm2lba(uch * fsm) -{ - return fsm[0] + 75 * (fsm[1] - 2 + 60 * fsm[2]); -} - -static inline int f_s_m2lba(uch f, uch s, uch m) -{ - return f + 75 * (s - 2 + 60 * m); -} - -static int start_read(int start) -{ - uch read_sector[4] = { c_read_data, }; - int i, e; - - fsm(start, &read_sector[1]); - clear_ur(); - for (i = 0; i < 4; i++) - if (read_sector[i] != (e = send_receive(read_sector[i]))) { - debug(("read_sector: %x echoes %x\n", - read_sector[i], e)); - stats(echo); - if (e == 0xff) { /* this seems to happen often */ - e = receive_echo(); - debug(("Second try %x\n", e)); - if (e != read_sector[i]) - return -1; - } - } - return 0; -} - -static int stop_read(void) -{ - int e; - type_0_command(c_stop, 0); - if ((e = receive_echo()) != 0xff) { - debug(("c_stop didn't send 0xff, but 0x%x\n", e)); - stats(stop_0xff); - return -1; - } - return 0; -} - -/* This function starts to read sectors in adapter memory, the - interrupt routine should stop the read. In fact, the bottom_half - routine takes care of this. Set a flag `background' in the cd - struct to indicate the process. */ - -static int read_background(int start, int reading) -{ - if (cd->background) - return -1; /* can't do twice */ - outw(dc_normal | BACK_AHEAD, r_data_control); - if (!reading && start_read(start)) - return -2; - cd->adapter_first = cd->adapter_last = start; - cd->background = 1; /* flag a read is going on */ - return 0; -} - -#ifdef USE_INSW -#define transport_data insw -#else -/* this routine implements insw(,,). There was a time i had the - impression that there would be any difference in error-behaviour. */ -void transport_data(int port, ush * dest, int count) -{ - int i; - ush *d; - for (i = 0, d = dest; i < count; i++, d++) - *d = inw(port); -} -#endif - - -#define MAX_TRIES 100 -static int read_sector(int start) -{ - int tries = 0; - if (cd->background) { - cd->background = 0; - cd->adapter_last = -1; /* invalidate adapter memory */ - stop_read(); - } - cd->fifo_overflowed = 0; - reset_cm260(); /* empty fifo etc. */ - if (start_read(start)) - return -1; - do { - if (sleep_or_timeout(&cd->data, DATA_TIMEOUT)) { - debug(("Read timed out sector 0x%x\n", start)); - stats(read_timeout); - stop_read(); - return -3; - } - tries++; - } while (cd->intr_ds & ds_fifo_empty && tries < MAX_TRIES); - if (tries > 1) - debug(("Took me some tries\n")) - else - if (tries == MAX_TRIES) - debug(("MAX_TRIES tries for read sector\n")); - transport_data(r_fifo_output_buffer, cd->sector, - READ_AHEAD * RAW_SECTOR_SIZE / 2); - if (read_background(start + READ_AHEAD, 1)) - stats(read_background); - cd->sector_first = start; - cd->sector_last = start + READ_AHEAD; - stats(read_restarted); - return 0; -} - -/* The function of bottom-half is to send a stop command to the drive - This isn't easy because the routine is not `owned' by any process; - we can't go to sleep! The variable cd->background gives the status: - 0 no read pending - 1 a read is pending - 2 c_stop waits for write_buffer_empty - 3 c_stop waits for receive_buffer_full: echo - 4 c_stop waits for receive_buffer_full: 0xff -*/ - -static void cm206_tasklet_func(unsigned long ignore) -{ - debug(("bh: %d\n", cd->background)); - switch (cd->background) { - case 1: - stats(bh); - if (!(cd->intr_ls & ls_transmitter_buffer_empty)) { - cd->command = c_stop; - outw(dc_mask_sync_error | dc_no_stop_on_error | - (inw(r_data_status) & 0x7f), r_data_control); - cd->background = 2; - break; /* we'd better not time-out here! */ - } else - outw(c_stop, r_uart_transmit); - /* fall into case 2: */ - case 2: - /* the write has been satisfied by interrupt routine */ - cd->background = 3; - break; - case 3: - if (cd->ur_r != cd->ur_w) { - if (cd->ur[cd->ur_r] != c_stop) { - debug(("cm206_bh: c_stop echoed 0x%x\n", - cd->ur[cd->ur_r])); - stats(echo); - } - cd->ur_r++; - cd->ur_r %= UR_SIZE; - } - cd->background++; - break; - case 4: - if (cd->ur_r != cd->ur_w) { - if (cd->ur[cd->ur_r] != 0xff) { - debug(("cm206_bh: c_stop reacted with 0x%x\n", cd->ur[cd->ur_r])); - stats(stop_0xff); - } - cd->ur_r++; - cd->ur_r %= UR_SIZE; - } - cd->background = 0; - } -} - -static DECLARE_TASKLET(cm206_tasklet, cm206_tasklet_func, 0); - -/* This command clears the dsb_possible_media_change flag, so we must - * retain it. - */ -static void get_drive_status(void) -{ - uch status[2]; - type_1_command(c_drive_status, 2, status); /* this might be done faster */ - cd->dsb = status[0]; - cd->cc = status[1]; - cd->media_changed |= - !!(cd->dsb & (dsb_possible_media_change | - dsb_drive_not_ready | dsb_tray_not_closed)); -} - -static void get_disc_status(void) -{ - if (type_1_command(c_disc_status, 7, cd->disc_status)) { - debug(("get_disc_status: error\n")); - } -} - -/* The new open. The real opening strategy is defined in cdrom.c. */ - -static int cm206_open(struct cdrom_device_info *cdi, int purpose) -{ - if (!cd->openfiles) { /* reset only first time */ - cd->background = 0; - reset_cm260(); - cd->adapter_last = -1; /* invalidate adapter memory */ - cd->sector_last = -1; - } - ++cd->openfiles; - stats(open); - return 0; -} - -static void cm206_release(struct cdrom_device_info *cdi) -{ - if (cd->openfiles == 1) { - if (cd->background) { - cd->background = 0; - stop_read(); - } - cd->sector_last = -1; /* Make our internal buffer invalid */ - FIRST_TRACK = 0; /* No valid disc status */ - } - --cd->openfiles; -} - -/* Empty buffer empties $sectors$ sectors of the adapter card buffer, - * and then reads a sector in kernel memory. */ -static void empty_buffer(int sectors) -{ - while (sectors >= 0) { - transport_data(r_fifo_output_buffer, - cd->sector + cd->fifo_overflowed, - RAW_SECTOR_SIZE / 2 - cd->fifo_overflowed); - --sectors; - ++cd->adapter_first; /* update the current adapter sector */ - cd->fifo_overflowed = 0; /* reset overflow bit */ - stats(sector_transferred); - } - cd->sector_first = cd->adapter_first - 1; - cd->sector_last = cd->adapter_first; /* update the buffer sector */ -} - -/* try_adapter. This function determines if the requested sector is - in adapter memory, or will appear there soon. Returns 0 upon - success */ -static int try_adapter(int sector) -{ - if (cd->adapter_first <= sector && sector < cd->adapter_last) { - /* sector is in adapter memory */ - empty_buffer(sector - cd->adapter_first); - return 0; - } else if (cd->background == 1 && cd->adapter_first <= sector - && sector < cd->adapter_first + cd->max_sectors) { - /* a read is going on, we can wait for it */ - cd->wait_back = 1; - while (sector >= cd->adapter_last) { - if (sleep_or_timeout(&cd->data, DATA_TIMEOUT)) { - debug(("Timed out during background wait: %d %d %d %d\n", sector, cd->adapter_last, cd->adapter_first, cd->background)); - stats(back_read_timeout); - cd->wait_back = 0; - return -1; - } - } - cd->wait_back = 0; - empty_buffer(sector - cd->adapter_first); - return 0; - } else - return -2; -} - -/* This is not a very smart implementation. We could optimize for - consecutive block numbers. I'm not convinced this would really - bring down the processor load. */ -static void do_cm206_request(request_queue_t * q) -{ - long int i, cd_sec_no; - int quarter, error; - uch *source, *dest; - struct request *req; - - while (1) { /* repeat until all requests have been satisfied */ - req = elv_next_request(q); - if (!req) - return; - - if (rq_data_dir(req) != READ) { - debug(("Non-read command %d on cdrom\n", req->cmd)); - end_request(req, 0); - continue; - } - spin_unlock_irq(q->queue_lock); - error = 0; - for (i = 0; i < req->nr_sectors; i++) { - int e1, e2; - cd_sec_no = (req->sector + i) / BLOCKS_ISO; /* 4 times 512 bytes */ - quarter = (req->sector + i) % BLOCKS_ISO; - dest = req->buffer + i * LINUX_BLOCK_SIZE; - /* is already in buffer memory? */ - if (cd->sector_first <= cd_sec_no - && cd_sec_no < cd->sector_last) { - source = - ((uch *) cd->sector) + 16 + - quarter * LINUX_BLOCK_SIZE + - (cd_sec_no - - cd->sector_first) * RAW_SECTOR_SIZE; - memcpy(dest, source, LINUX_BLOCK_SIZE); - } else if (!(e1 = try_adapter(cd_sec_no)) || - !(e2 = read_sector(cd_sec_no))) { - source = - ((uch *) cd->sector) + 16 + - quarter * LINUX_BLOCK_SIZE; - memcpy(dest, source, LINUX_BLOCK_SIZE); - } else { - error = 1; - debug(("cm206_request: %d %d\n", e1, e2)); - } - } - spin_lock_irq(q->queue_lock); - end_request(req, !error); - } -} - -/* Audio support. I've tried very hard, but the cm206 drive doesn't - seem to have a get_toc (table-of-contents) function, while i'm - pretty sure it must read the toc upon disc insertion. Therefore - this function has been implemented through a binary search - strategy. All track starts that happen to be found are stored in - cd->toc[], for future use. - - I've spent a whole day on a bug that only shows under Workman--- - I don't get it. Tried everything, nothing works. If workman asks - for track# 0xaa, it'll get the wrong time back. Any other program - receives the correct value. I'm stymied. -*/ - -/* seek seeks to address lba. It does wait to arrive there. */ -static void seek(int lba) -{ - int i; - uch seek_command[4] = { c_seek, }; - - fsm(lba, &seek_command[1]); - for (i = 0; i < 4; i++) - type_0_command(seek_command[i], 0); - cd->dsb = wait_dsb(); -} - -static uch bcdbin(unsigned char bcd) -{ /* stolen from mcd.c! */ - return (bcd >> 4) * 10 + (bcd & 0xf); -} - -static inline uch normalize_track(uch track) -{ - if (track < 1) - return 1; - if (track > LAST_TRACK) - return LAST_TRACK + 1; - return track; -} - -/* This function does a binary search for track start. It records all - * tracks seen in the process. Input $track$ must be between 1 and - * #-of-tracks+1. Note that the start of the disc must be in toc[1].fsm. - */ -static int get_toc_lba(uch track) -{ - int max = 74 * 60 * 75 - 150, min = fsm2lba(cd->toc[1].fsm); - int i, lba, l, old_lba = 0; - uch *q = cd->q; - uch ct; /* current track */ - int binary = 0; - const int skip = 3 * 60 * 75; /* 3 minutes */ - - for (i = track; i > 0; i--) - if (cd->toc[i].track) { - min = fsm2lba(cd->toc[i].fsm); - break; - } - lba = min + skip; - do { - seek(lba); - type_1_command(c_read_current_q, 10, q); - ct = normalize_track(q[1]); - if (!cd->toc[ct].track) { - l = q[9] - bcdbin(q[5]) + 75 * (q[8] - - bcdbin(q[4]) - 2 + - 60 * (q[7] - - bcdbin(q - [3]))); - cd->toc[ct].track = q[1]; /* lead out still 0xaa */ - fsm(l, cd->toc[ct].fsm); - cd->toc[ct].q0 = q[0]; /* contains adr and ctrl info */ - if (ct == track) - return l; - } - old_lba = lba; - if (binary) { - if (ct < track) - min = lba; - else - max = lba; - lba = (min + max) / 2; - } else { - if (ct < track) - lba += skip; - else { - binary = 1; - max = lba; - min = lba - skip; - lba = (min + max) / 2; - } - } - } while (lba != old_lba); - return lba; -} - -static void update_toc_entry(uch track) -{ - track = normalize_track(track); - if (!cd->toc[track].track) - get_toc_lba(track); -} - -/* return 0 upon success */ -static int read_toc_header(struct cdrom_tochdr *hp) -{ - if (!FIRST_TRACK) - get_disc_status(); - if (hp) { - int i; - hp->cdth_trk0 = FIRST_TRACK; - hp->cdth_trk1 = LAST_TRACK; - /* fill in first track position */ - for (i = 0; i < 3; i++) - cd->toc[1].fsm[i] = cd->disc_status[3 + i]; - update_toc_entry(LAST_TRACK + 1); /* find most entries */ - return 0; - } - return -1; -} - -static void play_from_to_msf(struct cdrom_msf *msfp) -{ - uch play_command[] = { c_play, - msfp->cdmsf_frame0, msfp->cdmsf_sec0, msfp->cdmsf_min0, - msfp->cdmsf_frame1, msfp->cdmsf_sec1, msfp->cdmsf_min1, 2, - 2 - }; - int i; - for (i = 0; i < 9; i++) - type_0_command(play_command[i], 0); - for (i = 0; i < 3; i++) - PLAY_TO.fsm[i] = play_command[i + 4]; - PLAY_TO.track = 0; /* say no track end */ - cd->dsb = wait_dsb(); -} - -static void play_from_to_track(int from, int to) -{ - uch play_command[8] = { c_play, }; - int i; - - if (from == 0) { /* continue paused play */ - for (i = 0; i < 3; i++) { - play_command[i + 1] = cd->audio_status[i + 2]; - play_command[i + 4] = PLAY_TO.fsm[i]; - } - } else { - update_toc_entry(from); - update_toc_entry(to + 1); - for (i = 0; i < 3; i++) { - play_command[i + 1] = cd->toc[from].fsm[i]; - PLAY_TO.fsm[i] = play_command[i + 4] = - cd->toc[to + 1].fsm[i]; - } - PLAY_TO.track = to; - } - for (i = 0; i < 7; i++) - type_0_command(play_command[i], 0); - for (i = 0; i < 2; i++) - type_0_command(0x2, 0); /* volume */ - cd->dsb = wait_dsb(); -} - -static int get_current_q(struct cdrom_subchnl *qp) -{ - int i; - uch *q = cd->q; - if (type_1_command(c_read_current_q, 10, q)) - return 0; -/* q[0] = bcdbin(q[0]); Don't think so! */ - for (i = 2; i < 6; i++) - q[i] = bcdbin(q[i]); - qp->cdsc_adr = q[0] & 0xf; - qp->cdsc_ctrl = q[0] >> 4; /* from mcd.c */ - qp->cdsc_trk = q[1]; - qp->cdsc_ind = q[2]; - if (qp->cdsc_format == CDROM_MSF) { - qp->cdsc_reladdr.msf.minute = q[3]; - qp->cdsc_reladdr.msf.second = q[4]; - qp->cdsc_reladdr.msf.frame = q[5]; - qp->cdsc_absaddr.msf.minute = q[7]; - qp->cdsc_absaddr.msf.second = q[8]; - qp->cdsc_absaddr.msf.frame = q[9]; - } else { - qp->cdsc_reladdr.lba = f_s_m2lba(q[5], q[4], q[3]); - qp->cdsc_absaddr.lba = f_s_m2lba(q[9], q[8], q[7]); - } - get_drive_status(); - if (cd->dsb & dsb_play_in_progress) - qp->cdsc_audiostatus = CDROM_AUDIO_PLAY; - else if (PAUSED) - qp->cdsc_audiostatus = CDROM_AUDIO_PAUSED; - else - qp->cdsc_audiostatus = CDROM_AUDIO_NO_STATUS; - return 0; -} - -static void invalidate_toc(void) -{ - memset(cd->toc, 0, sizeof(cd->toc)); - memset(cd->disc_status, 0, sizeof(cd->disc_status)); -} - -/* cdrom.c guarantees that cdte_format == CDROM_MSF */ -static void get_toc_entry(struct cdrom_tocentry *ep) -{ - uch track = normalize_track(ep->cdte_track); - update_toc_entry(track); - ep->cdte_addr.msf.frame = cd->toc[track].fsm[0]; - ep->cdte_addr.msf.second = cd->toc[track].fsm[1]; - ep->cdte_addr.msf.minute = cd->toc[track].fsm[2]; - ep->cdte_adr = cd->toc[track].q0 & 0xf; - ep->cdte_ctrl = cd->toc[track].q0 >> 4; - ep->cdte_datamode = 0; -} - -/* Audio ioctl. Ioctl commands connected to audio are in such an - * idiosyncratic i/o format, that we leave these untouched. Return 0 - * upon success. Memory checking has been done by cdrom_ioctl(), the - * calling function, as well as LBA/MSF sanitization. -*/ -static int cm206_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, - void *arg) -{ - switch (cmd) { - case CDROMREADTOCHDR: - return read_toc_header((struct cdrom_tochdr *) arg); - case CDROMREADTOCENTRY: - get_toc_entry((struct cdrom_tocentry *) arg); - return 0; - case CDROMPLAYMSF: - play_from_to_msf((struct cdrom_msf *) arg); - return 0; - case CDROMPLAYTRKIND: /* admittedly, not particularly beautiful */ - play_from_to_track(((struct cdrom_ti *) arg)->cdti_trk0, - ((struct cdrom_ti *) arg)->cdti_trk1); - return 0; - case CDROMSTOP: - PAUSED = 0; - if (cd->dsb & dsb_play_in_progress) - return type_0_command(c_stop, 1); - else - return 0; - case CDROMPAUSE: - get_drive_status(); - if (cd->dsb & dsb_play_in_progress) { - type_0_command(c_stop, 1); - type_1_command(c_audio_status, 5, - cd->audio_status); - PAUSED = 1; /* say we're paused */ - } - return 0; - case CDROMRESUME: - if (PAUSED) - play_from_to_track(0, 0); - PAUSED = 0; - return 0; - case CDROMSTART: - case CDROMVOLCTRL: - return 0; - case CDROMSUBCHNL: - return get_current_q((struct cdrom_subchnl *) arg); - default: - return -EINVAL; - } -} - -static int cm206_media_changed(struct cdrom_device_info *cdi, int disc_nr) -{ - if (cd != NULL) { - int r; - get_drive_status(); /* ensure cd->media_changed OK */ - r = cd->media_changed; - cd->media_changed = 0; /* clear bit */ - return r; - } else - return -EIO; -} - -/* The new generic cdrom support. Routines should be concise, most of - the logic should be in cdrom.c */ - - -/* controls tray movement */ -static int cm206_tray_move(struct cdrom_device_info *cdi, int position) -{ - if (position) { /* 1: eject */ - type_0_command(c_open_tray, 1); - invalidate_toc(); - } else - type_0_command(c_close_tray, 1); /* 0: close */ - return 0; -} - -/* gives current state of the drive */ -static int cm206_drive_status(struct cdrom_device_info *cdi, int slot_nr) -{ - get_drive_status(); - if (cd->dsb & dsb_tray_not_closed) - return CDS_TRAY_OPEN; - if (!(cd->dsb & dsb_disc_present)) - return CDS_NO_DISC; - if (cd->dsb & dsb_drive_not_ready) - return CDS_DRIVE_NOT_READY; - return CDS_DISC_OK; -} - -/* locks or unlocks door lock==1: lock; return 0 upon success */ -static int cm206_lock_door(struct cdrom_device_info *cdi, int lock) -{ - uch command = (lock) ? c_lock_tray : c_unlock_tray; - type_0_command(command, 1); /* wait and get dsb */ - /* the logic calculates the success, 0 means successful */ - return lock ^ ((cd->dsb & dsb_tray_locked) != 0); -} - -/* Although a session start should be in LBA format, we return it in - MSF format because it is slightly easier, and the new generic ioctl - will take care of the necessary conversion. */ -static int cm206_get_last_session(struct cdrom_device_info *cdi, - struct cdrom_multisession *mssp) -{ - if (!FIRST_TRACK) - get_disc_status(); - if (mssp != NULL) { - if (DISC_STATUS & cds_multi_session) { /* multi-session */ - mssp->addr.msf.frame = cd->disc_status[3]; - mssp->addr.msf.second = cd->disc_status[4]; - mssp->addr.msf.minute = cd->disc_status[5]; - mssp->addr_format = CDROM_MSF; - mssp->xa_flag = 1; - } else { - mssp->xa_flag = 0; - } - return 1; - } - return 0; -} - -static int cm206_get_upc(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) -{ - uch upc[10]; - char *ret = mcn->medium_catalog_number; - int i; - - if (type_1_command(c_read_upc, 10, upc)) - return -EIO; - for (i = 0; i < 13; i++) { - int w = i / 2 + 1, r = i % 2; - if (r) - ret[i] = 0x30 | (upc[w] & 0x0f); - else - ret[i] = 0x30 | ((upc[w] >> 4) & 0x0f); - } - ret[13] = '\0'; - return 0; -} - -static int cm206_reset(struct cdrom_device_info *cdi) -{ - stop_read(); - reset_cm260(); - outw(dc_normal | dc_break | READ_AHEAD, r_data_control); - mdelay(1); /* 750 musec minimum */ - outw(dc_normal | READ_AHEAD, r_data_control); - cd->sector_last = -1; /* flag no data buffered */ - cd->adapter_last = -1; - invalidate_toc(); - return 0; -} - -static int cm206_select_speed(struct cdrom_device_info *cdi, int speed) -{ - int r; - switch (speed) { - case 0: - r = type_0_command(c_auto_mode, 1); - break; - case 1: - r = type_0_command(c_force_1x, 1); - break; - case 2: - r = type_0_command(c_force_2x, 1); - break; - default: - return -1; - } - if (r < 0) - return r; - else - return 1; -} - -static struct cdrom_device_ops cm206_dops = { - .open = cm206_open, - .release = cm206_release, - .drive_status = cm206_drive_status, - .media_changed = cm206_media_changed, - .tray_move = cm206_tray_move, - .lock_door = cm206_lock_door, - .select_speed = cm206_select_speed, - .get_last_session = cm206_get_last_session, - .get_mcn = cm206_get_upc, - .reset = cm206_reset, - .audio_ioctl = cm206_audio_ioctl, - .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | - CDC_MULTI_SESSION | CDC_MEDIA_CHANGED | - CDC_MCN | CDC_PLAY_AUDIO | CDC_SELECT_SPEED | - CDC_DRIVE_STATUS, - .n_minors = 1, -}; - - -static struct cdrom_device_info cm206_info = { - .ops = &cm206_dops, - .speed = 2, - .capacity = 1, - .name = "cm206", -}; - -static int cm206_block_open(struct inode *inode, struct file *file) -{ - return cdrom_open(&cm206_info, inode, file); -} - -static int cm206_block_release(struct inode *inode, struct file *file) -{ - return cdrom_release(&cm206_info, file); -} - -static int cm206_block_ioctl(struct inode *inode, struct file *file, - unsigned cmd, unsigned long arg) -{ - switch (cmd) { -#ifdef STATISTICS - case CM206CTL_GET_STAT: - if (arg >= NR_STATS) - return -EINVAL; - return cd->stats[arg]; - case CM206CTL_GET_LAST_STAT: - if (arg >= NR_STATS) - return -EINVAL; - return cd->last_stat[arg]; -#endif - default: - break; - } - - return cdrom_ioctl(file, &cm206_info, inode, cmd, arg); -} - -static int cm206_block_media_changed(struct gendisk *disk) -{ - return cdrom_media_changed(&cm206_info); -} - -static struct block_device_operations cm206_bdops = -{ - .owner = THIS_MODULE, - .open = cm206_block_open, - .release = cm206_block_release, - .ioctl = cm206_block_ioctl, - .media_changed = cm206_block_media_changed, -}; - -static struct gendisk *cm206_gendisk; - -/* This function probes for the adapter card. It returns the base - address if it has found the adapter card. One can specify a base - port to probe specifically, or 0 which means span all possible - bases. - - Linus says it is too dangerous to use writes for probing, so we - stick with pure reads for a while. Hope that 8 possible ranges, - request_region, 15 bits of one port and 6 of another make things - likely enough to accept the region on the first hit... - */ -static int __init probe_base_port(int base) -{ - int b = 0x300, e = 0x370; /* this is the range of start addresses */ - volatile int fool, i; - - if (base) - b = e = base; - for (base = b; base <= e; base += 0x10) { - if (!request_region(base, 0x10,"cm206")) - continue; - for (i = 0; i < 3; i++) - fool = inw(base + 2); /* empty possibly uart_receive_buffer */ - if ((inw(base + 6) & 0xffef) != 0x0001 || /* line_status */ - (inw(base) & 0xad00) != 0) { /* data status */ - release_region(base,0x10); - continue; - } - return (base); - } - return 0; -} - -#if !defined(MODULE) || defined(AUTO_PROBE_MODULE) -/* Probe for irq# nr. If nr==0, probe for all possible irq's. */ -static int __init probe_irq(int nr) -{ - int irqs, irq; - outw(dc_normal | READ_AHEAD, r_data_control); /* disable irq-generation */ - sti(); - irqs = probe_irq_on(); - reset_cm260(); /* causes interrupt */ - udelay(100); /* wait for it */ - irq = probe_irq_off(irqs); - outw(dc_normal | READ_AHEAD, r_data_control); /* services interrupt */ - if (nr && irq != nr && irq > 0) - return 0; /* wrong interrupt happened */ - else - return irq; -} -#endif - -int __init cm206_init(void) -{ - uch e = 0; - long int size = sizeof(struct cm206_struct); - struct gendisk *disk; - - printk(KERN_INFO "cm206 cdrom driver " REVISION); - cm206_base = probe_base_port(auto_probe ? 0 : cm206_base); - if (!cm206_base) { - printk(" can't find adapter!\n"); - return -EIO; - } - printk(" adapter at 0x%x", cm206_base); - cd = kmalloc(size, GFP_KERNEL); - if (!cd) - goto out_base; - /* Now we have found the adaptor card, try to reset it. As we have - * found out earlier, this process generates an interrupt as well, - * so we might just exploit that fact for irq probing! */ -#if !defined(MODULE) || defined(AUTO_PROBE_MODULE) - cm206_irq = probe_irq(auto_probe ? 0 : cm206_irq); - if (cm206_irq <= 0) { - printk("can't find IRQ!\n"); - goto out_probe; - } else - printk(" IRQ %d found\n", cm206_irq); -#else - cli(); - reset_cm260(); - /* Now, the problem here is that reset_cm260 can generate an - interrupt. It seems that this can cause a kernel oops some time - later. So we wait a while and `service' this interrupt. */ - mdelay(1); - outw(dc_normal | READ_AHEAD, r_data_control); - sti(); - printk(" using IRQ %d\n", cm206_irq); -#endif - if (send_receive_polled(c_drive_configuration) != - c_drive_configuration) { - printk(KERN_INFO " drive not there\n"); - goto out_probe; - } - e = send_receive_polled(c_gimme); - printk(KERN_INFO "Firmware revision %d", e & dcf_revision_code); - if (e & dcf_transfer_rate) - printk(" double"); - else - printk(" single"); - printk(" speed drive"); - if (e & dcf_motorized_tray) - printk(", motorized tray"); - if (request_irq(cm206_irq, cm206_interrupt, 0, "cm206", NULL)) { - printk("\nUnable to reserve IRQ---aborted\n"); - goto out_probe; - } - printk(".\n"); - - if (register_blkdev(MAJOR_NR, "cm206")) - goto out_blkdev; - - disk = alloc_disk(1); - if (!disk) - goto out_disk; - disk->major = MAJOR_NR; - disk->first_minor = 0; - sprintf(disk->disk_name, "cm206cd"); - disk->fops = &cm206_bdops; - disk->flags = GENHD_FL_CD; - cm206_gendisk = disk; - if (register_cdrom(&cm206_info) != 0) { - printk(KERN_INFO "Cannot register for cdrom %d!\n", MAJOR_NR); - goto out_cdrom; - } - cm206_queue = blk_init_queue(do_cm206_request, &cm206_lock); - if (!cm206_queue) - goto out_queue; - - blk_queue_hardsect_size(cm206_queue, 2048); - disk->queue = cm206_queue; - add_disk(disk); - - memset(cd, 0, sizeof(*cd)); /* give'm some reasonable value */ - cd->sector_last = -1; /* flag no data buffered */ - cd->adapter_last = -1; - init_timer(&cd->timer); - cd->timer.function = cm206_timeout; - cd->max_sectors = (inw(r_data_status) & ds_ram_size) ? 24 : 97; - printk(KERN_INFO "%d kB adapter memory available, " - " %ld bytes kernel memory used.\n", cd->max_sectors * 2, - size); - return 0; - -out_queue: - unregister_cdrom(&cm206_info); -out_cdrom: - put_disk(disk); -out_disk: - unregister_blkdev(MAJOR_NR, "cm206"); -out_blkdev: - free_irq(cm206_irq, NULL); -out_probe: - kfree(cd); -out_base: - release_region(cm206_base, 16); - return -EIO; -} - -#ifdef MODULE - - -static void __init parse_options(void) -{ - int i; - for (i = 0; i < 2; i++) { - if (0x300 <= cm206[i] && i <= 0x370 - && cm206[i] % 0x10 == 0) { - cm206_base = cm206[i]; - auto_probe = 0; - } else if (3 <= cm206[i] && cm206[i] <= 15) { - cm206_irq = cm206[i]; - auto_probe = 0; - } - } -} - -static int __init __cm206_init(void) -{ - parse_options(); -#if !defined(AUTO_PROBE_MODULE) - auto_probe = 0; -#endif - return cm206_init(); -} - -static void __exit cm206_exit(void) -{ - del_gendisk(cm206_gendisk); - put_disk(cm206_gendisk); - if (unregister_cdrom(&cm206_info)) { - printk("Can't unregister cdrom cm206\n"); - return; - } - if (unregister_blkdev(MAJOR_NR, "cm206")) { - printk("Can't unregister major cm206\n"); - return; - } - blk_cleanup_queue(cm206_queue); - free_irq(cm206_irq, NULL); - kfree(cd); - release_region(cm206_base, 16); - printk(KERN_INFO "cm206 removed\n"); -} - -module_init(__cm206_init); -module_exit(cm206_exit); - -#else /* !MODULE */ - -/* This setup function accepts either `auto' or numbers in the range - * 3--11 (for irq) or 0x300--0x370 (for base port) or both. */ - -static int __init cm206_setup(char *s) -{ - int i, p[4]; - - (void) get_options(s, ARRAY_SIZE(p), p); - - if (!strcmp(s, "auto")) - auto_probe = 1; - for (i = 1; i <= p[0]; i++) { - if (0x300 <= p[i] && i <= 0x370 && p[i] % 0x10 == 0) { - cm206_base = p[i]; - auto_probe = 0; - } else if (3 <= p[i] && p[i] <= 15) { - cm206_irq = p[i]; - auto_probe = 0; - } - } - return 1; -} - -__setup("cm206=", cm206_setup); - -#endif /* !MODULE */ -MODULE_ALIAS_BLOCKDEV_MAJOR(CM206_CDROM_MAJOR); - diff --git a/drivers/cdrom/cm206.h b/drivers/cdrom/cm206.h deleted file mode 100644 index 0ae51c1a0dac..000000000000 --- a/drivers/cdrom/cm206.h +++ /dev/null @@ -1,171 +0,0 @@ -/* cm206.h Header file for cm206.c. - Copyright (c) 1995 David van Leeuwen -*/ - -#ifndef LINUX_CM206_H -#define LINUX_CM206_H - -#include - -/* First, the cm260 stuff */ -/* The ports and irq used. Although CM206_BASE and CM206_IRQ are defined - below, the values are not used unless autoprobing is turned off and - no LILO boot options or module command line options are given. Change - these values to your own as last resort if autoprobing and options - don't work. */ - -#define CM206_BASE 0x340 -#define CM206_IRQ 11 - -#define r_data_status (cm206_base) -#define r_uart_receive (cm206_base+0x2) -#define r_fifo_output_buffer (cm206_base+0x4) -#define r_line_status (cm206_base+0x6) -#define r_data_control (cm206_base+0x8) -#define r_uart_transmit (cm206_base+0xa) -#define r_test_clock (cm206_base+0xc) -#define r_test_control (cm206_base+0xe) - -/* the data_status flags */ -#define ds_ram_size 0x4000 -#define ds_toc_ready 0x2000 -#define ds_fifo_empty 0x1000 -#define ds_sync_error 0x800 -#define ds_crc_error 0x400 -#define ds_data_error 0x200 -#define ds_fifo_overflow 0x100 -#define ds_data_ready 0x80 - -/* the line_status flags */ -#define ls_attention 0x10 -#define ls_parity_error 0x8 -#define ls_overrun 0x4 -#define ls_receive_buffer_full 0x2 -#define ls_transmitter_buffer_empty 0x1 - -/* the data control register flags */ -#define dc_read_q_channel 0x4000 -#define dc_mask_sync_error 0x2000 -#define dc_toc_enable 0x1000 -#define dc_no_stop_on_error 0x800 -#define dc_break 0x400 -#define dc_initialize 0x200 -#define dc_mask_transmit_ready 0x100 -#define dc_flag_enable 0x80 - -/* Define the default data control register flags here */ -#define dc_normal (dc_mask_sync_error | dc_no_stop_on_error | \ - dc_mask_transmit_ready) - -/* now some constants related to the cm206 */ -/* another drive status byte, echoed by the cm206 on most commands */ - -#define dsb_error_condition 0x1 -#define dsb_play_in_progress 0x4 -#define dsb_possible_media_change 0x8 -#define dsb_disc_present 0x10 -#define dsb_drive_not_ready 0x20 -#define dsb_tray_locked 0x40 -#define dsb_tray_not_closed 0x80 - -#define dsb_not_useful (dsb_drive_not_ready | dsb_tray_not_closed) - -/* the cm206 command set */ - -#define c_close_tray 0 -#define c_lock_tray 0x01 -#define c_unlock_tray 0x04 -#define c_open_tray 0x05 -#define c_seek 0x10 -#define c_read_data 0x20 -#define c_force_1x 0x21 -#define c_force_2x 0x22 -#define c_auto_mode 0x23 -#define c_play 0x30 -#define c_set_audio_mode 0x31 -#define c_read_current_q 0x41 -#define c_stream_q 0x42 -#define c_drive_status 0x50 -#define c_disc_status 0x51 -#define c_audio_status 0x52 -#define c_drive_configuration 0x53 -#define c_read_upc 0x60 -#define c_stop 0x70 -#define c_calc_checksum 0xe5 - -#define c_gimme 0xf8 - -/* finally, the (error) condition that the drive can be in * - * OK, this is not always an error, but let's prefix it with e_ */ - -#define e_none 0 -#define e_illegal_command 0x01 -#define e_sync 0x02 -#define e_seek 0x03 -#define e_parity 0x04 -#define e_focus 0x05 -#define e_header_sync 0x06 -#define e_code_incompatibility 0x07 -#define e_reset_done 0x08 -#define e_bad_parameter 0x09 -#define e_radial 0x0a -#define e_sub_code 0x0b -#define e_no_data_track 0x0c -#define e_scan 0x0d -#define e_tray_open 0x0f -#define e_no_disc 0x10 -#define e_tray stalled 0x11 - -/* drive configuration masks */ - -#define dcf_revision_code 0x7 -#define dcf_transfer_rate 0x60 -#define dcf_motorized_tray 0x80 - -/* disc status byte */ - -#define cds_multi_session 0x2 -#define cds_all_audio 0x8 -#define cds_xa_mode 0xf0 - -/* finally some ioctls for the driver */ - -#define CM206CTL_GET_STAT _IO( 0x20, 0 ) -#define CM206CTL_GET_LAST_STAT _IO( 0x20, 1 ) - -#ifdef STATISTICS - -/* This is an ugly way to guarantee that the names of the statistics - * are the same in the code and in the diagnostics program. */ - -#ifdef __KERNEL__ -#define x(a) st_ ## a -#define y enum -#else -#define x(a) #a -#define y char * stats_name[] = -#endif - -y {x(interrupt), x(data_ready), x(fifo_overflow), x(data_error), - x(crc_error), x(sync_error), x(lost_intr), x(echo), - x(write_timeout), x(receive_timeout), x(read_timeout), - x(dsb_timeout), x(stop_0xff), x(back_read_timeout), - x(sector_transferred), x(read_restarted), x(read_background), - x(bh), x(open), x(ioctl_multisession), x(attention) -#ifdef __KERNEL__ - , x(last_entry) -#endif - }; - -#ifdef __KERNEL__ -#define NR_STATS st_last_entry -#else -#define NR_STATS (sizeof(stats_name)/sizeof(char*)) -#endif - -#undef y -#undef x - -#endif /* STATISTICS */ - -#endif /* LINUX_CM206_H */ diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c deleted file mode 100644 index 176742ed007b..000000000000 --- a/drivers/cdrom/gscd.c +++ /dev/null @@ -1,1029 +0,0 @@ -#define GSCD_VERSION "0.4a Oliver Raupach " - -/* - linux/drivers/block/gscd.c - GoldStar R420 CDROM driver - - Copyright (C) 1995 Oliver Raupach - based upon pre-works by Eberhard Moenkeberg - - - For all kind of other information about the GoldStar CDROM - and this Linux device driver I installed a WWW-URL: - http://linux.rz.fh-hannover.de/~raupach - - - If you are the editor of a Linux CD, you should - enable gscd.c within your boot floppy kernel and - send me one of your CDs for free. - - - -------------------------------------------------------------------- - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - -------------------------------------------------------------------- - - 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x - Removed init_module & cleanup_module in favor of - module_init & module_exit. - Torben Mathiasen - -*/ - -/* These settings are for various debug-level. Leave they untouched ... */ -#define NO_GSCD_DEBUG -#define NO_IOCTL_DEBUG -#define NO_MODULE_DEBUG -#define NO_FUTURE_WORK -/*------------------------*/ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define MAJOR_NR GOLDSTAR_CDROM_MAJOR -#include -#include "gscd.h" - -static int gscdPresent = 0; - -static unsigned char gscd_buf[2048]; /* buffer for block size conversion */ -static int gscd_bn = -1; -static short gscd_port = GSCD_BASE_ADDR; -module_param_named(gscd, gscd_port, short, 0); - -/* Kommt spaeter vielleicht noch mal dran ... - * static DECLARE_WAIT_QUEUE_HEAD(gscd_waitq); - */ - -static void gscd_read_cmd(struct request *req); -static void gscd_hsg2msf(long hsg, struct msf *msf); -static void gscd_bin2bcd(unsigned char *p); - -/* Schnittstellen zum Kern/FS */ - -static void __do_gscd_request(unsigned long dummy); -static int gscd_ioctl(struct inode *, struct file *, unsigned int, - unsigned long); -static int gscd_open(struct inode *, struct file *); -static int gscd_release(struct inode *, struct file *); -static int check_gscd_med_chg(struct gendisk *disk); - -/* GoldStar Funktionen */ - -static void cmd_out(int, char *, char *, int); -static void cmd_status(void); -static void init_cd_drive(int); - -static int get_status(void); -static void clear_Audio(void); -static void cc_invalidate(void); - -/* some things for the next version */ -#ifdef FUTURE_WORK -static void update_state(void); -static long gscd_msf2hsg(struct msf *mp); -static int gscd_bcd2bin(unsigned char bcd); -#endif - - -/* lo-level cmd-Funktionen */ - -static void cmd_info_in(char *, int); -static void cmd_end(void); -static void cmd_read_b(char *, int, int); -static void cmd_read_w(char *, int, int); -static int cmd_unit_alive(void); -static void cmd_write_cmd(char *); - - -/* GoldStar Variablen */ - -static int curr_drv_state; -static int drv_states[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; -static int drv_mode; -static int disk_state; -static int speed; -static int ndrives; - -static unsigned char drv_num_read; -static unsigned char f_dsk_valid; -static unsigned char current_drive; -static unsigned char f_drv_ok; - - -static char f_AudioPlay; -static char f_AudioPause; -static int AudioStart_m; -static int AudioStart_f; -static int AudioEnd_m; -static int AudioEnd_f; - -static DEFINE_TIMER(gscd_timer, NULL, 0, 0); -static DEFINE_SPINLOCK(gscd_lock); -static struct request_queue *gscd_queue; - -static struct block_device_operations gscd_fops = { - .owner = THIS_MODULE, - .open = gscd_open, - .release = gscd_release, - .ioctl = gscd_ioctl, - .media_changed = check_gscd_med_chg, -}; - -/* - * Checking if the media has been changed - * (not yet implemented) - */ -static int check_gscd_med_chg(struct gendisk *disk) -{ -#ifdef GSCD_DEBUG - printk("gscd: check_med_change\n"); -#endif - return 0; -} - - -#ifndef MODULE -/* Using new interface for kernel-parameters */ - -static int __init gscd_setup(char *str) -{ - int ints[2]; - (void) get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) { - gscd_port = ints[1]; - } - return 1; -} - -__setup("gscd=", gscd_setup); - -#endif - -static int gscd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, - unsigned long arg) -{ - unsigned char to_do[10]; - unsigned char dummy; - - - switch (cmd) { - case CDROMSTART: /* Spin up the drive */ - /* Don't think we can do this. Even if we could, - * I think the drive times out and stops after a while - * anyway. For now, ignore it. - */ - return 0; - - case CDROMRESUME: /* keine Ahnung was das ist */ - return 0; - - - case CDROMEJECT: - cmd_status(); - to_do[0] = CMD_TRAY_CTL; - cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); - - return 0; - - default: - return -EINVAL; - } - -} - - -/* - * Take care of the different block sizes between cdrom and Linux. - * When Linux gets variable block sizes this will probably go away. - */ - -static void gscd_transfer(struct request *req) -{ - while (req->nr_sectors > 0 && gscd_bn == req->sector / 4) { - long offs = (req->sector & 3) * 512; - memcpy(req->buffer, gscd_buf + offs, 512); - req->nr_sectors--; - req->sector++; - req->buffer += 512; - } -} - - -/* - * I/O request routine called from Linux kernel. - */ - -static void do_gscd_request(request_queue_t * q) -{ - __do_gscd_request(0); -} - -static void __do_gscd_request(unsigned long dummy) -{ - struct request *req; - unsigned int block; - unsigned int nsect; - -repeat: - req = elv_next_request(gscd_queue); - if (!req) - return; - - block = req->sector; - nsect = req->nr_sectors; - - if (req->sector == -1) - goto out; - - if (rq_data_dir(req) != READ) { - printk("GSCD: bad cmd %u\n", rq_data_dir(req)); - end_request(req, 0); - goto repeat; - } - - gscd_transfer(req); - - /* if we satisfied the request from the buffer, we're done. */ - - if (req->nr_sectors == 0) { - end_request(req, 1); - goto repeat; - } -#ifdef GSCD_DEBUG - printk("GSCD: block %d, nsect %d\n", block, nsect); -#endif - gscd_read_cmd(req); -out: - return; -} - - - -/* - * Check the result of the set-mode command. On success, send the - * read-data command. - */ - -static void gscd_read_cmd(struct request *req) -{ - long block; - struct gscd_Play_msf gscdcmd; - char cmd[] = { CMD_READ, 0x80, 0, 0, 0, 0, 1 }; /* cmd mode M-S-F secth sectl */ - - cmd_status(); - if (disk_state & (ST_NO_DISK | ST_DOOR_OPEN)) { - printk("GSCD: no disk or door open\n"); - end_request(req, 0); - } else { - if (disk_state & ST_INVALID) { - printk("GSCD: disk invalid\n"); - end_request(req, 0); - } else { - gscd_bn = -1; /* purge our buffer */ - block = req->sector / 4; - gscd_hsg2msf(block, &gscdcmd.start); /* cvt to msf format */ - - cmd[2] = gscdcmd.start.min; - cmd[3] = gscdcmd.start.sec; - cmd[4] = gscdcmd.start.frame; - -#ifdef GSCD_DEBUG - printk("GSCD: read msf %d:%d:%d\n", cmd[2], cmd[3], - cmd[4]); -#endif - cmd_out(TYPE_DATA, (char *) &cmd, - (char *) &gscd_buf[0], 1); - - gscd_bn = req->sector / 4; - gscd_transfer(req); - end_request(req, 1); - } - } - SET_TIMER(__do_gscd_request, 1); -} - - -/* - * Open the device special file. Check that a disk is in. - */ - -static int gscd_open(struct inode *ip, struct file *fp) -{ - int st; - -#ifdef GSCD_DEBUG - printk("GSCD: open\n"); -#endif - - if (gscdPresent == 0) - return -ENXIO; /* no hardware */ - - get_status(); - st = disk_state & (ST_NO_DISK | ST_DOOR_OPEN); - if (st) { - printk("GSCD: no disk or door open\n"); - return -ENXIO; - } - -/* if (updateToc() < 0) - return -EIO; -*/ - - return 0; -} - - -/* - * On close, we flush all gscd blocks from the buffer cache. - */ - -static int gscd_release(struct inode *inode, struct file *file) -{ - -#ifdef GSCD_DEBUG - printk("GSCD: release\n"); -#endif - - gscd_bn = -1; - - return 0; -} - - -static int get_status(void) -{ - int status; - - cmd_status(); - status = disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01); - - if (status == (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) { - cc_invalidate(); - return 1; - } else { - return 0; - } -} - - -static void cc_invalidate(void) -{ - drv_num_read = 0xFF; - f_dsk_valid = 0xFF; - current_drive = 0xFF; - f_drv_ok = 0xFF; - - clear_Audio(); - -} - -static void clear_Audio(void) -{ - - f_AudioPlay = 0; - f_AudioPause = 0; - AudioStart_m = 0; - AudioStart_f = 0; - AudioEnd_m = 0; - AudioEnd_f = 0; - -} - -/* - * waiting ? - */ - -static int wait_drv_ready(void) -{ - int found, read; - - do { - found = inb(GSCDPORT(0)); - found &= 0x0f; - read = inb(GSCDPORT(0)); - read &= 0x0f; - } while (read != found); - -#ifdef GSCD_DEBUG - printk("Wait for: %d\n", read); -#endif - - return read; -} - -static void cc_Ident(char *respons) -{ - char to_do[] = { CMD_IDENT, 0, 0 }; - - cmd_out(TYPE_INFO, (char *) &to_do, (char *) respons, (int) 0x1E); - -} - -static void cc_SetSpeed(void) -{ - char to_do[] = { CMD_SETSPEED, 0, 0 }; - char dummy; - - if (speed > 0) { - to_do[1] = speed & 0x0F; - cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); - } -} - -static void cc_Reset(void) -{ - char to_do[] = { CMD_RESET, 0 }; - char dummy; - - cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); -} - -static void cmd_status(void) -{ - char to_do[] = { CMD_STATUS, 0 }; - char dummy; - - cmd_out(TYPE_INFO, (char *) &to_do, (char *) &dummy, 0); - -#ifdef GSCD_DEBUG - printk("GSCD: Status: %d\n", disk_state); -#endif - -} - -static void cmd_out(int cmd_type, char *cmd, char *respo_buf, int respo_count) -{ - int result; - - - result = wait_drv_ready(); - if (result != drv_mode) { - unsigned long test_loops = 0xFFFF; - int i, dummy; - - outb(curr_drv_state, GSCDPORT(0)); - - /* LOCLOOP_170 */ - do { - result = wait_drv_ready(); - test_loops--; - } while ((result != drv_mode) && (test_loops > 0)); - - if (result != drv_mode) { - disk_state = ST_x08 | ST_x04 | ST_INVALID; - return; - } - - /* ...and waiting */ - for (i = 1, dummy = 1; i < 0xFFFF; i++) { - dummy *= i; - } - } - - /* LOC_172 */ - /* check the unit */ - /* and wake it up */ - if (cmd_unit_alive() != 0x08) { - /* LOC_174 */ - /* game over for this unit */ - disk_state = ST_x08 | ST_x04 | ST_INVALID; - return; - } - - /* LOC_176 */ -#ifdef GSCD_DEBUG - printk("LOC_176 "); -#endif - if (drv_mode == 0x09) { - /* magic... */ - printk("GSCD: magic ...\n"); - outb(result, GSCDPORT(2)); - } - - /* write the command to the drive */ - cmd_write_cmd(cmd); - - /* LOC_178 */ - for (;;) { - result = wait_drv_ready(); - if (result != drv_mode) { - /* LOC_179 */ - if (result == 0x04) { /* Mode 4 */ - /* LOC_205 */ -#ifdef GSCD_DEBUG - printk("LOC_205 "); -#endif - disk_state = inb(GSCDPORT(2)); - - do { - result = wait_drv_ready(); - } while (result != drv_mode); - return; - - } else { - if (result == 0x06) { /* Mode 6 */ - /* LOC_181 */ -#ifdef GSCD_DEBUG - printk("LOC_181 "); -#endif - - if (cmd_type == TYPE_DATA) { - /* read data */ - /* LOC_184 */ - if (drv_mode == 9) { - /* read the data to the buffer (word) */ - - /* (*(cmd+1))?(CD_FRAMESIZE/2):(CD_FRAMESIZE_RAW/2) */ - cmd_read_w - (respo_buf, - respo_count, - CD_FRAMESIZE / - 2); - return; - } else { - /* read the data to the buffer (byte) */ - - /* (*(cmd+1))?(CD_FRAMESIZE):(CD_FRAMESIZE_RAW) */ - cmd_read_b - (respo_buf, - respo_count, - CD_FRAMESIZE); - return; - } - } else { - /* read the info to the buffer */ - cmd_info_in(respo_buf, - respo_count); - return; - } - - return; - } - } - - } else { - disk_state = ST_x08 | ST_x04 | ST_INVALID; - return; - } - } /* for (;;) */ - - -#ifdef GSCD_DEBUG - printk("\n"); -#endif -} - - -static void cmd_write_cmd(char *pstr) -{ - int i, j; - - /* LOC_177 */ -#ifdef GSCD_DEBUG - printk("LOC_177 "); -#endif - - /* calculate the number of parameter */ - j = *pstr & 0x0F; - - /* shift it out */ - for (i = 0; i < j; i++) { - outb(*pstr, GSCDPORT(2)); - pstr++; - } -} - - -static int cmd_unit_alive(void) -{ - int result; - unsigned long max_test_loops; - - - /* LOC_172 */ -#ifdef GSCD_DEBUG - printk("LOC_172 "); -#endif - - outb(curr_drv_state, GSCDPORT(0)); - max_test_loops = 0xFFFF; - - do { - result = wait_drv_ready(); - max_test_loops--; - } while ((result != 0x08) && (max_test_loops > 0)); - - return result; -} - - -static void cmd_info_in(char *pb, int count) -{ - int result; - char read; - - - /* read info */ - /* LOC_182 */ -#ifdef GSCD_DEBUG - printk("LOC_182 "); -#endif - - do { - read = inb(GSCDPORT(2)); - if (count > 0) { - *pb = read; - pb++; - count--; - } - - /* LOC_183 */ - do { - result = wait_drv_ready(); - } while (result == 0x0E); - } while (result == 6); - - cmd_end(); - return; -} - - -static void cmd_read_b(char *pb, int count, int size) -{ - int result; - int i; - - - /* LOC_188 */ - /* LOC_189 */ -#ifdef GSCD_DEBUG - printk("LOC_189 "); -#endif - - do { - do { - result = wait_drv_ready(); - } while (result != 6 || result == 0x0E); - - if (result != 6) { - cmd_end(); - return; - } -#ifdef GSCD_DEBUG - printk("LOC_191 "); -#endif - - for (i = 0; i < size; i++) { - *pb = inb(GSCDPORT(2)); - pb++; - } - count--; - } while (count > 0); - - cmd_end(); - return; -} - - -static void cmd_end(void) -{ - int result; - - - /* LOC_204 */ -#ifdef GSCD_DEBUG - printk("LOC_204 "); -#endif - - do { - result = wait_drv_ready(); - if (result == drv_mode) { - return; - } - } while (result != 4); - - /* LOC_205 */ -#ifdef GSCD_DEBUG - printk("LOC_205 "); -#endif - - disk_state = inb(GSCDPORT(2)); - - do { - result = wait_drv_ready(); - } while (result != drv_mode); - return; - -} - - -static void cmd_read_w(char *pb, int count, int size) -{ - int result; - int i; - - -#ifdef GSCD_DEBUG - printk("LOC_185 "); -#endif - - do { - /* LOC_185 */ - do { - result = wait_drv_ready(); - } while (result != 6 || result == 0x0E); - - if (result != 6) { - cmd_end(); - return; - } - - for (i = 0; i < size; i++) { - /* na, hier muss ich noch mal drueber nachdenken */ - *pb = inw(GSCDPORT(2)); - pb++; - } - count--; - } while (count > 0); - - cmd_end(); - return; -} - -static int __init find_drives(void) -{ - int *pdrv; - int drvnum; - int subdrv; - int i; - - speed = 0; - pdrv = (int *) &drv_states; - curr_drv_state = 0xFE; - subdrv = 0; - drvnum = 0; - - for (i = 0; i < 8; i++) { - subdrv++; - cmd_status(); - disk_state &= ST_x08 | ST_x04 | ST_INVALID | ST_x01; - if (disk_state != (ST_x08 | ST_x04 | ST_INVALID)) { - /* LOC_240 */ - *pdrv = curr_drv_state; - init_cd_drive(drvnum); - pdrv++; - drvnum++; - } else { - if (subdrv < 2) { - continue; - } else { - subdrv = 0; - } - } - -/* curr_drv_state<<1; <-- das geht irgendwie nicht */ -/* muss heissen: curr_drv_state <<= 1; (ist ja Wert-Zuweisung) */ - curr_drv_state *= 2; - curr_drv_state |= 1; -#ifdef GSCD_DEBUG - printk("DriveState: %d\n", curr_drv_state); -#endif - } - - ndrives = drvnum; - return drvnum; -} - -static void __init init_cd_drive(int num) -{ - char resp[50]; - int i; - - printk("GSCD: init unit %d\n", num); - cc_Ident((char *) &resp); - - printk("GSCD: identification: "); - for (i = 0; i < 0x1E; i++) { - printk("%c", resp[i]); - } - printk("\n"); - - cc_SetSpeed(); - -} - -#ifdef FUTURE_WORK -/* return_done */ -static void update_state(void) -{ - unsigned int AX; - - - if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) == 0) { - if (disk_state == (ST_x08 | ST_x04 | ST_INVALID)) { - AX = ST_INVALID; - } - - if ((disk_state & (ST_x08 | ST_x04 | ST_INVALID | ST_x01)) - == 0) { - invalidate(); - f_drv_ok = 0; - } - - AX |= 0x8000; - } - - if (disk_state & ST_PLAYING) { - AX |= 0x200; - } - - AX |= 0x100; - /* pkt_esbx = AX; */ - - disk_state = 0; - -} -#endif - -static struct gendisk *gscd_disk; - -static void __exit gscd_exit(void) -{ - CLEAR_TIMER; - - del_gendisk(gscd_disk); - put_disk(gscd_disk); - if ((unregister_blkdev(MAJOR_NR, "gscd") == -EINVAL)) { - printk("What's that: can't unregister GoldStar-module\n"); - return; - } - blk_cleanup_queue(gscd_queue); - release_region(gscd_port, GSCD_IO_EXTENT); - printk(KERN_INFO "GoldStar-module released.\n"); -} - -/* This is the common initialisation for the GoldStar drive. */ -/* It is called at boot time AND for module init. */ -static int __init gscd_init(void) -{ - int i; - int result; - int ret=0; - - printk(KERN_INFO "GSCD: version %s\n", GSCD_VERSION); - printk(KERN_INFO - "GSCD: Trying to detect a Goldstar R420 CD-ROM drive at 0x%X.\n", - gscd_port); - - if (!request_region(gscd_port, GSCD_IO_EXTENT, "gscd")) { - printk(KERN_WARNING "GSCD: Init failed, I/O port (%X) already" - " in use.\n", gscd_port); - return -EIO; - } - - - /* check for card */ - result = wait_drv_ready(); - if (result == 0x09) { - printk(KERN_WARNING "GSCD: DMA kann ich noch nicht!\n"); - ret = -EIO; - goto err_out1; - } - - if (result == 0x0b) { - drv_mode = result; - i = find_drives(); - if (i == 0) { - printk(KERN_WARNING "GSCD: GoldStar CD-ROM Drive is" - " not found.\n"); - ret = -EIO; - goto err_out1; - } - } - - if ((result != 0x0b) && (result != 0x09)) { - printk(KERN_WARNING "GSCD: GoldStar Interface Adapter does not " - "exist or H/W error\n"); - ret = -EIO; - goto err_out1; - } - - /* reset all drives */ - i = 0; - while (drv_states[i] != 0) { - curr_drv_state = drv_states[i]; - printk(KERN_INFO "GSCD: Reset unit %d ... ", i); - cc_Reset(); - printk("done\n"); - i++; - } - - gscd_disk = alloc_disk(1); - if (!gscd_disk) - goto err_out1; - gscd_disk->major = MAJOR_NR; - gscd_disk->first_minor = 0; - gscd_disk->fops = &gscd_fops; - sprintf(gscd_disk->disk_name, "gscd"); - - if (register_blkdev(MAJOR_NR, "gscd")) { - ret = -EIO; - goto err_out2; - } - - gscd_queue = blk_init_queue(do_gscd_request, &gscd_lock); - if (!gscd_queue) { - ret = -ENOMEM; - goto err_out3; - } - - disk_state = 0; - gscdPresent = 1; - - gscd_disk->queue = gscd_queue; - add_disk(gscd_disk); - - printk(KERN_INFO "GSCD: GoldStar CD-ROM Drive found.\n"); - return 0; - -err_out3: - unregister_blkdev(MAJOR_NR, "gscd"); -err_out2: - put_disk(gscd_disk); -err_out1: - release_region(gscd_port, GSCD_IO_EXTENT); - return ret; -} - -static void gscd_hsg2msf(long hsg, struct msf *msf) -{ - hsg += CD_MSF_OFFSET; - msf->min = hsg / (CD_FRAMES * CD_SECS); - hsg %= CD_FRAMES * CD_SECS; - msf->sec = hsg / CD_FRAMES; - msf->frame = hsg % CD_FRAMES; - - gscd_bin2bcd(&msf->min); /* convert to BCD */ - gscd_bin2bcd(&msf->sec); - gscd_bin2bcd(&msf->frame); -} - - -static void gscd_bin2bcd(unsigned char *p) -{ - int u, t; - - u = *p % 10; - t = *p / 10; - *p = u | (t << 4); -} - - -#ifdef FUTURE_WORK -static long gscd_msf2hsg(struct msf *mp) -{ - return gscd_bcd2bin(mp->frame) - + gscd_bcd2bin(mp->sec) * CD_FRAMES - + gscd_bcd2bin(mp->min) * CD_FRAMES * CD_SECS - CD_MSF_OFFSET; -} - -static int gscd_bcd2bin(unsigned char bcd) -{ - return (bcd >> 4) * 10 + (bcd & 0xF); -} -#endif - -MODULE_AUTHOR("Oliver Raupach "); -MODULE_LICENSE("GPL"); -module_init(gscd_init); -module_exit(gscd_exit); -MODULE_ALIAS_BLOCKDEV_MAJOR(GOLDSTAR_CDROM_MAJOR); diff --git a/drivers/cdrom/gscd.h b/drivers/cdrom/gscd.h deleted file mode 100644 index a41e64bfc061..000000000000 --- a/drivers/cdrom/gscd.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Definitions for a GoldStar R420 CD-ROM interface - * - * Copyright (C) 1995 Oliver Raupach - * Eberhard Moenkeberg - * - * Published under the GPL. - * - */ - - -/* The Interface Card default address is 0x340. This will work for most - applications. Address selection is accomplished by jumpers PN801-1 to - PN801-4 on the GoldStar Interface Card. - Appropriate settings are: 0x300, 0x310, 0x320, 0x330, 0x340, 0x350, 0x360 - 0x370, 0x380, 0x390, 0x3A0, 0x3B0, 0x3C0, 0x3D0, 0x3E0, 0x3F0 */ - -/* insert here the I/O port address and extent */ -#define GSCD_BASE_ADDR 0x340 -#define GSCD_IO_EXTENT 4 - - -/************** nothing to set up below here *********************/ - -/* port access macro */ -#define GSCDPORT(x) (gscd_port + (x)) - -/* - * commands - * the lower nibble holds the command length - */ -#define CMD_STATUS 0x01 -#define CMD_READSUBQ 0x02 /* 1: ?, 2: UPC, 5: ? */ -#define CMD_SEEK 0x05 /* read_mode M-S-F */ -#define CMD_READ 0x07 /* read_mode M-S-F nsec_h nsec_l */ -#define CMD_RESET 0x11 -#define CMD_SETMODE 0x15 -#define CMD_PLAY 0x17 /* M-S-F M-S-F */ -#define CMD_LOCK_CTL 0x22 /* 0: unlock, 1: lock */ -#define CMD_IDENT 0x31 -#define CMD_SETSPEED 0x32 /* 0: auto */ /* ??? */ -#define CMD_GETMODE 0x41 -#define CMD_PAUSE 0x51 -#define CMD_READTOC 0x61 -#define CMD_DISKINFO 0x71 -#define CMD_TRAY_CTL 0x81 - -/* - * disk_state: - */ -#define ST_PLAYING 0x80 -#define ST_UNLOCKED 0x40 -#define ST_NO_DISK 0x20 -#define ST_DOOR_OPEN 0x10 -#define ST_x08 0x08 -#define ST_x04 0x04 -#define ST_INVALID 0x02 -#define ST_x01 0x01 - -/* - * cmd_type: - */ -#define TYPE_INFO 0x01 -#define TYPE_DATA 0x02 - -/* - * read_mode: - */ -#define MOD_POLLED 0x80 -#define MOD_x08 0x08 -#define MOD_RAW 0x04 - -#define READ_DATA(port, buf, nr) insb(port, buf, nr) - -#define SET_TIMER(func, jifs) \ - ((mod_timer(&gscd_timer, jiffies + jifs)), \ - (gscd_timer.function = func)) - -#define CLEAR_TIMER del_timer_sync(&gscd_timer) - -#define MAX_TRACKS 104 - -struct msf { - unsigned char min; - unsigned char sec; - unsigned char frame; -}; - -struct gscd_Play_msf { - struct msf start; - struct msf end; -}; - -struct gscd_DiskInfo { - unsigned char first; - unsigned char last; - struct msf diskLength; - struct msf firstTrack; -}; - -struct gscd_Toc { - unsigned char ctrl_addr; - unsigned char track; - unsigned char pointIndex; - struct msf trackTime; - struct msf diskTime; -}; - diff --git a/drivers/cdrom/isp16.c b/drivers/cdrom/isp16.c deleted file mode 100644 index db0fd9a240e3..000000000000 --- a/drivers/cdrom/isp16.c +++ /dev/null @@ -1,374 +0,0 @@ -/* -- ISP16 cdrom detection and configuration - * - * Copyright (c) 1995,1996 Eric van der Maarel - * - * Version 0.6 - * - * History: - * 0.5 First release. - * Was included in the sjcd and optcd cdrom drivers. - * 0.6 First "stand-alone" version. - * Removed sound configuration. - * Added "module" support. - * - * 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x - * Removed init_module & cleanup_module in favor of - * module_init & module_exit. - * Torben Mathiasen - * - * 19 June 2004 -- check_region() converted to request_region() - * and return statement cleanups. - * - Jesper Juhl - * - * Detect cdrom interface on ISP16 sound card. - * Configure cdrom interface. - * - * Algorithm for the card with OPTi 82C928 taken - * from the CDSETUP.SYS driver for MSDOS, - * by OPTi Computers, version 2.03. - * Algorithm for the card with OPTi 82C929 as communicated - * to me by Vadim Model and Leo Spiekman. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#define ISP16_VERSION_MAJOR 0 -#define ISP16_VERSION_MINOR 6 - -#include - -#include -#include -#include -#include -#include -#include -#include "isp16.h" - -static short isp16_detect(void); -static short isp16_c928__detect(void); -static short isp16_c929__detect(void); -static short isp16_cdi_config(int base, u_char drive_type, int irq, - int dma); -static short isp16_type; /* dependent on type of interface card */ -static u_char isp16_ctrl; -static u_short isp16_enable_port; - -static int isp16_cdrom_base = ISP16_CDROM_IO_BASE; -static int isp16_cdrom_irq = ISP16_CDROM_IRQ; -static int isp16_cdrom_dma = ISP16_CDROM_DMA; -static char *isp16_cdrom_type = ISP16_CDROM_TYPE; - -module_param(isp16_cdrom_base, int, 0); -module_param(isp16_cdrom_irq, int, 0); -module_param(isp16_cdrom_dma, int, 0); -module_param(isp16_cdrom_type, charp, 0); - -#define ISP16_IN(p) (outb(isp16_ctrl,ISP16_CTRL_PORT), inb(p)) -#define ISP16_OUT(p,b) (outb(isp16_ctrl,ISP16_CTRL_PORT), outb(b,p)) - -#ifndef MODULE - -static int -__init isp16_setup(char *str) -{ - int ints[4]; - - (void) get_options(str, ARRAY_SIZE(ints), ints); - if (ints[0] > 0) - isp16_cdrom_base = ints[1]; - if (ints[0] > 1) - isp16_cdrom_irq = ints[2]; - if (ints[0] > 2) - isp16_cdrom_dma = ints[3]; - if (str) - isp16_cdrom_type = str; - - return 1; -} - -__setup("isp16=", isp16_setup); - -#endif /* MODULE */ - -/* - * ISP16 initialisation. - * - */ -static int __init isp16_init(void) -{ - u_char expected_drive; - - printk(KERN_INFO - "ISP16: configuration cdrom interface, version %d.%d.\n", - ISP16_VERSION_MAJOR, ISP16_VERSION_MINOR); - - if (!strcmp(isp16_cdrom_type, "noisp16")) { - printk("ISP16: no cdrom interface configured.\n"); - return 0; - } - - if (!request_region(ISP16_IO_BASE, ISP16_IO_SIZE, "isp16")) { - printk("ISP16: i/o ports already in use.\n"); - goto out; - } - - if ((isp16_type = isp16_detect()) < 0) { - printk("ISP16: no cdrom interface found.\n"); - goto cleanup_out; - } - - printk(KERN_INFO - "ISP16: cdrom interface (with OPTi 82C92%d chip) detected.\n", - (isp16_type == 2) ? 9 : 8); - - if (!strcmp(isp16_cdrom_type, "Sanyo")) - expected_drive = - (isp16_type ? ISP16_SANYO1 : ISP16_SANYO0); - else if (!strcmp(isp16_cdrom_type, "Sony")) - expected_drive = ISP16_SONY; - else if (!strcmp(isp16_cdrom_type, "Panasonic")) - expected_drive = - (isp16_type ? ISP16_PANASONIC1 : ISP16_PANASONIC0); - else if (!strcmp(isp16_cdrom_type, "Mitsumi")) - expected_drive = ISP16_MITSUMI; - else { - printk("ISP16: %s not supported by cdrom interface.\n", - isp16_cdrom_type); - goto cleanup_out; - } - - if (isp16_cdi_config(isp16_cdrom_base, expected_drive, - isp16_cdrom_irq, isp16_cdrom_dma) < 0) { - printk - ("ISP16: cdrom interface has not been properly configured.\n"); - goto cleanup_out; - } - printk(KERN_INFO - "ISP16: cdrom interface set up with io base 0x%03X, irq %d, dma %d," - " type %s.\n", isp16_cdrom_base, isp16_cdrom_irq, - isp16_cdrom_dma, isp16_cdrom_type); - return 0; - -cleanup_out: - release_region(ISP16_IO_BASE, ISP16_IO_SIZE); -out: - return -EIO; -} - -static short __init isp16_detect(void) -{ - - if (isp16_c929__detect() >= 0) - return 2; - else - return (isp16_c928__detect()); -} - -static short __init isp16_c928__detect(void) -{ - u_char ctrl; - u_char enable_cdrom; - u_char io; - short i = -1; - - isp16_ctrl = ISP16_C928__CTRL; - isp16_enable_port = ISP16_C928__ENABLE_PORT; - - /* read' and write' are a special read and write, respectively */ - - /* read' ISP16_CTRL_PORT, clear last two bits and write' back the result */ - ctrl = ISP16_IN(ISP16_CTRL_PORT) & 0xFC; - ISP16_OUT(ISP16_CTRL_PORT, ctrl); - - /* read' 3,4 and 5-bit from the cdrom enable port */ - enable_cdrom = ISP16_IN(ISP16_C928__ENABLE_PORT) & 0x38; - - if (!(enable_cdrom & 0x20)) { /* 5-bit not set */ - /* read' last 2 bits of ISP16_IO_SET_PORT */ - io = ISP16_IN(ISP16_IO_SET_PORT) & 0x03; - if (((io & 0x01) << 1) == (io & 0x02)) { /* bits are the same */ - if (io == 0) { /* ...the same and 0 */ - i = 0; - enable_cdrom |= 0x20; - } else { /* ...the same and 1 *//* my card, first time 'round */ - i = 1; - enable_cdrom |= 0x28; - } - ISP16_OUT(ISP16_C928__ENABLE_PORT, enable_cdrom); - } else { /* bits are not the same */ - ISP16_OUT(ISP16_CTRL_PORT, ctrl); - return i; /* -> not detected: possibly incorrect conclusion */ - } - } else if (enable_cdrom == 0x20) - i = 0; - else if (enable_cdrom == 0x28) /* my card, already initialised */ - i = 1; - - ISP16_OUT(ISP16_CTRL_PORT, ctrl); - - return i; -} - -static short __init isp16_c929__detect(void) -{ - u_char ctrl; - u_char tmp; - - isp16_ctrl = ISP16_C929__CTRL; - isp16_enable_port = ISP16_C929__ENABLE_PORT; - - /* read' and write' are a special read and write, respectively */ - - /* read' ISP16_CTRL_PORT and save */ - ctrl = ISP16_IN(ISP16_CTRL_PORT); - - /* write' zero to the ctrl port and get response */ - ISP16_OUT(ISP16_CTRL_PORT, 0); - tmp = ISP16_IN(ISP16_CTRL_PORT); - - if (tmp != 2) /* isp16 with 82C929 not detected */ - return -1; - - /* restore ctrl port value */ - ISP16_OUT(ISP16_CTRL_PORT, ctrl); - - return 2; -} - -static short __init -isp16_cdi_config(int base, u_char drive_type, int irq, int dma) -{ - u_char base_code; - u_char irq_code; - u_char dma_code; - u_char i; - - if ((drive_type == ISP16_MITSUMI) && (dma != 0)) - printk("ISP16: Mitsumi cdrom drive has no dma support.\n"); - - switch (base) { - case 0x340: - base_code = ISP16_BASE_340; - break; - case 0x330: - base_code = ISP16_BASE_330; - break; - case 0x360: - base_code = ISP16_BASE_360; - break; - case 0x320: - base_code = ISP16_BASE_320; - break; - default: - printk - ("ISP16: base address 0x%03X not supported by cdrom interface.\n", - base); - return -1; - } - switch (irq) { - case 0: - irq_code = ISP16_IRQ_X; - break; /* disable irq */ - case 5: - irq_code = ISP16_IRQ_5; - printk("ISP16: irq 5 shouldn't be used by cdrom interface," - " due to possible conflicts with the sound card.\n"); - break; - case 7: - irq_code = ISP16_IRQ_7; - printk("ISP16: irq 7 shouldn't be used by cdrom interface," - " due to possible conflicts with the sound card.\n"); - break; - case 3: - irq_code = ISP16_IRQ_3; - break; - case 9: - irq_code = ISP16_IRQ_9; - break; - case 10: - irq_code = ISP16_IRQ_10; - break; - case 11: - irq_code = ISP16_IRQ_11; - break; - default: - printk("ISP16: irq %d not supported by cdrom interface.\n", - irq); - return -1; - } - switch (dma) { - case 0: - dma_code = ISP16_DMA_X; - break; /* disable dma */ - case 1: - printk("ISP16: dma 1 cannot be used by cdrom interface," - " due to conflict with the sound card.\n"); - return -1; - break; - case 3: - dma_code = ISP16_DMA_3; - break; - case 5: - dma_code = ISP16_DMA_5; - break; - case 6: - dma_code = ISP16_DMA_6; - break; - case 7: - dma_code = ISP16_DMA_7; - break; - default: - printk("ISP16: dma %d not supported by cdrom interface.\n", - dma); - return -1; - } - - if (drive_type != ISP16_SONY && drive_type != ISP16_PANASONIC0 && - drive_type != ISP16_PANASONIC1 && drive_type != ISP16_SANYO0 && - drive_type != ISP16_SANYO1 && drive_type != ISP16_MITSUMI && - drive_type != ISP16_DRIVE_X) { - printk - ("ISP16: drive type (code 0x%02X) not supported by cdrom" - " interface.\n", drive_type); - return -1; - } - - /* set type of interface */ - i = ISP16_IN(ISP16_DRIVE_SET_PORT) & ISP16_DRIVE_SET_MASK; /* clear some bits */ - ISP16_OUT(ISP16_DRIVE_SET_PORT, i | drive_type); - - /* enable cdrom on interface with 82C929 chip */ - if (isp16_type > 1) - ISP16_OUT(isp16_enable_port, ISP16_ENABLE_CDROM); - - /* set base address, irq and dma */ - i = ISP16_IN(ISP16_IO_SET_PORT) & ISP16_IO_SET_MASK; /* keep some bits */ - ISP16_OUT(ISP16_IO_SET_PORT, i | base_code | irq_code | dma_code); - - return 0; -} - -static void __exit isp16_exit(void) -{ - release_region(ISP16_IO_BASE, ISP16_IO_SIZE); - printk(KERN_INFO "ISP16: module released.\n"); -} - -module_init(isp16_init); -module_exit(isp16_exit); - -MODULE_LICENSE("GPL"); diff --git a/drivers/cdrom/isp16.h b/drivers/cdrom/isp16.h deleted file mode 100644 index 5bd22c8f7a96..000000000000 --- a/drivers/cdrom/isp16.h +++ /dev/null @@ -1,72 +0,0 @@ -/* -- isp16.h - * - * Header for detection and initialisation of cdrom interface (only) on - * ISP16 (MAD16, Mozart) sound card. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -/* These are the default values */ -#define ISP16_CDROM_TYPE "Sanyo" -#define ISP16_CDROM_IO_BASE 0x340 -#define ISP16_CDROM_IRQ 0 -#define ISP16_CDROM_DMA 0 - -/* Some (Media)Magic */ -/* define types of drive the interface on an ISP16 card may be looking at */ -#define ISP16_DRIVE_X 0x00 -#define ISP16_SONY 0x02 -#define ISP16_PANASONIC0 0x02 -#define ISP16_SANYO0 0x02 -#define ISP16_MITSUMI 0x04 -#define ISP16_PANASONIC1 0x06 -#define ISP16_SANYO1 0x06 -#define ISP16_DRIVE_NOT_USED 0x08 /* not used */ -#define ISP16_DRIVE_SET_MASK 0xF1 /* don't change 0-bit or 4-7-bits*/ -/* ...for port */ -#define ISP16_DRIVE_SET_PORT 0xF8D -/* set io parameters */ -#define ISP16_BASE_340 0x00 -#define ISP16_BASE_330 0x40 -#define ISP16_BASE_360 0x80 -#define ISP16_BASE_320 0xC0 -#define ISP16_IRQ_X 0x00 -#define ISP16_IRQ_5 0x04 /* shouldn't be used to avoid sound card conflicts */ -#define ISP16_IRQ_7 0x08 /* shouldn't be used to avoid sound card conflicts */ -#define ISP16_IRQ_3 0x0C -#define ISP16_IRQ_9 0x10 -#define ISP16_IRQ_10 0x14 -#define ISP16_IRQ_11 0x18 -#define ISP16_DMA_X 0x03 -#define ISP16_DMA_3 0x00 -#define ISP16_DMA_5 0x00 -#define ISP16_DMA_6 0x01 -#define ISP16_DMA_7 0x02 -#define ISP16_IO_SET_MASK 0x20 /* don't change 5-bit */ -/* ...for port */ -#define ISP16_IO_SET_PORT 0xF8E -/* enable the card */ -#define ISP16_C928__ENABLE_PORT 0xF90 /* ISP16 with OPTi 82C928 chip */ -#define ISP16_C929__ENABLE_PORT 0xF91 /* ISP16 with OPTi 82C929 chip */ -#define ISP16_ENABLE_CDROM 0x80 /* seven bit */ - -/* the magic stuff */ -#define ISP16_CTRL_PORT 0xF8F -#define ISP16_C928__CTRL 0xE2 /* ISP16 with OPTi 82C928 chip */ -#define ISP16_C929__CTRL 0xE3 /* ISP16 with OPTi 82C929 chip */ - -#define ISP16_IO_BASE 0xF8D -#define ISP16_IO_SIZE 5 /* ports used from 0xF8D up to 0xF91 */ diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c deleted file mode 100644 index 972ee9c8247c..000000000000 --- a/drivers/cdrom/mcdx.c +++ /dev/null @@ -1,1943 +0,0 @@ -/* - * The Mitsumi CDROM interface - * Copyright (C) 1995 1996 Heiko Schlittermann - * VERSION: 2.14(hs) - * - * ... anyway, I'm back again, thanks to Marcin, he adopted - * large portions of my code (at least the parts containing - * my main thoughts ...) - * - ****************** H E L P ********************************* - * If you ever plan to update your CD ROM drive and perhaps - * want to sell or simply give away your Mitsumi FX-001[DS] - * -- Please -- - * mail me (heiko@lotte.sax.de). When my last drive goes - * ballistic no more driver support will be available from me! - ************************************************************* - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Thanks to - * The Linux Community at all and ... - * Martin Harriss (he wrote the first Mitsumi Driver) - * Eberhard Moenkeberg (he gave me much support and the initial kick) - * Bernd Huebner, Ruediger Helsch (Unifix-Software GmbH, they - * improved the original driver) - * Jon Tombs, Bjorn Ekwall (module support) - * Daniel v. Mosnenck (he sent me the Technical and Programming Reference) - * Gerd Knorr (he lent me his PhotoCD) - * Nils Faerber and Roger E. Wolff (extensively tested the LU portion) - * Andreas Kies (testing the mysterious hang-ups) - * Heiko Eissfeldt (VERIFY_READ/WRITE) - * Marcin Dalecki (improved performance, shortened code) - * ... somebody forgotten? - * - * 9 November 1999 -- Make kernel-parameter implementation work with 2.3.x - * Removed init_module & cleanup_module in favor of - * module_init & module_exit. - * Torben Mathiasen - */ - - -#ifdef RCS -static const char *mcdx_c_version - = "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $"; -#endif - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#define MAJOR_NR MITSUMI_X_CDROM_MAJOR -#include - -#include "mcdx.h" - -#ifndef HZ -#error HZ not defined -#endif - -#define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args) - -#if !MCDX_QUIET -#define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args) -#else -#define xinfo(fmt, args...) { ; } -#endif - -#if MCDX_DEBUG -#define xtrace(lvl, fmt, args...) \ - { if (lvl > 0) \ - { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } } -#define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args) -#else -#define xtrace(lvl, fmt, args...) { ; } -#define xdebug(fmt, args...) { ; } -#endif - -/* CONSTANTS *******************************************************/ - -/* Following are the number of sectors we _request_ from the drive - every time an access outside the already requested range is done. - The _direct_ size is the number of sectors we're allowed to skip - directly (performing a read instead of requesting the new sector - needed */ -static const int REQUEST_SIZE = 800; /* should be less then 255 * 4 */ -static const int DIRECT_SIZE = 400; /* should be less then REQUEST_SIZE */ - -enum drivemodes { TOC, DATA, RAW, COOKED }; -enum datamodes { MODE0, MODE1, MODE2 }; -enum resetmodes { SOFT, HARD }; - -static const int SINGLE = 0x01; /* single speed drive (FX001S, LU) */ -static const int DOUBLE = 0x02; /* double speed drive (FX001D, ..? */ -static const int DOOR = 0x04; /* door locking capability */ -static const int MULTI = 0x08; /* multi session capability */ - -static const unsigned char READ1X = 0xc0; -static const unsigned char READ2X = 0xc1; - - -/* DECLARATIONS ****************************************************/ -struct s_subqcode { - unsigned char control; - unsigned char tno; - unsigned char index; - struct cdrom_msf0 tt; - struct cdrom_msf0 dt; -}; - -struct s_diskinfo { - unsigned int n_first; - unsigned int n_last; - struct cdrom_msf0 msf_leadout; - struct cdrom_msf0 msf_first; -}; - -struct s_multi { - unsigned char multi; - struct cdrom_msf0 msf_last; -}; - -struct s_version { - unsigned char code; - unsigned char ver; -}; - -/* Per drive/controller stuff **************************************/ - -struct s_drive_stuff { - /* waitqueues */ - wait_queue_head_t busyq; - wait_queue_head_t lockq; - wait_queue_head_t sleepq; - - /* flags */ - volatile int introk; /* status of last irq operation */ - volatile int busy; /* drive performs an operation */ - volatile int lock; /* exclusive usage */ - - /* cd infos */ - struct s_diskinfo di; - struct s_multi multi; - struct s_subqcode *toc; /* first entry of the toc array */ - struct s_subqcode start; - struct s_subqcode stop; - int xa; /* 1 if xa disk */ - int audio; /* 1 if audio disk */ - int audiostatus; - - /* `buffer' control */ - volatile int valid; /* pending, ..., values are valid */ - volatile int pending; /* next sector to be read */ - volatile int low_border; /* first sector not to be skipped direct */ - volatile int high_border; /* first sector `out of area' */ -#ifdef AK2 - volatile int int_err; -#endif /* AK2 */ - - /* adds and odds */ - unsigned wreg_data; /* w data */ - unsigned wreg_reset; /* w hardware reset */ - unsigned wreg_hcon; /* w hardware conf */ - unsigned wreg_chn; /* w channel */ - unsigned rreg_data; /* r data */ - unsigned rreg_status; /* r status */ - - int irq; /* irq used by this drive */ - int present; /* drive present and its capabilities */ - unsigned char readcmd; /* read cmd depends on single/double speed */ - unsigned char playcmd; /* play should always be single speed */ - unsigned int xxx; /* set if changed, reset while open */ - unsigned int yyy; /* set if changed, reset by media_changed */ - int users; /* keeps track of open/close */ - int lastsector; /* last block accessible */ - int status; /* last operation's error / status */ - int readerrs; /* # of blocks read w/o error */ - struct cdrom_device_info info; - struct gendisk *disk; -}; - - -/* Prototypes ******************************************************/ - -/* The following prototypes are already declared elsewhere. They are - repeated here to show what's going on. And to sense, if they're - changed elsewhere. */ - -static int mcdx_init(void); - -static int mcdx_block_open(struct inode *inode, struct file *file) -{ - struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data; - return cdrom_open(&p->info, inode, file); -} - -static int mcdx_block_release(struct inode *inode, struct file *file) -{ - struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data; - return cdrom_release(&p->info, file); -} - -static int mcdx_block_ioctl(struct inode *inode, struct file *file, - unsigned cmd, unsigned long arg) -{ - struct s_drive_stuff *p = inode->i_bdev->bd_disk->private_data; - return cdrom_ioctl(file, &p->info, inode, cmd, arg); -} - -static int mcdx_block_media_changed(struct gendisk *disk) -{ - struct s_drive_stuff *p = disk->private_data; - return cdrom_media_changed(&p->info); -} - -static struct block_device_operations mcdx_bdops = -{ - .owner = THIS_MODULE, - .open = mcdx_block_open, - .release = mcdx_block_release, - .ioctl = mcdx_block_ioctl, - .media_changed = mcdx_block_media_changed, -}; - - -/* Indirect exported functions. These functions are exported by their - addresses, such as mcdx_open and mcdx_close in the - structure mcdx_dops. */ - -/* exported by file_ops */ -static int mcdx_open(struct cdrom_device_info *cdi, int purpose); -static void mcdx_close(struct cdrom_device_info *cdi); -static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr); -static int mcdx_tray_move(struct cdrom_device_info *cdi, int position); -static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock); -static int mcdx_audio_ioctl(struct cdrom_device_info *cdi, - unsigned int cmd, void *arg); - -/* misc internal support functions */ -static void log2msf(unsigned int, struct cdrom_msf0 *); -static unsigned int msf2log(const struct cdrom_msf0 *); -static unsigned int uint2bcd(unsigned int); -static unsigned int bcd2uint(unsigned char); -static unsigned port(int *); -static int irq(int *); -static void mcdx_delay(struct s_drive_stuff *, long jifs); -static int mcdx_transfer(struct s_drive_stuff *, char *buf, int sector, - int nr_sectors); -static int mcdx_xfer(struct s_drive_stuff *, char *buf, int sector, - int nr_sectors); - -static int mcdx_config(struct s_drive_stuff *, int); -static int mcdx_requestversion(struct s_drive_stuff *, struct s_version *, - int); -static int mcdx_stop(struct s_drive_stuff *, int); -static int mcdx_hold(struct s_drive_stuff *, int); -static int mcdx_reset(struct s_drive_stuff *, enum resetmodes, int); -static int mcdx_setdrivemode(struct s_drive_stuff *, enum drivemodes, int); -static int mcdx_setdatamode(struct s_drive_stuff *, enum datamodes, int); -static int mcdx_requestsubqcode(struct s_drive_stuff *, - struct s_subqcode *, int); -static int mcdx_requestmultidiskinfo(struct s_drive_stuff *, - struct s_multi *, int); -static int mcdx_requesttocdata(struct s_drive_stuff *, struct s_diskinfo *, - int); -static int mcdx_getstatus(struct s_drive_stuff *, int); -static int mcdx_getval(struct s_drive_stuff *, int to, int delay, char *); -static int mcdx_talk(struct s_drive_stuff *, - const unsigned char *cmd, size_t, - void *buffer, size_t size, unsigned int timeout, int); -static int mcdx_readtoc(struct s_drive_stuff *); -static int mcdx_playtrk(struct s_drive_stuff *, const struct cdrom_ti *); -static int mcdx_playmsf(struct s_drive_stuff *, const struct cdrom_msf *); -static int mcdx_setattentuator(struct s_drive_stuff *, - struct cdrom_volctrl *, int); - -/* static variables ************************************************/ - -static int mcdx_drive_map[][2] = MCDX_DRIVEMAP; -static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES]; -static DEFINE_SPINLOCK(mcdx_lock); -static struct request_queue *mcdx_queue; - -/* You can only set the first two pairs, from old MODULE_PARM code. */ -static int mcdx_set(const char *val, struct kernel_param *kp) -{ - get_options((char *)val, 4, (int *)mcdx_drive_map); - return 0; -} -module_param_call(mcdx, mcdx_set, NULL, NULL, 0); - -static struct cdrom_device_ops mcdx_dops = { - .open = mcdx_open, - .release = mcdx_close, - .media_changed = mcdx_media_changed, - .tray_move = mcdx_tray_move, - .lock_door = mcdx_lockdoor, - .audio_ioctl = mcdx_audio_ioctl, - .capability = CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED | - CDC_PLAY_AUDIO | CDC_DRIVE_STATUS, -}; - -/* KERNEL INTERFACE FUNCTIONS **************************************/ - - -static int mcdx_audio_ioctl(struct cdrom_device_info *cdi, - unsigned int cmd, void *arg) -{ - struct s_drive_stuff *stuffp = cdi->handle; - - if (!stuffp->present) - return -ENXIO; - - if (stuffp->xxx) { - if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) { - stuffp->lastsector = -1; - } else { - stuffp->lastsector = (CD_FRAMESIZE / 512) - * msf2log(&stuffp->di.msf_leadout) - 1; - } - - if (stuffp->toc) { - kfree(stuffp->toc); - stuffp->toc = NULL; - if (-1 == mcdx_readtoc(stuffp)) - return -1; - } - - stuffp->xxx = 0; - } - - switch (cmd) { - case CDROMSTART:{ - xtrace(IOCTL, "ioctl() START\n"); - /* Spin up the drive. Don't think we can do this. - * For now, ignore it. - */ - return 0; - } - - case CDROMSTOP:{ - xtrace(IOCTL, "ioctl() STOP\n"); - stuffp->audiostatus = CDROM_AUDIO_INVALID; - if (-1 == mcdx_stop(stuffp, 1)) - return -EIO; - return 0; - } - - case CDROMPLAYTRKIND:{ - struct cdrom_ti *ti = (struct cdrom_ti *) arg; - - xtrace(IOCTL, "ioctl() PLAYTRKIND\n"); - if ((ti->cdti_trk0 < stuffp->di.n_first) - || (ti->cdti_trk0 > stuffp->di.n_last) - || (ti->cdti_trk1 < stuffp->di.n_first)) - return -EINVAL; - if (ti->cdti_trk1 > stuffp->di.n_last) - ti->cdti_trk1 = stuffp->di.n_last; - xtrace(PLAYTRK, "ioctl() track %d to %d\n", - ti->cdti_trk0, ti->cdti_trk1); - return mcdx_playtrk(stuffp, ti); - } - - case CDROMPLAYMSF:{ - struct cdrom_msf *msf = (struct cdrom_msf *) arg; - - xtrace(IOCTL, "ioctl() PLAYMSF\n"); - - if ((stuffp->audiostatus == CDROM_AUDIO_PLAY) - && (-1 == mcdx_hold(stuffp, 1))) - return -EIO; - - msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0); - msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0); - msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0); - - msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1); - msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1); - msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1); - - stuffp->stop.dt.minute = msf->cdmsf_min1; - stuffp->stop.dt.second = msf->cdmsf_sec1; - stuffp->stop.dt.frame = msf->cdmsf_frame1; - - return mcdx_playmsf(stuffp, msf); - } - - case CDROMRESUME:{ - xtrace(IOCTL, "ioctl() RESUME\n"); - return mcdx_playtrk(stuffp, NULL); - } - - case CDROMREADTOCENTRY:{ - struct cdrom_tocentry *entry = - (struct cdrom_tocentry *) arg; - struct s_subqcode *tp = NULL; - xtrace(IOCTL, "ioctl() READTOCENTRY\n"); - - if (-1 == mcdx_readtoc(stuffp)) - return -1; - if (entry->cdte_track == CDROM_LEADOUT) - tp = &stuffp->toc[stuffp->di.n_last - - stuffp->di.n_first + 1]; - else if (entry->cdte_track > stuffp->di.n_last - || entry->cdte_track < stuffp->di.n_first) - return -EINVAL; - else - tp = &stuffp->toc[entry->cdte_track - - stuffp->di.n_first]; - - if (NULL == tp) - return -EIO; - entry->cdte_adr = tp->control; - entry->cdte_ctrl = tp->control >> 4; - /* Always return stuff in MSF, and let the Uniform cdrom driver - worry about what the user actually wants */ - entry->cdte_addr.msf.minute = - bcd2uint(tp->dt.minute); - entry->cdte_addr.msf.second = - bcd2uint(tp->dt.second); - entry->cdte_addr.msf.frame = - bcd2uint(tp->dt.frame); - return 0; - } - - case CDROMSUBCHNL:{ - struct cdrom_subchnl *sub = - (struct cdrom_subchnl *) arg; - struct s_subqcode q; - - xtrace(IOCTL, "ioctl() SUBCHNL\n"); - - if (-1 == mcdx_requestsubqcode(stuffp, &q, 2)) - return -EIO; - - xtrace(SUBCHNL, "audiostatus: %x\n", - stuffp->audiostatus); - sub->cdsc_audiostatus = stuffp->audiostatus; - sub->cdsc_adr = q.control; - sub->cdsc_ctrl = q.control >> 4; - sub->cdsc_trk = bcd2uint(q.tno); - sub->cdsc_ind = bcd2uint(q.index); - - xtrace(SUBCHNL, "trk %d, ind %d\n", - sub->cdsc_trk, sub->cdsc_ind); - /* Always return stuff in MSF, and let the Uniform cdrom driver - worry about what the user actually wants */ - sub->cdsc_absaddr.msf.minute = - bcd2uint(q.dt.minute); - sub->cdsc_absaddr.msf.second = - bcd2uint(q.dt.second); - sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame); - sub->cdsc_reladdr.msf.minute = - bcd2uint(q.tt.minute); - sub->cdsc_reladdr.msf.second = - bcd2uint(q.tt.second); - sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame); - xtrace(SUBCHNL, - "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n", - sub->cdsc_absaddr.msf.minute, - sub->cdsc_absaddr.msf.second, - sub->cdsc_absaddr.msf.frame, - sub->cdsc_reladdr.msf.minute, - sub->cdsc_reladdr.msf.second, - sub->cdsc_reladdr.msf.frame); - - return 0; - } - - case CDROMREADTOCHDR:{ - struct cdrom_tochdr *toc = - (struct cdrom_tochdr *) arg; - - xtrace(IOCTL, "ioctl() READTOCHDR\n"); - toc->cdth_trk0 = stuffp->di.n_first; - toc->cdth_trk1 = stuffp->di.n_last; - xtrace(TOCHDR, - "ioctl() track0 = %d, track1 = %d\n", - stuffp->di.n_first, stuffp->di.n_last); - return 0; - } - - case CDROMPAUSE:{ - xtrace(IOCTL, "ioctl() PAUSE\n"); - if (stuffp->audiostatus != CDROM_AUDIO_PLAY) - return -EINVAL; - if (-1 == mcdx_stop(stuffp, 1)) - return -EIO; - stuffp->audiostatus = CDROM_AUDIO_PAUSED; - if (-1 == - mcdx_requestsubqcode(stuffp, &stuffp->start, - 1)) - return -EIO; - return 0; - } - - case CDROMMULTISESSION:{ - struct cdrom_multisession *ms = - (struct cdrom_multisession *) arg; - xtrace(IOCTL, "ioctl() MULTISESSION\n"); - /* Always return stuff in LBA, and let the Uniform cdrom driver - worry about what the user actually wants */ - ms->addr.lba = msf2log(&stuffp->multi.msf_last); - ms->xa_flag = !!stuffp->multi.multi; - xtrace(MS, - "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n", - ms->xa_flag, ms->addr.lba, - stuffp->multi.msf_last.minute, - stuffp->multi.msf_last.second, - stuffp->multi.msf_last.frame); - - return 0; - } - - case CDROMEJECT:{ - xtrace(IOCTL, "ioctl() EJECT\n"); - if (stuffp->users > 1) - return -EBUSY; - return (mcdx_tray_move(cdi, 1)); - } - - case CDROMCLOSETRAY:{ - xtrace(IOCTL, "ioctl() CDROMCLOSETRAY\n"); - return (mcdx_tray_move(cdi, 0)); - } - - case CDROMVOLCTRL:{ - struct cdrom_volctrl *volctrl = - (struct cdrom_volctrl *) arg; - xtrace(IOCTL, "ioctl() VOLCTRL\n"); - -#if 0 /* not tested! */ - /* adjust for the weirdness of workman (md) */ - /* can't test it (hs) */ - volctrl.channel2 = volctrl.channel1; - volctrl.channel1 = volctrl.channel3 = 0x00; -#endif - return mcdx_setattentuator(stuffp, volctrl, 2); - } - - default: - return -EINVAL; - } -} - -static void do_mcdx_request(request_queue_t * q) -{ - struct s_drive_stuff *stuffp; - struct request *req; - - again: - - req = elv_next_request(q); - if (!req) - return; - - stuffp = req->rq_disk->private_data; - - if (!stuffp->present) { - xwarn("do_request(): bad device: %s\n",req->rq_disk->disk_name); - xtrace(REQUEST, "end_request(0): bad device\n"); - end_request(req, 0); - return; - } - - if (stuffp->audio) { - xwarn("do_request() attempt to read from audio cd\n"); - xtrace(REQUEST, "end_request(0): read from audio\n"); - end_request(req, 0); - return; - } - - xtrace(REQUEST, "do_request() (%lu + %lu)\n", - req->sector, req->nr_sectors); - - if (rq_data_dir(req) != READ) { - xwarn("do_request(): non-read command to cd!!\n"); - xtrace(REQUEST, "end_request(0): write\n"); - end_request(req, 0); - return; - } - else { - stuffp->status = 0; - while (req->nr_sectors) { - int i; - - i = mcdx_transfer(stuffp, - req->buffer, - req->sector, - req->nr_sectors); - - if (i == -1) { - end_request(req, 0); - goto again; - } - req->sector += i; - req->nr_sectors -= i; - req->buffer += (i * 512); - } - end_request(req, 1); - goto again; - - xtrace(REQUEST, "end_request(1)\n"); - end_request(req, 1); - } - - goto again; -} - -static int mcdx_open(struct cdrom_device_info *cdi, int purpose) -{ - struct s_drive_stuff *stuffp; - xtrace(OPENCLOSE, "open()\n"); - stuffp = cdi->handle; - if (!stuffp->present) - return -ENXIO; - - /* Make the modules looking used ... (thanx bjorn). - * But we shouldn't forget to decrement the module counter - * on error return */ - - /* this is only done to test if the drive talks with us */ - if (-1 == mcdx_getstatus(stuffp, 1)) - return -EIO; - - if (stuffp->xxx) { - - xtrace(OPENCLOSE, "open() media changed\n"); - stuffp->audiostatus = CDROM_AUDIO_INVALID; - stuffp->readcmd = 0; - xtrace(OPENCLOSE, "open() Request multisession info\n"); - if (-1 == - mcdx_requestmultidiskinfo(stuffp, &stuffp->multi, 6)) - xinfo("No multidiskinfo\n"); - } else { - /* multisession ? */ - if (!stuffp->multi.multi) - stuffp->multi.msf_last.second = 2; - - xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n", - stuffp->multi.multi, - stuffp->multi.msf_last.minute, - stuffp->multi.msf_last.second, - stuffp->multi.msf_last.frame); - - {; - } /* got multisession information */ - /* request the disks table of contents (aka diskinfo) */ - if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) { - - stuffp->lastsector = -1; - - } else { - - stuffp->lastsector = (CD_FRAMESIZE / 512) - * msf2log(&stuffp->di.msf_leadout) - 1; - - xtrace(OPENCLOSE, - "open() start %d (%02x:%02x.%02x) %d\n", - stuffp->di.n_first, - stuffp->di.msf_first.minute, - stuffp->di.msf_first.second, - stuffp->di.msf_first.frame, - msf2log(&stuffp->di.msf_first)); - xtrace(OPENCLOSE, - "open() last %d (%02x:%02x.%02x) %d\n", - stuffp->di.n_last, - stuffp->di.msf_leadout.minute, - stuffp->di.msf_leadout.second, - stuffp->di.msf_leadout.frame, - msf2log(&stuffp->di.msf_leadout)); - } - - if (stuffp->toc) { - xtrace(MALLOC, "open() free old toc @ %p\n", - stuffp->toc); - kfree(stuffp->toc); - - stuffp->toc = NULL; - } - - xtrace(OPENCLOSE, "open() init irq generation\n"); - if (-1 == mcdx_config(stuffp, 1)) - return -EIO; -#ifdef FALLBACK - /* Set the read speed */ - xwarn("AAA %x AAA\n", stuffp->readcmd); - if (stuffp->readerrs) - stuffp->readcmd = READ1X; - else - stuffp->readcmd = - stuffp->present | SINGLE ? READ1X : READ2X; - xwarn("XXX %x XXX\n", stuffp->readcmd); -#else - stuffp->readcmd = - stuffp->present | SINGLE ? READ1X : READ2X; -#endif - - /* try to get the first sector, iff any ... */ - if (stuffp->lastsector >= 0) { - char buf[512]; - int ans; - int tries; - - stuffp->xa = 0; - stuffp->audio = 0; - - for (tries = 6; tries; tries--) { - - stuffp->introk = 1; - - xtrace(OPENCLOSE, "open() try as %s\n", - stuffp->xa ? "XA" : "normal"); - /* set data mode */ - if (-1 == (ans = mcdx_setdatamode(stuffp, - stuffp-> - xa ? - MODE2 : - MODE1, - 1))) { - /* return -EIO; */ - stuffp->xa = 0; - break; - } - - if ((stuffp->audio = e_audio(ans))) - break; - - while (0 == - (ans = - mcdx_transfer(stuffp, buf, 0, 1))); - - if (ans == 1) - break; - stuffp->xa = !stuffp->xa; - } - } - /* xa disks will be read in raw mode, others not */ - if (-1 == mcdx_setdrivemode(stuffp, - stuffp->xa ? RAW : COOKED, - 1)) - return -EIO; - if (stuffp->audio) { - xinfo("open() audio disk found\n"); - } else if (stuffp->lastsector >= 0) { - xinfo("open() %s%s disk found\n", - stuffp->xa ? "XA / " : "", - stuffp->multi. - multi ? "Multi Session" : "Single Session"); - } - } - stuffp->xxx = 0; - stuffp->users++; - return 0; -} - -static void mcdx_close(struct cdrom_device_info *cdi) -{ - struct s_drive_stuff *stuffp; - - xtrace(OPENCLOSE, "close()\n"); - - stuffp = cdi->handle; - - --stuffp->users; -} - -static int mcdx_media_changed(struct cdrom_device_info *cdi, int disc_nr) -/* Return: 1 if media changed since last call to this function - 0 otherwise */ -{ - struct s_drive_stuff *stuffp; - - xinfo("mcdx_media_changed called for device %s\n", cdi->name); - - stuffp = cdi->handle; - mcdx_getstatus(stuffp, 1); - - if (stuffp->yyy == 0) - return 0; - - stuffp->yyy = 0; - return 1; -} - -#ifndef MODULE -static int __init mcdx_setup(char *str) -{ - int pi[4]; - (void) get_options(str, ARRAY_SIZE(pi), pi); - - if (pi[0] > 0) - mcdx_drive_map[0][0] = pi[1]; - if (pi[0] > 1) - mcdx_drive_map[0][1] = pi[2]; - return 1; -} - -__setup("mcdx=", mcdx_setup); - -#endif - -/* DIRTY PART ******************************************************/ - -static void mcdx_delay(struct s_drive_stuff *stuff, long jifs) -/* This routine is used for sleeping. - * A jifs value <0 means NO sleeping, - * =0 means minimal sleeping (let the kernel - * run for other processes) - * >0 means at least sleep for that amount. - * May be we could use a simple count loop w/ jumps to itself, but - * I wanna make this independent of cpu speed. [1 jiffy is 1/HZ] sec */ -{ - if (jifs < 0) - return; - - xtrace(SLEEP, "*** delay: sleepq\n"); - interruptible_sleep_on_timeout(&stuff->sleepq, jifs); - xtrace(SLEEP, "delay awoken\n"); - if (signal_pending(current)) { - xtrace(SLEEP, "got signal\n"); - } -} - -static irqreturn_t mcdx_intr(int irq, void *dev_id) -{ - struct s_drive_stuff *stuffp = dev_id; - unsigned char b; - -#ifdef AK2 - if (!stuffp->busy && stuffp->pending) - stuffp->int_err = 1; - -#endif /* AK2 */ - /* get the interrupt status */ - b = inb(stuffp->rreg_status); - stuffp->introk = ~b & MCDX_RBIT_DTEN; - - /* NOTE: We only should get interrupts if the data we - * requested are ready to transfer. - * But the drive seems to generate ``asynchronous'' interrupts - * on several error conditions too. (Despite the err int enable - * setting during initialisation) */ - - /* if not ok, read the next byte as the drives status */ - if (!stuffp->introk) { - xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b); - if (~b & MCDX_RBIT_STEN) { - xinfo("intr() irq %d status 0x%02x\n", - irq, inb(stuffp->rreg_data)); - } else { - xinfo("intr() irq %d ambiguous hw status\n", irq); - } - } else { - xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b); - } - - stuffp->busy = 0; - wake_up_interruptible(&stuffp->busyq); - return IRQ_HANDLED; -} - - -static int mcdx_talk(struct s_drive_stuff *stuffp, - const unsigned char *cmd, size_t cmdlen, - void *buffer, size_t size, unsigned int timeout, int tries) -/* Send a command to the drive, wait for the result. - * returns -1 on timeout, drive status otherwise - * If buffer is not zero, the result (length size) is stored there. - * If buffer is zero the size should be the number of bytes to read - * from the drive. These bytes are discarded. - */ -{ - int st; - char c; - int discard; - - /* Somebody wants the data read? */ - if ((discard = (buffer == NULL))) - buffer = &c; - - while (stuffp->lock) { - xtrace(SLEEP, "*** talk: lockq\n"); - interruptible_sleep_on(&stuffp->lockq); - xtrace(SLEEP, "talk: awoken\n"); - } - - stuffp->lock = 1; - - /* An operation other then reading data destroys the - * data already requested and remembered in stuffp->request, ... */ - stuffp->valid = 0; - -#if MCDX_DEBUG & TALK - { - unsigned char i; - xtrace(TALK, - "talk() %d / %d tries, res.size %d, command 0x%02x", - tries, timeout, size, (unsigned char) cmd[0]); - for (i = 1; i < cmdlen; i++) - xtrace(TALK, " 0x%02x", cmd[i]); - xtrace(TALK, "\n"); - } -#endif - - /* give up if all tries are done (bad) or if the status - * st != -1 (good) */ - for (st = -1; st == -1 && tries; tries--) { - - char *bp = (char *) buffer; - size_t sz = size; - - outsb(stuffp->wreg_data, cmd, cmdlen); - xtrace(TALK, "talk() command sent\n"); - - /* get the status byte */ - if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) { - xinfo("talk() %02x timed out (status), %d tr%s left\n", - cmd[0], tries - 1, tries == 2 ? "y" : "ies"); - continue; - } - st = *bp; - sz--; - if (!discard) - bp++; - - xtrace(TALK, "talk() got status 0x%02x\n", st); - - /* command error? */ - if (e_cmderr(st)) { - xwarn("command error cmd = %02x %s \n", - cmd[0], cmdlen > 1 ? "..." : ""); - st = -1; - continue; - } - - /* audio status? */ - if (stuffp->audiostatus == CDROM_AUDIO_INVALID) - stuffp->audiostatus = - e_audiobusy(st) ? CDROM_AUDIO_PLAY : - CDROM_AUDIO_NO_STATUS; - else if (stuffp->audiostatus == CDROM_AUDIO_PLAY - && e_audiobusy(st) == 0) - stuffp->audiostatus = CDROM_AUDIO_COMPLETED; - - /* media change? */ - if (e_changed(st)) { - xinfo("talk() media changed\n"); - stuffp->xxx = stuffp->yyy = 1; - } - - /* now actually get the data */ - while (sz--) { - if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) { - xinfo("talk() %02x timed out (data), %d tr%s left\n", - cmd[0], tries - 1, - tries == 2 ? "y" : "ies"); - st = -1; - break; - } - if (!discard) - bp++; - xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1)); - } - } - -#if !MCDX_QUIET - if (!tries && st == -1) - xinfo("talk() giving up\n"); -#endif - - stuffp->lock = 0; - wake_up_interruptible(&stuffp->lockq); - - xtrace(TALK, "talk() done with 0x%02x\n", st); - return st; -} - -/* MODULE STUFF ***********************************************************/ - -static int __init __mcdx_init(void) -{ - int i; - int drives = 0; - - mcdx_init(); - for (i = 0; i < MCDX_NDRIVES; i++) { - if (mcdx_stuffp[i]) { - xtrace(INIT, "init_module() drive %d stuff @ %p\n", - i, mcdx_stuffp[i]); - drives++; - } - } - - if (!drives) - return -EIO; - - return 0; -} - -static void __exit mcdx_exit(void) -{ - int i; - - xinfo("cleanup_module called\n"); - - for (i = 0; i < MCDX_NDRIVES; i++) { - struct s_drive_stuff *stuffp = mcdx_stuffp[i]; - if (!stuffp) - continue; - del_gendisk(stuffp->disk); - if (unregister_cdrom(&stuffp->info)) { - printk(KERN_WARNING "Can't unregister cdrom mcdx\n"); - continue; - } - put_disk(stuffp->disk); - release_region(stuffp->wreg_data, MCDX_IO_SIZE); - free_irq(stuffp->irq, NULL); - if (stuffp->toc) { - xtrace(MALLOC, "cleanup_module() free toc @ %p\n", - stuffp->toc); - kfree(stuffp->toc); - } - xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n", - stuffp); - mcdx_stuffp[i] = NULL; - kfree(stuffp); - } - - if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) { - xwarn("cleanup() unregister_blkdev() failed\n"); - } -#if !MCDX_QUIET - else - xinfo("cleanup() succeeded\n"); -#endif - blk_cleanup_queue(mcdx_queue); -} - -#ifdef MODULE -module_init(__mcdx_init); -#endif -module_exit(mcdx_exit); - - -/* Support functions ************************************************/ - -static int __init mcdx_init_drive(int drive) -{ - struct s_version version; - struct gendisk *disk; - struct s_drive_stuff *stuffp; - int size = sizeof(*stuffp); - char msg[80]; - - xtrace(INIT, "init() try drive %d\n", drive); - - xtrace(INIT, "kmalloc space for stuffpt's\n"); - xtrace(MALLOC, "init() malloc %d bytes\n", size); - if (!(stuffp = kzalloc(size, GFP_KERNEL))) { - xwarn("init() malloc failed\n"); - return 1; - } - - disk = alloc_disk(1); - if (!disk) { - xwarn("init() malloc failed\n"); - kfree(stuffp); - return 1; - } - - xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n", - sizeof(*stuffp), stuffp); - - /* set default values */ - stuffp->present = 0; /* this should be 0 already */ - stuffp->toc = NULL; /* this should be NULL already */ - - /* setup our irq and i/o addresses */ - stuffp->irq = irq(mcdx_drive_map[drive]); - stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]); - stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1; - stuffp->wreg_hcon = stuffp->wreg_reset + 1; - stuffp->wreg_chn = stuffp->wreg_hcon + 1; - - init_waitqueue_head(&stuffp->busyq); - init_waitqueue_head(&stuffp->lockq); - init_waitqueue_head(&stuffp->sleepq); - - /* check if i/o addresses are available */ - if (!request_region(stuffp->wreg_data, MCDX_IO_SIZE, "mcdx")) { - xwarn("0x%03x,%d: Init failed. " - "I/O ports (0x%03x..0x%03x) already in use.\n", - stuffp->wreg_data, stuffp->irq, - stuffp->wreg_data, - stuffp->wreg_data + MCDX_IO_SIZE - 1); - xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); - kfree(stuffp); - put_disk(disk); - xtrace(INIT, "init() continue at next drive\n"); - return 0; /* next drive */ - } - - xtrace(INIT, "init() i/o port is available at 0x%03x\n" - stuffp->wreg_data); - xtrace(INIT, "init() hardware reset\n"); - mcdx_reset(stuffp, HARD, 1); - - xtrace(INIT, "init() get version\n"); - if (-1 == mcdx_requestversion(stuffp, &version, 4)) { - /* failed, next drive */ - release_region(stuffp->wreg_data, MCDX_IO_SIZE); - xwarn("%s=0x%03x,%d: Init failed. Can't get version.\n", - MCDX, stuffp->wreg_data, stuffp->irq); - xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); - kfree(stuffp); - put_disk(disk); - xtrace(INIT, "init() continue at next drive\n"); - return 0; - } - - switch (version.code) { - case 'D': - stuffp->readcmd = READ2X; - stuffp->present = DOUBLE | DOOR | MULTI; - break; - case 'F': - stuffp->readcmd = READ1X; - stuffp->present = SINGLE | DOOR | MULTI; - break; - case 'M': - stuffp->readcmd = READ1X; - stuffp->present = SINGLE; - break; - default: - stuffp->present = 0; - break; - } - - stuffp->playcmd = READ1X; - - if (!stuffp->present) { - release_region(stuffp->wreg_data, MCDX_IO_SIZE); - xwarn("%s=0x%03x,%d: Init failed. No Mitsumi CD-ROM?.\n", - MCDX, stuffp->wreg_data, stuffp->irq); - kfree(stuffp); - put_disk(disk); - return 0; /* next drive */ - } - - xtrace(INIT, "init() register blkdev\n"); - if (register_blkdev(MAJOR_NR, "mcdx")) { - release_region(stuffp->wreg_data, MCDX_IO_SIZE); - kfree(stuffp); - put_disk(disk); - return 1; - } - - mcdx_queue = blk_init_queue(do_mcdx_request, &mcdx_lock); - if (!mcdx_queue) { - unregister_blkdev(MAJOR_NR, "mcdx"); - release_region(stuffp->wreg_data, MCDX_IO_SIZE); - kfree(stuffp); - put_disk(disk); - return 1; - } - - xtrace(INIT, "init() subscribe irq and i/o\n"); - if (request_irq(stuffp->irq, mcdx_intr, IRQF_DISABLED, "mcdx", stuffp)) { - release_region(stuffp->wreg_data, MCDX_IO_SIZE); - xwarn("%s=0x%03x,%d: Init failed. Can't get irq (%d).\n", - MCDX, stuffp->wreg_data, stuffp->irq, stuffp->irq); - stuffp->irq = 0; - blk_cleanup_queue(mcdx_queue); - kfree(stuffp); - put_disk(disk); - return 0; - } - - xtrace(INIT, "init() get garbage\n"); - { - int i; - mcdx_delay(stuffp, HZ / 2); - for (i = 100; i; i--) - (void) inb(stuffp->rreg_status); - } - - -#ifdef WE_KNOW_WHY - /* irq 11 -> channel register */ - outb(0x50, stuffp->wreg_chn); -#endif - - xtrace(INIT, "init() set non dma but irq mode\n"); - mcdx_config(stuffp, 1); - - stuffp->info.ops = &mcdx_dops; - stuffp->info.speed = 2; - stuffp->info.capacity = 1; - stuffp->info.handle = stuffp; - sprintf(stuffp->info.name, "mcdx%d", drive); - disk->major = MAJOR_NR; - disk->first_minor = drive; - strcpy(disk->disk_name, stuffp->info.name); - disk->fops = &mcdx_bdops; - disk->flags = GENHD_FL_CD; - stuffp->disk = disk; - - sprintf(msg, " mcdx: Mitsumi CD-ROM installed at 0x%03x, irq %d." - " (Firmware version %c %x)\n", - stuffp->wreg_data, stuffp->irq, version.code, version.ver); - mcdx_stuffp[drive] = stuffp; - xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp); - if (register_cdrom(&stuffp->info) != 0) { - printk("Cannot register Mitsumi CD-ROM!\n"); - free_irq(stuffp->irq, NULL); - release_region(stuffp->wreg_data, MCDX_IO_SIZE); - kfree(stuffp); - put_disk(disk); - if (unregister_blkdev(MAJOR_NR, "mcdx") != 0) - xwarn("cleanup() unregister_blkdev() failed\n"); - blk_cleanup_queue(mcdx_queue); - return 2; - } - disk->private_data = stuffp; - disk->queue = mcdx_queue; - add_disk(disk); - printk(msg); - return 0; -} - -static int __init mcdx_init(void) -{ - int drive; - xwarn("Version 2.14(hs) \n"); - - xwarn("$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $\n"); - - /* zero the pointer array */ - for (drive = 0; drive < MCDX_NDRIVES; drive++) - mcdx_stuffp[drive] = NULL; - - /* do the initialisation */ - for (drive = 0; drive < MCDX_NDRIVES; drive++) { - switch (mcdx_init_drive(drive)) { - case 2: - return -EIO; - case 1: - break; - } - } - return 0; -} - -static int mcdx_transfer(struct s_drive_stuff *stuffp, - char *p, int sector, int nr_sectors) -/* This seems to do the actually transfer. But it does more. It - keeps track of errors occurred and will (if possible) fall back - to single speed on error. - Return: -1 on timeout or other error - else status byte (as in stuff->st) */ -{ - int ans; - - ans = mcdx_xfer(stuffp, p, sector, nr_sectors); - return ans; -#ifdef FALLBACK - if (-1 == ans) - stuffp->readerrs++; - else - return ans; - - if (stuffp->readerrs && stuffp->readcmd == READ1X) { - xwarn("XXX Already reading 1x -- no chance\n"); - return -1; - } - - xwarn("XXX Fallback to 1x\n"); - - stuffp->readcmd = READ1X; - return mcdx_transfer(stuffp, p, sector, nr_sectors); -#endif - -} - - -static int mcdx_xfer(struct s_drive_stuff *stuffp, - char *p, int sector, int nr_sectors) -/* This does actually the transfer from the drive. - Return: -1 on timeout or other error - else status byte (as in stuff->st) */ -{ - int border; - int done = 0; - long timeout; - - if (stuffp->audio) { - xwarn("Attempt to read from audio CD.\n"); - return -1; - } - - if (!stuffp->readcmd) { - xinfo("Can't transfer from missing disk.\n"); - return -1; - } - - while (stuffp->lock) { - interruptible_sleep_on(&stuffp->lockq); - } - - if (stuffp->valid && (sector >= stuffp->pending) - && (sector < stuffp->low_border)) { - - /* All (or at least a part of the sectors requested) seems - * to be already requested, so we don't need to bother the - * drive with new requests ... - * Wait for the drive become idle, but first - * check for possible occurred errors --- the drive - * seems to report them asynchronously */ - - - border = stuffp->high_border < (border = - sector + nr_sectors) - ? stuffp->high_border : border; - - stuffp->lock = current->pid; - - do { - - while (stuffp->busy) { - - timeout = - interruptible_sleep_on_timeout - (&stuffp->busyq, 5 * HZ); - - if (!stuffp->introk) { - xtrace(XFER, - "error via interrupt\n"); - } else if (!timeout) { - xtrace(XFER, "timeout\n"); - } else if (signal_pending(current)) { - xtrace(XFER, "signal\n"); - } else - continue; - - stuffp->lock = 0; - stuffp->busy = 0; - stuffp->valid = 0; - - wake_up_interruptible(&stuffp->lockq); - xtrace(XFER, "transfer() done (-1)\n"); - return -1; - } - - /* check if we need to set the busy flag (as we - * expect an interrupt */ - stuffp->busy = (3 == (stuffp->pending & 3)); - - /* Test if it's the first sector of a block, - * there we have to skip some bytes as we read raw data */ - if (stuffp->xa && (0 == (stuffp->pending & 3))) { - const int HEAD = - CD_FRAMESIZE_RAW - CD_XA_TAIL - - CD_FRAMESIZE; - insb(stuffp->rreg_data, p, HEAD); - } - - /* now actually read the data */ - insb(stuffp->rreg_data, p, 512); - - /* test if it's the last sector of a block, - * if so, we have to handle XA special */ - if ((3 == (stuffp->pending & 3)) && stuffp->xa) { - char dummy[CD_XA_TAIL]; - insb(stuffp->rreg_data, &dummy[0], CD_XA_TAIL); - } - - if (stuffp->pending == sector) { - p += 512; - done++; - sector++; - } - } while (++(stuffp->pending) < border); - - stuffp->lock = 0; - wake_up_interruptible(&stuffp->lockq); - - } else { - - /* The requested sector(s) is/are out of the - * already requested range, so we have to bother the drive - * with a new request. */ - - static unsigned char cmd[] = { - 0, - 0, 0, 0, - 0, 0, 0 - }; - - cmd[0] = stuffp->readcmd; - - /* The numbers held in ->pending, ..., should be valid */ - stuffp->valid = 1; - stuffp->pending = sector & ~3; - - /* do some sanity checks */ - if (stuffp->pending > stuffp->lastsector) { - xwarn - ("transfer() sector %d from nirvana requested.\n", - stuffp->pending); - stuffp->status = MCDX_ST_EOM; - stuffp->valid = 0; - xtrace(XFER, "transfer() done (-1)\n"); - return -1; - } - - if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE) - > stuffp->lastsector + 1) { - xtrace(XFER, "cut low_border\n"); - stuffp->low_border = stuffp->lastsector + 1; - } - if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE) - > stuffp->lastsector + 1) { - xtrace(XFER, "cut high_border\n"); - stuffp->high_border = stuffp->lastsector + 1; - } - - { /* Convert the sector to be requested to MSF format */ - struct cdrom_msf0 pending; - log2msf(stuffp->pending / 4, &pending); - cmd[1] = pending.minute; - cmd[2] = pending.second; - cmd[3] = pending.frame; - } - - cmd[6] = - (unsigned - char) ((stuffp->high_border - stuffp->pending) / 4); - xtrace(XFER, "[%2d]\n", cmd[6]); - - stuffp->busy = 1; - /* Now really issue the request command */ - outsb(stuffp->wreg_data, cmd, sizeof cmd); - - } -#ifdef AK2 - if (stuffp->int_err) { - stuffp->valid = 0; - stuffp->int_err = 0; - return -1; - } -#endif /* AK2 */ - - stuffp->low_border = (stuffp->low_border += - done) < - stuffp->high_border ? stuffp->low_border : stuffp->high_border; - - return done; -} - - -/* Access to elements of the mcdx_drive_map members */ - -static unsigned port(int *ip) -{ - return ip[0]; -} -static int irq(int *ip) -{ - return ip[1]; -} - -/* Misc number converters */ - -static unsigned int bcd2uint(unsigned char c) -{ - return (c >> 4) * 10 + (c & 0x0f); -} - -static unsigned int uint2bcd(unsigned int ival) -{ - return ((ival / 10) << 4) | (ival % 10); -} - -static void log2msf(unsigned int l, struct cdrom_msf0 *pmsf) -{ - l += CD_MSF_OFFSET; - pmsf->minute = uint2bcd(l / 4500), l %= 4500; - pmsf->second = uint2bcd(l / 75); - pmsf->frame = uint2bcd(l % 75); -} - -static unsigned int msf2log(const struct cdrom_msf0 *pmsf) -{ - return bcd2uint(pmsf->frame) - + bcd2uint(pmsf->second) * 75 - + bcd2uint(pmsf->minute) * 4500 - CD_MSF_OFFSET; -} - -int mcdx_readtoc(struct s_drive_stuff *stuffp) -/* Read the toc entries from the CD, - * Return: -1 on failure, else 0 */ -{ - - if (stuffp->toc) { - xtrace(READTOC, "ioctl() toc already read\n"); - return 0; - } - - xtrace(READTOC, "ioctl() readtoc for %d tracks\n", - stuffp->di.n_last - stuffp->di.n_first + 1); - - if (-1 == mcdx_hold(stuffp, 1)) - return -1; - - xtrace(READTOC, "ioctl() tocmode\n"); - if (-1 == mcdx_setdrivemode(stuffp, TOC, 1)) - return -EIO; - - /* all seems to be ok so far ... malloc */ - { - int size; - size = - sizeof(struct s_subqcode) * (stuffp->di.n_last - - stuffp->di.n_first + 2); - - xtrace(MALLOC, "ioctl() malloc %d bytes\n", size); - stuffp->toc = kmalloc(size, GFP_KERNEL); - if (!stuffp->toc) { - xwarn("Cannot malloc %d bytes for toc\n", size); - mcdx_setdrivemode(stuffp, DATA, 1); - return -EIO; - } - } - - /* now read actually the index */ - { - int trk; - int retries; - - for (trk = 0; - trk < (stuffp->di.n_last - stuffp->di.n_first + 1); - trk++) - stuffp->toc[trk].index = 0; - - for (retries = 300; retries; retries--) { /* why 300? */ - struct s_subqcode q; - unsigned int idx; - - if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) { - mcdx_setdrivemode(stuffp, DATA, 1); - return -EIO; - } - - idx = bcd2uint(q.index); - - if ((idx > 0) - && (idx <= stuffp->di.n_last) - && (q.tno == 0) - && (stuffp->toc[idx - stuffp->di.n_first]. - index == 0)) { - stuffp->toc[idx - stuffp->di.n_first] = q; - xtrace(READTOC, - "ioctl() toc idx %d (trk %d)\n", - idx, trk); - trk--; - } - if (trk == 0) - break; - } - memset(&stuffp-> - toc[stuffp->di.n_last - stuffp->di.n_first + 1], 0, - sizeof(stuffp->toc[0])); - stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + - 1].dt = stuffp->di.msf_leadout; - } - - /* unset toc mode */ - xtrace(READTOC, "ioctl() undo toc mode\n"); - if (-1 == mcdx_setdrivemode(stuffp, DATA, 2)) - return -EIO; - -#if MCDX_DEBUG && READTOC - { - int trk; - for (trk = 0; - trk < (stuffp->di.n_last - stuffp->di.n_first + 2); - trk++) - xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x" - " %02x:%02x.%02x %02x:%02x.%02x\n", - trk + stuffp->di.n_first, - stuffp->toc[trk].control, - stuffp->toc[trk].tno, - stuffp->toc[trk].index, - stuffp->toc[trk].tt.minute, - stuffp->toc[trk].tt.second, - stuffp->toc[trk].tt.frame, - stuffp->toc[trk].dt.minute, - stuffp->toc[trk].dt.second, - stuffp->toc[trk].dt.frame); - } -#endif - - return 0; -} - -static int -mcdx_playmsf(struct s_drive_stuff *stuffp, const struct cdrom_msf *msf) -{ - unsigned char cmd[7] = { - 0, 0, 0, 0, 0, 0, 0 - }; - - if (!stuffp->readcmd) { - xinfo("Can't play from missing disk.\n"); - return -1; - } - - cmd[0] = stuffp->playcmd; - - cmd[1] = msf->cdmsf_min0; - cmd[2] = msf->cdmsf_sec0; - cmd[3] = msf->cdmsf_frame0; - cmd[4] = msf->cdmsf_min1; - cmd[5] = msf->cdmsf_sec1; - cmd[6] = msf->cdmsf_frame1; - - xtrace(PLAYMSF, "ioctl(): play %x " - "%02x:%02x:%02x -- %02x:%02x:%02x\n", - cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5], cmd[6]); - - outsb(stuffp->wreg_data, cmd, sizeof cmd); - - if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) { - xwarn("playmsf() timeout\n"); - return -1; - } - - stuffp->audiostatus = CDROM_AUDIO_PLAY; - return 0; -} - -static int -mcdx_playtrk(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti) -{ - struct s_subqcode *p; - struct cdrom_msf msf; - - if (-1 == mcdx_readtoc(stuffp)) - return -1; - - if (ti) - p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first]; - else - p = &stuffp->start; - - msf.cdmsf_min0 = p->dt.minute; - msf.cdmsf_sec0 = p->dt.second; - msf.cdmsf_frame0 = p->dt.frame; - - if (ti) { - p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1]; - stuffp->stop = *p; - } else - p = &stuffp->stop; - - msf.cdmsf_min1 = p->dt.minute; - msf.cdmsf_sec1 = p->dt.second; - msf.cdmsf_frame1 = p->dt.frame; - - return mcdx_playmsf(stuffp, &msf); -} - - -/* Drive functions ************************************************/ - -static int mcdx_tray_move(struct cdrom_device_info *cdi, int position) -{ - struct s_drive_stuff *stuffp = cdi->handle; - - if (!stuffp->present) - return -ENXIO; - if (!(stuffp->present & DOOR)) - return -ENOSYS; - - if (position) /* 1: eject */ - return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, 3); - else /* 0: close */ - return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, 3); - return 1; -} - -static int mcdx_stop(struct s_drive_stuff *stuffp, int tries) -{ - return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries); -} - -static int mcdx_hold(struct s_drive_stuff *stuffp, int tries) -{ - return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries); -} - -static int mcdx_requestsubqcode(struct s_drive_stuff *stuffp, - struct s_subqcode *sub, int tries) -{ - char buf[11]; - int ans; - - if (-1 == (ans = mcdx_talk(stuffp, "\x20", 1, buf, sizeof(buf), - 2 * HZ, tries))) - return -1; - sub->control = buf[1]; - sub->tno = buf[2]; - sub->index = buf[3]; - sub->tt.minute = buf[4]; - sub->tt.second = buf[5]; - sub->tt.frame = buf[6]; - sub->dt.minute = buf[8]; - sub->dt.second = buf[9]; - sub->dt.frame = buf[10]; - - return ans; -} - -static int mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp, - struct s_multi *multi, int tries) -{ - char buf[5]; - int ans; - - if (stuffp->present & MULTI) { - ans = - mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ, - tries); - multi->multi = buf[1]; - multi->msf_last.minute = buf[2]; - multi->msf_last.second = buf[3]; - multi->msf_last.frame = buf[4]; - return ans; - } else { - multi->multi = 0; - return 0; - } -} - -static int mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info, - int tries) -{ - char buf[9]; - int ans; - ans = - mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries); - if (ans == -1) { - info->n_first = 0; - info->n_last = 0; - } else { - info->n_first = bcd2uint(buf[1]); - info->n_last = bcd2uint(buf[2]); - info->msf_leadout.minute = buf[3]; - info->msf_leadout.second = buf[4]; - info->msf_leadout.frame = buf[5]; - info->msf_first.minute = buf[6]; - info->msf_first.second = buf[7]; - info->msf_first.frame = buf[8]; - } - return ans; -} - -static int mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode, - int tries) -{ - char cmd[2]; - int ans; - - xtrace(HW, "setdrivemode() %d\n", mode); - - if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries))) - return -1; - - switch (mode) { - case TOC: - cmd[1] |= 0x04; - break; - case DATA: - cmd[1] &= ~0x04; - break; - case RAW: - cmd[1] |= 0x40; - break; - case COOKED: - cmd[1] &= ~0x40; - break; - default: - break; - } - cmd[0] = 0x50; - return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries); -} - -static int mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode, - int tries) -{ - unsigned char cmd[2] = { 0xa0 }; - xtrace(HW, "setdatamode() %d\n", mode); - switch (mode) { - case MODE0: - cmd[1] = 0x00; - break; - case MODE1: - cmd[1] = 0x01; - break; - case MODE2: - cmd[1] = 0x02; - break; - default: - return -EINVAL; - } - return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries); -} - -static int mcdx_config(struct s_drive_stuff *stuffp, int tries) -{ - char cmd[4]; - - xtrace(HW, "config()\n"); - - cmd[0] = 0x90; - - cmd[1] = 0x10; /* irq enable */ - cmd[2] = 0x05; /* pre, err irq enable */ - - if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries)) - return -1; - - cmd[1] = 0x02; /* dma select */ - cmd[2] = 0x00; /* no dma */ - - return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries); -} - -static int mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver, - int tries) -{ - char buf[3]; - int ans; - - if (-1 == (ans = mcdx_talk(stuffp, "\xdc", - 1, buf, sizeof(buf), 2 * HZ, tries))) - return ans; - - ver->code = buf[1]; - ver->ver = buf[2]; - - return ans; -} - -static int mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries) -{ - if (mode == HARD) { - outb(0, stuffp->wreg_chn); /* no dma, no irq -> hardware */ - outb(0, stuffp->wreg_reset); /* hw reset */ - return 0; - } else - return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries); -} - -static int mcdx_lockdoor(struct cdrom_device_info *cdi, int lock) -{ - struct s_drive_stuff *stuffp = cdi->handle; - char cmd[2] = { 0xfe }; - - if (!(stuffp->present & DOOR)) - return -ENOSYS; - if (stuffp->present & DOOR) { - cmd[1] = lock ? 0x01 : 0x00; - return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, 3); - } else - return 0; -} - -static int mcdx_getstatus(struct s_drive_stuff *stuffp, int tries) -{ - return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries); -} - -static int -mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char *buf) -{ - unsigned long timeout = to + jiffies; - char c; - - if (!buf) - buf = &c; - - while (inb(stuffp->rreg_status) & MCDX_RBIT_STEN) { - if (time_after(jiffies, timeout)) - return -1; - mcdx_delay(stuffp, delay); - } - - *buf = (unsigned char) inb(stuffp->rreg_data) & 0xff; - - return 0; -} - -static int mcdx_setattentuator(struct s_drive_stuff *stuffp, - struct cdrom_volctrl *vol, int tries) -{ - char cmd[5]; - cmd[0] = 0xae; - cmd[1] = vol->channel0; - cmd[2] = 0; - cmd[3] = vol->channel1; - cmd[4] = 0; - - return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries); -} - -MODULE_LICENSE("GPL"); -MODULE_ALIAS_BLOCKDEV_MAJOR(MITSUMI_X_CDROM_MAJOR); diff --git a/drivers/cdrom/mcdx.h b/drivers/cdrom/mcdx.h deleted file mode 100644 index 83c364a74dc4..000000000000 --- a/drivers/cdrom/mcdx.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Definitions for the Mitsumi CDROM interface - * Copyright (C) 1995 1996 Heiko Schlittermann - * VERSION: @VERSION@ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Thanks to - * The Linux Community at all and ... - * Martin Harris (he wrote the first Mitsumi Driver) - * Eberhard Moenkeberg (he gave me much support and the initial kick) - * Bernd Huebner, Ruediger Helsch (Unifix-Software Gmbh, they - * improved the original driver) - * Jon Tombs, Bjorn Ekwall (module support) - * Daniel v. Mosnenck (he sent me the Technical and Programming Reference) - * Gerd Knorr (he lent me his PhotoCD) - * Nils Faerber and Roger E. Wolff (extensively tested the LU portion) - * Andreas Kies (testing the mysterious hang up's) - * ... somebody forgotten? - * Marcin Dalecki - * - */ - -/* - * The following lines are for user configuration - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * {0|1} -- 1 if you want the driver detect your drive, may crash and - * needs a long time to seek. The higher the address the longer the - * seek. - * - * WARNING: AUTOPROBE doesn't work. - */ -#define MCDX_AUTOPROBE 0 - -/* - * Drive specific settings according to the jumpers on the controller - * board(s). - * o MCDX_NDRIVES : number of used entries of the following table - * o MCDX_DRIVEMAP : table of {i/o base, irq} per controller - * - * NOTE: I didn't get a drive at irq 9(2) working. Not even alone. - */ -#if MCDX_AUTOPROBE == 0 - #define MCDX_NDRIVES 1 - #define MCDX_DRIVEMAP { \ - {0x300, 11}, \ - {0x304, 05}, \ - {0x000, 00}, \ - {0x000, 00}, \ - {0x000, 00}, \ - } -#else - #error Autoprobing is not implemented yet. -#endif - -#ifndef MCDX_QUIET -#define MCDX_QUIET 1 -#endif - -#ifndef MCDX_DEBUG -#define MCDX_DEBUG 0 -#endif - -/* *** make the following line uncommented, if you're sure, - * *** all configuration is done */ -/* #define I_WAS_HERE */ - -/* The name of the device */ -#define MCDX "mcdx" - -/* Flags for DEBUGGING */ -#define INIT 0 -#define MALLOC 0 -#define IOCTL 0 -#define PLAYTRK 0 -#define SUBCHNL 0 -#define TOCHDR 0 -#define MS 0 -#define PLAYMSF 0 -#define READTOC 0 -#define OPENCLOSE 0 -#define HW 0 -#define TALK 0 -#define IRQ 0 -#define XFER 0 -#define REQUEST 0 -#define SLEEP 0 - -/* The following addresses are taken from the Mitsumi Reference - * and describe the possible i/o range for the controller. - */ -#define MCDX_IO_BEGIN ((char*) 0x300) /* first base of i/o addr */ -#define MCDX_IO_END ((char*) 0x3fc) /* last base of i/o addr */ - -/* Per controller 4 bytes i/o are needed. */ -#define MCDX_IO_SIZE 4 - -/* - * Bits - */ - -/* The status byte, returned from every command, set if - * the description is true */ -#define MCDX_RBIT_OPEN 0x80 /* door is open */ -#define MCDX_RBIT_DISKSET 0x40 /* disk set (recognised) */ -#define MCDX_RBIT_CHANGED 0x20 /* disk was changed */ -#define MCDX_RBIT_CHECK 0x10 /* disk rotates, servo is on */ -#define MCDX_RBIT_AUDIOTR 0x08 /* current track is audio */ -#define MCDX_RBIT_RDERR 0x04 /* read error, refer SENSE KEY */ -#define MCDX_RBIT_AUDIOBS 0x02 /* currently playing audio */ -#define MCDX_RBIT_CMDERR 0x01 /* command, param or format error */ - -/* The I/O Register holding the h/w status of the drive, - * can be read at i/o base + 1 */ -#define MCDX_RBIT_DOOR 0x10 /* door is open */ -#define MCDX_RBIT_STEN 0x04 /* if 0, i/o base contains drive status */ -#define MCDX_RBIT_DTEN 0x02 /* if 0, i/o base contains data */ - -/* - * The commands. - */ - -#define OPCODE 1 /* offset of opcode */ -#define MCDX_CMD_REQUEST_TOC 1, 0x10 -#define MCDX_CMD_REQUEST_STATUS 1, 0x40 -#define MCDX_CMD_RESET 1, 0x60 -#define MCDX_CMD_REQUEST_DRIVE_MODE 1, 0xc2 -#define MCDX_CMD_SET_INTERLEAVE 2, 0xc8, 0 -#define MCDX_CMD_DATAMODE_SET 2, 0xa0, 0 - #define MCDX_DATAMODE1 0x01 - #define MCDX_DATAMODE2 0x02 -#define MCDX_CMD_LOCK_DOOR 2, 0xfe, 0 - -#define READ_AHEAD 4 /* 8 Sectors (4K) */ - -/* Useful macros */ -#define e_door(x) ((x) & MCDX_RBIT_OPEN) -#define e_check(x) (~(x) & MCDX_RBIT_CHECK) -#define e_notset(x) (~(x) & MCDX_RBIT_DISKSET) -#define e_changed(x) ((x) & MCDX_RBIT_CHANGED) -#define e_audio(x) ((x) & MCDX_RBIT_AUDIOTR) -#define e_audiobusy(x) ((x) & MCDX_RBIT_AUDIOBS) -#define e_cmderr(x) ((x) & MCDX_RBIT_CMDERR) -#define e_readerr(x) ((x) & MCDX_RBIT_RDERR) - -/** no drive specific */ -#define MCDX_CDBLK 2048 /* 2048 cooked data each blk */ - -#define MCDX_DATA_TIMEOUT (HZ/10) /* 0.1 second */ - -/* - * Access to the msf array - */ -#define MSF_MIN 0 /* minute */ -#define MSF_SEC 1 /* second */ -#define MSF_FRM 2 /* frame */ - -/* - * Errors - */ -#define MCDX_E 1 /* unspec error */ -#define MCDX_ST_EOM 0x0100 /* end of media */ -#define MCDX_ST_DRV 0x00ff /* mask to query the drive status */ - -#ifndef I_WAS_HERE -#ifndef MODULE -#warning You have not edited mcdx.h -#warning Perhaps irq and i/o settings are wrong. -#endif -#endif - -/* ex:set ts=4 sw=4: */ diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c deleted file mode 100644 index efd619c0fe10..000000000000 --- a/drivers/cdrom/optcd.c +++ /dev/null @@ -1,2105 +0,0 @@ -/* linux/drivers/cdrom/optcd.c - Optics Storage 8000 AT CDROM driver - $Id: optcd.c,v 1.11 1997/01/26 07:13:00 davem Exp $ - - Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl) - - - Based on Aztech CD268 CDROM driver by Werner Zimmermann and preworks - by Eberhard Moenkeberg (emoenke@gwdg.de). - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* Revision history - - - 14-5-95 v0.0 Plays sound tracks. No reading of data CDs yet. - Detection of disk change doesn't work. - 21-5-95 v0.1 First ALPHA version. CD can be mounted. The - device major nr is borrowed from the Aztech - driver. Speed is around 240 kb/s, as measured - with "time dd if=/dev/cdrom of=/dev/null \ - bs=2048 count=4096". - 24-6-95 v0.2 Reworked the #defines for the command codes - and the like, as well as the structure of - the hardware communication protocol, to - reflect the "official" documentation, kindly - supplied by C.K. Tan, Optics Storage Pte. Ltd. - Also tidied up the state machine somewhat. - 28-6-95 v0.3 Removed the ISP-16 interface code, as this - should go into its own driver. The driver now - has its own major nr. - Disk change detection now seems to work, too. - This version became part of the standard - kernel as of version 1.3.7 - 24-9-95 v0.4 Re-inserted ISP-16 interface code which I - copied from sjcd.c, with a few changes. - Updated README.optcd. Submitted for - inclusion in 1.3.21 - 29-9-95 v0.4a Fixed bug that prevented compilation as module - 25-10-95 v0.5 Started multisession code. Implementation - copied from Werner Zimmermann, who copied it - from Heiko Schlittermann's mcdx. - 17-1-96 v0.6 Multisession works; some cleanup too. - 18-4-96 v0.7 Increased some timing constants; - thanks to Luke McFarlane. Also tidied up some - printk behaviour. ISP16 initialization - is now handled by a separate driver. - - 09-11-99 Make kernel-parameter implementation work with 2.3.x - Removed init_module & cleanup_module in favor of - module_init & module_exit. - Torben Mathiasen -*/ - -/* Includes */ - - -#include -#include -#include -#include - -#include -#include - -#include -#include "optcd.h" - -#include - -#define MAJOR_NR OPTICS_CDROM_MAJOR -#define QUEUE (opt_queue) -#define CURRENT elv_next_request(opt_queue) - - -/* Debug support */ - - -/* Don't forget to add new debug flags here. */ -#if DEBUG_DRIVE_IF | DEBUG_VFS | DEBUG_CONV | DEBUG_TOC | \ - DEBUG_BUFFERS | DEBUG_REQUEST | DEBUG_STATE | DEBUG_MULTIS -#define DEBUG(x) debug x -static void debug(int debug_this, const char* fmt, ...) -{ - char s[1024]; - va_list args; - - if (!debug_this) - return; - - va_start(args, fmt); - vsnprintf(s, sizeof(s), fmt, args); - printk(KERN_DEBUG "optcd: %s\n", s); - va_end(args); -} -#else -#define DEBUG(x) -#endif - - -/* Drive hardware/firmware characteristics - Identifiers in accordance with Optics Storage documentation */ - - -#define optcd_port optcd /* Needed for the modutils. */ -static short optcd_port = OPTCD_PORTBASE; /* I/O base of drive. */ -module_param(optcd_port, short, 0); -/* Drive registers, read */ -#define DATA_PORT optcd_port /* Read data/status */ -#define STATUS_PORT optcd_port+1 /* Indicate data/status availability */ - -/* Drive registers, write */ -#define COMIN_PORT optcd_port /* For passing command/parameter */ -#define RESET_PORT optcd_port+1 /* Write anything and wait 0.5 sec */ -#define HCON_PORT optcd_port+2 /* Host Xfer Configuration */ - - -/* Command completion/status read from DATA register */ -#define ST_DRVERR 0x80 -#define ST_DOOR_OPEN 0x40 -#define ST_MIXEDMODE_DISK 0x20 -#define ST_MODE_BITS 0x1c -#define ST_M_STOP 0x00 -#define ST_M_READ 0x04 -#define ST_M_AUDIO 0x04 -#define ST_M_PAUSE 0x08 -#define ST_M_INITIAL 0x0c -#define ST_M_ERROR 0x10 -#define ST_M_OTHERS 0x14 -#define ST_MODE2TRACK 0x02 -#define ST_DSK_CHG 0x01 -#define ST_L_LOCK 0x01 -#define ST_CMD_OK 0x00 -#define ST_OP_OK 0x01 -#define ST_PA_OK 0x02 -#define ST_OP_ERROR 0x05 -#define ST_PA_ERROR 0x06 - - -/* Error codes (appear as command completion code from DATA register) */ -/* Player related errors */ -#define ERR_ILLCMD 0x11 /* Illegal command to player module */ -#define ERR_ILLPARM 0x12 /* Illegal parameter to player module */ -#define ERR_SLEDGE 0x13 -#define ERR_FOCUS 0x14 -#define ERR_MOTOR 0x15 -#define ERR_RADIAL 0x16 -#define ERR_PLL 0x17 /* PLL lock error */ -#define ERR_SUB_TIM 0x18 /* Subcode timeout error */ -#define ERR_SUB_NF 0x19 /* Subcode not found error */ -#define ERR_TRAY 0x1a -#define ERR_TOC 0x1b /* Table of Contents read error */ -#define ERR_JUMP 0x1c -/* Data errors */ -#define ERR_MODE 0x21 -#define ERR_FORM 0x22 -#define ERR_HEADADDR 0x23 /* Header Address not found */ -#define ERR_CRC 0x24 -#define ERR_ECC 0x25 /* Uncorrectable ECC error */ -#define ERR_CRC_UNC 0x26 /* CRC error and uncorrectable error */ -#define ERR_ILLBSYNC 0x27 /* Illegal block sync error */ -#define ERR_VDST 0x28 /* VDST not found */ -/* Timeout errors */ -#define ERR_READ_TIM 0x31 /* Read timeout error */ -#define ERR_DEC_STP 0x32 /* Decoder stopped */ -#define ERR_DEC_TIM 0x33 /* Decoder interrupt timeout error */ -/* Function abort codes */ -#define ERR_KEY 0x41 /* Key -Detected abort */ -#define ERR_READ_FINISH 0x42 /* Read Finish */ -/* Second Byte diagnostic codes */ -#define ERR_NOBSYNC 0x01 /* No block sync */ -#define ERR_SHORTB 0x02 /* Short block */ -#define ERR_LONGB 0x03 /* Long block */ -#define ERR_SHORTDSP 0x04 /* Short DSP word */ -#define ERR_LONGDSP 0x05 /* Long DSP word */ - - -/* Status availability flags read from STATUS register */ -#define FL_EJECT 0x20 -#define FL_WAIT 0x10 /* active low */ -#define FL_EOP 0x08 /* active low */ -#define FL_STEN 0x04 /* Status available when low */ -#define FL_DTEN 0x02 /* Data available when low */ -#define FL_DRQ 0x01 /* active low */ -#define FL_RESET 0xde /* These bits are high after a reset */ -#define FL_STDT (FL_STEN|FL_DTEN) - - -/* Transfer mode, written to HCON register */ -#define HCON_DTS 0x08 -#define HCON_SDRQB 0x04 -#define HCON_LOHI 0x02 -#define HCON_DMA16 0x01 - - -/* Drive command set, written to COMIN register */ -/* Quick response commands */ -#define COMDRVST 0x20 /* Drive Status Read */ -#define COMERRST 0x21 /* Error Status Read */ -#define COMIOCTLISTAT 0x22 /* Status Read; reset disk changed bit */ -#define COMINITSINGLE 0x28 /* Initialize Single Speed */ -#define COMINITDOUBLE 0x29 /* Initialize Double Speed */ -#define COMUNLOCK 0x30 /* Unlock */ -#define COMLOCK 0x31 /* Lock */ -#define COMLOCKST 0x32 /* Lock/Unlock Status */ -#define COMVERSION 0x40 /* Get Firmware Revision */ -#define COMVOIDREADMODE 0x50 /* Void Data Read Mode */ -/* Read commands */ -#define COMFETCH 0x60 /* Prefetch Data */ -#define COMREAD 0x61 /* Read */ -#define COMREADRAW 0x62 /* Read Raw Data */ -#define COMREADALL 0x63 /* Read All 2646 Bytes */ -/* Player control commands */ -#define COMLEADIN 0x70 /* Seek To Lead-in */ -#define COMSEEK 0x71 /* Seek */ -#define COMPAUSEON 0x80 /* Pause On */ -#define COMPAUSEOFF 0x81 /* Pause Off */ -#define COMSTOP 0x82 /* Stop */ -#define COMOPEN 0x90 /* Open Tray Door */ -#define COMCLOSE 0x91 /* Close Tray Door */ -#define COMPLAY 0xa0 /* Audio Play */ -#define COMPLAY_TNO 0xa2 /* Audio Play By Track Number */ -#define COMSUBQ 0xb0 /* Read Sub-q Code */ -#define COMLOCATION 0xb1 /* Read Head Position */ -/* Audio control commands */ -#define COMCHCTRL 0xc0 /* Audio Channel Control */ -/* Miscellaneous (test) commands */ -#define COMDRVTEST 0xd0 /* Write Test Bytes */ -#define COMTEST 0xd1 /* Diagnostic Test */ - -/* Low level drive interface. Only here we do actual I/O - Waiting for status / data available */ - - -/* Busy wait until FLAG goes low. Return 0 on timeout. */ -static inline int flag_low(int flag, unsigned long timeout) -{ - int flag_high; - unsigned long count = 0; - - while ((flag_high = (inb(STATUS_PORT) & flag))) - if (++count >= timeout) - break; - - DEBUG((DEBUG_DRIVE_IF, "flag_low 0x%x count %ld%s", - flag, count, flag_high ? " timeout" : "")); - return !flag_high; -} - - -/* Timed waiting for status or data */ -static int sleep_timeout; /* max # of ticks to sleep */ -static DECLARE_WAIT_QUEUE_HEAD(waitq); -static void sleep_timer(unsigned long data); -static DEFINE_TIMER(delay_timer, sleep_timer, 0, 0); -static DEFINE_SPINLOCK(optcd_lock); -static struct request_queue *opt_queue; - -/* Timer routine: wake up when desired flag goes low, - or when timeout expires. */ -static void sleep_timer(unsigned long data) -{ - int flags = inb(STATUS_PORT) & FL_STDT; - - if (flags == FL_STDT && --sleep_timeout > 0) { - mod_timer(&delay_timer, jiffies + HZ/100); /* multi-statement macro */ - } else - wake_up(&waitq); -} - - -/* Sleep until FLAG goes low. Return 0 on timeout or wrong flag low. */ -static int sleep_flag_low(int flag, unsigned long timeout) -{ - int flag_high; - - DEBUG((DEBUG_DRIVE_IF, "sleep_flag_low")); - - sleep_timeout = timeout; - flag_high = inb(STATUS_PORT) & flag; - if (flag_high && sleep_timeout > 0) { - mod_timer(&delay_timer, jiffies + HZ/100); - sleep_on(&waitq); - flag_high = inb(STATUS_PORT) & flag; - } - - DEBUG((DEBUG_DRIVE_IF, "flag 0x%x count %ld%s", - flag, timeout, flag_high ? " timeout" : "")); - return !flag_high; -} - -/* Low level drive interface. Only here we do actual I/O - Sending commands and parameters */ - - -/* Errors in the command protocol */ -#define ERR_IF_CMD_TIMEOUT 0x100 -#define ERR_IF_ERR_TIMEOUT 0x101 -#define ERR_IF_RESP_TIMEOUT 0x102 -#define ERR_IF_DATA_TIMEOUT 0x103 -#define ERR_IF_NOSTAT 0x104 - - -/* Send command code. Return <0 indicates error */ -static int send_cmd(int cmd) -{ - unsigned char ack; - - DEBUG((DEBUG_DRIVE_IF, "sending command 0x%02x\n", cmd)); - - outb(HCON_DTS, HCON_PORT); /* Enable Suspend Data Transfer */ - outb(cmd, COMIN_PORT); /* Send command code */ - if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */ - return -ERR_IF_CMD_TIMEOUT; - ack = inb(DATA_PORT); /* read command acknowledge */ - outb(HCON_SDRQB, HCON_PORT); /* Disable Suspend Data Transfer */ - return ack==ST_OP_OK ? 0 : -ack; -} - - -/* Send command parameters. Return <0 indicates error */ -static int send_params(struct cdrom_msf *params) -{ - unsigned char ack; - - DEBUG((DEBUG_DRIVE_IF, "sending parameters" - " %02x:%02x:%02x" - " %02x:%02x:%02x", - params->cdmsf_min0, - params->cdmsf_sec0, - params->cdmsf_frame0, - params->cdmsf_min1, - params->cdmsf_sec1, - params->cdmsf_frame1)); - - outb(params->cdmsf_min0, COMIN_PORT); - outb(params->cdmsf_sec0, COMIN_PORT); - outb(params->cdmsf_frame0, COMIN_PORT); - outb(params->cdmsf_min1, COMIN_PORT); - outb(params->cdmsf_sec1, COMIN_PORT); - outb(params->cdmsf_frame1, COMIN_PORT); - if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */ - return -ERR_IF_CMD_TIMEOUT; - ack = inb(DATA_PORT); /* read command acknowledge */ - return ack==ST_PA_OK ? 0 : -ack; -} - - -/* Send parameters for SEEK command. Return <0 indicates error */ -static int send_seek_params(struct cdrom_msf *params) -{ - unsigned char ack; - - DEBUG((DEBUG_DRIVE_IF, "sending seek parameters" - " %02x:%02x:%02x", - params->cdmsf_min0, - params->cdmsf_sec0, - params->cdmsf_frame0)); - - outb(params->cdmsf_min0, COMIN_PORT); - outb(params->cdmsf_sec0, COMIN_PORT); - outb(params->cdmsf_frame0, COMIN_PORT); - if (!flag_low(FL_STEN, BUSY_TIMEOUT)) /* Wait for status */ - return -ERR_IF_CMD_TIMEOUT; - ack = inb(DATA_PORT); /* read command acknowledge */ - return ack==ST_PA_OK ? 0 : -ack; -} - - -/* Wait for command execution status. Choice between busy waiting - and sleeping. Return value <0 indicates timeout. */ -static inline int get_exec_status(int busy_waiting) -{ - unsigned char exec_status; - - if (busy_waiting - ? !flag_low(FL_STEN, BUSY_TIMEOUT) - : !sleep_flag_low(FL_STEN, SLEEP_TIMEOUT)) - return -ERR_IF_CMD_TIMEOUT; - - exec_status = inb(DATA_PORT); - DEBUG((DEBUG_DRIVE_IF, "returned exec status 0x%02x", exec_status)); - return exec_status; -} - - -/* Wait busy for extra byte of data that a command returns. - Return value <0 indicates timeout. */ -static inline int get_data(int short_timeout) -{ - unsigned char data; - - if (!flag_low(FL_STEN, short_timeout ? FAST_TIMEOUT : BUSY_TIMEOUT)) - return -ERR_IF_DATA_TIMEOUT; - - data = inb(DATA_PORT); - DEBUG((DEBUG_DRIVE_IF, "returned data 0x%02x", data)); - return data; -} - - -/* Returns 0 if failed */ -static int reset_drive(void) -{ - unsigned long count = 0; - int flags; - - DEBUG((DEBUG_DRIVE_IF, "reset drive")); - - outb(0, RESET_PORT); - while (++count < RESET_WAIT) - inb(DATA_PORT); - - count = 0; - while ((flags = (inb(STATUS_PORT) & FL_RESET)) != FL_RESET) - if (++count >= BUSY_TIMEOUT) - break; - - DEBUG((DEBUG_DRIVE_IF, "reset %s", - flags == FL_RESET ? "succeeded" : "failed")); - - if (flags != FL_RESET) - return 0; /* Reset failed */ - outb(HCON_SDRQB, HCON_PORT); /* Disable Suspend Data Transfer */ - return 1; /* Reset succeeded */ -} - - -/* Facilities for asynchronous operation */ - -/* Read status/data availability flags FL_STEN and FL_DTEN */ -static inline int stdt_flags(void) -{ - return inb(STATUS_PORT) & FL_STDT; -} - - -/* Fetch status that has previously been waited for. <0 means not available */ -static inline int fetch_status(void) -{ - unsigned char status; - - if (inb(STATUS_PORT) & FL_STEN) - return -ERR_IF_NOSTAT; - - status = inb(DATA_PORT); - DEBUG((DEBUG_DRIVE_IF, "fetched exec status 0x%02x", status)); - return status; -} - - -/* Fetch data that has previously been waited for. */ -static inline void fetch_data(char *buf, int n) -{ - insb(DATA_PORT, buf, n); - DEBUG((DEBUG_DRIVE_IF, "fetched 0x%x bytes", n)); -} - - -/* Flush status and data fifos */ -static inline void flush_data(void) -{ - while ((inb(STATUS_PORT) & FL_STDT) != FL_STDT) - inb(DATA_PORT); - DEBUG((DEBUG_DRIVE_IF, "flushed fifos")); -} - -/* Command protocol */ - - -/* Send a simple command and wait for response. Command codes < COMFETCH - are quick response commands */ -static inline int exec_cmd(int cmd) -{ - int ack = send_cmd(cmd); - if (ack < 0) - return ack; - return get_exec_status(cmd < COMFETCH); -} - - -/* Send a command with parameters. Don't wait for the response, - * which consists of data blocks read from the CD. */ -static inline int exec_read_cmd(int cmd, struct cdrom_msf *params) -{ - int ack = send_cmd(cmd); - if (ack < 0) - return ack; - return send_params(params); -} - - -/* Send a seek command with parameters and wait for response */ -static inline int exec_seek_cmd(int cmd, struct cdrom_msf *params) -{ - int ack = send_cmd(cmd); - if (ack < 0) - return ack; - ack = send_seek_params(params); - if (ack < 0) - return ack; - return 0; -} - - -/* Send a command with parameters and wait for response */ -static inline int exec_long_cmd(int cmd, struct cdrom_msf *params) -{ - int ack = exec_read_cmd(cmd, params); - if (ack < 0) - return ack; - return get_exec_status(0); -} - -/* Address conversion routines */ - - -/* Binary to BCD (2 digits) */ -static inline void single_bin2bcd(u_char *p) -{ - DEBUG((DEBUG_CONV, "bin2bcd %02d", *p)); - *p = (*p % 10) | ((*p / 10) << 4); -} - - -/* Convert entire msf struct */ -static void bin2bcd(struct cdrom_msf *msf) -{ - single_bin2bcd(&msf->cdmsf_min0); - single_bin2bcd(&msf->cdmsf_sec0); - single_bin2bcd(&msf->cdmsf_frame0); - single_bin2bcd(&msf->cdmsf_min1); - single_bin2bcd(&msf->cdmsf_sec1); - single_bin2bcd(&msf->cdmsf_frame1); -} - - -/* Linear block address to minute, second, frame form */ -#define CD_FPM (CD_SECS * CD_FRAMES) /* frames per minute */ - -static void lba2msf(int lba, struct cdrom_msf *msf) -{ - DEBUG((DEBUG_CONV, "lba2msf %d", lba)); - lba += CD_MSF_OFFSET; - msf->cdmsf_min0 = lba / CD_FPM; lba %= CD_FPM; - msf->cdmsf_sec0 = lba / CD_FRAMES; - msf->cdmsf_frame0 = lba % CD_FRAMES; - msf->cdmsf_min1 = 0; - msf->cdmsf_sec1 = 0; - msf->cdmsf_frame1 = 0; - bin2bcd(msf); -} - - -/* Two BCD digits to binary */ -static inline u_char bcd2bin(u_char bcd) -{ - DEBUG((DEBUG_CONV, "bcd2bin %x%02x", bcd)); - return (bcd >> 4) * 10 + (bcd & 0x0f); -} - - -static void msf2lba(union cdrom_addr *addr) -{ - addr->lba = addr->msf.minute * CD_FPM - + addr->msf.second * CD_FRAMES - + addr->msf.frame - CD_MSF_OFFSET; -} - - -/* Minute, second, frame address BCD to binary or to linear address, - depending on MODE */ -static void msf_bcd2bin(union cdrom_addr *addr) -{ - addr->msf.minute = bcd2bin(addr->msf.minute); - addr->msf.second = bcd2bin(addr->msf.second); - addr->msf.frame = bcd2bin(addr->msf.frame); -} - -/* High level drive commands */ - - -static int audio_status = CDROM_AUDIO_NO_STATUS; -static char toc_uptodate = 0; -static char disk_changed = 1; - -/* Get drive status, flagging completion of audio play and disk changes. */ -static int drive_status(void) -{ - int status; - - status = exec_cmd(COMIOCTLISTAT); - DEBUG((DEBUG_DRIVE_IF, "IOCTLISTAT: %03x", status)); - if (status < 0) - return status; - if (status == 0xff) /* No status available */ - return -ERR_IF_NOSTAT; - - if (((status & ST_MODE_BITS) != ST_M_AUDIO) && - (audio_status == CDROM_AUDIO_PLAY)) { - audio_status = CDROM_AUDIO_COMPLETED; - } - - if (status & ST_DSK_CHG) { - toc_uptodate = 0; - disk_changed = 1; - audio_status = CDROM_AUDIO_NO_STATUS; - } - - return status; -} - - -/* Read the current Q-channel info. Also used for reading the - table of contents. qp->cdsc_format must be set on entry to - indicate the desired address format */ -static int get_q_channel(struct cdrom_subchnl *qp) -{ - int status, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10; - - status = drive_status(); - if (status < 0) - return status; - qp->cdsc_audiostatus = audio_status; - - status = exec_cmd(COMSUBQ); - if (status < 0) - return status; - - d1 = get_data(0); - if (d1 < 0) - return d1; - qp->cdsc_adr = d1; - qp->cdsc_ctrl = d1 >> 4; - - d2 = get_data(0); - if (d2 < 0) - return d2; - qp->cdsc_trk = bcd2bin(d2); - - d3 = get_data(0); - if (d3 < 0) - return d3; - qp->cdsc_ind = bcd2bin(d3); - - d4 = get_data(0); - if (d4 < 0) - return d4; - qp->cdsc_reladdr.msf.minute = d4; - - d5 = get_data(0); - if (d5 < 0) - return d5; - qp->cdsc_reladdr.msf.second = d5; - - d6 = get_data(0); - if (d6 < 0) - return d6; - qp->cdsc_reladdr.msf.frame = d6; - - d7 = get_data(0); - if (d7 < 0) - return d7; - /* byte not used */ - - d8 = get_data(0); - if (d8 < 0) - return d8; - qp->cdsc_absaddr.msf.minute = d8; - - d9 = get_data(0); - if (d9 < 0) - return d9; - qp->cdsc_absaddr.msf.second = d9; - - d10 = get_data(0); - if (d10 < 0) - return d10; - qp->cdsc_absaddr.msf.frame = d10; - - DEBUG((DEBUG_TOC, "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", - d1, d2, d3, d4, d5, d6, d7, d8, d9, d10)); - - msf_bcd2bin(&qp->cdsc_absaddr); - msf_bcd2bin(&qp->cdsc_reladdr); - if (qp->cdsc_format == CDROM_LBA) { - msf2lba(&qp->cdsc_absaddr); - msf2lba(&qp->cdsc_reladdr); - } - - return 0; -} - -/* Table of contents handling */ - - -/* Errors in table of contents */ -#define ERR_TOC_MISSINGINFO 0x120 -#define ERR_TOC_MISSINGENTRY 0x121 - - -struct cdrom_disk_info { - unsigned char first; - unsigned char last; - struct cdrom_msf0 disk_length; - struct cdrom_msf0 first_track; - /* Multisession info: */ - unsigned char next; - struct cdrom_msf0 next_session; - struct cdrom_msf0 last_session; - unsigned char multi; - unsigned char xa; - unsigned char audio; -}; -static struct cdrom_disk_info disk_info; - -#define MAX_TRACKS 111 -static struct cdrom_subchnl toc[MAX_TRACKS]; - -#define QINFO_FIRSTTRACK 100 /* bcd2bin(0xa0) */ -#define QINFO_LASTTRACK 101 /* bcd2bin(0xa1) */ -#define QINFO_DISKLENGTH 102 /* bcd2bin(0xa2) */ -#define QINFO_NEXTSESSION 110 /* bcd2bin(0xb0) */ - -#define I_FIRSTTRACK 0x01 -#define I_LASTTRACK 0x02 -#define I_DISKLENGTH 0x04 -#define I_NEXTSESSION 0x08 -#define I_ALL (I_FIRSTTRACK | I_LASTTRACK | I_DISKLENGTH) - - -#if DEBUG_TOC -static void toc_debug_info(int i) -{ - printk(KERN_DEBUG "#%3d ctl %1x, adr %1x, track %2d index %3d" - " %2d:%02d.%02d %2d:%02d.%02d\n", - i, toc[i].cdsc_ctrl, toc[i].cdsc_adr, - toc[i].cdsc_trk, toc[i].cdsc_ind, - toc[i].cdsc_reladdr.msf.minute, - toc[i].cdsc_reladdr.msf.second, - toc[i].cdsc_reladdr.msf.frame, - toc[i].cdsc_absaddr.msf.minute, - toc[i].cdsc_absaddr.msf.second, - toc[i].cdsc_absaddr.msf.frame); -} -#endif - - -static int read_toc(void) -{ - int status, limit, count; - unsigned char got_info = 0; - struct cdrom_subchnl q_info; -#if DEBUG_TOC - int i; -#endif - - DEBUG((DEBUG_TOC, "starting read_toc")); - - count = 0; - for (limit = 60; limit > 0; limit--) { - int index; - - q_info.cdsc_format = CDROM_MSF; - status = get_q_channel(&q_info); - if (status < 0) - return status; - - index = q_info.cdsc_ind; - if (index > 0 && index < MAX_TRACKS - && q_info.cdsc_trk == 0 && toc[index].cdsc_ind == 0) { - toc[index] = q_info; - DEBUG((DEBUG_TOC, "got %d", index)); - if (index < 100) - count++; - - switch (q_info.cdsc_ind) { - case QINFO_FIRSTTRACK: - got_info |= I_FIRSTTRACK; - break; - case QINFO_LASTTRACK: - got_info |= I_LASTTRACK; - break; - case QINFO_DISKLENGTH: - got_info |= I_DISKLENGTH; - break; - case QINFO_NEXTSESSION: - got_info |= I_NEXTSESSION; - break; - } - } - - if ((got_info & I_ALL) == I_ALL - && toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count - >= toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1) - break; - } - - /* Construct disk_info from TOC */ - if (disk_info.first == 0) { - disk_info.first = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute; - disk_info.first_track.minute = - toc[disk_info.first].cdsc_absaddr.msf.minute; - disk_info.first_track.second = - toc[disk_info.first].cdsc_absaddr.msf.second; - disk_info.first_track.frame = - toc[disk_info.first].cdsc_absaddr.msf.frame; - } - disk_info.last = toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute; - disk_info.disk_length.minute = - toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.minute; - disk_info.disk_length.second = - toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.second-2; - disk_info.disk_length.frame = - toc[QINFO_DISKLENGTH].cdsc_absaddr.msf.frame; - disk_info.next_session.minute = - toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.minute; - disk_info.next_session.second = - toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.second; - disk_info.next_session.frame = - toc[QINFO_NEXTSESSION].cdsc_reladdr.msf.frame; - disk_info.next = toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute; - disk_info.last_session.minute = - toc[disk_info.next].cdsc_absaddr.msf.minute; - disk_info.last_session.second = - toc[disk_info.next].cdsc_absaddr.msf.second; - disk_info.last_session.frame = - toc[disk_info.next].cdsc_absaddr.msf.frame; - toc[disk_info.last + 1].cdsc_absaddr.msf.minute = - disk_info.disk_length.minute; - toc[disk_info.last + 1].cdsc_absaddr.msf.second = - disk_info.disk_length.second; - toc[disk_info.last + 1].cdsc_absaddr.msf.frame = - disk_info.disk_length.frame; -#if DEBUG_TOC - for (i = 1; i <= disk_info.last + 1; i++) - toc_debug_info(i); - toc_debug_info(QINFO_FIRSTTRACK); - toc_debug_info(QINFO_LASTTRACK); - toc_debug_info(QINFO_DISKLENGTH); - toc_debug_info(QINFO_NEXTSESSION); -#endif - - DEBUG((DEBUG_TOC, "exiting read_toc, got_info %x, count %d", - got_info, count)); - if ((got_info & I_ALL) != I_ALL - || toc[QINFO_FIRSTTRACK].cdsc_absaddr.msf.minute + count - < toc[QINFO_LASTTRACK].cdsc_absaddr.msf.minute + 1) - return -ERR_TOC_MISSINGINFO; - return 0; -} - - -#ifdef MULTISESSION -static int get_multi_disk_info(void) -{ - int sessions, status; - struct cdrom_msf multi_index; - - - for (sessions = 2; sessions < 10 /* %%for now */; sessions++) { - int count; - - for (count = 100; count < MAX_TRACKS; count++) - toc[count].cdsc_ind = 0; - - multi_index.cdmsf_min0 = disk_info.next_session.minute; - multi_index.cdmsf_sec0 = disk_info.next_session.second; - multi_index.cdmsf_frame0 = disk_info.next_session.frame; - if (multi_index.cdmsf_sec0 >= 20) - multi_index.cdmsf_sec0 -= 20; - else { - multi_index.cdmsf_sec0 += 40; - multi_index.cdmsf_min0--; - } - DEBUG((DEBUG_MULTIS, "Try %d: %2d:%02d.%02d", sessions, - multi_index.cdmsf_min0, - multi_index.cdmsf_sec0, - multi_index.cdmsf_frame0)); - bin2bcd(&multi_index); - multi_index.cdmsf_min1 = 0; - multi_index.cdmsf_sec1 = 0; - multi_index.cdmsf_frame1 = 1; - - status = exec_read_cmd(COMREAD, &multi_index); - if (status < 0) { - DEBUG((DEBUG_TOC, "exec_read_cmd COMREAD: %02x", - -status)); - break; - } - status = sleep_flag_low(FL_DTEN, MULTI_SEEK_TIMEOUT) ? - 0 : -ERR_TOC_MISSINGINFO; - flush_data(); - if (status < 0) { - DEBUG((DEBUG_TOC, "sleep_flag_low: %02x", -status)); - break; - } - - status = read_toc(); - if (status < 0) { - DEBUG((DEBUG_TOC, "read_toc: %02x", -status)); - break; - } - - disk_info.multi = 1; - } - - exec_cmd(COMSTOP); - - if (status < 0) - return -EIO; - return 0; -} -#endif /* MULTISESSION */ - - -static int update_toc(void) -{ - int status, count; - - if (toc_uptodate) - return 0; - - DEBUG((DEBUG_TOC, "starting update_toc")); - - disk_info.first = 0; - for (count = 0; count < MAX_TRACKS; count++) - toc[count].cdsc_ind = 0; - - status = exec_cmd(COMLEADIN); - if (status < 0) - return -EIO; - - status = read_toc(); - if (status < 0) { - DEBUG((DEBUG_TOC, "read_toc: %02x", -status)); - return -EIO; - } - - /* Audio disk detection. Look at first track. */ - disk_info.audio = - (toc[disk_info.first].cdsc_ctrl & CDROM_DATA_TRACK) ? 0 : 1; - - /* XA detection */ - disk_info.xa = drive_status() & ST_MODE2TRACK; - - /* Multisession detection: if we want this, define MULTISESSION */ - disk_info.multi = 0; -#ifdef MULTISESSION - if (disk_info.xa) - get_multi_disk_info(); /* Here disk_info.multi is set */ -#endif /* MULTISESSION */ - if (disk_info.multi) - printk(KERN_WARNING "optcd: Multisession support experimental, " - "see Documentation/cdrom/optcd\n"); - - DEBUG((DEBUG_TOC, "exiting update_toc")); - - toc_uptodate = 1; - return 0; -} - -/* Request handling */ - -static int current_valid(void) -{ - return CURRENT && - rq_data_dir(CURRENT) == READ && - CURRENT->sector != -1; -} - -/* Buffers for block size conversion. */ -#define NOBUF -1 - -static char buf[CD_FRAMESIZE * N_BUFS]; -static volatile int buf_bn[N_BUFS], next_bn; -static volatile int buf_in = 0, buf_out = NOBUF; - -static inline void opt_invalidate_buffers(void) -{ - int i; - - DEBUG((DEBUG_BUFFERS, "executing opt_invalidate_buffers")); - - for (i = 0; i < N_BUFS; i++) - buf_bn[i] = NOBUF; - buf_out = NOBUF; -} - - -/* Take care of the different block sizes between cdrom and Linux. - When Linux gets variable block sizes this will probably go away. */ -static void transfer(void) -{ -#if DEBUG_BUFFERS | DEBUG_REQUEST - printk(KERN_DEBUG "optcd: executing transfer\n"); -#endif - - if (!current_valid()) - return; - while (CURRENT -> nr_sectors) { - int bn = CURRENT -> sector / 4; - int i, offs, nr_sectors; - for (i = 0; i < N_BUFS && buf_bn[i] != bn; ++i); - - DEBUG((DEBUG_REQUEST, "found %d", i)); - - if (i >= N_BUFS) { - buf_out = NOBUF; - break; - } - - offs = (i * 4 + (CURRENT -> sector & 3)) * 512; - nr_sectors = 4 - (CURRENT -> sector & 3); - - if (buf_out != i) { - buf_out = i; - if (buf_bn[i] != bn) { - buf_out = NOBUF; - continue; - } - } - - if (nr_sectors > CURRENT -> nr_sectors) - nr_sectors = CURRENT -> nr_sectors; - memcpy(CURRENT -> buffer, buf + offs, nr_sectors * 512); - CURRENT -> nr_sectors -= nr_sectors; - CURRENT -> sector += nr_sectors; - CURRENT -> buffer += nr_sectors * 512; - } -} - - -/* State machine for reading disk blocks */ - -enum state_e { - S_IDLE, /* 0 */ - S_START, /* 1 */ - S_READ, /* 2 */ - S_DATA, /* 3 */ - S_STOP, /* 4 */ - S_STOPPING /* 5 */ -}; - -static volatile enum state_e state = S_IDLE; -#if DEBUG_STATE -static volatile enum state_e state_old = S_STOP; -static volatile int flags_old = 0; -static volatile long state_n = 0; -#endif - - -/* Used as mutex to keep do_optcd_request (and other processes calling - ioctl) out while some process is inside a VFS call. - Reverse is accomplished by checking if state = S_IDLE upon entry - of opt_ioctl and opt_media_change. */ -static int in_vfs = 0; - - -static volatile int transfer_is_active = 0; -static volatile int error = 0; /* %% do something with this?? */ -static int tries; /* ibid?? */ -static int timeout = 0; - -static void poll(unsigned long data); -static struct timer_list req_timer = {.function = poll}; - - -static void poll(unsigned long data) -{ - static volatile int read_count = 1; - int flags; - int loop_again = 1; - int status = 0; - int skip = 0; - - if (error) { - printk(KERN_ERR "optcd: I/O error 0x%02x\n", error); - opt_invalidate_buffers(); - if (!tries--) { - printk(KERN_ERR "optcd: read block %d failed;" - " Giving up\n", next_bn); - if (transfer_is_active) - loop_again = 0; - if (current_valid()) - end_request(CURRENT, 0); - tries = 5; - } - error = 0; - state = S_STOP; - } - - while (loop_again) - { - loop_again = 0; /* each case must flip this back to 1 if we want - to come back up here */ - -#if DEBUG_STATE - if (state == state_old) - state_n++; - else { - state_old = state; - if (++state_n > 1) - printk(KERN_DEBUG "optcd: %ld times " - "in previous state\n", state_n); - printk(KERN_DEBUG "optcd: state %d\n", state); - state_n = 0; - } -#endif - - switch (state) { - case S_IDLE: - return; - case S_START: - if (in_vfs) - break; - if (send_cmd(COMDRVST)) { - state = S_IDLE; - while (current_valid()) - end_request(CURRENT, 0); - return; - } - state = S_READ; - timeout = READ_TIMEOUT; - break; - case S_READ: { - struct cdrom_msf msf; - if (!skip) { - status = fetch_status(); - if (status < 0) - break; - if (status & ST_DSK_CHG) { - toc_uptodate = 0; - opt_invalidate_buffers(); - } - } - skip = 0; - if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) { - toc_uptodate = 0; - opt_invalidate_buffers(); - printk(KERN_WARNING "optcd: %s\n", - (status & ST_DOOR_OPEN) - ? "door open" - : "disk removed"); - state = S_IDLE; - while (current_valid()) - end_request(CURRENT, 0); - return; - } - if (!current_valid()) { - state = S_STOP; - loop_again = 1; - break; - } - next_bn = CURRENT -> sector / 4; - lba2msf(next_bn, &msf); - read_count = N_BUFS; - msf.cdmsf_frame1 = read_count; /* Not BCD! */ - - DEBUG((DEBUG_REQUEST, "reading %x:%x.%x %x:%x.%x", - msf.cdmsf_min0, - msf.cdmsf_sec0, - msf.cdmsf_frame0, - msf.cdmsf_min1, - msf.cdmsf_sec1, - msf.cdmsf_frame1)); - DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d" - " buf_out:%d buf_bn:%d", - next_bn, - buf_in, - buf_out, - buf_bn[buf_in])); - - exec_read_cmd(COMREAD, &msf); - state = S_DATA; - timeout = READ_TIMEOUT; - break; - } - case S_DATA: - flags = stdt_flags() & (FL_STEN|FL_DTEN); - -#if DEBUG_STATE - if (flags != flags_old) { - flags_old = flags; - printk(KERN_DEBUG "optcd: flags:%x\n", flags); - } - if (flags == FL_STEN) - printk(KERN_DEBUG "timeout cnt: %d\n", timeout); -#endif - - switch (flags) { - case FL_DTEN: /* only STEN low */ - if (!tries--) { - printk(KERN_ERR - "optcd: read block %d failed; " - "Giving up\n", next_bn); - if (transfer_is_active) { - tries = 0; - break; - } - if (current_valid()) - end_request(CURRENT, 0); - tries = 5; - } - state = S_START; - timeout = READ_TIMEOUT; - loop_again = 1; - case (FL_STEN|FL_DTEN): /* both high */ - break; - default: /* DTEN low */ - tries = 5; - if (!current_valid() && buf_in == buf_out) { - state = S_STOP; - loop_again = 1; - break; - } - if (read_count<=0) - printk(KERN_WARNING - "optcd: warning - try to read" - " 0 frames\n"); - while (read_count) { - buf_bn[buf_in] = NOBUF; - if (!flag_low(FL_DTEN, BUSY_TIMEOUT)) { - /* should be no waiting here!?? */ - printk(KERN_ERR - "read_count:%d " - "CURRENT->nr_sectors:%ld " - "buf_in:%d\n", - read_count, - CURRENT->nr_sectors, - buf_in); - printk(KERN_ERR - "transfer active: %x\n", - transfer_is_active); - read_count = 0; - state = S_STOP; - loop_again = 1; - end_request(CURRENT, 0); - break; - } - fetch_data(buf+ - CD_FRAMESIZE*buf_in, - CD_FRAMESIZE); - read_count--; - - DEBUG((DEBUG_REQUEST, - "S_DATA; ---I've read data- " - "read_count: %d", - read_count)); - DEBUG((DEBUG_REQUEST, - "next_bn:%d buf_in:%d " - "buf_out:%d buf_bn:%d", - next_bn, - buf_in, - buf_out, - buf_bn[buf_in])); - - buf_bn[buf_in] = next_bn++; - if (buf_out == NOBUF) - buf_out = buf_in; - buf_in = buf_in + 1 == - N_BUFS ? 0 : buf_in + 1; - } - if (!transfer_is_active) { - while (current_valid()) { - transfer(); - if (CURRENT -> nr_sectors == 0) - end_request(CURRENT, 1); - else - break; - } - } - - if (current_valid() - && (CURRENT -> sector / 4 < next_bn || - CURRENT -> sector / 4 > - next_bn + N_BUFS)) { - state = S_STOP; - loop_again = 1; - break; - } - timeout = READ_TIMEOUT; - if (read_count == 0) { - state = S_STOP; - loop_again = 1; - break; - } - } - break; - case S_STOP: - if (read_count != 0) - printk(KERN_ERR - "optcd: discard data=%x frames\n", - read_count); - flush_data(); - if (send_cmd(COMDRVST)) { - state = S_IDLE; - while (current_valid()) - end_request(CURRENT, 0); - return; - } - state = S_STOPPING; - timeout = STOP_TIMEOUT; - break; - case S_STOPPING: - status = fetch_status(); - if (status < 0 && timeout) - break; - if ((status >= 0) && (status & ST_DSK_CHG)) { - toc_uptodate = 0; - opt_invalidate_buffers(); - } - if (current_valid()) { - if (status >= 0) { - state = S_READ; - loop_again = 1; - skip = 1; - break; - } else { - state = S_START; - timeout = 1; - } - } else { - state = S_IDLE; - return; - } - break; - default: - printk(KERN_ERR "optcd: invalid state %d\n", state); - return; - } /* case */ - } /* while */ - - if (!timeout--) { - printk(KERN_ERR "optcd: timeout in state %d\n", state); - state = S_STOP; - if (exec_cmd(COMSTOP) < 0) { - state = S_IDLE; - while (current_valid()) - end_request(CURRENT, 0); - return; - } - } - - mod_timer(&req_timer, jiffies + HZ/100); -} - - -static void do_optcd_request(request_queue_t * q) -{ - DEBUG((DEBUG_REQUEST, "do_optcd_request(%ld+%ld)", - CURRENT -> sector, CURRENT -> nr_sectors)); - - if (disk_info.audio) { - printk(KERN_WARNING "optcd: tried to mount an Audio CD\n"); - end_request(CURRENT, 0); - return; - } - - transfer_is_active = 1; - while (current_valid()) { - transfer(); /* First try to transfer block from buffers */ - if (CURRENT -> nr_sectors == 0) { - end_request(CURRENT, 1); - } else { /* Want to read a block not in buffer */ - buf_out = NOBUF; - if (state == S_IDLE) { - /* %% Should this block the request queue?? */ - if (update_toc() < 0) { - while (current_valid()) - end_request(CURRENT, 0); - break; - } - /* Start state machine */ - state = S_START; - timeout = READ_TIMEOUT; - tries = 5; - /* %% why not start right away?? */ - mod_timer(&req_timer, jiffies + HZ/100); - } - break; - } - } - transfer_is_active = 0; - - DEBUG((DEBUG_REQUEST, "next_bn:%d buf_in:%d buf_out:%d buf_bn:%d", - next_bn, buf_in, buf_out, buf_bn[buf_in])); - DEBUG((DEBUG_REQUEST, "do_optcd_request ends")); -} - -/* IOCTLs */ - - -static char auto_eject = 0; - -static int cdrompause(void) -{ - int status; - - if (audio_status != CDROM_AUDIO_PLAY) - return -EINVAL; - - status = exec_cmd(COMPAUSEON); - if (status < 0) { - DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEON: %02x", -status)); - return -EIO; - } - audio_status = CDROM_AUDIO_PAUSED; - return 0; -} - - -static int cdromresume(void) -{ - int status; - - if (audio_status != CDROM_AUDIO_PAUSED) - return -EINVAL; - - status = exec_cmd(COMPAUSEOFF); - if (status < 0) { - DEBUG((DEBUG_VFS, "exec_cmd COMPAUSEOFF: %02x", -status)); - audio_status = CDROM_AUDIO_ERROR; - return -EIO; - } - audio_status = CDROM_AUDIO_PLAY; - return 0; -} - - -static int cdromplaymsf(void __user *arg) -{ - int status; - struct cdrom_msf msf; - - if (copy_from_user(&msf, arg, sizeof msf)) - return -EFAULT; - - bin2bcd(&msf); - status = exec_long_cmd(COMPLAY, &msf); - if (status < 0) { - DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status)); - audio_status = CDROM_AUDIO_ERROR; - return -EIO; - } - - audio_status = CDROM_AUDIO_PLAY; - return 0; -} - - -static int cdromplaytrkind(void __user *arg) -{ - int status; - struct cdrom_ti ti; - struct cdrom_msf msf; - - if (copy_from_user(&ti, arg, sizeof ti)) - return -EFAULT; - - if (ti.cdti_trk0 < disk_info.first - || ti.cdti_trk0 > disk_info.last - || ti.cdti_trk1 < ti.cdti_trk0) - return -EINVAL; - if (ti.cdti_trk1 > disk_info.last) - ti.cdti_trk1 = disk_info.last; - - msf.cdmsf_min0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.minute; - msf.cdmsf_sec0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.second; - msf.cdmsf_frame0 = toc[ti.cdti_trk0].cdsc_absaddr.msf.frame; - msf.cdmsf_min1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.minute; - msf.cdmsf_sec1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.second; - msf.cdmsf_frame1 = toc[ti.cdti_trk1 + 1].cdsc_absaddr.msf.frame; - - DEBUG((DEBUG_VFS, "play %02d:%02d.%02d to %02d:%02d.%02d", - msf.cdmsf_min0, - msf.cdmsf_sec0, - msf.cdmsf_frame0, - msf.cdmsf_min1, - msf.cdmsf_sec1, - msf.cdmsf_frame1)); - - bin2bcd(&msf); - status = exec_long_cmd(COMPLAY, &msf); - if (status < 0) { - DEBUG((DEBUG_VFS, "exec_long_cmd COMPLAY: %02x", -status)); - audio_status = CDROM_AUDIO_ERROR; - return -EIO; - } - - audio_status = CDROM_AUDIO_PLAY; - return 0; -} - - -static int cdromreadtochdr(void __user *arg) -{ - struct cdrom_tochdr tochdr; - - tochdr.cdth_trk0 = disk_info.first; - tochdr.cdth_trk1 = disk_info.last; - - return copy_to_user(arg, &tochdr, sizeof tochdr) ? -EFAULT : 0; -} - - -static int cdromreadtocentry(void __user *arg) -{ - struct cdrom_tocentry entry; - struct cdrom_subchnl *tocptr; - - if (copy_from_user(&entry, arg, sizeof entry)) - return -EFAULT; - - if (entry.cdte_track == CDROM_LEADOUT) - tocptr = &toc[disk_info.last + 1]; - else if (entry.cdte_track > disk_info.last - || entry.cdte_track < disk_info.first) - return -EINVAL; - else - tocptr = &toc[entry.cdte_track]; - - entry.cdte_adr = tocptr->cdsc_adr; - entry.cdte_ctrl = tocptr->cdsc_ctrl; - entry.cdte_addr.msf.minute = tocptr->cdsc_absaddr.msf.minute; - entry.cdte_addr.msf.second = tocptr->cdsc_absaddr.msf.second; - entry.cdte_addr.msf.frame = tocptr->cdsc_absaddr.msf.frame; - /* %% What should go into entry.cdte_datamode? */ - - if (entry.cdte_format == CDROM_LBA) - msf2lba(&entry.cdte_addr); - else if (entry.cdte_format != CDROM_MSF) - return -EINVAL; - - return copy_to_user(arg, &entry, sizeof entry) ? -EFAULT : 0; -} - - -static int cdromvolctrl(void __user *arg) -{ - int status; - struct cdrom_volctrl volctrl; - struct cdrom_msf msf; - - if (copy_from_user(&volctrl, arg, sizeof volctrl)) - return -EFAULT; - - msf.cdmsf_min0 = 0x10; - msf.cdmsf_sec0 = 0x32; - msf.cdmsf_frame0 = volctrl.channel0; - msf.cdmsf_min1 = volctrl.channel1; - msf.cdmsf_sec1 = volctrl.channel2; - msf.cdmsf_frame1 = volctrl.channel3; - - status = exec_long_cmd(COMCHCTRL, &msf); - if (status < 0) { - DEBUG((DEBUG_VFS, "exec_long_cmd COMCHCTRL: %02x", -status)); - return -EIO; - } - return 0; -} - - -static int cdromsubchnl(void __user *arg) -{ - int status; - struct cdrom_subchnl subchnl; - - if (copy_from_user(&subchnl, arg, sizeof subchnl)) - return -EFAULT; - - if (subchnl.cdsc_format != CDROM_LBA - && subchnl.cdsc_format != CDROM_MSF) - return -EINVAL; - - status = get_q_channel(&subchnl); - if (status < 0) { - DEBUG((DEBUG_VFS, "get_q_channel: %02x", -status)); - return -EIO; - } - - if (copy_to_user(arg, &subchnl, sizeof subchnl)) - return -EFAULT; - return 0; -} - - -static struct gendisk *optcd_disk; - - -static int cdromread(void __user *arg, int blocksize, int cmd) -{ - int status; - struct cdrom_msf msf; - - if (copy_from_user(&msf, arg, sizeof msf)) - return -EFAULT; - - bin2bcd(&msf); - msf.cdmsf_min1 = 0; - msf.cdmsf_sec1 = 0; - msf.cdmsf_frame1 = 1; /* read only one frame */ - status = exec_read_cmd(cmd, &msf); - - DEBUG((DEBUG_VFS, "read cmd status 0x%x", status)); - - if (!sleep_flag_low(FL_DTEN, SLEEP_TIMEOUT)) - return -EIO; - - fetch_data(optcd_disk->private_data, blocksize); - - if (copy_to_user(arg, optcd_disk->private_data, blocksize)) - return -EFAULT; - - return 0; -} - - -static int cdromseek(void __user *arg) -{ - int status; - struct cdrom_msf msf; - - if (copy_from_user(&msf, arg, sizeof msf)) - return -EFAULT; - - bin2bcd(&msf); - status = exec_seek_cmd(COMSEEK, &msf); - - DEBUG((DEBUG_VFS, "COMSEEK status 0x%x", status)); - - if (status < 0) - return -EIO; - return 0; -} - - -#ifdef MULTISESSION -static int cdrommultisession(void __user *arg) -{ - struct cdrom_multisession ms; - - if (copy_from_user(&ms, arg, sizeof ms)) - return -EFAULT; - - ms.addr.msf.minute = disk_info.last_session.minute; - ms.addr.msf.second = disk_info.last_session.second; - ms.addr.msf.frame = disk_info.last_session.frame; - - if (ms.addr_format != CDROM_LBA - && ms.addr_format != CDROM_MSF) - return -EINVAL; - if (ms.addr_format == CDROM_LBA) - msf2lba(&ms.addr); - - ms.xa_flag = disk_info.xa; - - if (copy_to_user(arg, &ms, sizeof(struct cdrom_multisession))) - return -EFAULT; - -#if DEBUG_MULTIS - if (ms.addr_format == CDROM_MSF) - printk(KERN_DEBUG - "optcd: multisession xa:%d, msf:%02d:%02d.%02d\n", - ms.xa_flag, - ms.addr.msf.minute, - ms.addr.msf.second, - ms.addr.msf.frame); - else - printk(KERN_DEBUG - "optcd: multisession %d, lba:0x%08x [%02d:%02d.%02d])\n", - ms.xa_flag, - ms.addr.lba, - disk_info.last_session.minute, - disk_info.last_session.second, - disk_info.last_session.frame); -#endif /* DEBUG_MULTIS */ - - return 0; -} -#endif /* MULTISESSION */ - - -static int cdromreset(void) -{ - if (state != S_IDLE) { - error = 1; - tries = 0; - } - - toc_uptodate = 0; - disk_changed = 1; - opt_invalidate_buffers(); - audio_status = CDROM_AUDIO_NO_STATUS; - - if (!reset_drive()) - return -EIO; - return 0; -} - -/* VFS calls */ - - -static int opt_ioctl(struct inode *ip, struct file *fp, - unsigned int cmd, unsigned long arg) -{ - int status, err, retval = 0; - void __user *argp = (void __user *)arg; - - DEBUG((DEBUG_VFS, "starting opt_ioctl")); - - if (!ip) - return -EINVAL; - - if (cmd == CDROMRESET) - return cdromreset(); - - /* is do_optcd_request or another ioctl busy? */ - if (state != S_IDLE || in_vfs) - return -EBUSY; - - in_vfs = 1; - - status = drive_status(); - if (status < 0) { - DEBUG((DEBUG_VFS, "drive_status: %02x", -status)); - in_vfs = 0; - return -EIO; - } - - if (status & ST_DOOR_OPEN) - switch (cmd) { /* Actions that can be taken with door open */ - case CDROMCLOSETRAY: - /* We do this before trying to read the toc. */ - err = exec_cmd(COMCLOSE); - if (err < 0) { - DEBUG((DEBUG_VFS, - "exec_cmd COMCLOSE: %02x", -err)); - in_vfs = 0; - return -EIO; - } - break; - default: in_vfs = 0; - return -EBUSY; - } - - err = update_toc(); - if (err < 0) { - DEBUG((DEBUG_VFS, "update_toc: %02x", -err)); - in_vfs = 0; - return -EIO; - } - - DEBUG((DEBUG_VFS, "ioctl cmd 0x%x", cmd)); - - switch (cmd) { - case CDROMPAUSE: retval = cdrompause(); break; - case CDROMRESUME: retval = cdromresume(); break; - case CDROMPLAYMSF: retval = cdromplaymsf(argp); break; - case CDROMPLAYTRKIND: retval = cdromplaytrkind(argp); break; - case CDROMREADTOCHDR: retval = cdromreadtochdr(argp); break; - case CDROMREADTOCENTRY: retval = cdromreadtocentry(argp); break; - - case CDROMSTOP: err = exec_cmd(COMSTOP); - if (err < 0) { - DEBUG((DEBUG_VFS, - "exec_cmd COMSTOP: %02x", - -err)); - retval = -EIO; - } else - audio_status = CDROM_AUDIO_NO_STATUS; - break; - case CDROMSTART: break; /* This is a no-op */ - case CDROMEJECT: err = exec_cmd(COMUNLOCK); - if (err < 0) { - DEBUG((DEBUG_VFS, - "exec_cmd COMUNLOCK: %02x", - -err)); - retval = -EIO; - break; - } - err = exec_cmd(COMOPEN); - if (err < 0) { - DEBUG((DEBUG_VFS, - "exec_cmd COMOPEN: %02x", - -err)); - retval = -EIO; - } - break; - - case CDROMVOLCTRL: retval = cdromvolctrl(argp); break; - case CDROMSUBCHNL: retval = cdromsubchnl(argp); break; - - /* The drive detects the mode and automatically delivers the - correct 2048 bytes, so we don't need these IOCTLs */ - case CDROMREADMODE2: retval = -EINVAL; break; - case CDROMREADMODE1: retval = -EINVAL; break; - - /* Drive doesn't support reading audio */ - case CDROMREADAUDIO: retval = -EINVAL; break; - - case CDROMEJECT_SW: auto_eject = (char) arg; - break; - -#ifdef MULTISESSION - case CDROMMULTISESSION: retval = cdrommultisession(argp); break; -#endif - - case CDROM_GET_MCN: retval = -EINVAL; break; /* not implemented */ - case CDROMVOLREAD: retval = -EINVAL; break; /* not implemented */ - - case CDROMREADRAW: - /* this drive delivers 2340 bytes in raw mode */ - retval = cdromread(argp, CD_FRAMESIZE_RAW1, COMREADRAW); - break; - case CDROMREADCOOKED: - retval = cdromread(argp, CD_FRAMESIZE, COMREAD); - break; - case CDROMREADALL: - retval = cdromread(argp, CD_FRAMESIZE_RAWER, COMREADALL); - break; - - case CDROMSEEK: retval = cdromseek(argp); break; - case CDROMPLAYBLK: retval = -EINVAL; break; /* not implemented */ - case CDROMCLOSETRAY: break; /* The action was taken earlier */ - default: retval = -EINVAL; - } - in_vfs = 0; - return retval; -} - - -static int open_count = 0; - -/* Open device special file; check that a disk is in. */ -static int opt_open(struct inode *ip, struct file *fp) -{ - DEBUG((DEBUG_VFS, "starting opt_open")); - - if (!open_count && state == S_IDLE) { - int status; - char *buf; - - buf = kmalloc(CD_FRAMESIZE_RAWER, GFP_KERNEL); - if (!buf) { - printk(KERN_INFO "optcd: cannot allocate read buffer\n"); - return -ENOMEM; - } - optcd_disk->private_data = buf; /* save read buffer */ - - toc_uptodate = 0; - opt_invalidate_buffers(); - - status = exec_cmd(COMCLOSE); /* close door */ - if (status < 0) { - DEBUG((DEBUG_VFS, "exec_cmd COMCLOSE: %02x", -status)); - } - - status = drive_status(); - if (status < 0) { - DEBUG((DEBUG_VFS, "drive_status: %02x", -status)); - goto err_out; - } - DEBUG((DEBUG_VFS, "status: %02x", status)); - if ((status & ST_DOOR_OPEN) || (status & ST_DRVERR)) { - printk(KERN_INFO "optcd: no disk or door open\n"); - goto err_out; - } - status = exec_cmd(COMLOCK); /* Lock door */ - if (status < 0) { - DEBUG((DEBUG_VFS, "exec_cmd COMLOCK: %02x", -status)); - } - status = update_toc(); /* Read table of contents */ - if (status < 0) { - DEBUG((DEBUG_VFS, "update_toc: %02x", -status)); - status = exec_cmd(COMUNLOCK); /* Unlock door */ - if (status < 0) { - DEBUG((DEBUG_VFS, - "exec_cmd COMUNLOCK: %02x", -status)); - } - goto err_out; - } - open_count++; - } - - DEBUG((DEBUG_VFS, "exiting opt_open")); - - return 0; - -err_out: - return -EIO; -} - - -/* Release device special file; flush all blocks from the buffer cache */ -static int opt_release(struct inode *ip, struct file *fp) -{ - int status; - - DEBUG((DEBUG_VFS, "executing opt_release")); - DEBUG((DEBUG_VFS, "inode: %p, device: %s, file: %p\n", - ip, ip->i_bdev->bd_disk->disk_name, fp)); - - if (!--open_count) { - toc_uptodate = 0; - opt_invalidate_buffers(); - status = exec_cmd(COMUNLOCK); /* Unlock door */ - if (status < 0) { - DEBUG((DEBUG_VFS, "exec_cmd COMUNLOCK: %02x", -status)); - } - if (auto_eject) { - status = exec_cmd(COMOPEN); - DEBUG((DEBUG_VFS, "exec_cmd COMOPEN: %02x", -status)); - } - kfree(optcd_disk->private_data); - del_timer(&delay_timer); - del_timer(&req_timer); - } - return 0; -} - - -/* Check if disk has been changed */ -static int opt_media_change(struct gendisk *disk) -{ - DEBUG((DEBUG_VFS, "executing opt_media_change")); - DEBUG((DEBUG_VFS, "dev: %s; disk_changed = %d\n", - disk->disk_name, disk_changed)); - - if (disk_changed) { - disk_changed = 0; - return 1; - } - return 0; -} - -/* Driver initialisation */ - - -/* Returns 1 if a drive is detected with a version string - starting with "DOLPHIN". Otherwise 0. */ -static int __init version_ok(void) -{ - char devname[100]; - int count, i, ch, status; - - status = exec_cmd(COMVERSION); - if (status < 0) { - DEBUG((DEBUG_VFS, "exec_cmd COMVERSION: %02x", -status)); - return 0; - } - if ((count = get_data(1)) < 0) { - DEBUG((DEBUG_VFS, "get_data(1): %02x", -count)); - return 0; - } - for (i = 0, ch = -1; count > 0; count--) { - if ((ch = get_data(1)) < 0) { - DEBUG((DEBUG_VFS, "get_data(1): %02x", -ch)); - break; - } - if (i < 99) - devname[i++] = ch; - } - devname[i] = '\0'; - if (ch < 0) - return 0; - - printk(KERN_INFO "optcd: Device %s detected\n", devname); - return ((devname[0] == 'D') - && (devname[1] == 'O') - && (devname[2] == 'L') - && (devname[3] == 'P') - && (devname[4] == 'H') - && (devname[5] == 'I') - && (devname[6] == 'N')); -} - - -static struct block_device_operations opt_fops = { - .owner = THIS_MODULE, - .open = opt_open, - .release = opt_release, - .ioctl = opt_ioctl, - .media_changed = opt_media_change, -}; - -#ifndef MODULE -/* Get kernel parameter when used as a kernel driver */ -static int optcd_setup(char *str) -{ - int ints[4]; - (void)get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) - optcd_port = ints[1]; - - return 1; -} - -__setup("optcd=", optcd_setup); - -#endif /* MODULE */ - -/* Test for presence of drive and initialize it. Called at boot time - or during module initialisation. */ -static int __init optcd_init(void) -{ - int status; - - if (optcd_port <= 0) { - printk(KERN_INFO - "optcd: no Optics Storage CDROM Initialization\n"); - return -EIO; - } - optcd_disk = alloc_disk(1); - if (!optcd_disk) { - printk(KERN_ERR "optcd: can't allocate disk\n"); - return -ENOMEM; - } - optcd_disk->major = MAJOR_NR; - optcd_disk->first_minor = 0; - optcd_disk->fops = &opt_fops; - sprintf(optcd_disk->disk_name, "optcd"); - - if (!request_region(optcd_port, 4, "optcd")) { - printk(KERN_ERR "optcd: conflict, I/O port 0x%x already used\n", - optcd_port); - put_disk(optcd_disk); - return -EIO; - } - - if (!reset_drive()) { - printk(KERN_ERR "optcd: drive at 0x%x not ready\n", optcd_port); - release_region(optcd_port, 4); - put_disk(optcd_disk); - return -EIO; - } - if (!version_ok()) { - printk(KERN_ERR "optcd: unknown drive detected; aborting\n"); - release_region(optcd_port, 4); - put_disk(optcd_disk); - return -EIO; - } - status = exec_cmd(COMINITDOUBLE); - if (status < 0) { - printk(KERN_ERR "optcd: cannot init double speed mode\n"); - release_region(optcd_port, 4); - DEBUG((DEBUG_VFS, "exec_cmd COMINITDOUBLE: %02x", -status)); - put_disk(optcd_disk); - return -EIO; - } - if (register_blkdev(MAJOR_NR, "optcd")) { - release_region(optcd_port, 4); - put_disk(optcd_disk); - return -EIO; - } - - - opt_queue = blk_init_queue(do_optcd_request, &optcd_lock); - if (!opt_queue) { - unregister_blkdev(MAJOR_NR, "optcd"); - release_region(optcd_port, 4); - put_disk(optcd_disk); - return -ENOMEM; - } - - blk_queue_hardsect_size(opt_queue, 2048); - optcd_disk->queue = opt_queue; - add_disk(optcd_disk); - - printk(KERN_INFO "optcd: DOLPHIN 8000 AT CDROM at 0x%x\n", optcd_port); - return 0; -} - - -static void __exit optcd_exit(void) -{ - del_gendisk(optcd_disk); - put_disk(optcd_disk); - if (unregister_blkdev(MAJOR_NR, "optcd") == -EINVAL) { - printk(KERN_ERR "optcd: what's that: can't unregister\n"); - return; - } - blk_cleanup_queue(opt_queue); - release_region(optcd_port, 4); - printk(KERN_INFO "optcd: module released.\n"); -} - -module_init(optcd_init); -module_exit(optcd_exit); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS_BLOCKDEV_MAJOR(OPTICS_CDROM_MAJOR); diff --git a/drivers/cdrom/optcd.h b/drivers/cdrom/optcd.h deleted file mode 100644 index 1911bb92ee28..000000000000 --- a/drivers/cdrom/optcd.h +++ /dev/null @@ -1,52 +0,0 @@ -/* linux/include/linux/optcd.h - Optics Storage 8000 AT CDROM driver - $Id: optcd.h,v 1.2 1996/01/15 18:43:44 root Exp root $ - - Copyright (C) 1995 Leo Spiekman (spiekman@dutette.et.tudelft.nl) - - - Configuration file for linux/drivers/cdrom/optcd.c -*/ - -#ifndef _LINUX_OPTCD_H -#define _LINUX_OPTCD_H - - -/* I/O base of drive. Drive uses base to base+2. - This setting can be overridden with the kernel or insmod command - line option 'optcd='. Use address of 0 to disable driver. */ -#define OPTCD_PORTBASE 0x340 - - -/* enable / disable parts of driver by define / undef */ -#define MULTISESSION /* multisession support (ALPHA) */ - - -/* Change 0 to 1 to debug various parts of the driver */ -#define DEBUG_DRIVE_IF 0 /* Low level drive interface */ -#define DEBUG_CONV 0 /* Address conversions */ -#define DEBUG_BUFFERS 0 /* Buffering and block size conversion */ -#define DEBUG_REQUEST 0 /* Request mechanism */ -#define DEBUG_STATE 0 /* State machine */ -#define DEBUG_TOC 0 /* Q-channel and Table of Contents */ -#define DEBUG_MULTIS 0 /* Multisession code */ -#define DEBUG_VFS 0 /* VFS interface */ - - -/* Don't touch these unless you know what you're doing. */ - -/* Various timeout loop repetition counts. */ -#define BUSY_TIMEOUT 10000000 /* for busy wait */ -#define FAST_TIMEOUT 100000 /* ibid. for probing */ -#define SLEEP_TIMEOUT 6000 /* for timer wait */ -#define MULTI_SEEK_TIMEOUT 1000 /* for timer wait */ -#define READ_TIMEOUT 6000 /* for poll wait */ -#define STOP_TIMEOUT 2000 /* for poll wait */ -#define RESET_WAIT 5000 /* busy wait at drive reset */ - -/* # of buffers for block size conversion. 6 is optimal for my setup (P75), - giving 280 kb/s, with 0.4% CPU usage. Experiment to find your optimal - setting */ -#define N_BUFS 6 - - -#endif /* _LINUX_OPTCD_H */ diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c deleted file mode 100644 index a1283b1ef989..000000000000 --- a/drivers/cdrom/sbpcd.c +++ /dev/null @@ -1,5966 +0,0 @@ -/* - * sbpcd.c CD-ROM device driver for the whole family of traditional, - * non-ATAPI IDE-style Matsushita/Panasonic CR-5xx drives. - * Works with SoundBlaster compatible cards and with "no-sound" - * interface cards like Lasermate, Panasonic CI-101P, Teac, ... - * Also for the Longshine LCS-7260 drive. - * Also for the IBM "External ISA CD-Rom" drive. - * Also for the CreativeLabs CD200 drive. - * Also for the TEAC CD-55A drive. - * Also for the ECS-AT "Vertos 100" drive. - * Not for Sanyo drives (but for the H94A, sjcd is there...). - * Not for any other Funai drives than the CD200 types (sometimes - * labelled E2550UA or MK4015 or 2800F). - */ - -#define VERSION "v4.63 Andrew J. Kroll Wed Jul 26 04:24:10 EDT 2000" - -/* Copyright (C) 1993, 1994, 1995 Eberhard Moenkeberg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * You should have received a copy of the GNU General Public License - * (for example /usr/src/linux/COPYING); if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * If you change this software, you should mail a .diff file with some - * description lines to emoenke@gwdg.de. I want to know about it. - * - * If you are the editor of a Linux CD, you should enable sbpcd.c within - * your boot floppy kernel and send me one of your CDs for free. - * - * If you would like to port the driver to an other operating system (f.e. - * FreeBSD or NetBSD) or use it as an information source, you shall not be - * restricted by the GPL under the following conditions: - * a) the source code of your work is freely available - * b) my part of the work gets mentioned at all places where your - * authorship gets mentioned - * c) I receive a copy of your code together with a full installation - * package of your operating system for free. - * - * - * VERSION HISTORY - * - * 0.1 initial release, April/May 93, after mcd.c (Martin Harriss) - * - * 0.2 thek "repeat:"-loop in do_sbpcd_request did not check for - * end-of-request_queue (resulting in kernel panic). - * Flow control seems stable, but throughput is not better. - * - * 0.3 interrupt locking totally eliminated (maybe "inb" and "outb" - * are still locking) - 0.2 made keyboard-type-ahead losses. - * check_sbpcd_media_change added (to use by isofs/inode.c) - * - but it detects almost nothing. - * - * 0.4 use MAJOR 25 definitely. - * Almost total re-design to support double-speed drives and - * "naked" (no sound) interface cards ("LaserMate" interface type). - * Flow control should be exact now. - * Don't occupy the SbPro IRQ line (not needed either); will - * live together with Hannu Savolainen's sndkit now. - * Speeded up data transfer to 150 kB/sec, with help from Kai - * Makisara, the "provider" of the "mt" tape utility. - * Give "SpinUp" command if necessary. - * First steps to support up to 4 drives (but currently only one). - * Implemented audio capabilities - workman should work, xcdplayer - * gives some problems. - * This version is still consuming too much CPU time, and - * sleeping still has to be worked on. - * During "long" implied seeks, it seems possible that a - * ReadStatus command gets ignored. That gives the message - * "ResponseStatus timed out" (happens about 6 times here during - * a "ls -alR" of the YGGDRASIL LGX-Beta CD). Such a case is - * handled without data error, but it should get done better. - * - * 0.5 Free CPU during waits (again with help from Kai Makisara). - * Made it work together with the LILO/kernel setup standard. - * Included auto-probing code, as suggested by YGGDRASIL. - * Formal redesign to add DDI debugging. - * There are still flaws in IOCTL (workman with double speed drive). - * - * 1.0 Added support for all drive IDs (0...3, no longer only 0) - * and up to 4 drives on one controller. - * Added "#define MANY_SESSION" for "old" multi session CDs. - * - * 1.1 Do SpinUp for new drives, too. - * Revised for clean compile under "old" kernels (0.99pl9). - * - * 1.2 Found the "workman with double-speed drive" bug: use the driver's - * audio_state, not what the drive is reporting with ReadSubQ. - * - * 1.3 Minor cleanups. - * Refinements regarding Workman. - * - * 1.4 Read XA disks (PhotoCDs) with "old" drives, too (but only the first - * session - no chance to fully access a "multi-session" CD). - * This currently still is too slow (50 kB/sec) - but possibly - * the old drives won't do it faster. - * Implemented "door (un)lock" for new drives (still does not work - * as wanted - no lock possible after an unlock). - * Added some debugging printout for the UPC/EAN code - but my drives - * return only zeroes. Is there no UPC/EAN code written? - * - * 1.5 Laborate with UPC/EAN code (not better yet). - * Adapt to kernel 1.1.8 change (have to explicitly include - * now). - * - * 1.6 Trying to read audio frames as data. Impossible with the current - * drive firmware levels, as it seems. Awaiting any hint. ;-) - * Changed "door unlock": repeat it until success. - * Changed CDROMSTOP routine (stop somewhat "softer" so that Workman - * won't get confused). - * Added a third interface type: Sequoia S-1000, as used with the SPEA - * Media FX sound card. This interface (usable for Sony and Mitsumi - * drives, too) needs a special configuration setup and behaves like a - * LaserMate type after that. Still experimental - I do not have such - * an interface. - * Use the "variable BLOCK_SIZE" feature (2048). But it does only work - * if you give the mount option "block=2048". - * The media_check routine is currently disabled; now that it gets - * called as it should I fear it must get synchronized for not to - * disturb the normal driver's activity. - * - * 2.0 Version number bumped - two reasons: - * - reading audio tracks as data works now with CR-562 and CR-563. We - * currently do it by an IOCTL (yet has to get standardized), one frame - * at a time; that is pretty slow. But it works. - * - we are maintaining now up to 4 interfaces (each up to 4 drives): - * did it the easy way - a different MAJOR (25, 26, ...) and a different - * copy of the driver (sbpcd.c, sbpcd2.c, sbpcd3.c, sbpcd4.c - only - * distinguished by the value of SBPCD_ISSUE and the driver's name), - * and a common sbpcd.h file. - * Bettered the "ReadCapacity error" problem with old CR-52x drives (the - * drives sometimes need a manual "eject/insert" before work): just - * reset the drive and do again. Needs lots of resets here and sometimes - * that does not cure, so this can't be the solution. - * - * 2.1 Found bug with multisession CDs (accessing frame 16). - * "read audio" works now with address type CDROM_MSF, too. - * Bigger audio frame buffer: allows reading max. 4 frames at time; this - * gives a significant speedup, but reading more than one frame at once - * gives missing chunks at each single frame boundary. - * - * 2.2 Kernel interface cleanups: timers, init, setup, media check. - * - * 2.3 Let "door lock" and "eject" live together. - * Implemented "close tray" (done automatically during open). - * - * 2.4 Use different names for device registering. - * - * 2.5 Added "#if EJECT" code (default: enabled) to automatically eject - * the tray during last call to "sbpcd_release". - * Added "#if JUKEBOX" code (default: disabled) to automatically eject - * the tray during call to "sbpcd_open" if no disk is in. - * Turn on the CD volume of "compatible" sound cards, too; just define - * SOUND_BASE (in sbpcd.h) accordingly (default: disabled). - * - * 2.6 Nothing new. - * - * 2.7 Added CDROMEJECT_SW ioctl to set the "EJECT" behavior on the fly: - * 0 disables, 1 enables auto-ejecting. Useful to keep the tray in - * during shutdown. - * - * 2.8 Added first support (still BETA, I need feedback or a drive) for - * the Longshine LCS-7260 drives. They appear as double-speed drives - * using the "old" command scheme, extended by tray control and door - * lock functions. - * Found (and fixed preliminary) a flaw with some multisession CDs: we - * have to re-direct not only the accesses to frame 16 (the isofs - * routines drive it up to max. 100), but also those to the continuation - * (repetition) frames (as far as they exist - currently set fix as - * 16..20). - * Changed default of the "JUKEBOX" define. If you use this default, - * your tray will eject if you try to mount without a disk in. Next - * mount command will insert the tray - so, just fill in a disk. ;-) - * - * 2.9 Fulfilled the Longshine LCS-7260 support; with great help and - * experiments by Serge Robyns. - * First attempts to support the TEAC CD-55A drives; but still not - * usable yet. - * Implemented the CDROMMULTISESSION ioctl; this is an attempt to handle - * multi session CDs more "transparent" (redirection handling has to be - * done within the isofs routines, and only for the special purpose of - * obtaining the "right" volume descriptor; accesses to the raw device - * should not get redirected). - * - * 3.0 Just a "normal" increment, with some provisions to do it better. ;-) - * Introduced "#define READ_AUDIO" to specify the maximum number of - * audio frames to grab with one request. This defines a buffer size - * within kernel space; a value of 0 will reserve no such space and - * disable the CDROMREADAUDIO ioctl. A value of 75 enables the reading - * of a whole second with one command, but will use a buffer of more - * than 172 kB. - * Started CD200 support. Drive detection should work, but nothing - * more. - * - * 3.1 Working to support the CD200 and the Teac CD-55A drives. - * AT-BUS style device numbering no longer used: use SCSI style now. - * So, the first "found" device has MINOR 0, regardless of the - * jumpered drive ID. This implies modifications to the /dev/sbpcd* - * entries for some people, but will help the DAU (german TLA, english: - * "newbie", maybe ;-) to install his "first" system from a CD. - * - * 3.2 Still testing with CD200 and CD-55A drives. - * - * 3.3 Working with CD200 support. - * - * 3.4 Auto-probing stops if an address of 0 is seen (to be entered with - * the kernel command line). - * Made the driver "loadable". If used as a module, "audio copy" is - * disabled, and the internal read ahead data buffer has a reduced size - * of 4 kB; so, throughput may be reduced a little bit with slow CPUs. - * - * 3.5 Provisions to handle weird photoCDs which have an interrupted - * "formatting" immediately after the last frames of some files: simply - * never "read ahead" with MultiSession CDs. By this, CPU usage may be - * increased with those CDs, and there may be a loss in speed. - * Re-structured the messaging system. - * The "loadable" version no longer has a limited READ_AUDIO buffer - * size. - * Removed "MANY_SESSION" handling for "old" multi session CDs. - * Added "private" IOCTLs CDROMRESET and CDROMVOLREAD. - * Started again to support the TEAC CD-55A drives, now that I found - * the money for "my own" drive. ;-) - * The TEAC CD-55A support is fairly working now. - * I have measured that the drive "delivers" at 600 kB/sec (even with - * bigger requests than the drive's 64 kB buffer can satisfy), but - * the "real" rate does not exceed 520 kB/sec at the moment. - * Caused by the various changes to build in TEAC support, the timed - * loops are de-optimized at the moment (less throughput with CR-52x - * drives, and the TEAC will give speed only with SBP_BUFFER_FRAMES 64). - * - * 3.6 Fixed TEAC data read problems with SbPro interfaces. - * Initial size of the READ_AUDIO buffer is 0. Can get set to any size - * during runtime. - * - * 3.7 Introduced MAX_DRIVES for some poor interface cards (seen with TEAC - * drives) which allow only one drive (ID 0); this avoids repetitive - * detection under IDs 1..3. - * Elongated cmd_out_T response waiting; necessary for photo CDs with - * a lot of sessions. - * Bettered the sbpcd_open() behavior with TEAC drives. - * - * 3.8 Elongated max_latency for CR-56x drives. - * - * 3.9 Finally fixed the long-known SoundScape/SPEA/Sequoia S-1000 interface - * configuration bug. - * Now Corey, Heiko, Ken, Leo, Vadim/Eric & Werner are invited to copy - * the config_spea() routine into their drivers. ;-) - * - * 4.0 No "big step" - normal version increment. - * Adapted the benefits from 1.3.33. - * Fiddled with CDROMREADAUDIO flaws. - * Avoid ReadCapacity command with CD200 drives (the MKE 1.01 version - * seems not to support it). - * Fulfilled "read audio" for CD200 drives, with help of Pete Heist - * (heistp@rpi.edu). - * - * 4.1 Use loglevel KERN_INFO with printk(). - * Added support for "Vertos 100" drive ("ECS-AT") - it is very similar - * to the Longshine LCS-7260. Give feedback if you can - I never saw - * such a drive, and I have no specs. - * - * 4.2 Support for Teac 16-bit interface cards. Can't get auto-detected, - * so you have to jumper your card to 0x2C0. Still not 100% - come - * in contact if you can give qualified feedback. - * Use loglevel KERN_NOTICE with printk(). If you get annoyed by a - * flood of unwanted messages and the accompanied delay, try to read - * my documentation. Especially the Linux CDROM drivers have to do an - * important job for the newcomers, so the "distributed" version has - * to fit some special needs. Since generations, the flood of messages - * is user-configurable (even at runtime), but to get aware of this, one - * needs a special mental quality: the ability to read. - * - * 4.3 CD200F does not like to receive a command while the drive is - * reading the ToC; still trying to solve it. - * Removed some redundant verify_area calls (yes, Heiko Eissfeldt - * is visiting all the Linux CDROM drivers ;-). - * - * 4.4 Adapted one idea from tiensivu@pilot.msu.edu's "stripping-down" - * experiments: "KLOGD_PAUSE". - * Inhibited "play audio" attempts with data CDs. Provisions for a - * "data-safe" handling of "mixed" (data plus audio) Cds. - * - * 4.5 Meanwhile Gonzalo Tornaria (GTL) built a - * special end_request routine: we seem to have to take care for not - * to have two processes working at the request list. My understanding - * was and is that ll_rw_blk should not call do_sbpcd_request as long - * as there is still one call active (the first call will care for all - * outstanding I/Os, and if a second call happens, that is a bug in - * ll_rw_blk.c). - * "Check media change" without touching any drive. - * - * 4.6 Use a semaphore to synchronize multi-activity; elaborated by Rob - * Riggs . At the moment, we simply block "read" - * against "ioctl" and vice versa. This could be refined further, but - * I guess with almost no performance increase. - * Experiments to speed up the CD-55A; again with help of Rob Riggs - * (to be true, he gave both, idea & code. ;-) - * - * 4.61 Ported to Uniform CD-ROM driver by - * Heiko Eissfeldt with additional - * changes by Erik Andersen - * - * 4.62 Fix a bug where playing audio left the drive in an unusable state. - * Heiko Eissfeldt - * - * November 1999 -- Make kernel-parameter implementation work with 2.3.x - * Removed init_module & cleanup_module in favor of - * module_init & module_exit. - * Torben Mathiasen - * - * 4.63 Bug fixes for audio annoyances, new legacy CDROM maintainer. - * Annoying things fixed: - * TOC reread on automated disk changes - * TOC reread on manual cd changes - * Play IOCTL tries to play CD before it's actually ready... sometimes. - * CD_AUDIO_COMPLETED state so workman (and other playes) can repeat play. - * Andrew J. Kroll Wed Jul 26 04:24:10 EDT 2000 - * - * 4.64 Fix module parameters - were being completely ignored. - * Can also specify max_drives=N as a setup int to get rid of - * "ghost" drives on crap hardware (aren't they all?) Paul Gortmaker - * - * TODO - * implement "read all subchannel data" (96 bytes per frame) - * remove alot of the virtual status bits and deal with hardware status - * move the change of cd for audio to a better place - * add debug levels to insmod parameters (trivial) - * - * special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine - * elaborated speed-up experiments (and the fabulous results!), for - * the "push" towards load-free wait loops, and for the extensive mail - * thread which brought additional hints and bug fixes. - * - */ - -/* - * Trying to merge requests breaks this driver horribly (as in it goes - * boom and apparently has done so since 2.3.41). As it is a legacy - * driver for a horribly slow double speed CD on a hideous interface - * designed for polled operation, I won't lose any sleep in simply - * disallowing merging. Paul G. 02/2001 - * - * Thu May 30 14:14:47 CEST 2002: - * - * I have presumably found the reson for the above - there was a bogous - * end_request substitute, which was manipulating the request queues - * incorrectly. If someone has access to the actual hardware, and it's - * still operations - well please free to test it. - * - * Marcin Dalecki - */ - -/* - * Add bio/kdev_t changes for 2.5.x required to make it work again. - * Still room for improvement in the request handling here if anyone - * actually cares. Bring your own chainsaw. Paul G. 02/2002 - */ - - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include "sbpcd.h" - -#define MAJOR_NR MATSUSHITA_CDROM_MAJOR -#include - -/*==========================================================================*/ -#if SBPCD_DIS_IRQ -# define SBPCD_CLI cli() -# define SBPCD_STI sti() -#else -# define SBPCD_CLI -# define SBPCD_STI -#endif - -/*==========================================================================*/ -/* - * auto-probing address list - * inspired by Adam J. Richter from Yggdrasil - * - * still not good enough - can cause a hang. - * example: a NE 2000 ethernet card at 300 will cause a hang probing 310. - * if that happens, reboot and use the LILO (kernel) command line. - * The possibly conflicting ethernet card addresses get NOT probed - * by default - to minimize the hang possibilities. - * - * The SB Pro addresses get "mirrored" at 0x6xx and some more locations - to - * avoid a type error, the 0x2xx-addresses must get checked before 0x6xx. - * - * send mail to emoenke@gwdg.de if your interface card is not FULLY - * represented here. - */ -static int sbpcd[] = -{ - CDROM_PORT, SBPRO, /* probe with user's setup first */ -#if DISTRIBUTION - 0x230, 1, /* Soundblaster Pro and 16 (default) */ -#if 0 - 0x300, 0, /* CI-101P (default), WDH-7001C (default), - Galaxy (default), Reveal (one default) */ - 0x250, 1, /* OmniCD default, Soundblaster Pro and 16 */ - 0x2C0, 3, /* Teac 16-bit cards */ - 0x260, 1, /* OmniCD */ - 0x320, 0, /* Lasermate, CI-101P, WDH-7001C, Galaxy, Reveal (other default), - Longshine LCS-6853 (default) */ - 0x338, 0, /* Reveal Sound Wave 32 card model #SC600 */ - 0x340, 0, /* Mozart sound card (default), Lasermate, CI-101P */ - 0x360, 0, /* Lasermate, CI-101P */ - 0x270, 1, /* Soundblaster 16 */ - 0x670, 0, /* "sound card #9" */ - 0x690, 0, /* "sound card #9" */ - 0x338, 2, /* SPEA Media FX, Ensonic SoundScape (default) */ - 0x328, 2, /* SPEA Media FX */ - 0x348, 2, /* SPEA Media FX */ - 0x634, 0, /* some newer sound cards */ - 0x638, 0, /* some newer sound cards */ - 0x230, 1, /* some newer sound cards */ - /* due to incomplete address decoding of the SbPro card, these must be last */ - 0x630, 0, /* "sound card #9" (default) */ - 0x650, 0, /* "sound card #9" */ -#ifdef MODULE - /* - * some "hazardous" locations (no harm with the loadable version) - * (will stop the bus if a NE2000 ethernet card resides at offset -0x10) - */ - 0x330, 0, /* Lasermate, CI-101P, WDH-7001C */ - 0x350, 0, /* Lasermate, CI-101P */ - 0x358, 2, /* SPEA Media FX */ - 0x370, 0, /* Lasermate, CI-101P */ - 0x290, 1, /* Soundblaster 16 */ - 0x310, 0, /* Lasermate, CI-101P, WDH-7001C */ -#endif /* MODULE */ -#endif -#endif /* DISTRIBUTION */ -}; - -/* - * Protects access to global structures etc. - */ -static __cacheline_aligned DEFINE_SPINLOCK(sbpcd_lock); -static struct request_queue *sbpcd_queue; - -/* You can only set the first pair, from old MODULE_PARM code. */ -static int sbpcd_set(const char *val, struct kernel_param *kp) -{ - get_options((char *)val, 2, (int *)sbpcd); - return 0; -} -module_param_call(sbpcd, sbpcd_set, NULL, NULL, 0); - -#define NUM_PROBE (sizeof(sbpcd) / sizeof(int)) - -/*==========================================================================*/ - -#define INLINE inline - -/*==========================================================================*/ -/* - * the forward references: - */ -static void sbp_sleep(u_int); -static void mark_timeout_delay(u_long); -static void mark_timeout_data(u_long); -#if 0 -static void mark_timeout_audio(u_long); -#endif -static void sbp_read_cmd(struct request *req); -static int sbp_data(struct request *req); -static int cmd_out(void); -static int DiskInfo(void); - -/*==========================================================================*/ - -/* - * pattern for printk selection: - * - * (1<99) msgnum=0; - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - printk(MSG_LEVEL "%s-%d [%02d]: %s", major_name, current_drive - D_S, msgnum, buf); -#if KLOGD_PAUSE - sbp_sleep(KLOGD_PAUSE); /* else messages get lost */ -#endif /* KLOGD_PAUSE */ - return; -} -/*==========================================================================*/ -/* - * DDI interface: runtime trace bit pattern maintenance - */ -static int sbpcd_dbg_ioctl(unsigned long arg, int level) -{ - switch(arg) - { - case 0: /* OFF */ - sbpcd_debug = DBG_INF; - break; - - default: - if (arg>=128) sbpcd_debug &= ~(1<<(arg-128)); - else sbpcd_debug |= (1<>4)); -} -/*==========================================================================*/ -static INLINE u_char byt2bcd(u_char i) -{ - return (((i/10)<<4)+i%10); -} -/*==========================================================================*/ -static INLINE u_char bcd2bin(u_char bcd) -{ - return ((bcd>>4)*10+(bcd&0x0F)); -} -/*==========================================================================*/ -static INLINE int msf2blk(int msfx) -{ - MSF msf; - int i; - - msf.n=msfx; - i=(msf.c[2] * CD_SECS + msf.c[1]) * CD_FRAMES + msf.c[0] - CD_MSF_OFFSET; - if (i<0) return (0); - return (i); -} -/*==========================================================================*/ -/* - * convert m-s-f_number (3 bytes only) to logical_block_address - */ -static INLINE int msf2lba(u_char *msf) -{ - int i; - - i=(msf[0] * CD_SECS + msf[1]) * CD_FRAMES + msf[2] - CD_MSF_OFFSET; - if (i<0) return (0); - return (i); -} -/*==========================================================================*/ -/* evaluate cc_ReadError code */ -static int sta2err(int sta) -{ - if (famT_drive) - { - if (sta==0x00) return (0); - if (sta==0x01) return (-604); /* CRC error */ - if (sta==0x02) return (-602); /* drive not ready */ - if (sta==0x03) return (-607); /* unknown media */ - if (sta==0x04) return (-612); /* general failure */ - if (sta==0x05) return (0); - if (sta==0x06) return (-ERR_DISKCHANGE); /* disk change */ - if (sta==0x0b) return (-612); /* general failure */ - if (sta==0xff) return (-612); /* general failure */ - return (0); - } - else - { - if (sta<=2) return (sta); - if (sta==0x05) return (-604); /* CRC error */ - if (sta==0x06) return (-606); /* seek error */ - if (sta==0x0d) return (-606); /* seek error */ - if (sta==0x0e) return (-603); /* unknown command */ - if (sta==0x14) return (-603); /* unknown command */ - if (sta==0x0c) return (-611); /* read fault */ - if (sta==0x0f) return (-611); /* read fault */ - if (sta==0x10) return (-611); /* read fault */ - if (sta>=0x16) return (-612); /* general failure */ - if (sta==0x11) return (-ERR_DISKCHANGE); /* disk change (LCS: removed) */ - if (famL_drive) - if (sta==0x12) return (-ERR_DISKCHANGE); /* disk change (inserted) */ - return (-602); /* drive not ready */ - } -} -/*==========================================================================*/ -static INLINE void clr_cmdbuf(void) -{ - int i; - - for (i=0;i<10;i++) drvcmd[i]=0; - cmd_type=0; -} -/*==========================================================================*/ -static void flush_status(void) -{ - int i; - - sbp_sleep(15*HZ/10); - for (i=maxtim_data;i!=0;i--) inb(CDi_status); -} -/*====================================================================*/ -/* - * CDi status loop for Teac CD-55A (Rob Riggs) - * - * This is needed because for some strange reason - * the CD-55A can take a real long time to give a - * status response. This seems to happen after we - * issue a READ command where a long seek is involved. - * - * I tried to ensure that we get max throughput with - * minimal busy waiting. We busy wait at first, then - * "switch gears" and start sleeping. We sleep for - * longer periods of time the longer we wait. - * - */ -static int CDi_stat_loop_T(void) -{ - int i, gear=1; - u_long timeout_1, timeout_2, timeout_3, timeout_4; - - timeout_1 = jiffies + HZ / 50; /* sbp_sleep(0) for a short period */ - timeout_2 = jiffies + HZ / 5; /* nap for no more than 200ms */ - timeout_3 = jiffies + 5 * HZ; /* sleep for up to 5s */ - timeout_4 = jiffies + 45 * HZ; /* long sleep for up to 45s. */ - do - { - i = inb(CDi_status); - if (!(i&s_not_data_ready)) return (i); - if (!(i&s_not_result_ready)) return (i); - switch(gear) - { - case 4: - sbp_sleep(HZ); - if (time_after(jiffies, timeout_4)) gear++; - msg(DBG_TEA, "CDi_stat_loop_T: long sleep active.\n"); - break; - case 3: - sbp_sleep(HZ/10); - if (time_after(jiffies, timeout_3)) gear++; - break; - case 2: - sbp_sleep(HZ/100); - if (time_after(jiffies, timeout_2)) gear++; - break; - case 1: - sbp_sleep(0); - if (time_after(jiffies, timeout_1)) gear++; - } - } while (gear < 5); - return -1; -} -/*==========================================================================*/ -static int CDi_stat_loop(void) -{ - int i,j; - - for(timeout = jiffies + 10*HZ, i=maxtim_data; time_before(jiffies, timeout); ) - { - for ( ;i!=0;i--) - { - j=inb(CDi_status); - if (!(j&s_not_data_ready)) return (j); - if (!(j&s_not_result_ready)) return (j); - if (fam0L_drive) if (j&s_attention) return (j); - } - sbp_sleep(1); - i = 1; - } - msg(DBG_LCS,"CDi_stat_loop failed in line %d\n", __LINE__); - return (-1); -} -/*==========================================================================*/ -#if 00000 -/*==========================================================================*/ -static int tst_DataReady(void) -{ - int i; - - i=inb(CDi_status); - if (i&s_not_data_ready) return (0); - return (1); -} -/*==========================================================================*/ -static int tst_ResultReady(void) -{ - int i; - - i=inb(CDi_status); - if (i&s_not_result_ready) return (0); - return (1); -} -/*==========================================================================*/ -static int tst_Attention(void) -{ - int i; - - i=inb(CDi_status); - if (i&s_attention) return (1); - return (0); -} -/*==========================================================================*/ -#endif -/*==========================================================================*/ -static int ResponseInfo(void) -{ - int i,j,st=0; - u_long timeout; - - for (i=0,timeout=jiffies+HZ;i0) msg(DBG_INF,"ResponseInfo: got %d trailing bytes.\n",j); -#endif /* 000 */ - for (j=0;j0) return (-j); - else return (i); -} -/*==========================================================================*/ -static void EvaluateStatus(int st) -{ - current_drive->status_bits=0; - if (fam1_drive) current_drive->status_bits=st|p_success; - else if (fam0_drive) - { - if (st&p_caddin_old) current_drive->status_bits |= p_door_closed|p_caddy_in; - if (st&p_spinning) current_drive->status_bits |= p_spinning; - if (st&p_check) current_drive->status_bits |= p_check; - if (st&p_success_old) current_drive->status_bits |= p_success; - if (st&p_busy_old) current_drive->status_bits |= p_busy_new; - if (st&p_disk_ok) current_drive->status_bits |= p_disk_ok; - } - else if (famLV_drive) - { - current_drive->status_bits |= p_success; - if (st&p_caddin_old) current_drive->status_bits |= p_disk_ok|p_caddy_in; - if (st&p_spinning) current_drive->status_bits |= p_spinning; - if (st&p_check) current_drive->status_bits |= p_check; - if (st&p_busy_old) current_drive->status_bits |= p_busy_new; - if (st&p_lcs_door_closed) current_drive->status_bits |= p_door_closed; - if (st&p_lcs_door_locked) current_drive->status_bits |= p_door_locked; - } - else if (fam2_drive) - { - current_drive->status_bits |= p_success; - if (st&p2_check) current_drive->status_bits |= p1_check; - if (st&p2_door_closed) current_drive->status_bits |= p1_door_closed; - if (st&p2_disk_in) current_drive->status_bits |= p1_disk_in; - if (st&p2_busy1) current_drive->status_bits |= p1_busy; - if (st&p2_busy2) current_drive->status_bits |= p1_busy; - if (st&p2_spinning) current_drive->status_bits |= p1_spinning; - if (st&p2_door_locked) current_drive->status_bits |= p1_door_locked; - if (st&p2_disk_ok) current_drive->status_bits |= p1_disk_ok; - } - else if (famT_drive) - { - return; /* still needs to get coded */ - current_drive->status_bits |= p_success; - if (st&p2_check) current_drive->status_bits |= p1_check; - if (st&p2_door_closed) current_drive->status_bits |= p1_door_closed; - if (st&p2_disk_in) current_drive->status_bits |= p1_disk_in; - if (st&p2_busy1) current_drive->status_bits |= p1_busy; - if (st&p2_busy2) current_drive->status_bits |= p1_busy; - if (st&p2_spinning) current_drive->status_bits |= p1_spinning; - if (st&p2_door_locked) current_drive->status_bits |= p1_door_locked; - if (st&p2_disk_ok) current_drive->status_bits |= p1_disk_ok; - } - return; -} -/*==========================================================================*/ -static int cmd_out_T(void); - -static int get_state_T(void) -{ - int i; - - clr_cmdbuf(); - current_drive->n_bytes=1; - drvcmd[0]=CMDT_STATUS; - i=cmd_out_T(); - if (i>=0) i=infobuf[0]; - else - { - msg(DBG_TEA,"get_state_T error %d\n", i); - return (i); - } - if (i>=0) - /* 2: closed, disk in */ - current_drive->status_bits=p1_door_closed|p1_disk_in|p1_spinning|p1_disk_ok; - else if (current_drive->error_state==6) - { - /* 3: closed, disk in, changed ("06 xx xx") */ - current_drive->status_bits=p1_door_closed|p1_disk_in; - current_drive->CD_changed=0xFF; - current_drive->diskstate_flags &= ~toc_bit; - } - else if ((current_drive->error_state!=2)||(current_drive->b3!=0x3A)||(current_drive->b4==0x00)) - { - /* 1: closed, no disk ("xx yy zz"or "02 3A 00") */ - current_drive->status_bits=p1_door_closed; - current_drive->open_count=0; - } - else if (current_drive->b4==0x01) - { - /* 0: open ("02 3A 01") */ - current_drive->status_bits=0; - current_drive->open_count=0; - } - else - { - /* 1: closed, no disk ("02 3A xx") */ - current_drive->status_bits=p1_door_closed; - current_drive->open_count=0; - } - return (current_drive->status_bits); -} -/*==========================================================================*/ -static int ResponseStatus(void) -{ - int i,j; - u_long timeout; - - msg(DBG_STA,"doing ResponseStatus...\n"); - if (famT_drive) return (get_state_T()); - if (flags_cmd_out & f_respo3) timeout = jiffies; - else if (flags_cmd_out & f_respo2) timeout = jiffies + 16*HZ; - else timeout = jiffies + 4*HZ; - j=maxtim_8; - do - { - for ( ;j!=0;j--) - { - i=inb(CDi_status); - if (!(i&s_not_result_ready)) break; - } - if ((j!=0)||time_after(jiffies, timeout)) break; - sbp_sleep(1); - j = 1; - } - while (1); - if (j==0) - { - if ((flags_cmd_out & f_respo3) == 0) - msg(DBG_STA,"ResponseStatus: timeout.\n"); - current_drive->status_bits=0; - return (-401); - } - i=inb(CDi_info); - msg(DBG_STA,"ResponseStatus: response %02X.\n", i); - EvaluateStatus(i); - msg(DBG_STA,"status_bits=%02X, i=%02X\n",current_drive->status_bits,i); - return (current_drive->status_bits); -} -/*==========================================================================*/ -static void cc_ReadStatus(void) -{ - int i; - - msg(DBG_STA,"giving cc_ReadStatus command\n"); - if (famT_drive) return; - SBPCD_CLI; - if (fam0LV_drive) OUT(CDo_command,CMD0_STATUS); - else if (fam1_drive) OUT(CDo_command,CMD1_STATUS); - else if (fam2_drive) OUT(CDo_command,CMD2_STATUS); - if (!fam0LV_drive) for (i=0;i<6;i++) OUT(CDo_command,0); - SBPCD_STI; -} -/*==========================================================================*/ -static int cc_ReadError(void) -{ - int i; - - clr_cmdbuf(); - msg(DBG_ERR,"giving cc_ReadError command.\n"); - if (fam1_drive) - { - drvcmd[0]=CMD1_READ_ERR; - response_count=8; - flags_cmd_out=f_putcmd|f_ResponseStatus; - } - else if (fam0LV_drive) - { - drvcmd[0]=CMD0_READ_ERR; - response_count=6; - if (famLV_drive) - flags_cmd_out=f_putcmd; - else - flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus; - } - else if (fam2_drive) - { - drvcmd[0]=CMD2_READ_ERR; - response_count=6; - flags_cmd_out=f_putcmd; - } - else if (famT_drive) - { - response_count=5; - drvcmd[0]=CMDT_READ_ERR; - } - i=cmd_out(); - current_drive->error_byte=0; - msg(DBG_ERR,"cc_ReadError: cmd_out(CMDx_READ_ERR) returns %d (%02X)\n",i,i); - if (i<0) return (i); - if (fam0V_drive) i=1; - else i=2; - current_drive->error_byte=infobuf[i]; - msg(DBG_ERR,"cc_ReadError: infobuf[%d] is %d (%02X)\n",i,current_drive->error_byte,current_drive->error_byte); - i=sta2err(infobuf[i]); - if (i==-ERR_DISKCHANGE) - { - current_drive->CD_changed=0xFF; - current_drive->diskstate_flags &= ~toc_bit; - } - return (i); -} -/*==========================================================================*/ -static int cc_DriveReset(void); - -static int cmd_out_T(void) -{ -#undef CMDT_TRIES -#define CMDT_TRIES 1000 -#define TEST_FALSE_FF 1 - - int i, j, l=0, m, ntries; - unsigned long flags; - - current_drive->error_state=0; - current_drive->b3=0; - current_drive->b4=0; - current_drive->f_drv_error=0; - for (i=0;i<10;i++) sprintf(&msgbuf[i*3]," %02X",drvcmd[i]); - msgbuf[i*3]=0; - msg(DBG_CMD,"cmd_out_T:%s\n",msgbuf); - - OUT(CDo_sel_i_d,0); - OUT(CDo_enable,current_drive->drv_sel); - i=inb(CDi_status); - do_16bit=0; - if ((f_16bit)&&(!(i&0x80))) - { - do_16bit=1; - msg(DBG_TEA,"cmd_out_T: do_16bit set.\n"); - } - if (!(i&s_not_result_ready)) - do - { - j=inb(CDi_info); - i=inb(CDi_status); - sbp_sleep(0); - msg(DBG_TEA,"cmd_out_T: spurious !s_not_result_ready. (%02X)\n", j); - } - while (!(i&s_not_result_ready)); - save_flags(flags); cli(); - for (i=0;i<10;i++) OUT(CDo_command,drvcmd[i]); - restore_flags(flags); - for (ntries=CMDT_TRIES;ntries>0;ntries--) - { - if (drvcmd[0]==CMDT_READ_VER) sbp_sleep(HZ); /* fixme */ -#if 01 - OUT(CDo_sel_i_d,1); -#endif /* 01 */ - if (teac==2) - { - if ((i=CDi_stat_loop_T()) == -1) break; - } - else - { -#if 0 - OUT(CDo_sel_i_d,1); -#endif /* 0 */ - i=inb(CDi_status); - } - if (!(i&s_not_data_ready)) /* f.e. CMDT_DISKINFO */ - { - OUT(CDo_sel_i_d,1); - if (drvcmd[0]==CMDT_READ) return (0); /* handled elsewhere */ - if (drvcmd[0]==CMDT_DISKINFO) - { - l=0; - do - { - if (do_16bit) - { - i=inw(CDi_data); - infobuf[l++]=i&0x0ff; - infobuf[l++]=i>>8; -#if TEST_FALSE_FF - if ((l==2)&&(infobuf[0]==0x0ff)) - { - infobuf[0]=infobuf[1]; - l=1; - msg(DBG_TEA,"cmd_out_T: do_16bit: false first byte!\n"); - } -#endif /* TEST_FALSE_FF */ - } - else infobuf[l++]=inb(CDi_data); - i=inb(CDi_status); - } - while (!(i&s_not_data_ready)); - for (j=0;j1) msg(DBG_TEA,"cmd_out_T READ_ERR recursion (%02X): %d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n", drvcmd[0], recursion); - clr_cmdbuf(); - drvcmd[0]=CMDT_READ_ERR; - j=cmd_out_T(); /* !!! recursive here !!! */ - --recursion; - sbp_sleep(1); - } - while (j<0); - current_drive->error_state=infobuf[2]; - current_drive->b3=infobuf[3]; - current_drive->b4=infobuf[4]; - if (current_drive->f_drv_error) - { - current_drive->f_drv_error=0; - cc_DriveReset(); - current_drive->error_state=2; - } - return (-current_drive->error_state-400); - } - if (drvcmd[0]==CMDT_READ) return (0); /* handled elsewhere */ - if ((teac==0)||(ntries<(CMDT_TRIES-5))) sbp_sleep(HZ/10); - else sbp_sleep(HZ/100); - if (ntries>(CMDT_TRIES-50)) continue; - msg(DBG_TEA,"cmd_out_T: next CMDT_TRIES (%02X): %d.\n", drvcmd[0], ntries-1); - } - current_drive->f_drv_error=1; - cc_DriveReset(); - current_drive->error_state=2; - return (-99); -} -/*==========================================================================*/ -static int cmd_out(void) -{ - int i=0; - - if (famT_drive) return(cmd_out_T()); - - if (flags_cmd_out&f_putcmd) - { - unsigned long flags; - for (i=0;i<7;i++) - sprintf(&msgbuf[i*3], " %02X", drvcmd[i]); - msgbuf[i*3]=0; - msg(DBG_CMD,"cmd_out:%s\n", msgbuf); - save_flags(flags); cli(); - for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]); - restore_flags(flags); - } - if (response_count!=0) - { - if (cmd_type!=0) - { - if (sbpro_type==1) OUT(CDo_sel_i_d,1); - msg(DBG_INF,"misleaded to try ResponseData.\n"); - if (sbpro_type==1) OUT(CDo_sel_i_d,0); - return (-22); - } - else i=ResponseInfo(); - if (i<0) return (i); - } - if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to CDi_stat_loop.\n"); - if (flags_cmd_out&f_lopsta) - { - i=CDi_stat_loop(); - if ((i<0)||!(i&s_attention)) return (-8); - } - if (!(flags_cmd_out&f_getsta)) goto LOC_229; - - LOC_228: - if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cc_ReadStatus.\n"); - cc_ReadStatus(); - - LOC_229: - if (flags_cmd_out&f_ResponseStatus) - { - if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to ResponseStatus.\n"); - i=ResponseStatus(); - /* builds status_bits, returns orig. status or p_busy_new */ - if (i<0) return (i); - if (flags_cmd_out&(f_bit1|f_wait_if_busy)) - { - if (!st_check) - { - if ((flags_cmd_out&f_bit1)&&(i&p_success)) goto LOC_232; - if ((!(flags_cmd_out&f_wait_if_busy))||(!st_busy)) goto LOC_228; - } - } - } - LOC_232: - if (!(flags_cmd_out&f_obey_p_check)) return (0); - if (!st_check) return (0); - if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cc_ReadError.\n"); - i=cc_ReadError(); - if (current_drive->in_SpinUp) msg(DBG_SPI,"in_SpinUp: to cmd_out OK.\n"); - msg(DBG_000,"cmd_out: cc_ReadError=%d\n", i); - return (i); -} -/*==========================================================================*/ -static int cc_Seek(u_int pos, char f_blk_msf) -{ - int i; - - clr_cmdbuf(); - if (f_blk_msf>1) return (-3); - if (fam0V_drive) - { - drvcmd[0]=CMD0_SEEK; - if (f_blk_msf==1) pos=msf2blk(pos); - drvcmd[2]=(pos>>16)&0x00FF; - drvcmd[3]=(pos>>8)&0x00FF; - drvcmd[4]=pos&0x00FF; - if (fam0_drive) - flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta | - f_ResponseStatus | f_obey_p_check | f_bit1; - else - flags_cmd_out = f_putcmd; - } - else if (fam1L_drive) - { - drvcmd[0]=CMD1_SEEK; /* same as CMD1_ and CMDL_ */ - if (f_blk_msf==0) pos=blk2msf(pos); - drvcmd[1]=(pos>>16)&0x00FF; - drvcmd[2]=(pos>>8)&0x00FF; - drvcmd[3]=pos&0x00FF; - if (famL_drive) - flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; - else - flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; - } - else if (fam2_drive) - { - drvcmd[0]=CMD2_SEEK; - if (f_blk_msf==0) pos=blk2msf(pos); - drvcmd[2]=(pos>>24)&0x00FF; - drvcmd[3]=(pos>>16)&0x00FF; - drvcmd[4]=(pos>>8)&0x00FF; - drvcmd[5]=pos&0x00FF; - flags_cmd_out=f_putcmd|f_ResponseStatus; - } - else if (famT_drive) - { - drvcmd[0]=CMDT_SEEK; - if (f_blk_msf==1) pos=msf2blk(pos); - drvcmd[2]=(pos>>24)&0x00FF; - drvcmd[3]=(pos>>16)&0x00FF; - drvcmd[4]=(pos>>8)&0x00FF; - drvcmd[5]=pos&0x00FF; - current_drive->n_bytes=1; - } - response_count=0; - i=cmd_out(); - return (i); -} -/*==========================================================================*/ -static int cc_SpinUp(void) -{ - int i; - - msg(DBG_SPI,"SpinUp.\n"); - current_drive->in_SpinUp = 1; - clr_cmdbuf(); - if (fam0LV_drive) - { - drvcmd[0]=CMD0_SPINUP; - if (fam0L_drive) - flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta| - f_ResponseStatus|f_obey_p_check|f_bit1; - else - flags_cmd_out=f_putcmd; - } - else if (fam1_drive) - { - drvcmd[0]=CMD1_SPINUP; - flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; - } - else if (fam2_drive) - { - drvcmd[0]=CMD2_TRAY_CTL; - drvcmd[4]=0x01; /* "spinup" */ - flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; - } - else if (famT_drive) - { - drvcmd[0]=CMDT_TRAY_CTL; - drvcmd[4]=0x03; /* "insert", it hopefully spins the drive up */ - } - response_count=0; - i=cmd_out(); - current_drive->in_SpinUp = 0; - return (i); -} -/*==========================================================================*/ -static int cc_SpinDown(void) -{ - int i; - - if (fam0_drive) return (0); - clr_cmdbuf(); - response_count=0; - if (fam1_drive) - { - drvcmd[0]=CMD1_SPINDOWN; - flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; - } - else if (fam2_drive) - { - drvcmd[0]=CMD2_TRAY_CTL; - drvcmd[4]=0x02; /* "eject" */ - flags_cmd_out=f_putcmd|f_ResponseStatus; - } - else if (famL_drive) - { - drvcmd[0]=CMDL_SPINDOWN; - drvcmd[1]=1; - flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; - } - else if (famV_drive) - { - drvcmd[0]=CMDV_SPINDOWN; - flags_cmd_out=f_putcmd; - } - else if (famT_drive) - { - drvcmd[0]=CMDT_TRAY_CTL; - drvcmd[4]=0x02; /* "eject" */ - } - i=cmd_out(); - return (i); -} -/*==========================================================================*/ -static int cc_get_mode_T(void) -{ - int i; - - clr_cmdbuf(); - response_count=10; - drvcmd[0]=CMDT_GETMODE; - drvcmd[4]=response_count; - i=cmd_out_T(); - return (i); -} -/*==========================================================================*/ -static int cc_set_mode_T(void) -{ - int i; - - clr_cmdbuf(); - response_count=1; - drvcmd[0]=CMDT_SETMODE; - drvcmd[1]=current_drive->speed_byte; - drvcmd[2]=current_drive->frmsiz>>8; - drvcmd[3]=current_drive->frmsiz&0x0FF; - drvcmd[4]=current_drive->f_XA; /* 1: XA */ - drvcmd[5]=current_drive->type_byte; /* 0, 1, 3 */ - drvcmd[6]=current_drive->mode_xb_6; - drvcmd[7]=current_drive->mode_yb_7|current_drive->volume_control; - drvcmd[8]=current_drive->mode_xb_8; - drvcmd[9]=current_drive->delay; - i=cmd_out_T(); - return (i); -} -/*==========================================================================*/ -static int cc_prep_mode_T(void) -{ - int i, j; - - i=cc_get_mode_T(); - if (i<0) return (i); - for (i=0;i<10;i++) - sprintf(&msgbuf[i*3], " %02X", infobuf[i]); - msgbuf[i*3]=0; - msg(DBG_TEA,"CMDT_GETMODE:%s\n", msgbuf); - current_drive->speed_byte=0x02; /* 0x02: auto quad, 0x82: quad, 0x81: double, 0x80: single */ - current_drive->frmsiz=make16(infobuf[2],infobuf[3]); - current_drive->f_XA=infobuf[4]; - if (current_drive->f_XA==0) current_drive->type_byte=0; - else current_drive->type_byte=1; - current_drive->mode_xb_6=infobuf[6]; - current_drive->mode_yb_7=1; - current_drive->mode_xb_8=infobuf[8]; - current_drive->delay=0; /* 0, 1, 2, 3 */ - j=cc_set_mode_T(); - i=cc_get_mode_T(); - for (i=0;i<10;i++) - sprintf(&msgbuf[i*3], " %02X", infobuf[i]); - msgbuf[i*3]=0; - msg(DBG_TEA,"CMDT_GETMODE:%s\n", msgbuf); - return (j); -} -/*==========================================================================*/ -static int cc_SetSpeed(u_char speed, u_char x1, u_char x2) -{ - int i; - - if (fam0LV_drive) return (0); - clr_cmdbuf(); - response_count=0; - if (fam1_drive) - { - drvcmd[0]=CMD1_SETMODE; - drvcmd[1]=0x03; - drvcmd[2]=speed; - drvcmd[3]=x1; - drvcmd[4]=x2; - flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; - } - else if (fam2_drive) - { - drvcmd[0]=CMD2_SETSPEED; - if (speed&speed_auto) - { - drvcmd[2]=0xFF; - drvcmd[3]=0xFF; - } - else - { - drvcmd[2]=0; - drvcmd[3]=150; - } - flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; - } - else if (famT_drive) - { - return (0); - } - i=cmd_out(); - return (i); -} -/*==========================================================================*/ -static int cc_SetVolume(void) -{ - int i; - u_char channel0,channel1,volume0,volume1; - u_char control0,value0,control1,value1; - - current_drive->diskstate_flags &= ~volume_bit; - clr_cmdbuf(); - channel0=current_drive->vol_chan0; - volume0=current_drive->vol_ctrl0; - channel1=control1=current_drive->vol_chan1; - volume1=value1=current_drive->vol_ctrl1; - control0=value0=0; - - if (famV_drive) return (0); - - if (((current_drive->drv_options&audio_mono)!=0)&&(current_drive->drv_type>=drv_211)) - { - if ((volume0!=0)&&(volume1==0)) - { - volume1=volume0; - channel1=channel0; - } - else if ((volume0==0)&&(volume1!=0)) - { - volume0=volume1; - channel0=channel1; - } - } - if (channel0>1) - { - channel0=0; - volume0=0; - } - if (channel1>1) - { - channel1=1; - volume1=0; - } - - if (fam1_drive) - { - control0=channel0+1; - control1=channel1+1; - value0=(volume0>volume1)?volume0:volume1; - value1=value0; - if (volume0==0) control0=0; - if (volume1==0) control1=0; - drvcmd[0]=CMD1_SETMODE; - drvcmd[1]=0x05; - drvcmd[3]=control0; - drvcmd[4]=value0; - drvcmd[5]=control1; - drvcmd[6]=value1; - flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; - } - else if (fam2_drive) - { - control0=channel0+1; - control1=channel1+1; - value0=(volume0>volume1)?volume0:volume1; - value1=value0; - if (volume0==0) control0=0; - if (volume1==0) control1=0; - drvcmd[0]=CMD2_SETMODE; - drvcmd[1]=0x0E; - drvcmd[3]=control0; - drvcmd[4]=value0; - drvcmd[5]=control1; - drvcmd[6]=value1; - flags_cmd_out=f_putcmd|f_ResponseStatus; - } - else if (famL_drive) - { - if ((volume0==0)||(channel0!=0)) control0 |= 0x80; - if ((volume1==0)||(channel1!=1)) control0 |= 0x40; - if (volume0|volume1) value0=0x80; - drvcmd[0]=CMDL_SETMODE; - drvcmd[1]=0x03; - drvcmd[4]=control0; - drvcmd[5]=value0; - flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; - } - else if (fam0_drive) /* different firmware levels */ - { - if (current_drive->drv_type>=drv_300) - { - control0=volume0&0xFC; - value0=volume1&0xFC; - if ((volume0!=0)&&(volume0<4)) control0 |= 0x04; - if ((volume1!=0)&&(volume1<4)) value0 |= 0x04; - if (channel0!=0) control0 |= 0x01; - if (channel1==1) value0 |= 0x01; - } - else - { - value0=(volume0>volume1)?volume0:volume1; - if (current_drive->drv_typedrv_typedrv_type>=drv_201) - { - if (volume0==0) control0 |= 0x80; - if (volume1==0) control0 |= 0x40; - } - if (current_drive->drv_type>=drv_211) - { - if (channel0!=0) control0 |= 0x20; - if (channel1!=1) control0 |= 0x10; - } - } - drvcmd[0]=CMD0_SETMODE; - drvcmd[1]=0x83; - drvcmd[4]=control0; - drvcmd[5]=value0; - flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; - } - else if (famT_drive) - { - current_drive->volume_control=0; - if (!volume0) current_drive->volume_control|=0x10; - if (!volume1) current_drive->volume_control|=0x20; - i=cc_prep_mode_T(); - if (i<0) return (i); - } - if (!famT_drive) - { - response_count=0; - i=cmd_out(); - if (i<0) return (i); - } - current_drive->diskstate_flags |= volume_bit; - return (0); -} -/*==========================================================================*/ -static int GetStatus(void) -{ - int i; - - if (famT_drive) return (0); - flags_cmd_out=f_getsta|f_ResponseStatus|f_obey_p_check; - response_count=0; - cmd_type=0; - i=cmd_out(); - return (i); -} -/*==========================================================================*/ -static int cc_DriveReset(void) -{ - int i; - - msg(DBG_RES,"cc_DriveReset called.\n"); - clr_cmdbuf(); - response_count=0; - if (fam0LV_drive) OUT(CDo_reset,0x00); - else if (fam1_drive) - { - drvcmd[0]=CMD1_RESET; - flags_cmd_out=f_putcmd; - i=cmd_out(); - } - else if (fam2_drive) - { - drvcmd[0]=CMD2_RESET; - flags_cmd_out=f_putcmd; - i=cmd_out(); - OUT(CDo_reset,0x00); - } - else if (famT_drive) - { - OUT(CDo_sel_i_d,0); - OUT(CDo_enable,current_drive->drv_sel); - OUT(CDo_command,CMDT_RESET); - for (i=1;i<10;i++) OUT(CDo_command,0); - } - if (fam0LV_drive) sbp_sleep(5*HZ); /* wait 5 seconds */ - else sbp_sleep(1*HZ); /* wait a second */ -#if 1 - if (famT_drive) - { - msg(DBG_TEA, "================CMDT_RESET given=================.\n"); - sbp_sleep(3*HZ); - } -#endif /* 1 */ - flush_status(); - i=GetStatus(); - if (i<0) return i; - if (!famT_drive) - if (current_drive->error_byte!=aud_12) return -501; - return (0); -} - -/*==========================================================================*/ -static int SetSpeed(void) -{ - int i, speed; - - if (!(current_drive->drv_options&(speed_auto|speed_300|speed_150))) return (0); - speed=speed_auto; - if (!(current_drive->drv_options&speed_auto)) - { - speed |= speed_300; - if (!(current_drive->drv_options&speed_300)) speed=0; - } - i=cc_SetSpeed(speed,0,0); - return (i); -} - -static void switch_drive(struct sbpcd_drive *); - -static int sbpcd_select_speed(struct cdrom_device_info *cdi, int speed) -{ - struct sbpcd_drive *p = cdi->handle; - if (p != current_drive) - switch_drive(p); - - return cc_SetSpeed(speed == 2 ? speed_300 : speed_150, 0, 0); -} - -/*==========================================================================*/ -static int DriveReset(void) -{ - int i; - - i=cc_DriveReset(); - if (i<0) return (-22); - do - { - i=GetStatus(); - if ((i<0)&&(i!=-ERR_DISKCHANGE)) { - return (-2); /* from sta2err */ - } - if (!st_caddy_in) break; - sbp_sleep(1); - } - while (!st_diskok); -#if 000 - current_drive->CD_changed=1; -#endif - if ((st_door_closed) && (st_caddy_in)) - { - i=DiskInfo(); - if (i<0) return (-23); - } - return (0); -} - -static int sbpcd_reset(struct cdrom_device_info *cdi) -{ - struct sbpcd_drive *p = cdi->handle; - if (p != current_drive) - switch_drive(p); - return DriveReset(); -} - -/*==========================================================================*/ -static int cc_PlayAudio(int pos_audio_start,int pos_audio_end) -{ - int i, j, n; - - if (current_drive->audio_state==audio_playing) return (-EINVAL); - clr_cmdbuf(); - response_count=0; - if (famLV_drive) - { - drvcmd[0]=CMDL_PLAY; - i=msf2blk(pos_audio_start); - n=msf2blk(pos_audio_end)+1-i; - drvcmd[1]=(i>>16)&0x00FF; - drvcmd[2]=(i>>8)&0x00FF; - drvcmd[3]=i&0x00FF; - drvcmd[4]=(n>>16)&0x00FF; - drvcmd[5]=(n>>8)&0x00FF; - drvcmd[6]=n&0x00FF; - if (famL_drive) - flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta | - f_ResponseStatus | f_obey_p_check | f_wait_if_busy; - else - flags_cmd_out = f_putcmd; - } - else - { - j=1; - if (fam1_drive) - { - drvcmd[0]=CMD1_PLAY_MSF; - flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | - f_obey_p_check | f_wait_if_busy; - } - else if (fam2_drive) - { - drvcmd[0]=CMD2_PLAY_MSF; - flags_cmd_out = f_putcmd | f_ResponseStatus | f_obey_p_check; - } - else if (famT_drive) - { - drvcmd[0]=CMDT_PLAY_MSF; - j=3; - response_count=1; - } - else if (fam0_drive) - { - drvcmd[0]=CMD0_PLAY_MSF; - flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta | - f_ResponseStatus | f_obey_p_check | f_wait_if_busy; - } - drvcmd[j]=(pos_audio_start>>16)&0x00FF; - drvcmd[j+1]=(pos_audio_start>>8)&0x00FF; - drvcmd[j+2]=pos_audio_start&0x00FF; - drvcmd[j+3]=(pos_audio_end>>16)&0x00FF; - drvcmd[j+4]=(pos_audio_end>>8)&0x00FF; - drvcmd[j+5]=pos_audio_end&0x00FF; - } - i=cmd_out(); - return (i); -} -/*==========================================================================*/ -static int cc_Pause_Resume(int pau_res) -{ - int i; - - clr_cmdbuf(); - response_count=0; - if (fam1_drive) - { - drvcmd[0]=CMD1_PAU_RES; - if (pau_res!=1) drvcmd[1]=0x80; - flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; - } - else if (fam2_drive) - { - drvcmd[0]=CMD2_PAU_RES; - if (pau_res!=1) drvcmd[2]=0x01; - flags_cmd_out=f_putcmd|f_ResponseStatus; - } - else if (fam0LV_drive) - { - drvcmd[0]=CMD0_PAU_RES; - if (pau_res!=1) drvcmd[1]=0x80; - if (famL_drive) - flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus| - f_obey_p_check|f_bit1; - else if (famV_drive) - flags_cmd_out=f_putcmd; - else - flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus| - f_obey_p_check; - } - else if (famT_drive) - { - if (pau_res==3) return (cc_PlayAudio(current_drive->pos_audio_start,current_drive->pos_audio_end)); - else if (pau_res==1) drvcmd[0]=CMDT_PAUSE; - else return (-56); - } - i=cmd_out(); - return (i); -} -/*==========================================================================*/ -static int cc_LockDoor(char lock) -{ - int i; - - if (fam0_drive) return (0); - msg(DBG_LCK,"cc_LockDoor: %d (drive %d)\n", lock, current_drive - D_S); - msg(DBG_LCS,"p_door_locked bit %d before\n", st_door_locked); - clr_cmdbuf(); - response_count=0; - if (fam1_drive) - { - drvcmd[0]=CMD1_LOCK_CTL; - if (lock==1) drvcmd[1]=0x01; - flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; - } - else if (fam2_drive) - { - drvcmd[0]=CMD2_LOCK_CTL; - if (lock==1) drvcmd[4]=0x01; - flags_cmd_out=f_putcmd|f_ResponseStatus; - } - else if (famLV_drive) - { - drvcmd[0]=CMDL_LOCK_CTL; - if (lock==1) drvcmd[1]=0x01; - if (famL_drive) - flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; - else - flags_cmd_out=f_putcmd; - } - else if (famT_drive) - { - drvcmd[0]=CMDT_LOCK_CTL; - if (lock==1) drvcmd[4]=0x01; - } - i=cmd_out(); - msg(DBG_LCS,"p_door_locked bit %d after\n", st_door_locked); - return (i); -} -/*==========================================================================*/ -/*==========================================================================*/ -static int UnLockDoor(void) -{ - int i,j; - - j=20; - do - { - i=cc_LockDoor(0); - --j; - sbp_sleep(1); - } - while ((i<0)&&(j)); - if (i<0) - { - cc_DriveReset(); - return -84; - } - return (0); -} -/*==========================================================================*/ -static int LockDoor(void) -{ - int i,j; - - j=20; - do - { - i=cc_LockDoor(1); - --j; - sbp_sleep(1); - } - while ((i<0)&&(j)); - if (j==0) - { - cc_DriveReset(); - j=20; - do - { - i=cc_LockDoor(1); - --j; - sbp_sleep(1); - } - while ((i<0)&&(j)); - } - return (i); -} - -static int sbpcd_lock_door(struct cdrom_device_info *cdi, int lock) -{ - return lock ? LockDoor() : UnLockDoor(); -} - -/*==========================================================================*/ -static int cc_CloseTray(void) -{ - int i; - - if (fam0_drive) return (0); - msg(DBG_LCK,"cc_CloseTray (drive %d)\n", current_drive - D_S); - msg(DBG_LCS,"p_door_closed bit %d before\n", st_door_closed); - - clr_cmdbuf(); - response_count=0; - if (fam1_drive) - { - drvcmd[0]=CMD1_TRAY_CTL; - flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; - } - else if (fam2_drive) - { - drvcmd[0]=CMD2_TRAY_CTL; - drvcmd[1]=0x01; - drvcmd[4]=0x03; /* "insert" */ - flags_cmd_out=f_putcmd|f_ResponseStatus; - } - else if (famLV_drive) - { - drvcmd[0]=CMDL_TRAY_CTL; - if (famLV_drive) - flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta| - f_ResponseStatus|f_obey_p_check|f_bit1; - else - flags_cmd_out=f_putcmd; - } - else if (famT_drive) - { - drvcmd[0]=CMDT_TRAY_CTL; - drvcmd[4]=0x03; /* "insert" */ - } - i=cmd_out(); - msg(DBG_LCS,"p_door_closed bit %d after\n", st_door_closed); - - i=cc_ReadError(); - flags_cmd_out |= f_respo2; - cc_ReadStatus(); /* command: give 1-byte status */ - i=ResponseStatus(); - if (famT_drive&&(i<0)) - { - cc_DriveReset(); - i=ResponseStatus(); -#if 0 - sbp_sleep(HZ); -#endif /* 0 */ - i=ResponseStatus(); - } - if (i<0) - { - msg(DBG_INF,"sbpcd cc_CloseTray: ResponseStatus timed out (%d).\n",i); - } - if (!(famT_drive)) - { - if (!st_spinning) - { - cc_SpinUp(); - if (st_check) i=cc_ReadError(); - flags_cmd_out |= f_respo2; - cc_ReadStatus(); - i=ResponseStatus(); - } else { - } - } - i=DiskInfo(); - return (i); -} - -static int sbpcd_tray_move(struct cdrom_device_info *cdi, int position) -{ - int retval=0; - switch_drive(cdi->handle); - /* DUH! --AJK */ - if(current_drive->CD_changed != 0xFF) { - current_drive->CD_changed=0xFF; - current_drive->diskstate_flags &= ~cd_size_bit; - } - if (position == 1) { - cc_SpinDown(); - } else { - retval=cc_CloseTray(); - } - return retval; -} - -/*==========================================================================*/ -static int cc_ReadSubQ(void) -{ - int i,j; - - current_drive->diskstate_flags &= ~subq_bit; - for (j=255;j>0;j--) - { - clr_cmdbuf(); - if (fam1_drive) - { - drvcmd[0]=CMD1_READSUBQ; - flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; - response_count=11; - } - else if (fam2_drive) - { - drvcmd[0]=CMD2_READSUBQ; - drvcmd[1]=0x02; - drvcmd[3]=0x01; - flags_cmd_out=f_putcmd; - response_count=10; - } - else if (fam0LV_drive) - { - drvcmd[0]=CMD0_READSUBQ; - drvcmd[1]=0x02; - if (famLV_drive) - flags_cmd_out=f_putcmd; - else - flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; - response_count=13; - } - else if (famT_drive) - { - response_count=12; - drvcmd[0]=CMDT_READSUBQ; - drvcmd[1]=0x02; - drvcmd[2]=0x40; - drvcmd[3]=0x01; - drvcmd[8]=response_count; - } - i=cmd_out(); - if (i<0) return (i); - for (i=0;iSubQ_ctl_adr=current_drive->SubQ_trk=current_drive->SubQ_pnt_idx=current_drive->SubQ_whatisthis=0; - current_drive->SubQ_run_tot=current_drive->SubQ_run_trk=0; - return (0); - } - } - if (famT_drive) current_drive->SubQ_ctl_adr=infobuf[1]; - else current_drive->SubQ_ctl_adr=swap_nibbles(infobuf[1]); - current_drive->SubQ_trk=byt2bcd(infobuf[2]); - current_drive->SubQ_pnt_idx=byt2bcd(infobuf[3]); - if (fam0LV_drive) i=5; - else if (fam12_drive) i=4; - else if (famT_drive) i=8; - current_drive->SubQ_run_tot=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2])); /* msf-bin */ - i=7; - if (fam0LV_drive) i=9; - else if (fam12_drive) i=7; - else if (famT_drive) i=4; - current_drive->SubQ_run_trk=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2])); /* msf-bin */ - current_drive->SubQ_whatisthis=infobuf[i+3]; - current_drive->diskstate_flags |= subq_bit; - return (0); -} -/*==========================================================================*/ -static int cc_ModeSense(void) -{ - int i; - - if (fam2_drive) return (0); - if (famV_drive) return (0); - current_drive->diskstate_flags &= ~frame_size_bit; - clr_cmdbuf(); - if (fam1_drive) - { - response_count=5; - drvcmd[0]=CMD1_GETMODE; - flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; - } - else if (fam0L_drive) - { - response_count=2; - drvcmd[0]=CMD0_GETMODE; - if (famL_drive) flags_cmd_out=f_putcmd; - else flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; - } - else if (famT_drive) - { - response_count=10; - drvcmd[0]=CMDT_GETMODE; - drvcmd[4]=response_count; - } - i=cmd_out(); - if (i<0) return (i); - i=0; - current_drive->sense_byte=0; - if (fam1_drive) current_drive->sense_byte=infobuf[i++]; - else if (famT_drive) - { - if (infobuf[4]==0x01) current_drive->xa_byte=0x20; - else current_drive->xa_byte=0; - i=2; - } - current_drive->frame_size=make16(infobuf[i],infobuf[i+1]); - for (i=0;idiskstate_flags |= frame_size_bit; - return (0); -} -/*==========================================================================*/ -/*==========================================================================*/ -static int cc_ModeSelect(int framesize) -{ - int i; - - if (fam2_drive) return (0); - if (famV_drive) return (0); - current_drive->diskstate_flags &= ~frame_size_bit; - clr_cmdbuf(); - current_drive->frame_size=framesize; - if (framesize==CD_FRAMESIZE_RAW) current_drive->sense_byte=0x82; - else current_drive->sense_byte=0x00; - - msg(DBG_XA1,"cc_ModeSelect: %02X %04X\n", - current_drive->sense_byte, current_drive->frame_size); - - if (fam1_drive) - { - drvcmd[0]=CMD1_SETMODE; - drvcmd[1]=0x00; - drvcmd[2]=current_drive->sense_byte; - drvcmd[3]=(current_drive->frame_size>>8)&0xFF; - drvcmd[4]=current_drive->frame_size&0xFF; - flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; - } - else if (fam0L_drive) - { - drvcmd[0]=CMD0_SETMODE; - drvcmd[1]=0x00; - drvcmd[2]=(current_drive->frame_size>>8)&0xFF; - drvcmd[3]=current_drive->frame_size&0xFF; - drvcmd[4]=0x00; - if(famL_drive) - flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check; - else - flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; - } - else if (famT_drive) - { - return (-1); - } - response_count=0; - i=cmd_out(); - if (i<0) return (i); - current_drive->diskstate_flags |= frame_size_bit; - return (0); -} -/*==========================================================================*/ -static int cc_GetVolume(void) -{ - int i; - u_char switches; - u_char chan0=0; - u_char vol0=0; - u_char chan1=1; - u_char vol1=0; - - if (famV_drive) return (0); - current_drive->diskstate_flags &= ~volume_bit; - clr_cmdbuf(); - if (fam1_drive) - { - drvcmd[0]=CMD1_GETMODE; - drvcmd[1]=0x05; - response_count=5; - flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; - } - else if (fam2_drive) - { - drvcmd[0]=CMD2_GETMODE; - drvcmd[1]=0x0E; - response_count=5; - flags_cmd_out=f_putcmd; - } - else if (fam0L_drive) - { - drvcmd[0]=CMD0_GETMODE; - drvcmd[1]=0x03; - response_count=2; - if(famL_drive) - flags_cmd_out=f_putcmd; - else - flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; - } - else if (famT_drive) - { - i=cc_get_mode_T(); - if (i<0) return (i); - } - if (!famT_drive) - { - i=cmd_out(); - if (i<0) return (i); - } - if (fam1_drive) - { - chan0=infobuf[1]&0x0F; - vol0=infobuf[2]; - chan1=infobuf[3]&0x0F; - vol1=infobuf[4]; - if (chan0==0) - { - chan0=1; - vol0=0; - } - if (chan1==0) - { - chan1=2; - vol1=0; - } - chan0 >>= 1; - chan1 >>= 1; - } - else if (fam2_drive) - { - chan0=infobuf[1]; - vol0=infobuf[2]; - chan1=infobuf[3]; - vol1=infobuf[4]; - } - else if (famL_drive) - { - chan0=0; - chan1=1; - vol0=vol1=infobuf[1]; - switches=infobuf[0]; - if ((switches&0x80)!=0) chan0=1; - if ((switches&0x40)!=0) chan1=0; - } - else if (fam0_drive) /* different firmware levels */ - { - chan0=0; - chan1=1; - vol0=vol1=infobuf[1]; - if (current_drive->drv_type>=drv_201) - { - if (current_drive->drv_typedrv_type>=drv_211) - { - if ((switches&0x20)!=0) chan0=1; - if ((switches&0x10)!=0) chan1=0; - } - } - else - { - vol0=infobuf[0]; - if ((vol0&0x01)!=0) chan0=1; - if ((vol1&0x01)==0) chan1=0; - vol0 &= 0xFC; - vol1 &= 0xFC; - if (vol0!=0) vol0 += 3; - if (vol1!=0) vol1 += 3; - } - } - } - else if (famT_drive) - { - current_drive->volume_control=infobuf[7]; - chan0=0; - chan1=1; - if (current_drive->volume_control&0x10) vol0=0; - else vol0=0xff; - if (current_drive->volume_control&0x20) vol1=0; - else vol1=0xff; - } - current_drive->vol_chan0=chan0; - current_drive->vol_ctrl0=vol0; - current_drive->vol_chan1=chan1; - current_drive->vol_ctrl1=vol1; -#if 000 - current_drive->vol_chan2=2; - current_drive->vol_ctrl2=0xFF; - current_drive->vol_chan3=3; - current_drive->vol_ctrl3=0xFF; -#endif /* 000 */ - current_drive->diskstate_flags |= volume_bit; - return (0); -} -/*==========================================================================*/ -static int cc_ReadCapacity(void) -{ - int i, j; - - if (fam2_drive) return (0); /* some firmware lacks this command */ - if (famLV_drive) return (0); /* some firmware lacks this command */ - if (famT_drive) return (0); /* done with cc_ReadTocDescr() */ - current_drive->diskstate_flags &= ~cd_size_bit; - for (j=3;j>0;j--) - { - clr_cmdbuf(); - if (fam1_drive) - { - drvcmd[0]=CMD1_CAPACITY; - response_count=5; - flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; - } -#if 00 - else if (fam2_drive) - { - drvcmd[0]=CMD2_CAPACITY; - response_count=8; - flags_cmd_out=f_putcmd; - } -#endif - else if (fam0_drive) - { - drvcmd[0]=CMD0_CAPACITY; - response_count=5; - flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; - } - i=cmd_out(); - if (i>=0) break; - msg(DBG_000,"cc_ReadCapacity: cmd_out: err %d\n", i); - cc_ReadError(); - } - if (j==0) return (i); - if (fam1_drive) current_drive->CDsize_frm=msf2blk(make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2])))+CD_MSF_OFFSET; - else if (fam0_drive) current_drive->CDsize_frm=make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2])); -#if 00 - else if (fam2_drive) current_drive->CDsize_frm=make32(make16(infobuf[0],infobuf[1]),make16(infobuf[2],infobuf[3])); -#endif - current_drive->diskstate_flags |= cd_size_bit; - msg(DBG_000,"cc_ReadCapacity: %d frames.\n", current_drive->CDsize_frm); - return (0); -} -/*==========================================================================*/ -static int cc_ReadTocDescr(void) -{ - int i; - - current_drive->diskstate_flags &= ~toc_bit; - clr_cmdbuf(); - if (fam1_drive) - { - drvcmd[0]=CMD1_DISKINFO; - response_count=6; - flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; - } - else if (fam0LV_drive) - { - drvcmd[0]=CMD0_DISKINFO; - response_count=6; - if(famLV_drive) - flags_cmd_out=f_putcmd; - else - flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; - } - else if (fam2_drive) - { - /* possibly longer timeout periods necessary */ - current_drive->f_multisession=0; - drvcmd[0]=CMD2_DISKINFO; - drvcmd[1]=0x02; - drvcmd[2]=0xAB; - drvcmd[3]=0xFF; /* session */ - response_count=8; - flags_cmd_out=f_putcmd; - } - else if (famT_drive) - { - current_drive->f_multisession=0; - response_count=12; - drvcmd[0]=CMDT_DISKINFO; - drvcmd[1]=0x02; - drvcmd[6]=CDROM_LEADOUT; - drvcmd[8]=response_count; - drvcmd[9]=0x00; - } - i=cmd_out(); - if (i<0) return (i); - if ((famT_drive)&&(ixa_byte=infobuf[0]; - if (fam2_drive) - { - current_drive->first_session=infobuf[1]; - current_drive->last_session=infobuf[2]; - current_drive->n_first_track=infobuf[3]; - current_drive->n_last_track=infobuf[4]; - if (current_drive->first_session!=current_drive->last_session) - { - current_drive->f_multisession=1; - current_drive->lba_multi=msf2blk(make32(make16(0,infobuf[5]),make16(infobuf[6],infobuf[7]))); - } -#if 0 - if (current_drive->first_session!=current_drive->last_session) - { - if (current_drive->last_session<=20) - zwanzig=current_drive->last_session+1; - else zwanzig=20; - for (count=current_drive->first_session;countmsf_multi_n[count]=make32(make16(0,infobuf[5]),make16(infobuf[6],infobuf[7])); - } - current_drive->diskstate_flags |= multisession_bit; - } -#endif - drvcmd[0]=CMD2_DISKINFO; - drvcmd[1]=0x02; - drvcmd[2]=0xAA; - drvcmd[3]=0xFF; - response_count=5; - flags_cmd_out=f_putcmd; - i=cmd_out(); - if (i<0) return (i); - current_drive->size_msf=make32(make16(0,infobuf[2]),make16(infobuf[3],infobuf[4])); - current_drive->size_blk=msf2blk(current_drive->size_msf); - current_drive->CDsize_frm=current_drive->size_blk+1; - } - else if (famT_drive) - { - current_drive->size_msf=make32(make16(infobuf[8],infobuf[9]),make16(infobuf[10],infobuf[11])); - current_drive->size_blk=msf2blk(current_drive->size_msf); - current_drive->CDsize_frm=current_drive->size_blk+1; - current_drive->n_first_track=infobuf[2]; - current_drive->n_last_track=infobuf[3]; - } - else - { - current_drive->n_first_track=infobuf[1]; - current_drive->n_last_track=infobuf[2]; - current_drive->size_msf=make32(make16(0,infobuf[3]),make16(infobuf[4],infobuf[5])); - current_drive->size_blk=msf2blk(current_drive->size_msf); - if (famLV_drive) current_drive->CDsize_frm=current_drive->size_blk+1; - } - current_drive->diskstate_flags |= toc_bit; - msg(DBG_TOC,"TocDesc: xa %02X firstt %02X lastt %02X size %08X firstses %02X lastsess %02X\n", - current_drive->xa_byte, - current_drive->n_first_track, - current_drive->n_last_track, - current_drive->size_msf, - current_drive->first_session, - current_drive->last_session); - return (0); -} -/*==========================================================================*/ -static int cc_ReadTocEntry(int num) -{ - int i; - - clr_cmdbuf(); - if (fam1_drive) - { - drvcmd[0]=CMD1_READTOC; - drvcmd[2]=num; - response_count=8; - flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; - } - else if (fam2_drive) - { - /* possibly longer timeout periods necessary */ - drvcmd[0]=CMD2_DISKINFO; - drvcmd[1]=0x02; - drvcmd[2]=num; - response_count=5; - flags_cmd_out=f_putcmd; - } - else if (fam0LV_drive) - { - drvcmd[0]=CMD0_READTOC; - drvcmd[1]=0x02; - drvcmd[2]=num; - response_count=8; - if (famLV_drive) - flags_cmd_out=f_putcmd; - else - flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; - } - else if (famT_drive) - { - response_count=12; - drvcmd[0]=CMDT_DISKINFO; - drvcmd[1]=0x02; - drvcmd[6]=num; - drvcmd[8]=response_count; - drvcmd[9]=0x00; - } - i=cmd_out(); - if (i<0) return (i); - if ((famT_drive)&&(iTocEnt_nixbyte=infobuf[0]; - i=1; - } - else if (fam2_drive) i=0; - else if (famT_drive) i=5; - current_drive->TocEnt_ctl_adr=swap_nibbles(infobuf[i++]); - if ((fam1_drive)||(fam0L_drive)) - { - current_drive->TocEnt_number=infobuf[i++]; - current_drive->TocEnt_format=infobuf[i]; - } - else - { - current_drive->TocEnt_number=num; - current_drive->TocEnt_format=0; - } - if (fam1_drive) i=4; - else if (fam0LV_drive) i=5; - else if (fam2_drive) i=2; - else if (famT_drive) i=9; - current_drive->TocEnt_address=make32(make16(0,infobuf[i]), - make16(infobuf[i+1],infobuf[i+2])); - for (i=0;iTocEnt_nixbyte, current_drive->TocEnt_ctl_adr, - current_drive->TocEnt_number, current_drive->TocEnt_format, - current_drive->TocEnt_address); - return (0); -} -/*==========================================================================*/ -static int cc_ReadPacket(void) -{ - int i; - - clr_cmdbuf(); - drvcmd[0]=CMD0_PACKET; - drvcmd[1]=response_count; - if(famL_drive) flags_cmd_out=f_putcmd; - else if (fam01_drive) - flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; - else if (fam2_drive) return (-1); /* not implemented yet */ - else if (famT_drive) - { - return (-1); - } - i=cmd_out(); - return (i); -} -/*==========================================================================*/ -static int convert_UPC(u_char *p) -{ - int i; - - p++; - if (fam0L_drive) p[13]=0; - for (i=0;i<7;i++) - { - if (fam1_drive) current_drive->UPC_buf[i]=swap_nibbles(*p++); - else if (fam0L_drive) - { - current_drive->UPC_buf[i]=((*p++)<<4)&0xFF; - current_drive->UPC_buf[i] |= *p++; - } - else if (famT_drive) - { - return (-1); - } - else /* CD200 */ - { - return (-1); - } - } - current_drive->UPC_buf[6] &= 0xF0; - return (0); -} -/*==========================================================================*/ -static int cc_ReadUPC(void) -{ - int i; -#if TEST_UPC - int block, checksum; -#endif /* TEST_UPC */ - - if (fam2_drive) return (0); /* not implemented yet */ - if (famT_drive) return (0); /* not implemented yet */ - if (famV_drive) return (0); /* not implemented yet */ -#if 1 - if (fam0_drive) return (0); /* but it should work */ -#endif - - current_drive->diskstate_flags &= ~upc_bit; -#if TEST_UPC - for (block=CD_MSF_OFFSET+1;block>16)&0xFF; - drvcmd[2]=(block>>8)&0xFF; - drvcmd[3]=block&0xFF; -#endif /* TEST_UPC */ - response_count=8; - flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; - } - else if (fam0L_drive) - { - drvcmd[0]=CMD0_READ_UPC; -#if TEST_UPC - drvcmd[2]=(block>>16)&0xFF; - drvcmd[3]=(block>>8)&0xFF; - drvcmd[4]=block&0xFF; -#endif /* TEST_UPC */ - response_count=0; - flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; - } - else if (fam2_drive) - { - return (-1); - } - else if (famT_drive) - { - return (-1); - } - i=cmd_out(); - if (i<0) - { - msg(DBG_000,"cc_ReadUPC cmd_out: err %d\n", i); - return (i); - } - if (fam0L_drive) - { - response_count=16; - if (famL_drive) flags_cmd_out=f_putcmd; - i=cc_ReadPacket(); - if (i<0) - { - msg(DBG_000,"cc_ReadUPC ReadPacket: err %d\n", i); - return (i); - } - } -#if TEST_UPC - checksum=0; -#endif /* TEST_UPC */ - for (i=0;i<(fam1_drive?8:16);i++) - { -#if TEST_UPC - checksum |= infobuf[i]; -#endif /* TEST_UPC */ - sprintf(&msgbuf[i*3], " %02X", infobuf[i]); - } - msgbuf[i*3]=0; - msg(DBG_UPC,"UPC info:%s\n", msgbuf); -#if TEST_UPC - if ((checksum&0x7F)!=0) break; - } -#endif /* TEST_UPC */ - current_drive->UPC_ctl_adr=0; - if (fam1_drive) i=0; - else i=2; - if ((infobuf[i]&0x80)!=0) - { - convert_UPC(&infobuf[i]); - current_drive->UPC_ctl_adr = (current_drive->TocEnt_ctl_adr & 0xF0) | 0x02; - } - for (i=0;i<7;i++) - sprintf(&msgbuf[i*3], " %02X", current_drive->UPC_buf[i]); - sprintf(&msgbuf[i*3], " (%02X)", current_drive->UPC_ctl_adr); - msgbuf[i*3+5]=0; - msg(DBG_UPC,"UPC code:%s\n", msgbuf); - current_drive->diskstate_flags |= upc_bit; - return (0); -} - -static int sbpcd_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) -{ - int i; - unsigned char *mcnp = mcn->medium_catalog_number; - unsigned char *resp; - - current_drive->diskstate_flags &= ~upc_bit; - clr_cmdbuf(); - if (fam1_drive) - { - drvcmd[0]=CMD1_READ_UPC; - response_count=8; - flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; - } - else if (fam0L_drive) - { - drvcmd[0]=CMD0_READ_UPC; - response_count=0; - flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; - } - else if (fam2_drive) - { - return (-1); - } - else if (famT_drive) - { - return (-1); - } - i=cmd_out(); - if (i<0) - { - msg(DBG_000,"cc_ReadUPC cmd_out: err %d\n", i); - return (i); - } - if (fam0L_drive) - { - response_count=16; - if (famL_drive) flags_cmd_out=f_putcmd; - i=cc_ReadPacket(); - if (i<0) - { - msg(DBG_000,"cc_ReadUPC ReadPacket: err %d\n", i); - return (i); - } - } - current_drive->UPC_ctl_adr=0; - if (fam1_drive) i=0; - else i=2; - - resp = infobuf + i; - if (*resp++ == 0x80) { - /* packed bcd to single ASCII digits */ - *mcnp++ = (*resp >> 4) + '0'; - *mcnp++ = (*resp++ & 0x0f) + '0'; - *mcnp++ = (*resp >> 4) + '0'; - *mcnp++ = (*resp++ & 0x0f) + '0'; - *mcnp++ = (*resp >> 4) + '0'; - *mcnp++ = (*resp++ & 0x0f) + '0'; - *mcnp++ = (*resp >> 4) + '0'; - *mcnp++ = (*resp++ & 0x0f) + '0'; - *mcnp++ = (*resp >> 4) + '0'; - *mcnp++ = (*resp++ & 0x0f) + '0'; - *mcnp++ = (*resp >> 4) + '0'; - *mcnp++ = (*resp++ & 0x0f) + '0'; - *mcnp++ = (*resp >> 4) + '0'; - } - *mcnp = '\0'; - - current_drive->diskstate_flags |= upc_bit; - return (0); -} - -/*==========================================================================*/ -static int cc_CheckMultiSession(void) -{ - int i; - - if (fam2_drive) return (0); - current_drive->f_multisession=0; - current_drive->lba_multi=0; - if (fam0_drive) return (0); - clr_cmdbuf(); - if (fam1_drive) - { - drvcmd[0]=CMD1_MULTISESS; - response_count=6; - flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; - i=cmd_out(); - if (i<0) return (i); - if ((infobuf[0]&0x80)!=0) - { - current_drive->f_multisession=1; - current_drive->lba_multi=msf2blk(make32(make16(0,infobuf[1]), - make16(infobuf[2],infobuf[3]))); - } - } - else if (famLV_drive) - { - drvcmd[0]=CMDL_MULTISESS; - drvcmd[1]=3; - drvcmd[2]=1; - response_count=8; - flags_cmd_out=f_putcmd; - i=cmd_out(); - if (i<0) return (i); - current_drive->lba_multi=msf2blk(make32(make16(0,infobuf[5]), - make16(infobuf[6],infobuf[7]))); - } - else if (famT_drive) - { - response_count=12; - drvcmd[0]=CMDT_DISKINFO; - drvcmd[1]=0x02; - drvcmd[6]=0; - drvcmd[8]=response_count; - drvcmd[9]=0x40; - i=cmd_out(); - if (i<0) return (i); - if (ifirst_session=infobuf[2]; - current_drive->last_session=infobuf[3]; - current_drive->track_of_last_session=infobuf[6]; - if (current_drive->first_session!=current_drive->last_session) - { - current_drive->f_multisession=1; - current_drive->lba_multi=msf2blk(make32(make16(0,infobuf[9]),make16(infobuf[10],infobuf[11]))); - } - } - for (i=0;ilba_multi); - if (current_drive->lba_multi>200) - { - current_drive->f_multisession=1; - msg(DBG_MUL,"MultiSession base: %06X\n", current_drive->lba_multi); - } - return (0); -} -/*==========================================================================*/ -#ifdef FUTURE -static int cc_SubChanInfo(int frame, int count, u_char *buffer) - /* "frame" is a RED BOOK (msf-bin) address */ -{ - int i; - - if (fam0LV_drive) return (-ENOSYS); /* drive firmware lacks it */ - if (famT_drive) - { - return (-1); - } -#if 0 - if (current_drive->audio_state!=audio_playing) return (-ENODATA); -#endif - clr_cmdbuf(); - drvcmd[0]=CMD1_SUBCHANINF; - drvcmd[1]=(frame>>16)&0xFF; - drvcmd[2]=(frame>>8)&0xFF; - drvcmd[3]=frame&0xFF; - drvcmd[5]=(count>>8)&0xFF; - drvcmd[6]=count&0xFF; - flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; - cmd_type=READ_SC; - current_drive->frame_size=CD_FRAMESIZE_SUB; - i=cmd_out(); /* which buffer to use? */ - return (i); -} -#endif /* FUTURE */ -/*==========================================================================*/ -static void __init check_datarate(void) -{ - int i=0; - - msg(DBG_IOX,"check_datarate entered.\n"); - datarate=0; -#if TEST_STI - for (i=0;i<=1000;i++) printk("."); -#endif - /* set a timer to make (timed_out_delay!=0) after 1.1 seconds */ -#if 1 - del_timer(&delay_timer); -#endif - delay_timer.expires=jiffies+11*HZ/10; - timed_out_delay=0; - add_timer(&delay_timer); -#if 0 - msg(DBG_TIM,"delay timer started (11*HZ/10).\n"); -#endif - do - { - i=inb(CDi_status); - datarate++; -#if 1 - if (datarate>0x6FFFFFFF) break; -#endif - } - while (!timed_out_delay); - del_timer(&delay_timer); -#if 0 - msg(DBG_TIM,"datarate: %04X\n", datarate); -#endif - if (datarate<65536) datarate=65536; - maxtim16=datarate*16; - maxtim04=datarate*4; - maxtim02=datarate*2; - maxtim_8=datarate/32; -#if LONG_TIMING - maxtim_data=datarate/100; -#else - maxtim_data=datarate/300; -#endif /* LONG_TIMING */ -#if 0 - msg(DBG_TIM,"maxtim_8 %d, maxtim_data %d.\n", maxtim_8, maxtim_data); -#endif -} -/*==========================================================================*/ -#if 0 -static int c2_ReadError(int fam) -{ - int i; - - clr_cmdbuf(); - response_count=9; - clr_respo_buf(9); - if (fam==1) - { - drvcmd[0]=CMD0_READ_ERR; /* same as CMD1_ and CMDL_ */ - i=do_cmd(f_putcmd|f_lopsta|f_getsta|f_ResponseStatus); - } - else if (fam==2) - { - drvcmd[0]=CMD2_READ_ERR; - i=do_cmd(f_putcmd); - } - else return (-1); - return (i); -} -#endif -/*==========================================================================*/ -static void __init ask_mail(void) -{ - int i; - - msg(DBG_INF, "please mail the following lines to emoenke@gwdg.de\n"); - msg(DBG_INF, "(don't mail if you are not using the actual kernel):\n"); - msg(DBG_INF, "%s\n", VERSION); - msg(DBG_INF, "address %03X, type %s, drive %s (ID %d)\n", - CDo_command, type, current_drive->drive_model, current_drive->drv_id); - for (i=0;i<12;i++) - sprintf(&msgbuf[i*3], " %02X", infobuf[i]); - msgbuf[i*3]=0; - msg(DBG_INF,"infobuf =%s\n", msgbuf); - for (i=0;i<12;i++) - sprintf(&msgbuf[i*3], " %c ", infobuf[i]); - msgbuf[i*3]=0; - msg(DBG_INF,"infobuf =%s\n", msgbuf); -} -/*==========================================================================*/ -static int __init check_version(void) -{ - int i, j, l; - int teac_possible=0; - - msg(DBG_INI,"check_version: id=%d, d=%d.\n", current_drive->drv_id, current_drive - D_S); - current_drive->drv_type=0; - - /* check for CR-52x, CR-56x, LCS-7260 and ECS-AT */ - /* clear any pending error state */ - clr_cmdbuf(); - drvcmd[0]=CMD0_READ_ERR; /* same as CMD1_ and CMDL_ */ - response_count=9; - flags_cmd_out=f_putcmd; - i=cmd_out(); - if (i<0) msg(DBG_INI,"CMD0_READ_ERR returns %d (ok anyway).\n",i); - /* read drive version */ - clr_cmdbuf(); - for (i=0;i<12;i++) infobuf[i]=0; - drvcmd[0]=CMD0_READ_VER; /* same as CMD1_ and CMDL_ */ - response_count=12; /* fam1: only 11 */ - flags_cmd_out=f_putcmd; - i=cmd_out(); - if (i<-1) msg(DBG_INI,"CMD0_READ_VER returns %d\n",i); - if (i==-11) teac_possible++; - j=0; - for (i=0;i<12;i++) j+=infobuf[i]; - if (j) - { - for (i=0;i<12;i++) - sprintf(&msgbuf[i*3], " %02X", infobuf[i]); - msgbuf[i*3]=0; - msg(DBG_ECS,"infobuf =%s\n", msgbuf); - for (i=0;i<12;i++) - sprintf(&msgbuf[i*3], " %c ", infobuf[i]); - msgbuf[i*3]=0; - msg(DBG_ECS,"infobuf =%s\n", msgbuf); - } - for (i=0;i<4;i++) if (infobuf[i]!=family1[i]) break; - if (i==4) - { - current_drive->drive_model[0]='C'; - current_drive->drive_model[1]='R'; - current_drive->drive_model[2]='-'; - current_drive->drive_model[3]='5'; - current_drive->drive_model[4]=infobuf[i++]; - current_drive->drive_model[5]=infobuf[i++]; - current_drive->drive_model[6]=0; - current_drive->drv_type=drv_fam1; - } - if (!current_drive->drv_type) - { - for (i=0;i<8;i++) if (infobuf[i]!=family0[i]) break; - if (i==8) - { - current_drive->drive_model[0]='C'; - current_drive->drive_model[1]='R'; - current_drive->drive_model[2]='-'; - current_drive->drive_model[3]='5'; - current_drive->drive_model[4]='2'; - current_drive->drive_model[5]='x'; - current_drive->drive_model[6]=0; - current_drive->drv_type=drv_fam0; - } - } - if (!current_drive->drv_type) - { - for (i=0;i<8;i++) if (infobuf[i]!=familyL[i]) break; - if (i==8) - { - for (j=0;j<8;j++) - current_drive->drive_model[j]=infobuf[j]; - current_drive->drive_model[8]=0; - current_drive->drv_type=drv_famL; - } - } - if (!current_drive->drv_type) - { - for (i=0;i<6;i++) if (infobuf[i]!=familyV[i]) break; - if (i==6) - { - for (j=0;j<6;j++) - current_drive->drive_model[j]=infobuf[j]; - current_drive->drive_model[6]=0; - current_drive->drv_type=drv_famV; - i+=2; /* 2 blanks before version */ - } - } - if (!current_drive->drv_type) - { - /* check for CD200 */ - clr_cmdbuf(); - drvcmd[0]=CMD2_READ_ERR; - response_count=9; - flags_cmd_out=f_putcmd; - i=cmd_out(); - if (i<0) msg(DBG_INI,"CMD2_READERR returns %d (ok anyway).\n",i); - if (i<0) msg(DBG_000,"CMD2_READERR returns %d (ok anyway).\n",i); - /* read drive version */ - clr_cmdbuf(); - for (i=0;i<12;i++) infobuf[i]=0; - if (sbpro_type==1) OUT(CDo_sel_i_d,0); -#if 0 - OUT(CDo_reset,0); - sbp_sleep(6*HZ); - OUT(CDo_enable,current_drive->drv_sel); -#endif - drvcmd[0]=CMD2_READ_VER; - response_count=12; - flags_cmd_out=f_putcmd; - i=cmd_out(); - if (i<0) msg(DBG_INI,"CMD2_READ_VER returns %d\n",i); - if (i==-7) teac_possible++; - j=0; - for (i=0;i<12;i++) j+=infobuf[i]; - if (j) - { - for (i=0;i<12;i++) - sprintf(&msgbuf[i*3], " %02X", infobuf[i]); - msgbuf[i*3]=0; - msg(DBG_IDX,"infobuf =%s\n", msgbuf); - for (i=0;i<12;i++) - sprintf(&msgbuf[i*3], " %c ", infobuf[i]); - msgbuf[i*3]=0; - msg(DBG_IDX,"infobuf =%s\n", msgbuf); - } - if (i>=0) - { - for (i=0;i<5;i++) if (infobuf[i]!=family2[i]) break; - if (i==5) - { - current_drive->drive_model[0]='C'; - current_drive->drive_model[1]='D'; - current_drive->drive_model[2]='2'; - current_drive->drive_model[3]='0'; - current_drive->drive_model[4]='0'; - current_drive->drive_model[5]=infobuf[i++]; - current_drive->drive_model[6]=infobuf[i++]; - current_drive->drive_model[7]=0; - current_drive->drv_type=drv_fam2; - } - } - } - if (!current_drive->drv_type) - { - /* check for TEAC CD-55A */ - msg(DBG_TEA,"teac_possible: %d\n",teac_possible); - for (j=1;j<=((current_drive->drv_id==0)?3:1);j++) - { - for (l=1;l<=((current_drive->drv_id==0)?10:1);l++) - { - msg(DBG_TEA,"TEAC reset #%d-%d.\n", j, l); - if (sbpro_type==1) OUT(CDo_reset,0); - else - { - OUT(CDo_enable,current_drive->drv_sel); - OUT(CDo_sel_i_d,0); - OUT(CDo_command,CMDT_RESET); - for (i=0;i<9;i++) OUT(CDo_command,0); - } - sbp_sleep(5*HZ/10); - OUT(CDo_enable,current_drive->drv_sel); - OUT(CDo_sel_i_d,0); - i=inb(CDi_status); - msg(DBG_TEA,"TEAC CDi_status: %02X.\n",i); -#if 0 - if (i&s_not_result_ready) continue; /* drive not present or ready */ -#endif - i=inb(CDi_info); - msg(DBG_TEA,"TEAC CDi_info: %02X.\n",i); - if (i==0x55) break; /* drive found */ - } - if (i==0x55) break; /* drive found */ - } - if (i==0x55) /* drive found */ - { - msg(DBG_TEA,"TEAC drive found.\n"); - clr_cmdbuf(); - flags_cmd_out=f_putcmd; - response_count=12; - drvcmd[0]=CMDT_READ_VER; - drvcmd[4]=response_count; - for (i=0;i<12;i++) infobuf[i]=0; - i=cmd_out_T(); - if (i!=0) msg(DBG_TEA,"cmd_out_T(CMDT_READ_VER) returns %d.\n",i); - for (i=1;i<6;i++) if (infobuf[i]!=familyT[i-1]) break; - if (i==6) - { - current_drive->drive_model[0]='C'; - current_drive->drive_model[1]='D'; - current_drive->drive_model[2]='-'; - current_drive->drive_model[3]='5'; - current_drive->drive_model[4]='5'; - current_drive->drive_model[5]=0; - current_drive->drv_type=drv_famT; - } - } - } - if (!current_drive->drv_type) - { - msg(DBG_TEA,"no drive found at address %03X under ID %d.\n",CDo_command,current_drive->drv_id); - return (-522); - } - for (j=0;j<4;j++) current_drive->firmware_version[j]=infobuf[i+j]; - if (famL_drive) - { - u_char lcs_firm_e1[]="A E1"; - u_char lcs_firm_f4[]="A4F4"; - - for (j=0;j<4;j++) - if (current_drive->firmware_version[j]!=lcs_firm_e1[j]) break; - if (j==4) current_drive->drv_type=drv_e1; - - for (j=0;j<4;j++) - if (current_drive->firmware_version[j]!=lcs_firm_f4[j]) break; - if (j==4) current_drive->drv_type=drv_f4; - - if (current_drive->drv_type==drv_famL) ask_mail(); - } - else if (famT_drive) - { - j=infobuf[4]; /* one-byte version??? - here: 0x15 */ - if (j=='5') - { - current_drive->firmware_version[0]=infobuf[7]; - current_drive->firmware_version[1]=infobuf[8]; - current_drive->firmware_version[2]=infobuf[10]; - current_drive->firmware_version[3]=infobuf[11]; - } - else - { - if (j!=0x15) ask_mail(); - current_drive->firmware_version[0]='0'; - current_drive->firmware_version[1]='.'; - current_drive->firmware_version[2]='0'+(j>>4); - current_drive->firmware_version[3]='0'+(j&0x0f); - } - } - else /* CR-52x, CR-56x, CD200, ECS-AT */ - { - j = (current_drive->firmware_version[0] & 0x0F) * 100 + - (current_drive->firmware_version[2] & 0x0F) *10 + - (current_drive->firmware_version[3] & 0x0F); - if (fam0_drive) - { - if (j<200) current_drive->drv_type=drv_199; - else if (j<201) current_drive->drv_type=drv_200; - else if (j<210) current_drive->drv_type=drv_201; - else if (j<211) current_drive->drv_type=drv_210; - else if (j<300) current_drive->drv_type=drv_211; - else if (j>=300) current_drive->drv_type=drv_300; - } - else if (fam1_drive) - { - if (j<100) current_drive->drv_type=drv_099; - else - { - current_drive->drv_type=drv_100; - if ((j!=500)&&(j!=102)) ask_mail(); - } - } - else if (fam2_drive) - { - if (current_drive->drive_model[5]=='F') - { - if ((j!=1)&&(j!=35)&&(j!=200)&&(j!=210)) - ask_mail(); /* unknown version at time */ - } - else - { - msg(DBG_INF,"this CD200 drive is not fully supported yet - only audio will work.\n"); - if ((j!=101)&&(j!=35)) - ask_mail(); /* unknown version at time */ - } - } - else if (famV_drive) - { - if ((j==100)||(j==150)) current_drive->drv_type=drv_at; - ask_mail(); /* hopefully we get some feedback by this */ - } - } - msg(DBG_LCS,"drive type %02X\n",current_drive->drv_type); - msg(DBG_INI,"check_version done.\n"); - return (0); -} -/*==========================================================================*/ -static void switch_drive(struct sbpcd_drive *p) -{ - current_drive = p; - OUT(CDo_enable,current_drive->drv_sel); - msg(DBG_DID,"drive %d (ID=%d) activated.\n", - current_drive - D_S, current_drive->drv_id); - return; -} -/*==========================================================================*/ -#ifdef PATH_CHECK -/* - * probe for the presence of an interface card - */ -static int __init check_card(int port) -{ -#undef N_RESPO -#define N_RESPO 20 - int i, j, k; - u_char response[N_RESPO]; - u_char save_port0; - u_char save_port3; - - msg(DBG_INI,"check_card entered.\n"); - save_port0=inb(port+0); - save_port3=inb(port+3); - - for (j=0;j0;i--) OUT(port+0,0); - for (k=0;k0;i--) - { - if (inb(port+1)&s_not_result_ready) continue; - response[k]=inb(port+0); - break; - } - } - for (i=0;i0;i--) OUT(port+0,0); - for (k=0;k0;i--) - { - if (inb(port+1)&s_not_result_ready) continue; - response[k]=inb(port+0); - break; - } - } - for (i=0;i0;i--) OUT(port+0,0); - for (k=0;k0;i--) - { - if (inb(port+1)&s_not_result_ready) continue; - response[k]=inb(port+0); - break; - } - } - for (i=0;i0;i--) OUT(port+0,0); - for (k=0;k0;i--) - { - if (inb(port+1)&s_not_result_ready) continue; - response[k]=inb(port+0); - break; - } - } - for (i=0;idrv_id=j; - if (sbpro_type==1) p->drv_sel=(j&0x01)<<1|(j&0x02)>>1; - else p->drv_sel=j; - switch_drive(p); - msg(DBG_INI,"check_drives: drive %d (ID=%d) activated.\n",ndrives,j); - msg(DBG_000,"check_drives: drive %d (ID=%d) activated.\n",ndrives,j); - i=check_version(); - if (i<0) msg(DBG_INI,"check_version returns %d.\n",i); - else - { - current_drive->drv_options=drv_pattern[j]; - if (fam0L_drive) current_drive->drv_options&=~(speed_auto|speed_300|speed_150); - msg(DBG_INF, "Drive %d (ID=%d): %.9s (%.4s) at 0x%03X (type %d)\n", - current_drive - D_S, - current_drive->drv_id, - current_drive->drive_model, - current_drive->firmware_version, - CDo_command, - sbpro_type); - ndrives++; - } - } - for (j=ndrives;jpos_audio_end)-1; - if (i<0) return (-1); - i=cc_Seek(i,0); - return (i); -} -#endif /* FUTURE */ -/*==========================================================================*/ -static int ReadToC(void) -{ - int i, j; - current_drive->diskstate_flags &= ~toc_bit; - current_drive->ored_ctl_adr=0; - /* special handling of CD-I HE */ - if ((current_drive->n_first_track == 2 && current_drive->n_last_track == 2) || - current_drive->xa_byte == 0x10) - { - current_drive->TocBuffer[1].nixbyte=0; - current_drive->TocBuffer[1].ctl_adr=0x40; - current_drive->TocBuffer[1].number=1; - current_drive->TocBuffer[1].format=0; - current_drive->TocBuffer[1].address=blk2msf(0); - current_drive->ored_ctl_adr |= 0x40; - current_drive->n_first_track = 1; - current_drive->n_last_track = 1; - current_drive->xa_byte = 0x10; - j = 2; - } else - for (j=current_drive->n_first_track;j<=current_drive->n_last_track;j++) - { - i=cc_ReadTocEntry(j); - if (i<0) - { - msg(DBG_INF,"cc_ReadTocEntry(%d) returns %d.\n",j,i); - return (i); - } - current_drive->TocBuffer[j].nixbyte=current_drive->TocEnt_nixbyte; - current_drive->TocBuffer[j].ctl_adr=current_drive->TocEnt_ctl_adr; - current_drive->TocBuffer[j].number=current_drive->TocEnt_number; - current_drive->TocBuffer[j].format=current_drive->TocEnt_format; - current_drive->TocBuffer[j].address=current_drive->TocEnt_address; - current_drive->ored_ctl_adr |= current_drive->TocEnt_ctl_adr; - } - /* fake entry for LeadOut Track */ - current_drive->TocBuffer[j].nixbyte=0; - current_drive->TocBuffer[j].ctl_adr=0; - current_drive->TocBuffer[j].number=CDROM_LEADOUT; - current_drive->TocBuffer[j].format=0; - current_drive->TocBuffer[j].address=current_drive->size_msf; - - current_drive->diskstate_flags |= toc_bit; - return (0); -} -/*==========================================================================*/ -static int DiskInfo(void) -{ - int i, j; - - current_drive->mode=READ_M1; - -#undef LOOP_COUNT -#define LOOP_COUNT 10 /* needed for some "old" drives */ - - msg(DBG_000,"DiskInfo entered.\n"); - for (j=1;j=0) break; - msg(DBG_INF,"DiskInfo: ReadCapacity #%d returns %d\n", j, i); -#if 0 - i=cc_DriveReset(); -#endif - if (!fam0_drive && j == 2) break; - } - if (j==LOOP_COUNT) return (-33); /* give up */ - - i=cc_ReadTocDescr(); - if (i<0) - { - msg(DBG_INF,"DiskInfo: ReadTocDescr returns %d\n", i); - return (i); - } - i=ReadToC(); - if (i<0) - { - msg(DBG_INF,"DiskInfo: ReadToC returns %d\n", i); - return (i); - } - i=cc_CheckMultiSession(); - if (i<0) - { - msg(DBG_INF,"DiskInfo: cc_CheckMultiSession returns %d\n", i); - return (i); - } - if (current_drive->f_multisession) current_drive->sbp_bufsiz=1; /* possibly a weird PhotoCD */ - else current_drive->sbp_bufsiz=buffers; - i=cc_ReadTocEntry(current_drive->n_first_track); - if (i<0) - { - msg(DBG_INF,"DiskInfo: cc_ReadTocEntry(1) returns %d\n", i); - return (i); - } - i=cc_ReadUPC(); - if (i<0) msg(DBG_INF,"DiskInfo: cc_ReadUPC returns %d\n", i); - if ((fam0L_drive) && (current_drive->xa_byte==0x20 || current_drive->xa_byte == 0x10)) - { - /* XA disk with old drive */ - cc_ModeSelect(CD_FRAMESIZE_RAW1); - cc_ModeSense(); - } - if (famT_drive) cc_prep_mode_T(); - msg(DBG_000,"DiskInfo done.\n"); - return (0); -} - -static int sbpcd_drive_status(struct cdrom_device_info *cdi, int slot_nr) -{ - struct sbpcd_drive *p = cdi->handle; - int st; - - if (CDSL_CURRENT != slot_nr) { - /* we have no changer support */ - return -EINVAL; - } - - cc_ReadStatus(); - st=ResponseStatus(); - if (st<0) - { - msg(DBG_INF,"sbpcd_drive_status: timeout.\n"); - return (0); - } - msg(DBG_000,"Drive Status: door_locked =%d.\n", st_door_locked); - msg(DBG_000,"Drive Status: door_closed =%d.\n", st_door_closed); - msg(DBG_000,"Drive Status: caddy_in =%d.\n", st_caddy_in); - msg(DBG_000,"Drive Status: disk_ok =%d.\n", st_diskok); - msg(DBG_000,"Drive Status: spinning =%d.\n", st_spinning); - msg(DBG_000,"Drive Status: busy =%d.\n", st_busy); - -#if 0 - if (!(p->status_bits & p_door_closed)) return CDS_TRAY_OPEN; - if (p->status_bits & p_disk_ok) return CDS_DISC_OK; - if (p->status_bits & p_disk_in) return CDS_DRIVE_NOT_READY; - - return CDS_NO_DISC; -#else - if (p->status_bits & p_spinning) return CDS_DISC_OK; -/* return CDS_TRAY_OPEN; */ - return CDS_NO_DISC; - -#endif - -} - - -/*==========================================================================*/ -#ifdef FUTURE -/* - * called always if driver gets entered - * returns 0 or ERROR2 or ERROR15 - */ -static int prepare(u_char func, u_char subfunc) -{ - int i; - - if (fam0L_drive) - { - i=inb(CDi_status); - if (i&s_attention) GetStatus(); - } - else if (fam1_drive) GetStatus(); - else if (fam2_drive) GetStatus(); - else if (famT_drive) GetStatus(); - if (current_drive->CD_changed==0xFF) - { - current_drive->diskstate_flags=0; - current_drive->audio_state=0; - if (!st_diskok) - { - i=check_allowed1(func,subfunc); - if (i<0) return (-2); - } - else - { - i=check_allowed3(func,subfunc); - if (i<0) - { - current_drive->CD_changed=1; - return (-15); - } - } - } - else - { - if (!st_diskok) - { - current_drive->diskstate_flags=0; - current_drive->audio_state=0; - i=check_allowed1(func,subfunc); - if (i<0) return (-2); - } - else - { - if (st_busy) - { - if (current_drive->audio_state!=audio_pausing) - { - i=check_allowed2(func,subfunc); - if (i<0) return (-2); - } - } - else - { - if (current_drive->audio_state==audio_playing) seek_pos_audio_end(); - current_drive->audio_state=0; - } - if (!frame_size_valid) - { - i=DiskInfo(); - if (i<0) - { - current_drive->diskstate_flags=0; - current_drive->audio_state=0; - i=check_allowed1(func,subfunc); - if (i<0) return (-2); - } - } - } - } - return (0); -} -#endif /* FUTURE */ -/*==========================================================================*/ -/*==========================================================================*/ -/* - * Check the results of the "get status" command. - */ -static int sbp_status(void) -{ - int st; - - st=ResponseStatus(); - if (st<0) - { - msg(DBG_INF,"sbp_status: timeout.\n"); - return (0); - } - - if (!st_spinning) msg(DBG_SPI,"motor got off - ignoring.\n"); - - if (st_check) - { - msg(DBG_INF,"st_check detected - retrying.\n"); - return (0); - } - if (!st_door_closed) - { - msg(DBG_INF,"door is open - retrying.\n"); - return (0); - } - if (!st_caddy_in) - { - msg(DBG_INF,"disk removed - retrying.\n"); - return (0); - } - if (!st_diskok) - { - msg(DBG_INF,"!st_diskok detected - retrying.\n"); - return (0); - } - if (st_busy) - { - msg(DBG_INF,"st_busy detected - retrying.\n"); - return (0); - } - return (1); -} -/*==========================================================================*/ - -static int sbpcd_get_last_session(struct cdrom_device_info *cdi, struct cdrom_multisession *ms_infp) -{ - struct sbpcd_drive *p = cdi->handle; - ms_infp->addr_format = CDROM_LBA; - ms_infp->addr.lba = p->lba_multi; - if (p->f_multisession) - ms_infp->xa_flag=1; /* valid redirection address */ - else - ms_infp->xa_flag=0; /* invalid redirection address */ - - return 0; -} - -static int sbpcd_audio_ioctl(struct cdrom_device_info *cdi, u_int cmd, - void * arg) -{ - struct sbpcd_drive *p = cdi->handle; - int i, st, j; - - msg(DBG_IO2,"ioctl(%s, 0x%08lX, 0x%08p)\n", cdi->name, cmd, arg); - if (p->drv_id==-1) { - msg(DBG_INF, "ioctl: bad device: %s\n", cdi->name); - return (-ENXIO); /* no such drive */ - } - down(&ioctl_read_sem); - if (p != current_drive) - switch_drive(p); - - msg(DBG_IO2,"ioctl: device %s, request %04X\n",cdi->name,cmd); - switch (cmd) /* Sun-compatible */ - { - - case CDROMPAUSE: /* Pause the drive */ - msg(DBG_IOC,"ioctl: CDROMPAUSE entered.\n"); - /* pause the drive unit when it is currently in PLAY mode, */ - /* or reset the starting and ending locations when in PAUSED mode. */ - /* If applicable, at the next stopping point it reaches */ - /* the drive will discontinue playing. */ - switch (current_drive->audio_state) - { - case audio_playing: - if (famL_drive) i=cc_ReadSubQ(); - else i=cc_Pause_Resume(1); - if (i<0) RETURN_UP(-EIO); - if (famL_drive) i=cc_Pause_Resume(1); - else i=cc_ReadSubQ(); - if (i<0) RETURN_UP(-EIO); - current_drive->pos_audio_start=current_drive->SubQ_run_tot; - current_drive->audio_state=audio_pausing; - RETURN_UP(0); - case audio_pausing: - i=cc_Seek(current_drive->pos_audio_start,1); - if (i<0) RETURN_UP(-EIO); - RETURN_UP(0); - default: - RETURN_UP(-EINVAL); - } - - case CDROMRESUME: /* resume paused audio play */ - msg(DBG_IOC,"ioctl: CDROMRESUME entered.\n"); - /* resume playing audio tracks when a previous PLAY AUDIO call has */ - /* been paused with a PAUSE command. */ - /* It will resume playing from the location saved in SubQ_run_tot. */ - if (current_drive->audio_state!=audio_pausing) RETURN_UP(-EINVAL); - if (famL_drive) - i=cc_PlayAudio(current_drive->pos_audio_start, - current_drive->pos_audio_end); - else i=cc_Pause_Resume(3); - if (i<0) RETURN_UP(-EIO); - current_drive->audio_state=audio_playing; - RETURN_UP(0); - - case CDROMPLAYMSF: - msg(DBG_IOC,"ioctl: CDROMPLAYMSF entered.\n"); -#ifdef SAFE_MIXED - if (current_drive->has_data>1) RETURN_UP(-EBUSY); -#endif /* SAFE_MIXED */ - if (current_drive->audio_state==audio_playing) - { - i=cc_Pause_Resume(1); - if (i<0) RETURN_UP(-EIO); - i=cc_ReadSubQ(); - if (i<0) RETURN_UP(-EIO); - current_drive->pos_audio_start=current_drive->SubQ_run_tot; - i=cc_Seek(current_drive->pos_audio_start,1); - } - memcpy(&msf, (void *) arg, sizeof(struct cdrom_msf)); - /* values come as msf-bin */ - current_drive->pos_audio_start = (msf.cdmsf_min0<<16) | - (msf.cdmsf_sec0<<8) | - msf.cdmsf_frame0; - current_drive->pos_audio_end = (msf.cdmsf_min1<<16) | - (msf.cdmsf_sec1<<8) | - msf.cdmsf_frame1; - msg(DBG_IOX,"ioctl: CDROMPLAYMSF %08X %08X\n", - current_drive->pos_audio_start,current_drive->pos_audio_end); - i=cc_PlayAudio(current_drive->pos_audio_start,current_drive->pos_audio_end); - if (i<0) - { - msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i); - DriveReset(); - current_drive->audio_state=0; - RETURN_UP(-EIO); - } - current_drive->audio_state=audio_playing; - RETURN_UP(0); - - case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ - msg(DBG_IOC,"ioctl: CDROMPLAYTRKIND entered.\n"); -#ifdef SAFE_MIXED - if (current_drive->has_data>1) RETURN_UP(-EBUSY); -#endif /* SAFE_MIXED */ - if (current_drive->audio_state==audio_playing) - { - msg(DBG_IOX,"CDROMPLAYTRKIND: already audio_playing.\n"); -#if 1 - RETURN_UP(0); /* just let us play on */ -#else - RETURN_UP(-EINVAL); /* play on, but say "error" */ -#endif - } - memcpy(&ti,(void *) arg,sizeof(struct cdrom_ti)); - msg(DBG_IOX,"ioctl: trk0: %d, ind0: %d, trk1:%d, ind1:%d\n", - ti.cdti_trk0,ti.cdti_ind0,ti.cdti_trk1,ti.cdti_ind1); - if (ti.cdti_trk0n_first_track) RETURN_UP(-EINVAL); - if (ti.cdti_trk0>current_drive->n_last_track) RETURN_UP(-EINVAL); - if (ti.cdti_trk1current_drive->n_last_track) ti.cdti_trk1=current_drive->n_last_track; - current_drive->pos_audio_start=current_drive->TocBuffer[ti.cdti_trk0].address; - current_drive->pos_audio_end=current_drive->TocBuffer[ti.cdti_trk1+1].address; - i=cc_PlayAudio(current_drive->pos_audio_start,current_drive->pos_audio_end); - if (i<0) - { - msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i); - DriveReset(); - current_drive->audio_state=0; - RETURN_UP(-EIO); - } - current_drive->audio_state=audio_playing; - RETURN_UP(0); - - case CDROMREADTOCHDR: /* Read the table of contents header */ - msg(DBG_IOC,"ioctl: CDROMREADTOCHDR entered.\n"); - tochdr.cdth_trk0=current_drive->n_first_track; - tochdr.cdth_trk1=current_drive->n_last_track; - memcpy((void *) arg, &tochdr, sizeof(struct cdrom_tochdr)); - RETURN_UP(0); - - case CDROMREADTOCENTRY: /* Read an entry in the table of contents */ - msg(DBG_IOC,"ioctl: CDROMREADTOCENTRY entered.\n"); - memcpy(&tocentry, (void *) arg, sizeof(struct cdrom_tocentry)); - i=tocentry.cdte_track; - if (i==CDROM_LEADOUT) i=current_drive->n_last_track+1; - else if (in_first_track||i>current_drive->n_last_track) - RETURN_UP(-EINVAL); - tocentry.cdte_adr=current_drive->TocBuffer[i].ctl_adr&0x0F; - tocentry.cdte_ctrl=(current_drive->TocBuffer[i].ctl_adr>>4)&0x0F; - tocentry.cdte_datamode=current_drive->TocBuffer[i].format; - if (tocentry.cdte_format==CDROM_MSF) /* MSF-bin required */ - { - tocentry.cdte_addr.msf.minute=(current_drive->TocBuffer[i].address>>16)&0x00FF; - tocentry.cdte_addr.msf.second=(current_drive->TocBuffer[i].address>>8)&0x00FF; - tocentry.cdte_addr.msf.frame=current_drive->TocBuffer[i].address&0x00FF; - } - else if (tocentry.cdte_format==CDROM_LBA) /* blk required */ - tocentry.cdte_addr.lba=msf2blk(current_drive->TocBuffer[i].address); - else RETURN_UP(-EINVAL); - memcpy((void *) arg, &tocentry, sizeof(struct cdrom_tocentry)); - RETURN_UP(0); - - case CDROMSTOP: /* Spin down the drive */ - msg(DBG_IOC,"ioctl: CDROMSTOP entered.\n"); -#ifdef SAFE_MIXED - if (current_drive->has_data>1) RETURN_UP(-EBUSY); -#endif /* SAFE_MIXED */ - i=cc_Pause_Resume(1); - current_drive->audio_state=0; -#if 0 - cc_DriveReset(); -#endif - RETURN_UP(i); - - case CDROMSTART: /* Spin up the drive */ - msg(DBG_IOC,"ioctl: CDROMSTART entered.\n"); - cc_SpinUp(); - current_drive->audio_state=0; - RETURN_UP(0); - - case CDROMVOLCTRL: /* Volume control */ - msg(DBG_IOC,"ioctl: CDROMVOLCTRL entered.\n"); - memcpy(&volctrl,(char *) arg,sizeof(volctrl)); - current_drive->vol_chan0=0; - current_drive->vol_ctrl0=volctrl.channel0; - current_drive->vol_chan1=1; - current_drive->vol_ctrl1=volctrl.channel1; - i=cc_SetVolume(); - RETURN_UP(0); - - case CDROMVOLREAD: /* read Volume settings from drive */ - msg(DBG_IOC,"ioctl: CDROMVOLREAD entered.\n"); - st=cc_GetVolume(); - if (st<0) RETURN_UP(st); - volctrl.channel0=current_drive->vol_ctrl0; - volctrl.channel1=current_drive->vol_ctrl1; - volctrl.channel2=0; - volctrl.channel2=0; - memcpy((void *)arg,&volctrl,sizeof(volctrl)); - RETURN_UP(0); - - case CDROMSUBCHNL: /* Get subchannel info */ - msg(DBG_IOS,"ioctl: CDROMSUBCHNL entered.\n"); - /* Bogus, I can do better than this! --AJK - if ((st_spinning)||(!subq_valid)) { - i=cc_ReadSubQ(); - if (i<0) RETURN_UP(-EIO); - } - */ - i=cc_ReadSubQ(); - if (i<0) { - j=cc_ReadError(); /* clear out error status from drive */ - current_drive->audio_state=CDROM_AUDIO_NO_STATUS; - /* get and set the disk state here, - probably not the right place, but who cares! - It makes it work properly! --AJK */ - if (current_drive->CD_changed==0xFF) { - msg(DBG_000,"Disk changed detect\n"); - current_drive->diskstate_flags &= ~cd_size_bit; - } - RETURN_UP(-EIO); - } - if (current_drive->CD_changed==0xFF) { - /* reread the TOC because the disk has changed! --AJK */ - msg(DBG_000,"Disk changed STILL detected, rereading TOC!\n"); - i=DiskInfo(); - if(i==0) { - current_drive->CD_changed=0x00; /* cd has changed, procede, */ - RETURN_UP(-EIO); /* and get TOC, etc on next try! --AJK */ - } else { - RETURN_UP(-EIO); /* we weren't ready yet! --AJK */ - } - } - memcpy(&SC, (void *) arg, sizeof(struct cdrom_subchnl)); - /* - This virtual crap is very bogus! - It doesn't detect when the cd is done playing audio! - Lets do this right with proper hardware register reading! - */ - cc_ReadStatus(); - i=ResponseStatus(); - msg(DBG_000,"Drive Status: door_locked =%d.\n", st_door_locked); - msg(DBG_000,"Drive Status: door_closed =%d.\n", st_door_closed); - msg(DBG_000,"Drive Status: caddy_in =%d.\n", st_caddy_in); - msg(DBG_000,"Drive Status: disk_ok =%d.\n", st_diskok); - msg(DBG_000,"Drive Status: spinning =%d.\n", st_spinning); - msg(DBG_000,"Drive Status: busy =%d.\n", st_busy); - /* st_busy indicates if it's _ACTUALLY_ playing audio */ - switch (current_drive->audio_state) - { - case audio_playing: - if(st_busy==0) { - /* CD has stopped playing audio --AJK */ - current_drive->audio_state=audio_completed; - SC.cdsc_audiostatus=CDROM_AUDIO_COMPLETED; - } else { - SC.cdsc_audiostatus=CDROM_AUDIO_PLAY; - } - break; - case audio_pausing: - SC.cdsc_audiostatus=CDROM_AUDIO_PAUSED; - break; - case audio_completed: - SC.cdsc_audiostatus=CDROM_AUDIO_COMPLETED; - break; - default: - SC.cdsc_audiostatus=CDROM_AUDIO_NO_STATUS; - break; - } - SC.cdsc_adr=current_drive->SubQ_ctl_adr; - SC.cdsc_ctrl=current_drive->SubQ_ctl_adr>>4; - SC.cdsc_trk=bcd2bin(current_drive->SubQ_trk); - SC.cdsc_ind=bcd2bin(current_drive->SubQ_pnt_idx); - if (SC.cdsc_format==CDROM_LBA) - { - SC.cdsc_absaddr.lba=msf2blk(current_drive->SubQ_run_tot); - SC.cdsc_reladdr.lba=msf2blk(current_drive->SubQ_run_trk); - } - else /* not only if (SC.cdsc_format==CDROM_MSF) */ - { - SC.cdsc_absaddr.msf.minute=(current_drive->SubQ_run_tot>>16)&0x00FF; - SC.cdsc_absaddr.msf.second=(current_drive->SubQ_run_tot>>8)&0x00FF; - SC.cdsc_absaddr.msf.frame=current_drive->SubQ_run_tot&0x00FF; - SC.cdsc_reladdr.msf.minute=(current_drive->SubQ_run_trk>>16)&0x00FF; - SC.cdsc_reladdr.msf.second=(current_drive->SubQ_run_trk>>8)&0x00FF; - SC.cdsc_reladdr.msf.frame=current_drive->SubQ_run_trk&0x00FF; - } - memcpy((void *) arg, &SC, sizeof(struct cdrom_subchnl)); - msg(DBG_IOS,"CDROMSUBCHNL: %1X %02X %08X %08X %02X %02X %06X %06X\n", - SC.cdsc_format,SC.cdsc_audiostatus, - SC.cdsc_adr,SC.cdsc_ctrl, - SC.cdsc_trk,SC.cdsc_ind, - SC.cdsc_absaddr,SC.cdsc_reladdr); - RETURN_UP(0); - - default: - msg(DBG_IOC,"ioctl: unknown function request %04X\n", cmd); - RETURN_UP(-EINVAL); - } /* end switch(cmd) */ -} -/*==========================================================================*/ -/* - * Take care of the different block sizes between cdrom and Linux. - */ -static void sbp_transfer(struct request *req) -{ - long offs; - - while ( (req->nr_sectors > 0) && - (req->sector/4 >= current_drive->sbp_first_frame) && - (req->sector/4 <= current_drive->sbp_last_frame) ) - { - offs = (req->sector - current_drive->sbp_first_frame * 4) * 512; - memcpy(req->buffer, current_drive->sbp_buf + offs, 512); - req->nr_sectors--; - req->sector++; - req->buffer += 512; - } -} -/*==========================================================================*/ -/* - * special end_request for sbpcd to solve CURRENT==NULL bug. (GTL) - * GTL = Gonzalo Tornaria - * - * This is a kludge so we don't need to modify end_request. - * We put the req we take out after INIT_REQUEST in the requests list, - * so that end_request will discard it. - * - * The bug could be present in other block devices, perhaps we - * should modify INIT_REQUEST and end_request instead, and - * change every block device.. - * - * Could be a race here?? Could e.g. a timer interrupt schedule() us? - * If so, we should copy end_request here, and do it right.. (or - * modify end_request and the block devices). - * - * In any case, the race here would be much small than it was, and - * I couldn't reproduce.. - * - * The race could be: suppose CURRENT==NULL. We put our req in the list, - * and we are scheduled. Other process takes over, and gets into - * do_sbpcd_request. It sees CURRENT!=NULL (it is == to our req), so - * proceeds. It ends, so CURRENT is now NULL.. Now we awake somewhere in - * end_request, but now CURRENT==NULL... oops! - * - */ -#undef DEBUG_GTL - -/*==========================================================================*/ -/* - * I/O request routine, called from Linux kernel. - */ -static void do_sbpcd_request(request_queue_t * q) -{ - u_int block; - u_int nsect; - int status_tries, data_tries; - struct request *req; - struct sbpcd_drive *p; -#ifdef DEBUG_GTL - static int xx_nr=0; - int xnr; -#endif - - request_loop: -#ifdef DEBUG_GTL - xnr=++xx_nr; - - req = elv_next_request(q); - - if (!req) - { - printk( "do_sbpcd_request[%di](NULL), Pid:%d, Time:%li\n", - xnr, current->pid, jiffies); - printk( "do_sbpcd_request[%do](NULL) end 0 (null), Time:%li\n", - xnr, jiffies); - return; - } - - printk(" do_sbpcd_request[%di](%p:%ld+%ld), Pid:%d, Time:%li\n", - xnr, req, req->sector, req->nr_sectors, current->pid, jiffies); -#endif - - req = elv_next_request(q); /* take out our request so no other */ - if (!req) - return; - - if (req -> sector == -1) - end_request(req, 0); - spin_unlock_irq(q->queue_lock); - - down(&ioctl_read_sem); - if (rq_data_dir(elv_next_request(q)) != READ) - { - msg(DBG_INF, "bad cmd %d\n", req->cmd[0]); - goto err_done; - } - p = req->rq_disk->private_data; -#if OLD_BUSY - while (busy_audio) sbp_sleep(HZ); /* wait a bit */ - busy_data=1; -#endif /* OLD_BUSY */ - - if (p->audio_state==audio_playing) goto err_done; - if (p != current_drive) - switch_drive(p); - - block = req->sector; /* always numbered as 512-byte-pieces */ - nsect = req->nr_sectors; /* always counted as 512-byte-pieces */ - - msg(DBG_BSZ,"read sector %d (%d sectors)\n", block, nsect); -#if 0 - msg(DBG_MUL,"read LBA %d\n", block/4); -#endif - - sbp_transfer(req); - /* if we satisfied the request from the buffer, we're done. */ - if (req->nr_sectors == 0) - { -#ifdef DEBUG_GTL - printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 2, Time:%li\n", - xnr, req, req->sector, req->nr_sectors, jiffies); -#endif - up(&ioctl_read_sem); - spin_lock_irq(q->queue_lock); - end_request(req, 1); - goto request_loop; - } - -#ifdef FUTURE - i=prepare(0,0); /* at moment not really a hassle check, but ... */ - if (i!=0) - msg(DBG_INF,"\"prepare\" tells error %d -- ignored\n", i); -#endif /* FUTURE */ - - if (!st_spinning) cc_SpinUp(); - - for (data_tries=n_retries; data_tries > 0; data_tries--) - { - for (status_tries=3; status_tries > 0; status_tries--) - { - flags_cmd_out |= f_respo3; - cc_ReadStatus(); - if (sbp_status() != 0) break; - if (st_check) cc_ReadError(); - sbp_sleep(1); /* wait a bit, try again */ - } - if (status_tries == 0) - { - msg(DBG_INF,"sbp_status: failed after 3 tries in line %d\n", __LINE__); - break; - } - - sbp_read_cmd(req); - sbp_sleep(0); - if (sbp_data(req) != 0) - { -#ifdef SAFE_MIXED - current_drive->has_data=2; /* is really a data disk */ -#endif /* SAFE_MIXED */ -#ifdef DEBUG_GTL - printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 3, Time:%li\n", - xnr, req, req->sector, req->nr_sectors, jiffies); -#endif - up(&ioctl_read_sem); - spin_lock_irq(q->queue_lock); - end_request(req, 1); - goto request_loop; - } - } - - err_done: -#if OLD_BUSY - busy_data=0; -#endif /* OLD_BUSY */ -#ifdef DEBUG_GTL - printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 4 (error), Time:%li\n", - xnr, req, req->sector, req->nr_sectors, jiffies); -#endif - up(&ioctl_read_sem); - sbp_sleep(0); /* wait a bit, try again */ - spin_lock_irq(q->queue_lock); - end_request(req, 0); - goto request_loop; -} -/*==========================================================================*/ -/* - * build and send the READ command. - */ -static void sbp_read_cmd(struct request *req) -{ -#undef OLD - - int i; - int block; - - current_drive->sbp_first_frame=current_drive->sbp_last_frame=-1; /* purge buffer */ - current_drive->sbp_current = 0; - block=req->sector/4; - if (block+current_drive->sbp_bufsiz <= current_drive->CDsize_frm) - current_drive->sbp_read_frames = current_drive->sbp_bufsiz; - else - { - current_drive->sbp_read_frames=current_drive->CDsize_frm-block; - /* avoid reading past end of data */ - if (current_drive->sbp_read_frames < 1) - { - msg(DBG_INF,"requested frame %d, CD size %d ???\n", - block, current_drive->CDsize_frm); - current_drive->sbp_read_frames=1; - } - } - - flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | f_obey_p_check; - clr_cmdbuf(); - if (famV_drive) - { - drvcmd[0]=CMDV_READ; - lba2msf(block,&drvcmd[1]); /* msf-bcd format required */ - bin2bcdx(&drvcmd[1]); - bin2bcdx(&drvcmd[2]); - bin2bcdx(&drvcmd[3]); - drvcmd[4]=current_drive->sbp_read_frames>>8; - drvcmd[5]=current_drive->sbp_read_frames&0xff; - drvcmd[6]=0x02; /* flag "msf-bcd" */ - } - else if (fam0L_drive) - { - flags_cmd_out |= f_lopsta | f_getsta | f_bit1; - if (current_drive->xa_byte==0x20) - { - cmd_type=READ_M2; - drvcmd[0]=CMD0_READ_XA; /* "read XA frames", old drives */ - drvcmd[1]=(block>>16)&0x0ff; - drvcmd[2]=(block>>8)&0x0ff; - drvcmd[3]=block&0x0ff; - drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff; - drvcmd[5]=current_drive->sbp_read_frames&0x0ff; - } - else - { - drvcmd[0]=CMD0_READ; /* "read frames", old drives */ - if (current_drive->drv_type>=drv_201) - { - lba2msf(block,&drvcmd[1]); /* msf-bcd format required */ - bin2bcdx(&drvcmd[1]); - bin2bcdx(&drvcmd[2]); - bin2bcdx(&drvcmd[3]); - } - else - { - drvcmd[1]=(block>>16)&0x0ff; - drvcmd[2]=(block>>8)&0x0ff; - drvcmd[3]=block&0x0ff; - } - drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff; - drvcmd[5]=current_drive->sbp_read_frames&0x0ff; - drvcmd[6]=(current_drive->drv_typesbp_read_frames>>8)&0x0ff; - drvcmd[6]=current_drive->sbp_read_frames&0x0ff; - } - else if (fam2_drive) - { - drvcmd[0]=CMD2_READ; - lba2msf(block,&drvcmd[1]); /* msf-bin format required */ - drvcmd[4]=(current_drive->sbp_read_frames>>8)&0x0ff; - drvcmd[5]=current_drive->sbp_read_frames&0x0ff; - drvcmd[6]=0x02; - } - else if (famT_drive) - { - drvcmd[0]=CMDT_READ; - drvcmd[2]=(block>>24)&0x0ff; - drvcmd[3]=(block>>16)&0x0ff; - drvcmd[4]=(block>>8)&0x0ff; - drvcmd[5]=block&0x0ff; - drvcmd[7]=(current_drive->sbp_read_frames>>8)&0x0ff; - drvcmd[8]=current_drive->sbp_read_frames&0x0ff; - } - flags_cmd_out=f_putcmd; - response_count=0; - i=cmd_out(); - if (i<0) msg(DBG_INF,"error giving READ command: %0d\n", i); - return; -} -/*==========================================================================*/ -/* - * Check the completion of the read-data command. On success, read - * the current_drive->sbp_bufsiz * 2048 bytes of data from the disk into buffer. - */ -static int sbp_data(struct request *req) -{ - int i=0, j=0, l, frame; - u_int try=0; - u_long timeout; - u_char *p; - u_int data_tries = 0; - u_int data_waits = 0; - u_int data_retrying = 0; - int error_flag; - int xa_count; - int max_latency; - int success; - int wait; - int duration; - - error_flag=0; - success=0; -#if LONG_TIMING - max_latency=9*HZ; -#else - if (current_drive->f_multisession) max_latency=15*HZ; - else max_latency=5*HZ; -#endif - duration=jiffies; - for (frame=0;framesbp_read_frames&&!error_flag; frame++) - { - SBPCD_CLI; - - del_timer(&data_timer); - data_timer.expires=jiffies+max_latency; - timed_out_data=0; - add_timer(&data_timer); - while (!timed_out_data) - { - if (current_drive->f_multisession) try=maxtim_data*4; - else try=maxtim_data; - msg(DBG_000,"sbp_data: CDi_status loop: try=%d.\n",try); - for ( ; try!=0;try--) - { - j=inb(CDi_status); - if (!(j&s_not_data_ready)) break; - if (!(j&s_not_result_ready)) break; - if (fam0LV_drive) if (j&s_attention) break; - } - if (!(j&s_not_data_ready)) goto data_ready; - if (try==0) - { - if (data_retrying == 0) data_waits++; - data_retrying = 1; - msg(DBG_000,"sbp_data: CDi_status loop: sleeping.\n"); - sbp_sleep(1); - try = 1; - } - } - msg(DBG_INF,"sbp_data: CDi_status loop expired.\n"); - data_ready: - del_timer(&data_timer); - - if (timed_out_data) - { - msg(DBG_INF,"sbp_data: CDi_status timeout (timed_out_data) (%02X).\n", j); - error_flag++; - } - if (try==0) - { - msg(DBG_INF,"sbp_data: CDi_status timeout (try=0) (%02X).\n", j); - error_flag++; - } - if (!(j&s_not_result_ready)) - { - msg(DBG_INF, "sbp_data: RESULT_READY where DATA_READY awaited (%02X).\n", j); - response_count=20; - j=ResponseInfo(); - j=inb(CDi_status); - } - if (j&s_not_data_ready) - { - if ((current_drive->ored_ctl_adr&0x40)==0) - msg(DBG_INF, "CD contains no data tracks.\n"); - else msg(DBG_INF, "sbp_data: DATA_READY timeout (%02X).\n", j); - error_flag++; - } - SBPCD_STI; - if (error_flag) break; - - msg(DBG_000, "sbp_data: beginning to read.\n"); - p = current_drive->sbp_buf + frame * CD_FRAMESIZE; - if (sbpro_type==1) OUT(CDo_sel_i_d,1); - if (cmd_type==READ_M2) { - if (do_16bit) insw(CDi_data, xa_head_buf, CD_XA_HEAD>>1); - else insb(CDi_data, xa_head_buf, CD_XA_HEAD); - } - if (do_16bit) insw(CDi_data, p, CD_FRAMESIZE>>1); - else insb(CDi_data, p, CD_FRAMESIZE); - if (cmd_type==READ_M2) { - if (do_16bit) insw(CDi_data, xa_tail_buf, CD_XA_TAIL>>1); - else insb(CDi_data, xa_tail_buf, CD_XA_TAIL); - } - current_drive->sbp_current++; - if (sbpro_type==1) OUT(CDo_sel_i_d,0); - if (cmd_type==READ_M2) - { - for (xa_count=0;xa_count= 1000) - { - msg(DBG_INF,"sbp_data() statistics: %d waits in %d frames.\n", data_waits, data_tries); - data_waits = data_tries = 0; - } - } - duration=jiffies-duration; - msg(DBG_TEA,"time to read %d frames: %d jiffies .\n",frame,duration); - if (famT_drive) - { - wait=8; - do - { - if (teac==2) - { - if ((i=CDi_stat_loop_T()) == -1) break; - } - else - { - sbp_sleep(1); - OUT(CDo_sel_i_d,0); - i=inb(CDi_status); - } - if (!(i&s_not_data_ready)) - { - OUT(CDo_sel_i_d,1); - j=0; - do - { - if (do_16bit) i=inw(CDi_data); - else i=inb(CDi_data); - j++; - i=inb(CDi_status); - } - while (!(i&s_not_data_ready)); - msg(DBG_TEA, "==========too much data (%d bytes/words)==============.\n", j); - } - if (!(i&s_not_result_ready)) - { - OUT(CDo_sel_i_d,0); - l=0; - do - { - infobuf[l++]=inb(CDi_info); - i=inb(CDi_status); - } - while (!(i&s_not_result_ready)); - if (infobuf[0]==0x00) success=1; -#if 1 - for (j=0;j1) msg(DBG_TEA,"cmd_out_T READ_ERR recursion (sbp_data): %d !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n",recursion); - else msg(DBG_TEA,"sbp_data: CMDT_READ_ERR necessary.\n"); - clr_cmdbuf(); - drvcmd[0]=CMDT_READ_ERR; - j=cmd_out_T(); /* !!! recursive here !!! */ - --recursion; - sbp_sleep(1); - } - while (j<0); - current_drive->error_state=infobuf[2]; - current_drive->b3=infobuf[3]; - current_drive->b4=infobuf[4]; - } - break; - } - else - { -#if 0 - msg(DBG_TEA, "============= waiting for result=================.\n"); - sbp_sleep(1); -#endif - } - } - while (wait--); - } - - if (error_flag) /* must have been spurious D_RDY or (ATTN&&!D_RDY) */ - { - msg(DBG_TEA, "================error flag: %d=================.\n", error_flag); - msg(DBG_INF,"sbp_data: read aborted by drive.\n"); -#if 1 - i=cc_DriveReset(); /* ugly fix to prevent a hang */ -#else - i=cc_ReadError(); -#endif - return (0); - } - - if (fam0LV_drive) - { - SBPCD_CLI; - i=maxtim_data; - for (timeout=jiffies+HZ; time_before(jiffies, timeout); timeout--) - { - for ( ;i!=0;i--) - { - j=inb(CDi_status); - if (!(j&s_not_data_ready)) break; - if (!(j&s_not_result_ready)) break; - if (j&s_attention) break; - } - if (i != 0 || time_after_eq(jiffies, timeout)) break; - sbp_sleep(0); - i = 1; - } - if (i==0) msg(DBG_INF,"status timeout after READ.\n"); - if (!(j&s_attention)) - { - msg(DBG_INF,"sbp_data: timeout waiting DRV_ATTN - retrying.\n"); - i=cc_DriveReset(); /* ugly fix to prevent a hang */ - SBPCD_STI; - return (0); - } - SBPCD_STI; - } - -#if 0 - if (!success) -#endif - do - { - if (fam0LV_drive) cc_ReadStatus(); -#if 1 - if (famT_drive) msg(DBG_TEA, "================before ResponseStatus=================.\n", i); -#endif - i=ResponseStatus(); /* builds status_bits, returns orig. status (old) or faked p_success (new) */ -#if 1 - if (famT_drive) msg(DBG_TEA, "================ResponseStatus: %d=================.\n", i); -#endif - if (i<0) - { - msg(DBG_INF,"bad cc_ReadStatus after read: %02X\n", current_drive->status_bits); - return (0); - } - } - while ((fam0LV_drive)&&(!st_check)&&(!(i&p_success))); - if (st_check) - { - i=cc_ReadError(); - msg(DBG_INF,"cc_ReadError was necessary after read: %d\n",i); - return (0); - } - if (fatal_err) - { - fatal_err=0; - current_drive->sbp_first_frame=current_drive->sbp_last_frame=-1; /* purge buffer */ - current_drive->sbp_current = 0; - msg(DBG_INF,"sbp_data: fatal_err - retrying.\n"); - return (0); - } - - current_drive->sbp_first_frame = req -> sector / 4; - current_drive->sbp_last_frame = current_drive->sbp_first_frame + current_drive->sbp_read_frames - 1; - sbp_transfer(req); - return (1); -} -/*==========================================================================*/ - -static int sbpcd_block_open(struct inode *inode, struct file *file) -{ - struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data; - return cdrom_open(p->sbpcd_infop, inode, file); -} - -static int sbpcd_block_release(struct inode *inode, struct file *file) -{ - struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data; - return cdrom_release(p->sbpcd_infop, file); -} - -static int sbpcd_block_ioctl(struct inode *inode, struct file *file, - unsigned cmd, unsigned long arg) -{ - struct sbpcd_drive *p = inode->i_bdev->bd_disk->private_data; - struct cdrom_device_info *cdi = p->sbpcd_infop; - int ret, i; - - ret = cdrom_ioctl(file, p->sbpcd_infop, inode, cmd, arg); - if (ret != -ENOSYS) - return ret; - - msg(DBG_IO2,"ioctl(%s, 0x%08lX, 0x%08lX)\n", cdi->name, cmd, arg); - if (p->drv_id==-1) { - msg(DBG_INF, "ioctl: bad device: %s\n", cdi->name); - return (-ENXIO); /* no such drive */ - } - down(&ioctl_read_sem); - if (p != current_drive) - switch_drive(p); - - msg(DBG_IO2,"ioctl: device %s, request %04X\n",cdi->name,cmd); - switch (cmd) /* Sun-compatible */ - { - case DDIOCSDBG: /* DDI Debug */ - if (!capable(CAP_SYS_ADMIN)) RETURN_UP(-EPERM); - i=sbpcd_dbg_ioctl(arg,1); - RETURN_UP(i); - case CDROMRESET: /* hard reset the drive */ - msg(DBG_IOC,"ioctl: CDROMRESET entered.\n"); - i=DriveReset(); - current_drive->audio_state=0; - RETURN_UP(i); - - case CDROMREADMODE1: - msg(DBG_IOC,"ioctl: CDROMREADMODE1 requested.\n"); -#ifdef SAFE_MIXED - if (current_drive->has_data>1) RETURN_UP(-EBUSY); -#endif /* SAFE_MIXED */ - cc_ModeSelect(CD_FRAMESIZE); - cc_ModeSense(); - current_drive->mode=READ_M1; - RETURN_UP(0); - - case CDROMREADMODE2: /* not usable at the moment */ - msg(DBG_IOC,"ioctl: CDROMREADMODE2 requested.\n"); -#ifdef SAFE_MIXED - if (current_drive->has_data>1) RETURN_UP(-EBUSY); -#endif /* SAFE_MIXED */ - cc_ModeSelect(CD_FRAMESIZE_RAW1); - cc_ModeSense(); - current_drive->mode=READ_M2; - RETURN_UP(0); - - case CDROMAUDIOBUFSIZ: /* configure the audio buffer size */ - msg(DBG_IOC,"ioctl: CDROMAUDIOBUFSIZ entered.\n"); - if (current_drive->sbp_audsiz>0) - vfree(current_drive->aud_buf); - current_drive->aud_buf=NULL; - current_drive->sbp_audsiz=arg; - - if (current_drive->sbp_audsiz>16) - { - current_drive->sbp_audsiz = 0; - RETURN_UP(current_drive->sbp_audsiz); - } - - if (current_drive->sbp_audsiz>0) - { - current_drive->aud_buf=(u_char *) vmalloc(current_drive->sbp_audsiz*CD_FRAMESIZE_RAW); - if (current_drive->aud_buf==NULL) - { - msg(DBG_INF,"audio buffer (%d frames) not available.\n",current_drive->sbp_audsiz); - current_drive->sbp_audsiz=0; - } - else msg(DBG_INF,"audio buffer size: %d frames.\n",current_drive->sbp_audsiz); - } - RETURN_UP(current_drive->sbp_audsiz); - - case CDROMREADAUDIO: - { /* start of CDROMREADAUDIO */ - int i=0, j=0, frame, block=0; - u_int try=0; - u_long timeout; - u_char *p; - u_int data_tries = 0; - u_int data_waits = 0; - u_int data_retrying = 0; - int status_tries; - int error_flag; - - msg(DBG_IOC,"ioctl: CDROMREADAUDIO entered.\n"); - if (fam0_drive) RETURN_UP(-EINVAL); - if (famL_drive) RETURN_UP(-EINVAL); - if (famV_drive) RETURN_UP(-EINVAL); - if (famT_drive) RETURN_UP(-EINVAL); -#ifdef SAFE_MIXED - if (current_drive->has_data>1) RETURN_UP(-EBUSY); -#endif /* SAFE_MIXED */ - if (current_drive->aud_buf==NULL) RETURN_UP(-EINVAL); - if (copy_from_user(&read_audio, (void __user *)arg, - sizeof(struct cdrom_read_audio))) - RETURN_UP(-EFAULT); - if (read_audio.nframes < 0 || read_audio.nframes>current_drive->sbp_audsiz) RETURN_UP(-EINVAL); - if (!access_ok(VERIFY_WRITE, read_audio.buf, - read_audio.nframes*CD_FRAMESIZE_RAW)) - RETURN_UP(-EFAULT); - - if (read_audio.addr_format==CDROM_MSF) /* MSF-bin specification of where to start */ - block=msf2lba(&read_audio.addr.msf.minute); - else if (read_audio.addr_format==CDROM_LBA) /* lba specification of where to start */ - block=read_audio.addr.lba; - else RETURN_UP(-EINVAL); -#if 000 - i=cc_SetSpeed(speed_150,0,0); - if (i) msg(DBG_AUD,"read_audio: SetSpeed error %d\n", i); -#endif - msg(DBG_AUD,"read_audio: lba: %d, msf: %06X\n", - block, blk2msf(block)); - msg(DBG_AUD,"read_audio: before cc_ReadStatus.\n"); -#if OLD_BUSY - while (busy_data) sbp_sleep(HZ/10); /* wait a bit */ - busy_audio=1; -#endif /* OLD_BUSY */ - error_flag=0; - for (data_tries=5; data_tries>0; data_tries--) - { - msg(DBG_AUD,"data_tries=%d ...\n", data_tries); - current_drive->mode=READ_AU; - cc_ModeSelect(CD_FRAMESIZE_RAW); - cc_ModeSense(); - for (status_tries=3; status_tries > 0; status_tries--) - { - flags_cmd_out |= f_respo3; - cc_ReadStatus(); - if (sbp_status() != 0) break; - if (st_check) cc_ReadError(); - sbp_sleep(1); /* wait a bit, try again */ - } - if (status_tries == 0) - { - msg(DBG_AUD,"read_audio: sbp_status: failed after 3 tries in line %d.\n", __LINE__); - continue; - } - msg(DBG_AUD,"read_audio: sbp_status: ok.\n"); - - flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | f_obey_p_check; - if (fam0L_drive) - { - flags_cmd_out |= f_lopsta | f_getsta | f_bit1; - cmd_type=READ_M2; - drvcmd[0]=CMD0_READ_XA; /* "read XA frames", old drives */ - drvcmd[1]=(block>>16)&0x000000ff; - drvcmd[2]=(block>>8)&0x000000ff; - drvcmd[3]=block&0x000000ff; - drvcmd[4]=0; - drvcmd[5]=read_audio.nframes; /* # of frames */ - drvcmd[6]=0; - } - else if (fam1_drive) - { - drvcmd[0]=CMD1_READ; /* "read frames", new drives */ - lba2msf(block,&drvcmd[1]); /* msf-bin format required */ - drvcmd[4]=0; - drvcmd[5]=0; - drvcmd[6]=read_audio.nframes; /* # of frames */ - } - else if (fam2_drive) - { - drvcmd[0]=CMD2_READ_XA2; - lba2msf(block,&drvcmd[1]); /* msf-bin format required */ - drvcmd[4]=0; - drvcmd[5]=read_audio.nframes; /* # of frames */ - drvcmd[6]=0x11; /* raw mode */ - } - else if (famT_drive) /* CD-55A: not tested yet */ - { - } - msg(DBG_AUD,"read_audio: before giving \"read\" command.\n"); - flags_cmd_out=f_putcmd; - response_count=0; - i=cmd_out(); - if (i<0) msg(DBG_INF,"error giving READ AUDIO command: %0d\n", i); - sbp_sleep(0); - msg(DBG_AUD,"read_audio: after giving \"read\" command.\n"); - for (frame=1;frame<2 && !error_flag; frame++) - { - try=maxtim_data; - for (timeout=jiffies+9*HZ; ; ) - { - for ( ; try!=0;try--) - { - j=inb(CDi_status); - if (!(j&s_not_data_ready)) break; - if (!(j&s_not_result_ready)) break; - if (fam0L_drive) if (j&s_attention) break; - } - if (try != 0 || time_after_eq(jiffies, timeout)) break; - if (data_retrying == 0) data_waits++; - data_retrying = 1; - sbp_sleep(1); - try = 1; - } - if (try==0) - { - msg(DBG_INF,"read_audio: sbp_data: CDi_status timeout.\n"); - error_flag++; - break; - } - msg(DBG_AUD,"read_audio: sbp_data: CDi_status ok.\n"); - if (j&s_not_data_ready) - { - msg(DBG_INF, "read_audio: sbp_data: DATA_READY timeout.\n"); - error_flag++; - break; - } - msg(DBG_AUD,"read_audio: before reading data.\n"); - error_flag=0; - p = current_drive->aud_buf; - if (sbpro_type==1) OUT(CDo_sel_i_d,1); - if (do_16bit) - { - u_short *p2 = (u_short *) p; - - for (; (u_char *) p2 < current_drive->aud_buf + read_audio.nframes*CD_FRAMESIZE_RAW;) - { - if ((inb_p(CDi_status)&s_not_data_ready)) continue; - - /* get one sample */ - *p2++ = inw_p(CDi_data); - *p2++ = inw_p(CDi_data); - } - } else { - for (; p < current_drive->aud_buf + read_audio.nframes*CD_FRAMESIZE_RAW;) - { - if ((inb_p(CDi_status)&s_not_data_ready)) continue; - - /* get one sample */ - *p++ = inb_p(CDi_data); - *p++ = inb_p(CDi_data); - *p++ = inb_p(CDi_data); - *p++ = inb_p(CDi_data); - } - } - if (sbpro_type==1) OUT(CDo_sel_i_d,0); - data_retrying = 0; - } - msg(DBG_AUD,"read_audio: after reading data.\n"); - if (error_flag) /* must have been spurious D_RDY or (ATTN&&!D_RDY) */ - { - msg(DBG_AUD,"read_audio: read aborted by drive\n"); -#if 0000 - i=cc_DriveReset(); /* ugly fix to prevent a hang */ -#else - i=cc_ReadError(); -#endif - continue; - } - if (fam0L_drive) - { - i=maxtim_data; - for (timeout=jiffies+9*HZ; time_before(jiffies, timeout); timeout--) - { - for ( ;i!=0;i--) - { - j=inb(CDi_status); - if (!(j&s_not_data_ready)) break; - if (!(j&s_not_result_ready)) break; - if (j&s_attention) break; - } - if (i != 0 || time_after_eq(jiffies, timeout)) break; - sbp_sleep(0); - i = 1; - } - if (i==0) msg(DBG_AUD,"read_audio: STATUS TIMEOUT AFTER READ"); - if (!(j&s_attention)) - { - msg(DBG_AUD,"read_audio: sbp_data: timeout waiting DRV_ATTN - retrying\n"); - i=cc_DriveReset(); /* ugly fix to prevent a hang */ - continue; - } - } - do - { - if (fam0L_drive) cc_ReadStatus(); - i=ResponseStatus(); /* builds status_bits, returns orig. status (old) or faked p_success (new) */ - if (i<0) { msg(DBG_AUD, - "read_audio: cc_ReadStatus error after read: %02X\n", - current_drive->status_bits); - continue; /* FIXME */ - } - } - while ((fam0L_drive)&&(!st_check)&&(!(i&p_success))); - if (st_check) - { - i=cc_ReadError(); - msg(DBG_AUD,"read_audio: cc_ReadError was necessary after read: %02X\n",i); - continue; - } - if (copy_to_user(read_audio.buf, - current_drive->aud_buf, - read_audio.nframes * CD_FRAMESIZE_RAW)) - RETURN_UP(-EFAULT); - msg(DBG_AUD,"read_audio: copy_to_user done.\n"); - break; - } - cc_ModeSelect(CD_FRAMESIZE); - cc_ModeSense(); - current_drive->mode=READ_M1; -#if OLD_BUSY - busy_audio=0; -#endif /* OLD_BUSY */ - if (data_tries == 0) - { - msg(DBG_AUD,"read_audio: failed after 5 tries in line %d.\n", __LINE__); - RETURN_UP(-EIO); - } - msg(DBG_AUD,"read_audio: successful return.\n"); - RETURN_UP(0); - } /* end of CDROMREADAUDIO */ - - default: - msg(DBG_IOC,"ioctl: unknown function request %04X\n", cmd); - RETURN_UP(-EINVAL); - } /* end switch(cmd) */ -} - -static int sbpcd_block_media_changed(struct gendisk *disk) -{ - struct sbpcd_drive *p = disk->private_data; - return cdrom_media_changed(p->sbpcd_infop); -} - -static struct block_device_operations sbpcd_bdops = -{ - .owner = THIS_MODULE, - .open = sbpcd_block_open, - .release = sbpcd_block_release, - .ioctl = sbpcd_block_ioctl, - .media_changed = sbpcd_block_media_changed, -}; -/*==========================================================================*/ -/* - * Open the device special file. Check that a disk is in. Read TOC. - */ -static int sbpcd_open(struct cdrom_device_info *cdi, int purpose) -{ - struct sbpcd_drive *p = cdi->handle; - - down(&ioctl_read_sem); - switch_drive(p); - - /* - * try to keep an "open" counter here and lock the door if 0->1. - */ - msg(DBG_LCK,"open_count: %d -> %d\n", - current_drive->open_count,current_drive->open_count+1); - if (++current_drive->open_count<=1) - { - int i; - i=LockDoor(); - current_drive->open_count=1; - if (famT_drive) msg(DBG_TEA,"sbpcd_open: before i=DiskInfo();.\n"); - i=DiskInfo(); - if (famT_drive) msg(DBG_TEA,"sbpcd_open: after i=DiskInfo();.\n"); - if ((current_drive->ored_ctl_adr&0x40)==0) - { - msg(DBG_INF,"CD contains no data tracks.\n"); -#ifdef SAFE_MIXED - current_drive->has_data=0; -#endif /* SAFE_MIXED */ - } -#ifdef SAFE_MIXED - else if (current_drive->has_data<1) current_drive->has_data=1; -#endif /* SAFE_MIXED */ - } - if (!st_spinning) cc_SpinUp(); - RETURN_UP(0); -} -/*==========================================================================*/ -/* - * On close, we flush all sbp blocks from the buffer cache. - */ -static void sbpcd_release(struct cdrom_device_info * cdi) -{ - struct sbpcd_drive *p = cdi->handle; - - if (p->drv_id==-1) { - msg(DBG_INF, "release: bad device: %s\n", cdi->name); - return; - } - down(&ioctl_read_sem); - switch_drive(p); - /* - * try to keep an "open" counter here and unlock the door if 1->0. - */ - msg(DBG_LCK,"open_count: %d -> %d\n", - p->open_count,p->open_count-1); - if (p->open_count>-2) /* CDROMEJECT may have been done */ - { - if (--p->open_count<=0) - { - p->sbp_first_frame=p->sbp_last_frame=-1; - if (p->audio_state!=audio_playing) - if (p->f_eject) cc_SpinDown(); - p->diskstate_flags &= ~cd_size_bit; - p->open_count=0; -#ifdef SAFE_MIXED - p->has_data=0; -#endif /* SAFE_MIXED */ - } - } - up(&ioctl_read_sem); - return ; -} -/*==========================================================================*/ -/* - * - */ -static int sbpcd_media_changed( struct cdrom_device_info *cdi, int disc_nr); -static struct cdrom_device_ops sbpcd_dops = { - .open = sbpcd_open, - .release = sbpcd_release, - .drive_status = sbpcd_drive_status, - .media_changed = sbpcd_media_changed, - .tray_move = sbpcd_tray_move, - .lock_door = sbpcd_lock_door, - .select_speed = sbpcd_select_speed, - .get_last_session = sbpcd_get_last_session, - .get_mcn = sbpcd_get_mcn, - .reset = sbpcd_reset, - .audio_ioctl = sbpcd_audio_ioctl, - .capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | - CDC_MULTI_SESSION | CDC_MEDIA_CHANGED | - CDC_MCN | CDC_PLAY_AUDIO, - .n_minors = 1, -}; - -/*==========================================================================*/ -/* - * accept "kernel command line" parameters - * (suggested by Peter MacDonald with SLS 1.03) - * - * This is only implemented for the first controller. Should be enough to - * allow installing with a "strange" distribution kernel. - * - * use: tell LILO: - * sbpcd=0x230,SoundBlaster - * or - * sbpcd=0x300,LaserMate - * or - * sbpcd=0x338,SoundScape - * or - * sbpcd=0x2C0,Teac16bit - * - * (upper/lower case sensitive here - but all-lowercase is ok!!!). - * - * the address value has to be the CDROM PORT ADDRESS - - * not the soundcard base address. - * For the SPEA/SoundScape setup, DO NOT specify the "configuration port" - * address, but the address which is really used for the CDROM (usually 8 - * bytes above). - * - */ - -int sbpcd_setup(char *s) -{ -#ifndef MODULE - int p[4]; - (void)get_options(s, ARRAY_SIZE(p), p); - setup_done++; - msg(DBG_INI,"sbpcd_setup called with %04X,%s\n",p[1], s); - sbpro_type=0; /* default: "LaserMate" */ - if (p[0]>1) sbpro_type=p[2]; - else if (!strcmp(s,str_sb)) sbpro_type=1; - else if (!strcmp(s,str_sb_l)) sbpro_type=1; - else if (!strcmp(s,str_sp)) sbpro_type=2; - else if (!strcmp(s,str_sp_l)) sbpro_type=2; - else if (!strcmp(s,str_ss)) sbpro_type=2; - else if (!strcmp(s,str_ss_l)) sbpro_type=2; - else if (!strcmp(s,str_t16)) sbpro_type=3; - else if (!strcmp(s,str_t16_l)) sbpro_type=3; - if (p[0]>0) sbpcd_ioaddr=p[1]; - if (p[0]>2) max_drives=p[3]; -#else - sbpcd_ioaddr = sbpcd[0]; - sbpro_type = sbpcd[1]; -#endif - - CDo_command=sbpcd_ioaddr; - CDi_info=sbpcd_ioaddr; - CDi_status=sbpcd_ioaddr+1; - CDo_sel_i_d=sbpcd_ioaddr+1; - CDo_reset=sbpcd_ioaddr+2; - CDo_enable=sbpcd_ioaddr+3; - f_16bit=0; - if ((sbpro_type==1)||(sbpro_type==3)) - { - CDi_data=sbpcd_ioaddr; - if (sbpro_type==3) - { - f_16bit=1; - sbpro_type=1; - } - } - else CDi_data=sbpcd_ioaddr+2; - - return 1; -} - -__setup("sbpcd=", sbpcd_setup); - - -/*==========================================================================*/ -/* - * Sequoia S-1000 CD-ROM Interface Configuration - * as used within SPEA Media FX, Ensonic SoundScape and some Reveal cards - * The soundcard has to get jumpered for the interface type "Panasonic" - * (not Sony or Mitsumi) and to get soft-configured for - * -> configuration port address - * -> CDROM port offset (num_ports): has to be 8 here. Possibly this - * offset value determines the interface type (none, Panasonic, - * Mitsumi, Sony). - * The interface uses a configuration port (0x320, 0x330, 0x340, 0x350) - * some bytes below the real CDROM address. - * - * For the Panasonic style (LaserMate) interface and the configuration - * port 0x330, we have to use an offset of 8; so, the real CDROM port - * address is 0x338. - */ -static int __init config_spea(void) -{ - /* - * base address offset between configuration port and CDROM port, - * this probably defines the interface type - * 2 (type=??): 0x00 - * 8 (type=LaserMate):0x10 - * 16 (type=??):0x20 - * 32 (type=??):0x30 - */ - int n_ports=0x10; - - int irq_number=0; /* off:0x00, 2/9:0x01, 7:0x03, 12:0x05, 15:0x07 */ - int dma_channel=0; /* off: 0x00, 0:0x08, 1:0x18, 3:0x38, 5:0x58, 6:0x68 */ - int dack_polarity=0; /* L:0x00, H:0x80 */ - int drq_polarity=0x40; /* L:0x00, H:0x40 */ - int i; - -#define SPEA_REG_1 sbpcd_ioaddr-0x08+4 -#define SPEA_REG_2 sbpcd_ioaddr-0x08+5 - - OUT(SPEA_REG_1,0xFF); - i=inb(SPEA_REG_1); - if (i!=0x0F) - { - msg(DBG_SEQ,"no SPEA interface at %04X present.\n", sbpcd_ioaddr); - return (-1); /* no interface found */ - } - OUT(SPEA_REG_1,0x04); - OUT(SPEA_REG_2,0xC0); - - OUT(SPEA_REG_1,0x05); - OUT(SPEA_REG_2,0x10|drq_polarity|dack_polarity); - -#if 1 -#define SPEA_PATTERN 0x80 -#else -#define SPEA_PATTERN 0x00 -#endif - OUT(SPEA_REG_1,0x06); - OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN); - OUT(SPEA_REG_2,dma_channel|irq_number|SPEA_PATTERN); - - OUT(SPEA_REG_1,0x09); - i=(inb(SPEA_REG_2)&0xCF)|n_ports; - OUT(SPEA_REG_2,i); - - sbpro_type = 0; /* acts like a LaserMate interface now */ - msg(DBG_SEQ,"found SoundScape interface at %04X.\n", sbpcd_ioaddr); - return (0); -} - -/*==========================================================================*/ -/* - * Test for presence of drive and initialize it. - * Called once at boot or load time. - */ - -/* FIXME: cleanups after failed allocations are too ugly for words */ -#ifdef MODULE -int __init __sbpcd_init(void) -#else -int __init sbpcd_init(void) -#endif -{ - int i=0, j=0; - int addr[2]={1, CDROM_PORT}; - int port_index; - - sti(); - - msg(DBG_INF,"sbpcd.c %s\n", VERSION); -#ifndef MODULE -#if DISTRIBUTION - if (!setup_done) - { - msg(DBG_INF,"Looking for Matsushita/Panasonic, CreativeLabs, Longshine, TEAC CD-ROM drives\n"); - msg(DBG_INF,"= = = = = = = = = = W A R N I N G = = = = = = = = = =\n"); - msg(DBG_INF,"Auto-Probing can cause a hang (f.e. touching an NE2000 card).\n"); - msg(DBG_INF,"If that happens, you have to reboot and use the\n"); - msg(DBG_INF,"LILO (kernel) command line feature like:\n"); - msg(DBG_INF," LILO boot: ... sbpcd=0x230,SoundBlaster\n"); - msg(DBG_INF,"or like:\n"); - msg(DBG_INF," LILO boot: ... sbpcd=0x300,LaserMate\n"); - msg(DBG_INF,"or like:\n"); - msg(DBG_INF," LILO boot: ... sbpcd=0x338,SoundScape\n"); - msg(DBG_INF,"with your REAL address.\n"); - msg(DBG_INF,"= = = = = = = = = = END of WARNING = = = = = == = = =\n"); - } -#endif /* DISTRIBUTION */ - sbpcd[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */ - sbpcd[1]=sbpro_type; /* possibly changed by kernel command line */ -#endif /* MODULE */ - - for (port_index=0;port_index=0) break; /* drive found */ - } /* end of cycling through the set of possible I/O port addresses */ - - if (ndrives==0) - { - msg(DBG_INF, "No drive found.\n"); -#ifdef MODULE - return -EIO; -#else - goto init_done; -#endif /* MODULE */ - } - - if (port_index>0) - { - msg(DBG_INF, "You should read Documentation/cdrom/sbpcd\n"); - msg(DBG_INF, "and then configure sbpcd.h for your hardware.\n"); - } - check_datarate(); - msg(DBG_INI,"check_datarate done.\n"); - - for (j=0;jdrv_id==-1) - continue; - switch_drive(p); -#if 1 - if (!famL_drive) cc_DriveReset(); -#endif - if (!st_spinning) cc_SpinUp(); - p->sbp_first_frame = -1; /* First frame in buffer */ - p->sbp_last_frame = -1; /* Last frame in buffer */ - p->sbp_read_frames = 0; /* Number of frames being read to buffer */ - p->sbp_current = 0; /* Frame being currently read */ - p->CD_changed=1; - p->frame_size=CD_FRAMESIZE; - p->f_eject=0; -#if EJECT - if (!fam0_drive) p->f_eject=1; -#endif /* EJECT */ - cc_ReadStatus(); - i=ResponseStatus(); /* returns orig. status or p_busy_new */ - if (famT_drive) i=ResponseStatus(); /* returns orig. status or p_busy_new */ - if (i<0) - { - if (i!=-402) - msg(DBG_INF,"init: ResponseStatus returns %d.\n",i); - } - else - { - if (st_check) - { - i=cc_ReadError(); - msg(DBG_INI,"init: cc_ReadError returns %d\n",i); - } - } - msg(DBG_INI,"init: first GetStatus: %d\n",i); - msg(DBG_LCS,"init: first GetStatus: error_byte=%d\n", - p->error_byte); - if (p->error_byte==aud_12) - { - timeout=jiffies+2*HZ; - do - { - i=GetStatus(); - msg(DBG_INI,"init: second GetStatus: %02X\n",i); - msg(DBG_LCS, - "init: second GetStatus: error_byte=%d\n", - p->error_byte); - if (i<0) break; - if (!st_caddy_in) break; - } - while ((!st_diskok)||time_after(jiffies, timeout)); - } - i=SetSpeed(); - if (i>=0) p->CD_changed=1; - } - - if (!request_region(CDo_command,4,major_name)) - { - printk(KERN_WARNING "sbpcd: Unable to request region 0x%x\n", CDo_command); - return -EIO; - } - - /* - * Turn on the CD audio channels. - * The addresses are obtained from SOUND_BASE (see sbpcd.h). - */ -#if SOUND_BASE - OUT(MIXER_addr,MIXER_CD_Volume); /* select SB Pro mixer register */ - OUT(MIXER_data,0xCC); /* one nibble per channel, max. value: 0xFF */ -#endif /* SOUND_BASE */ - - if (register_blkdev(MAJOR_NR, major_name)) { -#ifdef MODULE - return -EIO; -#else - goto init_done; -#endif /* MODULE */ - } - - /* - * init error handling is broken beyond belief in this driver... - */ - sbpcd_queue = blk_init_queue(do_sbpcd_request, &sbpcd_lock); - if (!sbpcd_queue) { - release_region(CDo_command,4); - unregister_blkdev(MAJOR_NR, major_name); - return -ENOMEM; - } - - for (j=0;jdrv_id==-1) continue; - switch_drive(p); -#ifdef SAFE_MIXED - p->has_data=0; -#endif /* SAFE_MIXED */ - /* - * allocate memory for the frame buffers - */ - p->aud_buf=NULL; - p->sbp_audsiz=0; - p->sbp_bufsiz=buffers; - if (p->drv_type&drv_fam1) - if (READ_AUDIO>0) - p->sbp_audsiz = READ_AUDIO; - p->sbp_buf=(u_char *) vmalloc(buffers*CD_FRAMESIZE); - if (!p->sbp_buf) { - msg(DBG_INF,"data buffer (%d frames) not available.\n", - buffers); - if ((unregister_blkdev(MAJOR_NR, major_name) == -EINVAL)) - { - printk("Can't unregister %s\n", major_name); - } - release_region(CDo_command,4); - blk_cleanup_queue(sbpcd_queue); - return -EIO; - } -#ifdef MODULE - msg(DBG_INF,"data buffer size: %d frames.\n",buffers); -#endif /* MODULE */ - if (p->sbp_audsiz>0) - { - p->aud_buf=(u_char *) vmalloc(p->sbp_audsiz*CD_FRAMESIZE_RAW); - if (p->aud_buf==NULL) msg(DBG_INF,"audio buffer (%d frames) not available.\n",p->sbp_audsiz); - else msg(DBG_INF,"audio buffer size: %d frames.\n",p->sbp_audsiz); - } - sbpcd_infop = vmalloc(sizeof (struct cdrom_device_info)); - if (sbpcd_infop == NULL) - { - release_region(CDo_command,4); - blk_cleanup_queue(sbpcd_queue); - return -ENOMEM; - } - memset(sbpcd_infop, 0, sizeof(struct cdrom_device_info)); - sbpcd_infop->ops = &sbpcd_dops; - sbpcd_infop->speed = 2; - sbpcd_infop->capacity = 1; - sprintf(sbpcd_infop->name, "sbpcd%d", j); - sbpcd_infop->handle = p; - p->sbpcd_infop = sbpcd_infop; - disk = alloc_disk(1); - disk->major = MAJOR_NR; - disk->first_minor = j; - disk->fops = &sbpcd_bdops; - strcpy(disk->disk_name, sbpcd_infop->name); - disk->flags = GENHD_FL_CD; - p->disk = disk; - if (register_cdrom(sbpcd_infop)) - { - printk(" sbpcd: Unable to register with Uniform CD-ROm driver\n"); - } - disk->private_data = p; - disk->queue = sbpcd_queue; - add_disk(disk); - } - blk_queue_hardsect_size(sbpcd_queue, CD_FRAMESIZE); - -#ifndef MODULE - init_done: -#endif - return 0; -} -/*==========================================================================*/ -#ifdef MODULE -static void sbpcd_exit(void) -{ - int j; - - if ((unregister_blkdev(MAJOR_NR, major_name) == -EINVAL)) - { - msg(DBG_INF, "What's that: can't unregister %s.\n", major_name); - return; - } - release_region(CDo_command,4); - blk_cleanup_queue(sbpcd_queue); - for (j=0;j0) - vfree(D_S[j].aud_buf); - if ((unregister_cdrom(D_S[j].sbpcd_infop) == -EINVAL)) - { - msg(DBG_INF, "What's that: can't unregister info %s.\n", major_name); - return; - } - vfree(D_S[j].sbpcd_infop); - } - msg(DBG_INF, "%s module released.\n", major_name); -} - - -module_init(__sbpcd_init) /*HACK!*/; -module_exit(sbpcd_exit); - - -#endif /* MODULE */ -static int sbpcd_media_changed(struct cdrom_device_info *cdi, int disc_nr) -{ - struct sbpcd_drive *p = cdi->handle; - msg(DBG_CHK,"media_check (%s) called\n", cdi->name); - - if (p->CD_changed==0xFF) - { - p->CD_changed=0; - msg(DBG_CHK,"medium changed (drive %s)\n", cdi->name); - current_drive->diskstate_flags &= ~toc_bit; - /* we *don't* need invalidate here, it's done by caller */ - current_drive->diskstate_flags &= ~cd_size_bit; -#ifdef SAFE_MIXED - current_drive->has_data=0; -#endif /* SAFE_MIXED */ - - return (1); - } - else - return (0); -} - -MODULE_LICENSE("GPL"); -/* FIXME: Old modules.conf claims MATSUSHITA_CDROM2_MAJOR and CDROM3, but - AFAICT this doesn't support those majors, so why? --RR 30 Jul 2003 */ -MODULE_ALIAS_BLOCKDEV_MAJOR(MATSUSHITA_CDROM_MAJOR); - -/*==========================================================================*/ -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 8 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -8 - * c-argdecl-indent: 8 - * c-label-offset: -8 - * c-continued-statement-offset: 8 - * c-continued-brace-offset: 0 - * End: - */ - diff --git a/drivers/cdrom/sbpcd.h b/drivers/cdrom/sbpcd.h deleted file mode 100644 index 2f2225f13c6f..000000000000 --- a/drivers/cdrom/sbpcd.h +++ /dev/null @@ -1,839 +0,0 @@ -/* - * sbpcd.h Specify interface address and interface type here. - */ - -/* - * Attention! This file contains user-serviceable parts! - * I recommend to make use of it... - * If you feel helpless, look into Documentation/cdrom/sbpcd - * (good idea anyway, at least before mailing me). - * - * The definitions for the first controller can get overridden by - * the kernel command line ("lilo boot option"). - * Examples: - * sbpcd=0x300,LaserMate - * or - * sbpcd=0x230,SoundBlaster - * or - * sbpcd=0x338,SoundScape - * or - * sbpcd=0x2C0,Teac16bit - * - * If sbpcd gets used as a module, you can load it with - * insmod sbpcd.o sbpcd=0x300,0 - * or - * insmod sbpcd.o sbpcd=0x230,1 - * or - * insmod sbpcd.o sbpcd=0x338,2 - * or - * insmod sbpcd.o sbpcd=0x2C0,3 - * respective to override the configured address and type. - */ - -/* - * define your CDROM port base address as CDROM_PORT - * and specify the type of your interface card as SBPRO. - * - * address: - * ======== - * SBPRO type addresses typically are 0x0230 (=0x220+0x10), 0x0250, ... - * LASERMATE type (CI-101P, WDH-7001C) addresses typically are 0x0300, ... - * SOUNDSCAPE addresses are from the LASERMATE type and range. You have to - * specify the REAL address here, not the configuration port address. Look - * at the CDROM driver's invoking line within your DOS CONFIG.SYS, or let - * sbpcd auto-probe, if you are not firm with the address. - * There are some soundcards on the market with 0x0630, 0x0650, ...; their - * type is not obvious (both types are possible). - * - * example: if your SBPRO audio address is 0x220, specify 0x230 and SBPRO 1. - * if your soundcard has its CDROM port above 0x300, specify - * that address and try SBPRO 0 first. - * if your SoundScape configuration port is at 0x330, specify - * 0x338 and SBPRO 2. - * - * interface type: - * =============== - * set SBPRO to 1 for "true" SoundBlaster card - * set SBPRO to 0 for "compatible" soundcards and - * for "poor" (no sound) interface cards. - * set SBPRO to 2 for Ensonic SoundScape or SPEA Media FX cards - * set SBPRO to 3 for Teac 16bit interface cards - * - * Almost all "compatible" sound boards need to set SBPRO to 0. - * If SBPRO is set wrong, the drives will get found - but any - * data access will give errors (audio access will work). - * The "OmniCD" no-sound interface card from CreativeLabs and most Teac - * interface cards need SBPRO 1. - * - * sound base: - * =========== - * The SOUND_BASE definition tells if we should try to turn the CD sound - * channels on. It will only be of use regarding soundcards with a SbPro - * compatible mixer. - * - * Example: #define SOUND_BASE 0x220 enables the sound card's CD channels - * #define SOUND_BASE 0 leaves the soundcard untouched - */ -#define CDROM_PORT 0x340 /* <-----------<< port address */ -#define SBPRO 0 /* <-----------<< interface type */ -#define MAX_DRIVES 4 /* set to 1 if the card does not use "drive select" */ -#define SOUND_BASE 0x220 /* <-----------<< sound address of this card or 0 */ - -/* - * some more or less user dependent definitions - service them! - */ - -/* Set this to 0 once you have configured your interface definitions right. */ -#define DISTRIBUTION 1 - -/* - * Time to wait after giving a message. - * This gets important if you enable non-standard DBG_xxx flags. - * You will see what happens if you omit the pause or make it - * too short. Be warned! - */ -#define KLOGD_PAUSE 1 - -/* tray control: eject tray if no disk is in */ -#if DISTRIBUTION -#define JUKEBOX 0 -#else -#define JUKEBOX 1 -#endif /* DISTRIBUTION */ - -/* tray control: eject tray after last use */ -#if DISTRIBUTION -#define EJECT 0 -#else -#define EJECT 1 -#endif /* DISTRIBUTION */ - -/* max. number of audio frames to read with one */ -/* request (allocates n* 2352 bytes kernel memory!) */ -/* may be freely adjusted, f.e. 75 (= 1 sec.), at */ -/* runtime by use of the CDROMAUDIOBUFSIZ ioctl. */ -#define READ_AUDIO 0 - -/* Optimizations for the Teac CD-55A drive read performance. - * SBP_TEAC_SPEED can be changed here, or one can set the - * variable "teac" when loading as a module. - * Valid settings are: - * 0 - very slow - the recommended "DISTRIBUTION 1" setup. - * 1 - 2x performance with little overhead. No busy waiting. - * 2 - 4x performance with 5ms overhead per read. Busy wait. - * - * Setting SBP_TEAC_SPEED or the variable 'teac' to anything - * other than 0 may cause problems. If you run into them, first - * change SBP_TEAC_SPEED back to 0 and see if your drive responds - * normally. If yes, you are "allowed" to report your case - to help - * me with the driver, not to solve your hassle. Don´t mail if you - * simply are stuck into your own "tuning" experiments, you know? - */ -#define SBP_TEAC_SPEED 1 - -/*==========================================================================*/ -/*==========================================================================*/ -/* - * nothing to change below here if you are not fully aware what you're doing - */ -#ifndef _LINUX_SBPCD_H - -#define _LINUX_SBPCD_H -/*==========================================================================*/ -/*==========================================================================*/ -/* - * driver's own read_ahead, data mode - */ -#define SBP_BUFFER_FRAMES 8 - -#define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */ -#undef FUTURE -#undef SAFE_MIXED - -#define TEST_UPC 0 -#define SPEA_TEST 0 -#define TEST_STI 0 -#define OLD_BUSY 0 -#undef PATH_CHECK -#ifndef SOUND_BASE -#define SOUND_BASE 0 -#endif -#if DISTRIBUTION -#undef SBP_TEAC_SPEED -#define SBP_TEAC_SPEED 0 -#endif -/*==========================================================================*/ -/* - * DDI interface definitions - * "invented" by Fred N. van Kempen.. - */ -#define DDIOCSDBG 0x9000 - -/*==========================================================================*/ -/* - * "private" IOCTL functions - */ -#define CDROMAUDIOBUFSIZ 0x5382 /* set the audio buffer size */ - -/*==========================================================================*/ -/* - * Debug output levels - */ -#define DBG_INF 1 /* necessary information */ -#define DBG_BSZ 2 /* BLOCK_SIZE trace */ -#define DBG_REA 3 /* READ status trace */ -#define DBG_CHK 4 /* MEDIA CHECK trace */ -#define DBG_TIM 5 /* datarate timer test */ -#define DBG_INI 6 /* initialization trace */ -#define DBG_TOC 7 /* tell TocEntry values */ -#define DBG_IOC 8 /* ioctl trace */ -#define DBG_STA 9 /* ResponseStatus() trace */ -#define DBG_ERR 10 /* cc_ReadError() trace */ -#define DBG_CMD 11 /* cmd_out() trace */ -#define DBG_WRN 12 /* give explanation before auto-probing */ -#define DBG_MUL 13 /* multi session code test */ -#define DBG_IDX 14 /* test code for drive_id !=0 */ -#define DBG_IOX 15 /* some special information */ -#define DBG_DID 16 /* drive ID test */ -#define DBG_RES 17 /* drive reset info */ -#define DBG_SPI 18 /* SpinUp test */ -#define DBG_IOS 19 /* ioctl trace: subchannel functions */ -#define DBG_IO2 20 /* ioctl trace: general */ -#define DBG_UPC 21 /* show UPC information */ -#define DBG_XA1 22 /* XA mode debugging */ -#define DBG_LCK 23 /* door (un)lock info */ -#define DBG_SQ1 24 /* dump SubQ frame */ -#define DBG_AUD 25 /* READ AUDIO debugging */ -#define DBG_SEQ 26 /* Sequoia interface configuration trace */ -#define DBG_LCS 27 /* Longshine LCS-7260 debugging trace */ -#define DBG_CD2 28 /* MKE/Funai CD200 debugging trace */ -#define DBG_TEA 29 /* TEAC CD-55A debugging trace */ -#define DBG_ECS 30 /* ECS-AT (Vertos 100) debugging trace */ -#define DBG_000 31 /* unnecessary information */ - -/*==========================================================================*/ -/*==========================================================================*/ - -/* - * bits of flags_cmd_out: - */ -#define f_respo3 0x100 -#define f_putcmd 0x80 -#define f_respo2 0x40 -#define f_lopsta 0x20 -#define f_getsta 0x10 -#define f_ResponseStatus 0x08 -#define f_obey_p_check 0x04 -#define f_bit1 0x02 -#define f_wait_if_busy 0x01 - -/* - * diskstate_flags: - */ -#define x80_bit 0x80 -#define upc_bit 0x40 -#define volume_bit 0x20 -#define toc_bit 0x10 -#define multisession_bit 0x08 -#define cd_size_bit 0x04 -#define subq_bit 0x02 -#define frame_size_bit 0x01 - -/* - * disk states (bits of diskstate_flags): - */ -#define upc_valid (current_drive->diskstate_flags&upc_bit) -#define volume_valid (current_drive->diskstate_flags&volume_bit) -#define toc_valid (current_drive->diskstate_flags&toc_bit) -#define cd_size_valid (current_drive->diskstate_flags&cd_size_bit) -#define subq_valid (current_drive->diskstate_flags&subq_bit) -#define frame_size_valid (current_drive->diskstate_flags&frame_size_bit) - -/* - * the status_bits variable - */ -#define p_success 0x100 -#define p_door_closed 0x80 -#define p_caddy_in 0x40 -#define p_spinning 0x20 -#define p_check 0x10 -#define p_busy_new 0x08 -#define p_door_locked 0x04 -#define p_disk_ok 0x01 - -/* - * LCS-7260 special status result bits: - */ -#define p_lcs_door_locked 0x02 -#define p_lcs_door_closed 0x01 /* probably disk_in */ - -/* - * CR-52x special status result bits: - */ -#define p_caddin_old 0x40 -#define p_success_old 0x08 -#define p_busy_old 0x04 -#define p_bit_1 0x02 /* hopefully unused now */ - -/* - * "generation specific" defs of the status result bits: - */ -#define p0_door_closed 0x80 -#define p0_caddy_in 0x40 -#define p0_spinning 0x20 -#define p0_check 0x10 -#define p0_success 0x08 /* unused */ -#define p0_busy 0x04 -#define p0_bit_1 0x02 /* unused */ -#define p0_disk_ok 0x01 - -#define pL_disk_in 0x40 -#define pL_spinning 0x20 -#define pL_check 0x10 -#define pL_success 0x08 /* unused ?? */ -#define pL_busy 0x04 -#define pL_door_locked 0x02 -#define pL_door_closed 0x01 - -#define pV_door_closed 0x40 -#define pV_spinning 0x20 -#define pV_check 0x10 -#define pV_success 0x08 -#define pV_busy 0x04 -#define pV_door_locked 0x02 -#define pV_disk_ok 0x01 - -#define p1_door_closed 0x80 -#define p1_disk_in 0x40 -#define p1_spinning 0x20 -#define p1_check 0x10 -#define p1_busy 0x08 -#define p1_door_locked 0x04 -#define p1_bit_1 0x02 /* unused */ -#define p1_disk_ok 0x01 - -#define p2_disk_ok 0x80 -#define p2_door_locked 0x40 -#define p2_spinning 0x20 -#define p2_busy2 0x10 -#define p2_busy1 0x08 -#define p2_door_closed 0x04 -#define p2_disk_in 0x02 -#define p2_check 0x01 - -/* - * used drive states: - */ -#define st_door_closed (current_drive->status_bits&p_door_closed) -#define st_caddy_in (current_drive->status_bits&p_caddy_in) -#define st_spinning (current_drive->status_bits&p_spinning) -#define st_check (current_drive->status_bits&p_check) -#define st_busy (current_drive->status_bits&p_busy_new) -#define st_door_locked (current_drive->status_bits&p_door_locked) -#define st_diskok (current_drive->status_bits&p_disk_ok) - -/* - * bits of the CDi_status register: - */ -#define s_not_result_ready 0x04 /* 0: "result ready" */ -#define s_not_data_ready 0x02 /* 0: "data ready" */ -#define s_attention 0x01 /* 1: "attention required" */ -/* - * usable as: - */ -#define DRV_ATTN ((inb(CDi_status)&s_attention)!=0) -#define DATA_READY ((inb(CDi_status)&s_not_data_ready)==0) -#define RESULT_READY ((inb(CDi_status)&s_not_result_ready)==0) - -/* - * drive families and types (firmware versions): - */ -#define drv_fam0 0x0100 /* CR-52x family */ -#define drv_199 (drv_fam0+0x01) /* <200 */ -#define drv_200 (drv_fam0+0x02) /* <201 */ -#define drv_201 (drv_fam0+0x03) /* <210 */ -#define drv_210 (drv_fam0+0x04) /* <211 */ -#define drv_211 (drv_fam0+0x05) /* <300 */ -#define drv_300 (drv_fam0+0x06) /* >=300 */ - -#define drv_fam1 0x0200 /* CR-56x family */ -#define drv_099 (drv_fam1+0x01) /* <100 */ -#define drv_100 (drv_fam1+0x02) /* >=100, only 1.02 and 5.00 known */ - -#define drv_fam2 0x0400 /* CD200 family */ - -#define drv_famT 0x0800 /* TEAC CD-55A */ - -#define drv_famL 0x1000 /* Longshine family */ -#define drv_260 (drv_famL+0x01) /* LCS-7260 */ -#define drv_e1 (drv_famL+0x01) /* LCS-7260, firmware "A E1" */ -#define drv_f4 (drv_famL+0x02) /* LCS-7260, firmware "A4F4" */ - -#define drv_famV 0x2000 /* ECS-AT (vertos-100) family */ -#define drv_at (drv_famV+0x01) /* ECS-AT, firmware "1.00" */ - -#define fam0_drive (current_drive->drv_type&drv_fam0) -#define famL_drive (current_drive->drv_type&drv_famL) -#define famV_drive (current_drive->drv_type&drv_famV) -#define fam1_drive (current_drive->drv_type&drv_fam1) -#define fam2_drive (current_drive->drv_type&drv_fam2) -#define famT_drive (current_drive->drv_type&drv_famT) -#define fam0L_drive (current_drive->drv_type&(drv_fam0|drv_famL)) -#define fam0V_drive (current_drive->drv_type&(drv_fam0|drv_famV)) -#define famLV_drive (current_drive->drv_type&(drv_famL|drv_famV)) -#define fam0LV_drive (current_drive->drv_type&(drv_fam0|drv_famL|drv_famV)) -#define fam1L_drive (current_drive->drv_type&(drv_fam1|drv_famL)) -#define fam1V_drive (current_drive->drv_type&(drv_fam1|drv_famV)) -#define fam1LV_drive (current_drive->drv_type&(drv_fam1|drv_famL|drv_famV)) -#define fam01_drive (current_drive->drv_type&(drv_fam0|drv_fam1)) -#define fam12_drive (current_drive->drv_type&(drv_fam1|drv_fam2)) -#define fam2T_drive (current_drive->drv_type&(drv_fam2|drv_famT)) - -/* - * audio states: - */ -#define audio_completed 3 /* Forgot this one! --AJK */ -#define audio_playing 2 -#define audio_pausing 1 - -/* - * drv_pattern, drv_options: - */ -#define speed_auto 0x80 -#define speed_300 0x40 -#define speed_150 0x20 -#define audio_mono 0x04 - -/* - * values of cmd_type (0 else): - */ -#define READ_M1 0x01 /* "data mode 1": 2048 bytes per frame */ -#define READ_M2 0x02 /* "data mode 2": 12+2048+280 bytes per frame */ -#define READ_SC 0x04 /* "subchannel info": 96 bytes per frame */ -#define READ_AU 0x08 /* "audio frame": 2352 bytes per frame */ - -/* - * sense_byte: - * - * values: 00 - * 01 - * 81 - * 82 "raw audio" mode - * xx from infobuf[0] after 85 00 00 00 00 00 00 - */ - -/* audio status (bin) */ -#define aud_00 0x00 /* Audio status byte not supported or not valid */ -#define audx11 0x0b /* Audio play operation in progress */ -#define audx12 0x0c /* Audio play operation paused */ -#define audx13 0x0d /* Audio play operation successfully completed */ -#define audx14 0x0e /* Audio play operation stopped due to error */ -#define audx15 0x0f /* No current audio status to return */ -/* audio status (bcd) */ -#define aud_11 0x11 /* Audio play operation in progress */ -#define aud_12 0x12 /* Audio play operation paused */ -#define aud_13 0x13 /* Audio play operation successfully completed */ -#define aud_14 0x14 /* Audio play operation stopped due to error */ -#define aud_15 0x15 /* No current audio status to return */ - -/* - * highest allowed drive number (MINOR+1) - */ -#define NR_SBPCD 4 - -/* - * we try to never disable interrupts - seems to work - */ -#define SBPCD_DIS_IRQ 0 - -/* - * "write byte to port" - */ -#define OUT(x,y) outb(y,x) - -/*==========================================================================*/ - -#define MIXER_addr SOUND_BASE+4 /* sound card's address register */ -#define MIXER_data SOUND_BASE+5 /* sound card's data register */ -#define MIXER_CD_Volume 0x28 /* internal SB Pro register address */ - -/*==========================================================================*/ - -#define MAX_TRACKS 99 - -#define ERR_DISKCHANGE 615 - -/*==========================================================================*/ -/* - * To make conversions easier (machine dependent!) - */ -typedef union _msf -{ - u_int n; - u_char c[4]; -} MSF; - -typedef union _blk -{ - u_int n; - u_char c[4]; -} BLK; - -/*==========================================================================*/ - -/*============================================================================ -============================================================================== - -COMMAND SET of "old" drives like CR-521, CR-522 - (the CR-562 family is different): - -No. Command Code --------------------------------------------- - -Drive Commands: - 1 Seek 01 - 2 Read Data 02 - 3 Read XA-Data 03 - 4 Read Header 04 - 5 Spin Up 05 - 6 Spin Down 06 - 7 Diagnostic 07 - 8 Read UPC 08 - 9 Read ISRC 09 -10 Play Audio 0A -11 Play Audio MSF 0B -12 Play Audio Track/Index 0C - -Status Commands: -13 Read Status 81 -14 Read Error 82 -15 Read Drive Version 83 -16 Mode Select 84 -17 Mode Sense 85 -18 Set XA Parameter 86 -19 Read XA Parameter 87 -20 Read Capacity 88 -21 Read SUB_Q 89 -22 Read Disc Code 8A -23 Read Disc Information 8B -24 Read TOC 8C -25 Pause/Resume 8D -26 Read Packet 8E -27 Read Path Check 00 - - -all numbers (lba, msf-bin, msf-bcd, counts) to transfer high byte first - -mnemo 7-byte command #bytes response (r0...rn) -________ ____________________ ____ - -Read Status: -status: 81. (1) one-byte command, gives the main - status byte -Read Error: -check1: 82 00 00 00 00 00 00. (6) r1: audio status - -Read Packet: -check2: 8e xx 00 00 00 00 00. (xx) gets xx bytes response, relating - to commands 01 04 05 07 08 09 - -Play Audio: -play: 0a ll-bb-aa nn-nn-nn. (0) play audio, ll-bb-aa: starting block (lba), - nn-nn-nn: #blocks -Play Audio MSF: - 0b mm-ss-ff mm-ss-ff (0) play audio from/to - -Play Audio Track/Index: - 0c ... - -Pause/Resume: -pause: 8d pr 00 00 00 00 00. (0) pause (pr=00) - resume (pr=80) audio playing - -Mode Select: - 84 00 nn-nn ??.?? 00 (0) nn-nn: 2048 or 2340 - possibly defines transfer size - -set_vol: 84 83 00 00 sw le 00. (0) sw(itch): lrxxxxxx (off=1) - le(vel): min=0, max=FF, else half - (firmware 2.11) - -Mode Sense: -get_vol: 85 03 00 00 00 00 00. (2) tell current audio volume setting - -Read Disc Information: -tocdesc: 8b 00 00 00 00 00 00. (6) read the toc descriptor ("msf-bin"-format) - -Read TOC: -tocent: 8c fl nn 00 00 00 00. (8) read toc entry #nn - (fl=0:"lba"-, =2:"msf-bin"-format) - -Read Capacity: -capacit: 88 00 00 00 00 00 00. (5) "read CD-ROM capacity" - - -Read Path Check: -ping: 00 00 00 00 00 00 00. (2) r0=AA, r1=55 - ("ping" if the drive is connected) - -Read Drive Version: -ident: 83 00 00 00 00 00 00. (12) gives "MATSHITAn.nn" - (n.nn = 2.01, 2.11., 3.00, ...) - -Seek: -seek: 01 00 ll-bb-aa 00 00. (0) -seek: 01 02 mm-ss-ff 00 00. (0) - -Read Data: -read: 02 xx-xx-xx nn-nn fl. (?) read nn-nn blocks of 2048 bytes, - starting at block xx-xx-xx - fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx - -Read XA-Data: -read: 03 xx-xx-xx nn-nn fl. (?) read nn-nn blocks of 2340 bytes, - starting at block xx-xx-xx - fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx - -Read SUB_Q: - 89 fl 00 00 00 00 00. (13) r0: audio status, r4-r7: lba/msf, - fl=0: "lba", fl=2: "msf" - -Read Disc Code: - 8a 00 00 00 00 00 00. (14) possibly extended "check condition"-info - -Read Header: - 04 00 ll-bb-aa 00 00. (0) 4 bytes response with "check2" - 04 02 mm-ss-ff 00 00. (0) 4 bytes response with "check2" - -Spin Up: - 05 00 ll-bb-aa 00 00. (0) possibly implies a "seek" - -Spin Down: - 06 ... - -Diagnostic: - 07 00 ll-bb-aa 00 00. (2) 2 bytes response with "check2" - 07 02 mm-ss-ff 00 00. (2) 2 bytes response with "check2" - -Read UPC: - 08 00 ll-bb-aa 00 00. (16) - 08 02 mm-ss-ff 00 00. (16) - -Read ISRC: - 09 00 ll-bb-aa 00 00. (15) 15 bytes response with "check2" - 09 02 mm-ss-ff 00 00. (15) 15 bytes response with "check2" - -Set XA Parameter: - 86 ... - -Read XA Parameter: - 87 ... - -============================================================================== -============================================================================*/ - -/* - * commands - * - * CR-52x: CMD0_ - * CR-56x: CMD1_ - * CD200: CMD2_ - * LCS-7260: CMDL_ - * TEAC CD-55A: CMDT_ - * ECS-AT: CMDV_ - */ -#define CMD1_RESET 0x0a -#define CMD2_RESET 0x01 -#define CMDT_RESET 0xc0 - -#define CMD1_LOCK_CTL 0x0c -#define CMD2_LOCK_CTL 0x1e -#define CMDT_LOCK_CTL CMD2_LOCK_CTL -#define CMDL_LOCK_CTL 0x0e -#define CMDV_LOCK_CTL CMDL_LOCK_CTL - -#define CMD1_TRAY_CTL 0x07 -#define CMD2_TRAY_CTL 0x1b -#define CMDT_TRAY_CTL CMD2_TRAY_CTL -#define CMDL_TRAY_CTL 0x0d -#define CMDV_TRAY_CTL CMDL_TRAY_CTL - -#define CMD1_MULTISESS 0x8d -#define CMDL_MULTISESS 0x8c -#define CMDV_MULTISESS CMDL_MULTISESS - -#define CMD1_SUBCHANINF 0x11 -#define CMD2_SUBCHANINF 0x?? - -#define CMD1_ABORT 0x08 -#define CMD2_ABORT 0x08 -#define CMDT_ABORT 0x08 - -#define CMD2_x02 0x02 - -#define CMD2_SETSPEED 0xda - -#define CMD0_PATH_CHECK 0x00 -#define CMD1_PATH_CHECK 0x??? -#define CMD2_PATH_CHECK 0x??? -#define CMDT_PATH_CHECK 0x??? -#define CMDL_PATH_CHECK CMD0_PATH_CHECK -#define CMDV_PATH_CHECK CMD0_PATH_CHECK - -#define CMD0_SEEK 0x01 -#define CMD1_SEEK CMD0_SEEK -#define CMD2_SEEK 0x2b -#define CMDT_SEEK CMD2_SEEK -#define CMDL_SEEK CMD0_SEEK -#define CMDV_SEEK CMD0_SEEK - -#define CMD0_READ 0x02 -#define CMD1_READ 0x10 -#define CMD2_READ 0x28 -#define CMDT_READ CMD2_READ -#define CMDL_READ CMD0_READ -#define CMDV_READ CMD0_READ - -#define CMD0_READ_XA 0x03 -#define CMD2_READ_XA 0xd4 -#define CMD2_READ_XA2 0xd5 -#define CMDL_READ_XA CMD0_READ_XA /* really ?? */ -#define CMDV_READ_XA CMD0_READ_XA - -#define CMD0_READ_HEAD 0x04 - -#define CMD0_SPINUP 0x05 -#define CMD1_SPINUP 0x02 -#define CMD2_SPINUP CMD2_TRAY_CTL -#define CMDL_SPINUP CMD0_SPINUP -#define CMDV_SPINUP CMD0_SPINUP - -#define CMD0_SPINDOWN 0x06 /* really??? */ -#define CMD1_SPINDOWN 0x06 -#define CMD2_SPINDOWN CMD2_TRAY_CTL -#define CMDL_SPINDOWN 0x0d -#define CMDV_SPINDOWN CMD0_SPINDOWN - -#define CMD0_DIAG 0x07 - -#define CMD0_READ_UPC 0x08 -#define CMD1_READ_UPC 0x88 -#define CMD2_READ_UPC 0x??? -#define CMDL_READ_UPC CMD0_READ_UPC -#define CMDV_READ_UPC 0x8f - -#define CMD0_READ_ISRC 0x09 - -#define CMD0_PLAY 0x0a -#define CMD1_PLAY 0x??? -#define CMD2_PLAY 0x??? -#define CMDL_PLAY CMD0_PLAY -#define CMDV_PLAY CMD0_PLAY - -#define CMD0_PLAY_MSF 0x0b -#define CMD1_PLAY_MSF 0x0e -#define CMD2_PLAY_MSF 0x47 -#define CMDT_PLAY_MSF CMD2_PLAY_MSF -#define CMDL_PLAY_MSF 0x??? - -#define CMD0_PLAY_TI 0x0c -#define CMD1_PLAY_TI 0x0f - -#define CMD0_STATUS 0x81 -#define CMD1_STATUS 0x05 -#define CMD2_STATUS 0x00 -#define CMDT_STATUS CMD2_STATUS -#define CMDL_STATUS CMD0_STATUS -#define CMDV_STATUS CMD0_STATUS -#define CMD2_SEEK_LEADIN 0x00 - -#define CMD0_READ_ERR 0x82 -#define CMD1_READ_ERR CMD0_READ_ERR -#define CMD2_READ_ERR 0x03 -#define CMDT_READ_ERR CMD2_READ_ERR /* get audio status */ -#define CMDL_READ_ERR CMD0_READ_ERR -#define CMDV_READ_ERR CMD0_READ_ERR - -#define CMD0_READ_VER 0x83 -#define CMD1_READ_VER CMD0_READ_VER -#define CMD2_READ_VER 0x12 -#define CMDT_READ_VER CMD2_READ_VER /* really ?? */ -#define CMDL_READ_VER CMD0_READ_VER -#define CMDV_READ_VER CMD0_READ_VER - -#define CMD0_SETMODE 0x84 -#define CMD1_SETMODE 0x09 -#define CMD2_SETMODE 0x55 -#define CMDT_SETMODE CMD2_SETMODE -#define CMDL_SETMODE CMD0_SETMODE - -#define CMD0_GETMODE 0x85 -#define CMD1_GETMODE 0x84 -#define CMD2_GETMODE 0x5a -#define CMDT_GETMODE CMD2_GETMODE -#define CMDL_GETMODE CMD0_GETMODE - -#define CMD0_SET_XA 0x86 - -#define CMD0_GET_XA 0x87 - -#define CMD0_CAPACITY 0x88 -#define CMD1_CAPACITY 0x85 -#define CMD2_CAPACITY 0x25 -#define CMDL_CAPACITY CMD0_CAPACITY /* missing in some firmware versions */ - -#define CMD0_READSUBQ 0x89 -#define CMD1_READSUBQ 0x87 -#define CMD2_READSUBQ 0x42 -#define CMDT_READSUBQ CMD2_READSUBQ -#define CMDL_READSUBQ CMD0_READSUBQ -#define CMDV_READSUBQ CMD0_READSUBQ - -#define CMD0_DISKCODE 0x8a - -#define CMD0_DISKINFO 0x8b -#define CMD1_DISKINFO CMD0_DISKINFO -#define CMD2_DISKINFO 0x43 -#define CMDT_DISKINFO CMD2_DISKINFO -#define CMDL_DISKINFO CMD0_DISKINFO -#define CMDV_DISKINFO CMD0_DISKINFO - -#define CMD0_READTOC 0x8c -#define CMD1_READTOC CMD0_READTOC -#define CMD2_READTOC 0x??? -#define CMDL_READTOC CMD0_READTOC -#define CMDV_READTOC CMD0_READTOC - -#define CMD0_PAU_RES 0x8d -#define CMD1_PAU_RES 0x0d -#define CMD2_PAU_RES 0x4b -#define CMDT_PAUSE CMD2_PAU_RES -#define CMDL_PAU_RES CMD0_PAU_RES -#define CMDV_PAUSE CMD0_PAU_RES - -#define CMD0_PACKET 0x8e -#define CMD1_PACKET CMD0_PACKET -#define CMD2_PACKET 0x??? -#define CMDL_PACKET CMD0_PACKET -#define CMDV_PACKET 0x??? - -/*==========================================================================*/ -/*==========================================================================*/ -#endif /* _LINUX_SBPCD_H */ -/*==========================================================================*/ -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 8 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -8 - * c-argdecl-indent: 8 - * c-label-offset: -8 - * c-continued-statement-offset: 8 - * c-continued-brace-offset: 0 - * End: - */ diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c deleted file mode 100644 index 76c24e679e68..000000000000 --- a/drivers/cdrom/sjcd.c +++ /dev/null @@ -1,1815 +0,0 @@ -/* -- sjcd.c - * - * Sanyo CD-ROM device driver implementation, Version 1.6 - * Copyright (C) 1995 Vadim V. Model - * - * model@cecmow.enet.dec.com - * vadim@rbrf.ru - * vadim@ipsun.ras.ru - * - * - * This driver is based on pre-works by Eberhard Moenkeberg (emoenke@gwdg.de); - * it was developed under use of mcd.c from Martin Harriss, with help of - * Eric van der Maarel (H.T.M.v.d.Maarel@marin.nl). - * - * It is planned to include these routines into sbpcd.c later - to make - * a "mixed use" on one cable possible for all kinds of drives which use - * the SoundBlaster/Panasonic style CDROM interface. But today, the - * ability to install directly from CDROM is more important than flexibility. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * History: - * 1.1 First public release with kernel version 1.3.7. - * Written by Vadim Model. - * 1.2 Added detection and configuration of cdrom interface - * on ISP16 soundcard. - * Allow for command line options: sjcd=,, - * 1.3 Some minor changes to README.sjcd. - * 1.4 MSS Sound support!! Listen to a CD through the speakers. - * 1.5 Module support and bugfixes. - * Tray locking. - * 1.6 Removed ISP16 code from this driver. - * Allow only to set io base address on command line: sjcd= - * Changes to Documentation/cdrom/sjcd - * Added cleanup after any error in the initialisation. - * 1.7 Added code to set the sector size tables to prevent the bug present in - * the previous version of this driver. Coded added by Anthony Barbachan - * from bugfix tip originally suggested by Alan Cox. - * - * November 1999 -- Make kernel-parameter implementation work with 2.3.x - * Removed init_module & cleanup_module in favor of - * module_init & module_exit. - * Torben Mathiasen - */ - -#define SJCD_VERSION_MAJOR 1 -#define SJCD_VERSION_MINOR 7 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include "sjcd.h" - -static int sjcd_present = 0; -static struct request_queue *sjcd_queue; - -#define MAJOR_NR SANYO_CDROM_MAJOR -#define QUEUE (sjcd_queue) -#define CURRENT elv_next_request(sjcd_queue) - -#define SJCD_BUF_SIZ 32 /* cdr-h94a has internal 64K buffer */ - -/* - * buffer for block size conversion - */ -static char sjcd_buf[2048 * SJCD_BUF_SIZ]; -static volatile int sjcd_buf_bn[SJCD_BUF_SIZ], sjcd_next_bn; -static volatile int sjcd_buf_in, sjcd_buf_out = -1; - -/* - * Status. - */ -static unsigned short sjcd_status_valid = 0; -static unsigned short sjcd_door_closed; -static unsigned short sjcd_door_was_open; -static unsigned short sjcd_media_is_available; -static unsigned short sjcd_media_is_changed; -static unsigned short sjcd_toc_uptodate = 0; -static unsigned short sjcd_command_failed; -static volatile unsigned char sjcd_completion_status = 0; -static volatile unsigned char sjcd_completion_error = 0; -static unsigned short sjcd_command_is_in_progress = 0; -static unsigned short sjcd_error_reported = 0; -static DEFINE_SPINLOCK(sjcd_lock); - -static int sjcd_open_count; - -static int sjcd_audio_status; -static struct sjcd_play_msf sjcd_playing; - -static int sjcd_base = SJCD_BASE_ADDR; - -module_param(sjcd_base, int, 0); - -static DECLARE_WAIT_QUEUE_HEAD(sjcd_waitq); - -/* - * Data transfer. - */ -static volatile unsigned short sjcd_transfer_is_active = 0; - -enum sjcd_transfer_state { - SJCD_S_IDLE = 0, - SJCD_S_START = 1, - SJCD_S_MODE = 2, - SJCD_S_READ = 3, - SJCD_S_DATA = 4, - SJCD_S_STOP = 5, - SJCD_S_STOPPING = 6 -}; -static enum sjcd_transfer_state sjcd_transfer_state = SJCD_S_IDLE; -static long sjcd_transfer_timeout = 0; -static int sjcd_read_count = 0; -static unsigned char sjcd_mode = 0; - -#define SJCD_READ_TIMEOUT 5000 - -#if defined( SJCD_GATHER_STAT ) -/* - * Statistic. - */ -static struct sjcd_stat statistic; -#endif - -/* - * Timer. - */ -static DEFINE_TIMER(sjcd_delay_timer, NULL, 0, 0); - -#define SJCD_SET_TIMER( func, tmout ) \ - ( sjcd_delay_timer.expires = jiffies+tmout, \ - sjcd_delay_timer.function = ( void * )func, \ - add_timer( &sjcd_delay_timer ) ) - -#define CLEAR_TIMER del_timer( &sjcd_delay_timer ) - -/* - * Set up device, i.e., use command line data to set - * base address. - */ -#ifndef MODULE -static int __init sjcd_setup(char *str) -{ - int ints[2]; - (void) get_options(str, ARRAY_SIZE(ints), ints); - if (ints[0] > 0) - sjcd_base = ints[1]; - - return 1; -} - -__setup("sjcd=", sjcd_setup); - -#endif - -/* - * Special converters. - */ -static unsigned char bin2bcd(int bin) -{ - int u, v; - - u = bin % 10; - v = bin / 10; - return (u | (v << 4)); -} - -static int bcd2bin(unsigned char bcd) -{ - return ((bcd >> 4) * 10 + (bcd & 0x0F)); -} - -static long msf2hsg(struct msf *mp) -{ - return (bcd2bin(mp->frame) + bcd2bin(mp->sec) * 75 - + bcd2bin(mp->min) * 4500 - 150); -} - -static void hsg2msf(long hsg, struct msf *msf) -{ - hsg += 150; - msf->min = hsg / 4500; - hsg %= 4500; - msf->sec = hsg / 75; - msf->frame = hsg % 75; - msf->min = bin2bcd(msf->min); /* convert to BCD */ - msf->sec = bin2bcd(msf->sec); - msf->frame = bin2bcd(msf->frame); -} - -/* - * Send a command to cdrom. Invalidate status. - */ -static void sjcd_send_cmd(unsigned char cmd) -{ -#if defined( SJCD_TRACE ) - printk("SJCD: send_cmd( 0x%x )\n", cmd); -#endif - outb(cmd, SJCDPORT(0)); - sjcd_command_is_in_progress = 1; - sjcd_status_valid = 0; - sjcd_command_failed = 0; -} - -/* - * Send a command with one arg to cdrom. Invalidate status. - */ -static void sjcd_send_1_cmd(unsigned char cmd, unsigned char a) -{ -#if defined( SJCD_TRACE ) - printk("SJCD: send_1_cmd( 0x%x, 0x%x )\n", cmd, a); -#endif - outb(cmd, SJCDPORT(0)); - outb(a, SJCDPORT(0)); - sjcd_command_is_in_progress = 1; - sjcd_status_valid = 0; - sjcd_command_failed = 0; -} - -/* - * Send a command with four args to cdrom. Invalidate status. - */ -static void sjcd_send_4_cmd(unsigned char cmd, unsigned char a, - unsigned char b, unsigned char c, - unsigned char d) -{ -#if defined( SJCD_TRACE ) - printk("SJCD: send_4_cmd( 0x%x )\n", cmd); -#endif - outb(cmd, SJCDPORT(0)); - outb(a, SJCDPORT(0)); - outb(b, SJCDPORT(0)); - outb(c, SJCDPORT(0)); - outb(d, SJCDPORT(0)); - sjcd_command_is_in_progress = 1; - sjcd_status_valid = 0; - sjcd_command_failed = 0; -} - -/* - * Send a play or read command to cdrom. Invalidate Status. - */ -static void sjcd_send_6_cmd(unsigned char cmd, struct sjcd_play_msf *pms) -{ -#if defined( SJCD_TRACE ) - printk("SJCD: send_long_cmd( 0x%x )\n", cmd); -#endif - outb(cmd, SJCDPORT(0)); - outb(pms->start.min, SJCDPORT(0)); - outb(pms->start.sec, SJCDPORT(0)); - outb(pms->start.frame, SJCDPORT(0)); - outb(pms->end.min, SJCDPORT(0)); - outb(pms->end.sec, SJCDPORT(0)); - outb(pms->end.frame, SJCDPORT(0)); - sjcd_command_is_in_progress = 1; - sjcd_status_valid = 0; - sjcd_command_failed = 0; -} - -/* - * Get a value from the data port. Should not block, so we use a little - * wait for a while. Returns 0 if OK. - */ -static int sjcd_load_response(void *buf, int len) -{ - unsigned char *resp = (unsigned char *) buf; - - for (; len; --len) { - int i; - for (i = 200; - i-- && !SJCD_STATUS_AVAILABLE(inb(SJCDPORT(1)));); - if (i > 0) - *resp++ = (unsigned char) inb(SJCDPORT(0)); - else - break; - } - return (len); -} - -/* - * Load and parse command completion status (drive info byte and maybe error). - * Sorry, no error classification yet. - */ -static void sjcd_load_status(void) -{ - sjcd_media_is_changed = 0; - sjcd_completion_error = 0; - sjcd_completion_status = inb(SJCDPORT(0)); - if (sjcd_completion_status & SST_DOOR_OPENED) { - sjcd_door_closed = sjcd_media_is_available = 0; - } else { - sjcd_door_closed = 1; - if (sjcd_completion_status & SST_MEDIA_CHANGED) - sjcd_media_is_available = sjcd_media_is_changed = - 1; - else if (sjcd_completion_status & 0x0F) { - /* - * OK, we seem to catch an error ... - */ - while (!SJCD_STATUS_AVAILABLE(inb(SJCDPORT(1)))); - sjcd_completion_error = inb(SJCDPORT(0)); - if ((sjcd_completion_status & 0x08) && - (sjcd_completion_error & 0x40)) - sjcd_media_is_available = 0; - else - sjcd_command_failed = 1; - } else - sjcd_media_is_available = 1; - } - /* - * Ok, status loaded successfully. - */ - sjcd_status_valid = 1, sjcd_error_reported = 0; - sjcd_command_is_in_progress = 0; - - /* - * If the disk is changed, the TOC is not valid. - */ - if (sjcd_media_is_changed) - sjcd_toc_uptodate = 0; -#if defined( SJCD_TRACE ) - printk("SJCD: status %02x.%02x loaded.\n", - (int) sjcd_completion_status, (int) sjcd_completion_error); -#endif -} - -/* - * Read status from cdrom. Check to see if the status is available. - */ -static int sjcd_check_status(void) -{ - /* - * Try to load the response from cdrom into buffer. - */ - if (SJCD_STATUS_AVAILABLE(inb(SJCDPORT(1)))) { - sjcd_load_status(); - return (1); - } else { - /* - * No status is available. - */ - return (0); - } -} - -/* - * This is just timeout counter, and nothing more. Surprised ? :-) - */ -static volatile long sjcd_status_timeout; - -/* - * We need about 10 seconds to wait. The longest command takes about 5 seconds - * to probe the disk (usually after tray closed or drive reset). Other values - * should be thought of for other commands. - */ -#define SJCD_WAIT_FOR_STATUS_TIMEOUT 1000 - -static void sjcd_status_timer(void) -{ - if (sjcd_check_status()) { - /* - * The command completed and status is loaded, stop waiting. - */ - wake_up(&sjcd_waitq); - } else if (--sjcd_status_timeout <= 0) { - /* - * We are timed out. - */ - wake_up(&sjcd_waitq); - } else { - /* - * We have still some time to wait. Try again. - */ - SJCD_SET_TIMER(sjcd_status_timer, 1); - } -} - -/* - * Wait for status for 10 sec approx. Returns non-positive when timed out. - * Should not be used while reading data CDs. - */ -static int sjcd_wait_for_status(void) -{ - sjcd_status_timeout = SJCD_WAIT_FOR_STATUS_TIMEOUT; - SJCD_SET_TIMER(sjcd_status_timer, 1); - sleep_on(&sjcd_waitq); -#if defined( SJCD_DIAGNOSTIC ) || defined ( SJCD_TRACE ) - if (sjcd_status_timeout <= 0) - printk("SJCD: Error Wait For Status.\n"); -#endif - return (sjcd_status_timeout); -} - -static int sjcd_receive_status(void) -{ - int i; -#if defined( SJCD_TRACE ) - printk("SJCD: receive_status\n"); -#endif - /* - * Wait a bit for status available. - */ - for (i = 200; i-- && (sjcd_check_status() == 0);); - if (i < 0) { -#if defined( SJCD_TRACE ) - printk("SJCD: long wait for status\n"); -#endif - if (sjcd_wait_for_status() <= 0) - printk("SJCD: Timeout when read status.\n"); - else - i = 0; - } - return (i); -} - -/* - * Load the status. Issue get status command and wait for status available. - */ -static void sjcd_get_status(void) -{ -#if defined( SJCD_TRACE ) - printk("SJCD: get_status\n"); -#endif - sjcd_send_cmd(SCMD_GET_STATUS); - sjcd_receive_status(); -} - -/* - * Check the drive if the disk is changed. Should be revised. - */ -static int sjcd_disk_change(struct gendisk *disk) -{ -#if 0 - printk("SJCD: sjcd_disk_change(%s)\n", disk->disk_name); -#endif - if (!sjcd_command_is_in_progress) - sjcd_get_status(); - return (sjcd_status_valid ? sjcd_media_is_changed : 0); -} - -/* - * Read the table of contents (TOC) and TOC header if necessary. - * We assume that the drive contains no more than 99 toc entries. - */ -static struct sjcd_hw_disk_info sjcd_table_of_contents[SJCD_MAX_TRACKS]; -static unsigned char sjcd_first_track_no, sjcd_last_track_no; -#define sjcd_disk_length sjcd_table_of_contents[0].un.track_msf - -static int sjcd_update_toc(void) -{ - struct sjcd_hw_disk_info info; - int i; -#if defined( SJCD_TRACE ) - printk("SJCD: update toc:\n"); -#endif - /* - * check to see if we need to do anything - */ - if (sjcd_toc_uptodate) - return (0); - - /* - * Get the TOC start information. - */ - sjcd_send_1_cmd(SCMD_GET_DISK_INFO, SCMD_GET_1_TRACK); - sjcd_receive_status(); - - if (!sjcd_status_valid) { - printk("SJCD: cannot load status.\n"); - return (-1); - } - - if (!sjcd_media_is_available) { - printk("SJCD: no disk in drive\n"); - return (-1); - } - - if (!sjcd_command_failed) { - if (sjcd_load_response(&info, sizeof(info)) != 0) { - printk - ("SJCD: cannot load response about TOC start.\n"); - return (-1); - } - sjcd_first_track_no = bcd2bin(info.un.track_no); - } else { - printk("SJCD: get first failed\n"); - return (-1); - } -#if defined( SJCD_TRACE ) - printk("SJCD: TOC start 0x%02x ", sjcd_first_track_no); -#endif - /* - * Get the TOC finish information. - */ - sjcd_send_1_cmd(SCMD_GET_DISK_INFO, SCMD_GET_L_TRACK); - sjcd_receive_status(); - - if (!sjcd_status_valid) { - printk("SJCD: cannot load status.\n"); - return (-1); - } - - if (!sjcd_media_is_available) { - printk("SJCD: no disk in drive\n"); - return (-1); - } - - if (!sjcd_command_failed) { - if (sjcd_load_response(&info, sizeof(info)) != 0) { - printk - ("SJCD: cannot load response about TOC finish.\n"); - return (-1); - } - sjcd_last_track_no = bcd2bin(info.un.track_no); - } else { - printk("SJCD: get last failed\n"); - return (-1); - } -#if defined( SJCD_TRACE ) - printk("SJCD: TOC finish 0x%02x ", sjcd_last_track_no); -#endif - for (i = sjcd_first_track_no; i <= sjcd_last_track_no; i++) { - /* - * Get the first track information. - */ - sjcd_send_1_cmd(SCMD_GET_DISK_INFO, bin2bcd(i)); - sjcd_receive_status(); - - if (!sjcd_status_valid) { - printk("SJCD: cannot load status.\n"); - return (-1); - } - - if (!sjcd_media_is_available) { - printk("SJCD: no disk in drive\n"); - return (-1); - } - - if (!sjcd_command_failed) { - if (sjcd_load_response(&sjcd_table_of_contents[i], - sizeof(struct - sjcd_hw_disk_info)) - != 0) { - printk - ("SJCD: cannot load info for %d track\n", - i); - return (-1); - } - } else { - printk("SJCD: get info %d failed\n", i); - return (-1); - } - } - - /* - * Get the disk length info. - */ - sjcd_send_1_cmd(SCMD_GET_DISK_INFO, SCMD_GET_D_SIZE); - sjcd_receive_status(); - - if (!sjcd_status_valid) { - printk("SJCD: cannot load status.\n"); - return (-1); - } - - if (!sjcd_media_is_available) { - printk("SJCD: no disk in drive\n"); - return (-1); - } - - if (!sjcd_command_failed) { - if (sjcd_load_response(&info, sizeof(info)) != 0) { - printk - ("SJCD: cannot load response about disk size.\n"); - return (-1); - } - sjcd_disk_length.min = info.un.track_msf.min; - sjcd_disk_length.sec = info.un.track_msf.sec; - sjcd_disk_length.frame = info.un.track_msf.frame; - } else { - printk("SJCD: get size failed\n"); - return (1); - } -#if defined( SJCD_TRACE ) - printk("SJCD: (%02x:%02x.%02x)\n", sjcd_disk_length.min, - sjcd_disk_length.sec, sjcd_disk_length.frame); -#endif - return (0); -} - -/* - * Load subchannel information. - */ -static int sjcd_get_q_info(struct sjcd_hw_qinfo *qp) -{ - int s; -#if defined( SJCD_TRACE ) - printk("SJCD: load sub q\n"); -#endif - sjcd_send_cmd(SCMD_GET_QINFO); - s = sjcd_receive_status(); - if (s < 0 || sjcd_command_failed || !sjcd_status_valid) { - sjcd_send_cmd(0xF2); - s = sjcd_receive_status(); - if (s < 0 || sjcd_command_failed || !sjcd_status_valid) - return (-1); - sjcd_send_cmd(SCMD_GET_QINFO); - s = sjcd_receive_status(); - if (s < 0 || sjcd_command_failed || !sjcd_status_valid) - return (-1); - } - if (sjcd_media_is_available) - if (sjcd_load_response(qp, sizeof(*qp)) == 0) - return (0); - return (-1); -} - -/* - * Start playing from the specified position. - */ -static int sjcd_play(struct sjcd_play_msf *mp) -{ - struct sjcd_play_msf msf; - - /* - * Turn the device to play mode. - */ - sjcd_send_1_cmd(SCMD_SET_MODE, SCMD_MODE_PLAY); - if (sjcd_receive_status() < 0) - return (-1); - - /* - * Seek to the starting point. - */ - msf.start = mp->start; - msf.end.min = msf.end.sec = msf.end.frame = 0x00; - sjcd_send_6_cmd(SCMD_SEEK, &msf); - if (sjcd_receive_status() < 0) - return (-1); - - /* - * Start playing. - */ - sjcd_send_6_cmd(SCMD_PLAY, mp); - return (sjcd_receive_status()); -} - -/* - * Tray control functions. - */ -static int sjcd_tray_close(void) -{ -#if defined( SJCD_TRACE ) - printk("SJCD: tray_close\n"); -#endif - sjcd_send_cmd(SCMD_CLOSE_TRAY); - return (sjcd_receive_status()); -} - -static int sjcd_tray_lock(void) -{ -#if defined( SJCD_TRACE ) - printk("SJCD: tray_lock\n"); -#endif - sjcd_send_cmd(SCMD_LOCK_TRAY); - return (sjcd_receive_status()); -} - -static int sjcd_tray_unlock(void) -{ -#if defined( SJCD_TRACE ) - printk("SJCD: tray_unlock\n"); -#endif - sjcd_send_cmd(SCMD_UNLOCK_TRAY); - return (sjcd_receive_status()); -} - -static int sjcd_tray_open(void) -{ -#if defined( SJCD_TRACE ) - printk("SJCD: tray_open\n"); -#endif - sjcd_send_cmd(SCMD_EJECT_TRAY); - return (sjcd_receive_status()); -} - -/* - * Do some user commands. - */ -static int sjcd_ioctl(struct inode *ip, struct file *fp, - unsigned int cmd, unsigned long arg) -{ - void __user *argp = (void __user *)arg; -#if defined( SJCD_TRACE ) - printk("SJCD:ioctl\n"); -#endif - - sjcd_get_status(); - if (!sjcd_status_valid) - return (-EIO); - if (sjcd_update_toc() < 0) - return (-EIO); - - switch (cmd) { - case CDROMSTART:{ -#if defined( SJCD_TRACE ) - printk("SJCD: ioctl: start\n"); -#endif - return (0); - } - - case CDROMSTOP:{ -#if defined( SJCD_TRACE ) - printk("SJCD: ioctl: stop\n"); -#endif - sjcd_send_cmd(SCMD_PAUSE); - (void) sjcd_receive_status(); - sjcd_audio_status = CDROM_AUDIO_NO_STATUS; - return (0); - } - - case CDROMPAUSE:{ - struct sjcd_hw_qinfo q_info; -#if defined( SJCD_TRACE ) - printk("SJCD: ioctl: pause\n"); -#endif - if (sjcd_audio_status == CDROM_AUDIO_PLAY) { - sjcd_send_cmd(SCMD_PAUSE); - (void) sjcd_receive_status(); - if (sjcd_get_q_info(&q_info) < 0) { - sjcd_audio_status = - CDROM_AUDIO_NO_STATUS; - } else { - sjcd_audio_status = - CDROM_AUDIO_PAUSED; - sjcd_playing.start = q_info.abs; - } - return (0); - } else - return (-EINVAL); - } - - case CDROMRESUME:{ -#if defined( SJCD_TRACE ) - printk("SJCD: ioctl: resume\n"); -#endif - if (sjcd_audio_status == CDROM_AUDIO_PAUSED) { - /* - * continue play starting at saved location - */ - if (sjcd_play(&sjcd_playing) < 0) { - sjcd_audio_status = - CDROM_AUDIO_ERROR; - return (-EIO); - } else { - sjcd_audio_status = - CDROM_AUDIO_PLAY; - return (0); - } - } else - return (-EINVAL); - } - - case CDROMPLAYTRKIND:{ - struct cdrom_ti ti; - int s = -EFAULT; -#if defined( SJCD_TRACE ) - printk("SJCD: ioctl: playtrkind\n"); -#endif - if (!copy_from_user(&ti, argp, sizeof(ti))) { - s = 0; - if (ti.cdti_trk0 < sjcd_first_track_no) - return (-EINVAL); - if (ti.cdti_trk1 > sjcd_last_track_no) - ti.cdti_trk1 = sjcd_last_track_no; - if (ti.cdti_trk0 > ti.cdti_trk1) - return (-EINVAL); - - sjcd_playing.start = - sjcd_table_of_contents[ti.cdti_trk0]. - un.track_msf; - sjcd_playing.end = - (ti.cdti_trk1 < - sjcd_last_track_no) ? - sjcd_table_of_contents[ti.cdti_trk1 + - 1].un. - track_msf : sjcd_table_of_contents[0]. - un.track_msf; - - if (sjcd_play(&sjcd_playing) < 0) { - sjcd_audio_status = - CDROM_AUDIO_ERROR; - return (-EIO); - } else - sjcd_audio_status = - CDROM_AUDIO_PLAY; - } - return (s); - } - - case CDROMPLAYMSF:{ - struct cdrom_msf sjcd_msf; - int s; -#if defined( SJCD_TRACE ) - printk("SJCD: ioctl: playmsf\n"); -#endif - if ((s = - access_ok(VERIFY_READ, argp, sizeof(sjcd_msf)) - ? 0 : -EFAULT) == 0) { - if (sjcd_audio_status == CDROM_AUDIO_PLAY) { - sjcd_send_cmd(SCMD_PAUSE); - (void) sjcd_receive_status(); - sjcd_audio_status = - CDROM_AUDIO_NO_STATUS; - } - - if (copy_from_user(&sjcd_msf, argp, - sizeof(sjcd_msf))) - return (-EFAULT); - - sjcd_playing.start.min = - bin2bcd(sjcd_msf.cdmsf_min0); - sjcd_playing.start.sec = - bin2bcd(sjcd_msf.cdmsf_sec0); - sjcd_playing.start.frame = - bin2bcd(sjcd_msf.cdmsf_frame0); - sjcd_playing.end.min = - bin2bcd(sjcd_msf.cdmsf_min1); - sjcd_playing.end.sec = - bin2bcd(sjcd_msf.cdmsf_sec1); - sjcd_playing.end.frame = - bin2bcd(sjcd_msf.cdmsf_frame1); - - if (sjcd_play(&sjcd_playing) < 0) { - sjcd_audio_status = - CDROM_AUDIO_ERROR; - return (-EIO); - } else - sjcd_audio_status = - CDROM_AUDIO_PLAY; - } - return (s); - } - - case CDROMREADTOCHDR:{ - struct cdrom_tochdr toc_header; -#if defined (SJCD_TRACE ) - printk("SJCD: ioctl: readtocheader\n"); -#endif - toc_header.cdth_trk0 = sjcd_first_track_no; - toc_header.cdth_trk1 = sjcd_last_track_no; - if (copy_to_user(argp, &toc_header, - sizeof(toc_header))) - return -EFAULT; - return 0; - } - - case CDROMREADTOCENTRY:{ - struct cdrom_tocentry toc_entry; - int s; -#if defined( SJCD_TRACE ) - printk("SJCD: ioctl: readtocentry\n"); -#endif - if ((s = - access_ok(VERIFY_WRITE, argp, sizeof(toc_entry)) - ? 0 : -EFAULT) == 0) { - struct sjcd_hw_disk_info *tp; - - if (copy_from_user(&toc_entry, argp, - sizeof(toc_entry))) - return (-EFAULT); - if (toc_entry.cdte_track == CDROM_LEADOUT) - tp = &sjcd_table_of_contents[0]; - else if (toc_entry.cdte_track < - sjcd_first_track_no) - return (-EINVAL); - else if (toc_entry.cdte_track > - sjcd_last_track_no) - return (-EINVAL); - else - tp = &sjcd_table_of_contents - [toc_entry.cdte_track]; - - toc_entry.cdte_adr = - tp->track_control & 0x0F; - toc_entry.cdte_ctrl = - tp->track_control >> 4; - - switch (toc_entry.cdte_format) { - case CDROM_LBA: - toc_entry.cdte_addr.lba = - msf2hsg(&(tp->un.track_msf)); - break; - case CDROM_MSF: - toc_entry.cdte_addr.msf.minute = - bcd2bin(tp->un.track_msf.min); - toc_entry.cdte_addr.msf.second = - bcd2bin(tp->un.track_msf.sec); - toc_entry.cdte_addr.msf.frame = - bcd2bin(tp->un.track_msf. - frame); - break; - default: - return (-EINVAL); - } - if (copy_to_user(argp, &toc_entry, - sizeof(toc_entry))) - s = -EFAULT; - } - return (s); - } - - case CDROMSUBCHNL:{ - struct cdrom_subchnl subchnl; - int s; -#if defined( SJCD_TRACE ) - printk("SJCD: ioctl: subchnl\n"); -#endif - if ((s = - access_ok(VERIFY_WRITE, argp, sizeof(subchnl)) - ? 0 : -EFAULT) == 0) { - struct sjcd_hw_qinfo q_info; - - if (copy_from_user(&subchnl, argp, - sizeof(subchnl))) - return (-EFAULT); - - if (sjcd_get_q_info(&q_info) < 0) - return (-EIO); - - subchnl.cdsc_audiostatus = - sjcd_audio_status; - subchnl.cdsc_adr = - q_info.track_control & 0x0F; - subchnl.cdsc_ctrl = - q_info.track_control >> 4; - subchnl.cdsc_trk = - bcd2bin(q_info.track_no); - subchnl.cdsc_ind = bcd2bin(q_info.x); - - switch (subchnl.cdsc_format) { - case CDROM_LBA: - subchnl.cdsc_absaddr.lba = - msf2hsg(&(q_info.abs)); - subchnl.cdsc_reladdr.lba = - msf2hsg(&(q_info.rel)); - break; - case CDROM_MSF: - subchnl.cdsc_absaddr.msf.minute = - bcd2bin(q_info.abs.min); - subchnl.cdsc_absaddr.msf.second = - bcd2bin(q_info.abs.sec); - subchnl.cdsc_absaddr.msf.frame = - bcd2bin(q_info.abs.frame); - subchnl.cdsc_reladdr.msf.minute = - bcd2bin(q_info.rel.min); - subchnl.cdsc_reladdr.msf.second = - bcd2bin(q_info.rel.sec); - subchnl.cdsc_reladdr.msf.frame = - bcd2bin(q_info.rel.frame); - break; - default: - return (-EINVAL); - } - if (copy_to_user(argp, &subchnl, - sizeof(subchnl))) - s = -EFAULT; - } - return (s); - } - - case CDROMVOLCTRL:{ - struct cdrom_volctrl vol_ctrl; - int s; -#if defined( SJCD_TRACE ) - printk("SJCD: ioctl: volctrl\n"); -#endif - if ((s = - access_ok(VERIFY_READ, argp, sizeof(vol_ctrl)) - ? 0 : -EFAULT) == 0) { - unsigned char dummy[4]; - - if (copy_from_user(&vol_ctrl, argp, - sizeof(vol_ctrl))) - return (-EFAULT); - sjcd_send_4_cmd(SCMD_SET_VOLUME, - vol_ctrl.channel0, 0xFF, - vol_ctrl.channel1, 0xFF); - if (sjcd_receive_status() < 0) - return (-EIO); - (void) sjcd_load_response(dummy, 4); - } - return (s); - } - - case CDROMEJECT:{ -#if defined( SJCD_TRACE ) - printk("SJCD: ioctl: eject\n"); -#endif - if (!sjcd_command_is_in_progress) { - sjcd_tray_unlock(); - sjcd_send_cmd(SCMD_EJECT_TRAY); - (void) sjcd_receive_status(); - } - return (0); - } - -#if defined( SJCD_GATHER_STAT ) - case 0xABCD:{ -#if defined( SJCD_TRACE ) - printk("SJCD: ioctl: statistic\n"); -#endif - if (copy_to_user(argp, &statistic, sizeof(statistic))) - return -EFAULT; - return 0; - } -#endif - - default: - return (-EINVAL); - } -} - -/* - * Invalidate internal buffers of the driver. - */ -static void sjcd_invalidate_buffers(void) -{ - int i; - for (i = 0; i < SJCD_BUF_SIZ; sjcd_buf_bn[i++] = -1); - sjcd_buf_out = -1; -} - -/* - * Take care of the different block sizes between cdrom and Linux. - * When Linux gets variable block sizes this will probably go away. - */ - -static int current_valid(void) -{ - return CURRENT && - rq_data_dir(CURRENT) == READ && - CURRENT->sector != -1; -} - -static void sjcd_transfer(void) -{ -#if defined( SJCD_TRACE ) - printk("SJCD: transfer:\n"); -#endif - if (current_valid()) { - while (CURRENT->nr_sectors) { - int i, bn = CURRENT->sector / 4; - for (i = 0; - i < SJCD_BUF_SIZ && sjcd_buf_bn[i] != bn; - i++); - if (i < SJCD_BUF_SIZ) { - int offs = - (i * 4 + (CURRENT->sector & 3)) * 512; - int nr_sectors = 4 - (CURRENT->sector & 3); - if (sjcd_buf_out != i) { - sjcd_buf_out = i; - if (sjcd_buf_bn[i] != bn) { - sjcd_buf_out = -1; - continue; - } - } - if (nr_sectors > CURRENT->nr_sectors) - nr_sectors = CURRENT->nr_sectors; -#if defined( SJCD_TRACE ) - printk("SJCD: copy out\n"); -#endif - memcpy(CURRENT->buffer, sjcd_buf + offs, - nr_sectors * 512); - CURRENT->nr_sectors -= nr_sectors; - CURRENT->sector += nr_sectors; - CURRENT->buffer += nr_sectors * 512; - } else { - sjcd_buf_out = -1; - break; - } - } - } -#if defined( SJCD_TRACE ) - printk("SJCD: transfer: done\n"); -#endif -} - -static void sjcd_poll(void) -{ -#if defined( SJCD_GATHER_STAT ) - /* - * Update total number of ticks. - */ - statistic.ticks++; - statistic.tticks[sjcd_transfer_state]++; -#endif - - ReSwitch:switch (sjcd_transfer_state) { - - case SJCD_S_IDLE:{ -#if defined( SJCD_GATHER_STAT ) - statistic.idle_ticks++; -#endif -#if defined( SJCD_TRACE ) - printk("SJCD_S_IDLE\n"); -#endif - return; - } - - case SJCD_S_START:{ -#if defined( SJCD_GATHER_STAT ) - statistic.start_ticks++; -#endif - sjcd_send_cmd(SCMD_GET_STATUS); - sjcd_transfer_state = - sjcd_mode == - SCMD_MODE_COOKED ? SJCD_S_READ : SJCD_S_MODE; - sjcd_transfer_timeout = 500; -#if defined( SJCD_TRACE ) - printk("SJCD_S_START: goto SJCD_S_%s mode\n", - sjcd_transfer_state == - SJCD_S_READ ? "READ" : "MODE"); -#endif - break; - } - - case SJCD_S_MODE:{ - if (sjcd_check_status()) { - /* - * Previous command is completed. - */ - if (!sjcd_status_valid - || sjcd_command_failed) { -#if defined( SJCD_TRACE ) - printk - ("SJCD_S_MODE: pre-cmd failed: goto to SJCD_S_STOP mode\n"); -#endif - sjcd_transfer_state = SJCD_S_STOP; - goto ReSwitch; - } - - sjcd_mode = 0; /* unknown mode; should not be valid when failed */ - sjcd_send_1_cmd(SCMD_SET_MODE, - SCMD_MODE_COOKED); - sjcd_transfer_state = SJCD_S_READ; - sjcd_transfer_timeout = 1000; -#if defined( SJCD_TRACE ) - printk - ("SJCD_S_MODE: goto SJCD_S_READ mode\n"); -#endif - } -#if defined( SJCD_GATHER_STAT ) - else - statistic.mode_ticks++; -#endif - break; - } - - case SJCD_S_READ:{ - if (sjcd_status_valid ? 1 : sjcd_check_status()) { - /* - * Previous command is completed. - */ - if (!sjcd_status_valid - || sjcd_command_failed) { -#if defined( SJCD_TRACE ) - printk - ("SJCD_S_READ: pre-cmd failed: goto to SJCD_S_STOP mode\n"); -#endif - sjcd_transfer_state = SJCD_S_STOP; - goto ReSwitch; - } - if (!sjcd_media_is_available) { -#if defined( SJCD_TRACE ) - printk - ("SJCD_S_READ: no disk: goto to SJCD_S_STOP mode\n"); -#endif - sjcd_transfer_state = SJCD_S_STOP; - goto ReSwitch; - } - if (sjcd_mode != SCMD_MODE_COOKED) { - /* - * We seem to come from set mode. So discard one byte of result. - */ - if (sjcd_load_response - (&sjcd_mode, 1) != 0) { -#if defined( SJCD_TRACE ) - printk - ("SJCD_S_READ: load failed: goto to SJCD_S_STOP mode\n"); -#endif - sjcd_transfer_state = - SJCD_S_STOP; - goto ReSwitch; - } - if (sjcd_mode != SCMD_MODE_COOKED) { -#if defined( SJCD_TRACE ) - printk - ("SJCD_S_READ: mode failed: goto to SJCD_S_STOP mode\n"); -#endif - sjcd_transfer_state = - SJCD_S_STOP; - goto ReSwitch; - } - } - - if (current_valid()) { - struct sjcd_play_msf msf; - - sjcd_next_bn = CURRENT->sector / 4; - hsg2msf(sjcd_next_bn, &msf.start); - msf.end.min = 0; - msf.end.sec = 0; - msf.end.frame = sjcd_read_count = - SJCD_BUF_SIZ; -#if defined( SJCD_TRACE ) - printk - ("SJCD: ---reading msf-address %x:%x:%x %x:%x:%x\n", - msf.start.min, msf.start.sec, - msf.start.frame, msf.end.min, - msf.end.sec, msf.end.frame); - printk - ("sjcd_next_bn:%x buf_in:%x buf_out:%x buf_bn:%x\n", - sjcd_next_bn, sjcd_buf_in, - sjcd_buf_out, - sjcd_buf_bn[sjcd_buf_in]); -#endif - sjcd_send_6_cmd(SCMD_DATA_READ, - &msf); - sjcd_transfer_state = SJCD_S_DATA; - sjcd_transfer_timeout = 500; -#if defined( SJCD_TRACE ) - printk - ("SJCD_S_READ: go to SJCD_S_DATA mode\n"); -#endif - } else { -#if defined( SJCD_TRACE ) - printk - ("SJCD_S_READ: nothing to read: go to SJCD_S_STOP mode\n"); -#endif - sjcd_transfer_state = SJCD_S_STOP; - goto ReSwitch; - } - } -#if defined( SJCD_GATHER_STAT ) - else - statistic.read_ticks++; -#endif - break; - } - - case SJCD_S_DATA:{ - unsigned char stat; - - sjcd_s_data:stat = - inb(SJCDPORT - (1)); -#if defined( SJCD_TRACE ) - printk("SJCD_S_DATA: status = 0x%02x\n", stat); -#endif - if (SJCD_STATUS_AVAILABLE(stat)) { - /* - * No data is waiting for us in the drive buffer. Status of operation - * completion is available. Read and parse it. - */ - sjcd_load_status(); - - if (!sjcd_status_valid - || sjcd_command_failed) { -#if defined( SJCD_TRACE ) - printk - ("SJCD: read block %d failed, maybe audio disk? Giving up\n", - sjcd_next_bn); -#endif - if (current_valid()) - end_request(CURRENT, 0); -#if defined( SJCD_TRACE ) - printk - ("SJCD_S_DATA: pre-cmd failed: go to SJCD_S_STOP mode\n"); -#endif - sjcd_transfer_state = SJCD_S_STOP; - goto ReSwitch; - } - - if (!sjcd_media_is_available) { - printk - ("SJCD_S_DATA: no disk: go to SJCD_S_STOP mode\n"); - sjcd_transfer_state = SJCD_S_STOP; - goto ReSwitch; - } - - sjcd_transfer_state = SJCD_S_READ; - goto ReSwitch; - } else if (SJCD_DATA_AVAILABLE(stat)) { - /* - * One frame is read into device buffer. We must copy it to our memory. - * Otherwise cdrom hangs up. Check to see if we have something to copy - * to. - */ - if (!current_valid() - && sjcd_buf_in == sjcd_buf_out) { -#if defined( SJCD_TRACE ) - printk - ("SJCD_S_DATA: nothing to read: go to SJCD_S_STOP mode\n"); - printk - (" ... all the date would be discarded\n"); -#endif - sjcd_transfer_state = SJCD_S_STOP; - goto ReSwitch; - } - - /* - * Everything seems to be OK. Just read the frame and recalculate - * indices. - */ - sjcd_buf_bn[sjcd_buf_in] = -1; /* ??? */ - insb(SJCDPORT(2), - sjcd_buf + 2048 * sjcd_buf_in, 2048); -#if defined( SJCD_TRACE ) - printk - ("SJCD_S_DATA: next_bn=%d, buf_in=%d, buf_out=%d, buf_bn=%d\n", - sjcd_next_bn, sjcd_buf_in, - sjcd_buf_out, - sjcd_buf_bn[sjcd_buf_in]); -#endif - sjcd_buf_bn[sjcd_buf_in] = sjcd_next_bn++; - if (sjcd_buf_out == -1) - sjcd_buf_out = sjcd_buf_in; - if (++sjcd_buf_in == SJCD_BUF_SIZ) - sjcd_buf_in = 0; - - /* - * Only one frame is ready at time. So we should turn over to wait for - * another frame. If we need that, of course. - */ - if (--sjcd_read_count == 0) { - /* - * OK, request seems to be precessed. Continue transferring... - */ - if (!sjcd_transfer_is_active) { - while (current_valid()) { - /* - * Continue transferring. - */ - sjcd_transfer(); - if (CURRENT-> - nr_sectors == - 0) - end_request - (CURRENT, 1); - else - break; - } - } - if (current_valid() && - (CURRENT->sector / 4 < - sjcd_next_bn - || CURRENT->sector / 4 > - sjcd_next_bn + - SJCD_BUF_SIZ)) { -#if defined( SJCD_TRACE ) - printk - ("SJCD_S_DATA: can't read: go to SJCD_S_STOP mode\n"); -#endif - sjcd_transfer_state = - SJCD_S_STOP; - goto ReSwitch; - } - } - /* - * Now we should turn around rather than wait for while. - */ - goto sjcd_s_data; - } -#if defined( SJCD_GATHER_STAT ) - else - statistic.data_ticks++; -#endif - break; - } - - case SJCD_S_STOP:{ - sjcd_read_count = 0; - sjcd_send_cmd(SCMD_STOP); - sjcd_transfer_state = SJCD_S_STOPPING; - sjcd_transfer_timeout = 500; -#if defined( SJCD_GATHER_STAT ) - statistic.stop_ticks++; -#endif - break; - } - - case SJCD_S_STOPPING:{ - unsigned char stat; - - stat = inb(SJCDPORT(1)); -#if defined( SJCD_TRACE ) - printk("SJCD_S_STOP: status = 0x%02x\n", stat); -#endif - if (SJCD_DATA_AVAILABLE(stat)) { - int i; -#if defined( SJCD_TRACE ) - printk("SJCD_S_STOP: discard data\n"); -#endif - /* - * Discard all the data from the pipe. Foolish method. - */ - for (i = 2048; i--; - (void) inb(SJCDPORT(2))); - sjcd_transfer_timeout = 500; - } else if (SJCD_STATUS_AVAILABLE(stat)) { - sjcd_load_status(); - if (sjcd_status_valid - && sjcd_media_is_changed) { - sjcd_toc_uptodate = 0; - sjcd_invalidate_buffers(); - } - if (current_valid()) { - if (sjcd_status_valid) - sjcd_transfer_state = - SJCD_S_READ; - else - sjcd_transfer_state = - SJCD_S_START; - } else - sjcd_transfer_state = SJCD_S_IDLE; - goto ReSwitch; - } -#if defined( SJCD_GATHER_STAT ) - else - statistic.stopping_ticks++; -#endif - break; - } - - default: - printk("SJCD: poll: invalid state %d\n", - sjcd_transfer_state); - return; - } - - if (--sjcd_transfer_timeout == 0) { - printk("SJCD: timeout in state %d\n", sjcd_transfer_state); - while (current_valid()) - end_request(CURRENT, 0); - sjcd_send_cmd(SCMD_STOP); - sjcd_transfer_state = SJCD_S_IDLE; - goto ReSwitch; - } - - /* - * Get back in some time. 1 should be replaced with count variable to - * avoid unnecessary testings. - */ - SJCD_SET_TIMER(sjcd_poll, 1); -} - -static void do_sjcd_request(request_queue_t * q) -{ -#if defined( SJCD_TRACE ) - printk("SJCD: do_sjcd_request(%ld+%ld)\n", - CURRENT->sector, CURRENT->nr_sectors); -#endif - sjcd_transfer_is_active = 1; - while (current_valid()) { - sjcd_transfer(); - if (CURRENT->nr_sectors == 0) - end_request(CURRENT, 1); - else { - sjcd_buf_out = -1; /* Want to read a block not in buffer */ - if (sjcd_transfer_state == SJCD_S_IDLE) { - if (!sjcd_toc_uptodate) { - if (sjcd_update_toc() < 0) { - printk - ("SJCD: transfer: discard\n"); - while (current_valid()) - end_request(CURRENT, 0); - break; - } - } - sjcd_transfer_state = SJCD_S_START; - SJCD_SET_TIMER(sjcd_poll, HZ / 100); - } - break; - } - } - sjcd_transfer_is_active = 0; -#if defined( SJCD_TRACE ) - printk - ("sjcd_next_bn:%x sjcd_buf_in:%x sjcd_buf_out:%x sjcd_buf_bn:%x\n", - sjcd_next_bn, sjcd_buf_in, sjcd_buf_out, - sjcd_buf_bn[sjcd_buf_in]); - printk("do_sjcd_request ends\n"); -#endif -} - -/* - * Open the device special file. Check disk is in. - */ -static int sjcd_open(struct inode *ip, struct file *fp) -{ - /* - * Check the presence of device. - */ - if (!sjcd_present) - return (-ENXIO); - - /* - * Only read operations are allowed. Really? (:-) - */ - if (fp->f_mode & 2) - return (-EROFS); - - if (sjcd_open_count == 0) { - int s, sjcd_open_tries; -/* We don't know that, do we? */ -/* - sjcd_audio_status = CDROM_AUDIO_NO_STATUS; -*/ - sjcd_mode = 0; - sjcd_door_was_open = 0; - sjcd_transfer_state = SJCD_S_IDLE; - sjcd_invalidate_buffers(); - sjcd_status_valid = 0; - - /* - * Strict status checking. - */ - for (sjcd_open_tries = 4; --sjcd_open_tries;) { - if (!sjcd_status_valid) - sjcd_get_status(); - if (!sjcd_status_valid) { -#if defined( SJCD_DIAGNOSTIC ) - printk - ("SJCD: open: timed out when check status.\n"); -#endif - goto err_out; - } else if (!sjcd_media_is_available) { -#if defined( SJCD_DIAGNOSTIC ) - printk("SJCD: open: no disk in drive\n"); -#endif - if (!sjcd_door_closed) { - sjcd_door_was_open = 1; -#if defined( SJCD_TRACE ) - printk - ("SJCD: open: close the tray\n"); -#endif - s = sjcd_tray_close(); - if (s < 0 || !sjcd_status_valid - || sjcd_command_failed) { -#if defined( SJCD_DIAGNOSTIC ) - printk - ("SJCD: open: tray close attempt failed\n"); -#endif - goto err_out; - } - continue; - } else - goto err_out; - } - break; - } - s = sjcd_tray_lock(); - if (s < 0 || !sjcd_status_valid || sjcd_command_failed) { -#if defined( SJCD_DIAGNOSTIC ) - printk("SJCD: open: tray lock attempt failed\n"); -#endif - goto err_out; - } -#if defined( SJCD_TRACE ) - printk("SJCD: open: done\n"); -#endif - } - - ++sjcd_open_count; - return (0); - - err_out: - return (-EIO); -} - -/* - * On close, we flush all sjcd blocks from the buffer cache. - */ -static int sjcd_release(struct inode *inode, struct file *file) -{ - int s; - -#if defined( SJCD_TRACE ) - printk("SJCD: release\n"); -#endif - if (--sjcd_open_count == 0) { - sjcd_invalidate_buffers(); - s = sjcd_tray_unlock(); - if (s < 0 || !sjcd_status_valid || sjcd_command_failed) { -#if defined( SJCD_DIAGNOSTIC ) - printk - ("SJCD: release: tray unlock attempt failed.\n"); -#endif - } - if (sjcd_door_was_open) { - s = sjcd_tray_open(); - if (s < 0 || !sjcd_status_valid - || sjcd_command_failed) { -#if defined( SJCD_DIAGNOSTIC ) - printk - ("SJCD: release: tray unload attempt failed.\n"); -#endif - } - } - } - return 0; -} - -/* - * A list of file operations allowed for this cdrom. - */ -static struct block_device_operations sjcd_fops = { - .owner = THIS_MODULE, - .open = sjcd_open, - .release = sjcd_release, - .ioctl = sjcd_ioctl, - .media_changed = sjcd_disk_change, -}; - -/* - * Following stuff is intended for initialization of the cdrom. It - * first looks for presence of device. If the device is present, it - * will be reset. Then read the version of the drive and load status. - * The version is two BCD-coded bytes. - */ -static struct { - unsigned char major, minor; -} sjcd_version; - -static struct gendisk *sjcd_disk; - -/* - * Test for presence of drive and initialize it. Called at boot time. - * Probe cdrom, find out version and status. - */ -static int __init sjcd_init(void) -{ - int i; - - printk(KERN_INFO - "SJCD: Sanyo CDR-H94A cdrom driver version %d.%d.\n", - SJCD_VERSION_MAJOR, SJCD_VERSION_MINOR); - -#if defined( SJCD_TRACE ) - printk("SJCD: sjcd=0x%x: ", sjcd_base); -#endif - - if (register_blkdev(MAJOR_NR, "sjcd")) - return -EIO; - - sjcd_queue = blk_init_queue(do_sjcd_request, &sjcd_lock); - if (!sjcd_queue) - goto out0; - - blk_queue_hardsect_size(sjcd_queue, 2048); - - sjcd_disk = alloc_disk(1); - if (!sjcd_disk) { - printk(KERN_ERR "SJCD: can't allocate disk"); - goto out1; - } - sjcd_disk->major = MAJOR_NR, - sjcd_disk->first_minor = 0, - sjcd_disk->fops = &sjcd_fops, - sprintf(sjcd_disk->disk_name, "sjcd"); - - if (!request_region(sjcd_base, 4,"sjcd")) { - printk - ("SJCD: Init failed, I/O port (%X) is already in use\n", - sjcd_base); - goto out2; - } - - /* - * Check for card. Since we are booting now, we can't use standard - * wait algorithm. - */ - printk(KERN_INFO "SJCD: Resetting: "); - sjcd_send_cmd(SCMD_RESET); - for (i = 1000; i > 0 && !sjcd_status_valid; --i) { - unsigned long timer; - - /* - * Wait 10ms approx. - */ - for (timer = jiffies; time_before_eq(jiffies, timer);); - if ((i % 100) == 0) - printk("."); - (void) sjcd_check_status(); - } - if (i == 0 || sjcd_command_failed) { - printk(" reset failed, no drive found.\n"); - goto out3; - } else - printk("\n"); - - /* - * Get and print out cdrom version. - */ - printk(KERN_INFO "SJCD: Getting version: "); - sjcd_send_cmd(SCMD_GET_VERSION); - for (i = 1000; i > 0 && !sjcd_status_valid; --i) { - unsigned long timer; - - /* - * Wait 10ms approx. - */ - for (timer = jiffies; time_before_eq(jiffies, timer);); - if ((i % 100) == 0) - printk("."); - (void) sjcd_check_status(); - } - if (i == 0 || sjcd_command_failed) { - printk(" get version failed, no drive found.\n"); - goto out3; - } - - if (sjcd_load_response(&sjcd_version, sizeof(sjcd_version)) == 0) { - printk(" %1x.%02x\n", (int) sjcd_version.major, - (int) sjcd_version.minor); - } else { - printk(" read version failed, no drive found.\n"); - goto out3; - } - - /* - * Check and print out the tray state. (if it is needed?). - */ - if (!sjcd_status_valid) { - printk(KERN_INFO "SJCD: Getting status: "); - sjcd_send_cmd(SCMD_GET_STATUS); - for (i = 1000; i > 0 && !sjcd_status_valid; --i) { - unsigned long timer; - - /* - * Wait 10ms approx. - */ - for (timer = jiffies; - time_before_eq(jiffies, timer);); - if ((i % 100) == 0) - printk("."); - (void) sjcd_check_status(); - } - if (i == 0 || sjcd_command_failed) { - printk(" get status failed, no drive found.\n"); - goto out3; - } else - printk("\n"); - } - - printk(KERN_INFO "SJCD: Status: port=0x%x.\n", sjcd_base); - sjcd_disk->queue = sjcd_queue; - add_disk(sjcd_disk); - - sjcd_present++; - return (0); -out3: - release_region(sjcd_base, 4); -out2: - put_disk(sjcd_disk); -out1: - blk_cleanup_queue(sjcd_queue); -out0: - if ((unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL)) - printk("SJCD: cannot unregister device.\n"); - return (-EIO); -} - -static void __exit sjcd_exit(void) -{ - del_gendisk(sjcd_disk); - put_disk(sjcd_disk); - release_region(sjcd_base, 4); - blk_cleanup_queue(sjcd_queue); - if ((unregister_blkdev(MAJOR_NR, "sjcd") == -EINVAL)) - printk("SJCD: cannot unregister device.\n"); - printk(KERN_INFO "SJCD: module: removed.\n"); -} - -module_init(sjcd_init); -module_exit(sjcd_exit); - -MODULE_LICENSE("GPL"); -MODULE_ALIAS_BLOCKDEV_MAJOR(SANYO_CDROM_MAJOR); diff --git a/drivers/cdrom/sjcd.h b/drivers/cdrom/sjcd.h deleted file mode 100644 index 0aa5e714659d..000000000000 --- a/drivers/cdrom/sjcd.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Definitions for a Sanyo CD-ROM interface. - * - * Copyright (C) 1995 Vadim V. Model - * model@cecmow.enet.dec.com - * vadim@rbrf.msk.su - * vadim@ipsun.ras.ru - * Eric van der Maarel - * H.T.M.v.d.Maarel@marin.nl - * - * This information is based on mcd.c from M. Harriss and sjcd102.lst from - * E. Moenkeberg. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __SJCD_H__ -#define __SJCD_H__ - -/* - * Change this to set the I/O port address as default. More flexibility - * come with setup implementation. - */ -#define SJCD_BASE_ADDR 0x340 - -/* - * Change this to set the irq as default. Really SANYO do not use interrupts - * at all. - */ -#define SJCD_INTR_NR 0 - -/* - * Change this to set the dma as default value. really SANYO does not use - * direct memory access at all. - */ -#define SJCD_DMA_NR 0 - -/* - * Macros which allow us to find out the status of the drive. - */ -#define SJCD_STATUS_AVAILABLE( x ) (((x)&0x02)==0) -#define SJCD_DATA_AVAILABLE( x ) (((x)&0x01)==0) - -/* - * Port access macro. Three ports are available: S-data port (command port), - * status port (read only) and D-data port (read only). - */ -#define SJCDPORT( x ) ( sjcd_base + ( x ) ) -#define SJCD_STATUS_PORT SJCDPORT( 1 ) -#define SJCD_S_DATA_PORT SJCDPORT( 0 ) -#define SJCD_COMMAND_PORT SJCDPORT( 0 ) -#define SJCD_D_DATA_PORT SJCDPORT( 2 ) - -/* - * Drive info bits. Drive info available as first (mandatory) byte of - * command completion status. - */ -#define SST_NOT_READY 0x10 /* no disk in the drive (???) */ -#define SST_MEDIA_CHANGED 0x20 /* disk is changed */ -#define SST_DOOR_OPENED 0x40 /* door is open */ - -/* commands */ - -#define SCMD_EJECT_TRAY 0xD0 /* eject tray if not locked */ -#define SCMD_LOCK_TRAY 0xD2 /* lock tray when in */ -#define SCMD_UNLOCK_TRAY 0xD4 /* unlock tray when in */ -#define SCMD_CLOSE_TRAY 0xD6 /* load tray in */ - -#define SCMD_RESET 0xFA /* soft reset */ -#define SCMD_GET_STATUS 0x80 -#define SCMD_GET_VERSION 0xCC - -#define SCMD_DATA_READ 0xA0 /* are the same, depend on mode&args */ -#define SCMD_SEEK 0xA0 -#define SCMD_PLAY 0xA0 - -#define SCMD_GET_QINFO 0xA8 - -#define SCMD_SET_MODE 0xC4 -#define SCMD_MODE_PLAY 0xE0 -#define SCMD_MODE_COOKED (0xF8 & ~0x20) -#define SCMD_MODE_RAW 0xF9 -#define SCMD_MODE_x20_BIT 0x20 /* What is it for ? */ - -#define SCMD_SET_VOLUME 0xAE -#define SCMD_PAUSE 0xE0 -#define SCMD_STOP 0xE0 - -#define SCMD_GET_DISK_INFO 0xAA - -/* - * Some standard arguments for SCMD_GET_DISK_INFO. - */ -#define SCMD_GET_1_TRACK 0xA0 /* get the first track information */ -#define SCMD_GET_L_TRACK 0xA1 /* get the last track information */ -#define SCMD_GET_D_SIZE 0xA2 /* get the whole disk information */ - -/* - * Borrowed from hd.c. Allows to optimize multiple port read commands. - */ -#define S_READ_DATA( port, buf, nr ) insb( port, buf, nr ) - -/* - * We assume that there are no audio disks with TOC length more than this - * number (I personally have never seen disks with more than 20 fragments). - */ -#define SJCD_MAX_TRACKS 100 - -struct msf { - unsigned char min; - unsigned char sec; - unsigned char frame; -}; - -struct sjcd_hw_disk_info { - unsigned char track_control; - unsigned char track_no; - unsigned char x, y, z; - union { - unsigned char track_no; - struct msf track_msf; - } un; -}; - -struct sjcd_hw_qinfo { - unsigned char track_control; - unsigned char track_no; - unsigned char x; - struct msf rel; - struct msf abs; -}; - -struct sjcd_play_msf { - struct msf start; - struct msf end; -}; - -struct sjcd_disk_info { - unsigned char first; - unsigned char last; - struct msf disk_length; - struct msf first_track; -}; - -struct sjcd_toc { - unsigned char ctrl_addr; - unsigned char track; - unsigned char point_index; - struct msf track_time; - struct msf disk_time; -}; - -#if defined( SJCD_GATHER_STAT ) - -struct sjcd_stat { - int ticks; - int tticks[ 8 ]; - int idle_ticks; - int start_ticks; - int mode_ticks; - int read_ticks; - int data_ticks; - int stop_ticks; - int stopping_ticks; -}; - -#endif - -#endif diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c deleted file mode 100644 index f77ada933ea0..000000000000 --- a/drivers/cdrom/sonycd535.c +++ /dev/null @@ -1,1689 +0,0 @@ -/* - * Sony CDU-535 interface device driver - * - * This is a modified version of the CDU-31A device driver (see below). - * Changes were made using documentation for the CDU-531 (which Sony - * assures me is very similar to the 535) and partial disassembly of the - * DOS driver. I used Minyard's driver and replaced the CDU-31A - * commands with the CDU-531 commands. This was complicated by a different - * interface protocol with the drive. The driver is still polled. - * - * Data transfer rate is about 110 Kb/sec, theoretical maximum is 150 Kb/sec. - * I tried polling without the sony_sleep during the data transfers but - * it did not speed things up any. - * - * 1993-05-23 (rgj) changed the major number to 21 to get rid of conflict - * with CDU-31A driver. This is the also the number from the Linux - * Device Driver Registry for the Sony Drive. Hope nobody else is using it. - * - * 1993-08-29 (rgj) remove the configuring of the interface board address - * from the top level configuration, you have to modify it in this file. - * - * 1995-01-26 Made module-capable (Joel Katz ) - * - * 1995-05-20 - * Modified to support CDU-510/515 series - * (Claudio Porfiri) - * Fixed to report verify_area() failures - * (Heiko Eissfeldt ) - * - * 1995-06-01 - * More changes to support CDU-510/515 series - * (Claudio Porfiri) - * - * November 1999 -- Make kernel-parameter implementation work with 2.3.x - * Removed init_module & cleanup_module in favor of - * module_init & module_exit. - * Torben Mathiasen - * - * September 2003 - Fix SMP support by removing cli/sti calls. - * Using spinlocks with a wait_queue instead. - * Felipe Damasio - * - * Things to do: - * - handle errors and status better, put everything into a single word - * - use interrupts (code mostly there, but a big hole still missing) - * - handle multi-session CDs? - * - use DMA? - * - * Known Bugs: - * - - * - * Ken Pizzini (ken@halcyon.com) - * - * Original by: - * Ron Jeppesen (ronj.an@site007.saic.com) - * - * - *------------------------------------------------------------------------ - * Sony CDROM interface device driver. - * - * Corey Minyard (minyard@wf-rch.cirr.com) (CDU-535 complaints to Ken above) - * - * Colossians 3:17 - * - * The Sony interface device driver handles Sony interface CDROM - * drives and provides a complete block-level interface as well as an - * ioctl() interface compatible with the Sun (as specified in - * include/linux/cdrom.h). With this interface, CDROMs can be - * accessed and standard audio CDs can be played back normally. - * - * This interface is (unfortunately) a polled interface. This is - * because most Sony interfaces are set up with DMA and interrupts - * disables. Some (like mine) do not even have the capability to - * handle interrupts or DMA. For this reason you will see a bit of - * the following: - * - * snap = jiffies; - * while (jiffies-snap < SONY_JIFFIES_TIMEOUT) - * { - * if (some_condition()) - * break; - * sony_sleep(); - * } - * if (some_condition not met) - * { - * return an_error; - * } - * - * This ugly hack waits for something to happen, sleeping a little - * between every try. (The conditional is written so that jiffies - * wrap-around is handled properly.) - * - * One thing about these drives: They talk in MSF (Minute Second Frame) format. - * There are 75 frames a second, 60 seconds a minute, and up to 75 minutes on a - * disk. The funny thing is that these are sent to the drive in BCD, but the - * interface wants to see them in decimal. A lot of conversion goes on. - * - * Copyright (C) 1993 Corey Minyard - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - - -# include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define REALLY_SLOW_IO -#include -#include -#include - -#include - -#define MAJOR_NR CDU535_CDROM_MAJOR -#include - -#define sony535_cd_base_io sonycd535 /* for compatible parameter passing with "insmod" */ -#include "sonycd535.h" - -/* - * this is the base address of the interface card for the Sony CDU-535 - * CDROM drive. If your jumpers are set for an address other than - * this one (the default), change the following line to the - * proper address. - */ -#ifndef CDU535_ADDRESS -# define CDU535_ADDRESS 0x340 -#endif -#ifndef CDU535_INTERRUPT -# define CDU535_INTERRUPT 0 -#endif -#ifndef CDU535_HANDLE -# define CDU535_HANDLE "cdu535" -#endif -#ifndef CDU535_MESSAGE_NAME -# define CDU535_MESSAGE_NAME "Sony CDU-535" -#endif - -#define CDU535_BLOCK_SIZE 2048 - -#ifndef MAX_SPINUP_RETRY -# define MAX_SPINUP_RETRY 3 /* 1 is sufficient for most drives... */ -#endif -#ifndef RETRY_FOR_BAD_STATUS -# define RETRY_FOR_BAD_STATUS 100 /* in 10th of second */ -#endif - -#ifndef DEBUG -# define DEBUG 1 -#endif - -/* - * SONY535_BUFFER_SIZE determines the size of internal buffer used - * by the drive. It must be at least 2K and the larger the buffer - * the better the transfer rate. It does however take system memory. - * On my system I get the following transfer rates using dd to read - * 10 Mb off /dev/cdrom. - * - * 8K buffer 43 Kb/sec - * 16K buffer 66 Kb/sec - * 32K buffer 91 Kb/sec - * 64K buffer 111 Kb/sec - * 128K buffer 123 Kb/sec - * 512K buffer 123 Kb/sec - */ -#define SONY535_BUFFER_SIZE (64*1024) - -/* - * if LOCK_DOORS is defined then the eject button is disabled while - * the device is open. - */ -#ifndef NO_LOCK_DOORS -# define LOCK_DOORS -#endif - -static int read_subcode(void); -static void sony_get_toc(void); -static int cdu_open(struct inode *inode, struct file *filp); -static inline unsigned int int_to_bcd(unsigned int val); -static unsigned int bcd_to_int(unsigned int bcd); -static int do_sony_cmd(Byte * cmd, int nCmd, Byte status[2], - Byte * response, int n_response, int ignoreStatusBit7); - -/* The base I/O address of the Sony Interface. This is a variable (not a - #define) so it can be easily changed via some future ioctl() */ -static unsigned int sony535_cd_base_io = CDU535_ADDRESS; -module_param(sony535_cd_base_io, int, 0); - -/* - * The following are I/O addresses of the various registers for the drive. The - * comment for the base address also applies here. - */ -static unsigned short select_unit_reg; -static unsigned short result_reg; -static unsigned short command_reg; -static unsigned short read_status_reg; -static unsigned short data_reg; - -static DEFINE_SPINLOCK(sonycd535_lock); /* queue lock */ -static struct request_queue *sonycd535_queue; - -static int initialized; /* Has the drive been initialized? */ -static int sony_disc_changed = 1; /* Has the disk been changed - since the last check? */ -static int sony_toc_read; /* Has the table of contents been - read? */ -static unsigned int sony_buffer_size; /* Size in bytes of the read-ahead - buffer. */ -static unsigned int sony_buffer_sectors; /* Size (in 2048 byte records) of - the read-ahead buffer. */ -static unsigned int sony_usage; /* How many processes have the - drive open. */ - -static int sony_first_block = -1; /* First OS block (512 byte) in - the read-ahead buffer */ -static int sony_last_block = -1; /* Last OS block (512 byte) in - the read-ahead buffer */ - -static struct s535_sony_toc *sony_toc; /* Points to the table of - contents. */ - -static struct s535_sony_subcode *last_sony_subcode; /* Points to the last - subcode address read */ -static Byte **sony_buffer; /* Points to the pointers - to the sector buffers */ - -static int sony_inuse; /* is the drive in use? Only one - open at a time allowed */ - -/* - * The audio status uses the values from read subchannel data as specified - * in include/linux/cdrom.h. - */ -static int sony_audio_status = CDROM_AUDIO_NO_STATUS; - -/* - * The following are a hack for pausing and resuming audio play. The drive - * does not work as I would expect it, if you stop it then start it again, - * the drive seeks back to the beginning and starts over. This holds the - * position during a pause so a resume can restart it. It uses the - * audio status variable above to tell if it is paused. - * I just kept the CDU-31A driver behavior rather than using the PAUSE - * command on the CDU-535. - */ -static Byte cur_pos_msf[3]; -static Byte final_pos_msf[3]; - -/* What IRQ is the drive using? 0 if none. */ -static int sony535_irq_used = CDU535_INTERRUPT; - -/* The interrupt handler will wake this queue up when it gets an interrupt. */ -static DECLARE_WAIT_QUEUE_HEAD(cdu535_irq_wait); - - -/* - * This routine returns 1 if the disk has been changed since the last - * check or 0 if it hasn't. Setting flag to 0 resets the changed flag. - */ -static int -cdu535_check_media_change(struct gendisk *disk) -{ - /* if driver is not initialized, always return 0 */ - int retval = initialized ? sony_disc_changed : 0; - sony_disc_changed = 0; - return retval; -} - -static inline void -enable_interrupts(void) -{ -#ifdef USE_IRQ - /* - * This code was taken from cdu31a.c; it will not - * directly work for the cdu535 as written... - */ - curr_control_reg |= ( SONY_ATTN_INT_EN_BIT - | SONY_RES_RDY_INT_EN_BIT - | SONY_DATA_RDY_INT_EN_BIT); - outb(curr_control_reg, sony_cd_control_reg); -#endif -} - -static inline void -disable_interrupts(void) -{ -#ifdef USE_IRQ - /* - * This code was taken from cdu31a.c; it will not - * directly work for the cdu535 as written... - */ - curr_control_reg &= ~(SONY_ATTN_INT_EN_BIT - | SONY_RES_RDY_INT_EN_BIT - | SONY_DATA_RDY_INT_EN_BIT); - outb(curr_control_reg, sony_cd_control_reg); -#endif -} - -static irqreturn_t -cdu535_interrupt(int irq, void *dev_id) -{ - disable_interrupts(); - if (waitqueue_active(&cdu535_irq_wait)) { - wake_up(&cdu535_irq_wait); - return IRQ_HANDLED; - } - printk(CDU535_MESSAGE_NAME - ": Got an interrupt but nothing was waiting\n"); - return IRQ_NONE; -} - - -/* - * Wait a little while. - */ -static inline void -sony_sleep(void) -{ - if (sony535_irq_used <= 0) { /* poll */ - yield(); - } else { /* Interrupt driven */ - DEFINE_WAIT(wait); - - spin_lock_irq(&sonycd535_lock); - enable_interrupts(); - prepare_to_wait(&cdu535_irq_wait, &wait, TASK_INTERRUPTIBLE); - spin_unlock_irq(&sonycd535_lock); - schedule(); - finish_wait(&cdu535_irq_wait, &wait); - } -} - -/*------------------start of SONY CDU535 very specific ---------------------*/ - -/**************************************************************************** - * void select_unit( int unit_no ) - * - * Select the specified unit (0-3) so that subsequent commands reference it - ****************************************************************************/ -static void -select_unit(int unit_no) -{ - unsigned int select_mask = ~(1 << unit_no); - outb(select_mask, select_unit_reg); -} - -/*************************************************************************** - * int read_result_reg( Byte *data_ptr ) - * - * Read a result byte from the Sony CDU controller, store in location pointed - * to by data_ptr. Return zero on success, TIME_OUT if we did not receive - * data. - ***************************************************************************/ -static int -read_result_reg(Byte *data_ptr) -{ - unsigned long snap; - int read_status; - - snap = jiffies; - while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { - read_status = inb(read_status_reg); - if ((read_status & SONY535_RESULT_NOT_READY_BIT) == 0) { -#if DEBUG > 1 - printk(CDU535_MESSAGE_NAME - ": read_result_reg(): readStatReg = 0x%x\n", read_status); -#endif - *data_ptr = inb(result_reg); - return 0; - } else { - sony_sleep(); - } - } - printk(CDU535_MESSAGE_NAME " read_result_reg: TIME OUT!\n"); - return TIME_OUT; -} - -/**************************************************************************** - * int read_exec_status( Byte status[2] ) - * - * Read the execution status of the last command and put into status. - * Handles reading second status word if available. Returns 0 on success, - * TIME_OUT on failure. - ****************************************************************************/ -static int -read_exec_status(Byte status[2]) -{ - status[1] = 0; - if (read_result_reg(&(status[0])) != 0) - return TIME_OUT; - if ((status[0] & 0x80) != 0) { /* byte two follows */ - if (read_result_reg(&(status[1])) != 0) - return TIME_OUT; - } -#if DEBUG > 1 - printk(CDU535_MESSAGE_NAME ": read_exec_status: read 0x%x 0x%x\n", - status[0], status[1]); -#endif - return 0; -} - -/**************************************************************************** - * int check_drive_status( void ) - * - * Check the current drive status. Using this before executing a command - * takes care of the problem of unsolicited drive status-2 messages. - * Add a check of the audio status if we think the disk is playing. - ****************************************************************************/ -static int -check_drive_status(void) -{ - Byte status, e_status[2]; - int CDD, ATN; - Byte cmd; - - select_unit(0); - if (sony_audio_status == CDROM_AUDIO_PLAY) { /* check status */ - outb(SONY535_REQUEST_AUDIO_STATUS, command_reg); - if (read_result_reg(&status) == 0) { - switch (status) { - case 0x0: - break; /* play in progress */ - case 0x1: - break; /* paused */ - case 0x3: /* audio play completed */ - case 0x5: /* play not requested */ - sony_audio_status = CDROM_AUDIO_COMPLETED; - read_subcode(); - break; - case 0x4: /* error during play */ - sony_audio_status = CDROM_AUDIO_ERROR; - break; - } - } - } - /* now check drive status */ - outb(SONY535_REQUEST_DRIVE_STATUS_2, command_reg); - if (read_result_reg(&status) != 0) - return TIME_OUT; - -#if DEBUG > 1 - printk(CDU535_MESSAGE_NAME ": check_drive_status() got 0x%x\n", status); -#endif - - if (status == 0) - return 0; - - ATN = status & 0xf; - CDD = (status >> 4) & 0xf; - - switch (ATN) { - case 0x0: - break; /* go on to CDD stuff */ - case SONY535_ATN_BUSY: - if (initialized) - printk(CDU535_MESSAGE_NAME " error: drive busy\n"); - return CD_BUSY; - case SONY535_ATN_EJECT_IN_PROGRESS: - printk(CDU535_MESSAGE_NAME " error: eject in progress\n"); - sony_audio_status = CDROM_AUDIO_INVALID; - return CD_BUSY; - case SONY535_ATN_RESET_OCCURRED: - case SONY535_ATN_DISC_CHANGED: - case SONY535_ATN_RESET_AND_DISC_CHANGED: -#if DEBUG > 0 - printk(CDU535_MESSAGE_NAME " notice: reset occurred or disc changed\n"); -#endif - sony_disc_changed = 1; - sony_toc_read = 0; - sony_audio_status = CDROM_AUDIO_NO_STATUS; - sony_first_block = -1; - sony_last_block = -1; - if (initialized) { - cmd = SONY535_SPIN_UP; - do_sony_cmd(&cmd, 1, e_status, NULL, 0, 0); - sony_get_toc(); - } - return 0; - default: - printk(CDU535_MESSAGE_NAME " error: drive busy (ATN=0x%x)\n", ATN); - return CD_BUSY; - } - switch (CDD) { /* the 531 docs are not helpful in decoding this */ - case 0x0: /* just use the values from the DOS driver */ - case 0x2: - case 0xa: - break; /* no error */ - case 0xc: - printk(CDU535_MESSAGE_NAME - ": check_drive_status(): CDD = 0xc! Not properly handled!\n"); - return CD_BUSY; /* ? */ - default: - return CD_BUSY; - } - return 0; -} /* check_drive_status() */ - -/***************************************************************************** - * int do_sony_cmd( Byte *cmd, int n_cmd, Byte status[2], - * Byte *response, int n_response, int ignore_status_bit7 ) - * - * Generic routine for executing commands. The command and its parameters - * should be placed in the cmd[] array, number of bytes in the command is - * stored in nCmd. The response from the command will be stored in the - * response array. The number of bytes you expect back (excluding status) - * should be passed in n_response. Finally, some - * commands set bit 7 of the return status even when there is no second - * status byte, on these commands set ignoreStatusBit7 TRUE. - * If the command was sent and data received back, then we return 0, - * else we return TIME_OUT. You still have to check the status yourself. - * You should call check_drive_status() before calling this routine - * so that you do not lose notifications of disk changes, etc. - ****************************************************************************/ -static int -do_sony_cmd(Byte * cmd, int n_cmd, Byte status[2], - Byte * response, int n_response, int ignore_status_bit7) -{ - int i; - - /* write out the command */ - for (i = 0; i < n_cmd; i++) - outb(cmd[i], command_reg); - - /* read back the status */ - if (read_result_reg(status) != 0) - return TIME_OUT; - if (!ignore_status_bit7 && ((status[0] & 0x80) != 0)) { - /* get second status byte */ - if (read_result_reg(status + 1) != 0) - return TIME_OUT; - } else { - status[1] = 0; - } -#if DEBUG > 2 - printk(CDU535_MESSAGE_NAME ": do_sony_cmd %x: %x %x\n", - *cmd, status[0], status[1]); -#endif - - /* do not know about when I should read set of data and when not to */ - if ((status[0] & ((ignore_status_bit7 ? 0x7f : 0xff) & 0x8f)) != 0) - return 0; - - /* else, read in rest of data */ - for (i = 0; 0 < n_response; n_response--, i++) - if (read_result_reg(response + i) != 0) - return TIME_OUT; - return 0; -} /* do_sony_cmd() */ - -/************************************************************************** - * int set_drive_mode( int mode, Byte status[2] ) - * - * Set the drive mode to the specified value (mode=0 is audio, mode=e0 - * is mode-1 CDROM - **************************************************************************/ -static int -set_drive_mode(int mode, Byte status[2]) -{ - Byte cmd_buff[2]; - Byte ret_buff[1]; - - cmd_buff[0] = SONY535_SET_DRIVE_MODE; - cmd_buff[1] = mode; - return do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1); -} - -/*************************************************************************** - * int seek_and_read_N_blocks( Byte params[], int n_blocks, Byte status[2], - * Byte *data_buff, int buff_size ) - * - * Read n_blocks of data from the CDROM starting at position params[0:2], - * number of blocks in stored in params[3:5] -- both these are already - * int bcd format. - * Transfer the data into the buffer pointed at by data_buff. buff_size - * gives the number of bytes available in the buffer. - * The routine returns number of bytes read in if successful, otherwise - * it returns one of the standard error returns. - ***************************************************************************/ -static int -seek_and_read_N_blocks(Byte params[], int n_blocks, Byte status[2], - Byte **buff, int buf_size) -{ - Byte cmd_buff[7]; - int i; - int read_status; - unsigned long snap; - Byte *data_buff; - int sector_count = 0; - - if (buf_size < CDU535_BLOCK_SIZE * n_blocks) - return NO_ROOM; - - set_drive_mode(SONY535_CDROM_DRIVE_MODE, status); - - /* send command to read the data */ - cmd_buff[0] = SONY535_SEEK_AND_READ_N_BLOCKS_1; - for (i = 0; i < 6; i++) - cmd_buff[i + 1] = params[i]; - for (i = 0; i < 7; i++) - outb(cmd_buff[i], command_reg); - - /* read back the data one block at a time */ - while (0 < n_blocks--) { - /* wait for data to be ready */ - int data_valid = 0; - snap = jiffies; - while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { - read_status = inb(read_status_reg); - if ((read_status & SONY535_RESULT_NOT_READY_BIT) == 0) { - read_exec_status(status); - return BAD_STATUS; - } - if ((read_status & SONY535_DATA_NOT_READY_BIT) == 0) { - /* data is ready, read it */ - data_buff = buff[sector_count++]; - for (i = 0; i < CDU535_BLOCK_SIZE; i++) - *data_buff++ = inb(data_reg); /* unrolling this loop does not seem to help */ - data_valid = 1; - break; /* exit the timeout loop */ - } - sony_sleep(); /* data not ready, sleep a while */ - } - if (!data_valid) - return TIME_OUT; /* if we reach this stage */ - } - - /* read all the data, now read the status */ - if ((i = read_exec_status(status)) != 0) - return i; - return CDU535_BLOCK_SIZE * sector_count; -} /* seek_and_read_N_blocks() */ - -/**************************************************************************** - * int request_toc_data( Byte status[2], struct s535_sony_toc *toc ) - * - * Read in the table of contents data. Converts all the bcd data - * into integers in the toc structure. - ****************************************************************************/ -static int -request_toc_data(Byte status[2], struct s535_sony_toc *toc) -{ - int to_status; - int i, j, n_tracks, track_no; - int first_track_num, last_track_num; - Byte cmd_no = 0xb2; - Byte track_address_buffer[5]; - - /* read the fixed portion of the table of contents */ - if ((to_status = do_sony_cmd(&cmd_no, 1, status, (Byte *) toc, 15, 1)) != 0) - return to_status; - - /* convert the data into integers so we can use them */ - first_track_num = bcd_to_int(toc->first_track_num); - last_track_num = bcd_to_int(toc->last_track_num); - n_tracks = last_track_num - first_track_num + 1; - - /* read each of the track address descriptors */ - for (i = 0; i < n_tracks; i++) { - /* read the descriptor into a temporary buffer */ - for (j = 0; j < 5; j++) { - if (read_result_reg(track_address_buffer + j) != 0) - return TIME_OUT; - if (j == 1) /* need to convert from bcd */ - track_no = bcd_to_int(track_address_buffer[j]); - } - /* copy the descriptor to proper location - sonycd.c just fills */ - memcpy(toc->tracks + i, track_address_buffer, 5); - } - return 0; -} /* request_toc_data() */ - -/*************************************************************************** - * int spin_up_drive( Byte status[2] ) - * - * Spin up the drive (unless it is already spinning). - ***************************************************************************/ -static int -spin_up_drive(Byte status[2]) -{ - Byte cmd; - - /* first see if the drive is already spinning */ - cmd = SONY535_REQUEST_DRIVE_STATUS_1; - if (do_sony_cmd(&cmd, 1, status, NULL, 0, 0) != 0) - return TIME_OUT; - if ((status[0] & SONY535_STATUS1_NOT_SPINNING) == 0) - return 0; /* it's already spinning */ - - /* otherwise, give the spin-up command */ - cmd = SONY535_SPIN_UP; - return do_sony_cmd(&cmd, 1, status, NULL, 0, 0); -} - -/*--------------------end of SONY CDU535 very specific ---------------------*/ - -/* Convert from an integer 0-99 to BCD */ -static inline unsigned int -int_to_bcd(unsigned int val) -{ - int retval; - - retval = (val / 10) << 4; - retval = retval | val % 10; - return retval; -} - - -/* Convert from BCD to an integer from 0-99 */ -static unsigned int -bcd_to_int(unsigned int bcd) -{ - return (((bcd >> 4) & 0x0f) * 10) + (bcd & 0x0f); -} - - -/* - * Convert a logical sector value (like the OS would want to use for - * a block device) to an MSF format. - */ -static void -log_to_msf(unsigned int log, Byte *msf) -{ - log = log + LOG_START_OFFSET; - msf[0] = int_to_bcd(log / 4500); - log = log % 4500; - msf[1] = int_to_bcd(log / 75); - msf[2] = int_to_bcd(log % 75); -} - - -/* - * Convert an MSF format to a logical sector. - */ -static unsigned int -msf_to_log(Byte *msf) -{ - unsigned int log; - - - log = bcd_to_int(msf[2]); - log += bcd_to_int(msf[1]) * 75; - log += bcd_to_int(msf[0]) * 4500; - log = log - LOG_START_OFFSET; - - return log; -} - - -/* - * Take in integer size value and put it into a buffer like - * the drive would want to see a number-of-sector value. - */ -static void -size_to_buf(unsigned int size, Byte *buf) -{ - buf[0] = size / 65536; - size = size % 65536; - buf[1] = size / 256; - buf[2] = size % 256; -} - - -/* - * The OS calls this to perform a read or write operation to the drive. - * Write obviously fail. Reads to a read ahead of sony_buffer_size - * bytes to help speed operations. This especially helps since the OS - * may use 1024 byte blocks and the drive uses 2048 byte blocks. Since most - * data access on a CD is done sequentially, this saves a lot of operations. - */ -static void -do_cdu535_request(request_queue_t * q) -{ - struct request *req; - unsigned int read_size; - int block; - int nsect; - int copyoff; - int spin_up_retry; - Byte params[10]; - Byte status[2]; - Byte cmd[2]; - - while (1) { - req = elv_next_request(q); - if (!req) - return; - - block = req->sector; - nsect = req->nr_sectors; - if (!blk_fs_request(req)) { - end_request(req, 0); - continue; - } - if (rq_data_dir(req) == WRITE) { - end_request(req, 0); - continue; - } - /* - * If the block address is invalid or the request goes beyond - * the end of the media, return an error. - */ - if (sony_toc->lead_out_start_lba <= (block/4)) { - end_request(req, 0); - return; - } - if (sony_toc->lead_out_start_lba <= ((block + nsect) / 4)) { - end_request(req, 0); - return; - } - while (0 < nsect) { - /* - * If the requested sector is not currently in - * the read-ahead buffer, it must be read in. - */ - if ((block < sony_first_block) || (sony_last_block < block)) { - sony_first_block = (block / 4) * 4; - log_to_msf(block / 4, params); - - /* - * If the full read-ahead would go beyond the end of the media, trim - * it back to read just till the end of the media. - */ - if (sony_toc->lead_out_start_lba <= ((block / 4) + sony_buffer_sectors)) { - sony_last_block = (sony_toc->lead_out_start_lba * 4) - 1; - read_size = sony_toc->lead_out_start_lba - (block / 4); - } else { - sony_last_block = sony_first_block + (sony_buffer_sectors * 4) - 1; - read_size = sony_buffer_sectors; - } - size_to_buf(read_size, ¶ms[3]); - - /* - * Read the data. If the drive was not spinning, - * spin it up and try some more. - */ - for (spin_up_retry=0 ;; ++spin_up_retry) { - /* This loop has been modified to support the Sony - * CDU-510/515 series, thanks to Claudio Porfiri - * . - */ - /* - * This part is to deal with very slow hardware. We - * try at most MAX_SPINUP_RETRY times to read the same - * block. A check for seek_and_read_N_blocks' result is - * performed; if the result is wrong, the CDROM's engine - * is restarted and the operation is tried again. - */ - /* - * 1995-06-01: The system got problems when downloading - * from Slackware CDROM, the problem seems to be: - * seek_and_read_N_blocks returns BAD_STATUS and we - * should wait for a while before retrying, so a new - * part was added to discriminate the return value from - * seek_and_read_N_blocks for the various cases. - */ - int readStatus = seek_and_read_N_blocks(params, read_size, - status, sony_buffer, (read_size * CDU535_BLOCK_SIZE)); - if (0 <= readStatus) /* Good data; common case, placed first */ - break; - if (readStatus == NO_ROOM || spin_up_retry == MAX_SPINUP_RETRY) { - /* give up */ - if (readStatus == NO_ROOM) - printk(CDU535_MESSAGE_NAME " No room to read from CD\n"); - else - printk(CDU535_MESSAGE_NAME " Read error: 0x%.2x\n", - status[0]); - sony_first_block = -1; - sony_last_block = -1; - end_request(req, 0); - return; - } - if (readStatus == BAD_STATUS) { - /* Sleep for a while, then retry */ - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&sonycd535_lock); - schedule_timeout(RETRY_FOR_BAD_STATUS*HZ/10); - spin_lock_irq(&sonycd535_lock); - } -#if DEBUG > 0 - printk(CDU535_MESSAGE_NAME - " debug: calling spin up when reading data!\n"); -#endif - cmd[0] = SONY535_SPIN_UP; - do_sony_cmd(cmd, 1, status, NULL, 0, 0); - } - } - /* - * The data is in memory now, copy it to the buffer and advance to the - * next block to read. - */ - copyoff = block - sony_first_block; - memcpy(req->buffer, - sony_buffer[copyoff / 4] + 512 * (copyoff % 4), 512); - - block += 1; - nsect -= 1; - req->buffer += 512; - } - - end_request(req, 1); - } -} - -/* - * Read the table of contents from the drive and set sony_toc_read if - * successful. - */ -static void -sony_get_toc(void) -{ - Byte status[2]; - if (!sony_toc_read) { - /* do not call check_drive_status() from here since it can call this routine */ - if (request_toc_data(status, sony_toc) < 0) - return; - sony_toc->lead_out_start_lba = msf_to_log(sony_toc->lead_out_start_msf); - sony_toc_read = 1; - } -} - - -/* - * Search for a specific track in the table of contents. track is - * passed in bcd format - */ -static int -find_track(int track) -{ - int i; - int num_tracks; - - - num_tracks = bcd_to_int(sony_toc->last_track_num) - - bcd_to_int(sony_toc->first_track_num) + 1; - for (i = 0; i < num_tracks; i++) { - if (sony_toc->tracks[i].track == track) { - return i; - } - } - - return -1; -} - -/* - * Read the subcode and put it int last_sony_subcode for future use. - */ -static int -read_subcode(void) -{ - Byte cmd = SONY535_REQUEST_SUB_Q_DATA; - Byte status[2]; - int dsc_status; - - if (check_drive_status() != 0) - return -EIO; - - if ((dsc_status = do_sony_cmd(&cmd, 1, status, (Byte *) last_sony_subcode, - sizeof(struct s535_sony_subcode), 1)) != 0) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x, %d (read_subcode)\n", - status[0], dsc_status); - return -EIO; - } - return 0; -} - - -/* - * Get the subchannel info like the CDROMSUBCHNL command wants to see it. If - * the drive is playing, the subchannel needs to be read (since it would be - * changing). If the drive is paused or completed, the subcode information has - * already been stored, just use that. The ioctl call wants things in decimal - * (not BCD), so all the conversions are done. - */ -static int -sony_get_subchnl_info(void __user *arg) -{ - struct cdrom_subchnl schi; - - /* Get attention stuff */ - if (check_drive_status() != 0) - return -EIO; - - sony_get_toc(); - if (!sony_toc_read) { - return -EIO; - } - if (copy_from_user(&schi, arg, sizeof schi)) - return -EFAULT; - - switch (sony_audio_status) { - case CDROM_AUDIO_PLAY: - if (read_subcode() < 0) { - return -EIO; - } - break; - - case CDROM_AUDIO_PAUSED: - case CDROM_AUDIO_COMPLETED: - break; - - case CDROM_AUDIO_NO_STATUS: - schi.cdsc_audiostatus = sony_audio_status; - if (copy_to_user(arg, &schi, sizeof schi)) - return -EFAULT; - return 0; - break; - - case CDROM_AUDIO_INVALID: - case CDROM_AUDIO_ERROR: - default: - return -EIO; - } - - schi.cdsc_audiostatus = sony_audio_status; - schi.cdsc_adr = last_sony_subcode->address; - schi.cdsc_ctrl = last_sony_subcode->control; - schi.cdsc_trk = bcd_to_int(last_sony_subcode->track_num); - schi.cdsc_ind = bcd_to_int(last_sony_subcode->index_num); - if (schi.cdsc_format == CDROM_MSF) { - schi.cdsc_absaddr.msf.minute = bcd_to_int(last_sony_subcode->abs_msf[0]); - schi.cdsc_absaddr.msf.second = bcd_to_int(last_sony_subcode->abs_msf[1]); - schi.cdsc_absaddr.msf.frame = bcd_to_int(last_sony_subcode->abs_msf[2]); - - schi.cdsc_reladdr.msf.minute = bcd_to_int(last_sony_subcode->rel_msf[0]); - schi.cdsc_reladdr.msf.second = bcd_to_int(last_sony_subcode->rel_msf[1]); - schi.cdsc_reladdr.msf.frame = bcd_to_int(last_sony_subcode->rel_msf[2]); - } else if (schi.cdsc_format == CDROM_LBA) { - schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode->abs_msf); - schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode->rel_msf); - } - return copy_to_user(arg, &schi, sizeof schi) ? -EFAULT : 0; -} - - -/* - * The big ugly ioctl handler. - */ -static int -cdu_ioctl(struct inode *inode, - struct file *file, - unsigned int cmd, - unsigned long arg) -{ - Byte status[2]; - Byte cmd_buff[10], params[10]; - int i; - int dsc_status; - void __user *argp = (void __user *)arg; - - if (check_drive_status() != 0) - return -EIO; - - switch (cmd) { - case CDROMSTART: /* Spin up the drive */ - if (spin_up_drive(status) < 0) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTART)\n", - status[0]); - return -EIO; - } - return 0; - break; - - case CDROMSTOP: /* Spin down the drive */ - cmd_buff[0] = SONY535_HOLD; - do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); - - /* - * Spin the drive down, ignoring the error if the disk was - * already not spinning. - */ - sony_audio_status = CDROM_AUDIO_NO_STATUS; - cmd_buff[0] = SONY535_SPIN_DOWN; - dsc_status = do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); - if (((dsc_status < 0) && (dsc_status != BAD_STATUS)) || - ((status[0] & ~(SONY535_STATUS1_NOT_SPINNING)) != 0)) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMSTOP)\n", - status[0]); - return -EIO; - } - return 0; - break; - - case CDROMPAUSE: /* Pause the drive */ - cmd_buff[0] = SONY535_HOLD; /* CDU-31 driver uses AUDIO_STOP, not pause */ - if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPAUSE)\n", - status[0]); - return -EIO; - } - /* Get the current position and save it for resuming */ - if (read_subcode() < 0) { - return -EIO; - } - cur_pos_msf[0] = last_sony_subcode->abs_msf[0]; - cur_pos_msf[1] = last_sony_subcode->abs_msf[1]; - cur_pos_msf[2] = last_sony_subcode->abs_msf[2]; - sony_audio_status = CDROM_AUDIO_PAUSED; - return 0; - break; - - case CDROMRESUME: /* Start the drive after being paused */ - set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status); - - if (sony_audio_status != CDROM_AUDIO_PAUSED) { - return -EINVAL; - } - spin_up_drive(status); - - /* Start the drive at the saved position. */ - cmd_buff[0] = SONY535_PLAY_AUDIO; - cmd_buff[1] = 0; /* play back starting at this address */ - cmd_buff[2] = cur_pos_msf[0]; - cmd_buff[3] = cur_pos_msf[1]; - cmd_buff[4] = cur_pos_msf[2]; - cmd_buff[5] = SONY535_PLAY_AUDIO; - cmd_buff[6] = 2; /* set ending address */ - cmd_buff[7] = final_pos_msf[0]; - cmd_buff[8] = final_pos_msf[1]; - cmd_buff[9] = final_pos_msf[2]; - if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) || - (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMRESUME)\n", - status[0]); - return -EIO; - } - sony_audio_status = CDROM_AUDIO_PLAY; - return 0; - break; - - case CDROMPLAYMSF: /* Play starting at the given MSF address. */ - if (copy_from_user(params, argp, 6)) - return -EFAULT; - spin_up_drive(status); - set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status); - - /* The parameters are given in int, must be converted */ - for (i = 0; i < 3; i++) { - cmd_buff[2 + i] = int_to_bcd(params[i]); - cmd_buff[7 + i] = int_to_bcd(params[i + 3]); - } - cmd_buff[0] = SONY535_PLAY_AUDIO; - cmd_buff[1] = 0; /* play back starting at this address */ - /* cmd_buff[2-4] are filled in for loop above */ - cmd_buff[5] = SONY535_PLAY_AUDIO; - cmd_buff[6] = 2; /* set ending address */ - /* cmd_buff[7-9] are filled in for loop above */ - if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) || - (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPLAYMSF)\n", - status[0]); - return -EIO; - } - /* Save the final position for pauses and resumes */ - final_pos_msf[0] = cmd_buff[7]; - final_pos_msf[1] = cmd_buff[8]; - final_pos_msf[2] = cmd_buff[9]; - sony_audio_status = CDROM_AUDIO_PLAY; - return 0; - break; - - case CDROMREADTOCHDR: /* Read the table of contents header */ - { - struct cdrom_tochdr __user *hdr = argp; - struct cdrom_tochdr loc_hdr; - - sony_get_toc(); - if (!sony_toc_read) - return -EIO; - loc_hdr.cdth_trk0 = bcd_to_int(sony_toc->first_track_num); - loc_hdr.cdth_trk1 = bcd_to_int(sony_toc->last_track_num); - if (copy_to_user(hdr, &loc_hdr, sizeof *hdr)) - return -EFAULT; - } - return 0; - break; - - case CDROMREADTOCENTRY: /* Read a given table of contents entry */ - { - struct cdrom_tocentry __user *entry = argp; - struct cdrom_tocentry loc_entry; - int track_idx; - Byte *msf_val = NULL; - - sony_get_toc(); - if (!sony_toc_read) { - return -EIO; - } - - if (copy_from_user(&loc_entry, entry, sizeof loc_entry)) - return -EFAULT; - - /* Lead out is handled separately since it is special. */ - if (loc_entry.cdte_track == CDROM_LEADOUT) { - loc_entry.cdte_adr = 0 /*sony_toc->address2 */ ; - loc_entry.cdte_ctrl = sony_toc->control2; - msf_val = sony_toc->lead_out_start_msf; - } else { - track_idx = find_track(int_to_bcd(loc_entry.cdte_track)); - if (track_idx < 0) - return -EINVAL; - loc_entry.cdte_adr = 0 /*sony_toc->tracks[track_idx].address */ ; - loc_entry.cdte_ctrl = sony_toc->tracks[track_idx].control; - msf_val = sony_toc->tracks[track_idx].track_start_msf; - } - - /* Logical buffer address or MSF format requested? */ - if (loc_entry.cdte_format == CDROM_LBA) { - loc_entry.cdte_addr.lba = msf_to_log(msf_val); - } else if (loc_entry.cdte_format == CDROM_MSF) { - loc_entry.cdte_addr.msf.minute = bcd_to_int(*msf_val); - loc_entry.cdte_addr.msf.second = bcd_to_int(*(msf_val + 1)); - loc_entry.cdte_addr.msf.frame = bcd_to_int(*(msf_val + 2)); - } - if (copy_to_user(entry, &loc_entry, sizeof *entry)) - return -EFAULT; - } - return 0; - break; - - case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ - { - struct cdrom_ti ti; - int track_idx; - - sony_get_toc(); - if (!sony_toc_read) - return -EIO; - - if (copy_from_user(&ti, argp, sizeof ti)) - return -EFAULT; - if ((ti.cdti_trk0 < sony_toc->first_track_num) - || (sony_toc->last_track_num < ti.cdti_trk0) - || (ti.cdti_trk1 < ti.cdti_trk0)) { - return -EINVAL; - } - track_idx = find_track(int_to_bcd(ti.cdti_trk0)); - if (track_idx < 0) - return -EINVAL; - params[1] = sony_toc->tracks[track_idx].track_start_msf[0]; - params[2] = sony_toc->tracks[track_idx].track_start_msf[1]; - params[3] = sony_toc->tracks[track_idx].track_start_msf[2]; - /* - * If we want to stop after the last track, use the lead-out - * MSF to do that. - */ - if (bcd_to_int(sony_toc->last_track_num) <= ti.cdti_trk1) { - log_to_msf(msf_to_log(sony_toc->lead_out_start_msf) - 1, - &(params[4])); - } else { - track_idx = find_track(int_to_bcd(ti.cdti_trk1 + 1)); - if (track_idx < 0) - return -EINVAL; - log_to_msf(msf_to_log(sony_toc->tracks[track_idx].track_start_msf) - 1, - &(params[4])); - } - params[0] = 0x03; - - spin_up_drive(status); - - set_drive_mode(SONY535_AUDIO_DRIVE_MODE, status); - - /* Start the drive at the saved position. */ - cmd_buff[0] = SONY535_PLAY_AUDIO; - cmd_buff[1] = 0; /* play back starting at this address */ - cmd_buff[2] = params[1]; - cmd_buff[3] = params[2]; - cmd_buff[4] = params[3]; - cmd_buff[5] = SONY535_PLAY_AUDIO; - cmd_buff[6] = 2; /* set ending address */ - cmd_buff[7] = params[4]; - cmd_buff[8] = params[5]; - cmd_buff[9] = params[6]; - if ((do_sony_cmd(cmd_buff, 5, status, NULL, 0, 0) != 0) || - (do_sony_cmd(cmd_buff + 5, 5, status, NULL, 0, 0) != 0)) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMPLAYTRKIND)\n", - status[0]); - printk("... Params: %x %x %x %x %x %x %x\n", - params[0], params[1], params[2], - params[3], params[4], params[5], params[6]); - return -EIO; - } - /* Save the final position for pauses and resumes */ - final_pos_msf[0] = params[4]; - final_pos_msf[1] = params[5]; - final_pos_msf[2] = params[6]; - sony_audio_status = CDROM_AUDIO_PLAY; - return 0; - } - - case CDROMSUBCHNL: /* Get subchannel info */ - return sony_get_subchnl_info(argp); - - case CDROMVOLCTRL: /* Volume control. What volume does this change, anyway? */ - { - struct cdrom_volctrl volctrl; - - if (copy_from_user(&volctrl, argp, sizeof volctrl)) - return -EFAULT; - cmd_buff[0] = SONY535_SET_VOLUME; - cmd_buff[1] = volctrl.channel0; - cmd_buff[2] = volctrl.channel1; - if (do_sony_cmd(cmd_buff, 3, status, NULL, 0, 0) != 0) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMVOLCTRL)\n", - status[0]); - return -EIO; - } - } - return 0; - - case CDROMEJECT: /* Eject the drive */ - cmd_buff[0] = SONY535_STOP; - do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); - cmd_buff[0] = SONY535_SPIN_DOWN; - do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); - - sony_audio_status = CDROM_AUDIO_INVALID; - cmd_buff[0] = SONY535_EJECT_CADDY; - if (do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0) != 0) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (CDROMEJECT)\n", - status[0]); - return -EIO; - } - return 0; - break; - - default: - return -EINVAL; - } -} - - -/* - * Open the drive for operations. Spin the drive up and read the table of - * contents if these have not already been done. - */ -static int -cdu_open(struct inode *inode, - struct file *filp) -{ - Byte status[2], cmd_buff[2]; - - if (sony_inuse) - return -EBUSY; - if (check_drive_status() != 0) - return -EIO; - sony_inuse = 1; - - if (spin_up_drive(status) != 0) { - printk(CDU535_MESSAGE_NAME " error 0x%.2x (cdu_open, spin up)\n", - status[0]); - sony_inuse = 0; - return -EIO; - } - sony_get_toc(); - if (!sony_toc_read) { - cmd_buff[0] = SONY535_SPIN_DOWN; - do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); - sony_inuse = 0; - return -EIO; - } - check_disk_change(inode->i_bdev); - sony_usage++; - -#ifdef LOCK_DOORS - /* disable the eject button while mounted */ - cmd_buff[0] = SONY535_DISABLE_EJECT_BUTTON; - do_sony_cmd(cmd_buff, 1, status, NULL, 0, 0); -#endif - - return 0; -} - - -/* - * Close the drive. Spin it down if no task is using it. The spin - * down will fail if playing audio, so audio play is OK. - */ -static int -cdu_release(struct inode *inode, - struct file *filp) -{ - Byte status[2], cmd_no; - - sony_inuse = 0; - - if (0 < sony_usage) { - sony_usage--; - } - if (sony_usage == 0) { - check_drive_status(); - - if (sony_audio_status != CDROM_AUDIO_PLAY) { - cmd_no = SONY535_SPIN_DOWN; - do_sony_cmd(&cmd_no, 1, status, NULL, 0, 0); - } -#ifdef LOCK_DOORS - /* enable the eject button after umount */ - cmd_no = SONY535_ENABLE_EJECT_BUTTON; - do_sony_cmd(&cmd_no, 1, status, NULL, 0, 0); -#endif - } - return 0; -} - -static struct block_device_operations cdu_fops = -{ - .owner = THIS_MODULE, - .open = cdu_open, - .release = cdu_release, - .ioctl = cdu_ioctl, - .media_changed = cdu535_check_media_change, -}; - -static struct gendisk *cdu_disk; - -/* - * Initialize the driver. - */ -static int __init sony535_init(void) -{ - struct s535_sony_drive_config drive_config; - Byte cmd_buff[3]; - Byte ret_buff[2]; - Byte status[2]; - unsigned long snap; - int got_result = 0; - int tmp_irq; - int i; - int err; - - /* Setting the base I/O address to 0 will disable it. */ - if ((sony535_cd_base_io == 0xffff)||(sony535_cd_base_io == 0)) - return 0; - - /* Set up all the register locations */ - result_reg = sony535_cd_base_io; - command_reg = sony535_cd_base_io; - data_reg = sony535_cd_base_io + 1; - read_status_reg = sony535_cd_base_io + 2; - select_unit_reg = sony535_cd_base_io + 3; - -#ifndef USE_IRQ - sony535_irq_used = 0; /* polling only until this is ready... */ -#endif - /* we need to poll until things get initialized */ - tmp_irq = sony535_irq_used; - sony535_irq_used = 0; - -#if DEBUG > 0 - printk(KERN_INFO CDU535_MESSAGE_NAME ": probing base address %03X\n", - sony535_cd_base_io); -#endif - /* look for the CD-ROM, follows the procedure in the DOS driver */ - inb(select_unit_reg); - /* wait for 40 18 Hz ticks (reverse-engineered from DOS driver) */ - schedule_timeout_interruptible((HZ+17)*40/18); - inb(result_reg); - - outb(0, read_status_reg); /* does a reset? */ - snap = jiffies; - while (jiffies-snap < SONY_JIFFIES_TIMEOUT) { - select_unit(0); - if (inb(result_reg) != 0xff) { - got_result = 1; - break; - } - sony_sleep(); - } - - if (!got_result || check_drive_status() == TIME_OUT) - goto Enodev; - - /* CD-ROM drive responded -- get the drive configuration */ - cmd_buff[0] = SONY535_INQUIRY; - if (do_sony_cmd(cmd_buff, 1, status, (Byte *)&drive_config, 28, 1) != 0) - goto Enodev; - - /* was able to get the configuration, - * set drive mode as rest of init - */ -#if DEBUG > 0 - /* 0x50 == CADDY_NOT_INSERTED | NOT_SPINNING */ - if ( (status[0] & 0x7f) != 0 && (status[0] & 0x7f) != 0x50 ) - printk(CDU535_MESSAGE_NAME - "Inquiry command returned status = 0x%x\n", status[0]); -#endif - /* now ready to use interrupts, if available */ - sony535_irq_used = tmp_irq; - - /* A negative sony535_irq_used will attempt an autoirq. */ - if (sony535_irq_used < 0) { - unsigned long irq_mask, delay; - - irq_mask = probe_irq_on(); - enable_interrupts(); - outb(0, read_status_reg); /* does a reset? */ - delay = jiffies + HZ/10; - while (time_before(jiffies, delay)) ; - - sony535_irq_used = probe_irq_off(irq_mask); - disable_interrupts(); - } - if (sony535_irq_used > 0) { - if (request_irq(sony535_irq_used, cdu535_interrupt, - IRQF_DISABLED, CDU535_HANDLE, NULL)) { - printk("Unable to grab IRQ%d for the " CDU535_MESSAGE_NAME - " driver; polling instead.\n", sony535_irq_used); - sony535_irq_used = 0; - } - } - cmd_buff[0] = SONY535_SET_DRIVE_MODE; - cmd_buff[1] = 0x0; /* default audio */ - if (do_sony_cmd(cmd_buff, 2, status, ret_buff, 1, 1) != 0) - goto Enodev_irq; - - /* set the drive mode successful, we are set! */ - sony_buffer_size = SONY535_BUFFER_SIZE; - sony_buffer_sectors = sony_buffer_size / CDU535_BLOCK_SIZE; - - printk(KERN_INFO CDU535_MESSAGE_NAME " I/F CDROM : %8.8s %16.16s %4.4s", - drive_config.vendor_id, - drive_config.product_id, - drive_config.product_rev_level); - printk(" base address %03X, ", sony535_cd_base_io); - if (tmp_irq > 0) - printk("IRQ%d, ", tmp_irq); - printk("using %d byte buffer\n", sony_buffer_size); - - if (register_blkdev(MAJOR_NR, CDU535_HANDLE)) { - err = -EIO; - goto out1; - } - sonycd535_queue = blk_init_queue(do_cdu535_request, &sonycd535_lock); - if (!sonycd535_queue) { - err = -ENOMEM; - goto out1a; - } - - blk_queue_hardsect_size(sonycd535_queue, CDU535_BLOCK_SIZE); - sony_toc = kmalloc(sizeof(struct s535_sony_toc), GFP_KERNEL); - err = -ENOMEM; - if (!sony_toc) - goto out2; - last_sony_subcode = kmalloc(sizeof(struct s535_sony_subcode), GFP_KERNEL); - if (!last_sony_subcode) - goto out3; - sony_buffer = kmalloc(sizeof(Byte *) * sony_buffer_sectors, GFP_KERNEL); - if (!sony_buffer) - goto out4; - for (i = 0; i < sony_buffer_sectors; i++) { - sony_buffer[i] = kmalloc(CDU535_BLOCK_SIZE, GFP_KERNEL); - if (!sony_buffer[i]) { - while (--i>=0) - kfree(sony_buffer[i]); - goto out5; - } - } - initialized = 1; - - cdu_disk = alloc_disk(1); - if (!cdu_disk) - goto out6; - cdu_disk->major = MAJOR_NR; - cdu_disk->first_minor = 0; - cdu_disk->fops = &cdu_fops; - sprintf(cdu_disk->disk_name, "cdu"); - - if (!request_region(sony535_cd_base_io, 4, CDU535_HANDLE)) { - printk(KERN_WARNING"sonycd535: Unable to request region 0x%x\n", - sony535_cd_base_io); - goto out7; - } - cdu_disk->queue = sonycd535_queue; - add_disk(cdu_disk); - return 0; - -out7: - put_disk(cdu_disk); -out6: - for (i = 0; i < sony_buffer_sectors; i++) - kfree(sony_buffer[i]); -out5: - kfree(sony_buffer); -out4: - kfree(last_sony_subcode); -out3: - kfree(sony_toc); -out2: - blk_cleanup_queue(sonycd535_queue); -out1a: - unregister_blkdev(MAJOR_NR, CDU535_HANDLE); -out1: - if (sony535_irq_used) - free_irq(sony535_irq_used, NULL); - return err; -Enodev_irq: - if (sony535_irq_used) - free_irq(sony535_irq_used, NULL); -Enodev: - printk("Did not find a " CDU535_MESSAGE_NAME " drive\n"); - return -EIO; -} - -#ifndef MODULE - -/* - * accept "kernel command line" parameters - * (added by emoenke@gwdg.de) - * - * use: tell LILO: - * sonycd535=0x320 - * - * the address value has to be the existing CDROM port address. - */ -static int __init -sonycd535_setup(char *strings) -{ - int ints[3]; - (void)get_options(strings, ARRAY_SIZE(ints), ints); - /* if IRQ change and default io base desired, - * then call with io base of 0 - */ - if (ints[0] > 0) - if (ints[1] != 0) - sony535_cd_base_io = ints[1]; - if (ints[0] > 1) - sony535_irq_used = ints[2]; - if ((strings != NULL) && (*strings != '\0')) - printk(CDU535_MESSAGE_NAME - ": Warning: Unknown interface type: %s\n", strings); - - return 1; -} - -__setup("sonycd535=", sonycd535_setup); - -#endif /* MODULE */ - -static void __exit -sony535_exit(void) -{ - int i; - - release_region(sony535_cd_base_io, 4); - for (i = 0; i < sony_buffer_sectors; i++) - kfree(sony_buffer[i]); - kfree(sony_buffer); - kfree(last_sony_subcode); - kfree(sony_toc); - del_gendisk(cdu_disk); - put_disk(cdu_disk); - blk_cleanup_queue(sonycd535_queue); - if (unregister_blkdev(MAJOR_NR, CDU535_HANDLE) == -EINVAL) - printk("Uh oh, couldn't unregister " CDU535_HANDLE "\n"); - else - printk(KERN_INFO CDU535_HANDLE " module released\n"); -} - -module_init(sony535_init); -module_exit(sony535_exit); - - -MODULE_LICENSE("GPL"); -MODULE_ALIAS_BLOCKDEV_MAJOR(CDU535_CDROM_MAJOR); diff --git a/drivers/cdrom/sonycd535.h b/drivers/cdrom/sonycd535.h deleted file mode 100644 index 5dea1ef168d6..000000000000 --- a/drivers/cdrom/sonycd535.h +++ /dev/null @@ -1,183 +0,0 @@ -#ifndef SONYCD535_H -#define SONYCD535_H - -/* - * define all the commands recognized by the CDU-531/5 - */ -#define SONY535_REQUEST_DRIVE_STATUS_1 (0x80) -#define SONY535_REQUEST_SENSE (0x82) -#define SONY535_REQUEST_DRIVE_STATUS_2 (0x84) -#define SONY535_REQUEST_ERROR_STATUS (0x86) -#define SONY535_REQUEST_AUDIO_STATUS (0x88) -#define SONY535_INQUIRY (0x8a) - -#define SONY535_SET_INACTIVITY_TIME (0x90) - -#define SONY535_SEEK_AND_READ_N_BLOCKS_1 (0xa0) -#define SONY535_SEEK_AND_READ_N_BLOCKS_2 (0xa4) -#define SONY535_PLAY_AUDIO (0xa6) - -#define SONY535_REQUEST_DISC_CAPACITY (0xb0) -#define SONY535_REQUEST_TOC_DATA (0xb2) -#define SONY535_REQUEST_SUB_Q_DATA (0xb4) -#define SONY535_REQUEST_ISRC (0xb6) -#define SONY535_REQUEST_UPC_EAN (0xb8) - -#define SONY535_SET_DRIVE_MODE (0xc0) -#define SONY535_REQUEST_DRIVE_MODE (0xc2) -#define SONY535_SET_RETRY_COUNT (0xc4) - -#define SONY535_DIAGNOSTIC_1 (0xc6) -#define SONY535_DIAGNOSTIC_4 (0xcc) -#define SONY535_DIAGNOSTIC_5 (0xce) - -#define SONY535_EJECT_CADDY (0xd0) -#define SONY535_DISABLE_EJECT_BUTTON (0xd2) -#define SONY535_ENABLE_EJECT_BUTTON (0xd4) - -#define SONY535_HOLD (0xe0) -#define SONY535_AUDIO_PAUSE_ON_OFF (0xe2) -#define SONY535_SET_VOLUME (0xe8) - -#define SONY535_STOP (0xf0) -#define SONY535_SPIN_UP (0xf2) -#define SONY535_SPIN_DOWN (0xf4) - -#define SONY535_CLEAR_PARAMETERS (0xf6) -#define SONY535_CLEAR_ENDING_ADDRESS (0xf8) - -/* - * define some masks - */ -#define SONY535_DATA_NOT_READY_BIT (0x1) -#define SONY535_RESULT_NOT_READY_BIT (0x2) - -/* - * drive status 1 - */ -#define SONY535_STATUS1_COMMAND_ERROR (0x1) -#define SONY535_STATUS1_DATA_ERROR (0x2) -#define SONY535_STATUS1_SEEK_ERROR (0x4) -#define SONY535_STATUS1_DISC_TYPE_ERROR (0x8) -#define SONY535_STATUS1_NOT_SPINNING (0x10) -#define SONY535_STATUS1_EJECT_BUTTON_PRESSED (0x20) -#define SONY535_STATUS1_CADDY_NOT_INSERTED (0x40) -#define SONY535_STATUS1_BYTE_TWO_FOLLOWS (0x80) - -/* - * drive status 2 - */ -#define SONY535_CDD_LOADING_ERROR (0x7) -#define SONY535_CDD_NO_DISC (0x8) -#define SONY535_CDD_UNLOADING_ERROR (0x9) -#define SONY535_CDD_CADDY_NOT_INSERTED (0xd) -#define SONY535_ATN_RESET_OCCURRED (0x2) -#define SONY535_ATN_DISC_CHANGED (0x4) -#define SONY535_ATN_RESET_AND_DISC_CHANGED (0x6) -#define SONY535_ATN_EJECT_IN_PROGRESS (0xe) -#define SONY535_ATN_BUSY (0xf) - -/* - * define some parameters - */ -#define SONY535_AUDIO_DRIVE_MODE (0) -#define SONY535_CDROM_DRIVE_MODE (0xe0) - -#define SONY535_PLAY_OP_PLAYBACK (0) -#define SONY535_PLAY_OP_ENTER_HOLD (1) -#define SONY535_PLAY_OP_SET_AUDIO_ENDING_ADDR (2) -#define SONY535_PLAY_OP_SCAN_FORWARD (3) -#define SONY535_PLAY_OP_SCAN_BACKWARD (4) - -/* - * convert from msf format to block number - */ -#define SONY_BLOCK_NUMBER(m,s,f) (((m)*60L+(s))*75L+(f)) -#define SONY_BLOCK_NUMBER_MSF(x) (((x)[0]*60L+(x)[1])*75L+(x)[2]) - -/* - * error return values from the doSonyCmd() routines - */ -#define TIME_OUT (-1) -#define NO_CDROM (-2) -#define BAD_STATUS (-3) -#define CD_BUSY (-4) -#define NOT_DATA_CD (-5) -#define NO_ROOM (-6) - -#define LOG_START_OFFSET 150 /* Offset of first logical sector */ - -#define SONY_JIFFIES_TIMEOUT (5*HZ) /* Maximum time - the drive will wait/try for an - operation */ -#define SONY_READY_RETRIES (50000) /* How many times to retry a - spin waiting for a register - to come ready */ -#define SONY535_FAST_POLLS (10000) /* how many times recheck - status waiting for a data - to become ready */ - -typedef unsigned char Byte; - -/* - * This is the complete status returned from the drive configuration request - * command. - */ -struct s535_sony_drive_config -{ - char vendor_id[8]; - char product_id[16]; - char product_rev_level[4]; -}; - -/* The following is returned from the request sub-q data command */ -struct s535_sony_subcode -{ - unsigned char address :4; - unsigned char control :4; - unsigned char track_num; - unsigned char index_num; - unsigned char rel_msf[3]; - unsigned char abs_msf[3]; -}; - -struct s535_sony_disc_capacity -{ - Byte mFirstTrack, sFirstTrack, fFirstTrack; - Byte mLeadOut, sLeadOut, fLeadOut; -}; - -/* - * The following is returned from the request TOC (Table Of Contents) command. - * (last_track_num-first_track_num+1) values are valid in tracks. - */ -struct s535_sony_toc -{ - unsigned char reserved0 :4; - unsigned char control0 :4; - unsigned char point0; - unsigned char first_track_num; - unsigned char reserved0a; - unsigned char reserved0b; - unsigned char reserved1 :4; - unsigned char control1 :4; - unsigned char point1; - unsigned char last_track_num; - unsigned char dummy1; - unsigned char dummy2; - unsigned char reserved2 :4; - unsigned char control2 :4; - unsigned char point2; - unsigned char lead_out_start_msf[3]; - struct - { - unsigned char reserved :4; - unsigned char control :4; - unsigned char track; - unsigned char track_start_msf[3]; - } tracks[100]; - - unsigned int lead_out_start_lba; -}; - -#endif /* SONYCD535_H */ -- cgit v1.2.3-59-g8ed1b From 72d3a38ee083a96c09032e608a4c7e047ce26760 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Mon, 9 Jul 2007 09:40:44 +0200 Subject: unexport bio_{,un}map_user bio_{,un}map_user no longer have any modular users. Signed-off-by: Adrian Bunk Signed-off-by: Jens Axboe --- fs/bio.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/bio.c b/fs/bio.c index 093345f00128..33e46340a766 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -1223,8 +1223,6 @@ EXPORT_SYMBOL(bio_hw_segments); EXPORT_SYMBOL(bio_add_page); EXPORT_SYMBOL(bio_add_pc_page); EXPORT_SYMBOL(bio_get_nr_vecs); -EXPORT_SYMBOL(bio_map_user); -EXPORT_SYMBOL(bio_unmap_user); EXPORT_SYMBOL(bio_map_kern); EXPORT_SYMBOL(bio_pair_release); EXPORT_SYMBOL(bio_split); -- cgit v1.2.3-59-g8ed1b From 15c31be4d5bd2402c6f5a288d56a24edc9252b71 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 10 Jul 2007 13:43:25 +0200 Subject: cfq-iosched: fix async queue behaviour With the cfq_queue hash removal, we inadvertently got rid of the async queue sharing. This was not intentional, in fact CFQ purposely shares the async queue per priority level to get good merging for async writes. So put some logic in cfq_get_queue() to track the shared queues. Signed-off-by: Jens Axboe --- block/cfq-iosched.c | 39 ++++++++++++++++++++++++++++++++++++--- include/linux/ioprio.h | 6 ++++-- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index baef5fc7cff8..e0aa4dad6742 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c @@ -92,6 +92,8 @@ struct cfq_data { struct cfq_queue *active_queue; struct cfq_io_context *active_cic; + struct cfq_queue *async_cfqq[IOPRIO_BE_NR]; + struct timer_list idle_class_timer; sector_t last_position; @@ -1351,8 +1353,8 @@ static void cfq_ioc_set_ioprio(struct io_context *ioc) } static struct cfq_queue * -cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk, - gfp_t gfp_mask) +cfq_find_alloc_queue(struct cfq_data *cfqd, int is_sync, + struct task_struct *tsk, gfp_t gfp_mask) { struct cfq_queue *cfqq, *new_cfqq = NULL; struct cfq_io_context *cic; @@ -1405,12 +1407,35 @@ retry: if (new_cfqq) kmem_cache_free(cfq_pool, new_cfqq); - atomic_inc(&cfqq->ref); out: WARN_ON((gfp_mask & __GFP_WAIT) && !cfqq); return cfqq; } +static struct cfq_queue * +cfq_get_queue(struct cfq_data *cfqd, int is_sync, struct task_struct *tsk, + gfp_t gfp_mask) +{ + const int ioprio = task_ioprio(tsk); + struct cfq_queue *cfqq = NULL; + + if (!is_sync) + cfqq = cfqd->async_cfqq[ioprio]; + if (!cfqq) + cfqq = cfq_find_alloc_queue(cfqd, is_sync, tsk, gfp_mask); + + /* + * pin the queue now that it's allocated, scheduler exit will prune it + */ + if (!is_sync && !cfqd->async_cfqq[ioprio]) { + atomic_inc(&cfqq->ref); + cfqd->async_cfqq[ioprio] = cfqq; + } + + atomic_inc(&cfqq->ref); + return cfqq; +} + /* * We drop cfq io contexts lazily, so we may find a dead one. */ @@ -2019,6 +2044,7 @@ static void cfq_exit_queue(elevator_t *e) { struct cfq_data *cfqd = e->elevator_data; request_queue_t *q = cfqd->queue; + int i; cfq_shutdown_timer_wq(cfqd); @@ -2035,6 +2061,13 @@ static void cfq_exit_queue(elevator_t *e) __cfq_exit_single_io_context(cfqd, cic); } + /* + * Put the async queues + */ + for (i = 0; i < IOPRIO_BE_NR; i++) + if (cfqd->async_cfqq[i]) + cfq_put_queue(cfqd->async_cfqq[i]); + spin_unlock_irq(q->queue_lock); cfq_shutdown_timer_wq(cfqd); diff --git a/include/linux/ioprio.h b/include/linux/ioprio.h index 8e2042b9d471..2eaa142cd061 100644 --- a/include/linux/ioprio.h +++ b/include/linux/ioprio.h @@ -47,8 +47,10 @@ enum { #define IOPRIO_NORM (4) static inline int task_ioprio(struct task_struct *task) { - WARN_ON(!ioprio_valid(task->ioprio)); - return IOPRIO_PRIO_DATA(task->ioprio); + if (ioprio_valid(task->ioprio)) + return IOPRIO_PRIO_DATA(task->ioprio); + + return IOPRIO_NORM; } static inline int task_nice_ioprio(struct task_struct *task) -- cgit v1.2.3-59-g8ed1b From 16ed002f224738366c1809023ec70a71ae51421c Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 10 Jul 2007 12:24:11 +0200 Subject: Use menuconfigs instead of menus, so the whole menu can be disabled at once instead of going through all options. Signed-off-by: Jan Engelhardt Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- block/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/block/Kconfig b/block/Kconfig index a50f48111647..285935134bcd 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -1,7 +1,7 @@ # # Block layer core configuration # -config BLOCK +menuconfig BLOCK bool "Enable the block layer" if EMBEDDED default y help @@ -49,6 +49,6 @@ config LSF If unsure, say Y. -endif +endif # BLOCK source block/Kconfig.iosched -- cgit v1.2.3-59-g8ed1b From 5f5c926e3cba972636b50ab872b421e992d4f401 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 10 Jul 2007 12:24:17 +0200 Subject: block/Kconfig already has its own "menuconfig" so remove these "menu, endmenu" that did not get cleaned up in the block patch [ http://lkml.org/lkml/2007/4/10/251 ] Signed-off-by: Jan Engelhardt Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- init/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/init/Kconfig b/init/Kconfig index a9e99f8328ff..d9d878a3bb46 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -686,6 +686,4 @@ config STOP_MACHINE Need stop_machine() primitive. endmenu -menu "Block layer" source "block/Kconfig" -endmenu -- cgit v1.2.3-59-g8ed1b From fd11d171e51a5b81c176d856d5df5612117e1a45 Mon Sep 17 00:00:00 2001 From: Jan Engelhardt Date: Tue, 10 Jul 2007 12:26:06 +0200 Subject: Make a "menuconfig" out of the Kconfig objects "menu, ..., endmenu", so that the user can disable all the options in that menu at once instead of having to disable each option separately. Signed-off-by: Jan Engelhardt Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- drivers/block/Kconfig | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index d6ad7b3ea0dc..6e23af1ecbdb 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -2,9 +2,12 @@ # Block device driver configuration # -if BLOCK +menuconfig BLK_DEV + bool "Block devices" + depends on BLOCK + default y -menu "Block devices" +if BLK_DEV config BLK_DEV_FD tristate "Normal floppy disk support" @@ -422,6 +425,4 @@ config ATA_OVER_ETH source "drivers/s390/block/Kconfig" -endmenu - -endif +endif # BLK_DEV -- cgit v1.2.3-59-g8ed1b From 70cee26e020c1d74ff559c991b96c7b19fa4173b Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 10 Jul 2007 12:26:24 +0200 Subject: Use list_for_each_entry() instead of list_for_each() in the block device elevator Signed-off-by: Matthias Kaehlcke Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- block/elevator.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/block/elevator.c b/block/elevator.c index ce866eb75f6a..4769a25d7037 100644 --- a/block/elevator.c +++ b/block/elevator.c @@ -112,12 +112,8 @@ static inline int elv_try_merge(struct request *__rq, struct bio *bio) static struct elevator_type *elevator_find(const char *name) { struct elevator_type *e; - struct list_head *entry; - - list_for_each(entry, &elv_list) { - - e = list_entry(entry, struct elevator_type, list); + list_for_each_entry(e, &elv_list, list) { if (!strcmp(e->elevator_name, name)) return e; } @@ -1116,14 +1112,11 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name) { elevator_t *e = q->elevator; struct elevator_type *elv = e->elevator_type; - struct list_head *entry; + struct elevator_type *__e; int len = 0; spin_lock(&elv_list_lock); - list_for_each(entry, &elv_list) { - struct elevator_type *__e; - - __e = list_entry(entry, struct elevator_type, list); + list_for_each_entry(__e, &elv_list, list) { if (!strcmp(elv->elevator_name, __e->elevator_name)) len += sprintf(name+len, "[%s] ", elv->elevator_name); else -- cgit v1.2.3-59-g8ed1b From c0613c1c940dac991b9e54db75dc9976491d9f0a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 10 Jul 2007 12:26:29 +0200 Subject: Documentation/block/barrier.txt is not in sync with the actual code: - blk_queue_ordered() no longer has a gfp_mask parameter - blk_queue_ordered_locked() no longer exists - sd_prepare_flush() looks slightly different Signed-off-by: Geert Uytterhoeven Acked-by: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Jens Axboe --- Documentation/block/barrier.txt | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/Documentation/block/barrier.txt b/Documentation/block/barrier.txt index a272c3db8094..7d279f2f5bb2 100644 --- a/Documentation/block/barrier.txt +++ b/Documentation/block/barrier.txt @@ -82,23 +82,12 @@ including draining and flushing. typedef void (prepare_flush_fn)(request_queue_t *q, struct request *rq); int blk_queue_ordered(request_queue_t *q, unsigned ordered, - prepare_flush_fn *prepare_flush_fn, - unsigned gfp_mask); - -int blk_queue_ordered_locked(request_queue_t *q, unsigned ordered, - prepare_flush_fn *prepare_flush_fn, - unsigned gfp_mask); - -The only difference between the two functions is whether or not the -caller is holding q->queue_lock on entry. The latter expects the -caller is holding the lock. + prepare_flush_fn *prepare_flush_fn); @q : the queue in question @ordered : the ordered mode the driver/device supports @prepare_flush_fn : this function should prepare @rq such that it flushes cache to physical medium when executed -@gfp_mask : gfp_mask used when allocating data structures - for ordered processing For example, SCSI disk driver's prepare_flush_fn looks like the following. @@ -106,9 +95,10 @@ following. static void sd_prepare_flush(request_queue_t *q, struct request *rq) { memset(rq->cmd, 0, sizeof(rq->cmd)); - rq->flags |= REQ_BLOCK_PC; + rq->cmd_type = REQ_TYPE_BLOCK_PC; rq->timeout = SD_TIMEOUT; rq->cmd[0] = SYNCHRONIZE_CACHE; + rq->cmd_len = 10; } The following seven ordered modes are supported. The following table -- cgit v1.2.3-59-g8ed1b