* [PATCH] SH/Dreamcast - add support for GD-Rom device
@ 2007-12-27 1:26 Adrian McMenamin
2007-12-27 8:18 ` Paul Mundt
0 siblings, 1 reply; 20+ messages in thread
From: Adrian McMenamin @ 2007-12-27 1:26 UTC (permalink / raw)
To: Paul Mundt, Jens Axboe; +Cc: linux-kernel, linux-sh
[-- Attachment #1: Type: text/plain, Size: 826 bytes --]
This patch adds support for the CD-Rom drive on the SEGA Dreamcast.
The SEGA Dreamcast has a built in CD-Rom drive, electrically similar
to an ATA-3 drive, but implementing a proprietary packet interface -
the so-called Sega Packet Interface (SPI)- and also supporting a
proprietary format of disk - the Giga Disk Rom, with a 1GB capacity.
The drive is know as the "GD-Rom drive".
This patch partially implements the SPI and also supports reading GD
Rom disks. Unlike previous GD Rom drivers (which were never in the
mainline), this driver implements DMA and not PIO for reads. It is a
new driver, not a modified version of previous drivers.
This is the fourth iteration of this patch - which should work with
both 2.6-24-rc5 and Paul Mundt's 2.6.25 queue.
Signed-off by: Adrian McMenamin <adrian@mcmen.demon.co.uk>
----
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: gdrom.patch --]
[-- Type: text/x-patch; name=gdrom.patch, Size: 23958 bytes --]
diff -rupN linux-2.6-orig/drivers/block/Kconfig linux-2.6/drivers/block/Kconfig
--- linux-2.6-orig/drivers/block/Kconfig 2007-12-26 17:27:14.000000000 +0000
+++ linux-2.6/drivers/block/Kconfig 2007-12-27 00:08:39.000000000 +0000
@@ -105,6 +105,18 @@ config PARIDE
"MicroSolutions backpack protocol", "DataStor Commuter protocol"
etc.).
+config GDROM
+ tristate "SEGA Dreamcast GD-ROM drive"
+ depends on SH_DREAMCAST
+ help
+ A standard SEGA Dreamcast comes with a modified CD ROM drive called a
+ "GD-ROM" by SEGA to signify it is capable of reading special disks
+ with up to 1 GB of data. This drive will also read standard CD ROM
+ disks. Select this option to access any disks in your GD ROM drive.
+ Most users will want to say "Y" here.
+ You can also build this as a module which will be called gdrom.ko
+
+
source "drivers/block/paride/Kconfig"
config BLK_CPQ_DA
diff -rupN linux-2.6-orig/drivers/cdrom/gdrom.c linux-2.6/drivers/cdrom/gdrom.c
--- linux-2.6-orig/drivers/cdrom/gdrom.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6/drivers/cdrom/gdrom.c 2007-12-27 00:57:01.000000000 +0000
@@ -0,0 +1,776 @@
+/* GD ROM driver for the SEGA Dreamcast
+ * copyright Adrian McMenamin, 2007
+ * With thanks to Marcus Comstedt and Nathan Keynes
+ * for work in reversing PIO and DMA
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/cdrom.h>
+#include <linux/genhd.h>
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <scsi/scsi.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/delay.h>
+#include <asm/mach/dma.h>
+#include <asm/mach/sysasic.h>
+
+#define GDROM_DEV_NAME "gdrom"
+#define GD_SESSION_OFFSET 150
+
+/* GD Rom commands */
+#define GDROM_COM_SOFTRESET 0x08
+#define GDROM_COM_EXECDIAG 0x90
+#define GDROM_COM_PACKET 0xA0
+#define GDROM_COM_IDDEV 0xA1
+
+/* GD Rom registers */
+#define GDROM_BASE_REG 0xA05F7000
+#define GDROM_ALTSTATUS_REG (GDROM_BASE_REG + 0x18)
+#define GDROM_DATA_REG (GDROM_BASE_REG + 0x80)
+#define GDROM_ERROR_REG (GDROM_BASE_REG + 0x84)
+#define GDROM_INTSEC_REG (GDROM_BASE_REG + 0x88)
+#define GDROM_SECNUM_REG (GDROM_BASE_REG + 0x8C)
+#define GDROM_BCL_REG (GDROM_BASE_REG + 0x90)
+#define GDROM_BCH_REG (GDROM_BASE_REG + 0x94)
+#define GDROM_DSEL_REG (GDROM_BASE_REG + 0x98)
+#define GDROM_STATUSCOMMAND_REG (GDROM_BASE_REG + 0x9C)
+#define GDROM_RESET_REG (GDROM_BASE_REG + 0x4E4)
+
+#define GDROM_DMA_STARTADDR_REG (GDROM_BASE_REG + 0x404)
+#define GDROM_DMA_LENGTH_REG (GDROM_BASE_REG + 0x408)
+#define GDROM_DMA_DIRECTION_REG (GDROM_BASE_REG + 0x40C)
+#define GDROM_DMA_ENABLE_REG (GDROM_BASE_REG + 0x414)
+#define GDROM_DMA_STATUS_REG (GDROM_BASE_REG + 0x418)
+#define GDROM_DMA_WAIT_REG (GDROM_BASE_REG + 0x4A0)
+#define GDROM_DMA_ACCESS_CTRL_REG (GDROM_BASE_REG + 0x4B8)
+
+#define GDROM_HARD_SECTOR 2048
+#define BLOCK_LAYER_SECTOR 512
+#define GD_TO_BLK 4
+
+static const struct {
+ int sense_key;
+ const char * const text;
+} sense_texts[] = {
+ {NO_SENSE, "GDROM: OK"},
+ {RECOVERED_ERROR, "GDROM: Recovered from error"},
+ {NOT_READY, "GDROM: Device not ready"},
+ {MEDIUM_ERROR, "GDROM: Disk not ready"},
+ {HARDWARE_ERROR, "GDROM: Hardware error"},
+ {ILLEGAL_REQUEST, "GDROM: Command has failed"},
+ {UNIT_ATTENTION, "GDROM: Device needs attention - disk may have been changed"},
+ {DATA_PROTECT, "GDROM: Data protection error"},
+ {ABORTED_COMMAND, "GDROM: Command aborted"},
+};
+
+static struct platform_device *pd;
+static int gdrom_major;
+static wait_queue_head_t command_queue;
+static wait_queue_head_t request_queue;
+
+static DEFINE_SPINLOCK(gdrom_lock);
+static void gdrom_readdisk_dma(struct work_struct *work);
+static DECLARE_WORK(work, gdrom_readdisk_dma);
+static LIST_HEAD(gdrom_deferred);
+
+struct gdromtoc {
+ unsigned int entry[99];
+ unsigned int first, last;
+ unsigned int leadout;
+};
+
+static struct gdrom_unit {
+ struct gendisk *disk;
+ struct cdrom_device_info *cd_info;
+ int status;
+ int pending;
+ int transfer;
+ char disk_type;
+ struct gdromtoc *toc;
+ struct request_queue *gdrom_rq;
+} gd;
+
+struct gdrom_id {
+ char mid;
+ char modid;
+ char verid;
+ char padA[13];
+ char mname[16];
+ char modname[16];
+ char firmver[16];
+ char padB[16];
+};
+
+static int gdrom_getsense(short *bufstring);
+static int gdrom_packetcommand(struct cdrom_device_info *cd_info, struct packet_command *command);
+static int gdrom_hardreset(struct cdrom_device_info *cd_info);
+
+static void gdrom_wait_clrbusy(void)
+{
+ /* long timeouts - typical for a CD Rom */
+ unsigned long timeout = jiffies + HZ * 60;
+ while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) && (time_before(jiffies, timeout)))
+ cpu_relax();
+}
+
+static void gdrom_wait_busy_sleeps(void)
+{
+ unsigned long timeout;
+ /* Wait to get busy first */
+ timeout = jiffies + HZ * 60;
+ while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) == 0) && (time_before(jiffies, timeout)))
+ cpu_relax();
+ /* Now wait for busy to clear */
+ gdrom_wait_clrbusy();
+}
+
+static void gdrom_identifydevice(void *buf)
+{
+ int c;
+ short *data = buf;
+ gdrom_wait_clrbusy();
+ ctrl_outb(GDROM_COM_IDDEV, GDROM_STATUSCOMMAND_REG);
+ gdrom_wait_busy_sleeps();
+ /* now read in the data */
+ for (c = 0; c < 40; c++)
+ data[c] = ctrl_inw(GDROM_DATA_REG);
+}
+
+static void gdrom_spicommand(void *spi_string, int buflen)
+{
+ short *cmd = spi_string;
+ /* ensure IRQ_WAIT is set */
+ ctrl_outb(0x08, GDROM_ALTSTATUS_REG);
+ /* specify how many bytes we expect back */
+ ctrl_outb(buflen & 0xFF, GDROM_BCL_REG);
+ ctrl_outb((buflen >> 8) & 0xFF, GDROM_BCH_REG);
+ /* other parameters */
+ ctrl_outb(0, GDROM_INTSEC_REG);
+ ctrl_outb(0, GDROM_SECNUM_REG);
+ ctrl_outb(0, GDROM_ERROR_REG);
+ /* Wait until we can go */
+ gdrom_wait_clrbusy();
+ ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
+ while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) != 8)
+ cpu_relax(); /* wait for DRQ to be set to 1 */
+ outsw(PHYSADDR(GDROM_DATA_REG), cmd, 6);
+}
+
+/* gdrom_command_executediagnostic:
+ * Used to probe for presence of working GDROM
+ * Restarts GDROM device and then applies standard ATA 3
+ * Execute Diagnostic Command: a return of '1' indicates device 0
+ * present and device 1 absent
+ */
+static char gdrom_execute_diagnostic(void)
+{
+ gdrom_hardreset(gd.cd_info);
+ gdrom_wait_clrbusy();
+ ctrl_outb(GDROM_COM_EXECDIAG, GDROM_STATUSCOMMAND_REG);
+ gdrom_wait_busy_sleeps();
+ return ctrl_inb(GDROM_ERROR_REG);
+}
+
+/*
+ * Prepare disk command
+ * byte 0 = 0x70
+ * byte 1 = 0x1f
+ */
+static int gdrom_preparedisk_cmd(void)
+{
+ struct packet_command *spin_command;
+ spin_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
+ if (!spin_command)
+ return -ENOMEM;
+ spin_command->cmd[0] = 0x70;
+ spin_command->cmd[2] = 0x1f;
+ spin_command->buflen = 0;
+ gd.pending = 1;
+ gdrom_packetcommand(gd.cd_info, spin_command);
+ /* 60 second timeout */
+ wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
+ gd.pending = 0;
+ kfree(spin_command);
+ if (gd.status & 0x01) {
+ /* log an error */
+ gdrom_getsense(NULL);
+ return -EIO;
+ }
+ return 0;
+}
+
+/*
+ * Read TOC command
+ * byte 0 = 0x14
+ * byte 1 = session
+ * byte 3 = sizeof TOC >> 8 ie upper byte
+ * byte 4 = sizeof TOC & 0xff ie lower byte
+ */
+static int gdrom_readtoc_cmd(struct gdromtoc *toc, int session)
+{
+ int tocsize;
+ struct packet_command *toc_command;
+ toc_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
+ if (!toc_command)
+ return -ENOMEM;
+ tocsize = sizeof(struct gdromtoc);
+ toc_command->cmd[0] = 0x14;
+ toc_command->cmd[1] = session;
+ toc_command->cmd[3] = tocsize >> 8;
+ toc_command->cmd[4] = tocsize & 0xff;
+ toc_command->buflen = tocsize;
+ gd.pending = 1;
+ gdrom_packetcommand(gd.cd_info, toc_command);
+ wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
+ gd.pending = 0;
+ insw(PHYSADDR(GDROM_DATA_REG), toc, tocsize/2);
+ kfree(toc_command);
+ if (gd.status & 0x01)
+ return -EINVAL;
+ return 0;
+}
+
+/* TOC helpers */
+static int get_entry_lba(int track)
+{
+ return (cpu_to_be32(track & 0xffffff00) - GD_SESSION_OFFSET);
+}
+
+static int get_entry_q_ctrl(int track)
+{
+ return (track & 0x000000f0) >> 4;
+}
+
+static int get_entry_track(int track)
+{
+ return (track & 0x0000ff00) >> 8;
+}
+
+static int gdrom_get_last_session(struct cdrom_device_info *cd_info, struct cdrom_multisession *ms_info)
+{
+ int fentry, lentry, track, data, tocuse, err;
+ kfree(gd.toc);
+ gd.toc = kzalloc(sizeof(struct gdromtoc), GFP_KERNEL);
+ if (!gd.toc)
+ return -ENOMEM;
+ tocuse = 1;
+ /* Check if GD-ROM */
+ err = gdrom_readtoc_cmd(gd.toc, 1);
+ /* Not a GD-ROM so check if standard CD-ROM */
+ if (err) {
+ tocuse = 0;
+ err = gdrom_readtoc_cmd(gd.toc, 0);
+ if (err) {
+ printk(KERN_INFO "Could not get CD table of contents\n");
+ return -ENXIO;
+ }
+ }
+
+ fentry = get_entry_track(gd.toc->first);
+ lentry = get_entry_track(gd.toc->last);
+ /* Find the first data track */
+ track = get_entry_track(gd.toc->last);
+ do {
+ data = gd.toc->entry[track - 1];
+ if (get_entry_q_ctrl(data))
+ break; /* ie a real data track */
+ track--;
+ } while (track >= fentry);
+
+ if ((track > 100) || (track < get_entry_track(gd.toc->first))) {
+ gdrom_getsense(NULL);
+ printk(KERN_INFO "GDROM: No data on the last session of the CD\n");
+ return -ENXIO;
+ }
+
+ ms_info->addr_format = CDROM_LBA;
+ ms_info->addr.lba = get_entry_lba(data);
+ ms_info->xa_flag = 1;
+ return 0;
+}
+
+static int gdrom_open(struct cdrom_device_info *cd_info, int purpose)
+{
+ /* spin up the disk */
+ return gdrom_preparedisk_cmd();
+}
+
+/* this function is required even if empty */
+static void gdrom_release(struct cdrom_device_info *cd_info)
+{
+}
+
+static int gdrom_drivestatus(struct cdrom_device_info *cd_info, int ignore)
+{
+ /* read the sense key */
+ char sense = ctrl_inb(GDROM_ERROR_REG);
+ sense &= 0xF0;
+ if (sense == 0)
+ return CDS_DISC_OK;
+ if (sense == 0x20)
+ return CDS_DRIVE_NOT_READY;
+ /* default */
+ return CDS_NO_INFO;
+}
+
+static int gdrom_mediachanged(struct cdrom_device_info *cd_info, int ignore)
+{
+ /* check the sense key */
+ return ((ctrl_inb(GDROM_ERROR_REG) & 0xF0) == 0x60);
+}
+
+/* reset the G1 bus */
+static int gdrom_hardreset(struct cdrom_device_info *cd_info)
+{
+ int count;
+ ctrl_outl(0x1fffff, GDROM_RESET_REG);
+ for (count = 0xa0000000; count < 0xa0200000; count += 4)
+ ctrl_inl(count);
+ return 0;
+}
+
+/* keep the function loioking like the universal CD Rom specification - returning int*/
+static int gdrom_packetcommand(struct cdrom_device_info *cd_info, struct packet_command *command)
+{
+ gdrom_spicommand(&command->cmd, command->buflen);
+ return 0;
+}
+
+/* Get Sense SPI command
+ * From Marcus Comstedt
+ * cmd = 0x13
+ * cmd + 4 = length of returned buffer
+ * Returns 5 16 bit words
+ */
+static int gdrom_getsense(short *bufstring)
+{
+ struct packet_command *sense_command;
+ short sense[5];
+ int sense_key;
+ if (gd.pending)
+ return -EIO;
+
+ /* allocate command and buffer */
+ sense_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
+ if (!sense_command)
+ return -ENOMEM;
+
+ sense_command->cmd[0] = 0x13;
+ sense_command->cmd[4] = 10;
+ sense_command->buflen = 10;
+
+ gd.pending = 1;
+ gdrom_packetcommand(gd.cd_info, sense_command);
+ /* 60 second timeout */
+ wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
+ gd.pending = 0;
+ kfree(sense_command);
+ insw(PHYSADDR(GDROM_DATA_REG), &sense, 5);
+ if (sense[1] & 40) {
+ printk(KERN_INFO "GDROM: Drive not ready - command aborted\n");
+ return -EIO;
+ }
+ sense_key = sense[1] & 0x0F;
+ printk(KERN_INFO "%s\n", sense_texts[sense_key].text);
+
+ if (bufstring)
+ memcpy(bufstring, &sense[4], 2); /* return additional sense data */
+
+ if (sense_key < 2)
+ return 0;
+ return -EIO;
+}
+
+static struct cdrom_device_ops gdrom_ops = {
+ .open = gdrom_open,
+ .release = gdrom_release,
+ .drive_status = gdrom_drivestatus,
+ .media_changed = gdrom_mediachanged,
+ .get_last_session = gdrom_get_last_session,
+ .reset = gdrom_hardreset,
+ .capability = CDC_MULTI_SESSION | CDC_MEDIA_CHANGED |
+ CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R,
+ .n_minors = 1,
+};
+
+static int gdrom_bdops_open(struct inode *inode, struct file *file)
+{
+ return cdrom_open(gd.cd_info, inode, file);
+}
+
+static int gdrom_bdops_release(struct inode *inode, struct file *file)
+{
+ return cdrom_release(gd.cd_info, file);
+}
+
+static int gdrom_bdops_mediachanged(struct gendisk *disk)
+{
+ return cdrom_media_changed(gd.cd_info);
+}
+
+static int gdrom_bdops_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long arg)
+{
+ return cdrom_ioctl(file, gd.cd_info, inode, cmd, arg);
+}
+
+static struct block_device_operations gdrom_bdops = {
+ .owner = THIS_MODULE,
+ .open = gdrom_bdops_open,
+ .release = gdrom_bdops_release,
+ .media_changed = gdrom_bdops_mediachanged,
+ .ioctl = gdrom_bdops_ioctl,
+};
+
+static irqreturn_t gdrom_command_interrupt(int irq, void *dev_id)
+{
+ gd.status = ctrl_inb(GDROM_STATUSCOMMAND_REG);
+ if (gd.pending != 1)
+ return IRQ_HANDLED;
+ gd.pending = 0;
+ wake_up_interruptible(&command_queue);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t gdrom_dma_interrupt(int irq, void *dev_id)
+{
+ gd.status = ctrl_inb(GDROM_STATUSCOMMAND_REG);
+ if (gd.transfer != 1)
+ return IRQ_HANDLED;
+ gd.transfer = 0;
+ wake_up_interruptible(&request_queue);
+ return IRQ_HANDLED;
+}
+
+static int gdrom_set_command_interrupt_handler(void)
+{
+ /* need a queue to wait in */
+ init_waitqueue_head(&command_queue);
+ return request_irq(HW_EVENT_GDROM_CMD, gdrom_command_interrupt, IRQF_DISABLED, "gdrom_command", &gd);
+}
+
+static int gdrom_set_dma_interrupt_handler(void)
+{
+ init_waitqueue_head(&request_queue);
+ return request_irq(HW_EVENT_GDROM_DMA, gdrom_dma_interrupt, IRQF_DISABLED, "gdrom_dma", &gd);
+}
+
+/* Implement DMA read using SPI command
+ * 0 -> 0x30
+ * 1 -> mode
+ * 2 -> block >> 16
+ * 3 -> block >> 8
+ * 4 -> block
+ * 8 -> sectors >> 16
+ * 9 -> sectors >> 8
+ * 10 -> sectors
+ */
+static void gdrom_readdisk_dma(struct work_struct *work)
+{
+ int err, block, block_cnt;
+ struct packet_command *read_command;
+ struct list_head *elem, *next;
+ struct request *req;
+ unsigned long timeout;
+ if (list_empty(&gdrom_deferred))
+ return;
+ read_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
+ if (!read_command)
+ return; /* get more memory later? */
+ read_command->cmd[0] = 0x30;
+ read_command->cmd[1] = 0x20;
+ spin_lock(&gdrom_lock);
+ list_for_each_safe(elem, next, &gdrom_deferred) {
+ req = list_entry(elem, struct request, queuelist);
+ spin_unlock(&gdrom_lock);
+ block = req->sector/GD_TO_BLK + GD_SESSION_OFFSET;
+ block_cnt = req->nr_sectors/GD_TO_BLK;
+ ctrl_outl(PHYSADDR(req->buffer), GDROM_DMA_STARTADDR_REG);
+ ctrl_outl(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG);
+ ctrl_outl(1, GDROM_DMA_DIRECTION_REG);
+ ctrl_outl(1, GDROM_DMA_ENABLE_REG);
+ read_command->cmd[2] = (block >> 16) & 0xFF;
+ read_command->cmd[3] = (block >> 8) & 0xFF;
+ read_command->cmd[4] = block & 0xFF;
+ read_command->cmd[8] = (block_cnt >> 16) & 0xFF;
+ read_command->cmd[9] = (block_cnt >> 8) & 0xFF;
+ read_command->cmd[10] = block_cnt & 0xFF;
+ /* set for DMA */
+ ctrl_outb(1, GDROM_ERROR_REG);
+ /* other registers */
+ ctrl_outb(0, GDROM_SECNUM_REG);
+ ctrl_outb(0, GDROM_BCL_REG);
+ ctrl_outb(0, GDROM_BCH_REG);
+ ctrl_outb(0, GDROM_DSEL_REG);
+ ctrl_outb(0, GDROM_INTSEC_REG);
+ /* In multiple DMA transfers need to wait */
+ timeout = jiffies + HZ / 2;
+ while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) && (time_before(jiffies, timeout)))
+ cpu_relax();
+ ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
+ timeout = jiffies + HZ / 2;
+ while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) != 8) && (time_before(jiffies, timeout)))
+ cpu_relax(); /* wait for DRQ to be set to 1 */
+ gd.pending = 1;
+ gd.transfer = 1;
+ outsw(PHYSADDR(GDROM_DATA_REG), &read_command->cmd, 6);
+ timeout = jiffies + HZ / 2;
+ while ((ctrl_inb(GDROM_DMA_STATUS_REG)) && (time_before(jiffies, timeout)))
+ cpu_relax();
+ ctrl_outb(1, GDROM_DMA_STATUS_REG);
+ /* 5 second error margin here seems more reasonable */
+ wait_event_interruptible_timeout(request_queue, gd.transfer == 0, HZ * 5);
+ err = ctrl_inb(GDROM_DMA_STATUS_REG);
+ err = gd.transfer;
+ gd.transfer = 0;
+ gd.pending = 0;
+ /* now seek to take the request spinlock
+ * before handling ending the request */
+ spin_lock(&gdrom_lock);
+ list_del_init(&req->queuelist);
+ blk_requeue_request(gd.gdrom_rq, req);
+ if (err)
+ end_request(req, 0);
+ else
+ end_request(req, 1);
+ }
+ spin_unlock(&gdrom_lock);
+ kfree(read_command);
+}
+
+static void gdrom_request_handler_dma(struct request *req)
+{
+ /* dequeue, add to list of deferred work
+ * and then schedule workqueue */
+ blkdev_dequeue_request(req);
+ list_add_tail(&req->queuelist, &gdrom_deferred);
+ schedule_work(&work);
+}
+
+static void gdrom_request(struct request_queue *rq)
+{
+ struct request *req;
+ while ((req = elv_next_request(rq)) != NULL) {
+ if (!blk_fs_request(req)) {
+ printk(KERN_DEBUG "GDROM: Non-fs request ignored\n");
+ end_request(req, 0);
+ }
+ if (rq_data_dir(req) != READ) {
+ printk(KERN_NOTICE "GDROM: Read only device - write request ignored\n");
+ end_request(req, 0);
+ }
+ if (req->nr_sectors)
+ gdrom_request_handler_dma(req);
+ else
+ end_request(req, 0);
+ }
+}
+
+/* Print string identifying GD ROM device */
+static int __devinit gdrom_outputversion(void)
+{
+ struct gdrom_id *id;
+ char *model_name, *manuf_name, *firmw_ver;
+ int err = -ENOMEM;
+ /* query device ID */
+ id = kzalloc(sizeof(struct gdrom_id), GFP_KERNEL);
+ if (!id)
+ return err;
+ gdrom_identifydevice(id);
+ model_name = kstrndup(id->modname, 16, GFP_KERNEL);
+ if (!model_name)
+ goto free_id;
+ manuf_name = kstrndup(id->mname, 16, GFP_KERNEL);
+ if (!manuf_name)
+ goto free_model_name;
+ firmw_ver = kstrndup(id->firmver, 16, GFP_KERNEL);
+ if (!firmw_ver)
+ goto free_manuf_name;
+ printk(KERN_INFO "GDROM: %s from %s with firmware %s\n", model_name, manuf_name, firmw_ver);
+ err = 0;
+ kfree(firmw_ver);
+free_manuf_name:
+ kfree(manuf_name);
+free_model_name:
+ kfree(model_name);
+free_id:
+ kfree(id);
+ return err;
+}
+
+/* set the default mode for DMA transfer */
+static void __devinit gdrom_init_dma_mode(void)
+{
+ ctrl_outb(0x13, GDROM_ERROR_REG);
+ ctrl_outb(0x22, GDROM_INTSEC_REG);
+ gdrom_wait_clrbusy();
+ ctrl_outb(0xEF, GDROM_STATUSCOMMAND_REG);
+ gdrom_wait_busy_sleeps();
+ ctrl_outl(0x8843407F, GDROM_DMA_ACCESS_CTRL_REG); /* memory setting */
+ ctrl_outl(9, GDROM_DMA_WAIT_REG); /* DMA word setting */
+}
+
+static void __devinit probe_gdrom_setupcd(void)
+{
+ gd.cd_info->ops = &gdrom_ops;
+ gd.cd_info->capacity = 1;
+ strcpy(gd.cd_info->name, GDROM_DEV_NAME);
+ gd.cd_info->mask = CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|CDC_SELECT_DISC;
+}
+
+static void __devinit probe_gdrom_setupdisk(void)
+{
+ gd.disk->major = gdrom_major;
+ gd.disk->first_minor = 1;
+ gd.disk->minors = 1;
+ strcpy(gd.disk->disk_name, GDROM_DEV_NAME);
+}
+
+static void __devinit probe_gdrom_setupqueue(void)
+{
+ blk_queue_hardsect_size(gd.gdrom_rq, GDROM_HARD_SECTOR);
+ /* using DMA so memory will need to be contiguous */
+ blk_queue_max_hw_segments(gd.gdrom_rq, 1);
+ /* set a large max size to get most from DMA */
+ blk_queue_max_segment_size(gd.gdrom_rq, 0x40000);
+ gd.disk->queue = gd.gdrom_rq;
+ gdrom_init_dma_mode();
+}
+
+/*
+ * register this as a block device and as compliant with the
+ * universal CD Rom driver interface
+ */
+static int __devinit probe_gdrom(struct platform_device *devptr)
+{
+ int err;
+ if (gdrom_execute_diagnostic() != 1) {
+ printk(KERN_WARNING "GDROM: ATA Probe for GDROM failed.\n");
+ return -ENODEV;
+ }
+ if (gdrom_outputversion())
+ return -ENOMEM;
+ gdrom_major = register_blkdev(0, GDROM_DEV_NAME);
+ if (gdrom_major <= 0)
+ return gdrom_major;
+ printk(KERN_INFO "GDROM: Block device is registered with major number %d\n", gdrom_major);
+ gd.cd_info = kzalloc(sizeof(struct cdrom_device_info), GFP_KERNEL);
+ if (!gd.cd_info) {
+ err = -ENOMEM;
+ goto probe_fail_no_mem;
+ }
+ probe_gdrom_setupcd();
+ gd.disk = alloc_disk(1);
+ if (!gd.disk) {
+ err = -ENODEV;
+ goto probe_fail_no_disk;
+ }
+ probe_gdrom_setupdisk();
+ if (register_cdrom(gd.cd_info)) {
+ err = -ENODEV;
+ goto probe_fail_cdrom_register;
+ }
+ gd.disk->fops = &gdrom_bdops;
+ /* latch on to the interrupt */
+ err = gdrom_set_command_interrupt_handler();
+ if (err)
+ goto probe_fail_cmdirq_register;
+ err = gdrom_set_dma_interrupt_handler();
+ if (err)
+ goto probe_fail_dmairq_register;
+ gd.gdrom_rq = blk_init_queue(gdrom_request, &gdrom_lock);
+ if (!gd.gdrom_rq)
+ goto probe_fail_requestq;
+ probe_gdrom_setupqueue();
+ add_disk(gd.disk);
+ return 0;
+
+probe_fail_requestq:
+ free_irq(HW_EVENT_GDROM_DMA, &gd);
+probe_fail_dmairq_register:
+ free_irq(HW_EVENT_GDROM_CMD, &gd);
+probe_fail_cmdirq_register:
+probe_fail_cdrom_register:
+ del_gendisk(gd.disk);
+probe_fail_no_disk:
+ kfree(gd.cd_info);
+ unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
+ gdrom_major = 0;
+probe_fail_no_mem:
+ printk(KERN_WARNING "GDROM: Could not probe for device - error is 0x%X\n", err);
+ return err;
+}
+
+static int remove_gdrom(struct platform_device *devptr)
+{
+ blk_cleanup_queue(gd.gdrom_rq);
+ free_irq(HW_EVENT_GDROM_CMD, &gd);
+ free_irq(HW_EVENT_GDROM_DMA, &gd);
+ del_gendisk(gd.disk);
+ if (gdrom_major)
+ unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
+ return unregister_cdrom(gd.cd_info);
+}
+
+static struct platform_driver gdrom_driver = {
+ .probe = probe_gdrom,
+ .remove = remove_gdrom,
+ .driver = {
+ .name = GDROM_DEV_NAME,
+ },
+};
+
+static int __init init_gdrom(void)
+{
+ int rc;
+ gd.toc = NULL;
+ rc = platform_driver_register(&gdrom_driver);
+ if (rc)
+ return rc;
+ pd = platform_device_register_simple(GDROM_DEV_NAME, -1, NULL, 0);
+ if (IS_ERR(pd)) {
+ platform_driver_unregister(&gdrom_driver);
+ return PTR_ERR(pd);
+ }
+ return 0;
+}
+
+static void __exit exit_gdrom(void)
+{
+ platform_device_unregister(pd);
+ platform_driver_unregister(&gdrom_driver);
+ kfree(gd.toc);
+}
+
+module_init(init_gdrom);
+module_exit(exit_gdrom);
+MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
+MODULE_DESCRIPTION("SEGA Dreamcast GD-ROM Driver");
+MODULE_LICENSE("GPL");
diff -rupN linux-2.6-orig/drivers/cdrom/Makefile linux-2.6/drivers/cdrom/Makefile
--- linux-2.6-orig/drivers/cdrom/Makefile 2007-12-26 17:27:15.000000000 +0000
+++ linux-2.6/drivers/cdrom/Makefile 2007-12-27 00:08:39.000000000 +0000
@@ -11,3 +11,4 @@ obj-$(CONFIG_PARIDE_PCD) += cdrom.o
obj-$(CONFIG_CDROM_PKTCDVD) += cdrom.o
obj-$(CONFIG_VIOCD) += viocd.o cdrom.o
+obj-$(CONFIG_GDROM) += gdrom.o cdrom.o
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-27 1:26 Adrian McMenamin
@ 2007-12-27 8:18 ` Paul Mundt
2007-12-27 12:49 ` Adrian McMenamin
2007-12-27 19:11 ` Mike Frysinger
0 siblings, 2 replies; 20+ messages in thread
From: Paul Mundt @ 2007-12-27 8:18 UTC (permalink / raw)
To: Adrian McMenamin; +Cc: Jens Axboe, linux-kernel, linux-sh
On Thu, Dec 27, 2007 at 01:26:47AM +0000, Adrian McMenamin wrote:
> This patch adds support for the CD-Rom drive on the SEGA Dreamcast.
>
Please fix your mailer to inline the patch, preferably without word
wrapping. This is not a difficult thing, send yourself some test mails
until you get it sorted out.
> diff -rupN linux-2.6-orig/drivers/block/Kconfig linux-2.6/drivers/block/Kconfig
> --- linux-2.6-orig/drivers/block/Kconfig 2007-12-26 17:27:14.000000000 +0000
> +++ linux-2.6/drivers/block/Kconfig 2007-12-27 00:08:39.000000000 +0000
> @@ -105,6 +105,18 @@ config PARIDE
> "MicroSolutions backpack protocol", "DataStor Commuter protocol"
> etc.).
>
> +config GDROM
Why is this using a tab?
> + tristate "SEGA Dreamcast GD-ROM drive"
> + depends on SH_DREAMCAST
> + help
> + A standard SEGA Dreamcast comes with a modified CD ROM drive called a
> + "GD-ROM" by SEGA to signify it is capable of reading special disks
> + with up to 1 GB of data. This drive will also read standard CD ROM
> + disks. Select this option to access any disks in your GD ROM drive.
> + Most users will want to say "Y" here.
> + You can also build this as a module which will be called gdrom.ko
> +
> +
Superfluous whitespace.
> +static int gdrom_get_last_session(struct cdrom_device_info *cd_info, struct cdrom_multisession *ms_info)
> +{
> + int fentry, lentry, track, data, tocuse, err;
> + kfree(gd.toc);
> + gd.toc = kzalloc(sizeof(struct gdromtoc), GFP_KERNEL);
Er, what? The size of this never changes, allocate it once, and just
overload it every time you step in to this function. There's no reason to
free it and reallocate every time. Shove it in your probe routine with
the rest of your kzallocs.
> +/* keep the function loioking like the universal CD Rom specification - returning int*/
looking.
> +static int gdrom_set_command_interrupt_handler(void)
> +{
> + /* need a queue to wait in */
> + init_waitqueue_head(&command_queue);
> + return request_irq(HW_EVENT_GDROM_CMD, gdrom_command_interrupt, IRQF_DISABLED, "gdrom_command", &gd);
> +}
> +
> +static int gdrom_set_dma_interrupt_handler(void)
> +{
> + init_waitqueue_head(&request_queue);
> + return request_irq(HW_EVENT_GDROM_DMA, gdrom_dma_interrupt, IRQF_DISABLED, "gdrom_dma", &gd);
> +}
> +
Having separate functions for these is pretty pointless.
> + spin_lock(&gdrom_lock);
> + list_for_each_safe(elem, next, &gdrom_deferred) {
> + req = list_entry(elem, struct request, queuelist);
> + spin_unlock(&gdrom_lock);
[snip]
> + /* now seek to take the request spinlock
> + * before handling ending the request */
> + spin_lock(&gdrom_lock);
> + list_del_init(&req->queuelist);
> + blk_requeue_request(gd.gdrom_rq, req);
> + if (err)
> + end_request(req, 0);
> + else
> + end_request(req, 1);
> + }
> + spin_unlock(&gdrom_lock);
> + kfree(read_command);
> +}
> +
This locking is all over the place. What is this lock supposed to be
accomplishing?
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-27 8:18 ` Paul Mundt
@ 2007-12-27 12:49 ` Adrian McMenamin
2007-12-27 19:52 ` Jens Axboe
2007-12-27 19:11 ` Mike Frysinger
1 sibling, 1 reply; 20+ messages in thread
From: Adrian McMenamin @ 2007-12-27 12:49 UTC (permalink / raw)
To: Paul Mundt; +Cc: Adrian McMenamin, Jens Axboe, linux-kernel, linux-sh
On Thu, 2007-12-27 at 17:18 +0900, Paul Mundt wrote:
> On Thu, Dec 27, 2007 at 01:26:47AM +0000, Adrian McMenamin wrote:
>
> > + /* now seek to take the request spinlock
> > + * before handling ending the request */
> > + spin_lock(&gdrom_lock);
> > + list_del_init(&req->queuelist);
> > + blk_requeue_request(gd.gdrom_rq, req);
> > + if (err)
> > + end_request(req, 0);
> > + else
> > + end_request(req, 1);
> > + }
> > + spin_unlock(&gdrom_lock);
> > + kfree(read_command);
> > +}
> > +
> This locking is all over the place. What is this lock supposed to be
> accomplishing?
> -
I have to hold the lock to access the request queue. As the linked list
of deferred requests is under the control of code also protected by the
lock, it is also held to ensure manipulation of that list is serialised.
The first step of the loop manipulates that linked list - so it is held
as we re-iterate over the loop.
This is pretty much the way Jens recommended I do it.
^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH] SH/Dreamcast - add support for GD-Rom device
@ 2007-12-27 16:52 Adrian McMenamin
2007-12-27 20:56 ` Adrian McMenamin
` (2 more replies)
0 siblings, 3 replies; 20+ messages in thread
From: Adrian McMenamin @ 2007-12-27 16:52 UTC (permalink / raw)
To: Paul Mundt, Jens Axboe; +Cc: LKML, linux-sh
This patch adds support for the CD-Rom drive on the SEGA Dreamcast.
The SEGA Dreamcast has a built in CD-Rom drive, electrically similar
to an ATA-3 drive, but implementing a proprietary packet interface -
the so-called Sega Packet Interface (SPI)- and also supporting a
proprietary format of disk - the Giga Disk Rom, with a 1GB capacity.
The drive is know as the "GD-Rom drive".
This patch partially implements the SPI and also supports reading GD
Rom disks. Unlike previous GD Rom drivers (which were never in the
mainline), this driver implements DMA and not PIO for reads. It is a
new driver, not a modified version of previous drivers.
This is the fifth iteration of this patch - which should work with
both 2.6-24-rc5 and Paul Mundt's 2.6.25 queue.
Signed-off by: Adrian McMenamin <adrian@mcmen.demon.co.uk>
----
diff -rupN linux-2.6-orig/drivers/block/Kconfig linux-2.6/drivers/block/Kconfig
--- linux-2.6-orig/drivers/block/Kconfig 2007-12-26 17:27:14.000000000 +0000
+++ linux-2.6/drivers/block/Kconfig 2007-12-27 16:39:05.000000000 +0000
@@ -105,6 +105,17 @@ config PARIDE
"MicroSolutions backpack protocol", "DataStor Commuter protocol"
etc.).
+config GDROM
+ tristate "SEGA Dreamcast GD-ROM drive"
+ depends on SH_DREAMCAST
+ help
+ A standard SEGA Dreamcast comes with a modified CD ROM drive called a
+ "GD-ROM" by SEGA to signify it is capable of reading special disks
+ with up to 1 GB of data. This drive will also read standard CD ROM
+ disks. Select this option to access any disks in your GD ROM drive.
+ Most users will want to say "Y" here.
+ You can also build this as a module which will be called gdrom.ko
+
source "drivers/block/paride/Kconfig"
config BLK_CPQ_DA
diff -rupN linux-2.6-orig/drivers/cdrom/gdrom.c linux-2.6/drivers/cdrom/gdrom.c
--- linux-2.6-orig/drivers/cdrom/gdrom.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6/drivers/cdrom/gdrom.c 2007-12-27 16:39:05.000000000 +0000
@@ -0,0 +1,776 @@
+/* GD ROM driver for the SEGA Dreamcast
+ * copyright Adrian McMenamin, 2007
+ * With thanks to Marcus Comstedt and Nathan Keynes
+ * for work in reversing PIO and DMA
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/cdrom.h>
+#include <linux/genhd.h>
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <scsi/scsi.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/delay.h>
+#include <asm/mach/dma.h>
+#include <asm/mach/sysasic.h>
+
+#define GDROM_DEV_NAME "gdrom"
+#define GD_SESSION_OFFSET 150
+
+/* GD Rom commands */
+#define GDROM_COM_SOFTRESET 0x08
+#define GDROM_COM_EXECDIAG 0x90
+#define GDROM_COM_PACKET 0xA0
+#define GDROM_COM_IDDEV 0xA1
+
+/* GD Rom registers */
+#define GDROM_BASE_REG 0xA05F7000
+#define GDROM_ALTSTATUS_REG (GDROM_BASE_REG + 0x18)
+#define GDROM_DATA_REG (GDROM_BASE_REG + 0x80)
+#define GDROM_ERROR_REG (GDROM_BASE_REG + 0x84)
+#define GDROM_INTSEC_REG (GDROM_BASE_REG + 0x88)
+#define GDROM_SECNUM_REG (GDROM_BASE_REG + 0x8C)
+#define GDROM_BCL_REG (GDROM_BASE_REG + 0x90)
+#define GDROM_BCH_REG (GDROM_BASE_REG + 0x94)
+#define GDROM_DSEL_REG (GDROM_BASE_REG + 0x98)
+#define GDROM_STATUSCOMMAND_REG (GDROM_BASE_REG + 0x9C)
+#define GDROM_RESET_REG (GDROM_BASE_REG + 0x4E4)
+
+#define GDROM_DMA_STARTADDR_REG (GDROM_BASE_REG + 0x404)
+#define GDROM_DMA_LENGTH_REG (GDROM_BASE_REG + 0x408)
+#define GDROM_DMA_DIRECTION_REG (GDROM_BASE_REG + 0x40C)
+#define GDROM_DMA_ENABLE_REG (GDROM_BASE_REG + 0x414)
+#define GDROM_DMA_STATUS_REG (GDROM_BASE_REG + 0x418)
+#define GDROM_DMA_WAIT_REG (GDROM_BASE_REG + 0x4A0)
+#define GDROM_DMA_ACCESS_CTRL_REG (GDROM_BASE_REG + 0x4B8)
+
+#define GDROM_HARD_SECTOR 2048
+#define BLOCK_LAYER_SECTOR 512
+#define GD_TO_BLK 4
+
+static const struct {
+ int sense_key;
+ const char * const text;
+} sense_texts[] = {
+ {NO_SENSE, "GDROM: OK"},
+ {RECOVERED_ERROR, "GDROM: Recovered from error"},
+ {NOT_READY, "GDROM: Device not ready"},
+ {MEDIUM_ERROR, "GDROM: Disk not ready"},
+ {HARDWARE_ERROR, "GDROM: Hardware error"},
+ {ILLEGAL_REQUEST, "GDROM: Command has failed"},
+ {UNIT_ATTENTION, "GDROM: Device needs attention - disk may have been changed"},
+ {DATA_PROTECT, "GDROM: Data protection error"},
+ {ABORTED_COMMAND, "GDROM: Command aborted"},
+};
+
+static struct platform_device *pd;
+static int gdrom_major;
+static wait_queue_head_t command_queue;
+static wait_queue_head_t request_queue;
+
+static DEFINE_SPINLOCK(gdrom_lock);
+static void gdrom_readdisk_dma(struct work_struct *work);
+static DECLARE_WORK(work, gdrom_readdisk_dma);
+static LIST_HEAD(gdrom_deferred);
+
+struct gdromtoc {
+ unsigned int entry[99];
+ unsigned int first, last;
+ unsigned int leadout;
+};
+
+static struct gdrom_unit {
+ struct gendisk *disk;
+ struct cdrom_device_info *cd_info;
+ int status;
+ int pending;
+ int transfer;
+ char disk_type;
+ struct gdromtoc *toc;
+ struct request_queue *gdrom_rq;
+} gd;
+
+struct gdrom_id {
+ char mid;
+ char modid;
+ char verid;
+ char padA[13];
+ char mname[16];
+ char modname[16];
+ char firmver[16];
+ char padB[16];
+};
+
+static int gdrom_getsense(short *bufstring);
+static int gdrom_packetcommand(struct cdrom_device_info *cd_info, struct packet_command *command);
+static int gdrom_hardreset(struct cdrom_device_info *cd_info);
+
+static void gdrom_wait_clrbusy(void)
+{
+ /* long timeouts - typical for a CD Rom */
+ unsigned long timeout = jiffies + HZ * 60;
+ while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) && (time_before(jiffies, timeout)))
+ cpu_relax();
+}
+
+static void gdrom_wait_busy_sleeps(void)
+{
+ unsigned long timeout;
+ /* Wait to get busy first */
+ timeout = jiffies + HZ * 60;
+ while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) == 0) && (time_before(jiffies, timeout)))
+ cpu_relax();
+ /* Now wait for busy to clear */
+ gdrom_wait_clrbusy();
+}
+
+static void gdrom_identifydevice(void *buf)
+{
+ int c;
+ short *data = buf;
+ gdrom_wait_clrbusy();
+ ctrl_outb(GDROM_COM_IDDEV, GDROM_STATUSCOMMAND_REG);
+ gdrom_wait_busy_sleeps();
+ /* now read in the data */
+ for (c = 0; c < 40; c++)
+ data[c] = ctrl_inw(GDROM_DATA_REG);
+}
+
+static void gdrom_spicommand(void *spi_string, int buflen)
+{
+ short *cmd = spi_string;
+ /* ensure IRQ_WAIT is set */
+ ctrl_outb(0x08, GDROM_ALTSTATUS_REG);
+ /* specify how many bytes we expect back */
+ ctrl_outb(buflen & 0xFF, GDROM_BCL_REG);
+ ctrl_outb((buflen >> 8) & 0xFF, GDROM_BCH_REG);
+ /* other parameters */
+ ctrl_outb(0, GDROM_INTSEC_REG);
+ ctrl_outb(0, GDROM_SECNUM_REG);
+ ctrl_outb(0, GDROM_ERROR_REG);
+ /* Wait until we can go */
+ gdrom_wait_clrbusy();
+ ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
+ while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) != 8)
+ cpu_relax(); /* wait for DRQ to be set to 1 */
+ outsw(PHYSADDR(GDROM_DATA_REG), cmd, 6);
+}
+
+/* gdrom_command_executediagnostic:
+ * Used to probe for presence of working GDROM
+ * Restarts GDROM device and then applies standard ATA 3
+ * Execute Diagnostic Command: a return of '1' indicates device 0
+ * present and device 1 absent
+ */
+static char gdrom_execute_diagnostic(void)
+{
+ gdrom_hardreset(gd.cd_info);
+ gdrom_wait_clrbusy();
+ ctrl_outb(GDROM_COM_EXECDIAG, GDROM_STATUSCOMMAND_REG);
+ gdrom_wait_busy_sleeps();
+ return ctrl_inb(GDROM_ERROR_REG);
+}
+
+/*
+ * Prepare disk command
+ * byte 0 = 0x70
+ * byte 1 = 0x1f
+ */
+static int gdrom_preparedisk_cmd(void)
+{
+ struct packet_command *spin_command;
+ spin_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
+ if (!spin_command)
+ return -ENOMEM;
+ spin_command->cmd[0] = 0x70;
+ spin_command->cmd[2] = 0x1f;
+ spin_command->buflen = 0;
+ gd.pending = 1;
+ gdrom_packetcommand(gd.cd_info, spin_command);
+ /* 60 second timeout */
+ wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
+ gd.pending = 0;
+ kfree(spin_command);
+ if (gd.status & 0x01) {
+ /* log an error */
+ gdrom_getsense(NULL);
+ return -EIO;
+ }
+ return 0;
+}
+
+/*
+ * Read TOC command
+ * byte 0 = 0x14
+ * byte 1 = session
+ * byte 3 = sizeof TOC >> 8 ie upper byte
+ * byte 4 = sizeof TOC & 0xff ie lower byte
+ */
+static int gdrom_readtoc_cmd(struct gdromtoc *toc, int session)
+{
+ int tocsize;
+ struct packet_command *toc_command;
+ toc_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
+ if (!toc_command)
+ return -ENOMEM;
+ tocsize = sizeof(struct gdromtoc);
+ toc_command->cmd[0] = 0x14;
+ toc_command->cmd[1] = session;
+ toc_command->cmd[3] = tocsize >> 8;
+ toc_command->cmd[4] = tocsize & 0xff;
+ toc_command->buflen = tocsize;
+ gd.pending = 1;
+ gdrom_packetcommand(gd.cd_info, toc_command);
+ wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
+ gd.pending = 0;
+ insw(PHYSADDR(GDROM_DATA_REG), toc, tocsize/2);
+ kfree(toc_command);
+ if (gd.status & 0x01)
+ return -EINVAL;
+ return 0;
+}
+
+/* TOC helpers */
+static int get_entry_lba(int track)
+{
+ return (cpu_to_be32(track & 0xffffff00) - GD_SESSION_OFFSET);
+}
+
+static int get_entry_q_ctrl(int track)
+{
+ return (track & 0x000000f0) >> 4;
+}
+
+static int get_entry_track(int track)
+{
+ return (track & 0x0000ff00) >> 8;
+}
+
+static int gdrom_get_last_session(struct cdrom_device_info *cd_info, struct cdrom_multisession *ms_info)
+{
+ int fentry, lentry, track, data, tocuse, err;
+ if (!gd.toc)
+ return -ENOMEM;
+ tocuse = 1;
+ /* Check if GD-ROM */
+ err = gdrom_readtoc_cmd(gd.toc, 1);
+ /* Not a GD-ROM so check if standard CD-ROM */
+ if (err) {
+ tocuse = 0;
+ err = gdrom_readtoc_cmd(gd.toc, 0);
+ if (err) {
+ printk(KERN_INFO "GDROM: Could not get CD table of contents\n");
+ return -ENXIO;
+ }
+ }
+
+ fentry = get_entry_track(gd.toc->first);
+ lentry = get_entry_track(gd.toc->last);
+ /* Find the first data track */
+ track = get_entry_track(gd.toc->last);
+ do {
+ data = gd.toc->entry[track - 1];
+ if (get_entry_q_ctrl(data))
+ break; /* ie a real data track */
+ track--;
+ } while (track >= fentry);
+
+ if ((track > 100) || (track < get_entry_track(gd.toc->first))) {
+ gdrom_getsense(NULL);
+ printk(KERN_INFO "GDROM: No data on the last session of the CD\n");
+ return -ENXIO;
+ }
+
+ ms_info->addr_format = CDROM_LBA;
+ ms_info->addr.lba = get_entry_lba(data);
+ ms_info->xa_flag = 1;
+ return 0;
+}
+
+static int gdrom_open(struct cdrom_device_info *cd_info, int purpose)
+{
+ /* spin up the disk */
+ return gdrom_preparedisk_cmd();
+}
+
+/* this function is required even if empty */
+static void gdrom_release(struct cdrom_device_info *cd_info)
+{
+}
+
+static int gdrom_drivestatus(struct cdrom_device_info *cd_info, int ignore)
+{
+ /* read the sense key */
+ char sense = ctrl_inb(GDROM_ERROR_REG);
+ sense &= 0xF0;
+ if (sense == 0)
+ return CDS_DISC_OK;
+ if (sense == 0x20)
+ return CDS_DRIVE_NOT_READY;
+ /* default */
+ return CDS_NO_INFO;
+}
+
+static int gdrom_mediachanged(struct cdrom_device_info *cd_info, int ignore)
+{
+ /* check the sense key */
+ return ((ctrl_inb(GDROM_ERROR_REG) & 0xF0) == 0x60);
+}
+
+/* reset the G1 bus */
+static int gdrom_hardreset(struct cdrom_device_info *cd_info)
+{
+ int count;
+ ctrl_outl(0x1fffff, GDROM_RESET_REG);
+ for (count = 0xa0000000; count < 0xa0200000; count += 4)
+ ctrl_inl(count);
+ return 0;
+}
+
+/* keep the function looking like the universal CD Rom specification - returning int*/
+static int gdrom_packetcommand(struct cdrom_device_info *cd_info, struct packet_command *command)
+{
+ gdrom_spicommand(&command->cmd, command->buflen);
+ return 0;
+}
+
+/* Get Sense SPI command
+ * From Marcus Comstedt
+ * cmd = 0x13
+ * cmd + 4 = length of returned buffer
+ * Returns 5 16 bit words
+ */
+static int gdrom_getsense(short *bufstring)
+{
+ struct packet_command *sense_command;
+ short sense[5];
+ int sense_key;
+ if (gd.pending)
+ return -EIO;
+
+ /* allocate command and buffer */
+ sense_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
+ if (!sense_command)
+ return -ENOMEM;
+
+ sense_command->cmd[0] = 0x13;
+ sense_command->cmd[4] = 10;
+ sense_command->buflen = 10;
+
+ gd.pending = 1;
+ gdrom_packetcommand(gd.cd_info, sense_command);
+ /* 60 second timeout */
+ wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
+ gd.pending = 0;
+ kfree(sense_command);
+ insw(PHYSADDR(GDROM_DATA_REG), &sense, 5);
+ if (sense[1] & 40) {
+ printk(KERN_INFO "GDROM: Drive not ready - command aborted\n");
+ return -EIO;
+ }
+ sense_key = sense[1] & 0x0F;
+ printk(KERN_INFO "%s\n", sense_texts[sense_key].text);
+
+ if (bufstring)
+ memcpy(bufstring, &sense[4], 2); /* return additional sense data */
+
+ if (sense_key < 2)
+ return 0;
+ return -EIO;
+}
+
+static struct cdrom_device_ops gdrom_ops = {
+ .open = gdrom_open,
+ .release = gdrom_release,
+ .drive_status = gdrom_drivestatus,
+ .media_changed = gdrom_mediachanged,
+ .get_last_session = gdrom_get_last_session,
+ .reset = gdrom_hardreset,
+ .capability = CDC_MULTI_SESSION | CDC_MEDIA_CHANGED |
+ CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R,
+ .n_minors = 1,
+};
+
+static int gdrom_bdops_open(struct inode *inode, struct file *file)
+{
+ return cdrom_open(gd.cd_info, inode, file);
+}
+
+static int gdrom_bdops_release(struct inode *inode, struct file *file)
+{
+ return cdrom_release(gd.cd_info, file);
+}
+
+static int gdrom_bdops_mediachanged(struct gendisk *disk)
+{
+ return cdrom_media_changed(gd.cd_info);
+}
+
+static int gdrom_bdops_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long arg)
+{
+ return cdrom_ioctl(file, gd.cd_info, inode, cmd, arg);
+}
+
+static struct block_device_operations gdrom_bdops = {
+ .owner = THIS_MODULE,
+ .open = gdrom_bdops_open,
+ .release = gdrom_bdops_release,
+ .media_changed = gdrom_bdops_mediachanged,
+ .ioctl = gdrom_bdops_ioctl,
+};
+
+static irqreturn_t gdrom_command_interrupt(int irq, void *dev_id)
+{
+ gd.status = ctrl_inb(GDROM_STATUSCOMMAND_REG);
+ if (gd.pending != 1)
+ return IRQ_HANDLED;
+ gd.pending = 0;
+ wake_up_interruptible(&command_queue);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t gdrom_dma_interrupt(int irq, void *dev_id)
+{
+ gd.status = ctrl_inb(GDROM_STATUSCOMMAND_REG);
+ if (gd.transfer != 1)
+ return IRQ_HANDLED;
+ gd.transfer = 0;
+ wake_up_interruptible(&request_queue);
+ return IRQ_HANDLED;
+}
+
+static int __devinit gdrom_set_interrupt_handlers(void)
+{
+ int err;
+ init_waitqueue_head(&command_queue);
+ err = request_irq(HW_EVENT_GDROM_CMD, gdrom_command_interrupt, IRQF_DISABLED, "gdrom_command", &gd);
+ if (err)
+ return err;
+ init_waitqueue_head(&request_queue);
+ err = request_irq(HW_EVENT_GDROM_DMA, gdrom_dma_interrupt, IRQF_DISABLED, "gdrom_dma", &gd);
+ if (err)
+ free_irq(HW_EVENT_GDROM_CMD, &gd);
+ return err;
+}
+
+/* Implement DMA read using SPI command
+ * 0 -> 0x30
+ * 1 -> mode
+ * 2 -> block >> 16
+ * 3 -> block >> 8
+ * 4 -> block
+ * 8 -> sectors >> 16
+ * 9 -> sectors >> 8
+ * 10 -> sectors
+ */
+static void gdrom_readdisk_dma(struct work_struct *work)
+{
+ int err, block, block_cnt;
+ struct packet_command *read_command;
+ struct list_head *elem, *next;
+ struct request *req;
+ unsigned long timeout;
+ if (list_empty(&gdrom_deferred))
+ return;
+ read_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
+ if (!read_command)
+ return; /* get more memory later? */
+ read_command->cmd[0] = 0x30;
+ read_command->cmd[1] = 0x20;
+ spin_lock(&gdrom_lock);
+ list_for_each_safe(elem, next, &gdrom_deferred) {
+ req = list_entry(elem, struct request, queuelist);
+ spin_unlock(&gdrom_lock);
+ block = req->sector/GD_TO_BLK + GD_SESSION_OFFSET;
+ block_cnt = req->nr_sectors/GD_TO_BLK;
+ ctrl_outl(PHYSADDR(req->buffer), GDROM_DMA_STARTADDR_REG);
+ ctrl_outl(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG);
+ ctrl_outl(1, GDROM_DMA_DIRECTION_REG);
+ ctrl_outl(1, GDROM_DMA_ENABLE_REG);
+ read_command->cmd[2] = (block >> 16) & 0xFF;
+ read_command->cmd[3] = (block >> 8) & 0xFF;
+ read_command->cmd[4] = block & 0xFF;
+ read_command->cmd[8] = (block_cnt >> 16) & 0xFF;
+ read_command->cmd[9] = (block_cnt >> 8) & 0xFF;
+ read_command->cmd[10] = block_cnt & 0xFF;
+ /* set for DMA */
+ ctrl_outb(1, GDROM_ERROR_REG);
+ /* other registers */
+ ctrl_outb(0, GDROM_SECNUM_REG);
+ ctrl_outb(0, GDROM_BCL_REG);
+ ctrl_outb(0, GDROM_BCH_REG);
+ ctrl_outb(0, GDROM_DSEL_REG);
+ ctrl_outb(0, GDROM_INTSEC_REG);
+ /* In multiple DMA transfers need to wait */
+ timeout = jiffies + HZ / 2;
+ while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) && (time_before(jiffies, timeout)))
+ cpu_relax();
+ ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
+ timeout = jiffies + HZ / 2;
+ while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) != 8) && (time_before(jiffies, timeout)))
+ cpu_relax(); /* wait for DRQ to be set to 1 */
+ gd.pending = 1;
+ gd.transfer = 1;
+ outsw(PHYSADDR(GDROM_DATA_REG), &read_command->cmd, 6);
+ timeout = jiffies + HZ / 2;
+ while ((ctrl_inb(GDROM_DMA_STATUS_REG)) && (time_before(jiffies, timeout)))
+ cpu_relax();
+ ctrl_outb(1, GDROM_DMA_STATUS_REG);
+ /* 5 second error margin here seems more reasonable */
+ wait_event_interruptible_timeout(request_queue, gd.transfer == 0, HZ * 5);
+ err = ctrl_inb(GDROM_DMA_STATUS_REG);
+ err = gd.transfer;
+ gd.transfer = 0;
+ gd.pending = 0;
+ /* now seek to take the request spinlock
+ * before handling ending the request */
+ spin_lock(&gdrom_lock);
+ list_del_init(&req->queuelist);
+ blk_requeue_request(gd.gdrom_rq, req);
+ if (err)
+ end_request(req, 0);
+ else
+ end_request(req, 1);
+ }
+ spin_unlock(&gdrom_lock);
+ kfree(read_command);
+}
+
+static void gdrom_request_handler_dma(struct request *req)
+{
+ /* dequeue, add to list of deferred work
+ * and then schedule workqueue */
+ blkdev_dequeue_request(req);
+ list_add_tail(&req->queuelist, &gdrom_deferred);
+ schedule_work(&work);
+}
+
+static void gdrom_request(struct request_queue *rq)
+{
+ struct request *req;
+ while ((req = elv_next_request(rq)) != NULL) {
+ if (!blk_fs_request(req)) {
+ printk(KERN_DEBUG "GDROM: Non-fs request ignored\n");
+ end_request(req, 0);
+ }
+ if (rq_data_dir(req) != READ) {
+ printk(KERN_NOTICE "GDROM: Read only device - write request ignored\n");
+ end_request(req, 0);
+ }
+ if (req->nr_sectors)
+ gdrom_request_handler_dma(req);
+ else
+ end_request(req, 0);
+ }
+}
+
+/* Print string identifying GD ROM device */
+static int __devinit gdrom_outputversion(void)
+{
+ struct gdrom_id *id;
+ char *model_name, *manuf_name, *firmw_ver;
+ int err = -ENOMEM;
+ /* query device ID */
+ id = kzalloc(sizeof(struct gdrom_id), GFP_KERNEL);
+ if (!id)
+ return err;
+ gdrom_identifydevice(id);
+ model_name = kstrndup(id->modname, 16, GFP_KERNEL);
+ if (!model_name)
+ goto free_id;
+ manuf_name = kstrndup(id->mname, 16, GFP_KERNEL);
+ if (!manuf_name)
+ goto free_model_name;
+ firmw_ver = kstrndup(id->firmver, 16, GFP_KERNEL);
+ if (!firmw_ver)
+ goto free_manuf_name;
+ printk(KERN_INFO "GDROM: %s from %s with firmware %s\n", model_name, manuf_name, firmw_ver);
+ err = 0;
+ kfree(firmw_ver);
+free_manuf_name:
+ kfree(manuf_name);
+free_model_name:
+ kfree(model_name);
+free_id:
+ kfree(id);
+ return err;
+}
+
+/* set the default mode for DMA transfer */
+static void __devinit gdrom_init_dma_mode(void)
+{
+ ctrl_outb(0x13, GDROM_ERROR_REG);
+ ctrl_outb(0x22, GDROM_INTSEC_REG);
+ gdrom_wait_clrbusy();
+ ctrl_outb(0xEF, GDROM_STATUSCOMMAND_REG);
+ gdrom_wait_busy_sleeps();
+ ctrl_outl(0x8843407F, GDROM_DMA_ACCESS_CTRL_REG); /* memory setting */
+ ctrl_outl(9, GDROM_DMA_WAIT_REG); /* DMA word setting */
+}
+
+static void __devinit probe_gdrom_setupcd(void)
+{
+ gd.cd_info->ops = &gdrom_ops;
+ gd.cd_info->capacity = 1;
+ strcpy(gd.cd_info->name, GDROM_DEV_NAME);
+ gd.cd_info->mask = CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|CDC_SELECT_DISC;
+}
+
+static void __devinit probe_gdrom_setupdisk(void)
+{
+ gd.disk->major = gdrom_major;
+ gd.disk->first_minor = 1;
+ gd.disk->minors = 1;
+ strcpy(gd.disk->disk_name, GDROM_DEV_NAME);
+}
+
+static void __devinit probe_gdrom_setupqueue(void)
+{
+ blk_queue_hardsect_size(gd.gdrom_rq, GDROM_HARD_SECTOR);
+ /* using DMA so memory will need to be contiguous */
+ blk_queue_max_hw_segments(gd.gdrom_rq, 1);
+ /* set a large max size to get most from DMA */
+ blk_queue_max_segment_size(gd.gdrom_rq, 0x40000);
+ gd.disk->queue = gd.gdrom_rq;
+ gdrom_init_dma_mode();
+}
+
+/*
+ * register this as a block device and as compliant with the
+ * universal CD Rom driver interface
+ */
+static int __devinit probe_gdrom(struct platform_device *devptr)
+{
+ int err;
+ if (gdrom_execute_diagnostic() != 1) {
+ printk(KERN_WARNING "GDROM: ATA Probe for GDROM failed.\n");
+ return -ENODEV;
+ }
+ if (gdrom_outputversion())
+ return -ENOMEM;
+ gdrom_major = register_blkdev(0, GDROM_DEV_NAME);
+ if (gdrom_major <= 0)
+ return gdrom_major;
+ printk(KERN_INFO "GDROM: Block device is registered with major number %d\n", gdrom_major);
+ gd.cd_info = kzalloc(sizeof(struct cdrom_device_info), GFP_KERNEL);
+ if (!gd.cd_info) {
+ err = -ENOMEM;
+ goto probe_fail_no_mem;
+ }
+ probe_gdrom_setupcd();
+ gd.disk = alloc_disk(1);
+ if (!gd.disk) {
+ err = -ENODEV;
+ goto probe_fail_no_disk;
+ }
+ probe_gdrom_setupdisk();
+ if (register_cdrom(gd.cd_info)) {
+ err = -ENODEV;
+ goto probe_fail_cdrom_register;
+ }
+ gd.disk->fops = &gdrom_bdops;
+ /* latch on to the interrupt */
+ err = gdrom_set_interrupt_handlers();
+ if (err)
+ goto probe_fail_cmdirq_register;
+ gd.gdrom_rq = blk_init_queue(gdrom_request, &gdrom_lock);
+ if (!gd.gdrom_rq)
+ goto probe_fail_requestq;
+ probe_gdrom_setupqueue();
+ gd.toc = kzalloc(sizeof(struct gdromtoc), GFP_KERNEL);
+ if (!gd.toc)
+ goto probe_fail_toc;
+ add_disk(gd.disk);
+ return 0;
+
+probe_fail_toc:
+ blk_cleanup_queue(gd.gdrom_rq);
+probe_fail_requestq:
+ free_irq(HW_EVENT_GDROM_DMA, &gd);
+ free_irq(HW_EVENT_GDROM_CMD, &gd);
+probe_fail_cmdirq_register:
+probe_fail_cdrom_register:
+ del_gendisk(gd.disk);
+probe_fail_no_disk:
+ kfree(gd.cd_info);
+ unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
+ gdrom_major = 0;
+probe_fail_no_mem:
+ printk(KERN_WARNING "GDROM: Could not probe for device - error is 0x%X\n", err);
+ return err;
+}
+
+static int remove_gdrom(struct platform_device *devptr)
+{
+ blk_cleanup_queue(gd.gdrom_rq);
+ free_irq(HW_EVENT_GDROM_CMD, &gd);
+ free_irq(HW_EVENT_GDROM_DMA, &gd);
+ del_gendisk(gd.disk);
+ if (gdrom_major)
+ unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
+ return unregister_cdrom(gd.cd_info);
+}
+
+static struct platform_driver gdrom_driver = {
+ .probe = probe_gdrom,
+ .remove = remove_gdrom,
+ .driver = {
+ .name = GDROM_DEV_NAME,
+ },
+};
+
+static int __init init_gdrom(void)
+{
+ int rc;
+ gd.toc = NULL;
+ rc = platform_driver_register(&gdrom_driver);
+ if (rc)
+ return rc;
+ pd = platform_device_register_simple(GDROM_DEV_NAME, -1, NULL, 0);
+ if (IS_ERR(pd)) {
+ platform_driver_unregister(&gdrom_driver);
+ return PTR_ERR(pd);
+ }
+ return 0;
+}
+
+static void __exit exit_gdrom(void)
+{
+ platform_device_unregister(pd);
+ platform_driver_unregister(&gdrom_driver);
+ kfree(gd.toc);
+}
+
+module_init(init_gdrom);
+module_exit(exit_gdrom);
+MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
+MODULE_DESCRIPTION("SEGA Dreamcast GD-ROM Driver");
+MODULE_LICENSE("GPL");
diff -rupN linux-2.6-orig/drivers/cdrom/Makefile linux-2.6/drivers/cdrom/Makefile
--- linux-2.6-orig/drivers/cdrom/Makefile 2007-12-26 17:27:15.000000000 +0000
+++ linux-2.6/drivers/cdrom/Makefile 2007-12-27 00:08:39.000000000 +0000
@@ -11,3 +11,4 @@ obj-$(CONFIG_PARIDE_PCD) += cdrom.o
obj-$(CONFIG_CDROM_PKTCDVD) += cdrom.o
obj-$(CONFIG_VIOCD) += viocd.o cdrom.o
+obj-$(CONFIG_GDROM) += gdrom.o cdrom.o
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-27 8:18 ` Paul Mundt
2007-12-27 12:49 ` Adrian McMenamin
@ 2007-12-27 19:11 ` Mike Frysinger
1 sibling, 0 replies; 20+ messages in thread
From: Mike Frysinger @ 2007-12-27 19:11 UTC (permalink / raw)
To: Paul Mundt; +Cc: Adrian McMenamin, Jens Axboe, linux-kernel, linux-sh
[-- Attachment #1: Type: text/plain, Size: 686 bytes --]
On Thursday 27 December 2007, Paul Mundt wrote:
> On Thu, Dec 27, 2007 at 01:26:47AM +0000, Adrian McMenamin wrote:
> > +static int gdrom_get_last_session(struct cdrom_device_info *cd_info,
> > struct cdrom_multisession *ms_info) +{
> > + int fentry, lentry, track, data, tocuse, err;
> > + kfree(gd.toc);
> > + gd.toc = kzalloc(sizeof(struct gdromtoc), GFP_KERNEL);
>
> Er, what? The size of this never changes, allocate it once, and just
> overload it every time you step in to this function. There's no reason to
> free it and reallocate every time. Shove it in your probe routine with
> the rest of your kzallocs.
since gd is a global, just dont declare toc as a pointer ...
-mike
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 835 bytes --]
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-27 12:49 ` Adrian McMenamin
@ 2007-12-27 19:52 ` Jens Axboe
0 siblings, 0 replies; 20+ messages in thread
From: Jens Axboe @ 2007-12-27 19:52 UTC (permalink / raw)
To: Adrian McMenamin; +Cc: Paul Mundt, Adrian McMenamin, linux-kernel, linux-sh
On Thu, Dec 27 2007, Adrian McMenamin wrote:
>
> On Thu, 2007-12-27 at 17:18 +0900, Paul Mundt wrote:
> > On Thu, Dec 27, 2007 at 01:26:47AM +0000, Adrian McMenamin wrote:
>
> >
> > > + /* now seek to take the request spinlock
> > > + * before handling ending the request */
> > > + spin_lock(&gdrom_lock);
> > > + list_del_init(&req->queuelist);
> > > + blk_requeue_request(gd.gdrom_rq, req);
> > > + if (err)
> > > + end_request(req, 0);
> > > + else
> > > + end_request(req, 1);
> > > + }
> > > + spin_unlock(&gdrom_lock);
> > > + kfree(read_command);
> > > +}
> > > +
> > This locking is all over the place. What is this lock supposed to be
> > accomplishing?
> > -
>
> I have to hold the lock to access the request queue. As the linked list
> of deferred requests is under the control of code also protected by the
> lock, it is also held to ensure manipulation of that list is serialised.
>
> The first step of the loop manipulates that linked list - so it is held
> as we re-iterate over the loop.
>
> This is pretty much the way Jens recommended I do it.
I didn't recommend the last requeue bit, it looks like a work-around due
to the way that end_request() works. The kerneldoc comment for that
function also tells you NOT to use this in new code. Use
end_dequeued_request() and get rid of the requeue, and streamline 'err'
so you can just pass it directly in.
The locking otherwise looks fine to me.
--
Jens Axboe
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-27 16:52 [PATCH] SH/Dreamcast - add support for GD-Rom device Adrian McMenamin
@ 2007-12-27 20:56 ` Adrian McMenamin
2007-12-27 22:20 ` Paul Mundt
2007-12-27 22:58 ` Joe Perches
2 siblings, 0 replies; 20+ messages in thread
From: Adrian McMenamin @ 2007-12-27 20:56 UTC (permalink / raw)
To: Paul Mundt; +Cc: Jens Axboe, LKML, linux-sh
On Thu, 2007-12-27 at 16:52 +0000, Adrian McMenamin wrote:
> This patch adds support for the CD-Rom drive on the SEGA Dreamcast.
>
> The SEGA Dreamcast has a built in CD-Rom drive, electrically similar
> to an ATA-3 drive, but implementing a proprietary packet interface -
> the so-called Sega Packet Interface (SPI)- and also supporting a
> proprietary format of disk - the Giga Disk Rom, with a 1GB capacity.
> The drive is know as the "GD-Rom drive".
>
> This patch partially implements the SPI and also supports reading GD
> Rom disks. Unlike previous GD Rom drivers (which were never in the
> mainline), this driver implements DMA and not PIO for reads. It is a
> new driver, not a modified version of previous drivers.
>
> This is the fifth iteration of this patch - which should work with
> both 2.6-24-rc5 and Paul Mundt's 2.6.25 queue.
>
> Signed-off by: Adrian McMenamin <adrian@mcmen.demon.co.uk>
>
> ----
>
Following up on more comments, here is a slightly reworked version of
the patch with better request handling.
Signed-off by: Adrian McMenamin <adrian@mcmen.demon.co.uk>
----
diff -rupN linux-2.6-orig/drivers/block/Kconfig linux-2.6/drivers/block/Kconfig
--- linux-2.6-orig/drivers/block/Kconfig 2007-12-26 17:27:14.000000000 +0000
+++ linux-2.6/drivers/block/Kconfig 2007-12-27 16:39:05.000000000 +0000
@@ -105,6 +105,17 @@ config PARIDE
"MicroSolutions backpack protocol", "DataStor Commuter protocol"
etc.).
+config GDROM
+ tristate "SEGA Dreamcast GD-ROM drive"
+ depends on SH_DREAMCAST
+ help
+ A standard SEGA Dreamcast comes with a modified CD ROM drive called a
+ "GD-ROM" by SEGA to signify it is capable of reading special disks
+ with up to 1 GB of data. This drive will also read standard CD ROM
+ disks. Select this option to access any disks in your GD ROM drive.
+ Most users will want to say "Y" here.
+ You can also build this as a module which will be called gdrom.ko
+
source "drivers/block/paride/Kconfig"
config BLK_CPQ_DA
diff -rupN linux-2.6-orig/drivers/cdrom/gdrom.c linux-2.6/drivers/cdrom/gdrom.c
--- linux-2.6-orig/drivers/cdrom/gdrom.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6/drivers/cdrom/gdrom.c 2007-12-27 20:45:18.000000000 +0000
@@ -0,0 +1,772 @@
+/* GD ROM driver for the SEGA Dreamcast
+ * copyright Adrian McMenamin, 2007
+ * With thanks to Marcus Comstedt and Nathan Keynes
+ * for work in reversing PIO and DMA
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/cdrom.h>
+#include <linux/genhd.h>
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <scsi/scsi.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/delay.h>
+#include <asm/mach/dma.h>
+#include <asm/mach/sysasic.h>
+
+#define GDROM_DEV_NAME "gdrom"
+#define GD_SESSION_OFFSET 150
+
+/* GD Rom commands */
+#define GDROM_COM_SOFTRESET 0x08
+#define GDROM_COM_EXECDIAG 0x90
+#define GDROM_COM_PACKET 0xA0
+#define GDROM_COM_IDDEV 0xA1
+
+/* GD Rom registers */
+#define GDROM_BASE_REG 0xA05F7000
+#define GDROM_ALTSTATUS_REG (GDROM_BASE_REG + 0x18)
+#define GDROM_DATA_REG (GDROM_BASE_REG + 0x80)
+#define GDROM_ERROR_REG (GDROM_BASE_REG + 0x84)
+#define GDROM_INTSEC_REG (GDROM_BASE_REG + 0x88)
+#define GDROM_SECNUM_REG (GDROM_BASE_REG + 0x8C)
+#define GDROM_BCL_REG (GDROM_BASE_REG + 0x90)
+#define GDROM_BCH_REG (GDROM_BASE_REG + 0x94)
+#define GDROM_DSEL_REG (GDROM_BASE_REG + 0x98)
+#define GDROM_STATUSCOMMAND_REG (GDROM_BASE_REG + 0x9C)
+#define GDROM_RESET_REG (GDROM_BASE_REG + 0x4E4)
+
+#define GDROM_DMA_STARTADDR_REG (GDROM_BASE_REG + 0x404)
+#define GDROM_DMA_LENGTH_REG (GDROM_BASE_REG + 0x408)
+#define GDROM_DMA_DIRECTION_REG (GDROM_BASE_REG + 0x40C)
+#define GDROM_DMA_ENABLE_REG (GDROM_BASE_REG + 0x414)
+#define GDROM_DMA_STATUS_REG (GDROM_BASE_REG + 0x418)
+#define GDROM_DMA_WAIT_REG (GDROM_BASE_REG + 0x4A0)
+#define GDROM_DMA_ACCESS_CTRL_REG (GDROM_BASE_REG + 0x4B8)
+
+#define GDROM_HARD_SECTOR 2048
+#define BLOCK_LAYER_SECTOR 512
+#define GD_TO_BLK 4
+
+static const struct {
+ int sense_key;
+ const char * const text;
+} sense_texts[] = {
+ {NO_SENSE, "GDROM: OK"},
+ {RECOVERED_ERROR, "GDROM: Recovered from error"},
+ {NOT_READY, "GDROM: Device not ready"},
+ {MEDIUM_ERROR, "GDROM: Disk not ready"},
+ {HARDWARE_ERROR, "GDROM: Hardware error"},
+ {ILLEGAL_REQUEST, "GDROM: Command has failed"},
+ {UNIT_ATTENTION, "GDROM: Device needs attention - disk may have been changed"},
+ {DATA_PROTECT, "GDROM: Data protection error"},
+ {ABORTED_COMMAND, "GDROM: Command aborted"},
+};
+
+static struct platform_device *pd;
+static int gdrom_major;
+static wait_queue_head_t command_queue;
+static wait_queue_head_t request_queue;
+
+static DEFINE_SPINLOCK(gdrom_lock);
+static void gdrom_readdisk_dma(struct work_struct *work);
+static DECLARE_WORK(work, gdrom_readdisk_dma);
+static LIST_HEAD(gdrom_deferred);
+
+struct gdromtoc {
+ unsigned int entry[99];
+ unsigned int first, last;
+ unsigned int leadout;
+};
+
+static struct gdrom_unit {
+ struct gendisk *disk;
+ struct cdrom_device_info *cd_info;
+ int status;
+ int pending;
+ int transfer;
+ char disk_type;
+ struct gdromtoc *toc;
+ struct request_queue *gdrom_rq;
+} gd;
+
+struct gdrom_id {
+ char mid;
+ char modid;
+ char verid;
+ char padA[13];
+ char mname[16];
+ char modname[16];
+ char firmver[16];
+ char padB[16];
+};
+
+static int gdrom_getsense(short *bufstring);
+static int gdrom_packetcommand(struct cdrom_device_info *cd_info, struct packet_command *command);
+static int gdrom_hardreset(struct cdrom_device_info *cd_info);
+
+static void gdrom_wait_clrbusy(void)
+{
+ /* long timeouts - typical for a CD Rom */
+ unsigned long timeout = jiffies + HZ * 60;
+ while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) && (time_before(jiffies, timeout)))
+ cpu_relax();
+}
+
+static void gdrom_wait_busy_sleeps(void)
+{
+ unsigned long timeout;
+ /* Wait to get busy first */
+ timeout = jiffies + HZ * 60;
+ while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) == 0) && (time_before(jiffies, timeout)))
+ cpu_relax();
+ /* Now wait for busy to clear */
+ gdrom_wait_clrbusy();
+}
+
+static void gdrom_identifydevice(void *buf)
+{
+ int c;
+ short *data = buf;
+ gdrom_wait_clrbusy();
+ ctrl_outb(GDROM_COM_IDDEV, GDROM_STATUSCOMMAND_REG);
+ gdrom_wait_busy_sleeps();
+ /* now read in the data */
+ for (c = 0; c < 40; c++)
+ data[c] = ctrl_inw(GDROM_DATA_REG);
+}
+
+static void gdrom_spicommand(void *spi_string, int buflen)
+{
+ short *cmd = spi_string;
+ /* ensure IRQ_WAIT is set */
+ ctrl_outb(0x08, GDROM_ALTSTATUS_REG);
+ /* specify how many bytes we expect back */
+ ctrl_outb(buflen & 0xFF, GDROM_BCL_REG);
+ ctrl_outb((buflen >> 8) & 0xFF, GDROM_BCH_REG);
+ /* other parameters */
+ ctrl_outb(0, GDROM_INTSEC_REG);
+ ctrl_outb(0, GDROM_SECNUM_REG);
+ ctrl_outb(0, GDROM_ERROR_REG);
+ /* Wait until we can go */
+ gdrom_wait_clrbusy();
+ ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
+ while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) != 8)
+ cpu_relax(); /* wait for DRQ to be set to 1 */
+ outsw(PHYSADDR(GDROM_DATA_REG), cmd, 6);
+}
+
+/* gdrom_command_executediagnostic:
+ * Used to probe for presence of working GDROM
+ * Restarts GDROM device and then applies standard ATA 3
+ * Execute Diagnostic Command: a return of '1' indicates device 0
+ * present and device 1 absent
+ */
+static char gdrom_execute_diagnostic(void)
+{
+ gdrom_hardreset(gd.cd_info);
+ gdrom_wait_clrbusy();
+ ctrl_outb(GDROM_COM_EXECDIAG, GDROM_STATUSCOMMAND_REG);
+ gdrom_wait_busy_sleeps();
+ return ctrl_inb(GDROM_ERROR_REG);
+}
+
+/*
+ * Prepare disk command
+ * byte 0 = 0x70
+ * byte 1 = 0x1f
+ */
+static int gdrom_preparedisk_cmd(void)
+{
+ struct packet_command *spin_command;
+ spin_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
+ if (!spin_command)
+ return -ENOMEM;
+ spin_command->cmd[0] = 0x70;
+ spin_command->cmd[2] = 0x1f;
+ spin_command->buflen = 0;
+ gd.pending = 1;
+ gdrom_packetcommand(gd.cd_info, spin_command);
+ /* 60 second timeout */
+ wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
+ gd.pending = 0;
+ kfree(spin_command);
+ if (gd.status & 0x01) {
+ /* log an error */
+ gdrom_getsense(NULL);
+ return -EIO;
+ }
+ return 0;
+}
+
+/*
+ * Read TOC command
+ * byte 0 = 0x14
+ * byte 1 = session
+ * byte 3 = sizeof TOC >> 8 ie upper byte
+ * byte 4 = sizeof TOC & 0xff ie lower byte
+ */
+static int gdrom_readtoc_cmd(struct gdromtoc *toc, int session)
+{
+ int tocsize;
+ struct packet_command *toc_command;
+ toc_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
+ if (!toc_command)
+ return -ENOMEM;
+ tocsize = sizeof(struct gdromtoc);
+ toc_command->cmd[0] = 0x14;
+ toc_command->cmd[1] = session;
+ toc_command->cmd[3] = tocsize >> 8;
+ toc_command->cmd[4] = tocsize & 0xff;
+ toc_command->buflen = tocsize;
+ gd.pending = 1;
+ gdrom_packetcommand(gd.cd_info, toc_command);
+ wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
+ gd.pending = 0;
+ insw(PHYSADDR(GDROM_DATA_REG), toc, tocsize/2);
+ kfree(toc_command);
+ if (gd.status & 0x01)
+ return -EINVAL;
+ return 0;
+}
+
+/* TOC helpers */
+static int get_entry_lba(int track)
+{
+ return (cpu_to_be32(track & 0xffffff00) - GD_SESSION_OFFSET);
+}
+
+static int get_entry_q_ctrl(int track)
+{
+ return (track & 0x000000f0) >> 4;
+}
+
+static int get_entry_track(int track)
+{
+ return (track & 0x0000ff00) >> 8;
+}
+
+static int gdrom_get_last_session(struct cdrom_device_info *cd_info, struct cdrom_multisession *ms_info)
+{
+ int fentry, lentry, track, data, tocuse, err;
+ if (!gd.toc)
+ return -ENOMEM;
+ tocuse = 1;
+ /* Check if GD-ROM */
+ err = gdrom_readtoc_cmd(gd.toc, 1);
+ /* Not a GD-ROM so check if standard CD-ROM */
+ if (err) {
+ tocuse = 0;
+ err = gdrom_readtoc_cmd(gd.toc, 0);
+ if (err) {
+ printk(KERN_INFO "GDROM: Could not get CD table of contents\n");
+ return -ENXIO;
+ }
+ }
+
+ fentry = get_entry_track(gd.toc->first);
+ lentry = get_entry_track(gd.toc->last);
+ /* Find the first data track */
+ track = get_entry_track(gd.toc->last);
+ do {
+ data = gd.toc->entry[track - 1];
+ if (get_entry_q_ctrl(data))
+ break; /* ie a real data track */
+ track--;
+ } while (track >= fentry);
+
+ if ((track > 100) || (track < get_entry_track(gd.toc->first))) {
+ gdrom_getsense(NULL);
+ printk(KERN_INFO "GDROM: No data on the last session of the CD\n");
+ return -ENXIO;
+ }
+
+ ms_info->addr_format = CDROM_LBA;
+ ms_info->addr.lba = get_entry_lba(data);
+ ms_info->xa_flag = 1;
+ return 0;
+}
+
+static int gdrom_open(struct cdrom_device_info *cd_info, int purpose)
+{
+ /* spin up the disk */
+ return gdrom_preparedisk_cmd();
+}
+
+/* this function is required even if empty */
+static void gdrom_release(struct cdrom_device_info *cd_info)
+{
+}
+
+static int gdrom_drivestatus(struct cdrom_device_info *cd_info, int ignore)
+{
+ /* read the sense key */
+ char sense = ctrl_inb(GDROM_ERROR_REG);
+ sense &= 0xF0;
+ if (sense == 0)
+ return CDS_DISC_OK;
+ if (sense == 0x20)
+ return CDS_DRIVE_NOT_READY;
+ /* default */
+ return CDS_NO_INFO;
+}
+
+static int gdrom_mediachanged(struct cdrom_device_info *cd_info, int ignore)
+{
+ /* check the sense key */
+ return ((ctrl_inb(GDROM_ERROR_REG) & 0xF0) == 0x60);
+}
+
+/* reset the G1 bus */
+static int gdrom_hardreset(struct cdrom_device_info *cd_info)
+{
+ int count;
+ ctrl_outl(0x1fffff, GDROM_RESET_REG);
+ for (count = 0xa0000000; count < 0xa0200000; count += 4)
+ ctrl_inl(count);
+ return 0;
+}
+
+/* keep the function looking like the universal CD Rom specification - returning int*/
+static int gdrom_packetcommand(struct cdrom_device_info *cd_info, struct packet_command *command)
+{
+ gdrom_spicommand(&command->cmd, command->buflen);
+ return 0;
+}
+
+/* Get Sense SPI command
+ * From Marcus Comstedt
+ * cmd = 0x13
+ * cmd + 4 = length of returned buffer
+ * Returns 5 16 bit words
+ */
+static int gdrom_getsense(short *bufstring)
+{
+ struct packet_command *sense_command;
+ short sense[5];
+ int sense_key;
+ if (gd.pending)
+ return -EIO;
+
+ /* allocate command and buffer */
+ sense_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
+ if (!sense_command)
+ return -ENOMEM;
+
+ sense_command->cmd[0] = 0x13;
+ sense_command->cmd[4] = 10;
+ sense_command->buflen = 10;
+
+ gd.pending = 1;
+ gdrom_packetcommand(gd.cd_info, sense_command);
+ /* 60 second timeout */
+ wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
+ gd.pending = 0;
+ kfree(sense_command);
+ insw(PHYSADDR(GDROM_DATA_REG), &sense, 5);
+ if (sense[1] & 40) {
+ printk(KERN_INFO "GDROM: Drive not ready - command aborted\n");
+ return -EIO;
+ }
+ sense_key = sense[1] & 0x0F;
+ printk(KERN_INFO "%s\n", sense_texts[sense_key].text);
+
+ if (bufstring)
+ memcpy(bufstring, &sense[4], 2); /* return additional sense data */
+
+ if (sense_key < 2)
+ return 0;
+ return -EIO;
+}
+
+static struct cdrom_device_ops gdrom_ops = {
+ .open = gdrom_open,
+ .release = gdrom_release,
+ .drive_status = gdrom_drivestatus,
+ .media_changed = gdrom_mediachanged,
+ .get_last_session = gdrom_get_last_session,
+ .reset = gdrom_hardreset,
+ .capability = CDC_MULTI_SESSION | CDC_MEDIA_CHANGED |
+ CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R,
+ .n_minors = 1,
+};
+
+static int gdrom_bdops_open(struct inode *inode, struct file *file)
+{
+ return cdrom_open(gd.cd_info, inode, file);
+}
+
+static int gdrom_bdops_release(struct inode *inode, struct file *file)
+{
+ return cdrom_release(gd.cd_info, file);
+}
+
+static int gdrom_bdops_mediachanged(struct gendisk *disk)
+{
+ return cdrom_media_changed(gd.cd_info);
+}
+
+static int gdrom_bdops_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long arg)
+{
+ return cdrom_ioctl(file, gd.cd_info, inode, cmd, arg);
+}
+
+static struct block_device_operations gdrom_bdops = {
+ .owner = THIS_MODULE,
+ .open = gdrom_bdops_open,
+ .release = gdrom_bdops_release,
+ .media_changed = gdrom_bdops_mediachanged,
+ .ioctl = gdrom_bdops_ioctl,
+};
+
+static irqreturn_t gdrom_command_interrupt(int irq, void *dev_id)
+{
+ gd.status = ctrl_inb(GDROM_STATUSCOMMAND_REG);
+ if (gd.pending != 1)
+ return IRQ_HANDLED;
+ gd.pending = 0;
+ wake_up_interruptible(&command_queue);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t gdrom_dma_interrupt(int irq, void *dev_id)
+{
+ gd.status = ctrl_inb(GDROM_STATUSCOMMAND_REG);
+ if (gd.transfer != 1)
+ return IRQ_HANDLED;
+ gd.transfer = 0;
+ wake_up_interruptible(&request_queue);
+ return IRQ_HANDLED;
+}
+
+static int __devinit gdrom_set_interrupt_handlers(void)
+{
+ int err;
+ init_waitqueue_head(&command_queue);
+ err = request_irq(HW_EVENT_GDROM_CMD, gdrom_command_interrupt, IRQF_DISABLED, "gdrom_command", &gd);
+ if (err)
+ return err;
+ init_waitqueue_head(&request_queue);
+ err = request_irq(HW_EVENT_GDROM_DMA, gdrom_dma_interrupt, IRQF_DISABLED, "gdrom_dma", &gd);
+ if (err)
+ free_irq(HW_EVENT_GDROM_CMD, &gd);
+ return err;
+}
+
+/* Implement DMA read using SPI command
+ * 0 -> 0x30
+ * 1 -> mode
+ * 2 -> block >> 16
+ * 3 -> block >> 8
+ * 4 -> block
+ * 8 -> sectors >> 16
+ * 9 -> sectors >> 8
+ * 10 -> sectors
+ */
+static void gdrom_readdisk_dma(struct work_struct *work)
+{
+ int err, block, block_cnt;
+ struct packet_command *read_command;
+ struct list_head *elem, *next;
+ struct request *req;
+ unsigned long timeout;
+ if (list_empty(&gdrom_deferred))
+ return;
+ read_command = kzalloc(sizeof(struct packet_command), GFP_KERNEL);
+ if (!read_command)
+ return; /* get more memory later? */
+ read_command->cmd[0] = 0x30;
+ read_command->cmd[1] = 0x20;
+ spin_lock(&gdrom_lock);
+ list_for_each_safe(elem, next, &gdrom_deferred) {
+ req = list_entry(elem, struct request, queuelist);
+ spin_unlock(&gdrom_lock);
+ block = req->sector/GD_TO_BLK + GD_SESSION_OFFSET;
+ block_cnt = req->nr_sectors/GD_TO_BLK;
+ ctrl_outl(PHYSADDR(req->buffer), GDROM_DMA_STARTADDR_REG);
+ ctrl_outl(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG);
+ ctrl_outl(1, GDROM_DMA_DIRECTION_REG);
+ ctrl_outl(1, GDROM_DMA_ENABLE_REG);
+ read_command->cmd[2] = (block >> 16) & 0xFF;
+ read_command->cmd[3] = (block >> 8) & 0xFF;
+ read_command->cmd[4] = block & 0xFF;
+ read_command->cmd[8] = (block_cnt >> 16) & 0xFF;
+ read_command->cmd[9] = (block_cnt >> 8) & 0xFF;
+ read_command->cmd[10] = block_cnt & 0xFF;
+ /* set for DMA */
+ ctrl_outb(1, GDROM_ERROR_REG);
+ /* other registers */
+ ctrl_outb(0, GDROM_SECNUM_REG);
+ ctrl_outb(0, GDROM_BCL_REG);
+ ctrl_outb(0, GDROM_BCH_REG);
+ ctrl_outb(0, GDROM_DSEL_REG);
+ ctrl_outb(0, GDROM_INTSEC_REG);
+ /* In multiple DMA transfers need to wait */
+ timeout = jiffies + HZ / 2;
+ while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) && (time_before(jiffies, timeout)))
+ cpu_relax();
+ ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
+ timeout = jiffies + HZ / 2;
+ while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) != 8) && (time_before(jiffies, timeout)))
+ cpu_relax(); /* wait for DRQ to be set to 1 */
+ gd.pending = 1;
+ gd.transfer = 1;
+ outsw(PHYSADDR(GDROM_DATA_REG), &read_command->cmd, 6);
+ timeout = jiffies + HZ / 2;
+ while ((ctrl_inb(GDROM_DMA_STATUS_REG)) && (time_before(jiffies, timeout)))
+ cpu_relax();
+ ctrl_outb(1, GDROM_DMA_STATUS_REG);
+ /* 5 second error margin here seems more reasonable */
+ wait_event_interruptible_timeout(request_queue, gd.transfer == 0, HZ * 5);
+ err = ctrl_inb(GDROM_DMA_STATUS_REG);
+ err = gd.transfer;
+ gd.transfer = 0;
+ gd.pending = 0;
+ /* now seek to take the request spinlock
+ * before handling ending the request */
+ spin_lock(&gdrom_lock);
+ list_del_init(&req->queuelist);
+ end_dequeued_request(req, 1 - err);
+ }
+ spin_unlock(&gdrom_lock);
+ kfree(read_command);
+}
+
+static void gdrom_request_handler_dma(struct request *req)
+{
+ /* dequeue, add to list of deferred work
+ * and then schedule workqueue */
+ blkdev_dequeue_request(req);
+ list_add_tail(&req->queuelist, &gdrom_deferred);
+ schedule_work(&work);
+}
+
+static void gdrom_request(struct request_queue *rq)
+{
+ struct request *req;
+ while ((req = elv_next_request(rq)) != NULL) {
+ if (!blk_fs_request(req)) {
+ printk(KERN_DEBUG "GDROM: Non-fs request ignored\n");
+ end_request(req, 0);
+ }
+ if (rq_data_dir(req) != READ) {
+ printk(KERN_NOTICE "GDROM: Read only device - write request ignored\n");
+ end_request(req, 0);
+ }
+ if (req->nr_sectors)
+ gdrom_request_handler_dma(req);
+ else
+ end_request(req, 0);
+ }
+}
+
+/* Print string identifying GD ROM device */
+static int __devinit gdrom_outputversion(void)
+{
+ struct gdrom_id *id;
+ char *model_name, *manuf_name, *firmw_ver;
+ int err = -ENOMEM;
+ /* query device ID */
+ id = kzalloc(sizeof(struct gdrom_id), GFP_KERNEL);
+ if (!id)
+ return err;
+ gdrom_identifydevice(id);
+ model_name = kstrndup(id->modname, 16, GFP_KERNEL);
+ if (!model_name)
+ goto free_id;
+ manuf_name = kstrndup(id->mname, 16, GFP_KERNEL);
+ if (!manuf_name)
+ goto free_model_name;
+ firmw_ver = kstrndup(id->firmver, 16, GFP_KERNEL);
+ if (!firmw_ver)
+ goto free_manuf_name;
+ printk(KERN_INFO "GDROM: %s from %s with firmware %s\n", model_name, manuf_name, firmw_ver);
+ err = 0;
+ kfree(firmw_ver);
+free_manuf_name:
+ kfree(manuf_name);
+free_model_name:
+ kfree(model_name);
+free_id:
+ kfree(id);
+ return err;
+}
+
+/* set the default mode for DMA transfer */
+static void __devinit gdrom_init_dma_mode(void)
+{
+ ctrl_outb(0x13, GDROM_ERROR_REG);
+ ctrl_outb(0x22, GDROM_INTSEC_REG);
+ gdrom_wait_clrbusy();
+ ctrl_outb(0xEF, GDROM_STATUSCOMMAND_REG);
+ gdrom_wait_busy_sleeps();
+ ctrl_outl(0x8843407F, GDROM_DMA_ACCESS_CTRL_REG); /* memory setting */
+ ctrl_outl(9, GDROM_DMA_WAIT_REG); /* DMA word setting */
+}
+
+static void __devinit probe_gdrom_setupcd(void)
+{
+ gd.cd_info->ops = &gdrom_ops;
+ gd.cd_info->capacity = 1;
+ strcpy(gd.cd_info->name, GDROM_DEV_NAME);
+ gd.cd_info->mask = CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|CDC_SELECT_DISC;
+}
+
+static void __devinit probe_gdrom_setupdisk(void)
+{
+ gd.disk->major = gdrom_major;
+ gd.disk->first_minor = 1;
+ gd.disk->minors = 1;
+ strcpy(gd.disk->disk_name, GDROM_DEV_NAME);
+}
+
+static void __devinit probe_gdrom_setupqueue(void)
+{
+ blk_queue_hardsect_size(gd.gdrom_rq, GDROM_HARD_SECTOR);
+ /* using DMA so memory will need to be contiguous */
+ blk_queue_max_hw_segments(gd.gdrom_rq, 1);
+ /* set a large max size to get most from DMA */
+ blk_queue_max_segment_size(gd.gdrom_rq, 0x40000);
+ gd.disk->queue = gd.gdrom_rq;
+ gdrom_init_dma_mode();
+}
+
+/*
+ * register this as a block device and as compliant with the
+ * universal CD Rom driver interface
+ */
+static int __devinit probe_gdrom(struct platform_device *devptr)
+{
+ int err;
+ if (gdrom_execute_diagnostic() != 1) {
+ printk(KERN_WARNING "GDROM: ATA Probe for GDROM failed.\n");
+ return -ENODEV;
+ }
+ if (gdrom_outputversion())
+ return -ENOMEM;
+ gdrom_major = register_blkdev(0, GDROM_DEV_NAME);
+ if (gdrom_major <= 0)
+ return gdrom_major;
+ printk(KERN_INFO "GDROM: Block device is registered with major number %d\n", gdrom_major);
+ gd.cd_info = kzalloc(sizeof(struct cdrom_device_info), GFP_KERNEL);
+ if (!gd.cd_info) {
+ err = -ENOMEM;
+ goto probe_fail_no_mem;
+ }
+ probe_gdrom_setupcd();
+ gd.disk = alloc_disk(1);
+ if (!gd.disk) {
+ err = -ENODEV;
+ goto probe_fail_no_disk;
+ }
+ probe_gdrom_setupdisk();
+ if (register_cdrom(gd.cd_info)) {
+ err = -ENODEV;
+ goto probe_fail_cdrom_register;
+ }
+ gd.disk->fops = &gdrom_bdops;
+ /* latch on to the interrupt */
+ err = gdrom_set_interrupt_handlers();
+ if (err)
+ goto probe_fail_cmdirq_register;
+ gd.gdrom_rq = blk_init_queue(gdrom_request, &gdrom_lock);
+ if (!gd.gdrom_rq)
+ goto probe_fail_requestq;
+ probe_gdrom_setupqueue();
+ gd.toc = kzalloc(sizeof(struct gdromtoc), GFP_KERNEL);
+ if (!gd.toc)
+ goto probe_fail_toc;
+ add_disk(gd.disk);
+ return 0;
+
+probe_fail_toc:
+ blk_cleanup_queue(gd.gdrom_rq);
+probe_fail_requestq:
+ free_irq(HW_EVENT_GDROM_DMA, &gd);
+ free_irq(HW_EVENT_GDROM_CMD, &gd);
+probe_fail_cmdirq_register:
+probe_fail_cdrom_register:
+ del_gendisk(gd.disk);
+probe_fail_no_disk:
+ kfree(gd.cd_info);
+ unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
+ gdrom_major = 0;
+probe_fail_no_mem:
+ printk(KERN_WARNING "GDROM: Could not probe for device - error is 0x%X\n", err);
+ return err;
+}
+
+static int remove_gdrom(struct platform_device *devptr)
+{
+ blk_cleanup_queue(gd.gdrom_rq);
+ free_irq(HW_EVENT_GDROM_CMD, &gd);
+ free_irq(HW_EVENT_GDROM_DMA, &gd);
+ del_gendisk(gd.disk);
+ if (gdrom_major)
+ unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
+ return unregister_cdrom(gd.cd_info);
+}
+
+static struct platform_driver gdrom_driver = {
+ .probe = probe_gdrom,
+ .remove = remove_gdrom,
+ .driver = {
+ .name = GDROM_DEV_NAME,
+ },
+};
+
+static int __init init_gdrom(void)
+{
+ int rc;
+ gd.toc = NULL;
+ rc = platform_driver_register(&gdrom_driver);
+ if (rc)
+ return rc;
+ pd = platform_device_register_simple(GDROM_DEV_NAME, -1, NULL, 0);
+ if (IS_ERR(pd)) {
+ platform_driver_unregister(&gdrom_driver);
+ return PTR_ERR(pd);
+ }
+ return 0;
+}
+
+static void __exit exit_gdrom(void)
+{
+ platform_device_unregister(pd);
+ platform_driver_unregister(&gdrom_driver);
+ kfree(gd.toc);
+}
+
+module_init(init_gdrom);
+module_exit(exit_gdrom);
+MODULE_AUTHOR("Adrian McMenamin <adrian@mcmen.demon.co.uk>");
+MODULE_DESCRIPTION("SEGA Dreamcast GD-ROM Driver");
+MODULE_LICENSE("GPL");
diff -rupN linux-2.6-orig/drivers/cdrom/Makefile linux-2.6/drivers/cdrom/Makefile
--- linux-2.6-orig/drivers/cdrom/Makefile 2007-12-26 17:27:15.000000000 +0000
+++ linux-2.6/drivers/cdrom/Makefile 2007-12-27 00:08:39.000000000 +0000
@@ -11,3 +11,4 @@ obj-$(CONFIG_PARIDE_PCD) += cdrom.o
obj-$(CONFIG_CDROM_PKTCDVD) += cdrom.o
obj-$(CONFIG_VIOCD) += viocd.o cdrom.o
+obj-$(CONFIG_GDROM) += gdrom.o cdrom.o
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-27 16:52 [PATCH] SH/Dreamcast - add support for GD-Rom device Adrian McMenamin
2007-12-27 20:56 ` Adrian McMenamin
@ 2007-12-27 22:20 ` Paul Mundt
2007-12-27 22:58 ` Joe Perches
2 siblings, 0 replies; 20+ messages in thread
From: Paul Mundt @ 2007-12-27 22:20 UTC (permalink / raw)
To: Adrian McMenamin; +Cc: Jens Axboe, LKML, linux-sh
On Thu, Dec 27, 2007 at 04:52:19PM +0000, Adrian McMenamin wrote:
> This patch adds support for the CD-Rom drive on the SEGA Dreamcast.
>
> The SEGA Dreamcast has a built in CD-Rom drive, electrically similar
> to an ATA-3 drive, but implementing a proprietary packet interface -
> the so-called Sega Packet Interface (SPI)- and also supporting a
> proprietary format of disk - the Giga Disk Rom, with a 1GB capacity.
> The drive is know as the "GD-Rom drive".
>
> This patch partially implements the SPI and also supports reading GD
> Rom disks. Unlike previous GD Rom drivers (which were never in the
> mainline), this driver implements DMA and not PIO for reads. It is a
> new driver, not a modified version of previous drivers.
>
> This is the fifth iteration of this patch - which should work with
> both 2.6-24-rc5 and Paul Mundt's 2.6.25 queue.
>
> Signed-off by: Adrian McMenamin <adrian@mcmen.demon.co.uk>
>
Looks fine to me. Thanks for cleaning it up, Adrian.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-27 16:52 [PATCH] SH/Dreamcast - add support for GD-Rom device Adrian McMenamin
2007-12-27 20:56 ` Adrian McMenamin
2007-12-27 22:20 ` Paul Mundt
@ 2007-12-27 22:58 ` Joe Perches
2007-12-28 0:18 ` Simon Holm Thøgersen
` (3 more replies)
2 siblings, 4 replies; 20+ messages in thread
From: Joe Perches @ 2007-12-27 22:58 UTC (permalink / raw)
To: Adrian McMenamin; +Cc: Paul Mundt, Jens Axboe, LKML, linux-sh
On Thu, 2007-12-27 at 16:52 +0000, Adrian McMenamin wrote:
> This patch adds support for the CD-Rom drive on the SEGA Dreamcast.
Because it was already so close, might as well make it checkpatch clean.
I also added a function gdrom_is_busy() to make a couple of tests
fit on a single line and perhaps easier to read.
Signed-off-by: Joe Perches <joe@perches.com>
--- a/drivers/cdrom/gdrom.c 2007-12-27 14:49:27.000000000 -0800
+++ b/drivers/cdrom/gdrom.c 2007-12-27 14:46:20.000000000 -0800
@@ -86,7 +86,8 @@
{MEDIUM_ERROR, "GDROM: Disk not ready"},
{HARDWARE_ERROR, "GDROM: Hardware error"},
{ILLEGAL_REQUEST, "GDROM: Command has failed"},
- {UNIT_ATTENTION, "GDROM: Device needs attention - disk may have been changed"},
+ {UNIT_ATTENTION, "GDROM: Device needs attention - "
+ "disk may have been changed"},
{DATA_PROTECT, "GDROM: Data protection error"},
{ABORTED_COMMAND, "GDROM: Command aborted"},
};
@@ -130,14 +131,20 @@
};
static int gdrom_getsense(short *bufstring);
-static int gdrom_packetcommand(struct cdrom_device_info *cd_info, struct packet_command *command);
+static int gdrom_packetcommand(struct cdrom_device_info *cd_info,
+ struct packet_command *command);
static int gdrom_hardreset(struct cdrom_device_info *cd_info);
+static bool gdrom_is_busy(void)
+{
+ return (ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) != 0;
+}
+
static void gdrom_wait_clrbusy(void)
{
/* long timeouts - typical for a CD Rom */
unsigned long timeout = jiffies + HZ * 60;
- while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) && (time_before(jiffies, timeout)))
+ while (gdrom_is_busy() && (time_before(jiffies, timeout)))
cpu_relax();
}
@@ -146,7 +153,7 @@
unsigned long timeout;
/* Wait to get busy first */
timeout = jiffies + HZ * 60;
- while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) == 0) && (time_before(jiffies, timeout)))
+ while (!gdrom_is_busy() && (time_before(jiffies, timeout)))
cpu_relax();
/* Now wait for busy to clear */
gdrom_wait_clrbusy();
@@ -216,7 +223,8 @@
gd.pending = 1;
gdrom_packetcommand(gd.cd_info, spin_command);
/* 60 second timeout */
- wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
+ wait_event_interruptible_timeout(command_queue,
+ gd.pending == 0, HZ * 60);
gd.pending = 0;
kfree(spin_command);
if (gd.status & 0x01) {
@@ -249,7 +257,8 @@
toc_command->buflen = tocsize;
gd.pending = 1;
gdrom_packetcommand(gd.cd_info, toc_command);
- wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
+ wait_event_interruptible_timeout(command_queue,
+ gd.pending == 0, HZ * 60);
gd.pending = 0;
insw(PHYSADDR(GDROM_DATA_REG), toc, tocsize/2);
kfree(toc_command);
@@ -274,7 +283,8 @@
return (track & 0x0000ff00) >> 8;
}
-static int gdrom_get_last_session(struct cdrom_device_info *cd_info, struct cdrom_multisession *ms_info)
+static int gdrom_get_last_session(struct cdrom_device_info *cd_info,
+ struct cdrom_multisession *ms_info)
{
int fentry, lentry, track, data, tocuse, err;
if (!gd.toc)
@@ -287,7 +297,8 @@
tocuse = 0;
err = gdrom_readtoc_cmd(gd.toc, 0);
if (err) {
- printk(KERN_INFO "GDROM: Could not get CD table of contents\n");
+ printk(KERN_INFO "GDROM: Could not get CD "
+ "table of contents\n");
return -ENXIO;
}
}
@@ -305,7 +316,8 @@
if ((track > 100) || (track < get_entry_track(gd.toc->first))) {
gdrom_getsense(NULL);
- printk(KERN_INFO "GDROM: No data on the last session of the CD\n");
+ printk(KERN_INFO "GDROM: No data on the last session "
+ "of the CD\n");
return -ENXIO;
}
@@ -355,8 +367,10 @@
return 0;
}
-/* keep the function looking like the universal CD Rom specification - returning int*/
-static int gdrom_packetcommand(struct cdrom_device_info *cd_info, struct packet_command *command)
+/* keep the function looking like the universal CD Rom specification -
+ * returning int */
+static int gdrom_packetcommand(struct cdrom_device_info *cd_info,
+ struct packet_command *command)
{
gdrom_spicommand(&command->cmd, command->buflen);
return 0;
@@ -388,7 +402,8 @@
gd.pending = 1;
gdrom_packetcommand(gd.cd_info, sense_command);
/* 60 second timeout */
- wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
+ wait_event_interruptible_timeout(command_queue,
+ gd.pending == 0, HZ * 60);
gd.pending = 0;
kfree(sense_command);
insw(PHYSADDR(GDROM_DATA_REG), &sense, 5);
@@ -400,7 +415,8 @@
printk(KERN_INFO "%s\n", sense_texts[sense_key].text);
if (bufstring)
- memcpy(bufstring, &sense[4], 2); /* return additional sense data */
+ memcpy(bufstring, &sense[4], 2);
+ /* return additional sense data */
if (sense_key < 2)
return 0;
@@ -434,7 +450,8 @@
return cdrom_media_changed(gd.cd_info);
}
-static int gdrom_bdops_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long arg)
+static int gdrom_bdops_ioctl(struct inode *inode, struct file *file,
+ unsigned cmd, unsigned long arg)
{
return cdrom_ioctl(file, gd.cd_info, inode, cmd, arg);
}
@@ -471,11 +488,13 @@
{
int err;
init_waitqueue_head(&command_queue);
- err = request_irq(HW_EVENT_GDROM_CMD, gdrom_command_interrupt, IRQF_DISABLED, "gdrom_command", &gd);
+ err = request_irq(HW_EVENT_GDROM_CMD, gdrom_command_interrupt,
+ IRQF_DISABLED, "gdrom_command", &gd);
if (err)
return err;
init_waitqueue_head(&request_queue);
- err = request_irq(HW_EVENT_GDROM_DMA, gdrom_dma_interrupt, IRQF_DISABLED, "gdrom_dma", &gd);
+ err = request_irq(HW_EVENT_GDROM_DMA, gdrom_dma_interrupt,
+ IRQF_DISABLED, "gdrom_dma", &gd);
if (err)
free_irq(HW_EVENT_GDROM_CMD, &gd);
return err;
@@ -531,27 +550,30 @@
ctrl_outb(0, GDROM_INTSEC_REG);
/* In multiple DMA transfers need to wait */
timeout = jiffies + HZ / 2;
- while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) && (time_before(jiffies, timeout)))
+ while (gdrom_is_busy() && (time_before(jiffies, timeout)))
cpu_relax();
ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
timeout = jiffies + HZ / 2;
- while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) != 8) && (time_before(jiffies, timeout)))
+ while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) != 8) &&
+ (time_before(jiffies, timeout)))
cpu_relax(); /* wait for DRQ to be set to 1 */
gd.pending = 1;
gd.transfer = 1;
outsw(PHYSADDR(GDROM_DATA_REG), &read_command->cmd, 6);
timeout = jiffies + HZ / 2;
- while ((ctrl_inb(GDROM_DMA_STATUS_REG)) && (time_before(jiffies, timeout)))
+ while ((ctrl_inb(GDROM_DMA_STATUS_REG)) &&
+ (time_before(jiffies, timeout)))
cpu_relax();
ctrl_outb(1, GDROM_DMA_STATUS_REG);
/* 5 second error margin here seems more reasonable */
- wait_event_interruptible_timeout(request_queue, gd.transfer == 0, HZ * 5);
+ wait_event_interruptible_timeout(request_queue,
+ gd.transfer == 0, HZ * 5);
err = ctrl_inb(GDROM_DMA_STATUS_REG);
err = gd.transfer;
gd.transfer = 0;
gd.pending = 0;
/* now seek to take the request spinlock
- * before handling ending the request */
+ * before handling ending the request */
spin_lock(&gdrom_lock);
list_del_init(&req->queuelist);
blk_requeue_request(gd.gdrom_rq, req);
@@ -567,7 +589,7 @@
static void gdrom_request_handler_dma(struct request *req)
{
/* dequeue, add to list of deferred work
- * and then schedule workqueue */
+ * and then schedule workqueue */
blkdev_dequeue_request(req);
list_add_tail(&req->queuelist, &gdrom_deferred);
schedule_work(&work);
@@ -582,7 +604,8 @@
end_request(req, 0);
}
if (rq_data_dir(req) != READ) {
- printk(KERN_NOTICE "GDROM: Read only device - write request ignored\n");
+ printk(KERN_NOTICE "GDROM: Read only device - "
+ "write request ignored\n");
end_request(req, 0);
}
if (req->nr_sectors)
@@ -612,7 +635,8 @@
firmw_ver = kstrndup(id->firmver, 16, GFP_KERNEL);
if (!firmw_ver)
goto free_manuf_name;
- printk(KERN_INFO "GDROM: %s from %s with firmware %s\n", model_name, manuf_name, firmw_ver);
+ printk(KERN_INFO "GDROM: %s from %s with firmware %s\n",
+ model_name, manuf_name, firmw_ver);
err = 0;
kfree(firmw_ver);
free_manuf_name:
@@ -641,7 +665,8 @@
gd.cd_info->ops = &gdrom_ops;
gd.cd_info->capacity = 1;
strcpy(gd.cd_info->name, GDROM_DEV_NAME);
- gd.cd_info->mask = CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|CDC_SELECT_DISC;
+ gd.cd_info->mask = CDC_CLOSE_TRAY | CDC_OPEN_TRAY |
+ CDC_LOCK | CDC_SELECT_DISC;
}
static void __devinit probe_gdrom_setupdisk(void)
@@ -671,7 +696,7 @@
{
int err;
if (gdrom_execute_diagnostic() != 1) {
- printk(KERN_WARNING "GDROM: ATA Probe for GDROM failed.\n");
+ printk(KERN_WARNING "GDROM: ATA Probe for GDROM failed\n");
return -ENODEV;
}
if (gdrom_outputversion())
@@ -679,7 +704,8 @@
gdrom_major = register_blkdev(0, GDROM_DEV_NAME);
if (gdrom_major <= 0)
return gdrom_major;
- printk(KERN_INFO "GDROM: Block device is registered with major number %d\n", gdrom_major);
+ printk(KERN_INFO "GDROM: Block device is registered "
+ "with major number %d\n", gdrom_major);
gd.cd_info = kzalloc(sizeof(struct cdrom_device_info), GFP_KERNEL);
if (!gd.cd_info) {
err = -ENOMEM;
@@ -724,7 +750,8 @@
unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
gdrom_major = 0;
probe_fail_no_mem:
- printk(KERN_WARNING "GDROM: Could not probe for device - error is 0x%X\n", err);
+ printk(KERN_WARNING "GDROM: Could not probe for device - "
+ "error is 0x%X\n", err);
return err;
}
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-27 22:58 ` Joe Perches
@ 2007-12-28 0:18 ` Simon Holm Thøgersen
2007-12-29 1:57 ` Joe Perches
2007-12-28 0:49 ` Mike Frysinger
` (2 subsequent siblings)
3 siblings, 1 reply; 20+ messages in thread
From: Simon Holm Thøgersen @ 2007-12-28 0:18 UTC (permalink / raw)
To: Joe Perches; +Cc: Adrian McMenamin, Paul Mundt, Jens Axboe, LKML, linux-sh
tor, 27 12 2007 kl. 14:58 -0800, skrev Joe Perches:
> On Thu, 2007-12-27 at 16:52 +0000, Adrian McMenamin wrote:
> > This patch adds support for the CD-Rom drive on the SEGA Dreamcast.
>
> Because it was already so close, might as well make it checkpatch clean.
>
> I also added a function gdrom_is_busy() to make a couple of tests
> fit on a single line and perhaps easier to read.
>
> Signed-off-by: Joe Perches <joe@perches.com>
>
> --- a/drivers/cdrom/gdrom.c 2007-12-27 14:49:27.000000000 -0800
> +++ b/drivers/cdrom/gdrom.c 2007-12-27 14:46:20.000000000 -0800
> @@ -86,7 +86,8 @@
> {MEDIUM_ERROR, "GDROM: Disk not ready"},
> {HARDWARE_ERROR, "GDROM: Hardware error"},
> {ILLEGAL_REQUEST, "GDROM: Command has failed"},
> - {UNIT_ATTENTION, "GDROM: Device needs attention - disk may have been changed"},
> + {UNIT_ATTENTION, "GDROM: Device needs attention - "
> + "disk may have been changed"},
> {DATA_PROTECT, "GDROM: Data protection error"},
> {ABORTED_COMMAND, "GDROM: Command aborted"},
> };
> @@ -130,14 +131,20 @@
> };
>
> static int gdrom_getsense(short *bufstring);
> -static int gdrom_packetcommand(struct cdrom_device_info *cd_info, struct packet_command *command);
> +static int gdrom_packetcommand(struct cdrom_device_info *cd_info,
> + struct packet_command *command);
> static int gdrom_hardreset(struct cdrom_device_info *cd_info);
>
> +static bool gdrom_is_busy(void)
> +{
> + return (ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) != 0;
> +}
> +
> static void gdrom_wait_clrbusy(void)
> {
> /* long timeouts - typical for a CD Rom */
> unsigned long timeout = jiffies + HZ * 60;
> - while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) && (time_before(jiffies, timeout)))
> + while (gdrom_is_busy() && (time_before(jiffies, timeout)))
^ ^
You don't need those parentheses.
> cpu_relax();
> }
>
> @@ -146,7 +153,7 @@
> unsigned long timeout;
> /* Wait to get busy first */
> timeout = jiffies + HZ * 60;
> - while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) == 0) && (time_before(jiffies, timeout)))
> + while (!gdrom_is_busy() && (time_before(jiffies, timeout)))
Same here.
> cpu_relax();
> /* Now wait for busy to clear */
> gdrom_wait_clrbusy();
> @@ -216,7 +223,8 @@
> gd.pending = 1;
> gdrom_packetcommand(gd.cd_info, spin_command);
> /* 60 second timeout */
> - wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
> + wait_event_interruptible_timeout(command_queue,
> + gd.pending == 0, HZ * 60);
> gd.pending = 0;
All three users of gdrom_packetcommand do the same timeout, so consider
moving this block into gdrom_packcommand.
> kfree(spin_command);
> if (gd.status & 0x01) {
> @@ -249,7 +257,8 @@
> toc_command->buflen = tocsize;
> gd.pending = 1;
> gdrom_packetcommand(gd.cd_info, toc_command);
> - wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
> + wait_event_interruptible_timeout(command_queue,
> + gd.pending == 0, HZ * 60);
> gd.pending = 0;
> insw(PHYSADDR(GDROM_DATA_REG), toc, tocsize/2);
> kfree(toc_command);
> @@ -274,7 +283,8 @@
> return (track & 0x0000ff00) >> 8;
> }
>
> -static int gdrom_get_last_session(struct cdrom_device_info *cd_info, struct cdrom_multisession *ms_info)
> +static int gdrom_get_last_session(struct cdrom_device_info *cd_info,
> + struct cdrom_multisession *ms_info)
> {
> int fentry, lentry, track, data, tocuse, err;
> if (!gd.toc)
> @@ -287,7 +297,8 @@
> tocuse = 0;
> err = gdrom_readtoc_cmd(gd.toc, 0);
> if (err) {
> - printk(KERN_INFO "GDROM: Could not get CD table of contents\n");
> + printk(KERN_INFO "GDROM: Could not get CD "
> + "table of contents\n");
> return -ENXIO;
> }
> }
> @@ -305,7 +316,8 @@
>
> if ((track > 100) || (track < get_entry_track(gd.toc->first))) {
> gdrom_getsense(NULL);
> - printk(KERN_INFO "GDROM: No data on the last session of the CD\n");
> + printk(KERN_INFO "GDROM: No data on the last session "
> + "of the CD\n");
> return -ENXIO;
> }
>
> @@ -355,8 +367,10 @@
> return 0;
> }
>
> -/* keep the function looking like the universal CD Rom specification - returning int*/
> -static int gdrom_packetcommand(struct cdrom_device_info *cd_info, struct packet_command *command)
> +/* keep the function looking like the universal CD Rom specification -
> + * returning int */
> +static int gdrom_packetcommand(struct cdrom_device_info *cd_info,
> + struct packet_command *command)
> {
> gdrom_spicommand(&command->cmd, command->buflen);
> return 0;
> @@ -388,7 +402,8 @@
> gd.pending = 1;
> gdrom_packetcommand(gd.cd_info, sense_command);
> /* 60 second timeout */
> - wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
> + wait_event_interruptible_timeout(command_queue,
> + gd.pending == 0, HZ * 60);
> gd.pending = 0;
> kfree(sense_command);
> insw(PHYSADDR(GDROM_DATA_REG), &sense, 5);
> @@ -400,7 +415,8 @@
> printk(KERN_INFO "%s\n", sense_texts[sense_key].text);
>
> if (bufstring)
> - memcpy(bufstring, &sense[4], 2); /* return additional sense data */
> + memcpy(bufstring, &sense[4], 2);
> + /* return additional sense data */
Put the comment on the if-line or use curly brackets and give the
comment its own line above memcpy?
>
> if (sense_key < 2)
> return 0;
> @@ -434,7 +450,8 @@
> return cdrom_media_changed(gd.cd_info);
> }
>
> -static int gdrom_bdops_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long arg)
> +static int gdrom_bdops_ioctl(struct inode *inode, struct file *file,
> + unsigned cmd, unsigned long arg)
> {
> return cdrom_ioctl(file, gd.cd_info, inode, cmd, arg);
> }
> @@ -471,11 +488,13 @@
> {
> int err;
> init_waitqueue_head(&command_queue);
> - err = request_irq(HW_EVENT_GDROM_CMD, gdrom_command_interrupt, IRQF_DISABLED, "gdrom_command", &gd);
> + err = request_irq(HW_EVENT_GDROM_CMD, gdrom_command_interrupt,
> + IRQF_DISABLED, "gdrom_command", &gd);
> if (err)
> return err;
> init_waitqueue_head(&request_queue);
> - err = request_irq(HW_EVENT_GDROM_DMA, gdrom_dma_interrupt, IRQF_DISABLED, "gdrom_dma", &gd);
> + err = request_irq(HW_EVENT_GDROM_DMA, gdrom_dma_interrupt,
> + IRQF_DISABLED, "gdrom_dma", &gd);
> if (err)
> free_irq(HW_EVENT_GDROM_CMD, &gd);
> return err;
> @@ -531,27 +550,30 @@
> ctrl_outb(0, GDROM_INTSEC_REG);
> /* In multiple DMA transfers need to wait */
> timeout = jiffies + HZ / 2;
> - while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) && (time_before(jiffies, timeout)))
> + while (gdrom_is_busy() && (time_before(jiffies, timeout)))
> cpu_relax();
Another one here.
> ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
> timeout = jiffies + HZ / 2;
> - while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) != 8) && (time_before(jiffies, timeout)))
> + while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) != 8) &&
> + (time_before(jiffies, timeout)))
What about a nice telling function like gdrom_is_busy for this?
> cpu_relax(); /* wait for DRQ to be set to 1 */
> gd.pending = 1;
> gd.transfer = 1;
> outsw(PHYSADDR(GDROM_DATA_REG), &read_command->cmd, 6);
> timeout = jiffies + HZ / 2;
> - while ((ctrl_inb(GDROM_DMA_STATUS_REG)) && (time_before(jiffies, timeout)))
> + while ((ctrl_inb(GDROM_DMA_STATUS_REG)) &&
> + (time_before(jiffies, timeout)))
Extra parentheses, also around ctrl_inb. And there should be curly
brackets around the following line, since the while condition is on two
lines.
> cpu_relax();
> ctrl_outb(1, GDROM_DMA_STATUS_REG);
> /* 5 second error margin here seems more reasonable */
> - wait_event_interruptible_timeout(request_queue, gd.transfer == 0, HZ * 5);
> + wait_event_interruptible_timeout(request_queue,
> + gd.transfer == 0, HZ * 5);
> err = ctrl_inb(GDROM_DMA_STATUS_REG);
> err = gd.transfer;
> gd.transfer = 0;
> gd.pending = 0;
> /* now seek to take the request spinlock
> - * before handling ending the request */
> + * before handling ending the request */
> spin_lock(&gdrom_lock);
> list_del_init(&req->queuelist);
> blk_requeue_request(gd.gdrom_rq, req);
> @@ -567,7 +589,7 @@
> static void gdrom_request_handler_dma(struct request *req)
> {
> /* dequeue, add to list of deferred work
> - * and then schedule workqueue */
> + * and then schedule workqueue */
> blkdev_dequeue_request(req);
> list_add_tail(&req->queuelist, &gdrom_deferred);
> schedule_work(&work);
> @@ -582,7 +604,8 @@
> end_request(req, 0);
> }
> if (rq_data_dir(req) != READ) {
> - printk(KERN_NOTICE "GDROM: Read only device - write request ignored\n");
> + printk(KERN_NOTICE "GDROM: Read only device - "
> + "write request ignored\n");
> end_request(req, 0);
> }
> if (req->nr_sectors)
> @@ -612,7 +635,8 @@
> firmw_ver = kstrndup(id->firmver, 16, GFP_KERNEL);
> if (!firmw_ver)
> goto free_manuf_name;
> - printk(KERN_INFO "GDROM: %s from %s with firmware %s\n", model_name, manuf_name, firmw_ver);
> + printk(KERN_INFO "GDROM: %s from %s with firmware %s\n",
> + model_name, manuf_name, firmw_ver);
> err = 0;
> kfree(firmw_ver);
> free_manuf_name:
> @@ -641,7 +665,8 @@
> gd.cd_info->ops = &gdrom_ops;
> gd.cd_info->capacity = 1;
> strcpy(gd.cd_info->name, GDROM_DEV_NAME);
> - gd.cd_info->mask = CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|CDC_SELECT_DISC;
> + gd.cd_info->mask = CDC_CLOSE_TRAY | CDC_OPEN_TRAY |
> + CDC_LOCK | CDC_SELECT_DISC;
> }
>
> static void __devinit probe_gdrom_setupdisk(void)
> @@ -671,7 +696,7 @@
> {
> int err;
> if (gdrom_execute_diagnostic() != 1) {
> - printk(KERN_WARNING "GDROM: ATA Probe for GDROM failed.\n");
> + printk(KERN_WARNING "GDROM: ATA Probe for GDROM failed\n");
> return -ENODEV;
> }
> if (gdrom_outputversion())
> @@ -679,7 +704,8 @@
> gdrom_major = register_blkdev(0, GDROM_DEV_NAME);
> if (gdrom_major <= 0)
> return gdrom_major;
> - printk(KERN_INFO "GDROM: Block device is registered with major number %d\n", gdrom_major);
> + printk(KERN_INFO "GDROM: Block device is registered "
> + "with major number %d\n", gdrom_major);
> gd.cd_info = kzalloc(sizeof(struct cdrom_device_info), GFP_KERNEL);
> if (!gd.cd_info) {
> err = -ENOMEM;
> @@ -724,7 +750,8 @@
> unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
> gdrom_major = 0;
> probe_fail_no_mem:
> - printk(KERN_WARNING "GDROM: Could not probe for device - error is 0x%X\n", err);
> + printk(KERN_WARNING "GDROM: Could not probe for device - "
> + "error is 0x%X\n", err);
> return err;
> }
Simon Holm Thøgersen
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-27 22:58 ` Joe Perches
2007-12-28 0:18 ` Simon Holm Thøgersen
@ 2007-12-28 0:49 ` Mike Frysinger
2007-12-28 3:41 ` Paul Mundt
2007-12-28 19:17 ` Gino Badouri
2007-12-30 13:38 ` Adrian McMenamin
3 siblings, 1 reply; 20+ messages in thread
From: Mike Frysinger @ 2007-12-28 0:49 UTC (permalink / raw)
To: Joe Perches; +Cc: Adrian McMenamin, Paul Mundt, Jens Axboe, LKML, linux-sh
[-- Attachment #1: Type: text/plain, Size: 781 bytes --]
On Thursday 27 December 2007, Joe Perches wrote:
> On Thu, 2007-12-27 at 16:52 +0000, Adrian McMenamin wrote:
> > This patch adds support for the CD-Rom drive on the SEGA Dreamcast.
>
> Because it was already so close, might as well make it checkpatch clean.
for the 80 col limit, that's up to the author. if Adrian is happy with it as
is, that's fine.
> I also added a function gdrom_is_busy() to make a couple of tests
> fit on a single line and perhaps easier to read.
i'd tend to agree it does make it easier to read, however you didnt make it
inline which means gcc may not inline it which means there's pointless
overhead of doing a function call.
otherwise, arbitrary breaking on 80 cols actually makes the code harder to
read for no gain.
-mike
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 835 bytes --]
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-28 0:49 ` Mike Frysinger
@ 2007-12-28 3:41 ` Paul Mundt
0 siblings, 0 replies; 20+ messages in thread
From: Paul Mundt @ 2007-12-28 3:41 UTC (permalink / raw)
To: Mike Frysinger; +Cc: Joe Perches, Adrian McMenamin, Jens Axboe, LKML, linux-sh
On Thu, Dec 27, 2007 at 07:49:01PM -0500, Mike Frysinger wrote:
> On Thursday 27 December 2007, Joe Perches wrote:
> > I also added a function gdrom_is_busy() to make a couple of tests
> > fit on a single line and perhaps easier to read.
>
> i'd tend to agree it does make it easier to read, however you didnt make it
> inline which means gcc may not inline it which means there's pointless
> overhead of doing a function call.
>
These days GCC is usually smart enough to automatically inline things
that are that small, it doesn't need to be explicitly labelled. If your
toolchain doesn't inline that gdrom_is_busy() implementation, get a
better toolchain.
> otherwise, arbitrary breaking on 80 cols actually makes the code harder to
> read for no gain.
Hey now, some of us have no intention of giving up our 80x25 consoles,
not everyone buys in to this whole newfangled X thing. ;-)
More than 80 columns is generally fine so long as it's done so tastefully
rather than arbitrarily based on a larger console width. However, if it
can be split up cleanly for 80 columns, then it should be. ie, use common
sense, rather than blindly adhering to the whims of an anal-retentive
script.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-27 22:58 ` Joe Perches
2007-12-28 0:18 ` Simon Holm Thøgersen
2007-12-28 0:49 ` Mike Frysinger
@ 2007-12-28 19:17 ` Gino Badouri
2007-12-28 22:09 ` Joe Perches
2007-12-30 13:38 ` Adrian McMenamin
3 siblings, 1 reply; 20+ messages in thread
From: Gino Badouri @ 2007-12-28 19:17 UTC (permalink / raw)
To: Joe Perches; +Cc: Adrian McMenamin, Paul Mundt, Jens Axboe, LKML, linux-sh
Op donderdag 27-12-2007 om 14:58 uur [tijdzone -0800], schreef Joe
Perches:
> On Thu, 2007-12-27 at 16:52 +0000, Adrian McMenamin wrote:
> > This patch adds support for the CD-Rom drive on the SEGA Dreamcast.
>
> Because it was already so close, might as well make it checkpatch clean.
>
> I also added a function gdrom_is_busy() to make a couple of tests
> fit on a single line and perhaps easier to read.
>
> Signed-off-by: Joe Perches <joe@perches.com>
>
> --- a/drivers/cdrom/gdrom.c 2007-12-27 14:49:27.000000000 -0800
> +++ b/drivers/cdrom/gdrom.c 2007-12-27 14:46:20.000000000 -0800
> @@ -86,7 +86,8 @@
> {MEDIUM_ERROR, "GDROM: Disk not ready"},
> {HARDWARE_ERROR, "GDROM: Hardware error"},
> {ILLEGAL_REQUEST, "GDROM: Command has failed"},
> - {UNIT_ATTENTION, "GDROM: Device needs attention - disk may have been changed"},
> + {UNIT_ATTENTION, "GDROM: Device needs attention - "
> + "disk may have been changed"},
> {DATA_PROTECT, "GDROM: Data protection error"},
> {ABORTED_COMMAND, "GDROM: Command aborted"},
> };
> @@ -130,14 +131,20 @@
> };
>
> static int gdrom_getsense(short *bufstring);
> -static int gdrom_packetcommand(struct cdrom_device_info *cd_info, struct packet_command *command);
> +static int gdrom_packetcommand(struct cdrom_device_info *cd_info,
> + struct packet_command *command);
> static int gdrom_hardreset(struct cdrom_device_info *cd_info);
>
> +static bool gdrom_is_busy(void)
> +{
> + return (ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) != 0;
> +}
> +
> static void gdrom_wait_clrbusy(void)
> {
> /* long timeouts - typical for a CD Rom */
> unsigned long timeout = jiffies + HZ * 60;
> - while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) && (time_before(jiffies, timeout)))
> + while (gdrom_is_busy() && (time_before(jiffies, timeout)))
> cpu_relax();
> }
>
> @@ -146,7 +153,7 @@
> unsigned long timeout;
> /* Wait to get busy first */
> timeout = jiffies + HZ * 60;
> - while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) == 0) && (time_before(jiffies, timeout)))
> + while (!gdrom_is_busy() && (time_before(jiffies, timeout)))
> cpu_relax();
> /* Now wait for busy to clear */
> gdrom_wait_clrbusy();
> @@ -216,7 +223,8 @@
> gd.pending = 1;
> gdrom_packetcommand(gd.cd_info, spin_command);
> /* 60 second timeout */
> - wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
> + wait_event_interruptible_timeout(command_queue,
> + gd.pending == 0, HZ * 60);
> gd.pending = 0;
> kfree(spin_command);
> if (gd.status & 0x01) {
> @@ -249,7 +257,8 @@
> toc_command->buflen = tocsize;
> gd.pending = 1;
> gdrom_packetcommand(gd.cd_info, toc_command);
> - wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
> + wait_event_interruptible_timeout(command_queue,
> + gd.pending == 0, HZ * 60);
> gd.pending = 0;
> insw(PHYSADDR(GDROM_DATA_REG), toc, tocsize/2);
> kfree(toc_command);
> @@ -274,7 +283,8 @@
> return (track & 0x0000ff00) >> 8;
> }
>
> -static int gdrom_get_last_session(struct cdrom_device_info *cd_info, struct cdrom_multisession *ms_info)
> +static int gdrom_get_last_session(struct cdrom_device_info *cd_info,
> + struct cdrom_multisession *ms_info)
> {
> int fentry, lentry, track, data, tocuse, err;
> if (!gd.toc)
> @@ -287,7 +297,8 @@
> tocuse = 0;
> err = gdrom_readtoc_cmd(gd.toc, 0);
> if (err) {
> - printk(KERN_INFO "GDROM: Could not get CD table of contents\n");
> + printk(KERN_INFO "GDROM: Could not get CD "
> + "table of contents\n");
> return -ENXIO;
> }
> }
> @@ -305,7 +316,8 @@
>
> if ((track > 100) || (track < get_entry_track(gd.toc->first))) {
> gdrom_getsense(NULL);
> - printk(KERN_INFO "GDROM: No data on the last session of the CD\n");
> + printk(KERN_INFO "GDROM: No data on the last session "
> + "of the CD\n");
> return -ENXIO;
> }
>
> @@ -355,8 +367,10 @@
> return 0;
> }
>
> -/* keep the function looking like the universal CD Rom specification - returning int*/
> -static int gdrom_packetcommand(struct cdrom_device_info *cd_info, struct packet_command *command)
> +/* keep the function looking like the universal CD Rom specification -
> + * returning int */
> +static int gdrom_packetcommand(struct cdrom_device_info *cd_info,
> + struct packet_command *command)
> {
> gdrom_spicommand(&command->cmd, command->buflen);
> return 0;
> @@ -388,7 +402,8 @@
> gd.pending = 1;
> gdrom_packetcommand(gd.cd_info, sense_command);
> /* 60 second timeout */
> - wait_event_interruptible_timeout(command_queue, gd.pending == 0, HZ * 60);
> + wait_event_interruptible_timeout(command_queue,
> + gd.pending == 0, HZ * 60);
> gd.pending = 0;
> kfree(sense_command);
> insw(PHYSADDR(GDROM_DATA_REG), &sense, 5);
> @@ -400,7 +415,8 @@
> printk(KERN_INFO "%s\n", sense_texts[sense_key].text);
>
> if (bufstring)
> - memcpy(bufstring, &sense[4], 2); /* return additional sense data */
> + memcpy(bufstring, &sense[4], 2);
> + /* return additional sense data */
>
> if (sense_key < 2)
> return 0;
> @@ -434,7 +450,8 @@
> return cdrom_media_changed(gd.cd_info);
> }
>
> -static int gdrom_bdops_ioctl(struct inode *inode, struct file *file, unsigned cmd, unsigned long arg)
> +static int gdrom_bdops_ioctl(struct inode *inode, struct file *file,
> + unsigned cmd, unsigned long arg)
> {
> return cdrom_ioctl(file, gd.cd_info, inode, cmd, arg);
> }
> @@ -471,11 +488,13 @@
> {
> int err;
> init_waitqueue_head(&command_queue);
> - err = request_irq(HW_EVENT_GDROM_CMD, gdrom_command_interrupt, IRQF_DISABLED, "gdrom_command", &gd);
> + err = request_irq(HW_EVENT_GDROM_CMD, gdrom_command_interrupt,
> + IRQF_DISABLED, "gdrom_command", &gd);
> if (err)
> return err;
> init_waitqueue_head(&request_queue);
> - err = request_irq(HW_EVENT_GDROM_DMA, gdrom_dma_interrupt, IRQF_DISABLED, "gdrom_dma", &gd);
> + err = request_irq(HW_EVENT_GDROM_DMA, gdrom_dma_interrupt,
> + IRQF_DISABLED, "gdrom_dma", &gd);
> if (err)
> free_irq(HW_EVENT_GDROM_CMD, &gd);
> return err;
> @@ -531,27 +550,30 @@
> ctrl_outb(0, GDROM_INTSEC_REG);
> /* In multiple DMA transfers need to wait */
> timeout = jiffies + HZ / 2;
> - while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) && (time_before(jiffies, timeout)))
> + while (gdrom_is_busy() && (time_before(jiffies, timeout)))
> cpu_relax();
> ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
> timeout = jiffies + HZ / 2;
> - while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) != 8) && (time_before(jiffies, timeout)))
> + while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) != 8) &&
> + (time_before(jiffies, timeout)))
> cpu_relax(); /* wait for DRQ to be set to 1 */
> gd.pending = 1;
> gd.transfer = 1;
> outsw(PHYSADDR(GDROM_DATA_REG), &read_command->cmd, 6);
> timeout = jiffies + HZ / 2;
> - while ((ctrl_inb(GDROM_DMA_STATUS_REG)) && (time_before(jiffies, timeout)))
> + while ((ctrl_inb(GDROM_DMA_STATUS_REG)) &&
> + (time_before(jiffies, timeout)))
> cpu_relax();
> ctrl_outb(1, GDROM_DMA_STATUS_REG);
> /* 5 second error margin here seems more reasonable */
> - wait_event_interruptible_timeout(request_queue, gd.transfer == 0, HZ * 5);
> + wait_event_interruptible_timeout(request_queue,
> + gd.transfer == 0, HZ * 5);
> err = ctrl_inb(GDROM_DMA_STATUS_REG);
> err = gd.transfer;
> gd.transfer = 0;
> gd.pending = 0;
> /* now seek to take the request spinlock
> - * before handling ending the request */
> + * before handling ending the request */
> spin_lock(&gdrom_lock);
> list_del_init(&req->queuelist);
> blk_requeue_request(gd.gdrom_rq, req);
> @@ -567,7 +589,7 @@
> static void gdrom_request_handler_dma(struct request *req)
> {
> /* dequeue, add to list of deferred work
> - * and then schedule workqueue */
> + * and then schedule workqueue */
> blkdev_dequeue_request(req);
> list_add_tail(&req->queuelist, &gdrom_deferred);
> schedule_work(&work);
> @@ -582,7 +604,8 @@
> end_request(req, 0);
> }
> if (rq_data_dir(req) != READ) {
> - printk(KERN_NOTICE "GDROM: Read only device - write request ignored\n");
> + printk(KERN_NOTICE "GDROM: Read only device - "
> + "write request ignored\n");
> end_request(req, 0);
> }
> if (req->nr_sectors)
> @@ -612,7 +635,8 @@
> firmw_ver = kstrndup(id->firmver, 16, GFP_KERNEL);
> if (!firmw_ver)
> goto free_manuf_name;
> - printk(KERN_INFO "GDROM: %s from %s with firmware %s\n", model_name, manuf_name, firmw_ver);
> + printk(KERN_INFO "GDROM: %s from %s with firmware %s\n",
> + model_name, manuf_name, firmw_ver);
> err = 0;
> kfree(firmw_ver);
> free_manuf_name:
> @@ -641,7 +665,8 @@
> gd.cd_info->ops = &gdrom_ops;
> gd.cd_info->capacity = 1;
> strcpy(gd.cd_info->name, GDROM_DEV_NAME);
> - gd.cd_info->mask = CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|CDC_SELECT_DISC;
> + gd.cd_info->mask = CDC_CLOSE_TRAY | CDC_OPEN_TRAY |
> + CDC_LOCK | CDC_SELECT_DISC;
> }
>
> static void __devinit probe_gdrom_setupdisk(void)
> @@ -671,7 +696,7 @@
> {
> int err;
> if (gdrom_execute_diagnostic() != 1) {
> - printk(KERN_WARNING "GDROM: ATA Probe for GDROM failed.\n");
> + printk(KERN_WARNING "GDROM: ATA Probe for GDROM failed\n");
> return -ENODEV;
> }
> if (gdrom_outputversion())
> @@ -679,7 +704,8 @@
> gdrom_major = register_blkdev(0, GDROM_DEV_NAME);
> if (gdrom_major <= 0)
> return gdrom_major;
> - printk(KERN_INFO "GDROM: Block device is registered with major number %d\n", gdrom_major);
> + printk(KERN_INFO "GDROM: Block device is registered "
> + "with major number %d\n", gdrom_major);
> gd.cd_info = kzalloc(sizeof(struct cdrom_device_info), GFP_KERNEL);
> if (!gd.cd_info) {
> err = -ENOMEM;
> @@ -724,7 +750,8 @@
> unregister_blkdev(gdrom_major, GDROM_DEV_NAME);
> gdrom_major = 0;
> probe_fail_no_mem:
> - printk(KERN_WARNING "GDROM: Could not probe for device - error is 0x%X\n", err);
> + printk(KERN_WARNING "GDROM: Could not probe for device - "
> + "error is 0x%X\n", err);
> return err;
> }
>
>
>
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-sh" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Applied this over the last patch and I can confirm it works like a
charm :)
Tested on the "sh-2.6" git kernel using two different GD-Rom drives.
Both commercial gd-rom's and cd-r's can be mounted.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-28 19:17 ` Gino Badouri
@ 2007-12-28 22:09 ` Joe Perches
0 siblings, 0 replies; 20+ messages in thread
From: Joe Perches @ 2007-12-28 22:09 UTC (permalink / raw)
To: Gino Badouri; +Cc: Adrian McMenamin, Paul Mundt, Jens Axboe, LKML, linux-sh
On Fri, 2007-12-28 at 20:17 +0100, Gino Badouri wrote:
> Applied this over the last patch and I can confirm it works like a
> charm :)
It's Adrian's patch that works well. Thanks Adrian.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-28 0:18 ` Simon Holm Thøgersen
@ 2007-12-29 1:57 ` Joe Perches
2007-12-29 12:03 ` Adrian McMenamin
0 siblings, 1 reply; 20+ messages in thread
From: Joe Perches @ 2007-12-29 1:57 UTC (permalink / raw)
To: Simon Holm Thøgersen
Cc: Adrian McMenamin, Paul Mundt, Jens Axboe, LKML, linux-sh
On Fri, 2007-12-28 at 01:18 +0100, Simon Holm Thøgersen wrote:
> > - while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) && (time_before(jiffies, timeout)))
> > + while (gdrom_is_busy() && (time_before(jiffies, timeout)))
> You don't need those parentheses.
> > + while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) != 8) &&
> > + (time_before(jiffies, timeout)))
> What about a nice telling function like gdrom_is_busy for this?
Perhaps (uncompiled/untested):
Remove unnecessary parenthesis
Remove GDROM: prefix from sense_texts
Add function gdrom_data_request
Check sense_key against sense_text array size
Signed-off-by: Joe Perches <joe@perches.com>
---
drivers/cdrom/gdrom.c | 53 ++++++++++++++++++++++++++----------------------
1 files changed, 29 insertions(+), 24 deletions(-)
diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
index 59d26e0..ab95438 100644
--- a/drivers/cdrom/gdrom.c
+++ b/drivers/cdrom/gdrom.c
@@ -80,16 +80,15 @@ static const struct {
int sense_key;
const char * const text;
} sense_texts[] = {
- {NO_SENSE, "GDROM: OK"},
- {RECOVERED_ERROR, "GDROM: Recovered from error"},
- {NOT_READY, "GDROM: Device not ready"},
- {MEDIUM_ERROR, "GDROM: Disk not ready"},
- {HARDWARE_ERROR, "GDROM: Hardware error"},
- {ILLEGAL_REQUEST, "GDROM: Command has failed"},
- {UNIT_ATTENTION, "GDROM: Device needs attention - "
- "disk may have been changed"},
- {DATA_PROTECT, "GDROM: Data protection error"},
- {ABORTED_COMMAND, "GDROM: Command aborted"},
+ {NO_SENSE, "OK"},
+ {RECOVERED_ERROR, "Recovered from error"},
+ {NOT_READY, "Device not ready"},
+ {MEDIUM_ERROR, "Disk not ready"},
+ {HARDWARE_ERROR, "Hardware error"},
+ {ILLEGAL_REQUEST, "Command has failed"},
+ {UNIT_ATTENTION, "Device needs attention - disk may have been changed"},
+ {DATA_PROTECT, "Data protection error"},
+ {ABORTED_COMMAND, "Command aborted"},
};
static struct platform_device *pd;
@@ -140,11 +139,16 @@ static bool gdrom_is_busy(void)
return (ctrl_inb(GDROM_ALTSTATUS_REG) & 0x80) != 0;
}
+static bool gdrom_data_request(void)
+{
+ return (ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) == 8;
+}
+
static void gdrom_wait_clrbusy(void)
{
/* long timeouts - typical for a CD Rom */
unsigned long timeout = jiffies + HZ * 60;
- while (gdrom_is_busy() && (time_before(jiffies, timeout)))
+ while (gdrom_is_busy() && time_before(jiffies, timeout))
cpu_relax();
}
@@ -153,7 +157,7 @@ static void gdrom_wait_busy_sleeps(void)
unsigned long timeout;
/* Wait to get busy first */
timeout = jiffies + HZ * 60;
- while (!gdrom_is_busy() && (time_before(jiffies, timeout)))
+ while (!gdrom_is_busy() && time_before(jiffies, timeout))
cpu_relax();
/* Now wait for busy to clear */
gdrom_wait_clrbusy();
@@ -186,8 +190,8 @@ static void gdrom_spicommand(void *spi_string, int buflen)
/* Wait until we can go */
gdrom_wait_clrbusy();
ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
- while ((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) != 8)
- cpu_relax(); /* wait for DRQ to be set to 1 */
+ while (!gdrom_data_request())
+ cpu_relax();
outsw(PHYSADDR(GDROM_DATA_REG), cmd, 6);
}
@@ -354,7 +358,7 @@ static int gdrom_drivestatus(struct cdrom_device_info *cd_info, int ignore)
static int gdrom_mediachanged(struct cdrom_device_info *cd_info, int ignore)
{
/* check the sense key */
- return ((ctrl_inb(GDROM_ERROR_REG) & 0xF0) == 0x60);
+ return (ctrl_inb(GDROM_ERROR_REG) & 0xF0) == 0x60;
}
/* reset the G1 bus */
@@ -412,11 +416,13 @@ static int gdrom_getsense(short *bufstring)
return -EIO;
}
sense_key = sense[1] & 0x0F;
- printk(KERN_INFO "%s\n", sense_texts[sense_key].text);
+ if (sense_key < ARRAY_SIZE(sense_texts))
+ printk(KERN_INFO "GDROM: %s\n", sense_texts[sense_key].text);
+ else
+ printk(KERN_ERR "GDROM: Unknown sense key: %d\n", sense_key);
- if (bufstring)
+ if (bufstring) /* return additional sense data */
memcpy(bufstring, &sense[4], 2);
- /* return additional sense data */
if (sense_key < 2)
return 0;
@@ -550,19 +556,18 @@ static void gdrom_readdisk_dma(struct work_struct *work)
ctrl_outb(0, GDROM_INTSEC_REG);
/* In multiple DMA transfers need to wait */
timeout = jiffies + HZ / 2;
- while (gdrom_is_busy() && (time_before(jiffies, timeout)))
+ while (gdrom_is_busy() && time_before(jiffies, timeout))
cpu_relax();
ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
timeout = jiffies + HZ / 2;
- while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) != 8) &&
- (time_before(jiffies, timeout)))
- cpu_relax(); /* wait for DRQ to be set to 1 */
+ while (!gdrom_data_request() && time_before(jiffies, timeout))
+ cpu_relax();
gd.pending = 1;
gd.transfer = 1;
outsw(PHYSADDR(GDROM_DATA_REG), &read_command->cmd, 6);
timeout = jiffies + HZ / 2;
- while ((ctrl_inb(GDROM_DMA_STATUS_REG)) &&
- (time_before(jiffies, timeout)))
+ while (ctrl_inb(GDROM_DMA_STATUS_REG) &&
+ time_before(jiffies, timeout))
cpu_relax();
ctrl_outb(1, GDROM_DMA_STATUS_REG);
/* 5 second error margin here seems more reasonable */
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-29 1:57 ` Joe Perches
@ 2007-12-29 12:03 ` Adrian McMenamin
2007-12-29 12:10 ` Adrian McMenamin
2007-12-29 18:07 ` Joe Perches
0 siblings, 2 replies; 20+ messages in thread
From: Adrian McMenamin @ 2007-12-29 12:03 UTC (permalink / raw)
To: Joe Perches; +Cc: LKML, linux-sh, Paul Mundt
On Fri, 2007-12-28 at 17:57 -0800, Joe Perches wrote:
>
> Perhaps (uncompiled/untested):
>
> Remove unnecessary parenthesis
> Remove GDROM: prefix from sense_texts
> Add function gdrom_data_request
> Check sense_key against sense_text array size
>
> Signed-off-by: Joe Perches <joe@perches.com>
> ---
> drivers/cdrom/gdrom.c | 53 ++++++++++++++++++++++++++----------------------
> 1 files changed, 29 insertions(+), 24 deletions(-)
>
> diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
> index 59d26e0..ab95438 100644
> --- a/drivers/cdrom/gdrom.c
> +++ b/drivers/cdrom/gdrom.c
> @@ -80,16 +80,15 @@ static const struct {
> int sense_key;
> const char * const text;
> } sense_texts[] = {
> - {NO_SENSE, "GDROM: OK"},
> - {RECOVERED_ERROR, "GDROM: Recovered from error"},
> - {NOT_READY, "GDROM: Device not ready"},
> - {MEDIUM_ERROR, "GDROM: Disk not ready"},
> - {HARDWARE_ERROR, "GDROM: Hardware error"},
> - {ILLEGAL_REQUEST, "GDROM: Command has failed"},
> - {UNIT_ATTENTION, "GDROM: Device needs attention - "
> - "disk may have been changed"},
> - {DATA_PROTECT, "GDROM: Data protection error"},
> - {ABORTED_COMMAND, "GDROM: Command aborted"},
> + {NO_SENSE, "OK"},
> + {RECOVERED_ERROR, "Recovered from error"},
> + {NOT_READY, "Device not ready"},
> + {MEDIUM_ERROR, "Disk not ready"},
> + {HARDWARE_ERROR, "Hardware error"},
> + {ILLEGAL_REQUEST, "Command has failed"},
> + {UNIT_ATTENTION, "Device needs attention - disk may have been changed"},
> + {DATA_PROTECT, "Data protection error"},
> + {ABORTED_COMMAND, "Command aborted"},
> };
>
> /* reset the G1 bus */
> @@ -412,11 +416,13 @@ static int gdrom_getsense(short *bufstring)
> return -EIO;
> }
> sense_key = sense[1] & 0x0F;
> - printk(KERN_INFO "%s\n", sense_texts[sense_key].text);
> + if (sense_key < ARRAY_SIZE(sense_texts))
> + printk(KERN_INFO "GDROM: %s\n", sense_texts[sense_key].text);
> + else
> + printk(KERN_ERR "GDROM: Unknown sense key: %d\n", sense_key);
>
> - if (bufstring)
> + if (bufstring) /* return additional sense data */
> memcpy(bufstring, &sense[4], 2);
> - /* return additional sense data */
>
> if (sense_key < 2)
> return 0;
> @@ -550,19 +556,18 @@ static void gdrom_readdisk_dma(struct work_struct *work)
> ctrl_outb(0, GDROM_INTSEC_REG);
> /* In multiple DMA transfers need to wait */
> timeout = jiffies + HZ / 2;
> - while (gdrom_is_busy() && (time_before(jiffies, timeout)))
> + while (gdrom_is_busy() && time_before(jiffies, timeout))
> cpu_relax();
> ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
> timeout = jiffies + HZ / 2;
> - while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) != 8) &&
> - (time_before(jiffies, timeout)))
> - cpu_relax(); /* wait for DRQ to be set to 1 */
> + while (!gdrom_data_request() && time_before(jiffies, timeout))
> + cpu_relax();
> gd.pending = 1;
> gd.transfer = 1;
> outsw(PHYSADDR(GDROM_DATA_REG), &read_command->cmd, 6);
> timeout = jiffies + HZ / 2;
> - while ((ctrl_inb(GDROM_DMA_STATUS_REG)) &&
> - (time_before(jiffies, timeout)))
> + while (ctrl_inb(GDROM_DMA_STATUS_REG) &&
> + time_before(jiffies, timeout))
> cpu_relax();
> ctrl_outb(1, GDROM_DMA_STATUS_REG);
> /* 5 second error margin here seems more reasonable */
>
>
> -
This won't work see include/scsi/scsi.h
/*
* 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
(The GD device specs says it supports 0, 1, 2, 3,4, 5, 6, 7 and 0xB)
ie we could get a sense key of 0x0B which would be greater than the
array size. I think you'd have to hard code the limit.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-29 12:03 ` Adrian McMenamin
@ 2007-12-29 12:10 ` Adrian McMenamin
2007-12-29 18:07 ` Joe Perches
1 sibling, 0 replies; 20+ messages in thread
From: Adrian McMenamin @ 2007-12-29 12:10 UTC (permalink / raw)
To: Joe Perches; +Cc: LKML, linux-sh, Paul Mundt
On Sat, 2007-12-29 at 12:03 +0000, Adrian McMenamin wrote:
> On Fri, 2007-12-28 at 17:57 -0800, Joe Perches wrote:
>
> >
> > Perhaps (uncompiled/untested):
> >
> > Remove unnecessary parenthesis
> > Remove GDROM: prefix from sense_texts
> > Add function gdrom_data_request
> > Check sense_key against sense_text array size
> >
> > Signed-off-by: Joe Perches <joe@perches.com>
> > ---
> > drivers/cdrom/gdrom.c | 53 ++++++++++++++++++++++++++----------------------
> > 1 files changed, 29 insertions(+), 24 deletions(-)
> >
> > diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c
> > index 59d26e0..ab95438 100644
> > --- a/drivers/cdrom/gdrom.c
> > +++ b/drivers/cdrom/gdrom.c
> > @@ -80,16 +80,15 @@ static const struct {
> > int sense_key;
> > const char * const text;
> > } sense_texts[] = {
> > - {NO_SENSE, "GDROM: OK"},
> > - {RECOVERED_ERROR, "GDROM: Recovered from error"},
> > - {NOT_READY, "GDROM: Device not ready"},
> > - {MEDIUM_ERROR, "GDROM: Disk not ready"},
> > - {HARDWARE_ERROR, "GDROM: Hardware error"},
> > - {ILLEGAL_REQUEST, "GDROM: Command has failed"},
> > - {UNIT_ATTENTION, "GDROM: Device needs attention - "
> > - "disk may have been changed"},
> > - {DATA_PROTECT, "GDROM: Data protection error"},
> > - {ABORTED_COMMAND, "GDROM: Command aborted"},
> > + {NO_SENSE, "OK"},
> > + {RECOVERED_ERROR, "Recovered from error"},
> > + {NOT_READY, "Device not ready"},
> > + {MEDIUM_ERROR, "Disk not ready"},
> > + {HARDWARE_ERROR, "Hardware error"},
> > + {ILLEGAL_REQUEST, "Command has failed"},
> > + {UNIT_ATTENTION, "Device needs attention - disk may have been changed"},
> > + {DATA_PROTECT, "Data protection error"},
> > + {ABORTED_COMMAND, "Command aborted"},
> > };
>
> >
> > /* reset the G1 bus */
> > @@ -412,11 +416,13 @@ static int gdrom_getsense(short *bufstring)
> > return -EIO;
> > }
> > sense_key = sense[1] & 0x0F;
> > - printk(KERN_INFO "%s\n", sense_texts[sense_key].text);
> > + if (sense_key < ARRAY_SIZE(sense_texts))
> > + printk(KERN_INFO "GDROM: %s\n", sense_texts[sense_key].text);
> > + else
> > + printk(KERN_ERR "GDROM: Unknown sense key: %d\n", sense_key);
> >
> > - if (bufstring)
> > + if (bufstring) /* return additional sense data */
> > memcpy(bufstring, &sense[4], 2);
> > - /* return additional sense data */
> >
> > if (sense_key < 2)
> > return 0;
> > @@ -550,19 +556,18 @@ static void gdrom_readdisk_dma(struct work_struct *work)
> > ctrl_outb(0, GDROM_INTSEC_REG);
> > /* In multiple DMA transfers need to wait */
> > timeout = jiffies + HZ / 2;
> > - while (gdrom_is_busy() && (time_before(jiffies, timeout)))
> > + while (gdrom_is_busy() && time_before(jiffies, timeout))
> > cpu_relax();
> > ctrl_outb(GDROM_COM_PACKET, GDROM_STATUSCOMMAND_REG);
> > timeout = jiffies + HZ / 2;
> > - while (((ctrl_inb(GDROM_ALTSTATUS_REG) & 0x88) != 8) &&
> > - (time_before(jiffies, timeout)))
> > - cpu_relax(); /* wait for DRQ to be set to 1 */
> > + while (!gdrom_data_request() && time_before(jiffies, timeout))
> > + cpu_relax();
> > gd.pending = 1;
> > gd.transfer = 1;
> > outsw(PHYSADDR(GDROM_DATA_REG), &read_command->cmd, 6);
> > timeout = jiffies + HZ / 2;
> > - while ((ctrl_inb(GDROM_DMA_STATUS_REG)) &&
> > - (time_before(jiffies, timeout)))
> > + while (ctrl_inb(GDROM_DMA_STATUS_REG) &&
> > + time_before(jiffies, timeout))
> > cpu_relax();
> > ctrl_outb(1, GDROM_DMA_STATUS_REG);
> > /* 5 second error margin here seems more reasonable */
> >
> >
> > -
>
>
> This won't work see include/scsi/scsi.h
>
>
> /*
> * 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
>
> (The GD device specs says it supports 0, 1, 2, 3,4, 5, 6, 7 and 0xB)
>
> ie we could get a sense key of 0x0B which would be greater than the
> array size. I think you'd have to hard code the limit.
>
>
Ignore that. Talking rubbish. As usual.
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-29 12:03 ` Adrian McMenamin
2007-12-29 12:10 ` Adrian McMenamin
@ 2007-12-29 18:07 ` Joe Perches
1 sibling, 0 replies; 20+ messages in thread
From: Joe Perches @ 2007-12-29 18:07 UTC (permalink / raw)
To: Adrian McMenamin; +Cc: LKML, linux-sh, Paul Mundt
On Sat, 2007-12-29 at 12:03 +0000, Adrian McMenamin wrote:
> This won't work see include/scsi/scsi.h
> /*
> * 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
>
> (The GD device specs says it supports 0, 1, 2, 3,4, 5, 6, 7 and 0xB)
>
> ie we could get a sense key of 0x0B which would be greater than the
> array size. I think you'd have to hard code the limit.
Then shouldn't this test be:
for (i = 0; i < ARRAY_SIZE(sense_texts); i++) {
if (sense_key == sense_texts[i].sense_key)
printk(KERN_INFO "GDROM: %s\n", sense_texts[i].text);
}
if (i >= ARRAY_SIZE(sense_texts))
printk(KERN_ERR "GDROM: Unknown sense key: %d\n", sense_key);
cheers, Joe
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-27 22:58 ` Joe Perches
` (2 preceding siblings ...)
2007-12-28 19:17 ` Gino Badouri
@ 2007-12-30 13:38 ` Adrian McMenamin
2007-12-31 5:23 ` Paul Mundt
3 siblings, 1 reply; 20+ messages in thread
From: Adrian McMenamin @ 2007-12-30 13:38 UTC (permalink / raw)
To: Joe Perches; +Cc: Paul Mundt, Jens Axboe, LKML, linux-sh
On Thu, 2007-12-27 at 14:58 -0800, Joe Perches wrote:
> On Thu, 2007-12-27 at 16:52 +0000, Adrian McMenamin wrote:
> > This patch adds support for the CD-Rom drive on the SEGA Dreamcast.
>
> Because it was already so close, might as well make it checkpatch clean.
>
> I also added a function gdrom_is_busy() to make a couple of tests
> fit on a single line and perhaps easier to read.
>
> Signed-off-by: Joe Perches <joe@perches.com>
>
Not really for me to decide if this gets applied - I'll leave that to
Paul as the maintainer. But I have no objection to them :)
^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH] SH/Dreamcast - add support for GD-Rom device
2007-12-30 13:38 ` Adrian McMenamin
@ 2007-12-31 5:23 ` Paul Mundt
0 siblings, 0 replies; 20+ messages in thread
From: Paul Mundt @ 2007-12-31 5:23 UTC (permalink / raw)
To: Adrian McMenamin; +Cc: Joe Perches, Jens Axboe, LKML, linux-sh
On Sun, Dec 30, 2007 at 01:38:24PM +0000, Adrian McMenamin wrote:
> On Thu, 2007-12-27 at 14:58 -0800, Joe Perches wrote:
> > On Thu, 2007-12-27 at 16:52 +0000, Adrian McMenamin wrote:
> > > This patch adds support for the CD-Rom drive on the SEGA Dreamcast.
> >
> > Because it was already so close, might as well make it checkpatch clean.
> >
> > I also added a function gdrom_is_busy() to make a couple of tests
> > fit on a single line and perhaps easier to read.
> >
> > Signed-off-by: Joe Perches <joe@perches.com>
> >
> Not really for me to decide if this gets applied - I'll leave that to
> Paul as the maintainer. But I have no objection to them :)
Both patches are fine with me, but it is ultimately Jens (as the
drivers/cdrom authority) that will have to decide whether to sign off on
the GDROM patches or not, and through which tree the patches will end up
being merged. I can certainly merge them through my tree with his
Acked-by if that's deemed the most convenient.
^ permalink raw reply [flat|nested] 20+ messages in thread
end of thread, other threads:[~2007-12-31 5:23 UTC | newest]
Thread overview: 20+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-12-27 16:52 [PATCH] SH/Dreamcast - add support for GD-Rom device Adrian McMenamin
2007-12-27 20:56 ` Adrian McMenamin
2007-12-27 22:20 ` Paul Mundt
2007-12-27 22:58 ` Joe Perches
2007-12-28 0:18 ` Simon Holm Thøgersen
2007-12-29 1:57 ` Joe Perches
2007-12-29 12:03 ` Adrian McMenamin
2007-12-29 12:10 ` Adrian McMenamin
2007-12-29 18:07 ` Joe Perches
2007-12-28 0:49 ` Mike Frysinger
2007-12-28 3:41 ` Paul Mundt
2007-12-28 19:17 ` Gino Badouri
2007-12-28 22:09 ` Joe Perches
2007-12-30 13:38 ` Adrian McMenamin
2007-12-31 5:23 ` Paul Mundt
-- strict thread matches above, loose matches on Subject: below --
2007-12-27 1:26 Adrian McMenamin
2007-12-27 8:18 ` Paul Mundt
2007-12-27 12:49 ` Adrian McMenamin
2007-12-27 19:52 ` Jens Axboe
2007-12-27 19:11 ` Mike Frysinger
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox