Commit ca2d5cec authored by Pete Zaitcev's avatar Pete Zaitcev Committed by Greg Kroah-Hartman

[PATCH] USB: Add ioctls to ub

This patch adds support for ioctls to ub, with the help of scsi_ioctl_cmd().
Now ub can eject CDs. But do not try to burn CDs yet, it's not tested.

Original patch from Peter Jones (aka deviant-).
Signed-off-by: default avatarPete Zaitcev <zaitcev@redhat.com>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 9adbc5e6
...@@ -300,6 +300,11 @@ struct ub_dev { ...@@ -300,6 +300,11 @@ struct ub_dev {
/* /*
*/ */
static int ub_bd_rq_fn_1(struct ub_dev *sc, struct request *rq);
static int ub_cmd_build_block(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
struct request *rq);
static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
struct request *rq);
static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd); static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
static void ub_end_rq(struct request *rq, int uptodate); static void ub_end_rq(struct request *rq, int uptodate);
static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd); static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
...@@ -591,40 +596,73 @@ static struct ub_scsi_cmd *ub_cmdq_pop(struct ub_dev *sc) ...@@ -591,40 +596,73 @@ static struct ub_scsi_cmd *ub_cmdq_pop(struct ub_dev *sc)
* The request function is our main entry point * The request function is our main entry point
*/ */
static inline int ub_bd_rq_fn_1(request_queue_t *q) static void ub_bd_rq_fn(request_queue_t *q)
{ {
#if 0
int writing = 0, pci_dir, i, n_elem;
u32 tmp;
unsigned int msg_size;
#endif
struct ub_dev *sc = q->queuedata; struct ub_dev *sc = q->queuedata;
struct request *rq; struct request *rq;
#if 0 /* We use rq->buffer for now */
struct scatterlist *sg; while ((rq = elv_next_request(q)) != NULL) {
int n_elem; if (ub_bd_rq_fn_1(sc, rq) != 0) {
#endif blk_stop_queue(q);
break;
}
}
}
static int ub_bd_rq_fn_1(struct ub_dev *sc, struct request *rq)
{
struct ub_scsi_cmd *cmd; struct ub_scsi_cmd *cmd;
int ub_dir;
unsigned int block, nblks;
int rc; int rc;
if ((rq = elv_next_request(q)) == NULL)
return 1;
if (atomic_read(&sc->poison) || sc->changed) { if (atomic_read(&sc->poison) || sc->changed) {
blkdev_dequeue_request(rq); blkdev_dequeue_request(rq);
ub_end_rq(rq, 0); ub_end_rq(rq, 0);
return 0; return 0;
} }
if ((cmd = ub_get_cmd(sc)) == NULL) { if ((cmd = ub_get_cmd(sc)) == NULL)
blk_stop_queue(q); return -1;
return 1; memset(cmd, 0, sizeof(struct ub_scsi_cmd));
}
blkdev_dequeue_request(rq); blkdev_dequeue_request(rq);
if (blk_pc_request(rq)) {
rc = ub_cmd_build_packet(sc, cmd, rq);
} else {
rc = ub_cmd_build_block(sc, cmd, rq);
}
if (rc != 0) {
ub_put_cmd(sc, cmd);
ub_end_rq(rq, 0);
blk_start_queue(sc->disk->queue);
return 0;
}
cmd->state = UB_CMDST_INIT;
cmd->done = ub_rw_cmd_done;
cmd->back = rq;
cmd->tag = sc->tagcnt++;
if ((rc = ub_submit_scsi(sc, cmd)) != 0) {
ub_put_cmd(sc, cmd);
ub_end_rq(rq, 0);
blk_start_queue(sc->disk->queue);
return 0;
}
return 0;
}
static int ub_cmd_build_block(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
struct request *rq)
{
int ub_dir;
#if 0 /* We use rq->buffer for now */
struct scatterlist *sg;
int n_elem;
#endif
unsigned int block, nblks;
if (rq_data_dir(rq) == WRITE) if (rq_data_dir(rq) == WRITE)
ub_dir = UB_DIR_WRITE; ub_dir = UB_DIR_WRITE;
else else
...@@ -652,6 +690,7 @@ static inline int ub_bd_rq_fn_1(request_queue_t *q) ...@@ -652,6 +690,7 @@ static inline int ub_bd_rq_fn_1(request_queue_t *q)
return 0; return 0;
} }
#endif #endif
/* /*
* XXX Unfortunately, this check does not work. It is quite possible * XXX Unfortunately, this check does not work. It is quite possible
* to get bogus non-null rq->buffer if you allow sg by mistake. * to get bogus non-null rq->buffer if you allow sg by mistake.
...@@ -663,13 +702,12 @@ static inline int ub_bd_rq_fn_1(request_queue_t *q) ...@@ -663,13 +702,12 @@ static inline int ub_bd_rq_fn_1(request_queue_t *q)
*/ */
static int do_print = 1; static int do_print = 1;
if (do_print) { if (do_print) {
printk(KERN_WARNING "%s: unmapped request\n", sc->name); printk(KERN_WARNING "%s: unmapped block request"
" flags 0x%lx sectors %lu\n",
sc->name, rq->flags, rq->nr_sectors);
do_print = 0; do_print = 0;
} }
ub_put_cmd(sc, cmd); return -1;
ub_end_rq(rq, 0);
blk_start_queue(q);
return 0;
} }
/* /*
...@@ -681,7 +719,6 @@ static inline int ub_bd_rq_fn_1(request_queue_t *q) ...@@ -681,7 +719,6 @@ static inline int ub_bd_rq_fn_1(request_queue_t *q)
block = rq->sector >> sc->capacity.bshift; block = rq->sector >> sc->capacity.bshift;
nblks = rq->nr_sectors >> sc->capacity.bshift; nblks = rq->nr_sectors >> sc->capacity.bshift;
memset(cmd, 0, sizeof(struct ub_scsi_cmd));
cmd->cdb[0] = (ub_dir == UB_DIR_READ)? READ_10: WRITE_10; cmd->cdb[0] = (ub_dir == UB_DIR_READ)? READ_10: WRITE_10;
/* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */ /* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */
cmd->cdb[2] = block >> 24; cmd->cdb[2] = block >> 24;
...@@ -691,27 +728,44 @@ static inline int ub_bd_rq_fn_1(request_queue_t *q) ...@@ -691,27 +728,44 @@ static inline int ub_bd_rq_fn_1(request_queue_t *q)
cmd->cdb[7] = nblks >> 8; cmd->cdb[7] = nblks >> 8;
cmd->cdb[8] = nblks; cmd->cdb[8] = nblks;
cmd->cdb_len = 10; cmd->cdb_len = 10;
cmd->dir = ub_dir; cmd->dir = ub_dir;
cmd->state = UB_CMDST_INIT;
cmd->data = rq->buffer; cmd->data = rq->buffer;
cmd->len = rq->nr_sectors * 512; cmd->len = rq->nr_sectors * 512;
cmd->done = ub_rw_cmd_done;
cmd->back = rq;
cmd->tag = sc->tagcnt++;
if ((rc = ub_submit_scsi(sc, cmd)) != 0) {
ub_put_cmd(sc, cmd);
ub_end_rq(rq, 0);
blk_start_queue(q);
return 0;
}
return 0; return 0;
} }
static void ub_bd_rq_fn(request_queue_t *q) static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
struct request *rq)
{ {
do { } while (ub_bd_rq_fn_1(q) == 0);
if (rq->data_len != 0 && rq->data == NULL) {
static int do_print = 1;
if (do_print) {
printk(KERN_WARNING "%s: unmapped packet request"
" flags 0x%lx length %d\n",
sc->name, rq->flags, rq->data_len);
do_print = 0;
}
return -1;
}
memcpy(&cmd->cdb, rq->cmd, rq->cmd_len);
cmd->cdb_len = rq->cmd_len;
if (rq->data_len == 0) {
cmd->dir = UB_DIR_NONE;
} else {
if (rq_data_dir(rq) == WRITE)
cmd->dir = UB_DIR_WRITE;
else
cmd->dir = UB_DIR_READ;
}
cmd->data = rq->data;
cmd->len = rq->data_len;
return 0;
} }
static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd) static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
...@@ -884,6 +938,7 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) ...@@ -884,6 +938,7 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
{ {
struct urb *urb = &sc->work_urb; struct urb *urb = &sc->work_urb;
struct bulk_cs_wrap *bcs; struct bulk_cs_wrap *bcs;
struct request *rq = cmd->back;
int pipe; int pipe;
int rc; int rc;
...@@ -1137,6 +1192,13 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd) ...@@ -1137,6 +1192,13 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
(*cmd->done)(sc, cmd); (*cmd->done)(sc, cmd);
} else if (cmd->state == UB_CMDST_SENSE) { } else if (cmd->state == UB_CMDST_SENSE) {
if (blk_pc_request(rq)) {
/*
* UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE
*/
memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE);
rq->sense_len = UB_SENSE_SIZE;
}
ub_state_done(sc, cmd, -EIO); ub_state_done(sc, cmd, -EIO);
} else { } else {
...@@ -1495,30 +1557,10 @@ static int ub_bd_release(struct inode *inode, struct file *filp) ...@@ -1495,30 +1557,10 @@ static int ub_bd_release(struct inode *inode, struct file *filp)
static int ub_bd_ioctl(struct inode *inode, struct file *filp, static int ub_bd_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
// void __user *usermem = (void *) arg; struct gendisk *disk = inode->i_bdev->bd_disk;
// struct carm_port *port = ino->i_bdev->bd_disk->private_data; void __user *usermem = (void __user *) arg;
// struct hd_geometry geom;
#if 0
switch (cmd) {
case HDIO_GETGEO:
if (usermem == NULL) // XXX Bizzare. Why?
return -EINVAL;
geom.heads = (u8) port->dev_geom_head;
geom.sectors = (u8) port->dev_geom_sect;
geom.cylinders = port->dev_geom_cyl;
geom.start = get_start_sect(ino->i_bdev);
if (copy_to_user(usermem, &geom, sizeof(geom)))
return -EFAULT;
return 0;
default: ;
}
#endif
return -ENOTTY; return scsi_cmd_ioctl(filp, disk, cmd, usermem);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment