Commit a98b28b1 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge bk://kernel.bkbits.net/acme/usb-2.5

into kroah.com:/home/greg/linux/BK/gregkh-2.5
parents 832b5fae 25d1aa56
...@@ -59,3 +59,6 @@ obj-$(CONFIG_USB_TEST) += misc/ ...@@ -59,3 +59,6 @@ obj-$(CONFIG_USB_TEST) += misc/
obj-$(CONFIG_USB_TIGL) += misc/ obj-$(CONFIG_USB_TIGL) += misc/
obj-$(CONFIG_USB_USS720) += misc/ obj-$(CONFIG_USB_USS720) += misc/
obj-$(CONFIG_USB_NET2280) += gadget/
obj-$(CONFIG_USB_ZERO) += gadget/
obj-$(CONFIG_USB_ETH) += gadget/
...@@ -1199,12 +1199,18 @@ int usb_physical_reset_device(struct usb_device *dev) ...@@ -1199,12 +1199,18 @@ int usb_physical_reset_device(struct usb_device *dev)
if (port < 0) if (port < 0)
return -ENOENT; return -ENOENT;
descriptor = kmalloc(sizeof *descriptor, GFP_NOIO);
if (!descriptor) {
return -ENOMEM;
}
down(&usb_address0_sem); down(&usb_address0_sem);
/* Send a reset to the device */ /* Send a reset to the device */
if (usb_hub_port_reset(parent, port, dev, HUB_SHORT_RESET_TIME)) { if (usb_hub_port_reset(parent, port, dev, HUB_SHORT_RESET_TIME)) {
usb_hub_port_disable(parent, port); usb_hub_port_disable(parent, port);
up(&usb_address0_sem); up(&usb_address0_sem);
kfree(descriptor);
return(-ENODEV); return(-ENODEV);
} }
...@@ -1214,6 +1220,7 @@ int usb_physical_reset_device(struct usb_device *dev) ...@@ -1214,6 +1220,7 @@ int usb_physical_reset_device(struct usb_device *dev)
err("USB device not accepting new address (error=%d)", ret); err("USB device not accepting new address (error=%d)", ret);
usb_hub_port_disable(parent, port); usb_hub_port_disable(parent, port);
up(&usb_address0_sem); up(&usb_address0_sem);
kfree(descriptor);
return ret; return ret;
} }
...@@ -1231,10 +1238,7 @@ int usb_physical_reset_device(struct usb_device *dev) ...@@ -1231,10 +1238,7 @@ int usb_physical_reset_device(struct usb_device *dev)
* If nothing changed, we reprogram the configuration and then * If nothing changed, we reprogram the configuration and then
* the alternate settings. * the alternate settings.
*/ */
descriptor = kmalloc(sizeof *descriptor, GFP_NOIO);
if (!descriptor) {
return -ENOMEM;
}
ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, descriptor, ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, descriptor,
sizeof(*descriptor)); sizeof(*descriptor));
if (ret < 0) { if (ret < 0) {
......
...@@ -22,63 +22,54 @@ static char *states[]={"FREE", "BEGINNING", "WORKING", "ERROR", "WAIT", "PREMATU ...@@ -22,63 +22,54 @@ static char *states[]={"FREE", "BEGINNING", "WORKING", "ERROR", "WAIT", "PREMATU
#define TRACE_STATE printk(KERN_DEBUG"hpusbscsi->state = %s at line %d\n", states[hpusbscsi->state], __LINE__) #define TRACE_STATE printk(KERN_DEBUG"hpusbscsi->state = %s at line %d\n", states[hpusbscsi->state], __LINE__)
/* global variables */ static Scsi_Host_Template hpusbscsi_scsi_host_template = {
.module = THIS_MODULE,
struct list_head hpusbscsi_devices; .name = "hpusbscsi",
//LIST_HEAD(hpusbscsi_devices); .proc_name = "hpusbscsi",
.queuecommand = hpusbscsi_scsi_queuecommand,
/* USB related parts */ .eh_abort_handler = hpusbscsi_scsi_abort,
.eh_host_reset_handler = hpusbscsi_scsi_host_reset,
.sg_tablesize = SG_ALL,
.can_queue = 1,
.this_id = -1,
.cmd_per_lun = 1,
.use_clustering = 1,
.emulated = 1,
};
static int static int
hpusbscsi_usb_probe (struct usb_interface *intf, hpusbscsi_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *altsetting = intf->altsetting;
struct hpusbscsi *new; struct hpusbscsi *new;
struct usb_device *dev = interface_to_usbdev (intf); int error = -ENOMEM;
struct usb_host_interface *altsetting =
&(intf->altsetting[0]);
int i, result; int i, result;
/* basic check */
if (altsetting->desc.bNumEndpoints != 3) { if (altsetting->desc.bNumEndpoints != 3) {
printk (KERN_ERR "Wrong number of endpoints\n"); printk (KERN_ERR "Wrong number of endpoints\n");
return -ENODEV; return -ENODEV;
} }
/* descriptor allocation */ new = kmalloc(sizeof(struct hpusbscsi), GFP_KERNEL);
if (!new)
new =
(struct hpusbscsi *) kmalloc (sizeof (struct hpusbscsi),
GFP_KERNEL);
if (new == NULL)
return -ENOMEM; return -ENOMEM;
DEBUG ("Allocated memory\n"); memset(new, 0, sizeof(struct hpusbscsi));
memset (new, 0, sizeof (struct hpusbscsi));
new->dataurb = usb_alloc_urb(0, GFP_KERNEL); new->dataurb = usb_alloc_urb(0, GFP_KERNEL);
if (!new->dataurb) { if (!new->dataurb)
kfree (new); goto out_kfree;
return -ENOMEM;
}
new->controlurb = usb_alloc_urb(0, GFP_KERNEL); new->controlurb = usb_alloc_urb(0, GFP_KERNEL);
if (!new->controlurb) { if (!new->controlurb)
usb_free_urb (new->dataurb); goto out_free_dataurb;
kfree (new);
return -ENOMEM;
}
new->dev = dev;
init_waitqueue_head (&new->pending);
init_waitqueue_head (&new->deathrow);
INIT_LIST_HEAD (&new->lh);
new->dev = dev;
init_waitqueue_head(&new->pending);
init_waitqueue_head(&new->deathrow);
/* finding endpoints */ error = -ENODEV;
for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
if ( if ((altsetting->endpoint[i].desc.
(altsetting->endpoint[i].desc.
bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_BULK) { USB_ENDPOINT_XFER_BULK) {
if (altsetting->endpoint[i].desc. if (altsetting->endpoint[i].desc.
...@@ -97,57 +88,71 @@ hpusbscsi_usb_probe (struct usb_interface *intf, ...@@ -97,57 +88,71 @@ hpusbscsi_usb_probe (struct usb_interface *intf,
new->ep_int = new->ep_int =
altsetting->endpoint[i].desc. altsetting->endpoint[i].desc.
bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
new->interrupt_interval= altsetting->endpoint[i].desc.bInterval; new->interrupt_interval= altsetting->endpoint[i].desc.
bInterval;
} }
} }
/* USB initialisation magic for the simple case */ /* USB initialisation magic for the simple case */
result = usb_set_interface(dev, altsetting->desc.bInterfaceNumber, 0);
result = usb_set_interface (dev, altsetting->desc.bInterfaceNumber, 0);
switch (result) { switch (result) {
case 0: /* no error */ case 0: /* no error */
break; break;
default: default:
printk (KERN_ERR "unknown error %d from usb_set_interface\n", printk(KERN_ERR "unknown error %d from usb_set_interface\n",
result); result);
goto err_out; goto out_free_controlurb;
} }
/* making a template for the scsi layer to fake detection of a scsi device */ /* build and submit an interrupt URB for status byte handling */
usb_fill_int_urb(new->controlurb, new->dev,
usb_rcvintpipe(new->dev, new->ep_int),
&new->scsi_state_byte, 1,
control_interrupt_callback,new,
new->interrupt_interval);
if (usb_submit_urb(new->controlurb, GFP_KERNEL) < 0)
goto out_free_controlurb;
memcpy (&(new->ctempl), &hpusbscsi_scsi_host_template, /* In host->hostdata we store a pointer to desc */
sizeof (hpusbscsi_scsi_host_template)); new->host = scsi_register(&hpusbscsi_scsi_host_template, sizeof(new));
(struct hpusbscsi *) new->ctempl.proc_dir = new; if (!new->host)
new->ctempl.module = THIS_MODULE; goto out_unlink_controlurb;
if (scsi_register_host(&new->ctempl)) new->host->hostdata[0] = (unsigned long)new;
goto err_out; scsi_add_host(new->host, &intf->dev);
new->sense_command[0] = REQUEST_SENSE; new->sense_command[0] = REQUEST_SENSE;
new->sense_command[4] = HPUSBSCSI_SENSE_LENGTH; new->sense_command[4] = HPUSBSCSI_SENSE_LENGTH;
/* adding to list for module unload */
list_add (&hpusbscsi_devices, &new->lh);
usb_set_intfdata(intf, new); usb_set_intfdata(intf, new);
return 0; return 0;
err_out: out_unlink_controlurb:
usb_free_urb (new->controlurb); usb_unlink_urb(new->controlurb);
usb_free_urb (new->dataurb); out_free_controlurb:
kfree (new); usb_free_urb(new->controlurb);
return -ENODEV; out_free_dataurb:
usb_free_urb(new->dataurb);
out_kfree:
kfree(new);
return error;
} }
static void static void
hpusbscsi_usb_disconnect (struct usb_interface *intf) hpusbscsi_usb_disconnect(struct usb_interface *intf)
{ {
struct hpusbscsi *desc = usb_get_intfdata(intf); struct hpusbscsi *desc = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
if (desc)
scsi_remove_host(desc->host);
usb_unlink_urb(desc->controlurb); usb_unlink_urb(desc->controlurb);
scsi_unregister(desc->host);
usb_free_urb(desc->controlurb);
usb_free_urb(desc->dataurb);
kfree(desc);
} }
static struct usb_device_id hpusbscsi_usb_ids[] = { static struct usb_device_id hpusbscsi_usb_ids[] = {
...@@ -178,101 +183,21 @@ static struct usb_driver hpusbscsi_usb_driver = { ...@@ -178,101 +183,21 @@ static struct usb_driver hpusbscsi_usb_driver = {
/* module initialisation */ /* module initialisation */
int __init static int __init
hpusbscsi_init (void) hpusbscsi_init (void)
{ {
int result; return usb_register(&hpusbscsi_usb_driver);
INIT_LIST_HEAD (&hpusbscsi_devices);
DEBUG ("Driver loaded\n");
if ((result = usb_register (&hpusbscsi_usb_driver)) < 0) {
printk (KERN_ERR "hpusbscsi: driver registration failed\n");
return -1;
} else {
return 0;
}
} }
void __exit static void __exit
hpusbscsi_exit (void) hpusbscsi_exit (void)
{ {
struct list_head *tmp; usb_deregister(&hpusbscsi_usb_driver);
struct list_head *old;
struct hpusbscsi * o;
for (tmp = hpusbscsi_devices.next; tmp != &hpusbscsi_devices;/*nothing */) {
old = tmp;
tmp = tmp->next;
o = (struct hpusbscsi *)old;
usb_unlink_urb(o->controlurb);
scsi_unregister_host(&o->ctempl);
usb_free_urb(o->controlurb);
usb_free_urb(o->dataurb);
kfree(old);
}
usb_deregister (&hpusbscsi_usb_driver);
} }
module_init (hpusbscsi_init); module_init (hpusbscsi_init);
module_exit (hpusbscsi_exit); module_exit (hpusbscsi_exit);
/* interface to the scsi layer */
static int
hpusbscsi_scsi_detect (struct SHT *sht)
{
/* Whole function stolen from usb-storage */
struct hpusbscsi *desc = (struct hpusbscsi *) sht->proc_dir;
/* What a hideous hack! */
char local_name[48];
/* set up the name of our subdirectory under /proc/scsi/ */
sprintf (local_name, "hpusbscsi-%d", desc->number);
sht->proc_name = kmalloc (strlen (local_name) + 1, GFP_KERNEL);
/* FIXME: where is this freed ? */
if (!sht->proc_name) {
return 0;
}
strcpy (sht->proc_name, local_name);
sht->proc_dir = NULL;
/* build and submit an interrupt URB for status byte handling */
usb_fill_int_urb(desc->controlurb,
desc->dev,
usb_rcvintpipe(desc->dev,desc->ep_int),
&desc->scsi_state_byte,
1,
control_interrupt_callback,
desc,
desc->interrupt_interval
);
if ( 0 > usb_submit_urb(desc->controlurb, GFP_KERNEL)) {
kfree(sht->proc_name);
return 0;
}
/* In host->hostdata we store a pointer to desc */
desc->host = scsi_register (sht, sizeof (desc));
if (desc->host == NULL) {
kfree (sht->proc_name);
usb_unlink_urb(desc->controlurb);
return 0;
}
desc->host->hostdata[0] = (unsigned long) desc;
return 1;
}
static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback) static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback)
{ {
struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->device->host->hostdata[0]); struct hpusbscsi* hpusbscsi = (struct hpusbscsi*)(srb->device->host->hostdata[0]);
......
...@@ -13,7 +13,6 @@ typedef void (*scsi_callback)(Scsi_Cmnd *); ...@@ -13,7 +13,6 @@ typedef void (*scsi_callback)(Scsi_Cmnd *);
struct hpusbscsi struct hpusbscsi
{ {
struct list_head lh;
struct usb_device *dev; /* NULL indicates unplugged device */ struct usb_device *dev; /* NULL indicates unplugged device */
int ep_out; int ep_out;
int ep_in; int ep_in;
...@@ -36,7 +35,6 @@ struct hpusbscsi ...@@ -36,7 +35,6 @@ struct hpusbscsi
int state; int state;
int current_data_pipe; int current_data_pipe;
Scsi_Host_Template ctempl;
u8 sense_command[SENSE_COMMAND_SIZE]; u8 sense_command[SENSE_COMMAND_SIZE];
u8 scsi_state_byte; u8 scsi_state_byte;
}; };
...@@ -52,7 +50,6 @@ static const unsigned char scsi_command_direction[256/8] = { ...@@ -52,7 +50,6 @@ static const unsigned char scsi_command_direction[256/8] = {
#define DIRECTION_IS_IN(x) ((scsi_command_direction[x>>3] >> (x & 7)) & 1) #define DIRECTION_IS_IN(x) ((scsi_command_direction[x>>3] >> (x & 7)) & 1)
static int hpusbscsi_scsi_detect (struct SHT * sht);
static void simple_command_callback(struct urb *u, struct pt_regs *regs); static void simple_command_callback(struct urb *u, struct pt_regs *regs);
static void scatter_gather_callback(struct urb *u, struct pt_regs *regs); static void scatter_gather_callback(struct urb *u, struct pt_regs *regs);
static void simple_payload_callback (struct urb *u, struct pt_regs *regs); static void simple_payload_callback (struct urb *u, struct pt_regs *regs);
...@@ -64,25 +61,6 @@ static int hpusbscsi_scsi_host_reset (Scsi_Cmnd *srb); ...@@ -64,25 +61,6 @@ static int hpusbscsi_scsi_host_reset (Scsi_Cmnd *srb);
static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb); static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb);
static void issue_request_sense (struct hpusbscsi *hpusbscsi); static void issue_request_sense (struct hpusbscsi *hpusbscsi);
static Scsi_Host_Template hpusbscsi_scsi_host_template = {
.name = "hpusbscsi",
.detect = hpusbscsi_scsi_detect,
// .release = hpusbscsi_scsi_release,
.queuecommand = hpusbscsi_scsi_queuecommand,
.eh_abort_handler = hpusbscsi_scsi_abort,
.eh_host_reset_handler = hpusbscsi_scsi_host_reset,
.sg_tablesize = SG_ALL,
.can_queue = 1,
.this_id = -1,
.cmd_per_lun = 1,
.present = 0,
.unchecked_isa_dma = FALSE,
.use_clustering = TRUE,
.emulated = TRUE
};
/* defines for internal driver state */ /* defines for internal driver state */
#define HP_STATE_FREE 0 /*ready for next request */ #define HP_STATE_FREE 0 /*ready for next request */
#define HP_STATE_BEGINNING 1 /*command being transferred */ #define HP_STATE_BEGINNING 1 /*command being transferred */
......
...@@ -327,76 +327,6 @@ static inline void mts_urb_abort(struct mts_desc* desc) { ...@@ -327,76 +327,6 @@ static inline void mts_urb_abort(struct mts_desc* desc) {
usb_unlink_urb( desc->urb ); usb_unlink_urb( desc->urb );
} }
static struct mts_desc * mts_list; /* list of active scanners */
struct semaphore mts_list_semaphore;
/* Internal list operations */
static
void mts_remove_nolock( struct mts_desc* to_remove )
{
MTS_DEBUG( "removing 0x%x from list\n",
(int)to_remove );
lock_kernel();
mts_urb_abort(to_remove);
MTS_DEBUG_GOT_HERE();
if ( to_remove != mts_list ) {
MTS_DEBUG_GOT_HERE();
if (to_remove->prev && to_remove->next)
to_remove->prev->next = to_remove->next;
} else {
MTS_DEBUG_GOT_HERE();
mts_list = to_remove->next;
if (mts_list) {
MTS_DEBUG_GOT_HERE();
mts_list->prev = 0;
}
}
if ( to_remove->next ) {
MTS_DEBUG_GOT_HERE();
to_remove->next->prev = to_remove->prev;
}
MTS_DEBUG_GOT_HERE();
scsi_unregister_host(&to_remove->ctempl);
unlock_kernel();
usb_free_urb(to_remove->urb);
kfree( to_remove );
}
static
void mts_add_nolock( struct mts_desc* to_add )
{
MTS_DEBUG( "adding 0x%x to list\n", (int)to_add );
to_add->prev = 0;
to_add->next = mts_list;
if ( mts_list ) {
mts_list->prev = to_add;
}
mts_list = to_add;
}
/* SCSI driver interface */
/* scsi related functions - dummies for now mostly */
static int mts_scsi_release(struct Scsi_Host *psh)
{
MTS_DEBUG_GOT_HERE();
return 0;
}
static int mts_scsi_abort (Scsi_Cmnd *srb) static int mts_scsi_abort (Scsi_Cmnd *srb)
{ {
struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]); struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]);
...@@ -419,54 +349,6 @@ static int mts_scsi_host_reset (Scsi_Cmnd *srb) ...@@ -419,54 +349,6 @@ static int mts_scsi_host_reset (Scsi_Cmnd *srb)
return 0; /* RANT why here 0 and not SUCCESS */ return 0; /* RANT why here 0 and not SUCCESS */
} }
/* the core of the scsi part */
/* faking a detection - which can't fail :-) */
static int mts_scsi_detect (struct SHT * sht)
{
/* Whole function stolen from usb-storage */
struct mts_desc * desc = (struct mts_desc *)sht->proc_dir;
/* What a hideous hack! */
char local_name[48];
MTS_DEBUG_GOT_HERE();
/* set up the name of our subdirectory under /proc/scsi/ */
sprintf(local_name, "microtek-%d", desc->host_number);
sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_KERNEL);
/* FIXME: where is this freed ? */
if (!sht->proc_name) {
MTS_ERROR( "unable to allocate memory for proc interface!!\n" );
return 0;
}
strcpy(sht->proc_name, local_name);
sht->proc_dir = NULL;
/* In host->hostdata we store a pointer to desc */
desc->host = scsi_register(sht, sizeof(desc));
if (desc->host == NULL) {
MTS_ERROR("Cannot register due to low memory");
kfree(sht->proc_name);
return 0;
}
desc->host->hostdata[0] = (unsigned long)desc;
/* FIXME: what if sizeof(void*) != sizeof(unsigned long)? */
return 1;
}
/* Main entrypoint: SCSI commands are dispatched to here */
static static
int mts_scsi_queuecommand (Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback ); int mts_scsi_queuecommand (Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback );
...@@ -744,52 +626,22 @@ int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback ) ...@@ -744,52 +626,22 @@ int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback )
out: out:
return err; return err;
} }
/*
* this defines our 'host'
*/
/* NOTE: This is taken from usb-storage, should be right. */
static Scsi_Host_Template mts_scsi_host_template = { static Scsi_Host_Template mts_scsi_host_template = {
.module = THIS_MODULE,
.name = "microtekX6", .name = "microtekX6",
.detect = mts_scsi_detect, .proc_name = "microtekX6",
.release = mts_scsi_release,
.queuecommand = mts_scsi_queuecommand, .queuecommand = mts_scsi_queuecommand,
.eh_abort_handler = mts_scsi_abort, .eh_abort_handler = mts_scsi_abort,
.eh_host_reset_handler =mts_scsi_host_reset, .eh_host_reset_handler = mts_scsi_host_reset,
.sg_tablesize = SG_ALL, .sg_tablesize = SG_ALL,
.can_queue = 1, .can_queue = 1,
.this_id = -1, .this_id = -1,
.cmd_per_lun = 1, .cmd_per_lun = 1,
.present = 0, .use_clustering = 1,
.unchecked_isa_dma = FALSE, .emulated = 1,
.use_clustering = TRUE,
.emulated = TRUE
}; };
/* USB layer driver interface implementation */
static void mts_usb_disconnect (struct usb_interface *intf)
{
struct mts_desc* to_remove = usb_get_intfdata(intf);
MTS_DEBUG_GOT_HERE();
usb_set_intfdata(intf, NULL);
if (to_remove) {
/* leave the list - lock it */
down(&mts_list_semaphore);
mts_remove_nolock(to_remove);
up(&mts_list_semaphore);
}
}
struct vendor_product struct vendor_product
{ {
char* name; char* name;
...@@ -837,7 +689,7 @@ static struct usb_device_id mts_usb_ids [] = ...@@ -837,7 +689,7 @@ static struct usb_device_id mts_usb_ids [] =
MODULE_DEVICE_TABLE (usb, mts_usb_ids); MODULE_DEVICE_TABLE (usb, mts_usb_ids);
static int mts_usb_probe (struct usb_interface *intf, static int mts_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
int i; int i;
...@@ -930,39 +782,23 @@ static int mts_usb_probe (struct usb_interface *intf, ...@@ -930,39 +782,23 @@ static int mts_usb_probe (struct usb_interface *intf,
} }
/* allocating a new descriptor */ new_desc = kmalloc(sizeof(struct mts_desc), GFP_KERNEL);
new_desc = (struct mts_desc *)kmalloc(sizeof(struct mts_desc), GFP_KERNEL); if (!new_desc)
if (new_desc == NULL) goto out;
{
MTS_ERROR("couldn't allocate scanner desc, bailing out!\n");
return -ENOMEM;
}
memset( new_desc, 0, sizeof(*new_desc) ); memset(new_desc, 0, sizeof(*new_desc));
new_desc->urb = usb_alloc_urb(0, GFP_KERNEL); new_desc->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!new_desc->urb) { if (!new_desc->urb)
kfree(new_desc); goto out_kfree;
return -ENOMEM;
}
/* initialising that descriptor */
new_desc->usb_dev = dev; new_desc->usb_dev = dev;
init_MUTEX(&new_desc->lock); init_MUTEX(&new_desc->lock);
if(mts_list){
new_desc->host_number = mts_list->host_number+1;
} else {
new_desc->host_number = 0;
}
/* endpoints */ /* endpoints */
new_desc->ep_out = ep_out; new_desc->ep_out = ep_out;
new_desc->ep_response = ep_in_set[0]; new_desc->ep_response = ep_in_set[0];
new_desc->ep_image = ep_in_set[1]; new_desc->ep_image = ep_in_set[1];
if ( new_desc->ep_out != MTS_EP_OUT ) if ( new_desc->ep_out != MTS_EP_OUT )
MTS_WARNING( "will this work? Command EP is not usually %d\n", MTS_WARNING( "will this work? Command EP is not usually %d\n",
(int)new_desc->ep_out ); (int)new_desc->ep_out );
...@@ -975,87 +811,48 @@ static int mts_usb_probe (struct usb_interface *intf, ...@@ -975,87 +811,48 @@ static int mts_usb_probe (struct usb_interface *intf,
MTS_WARNING( "will this work? Image data EP is not usually %d\n", MTS_WARNING( "will this work? Image data EP is not usually %d\n",
(int)new_desc->ep_image ); (int)new_desc->ep_image );
new_desc->host = scsi_register(&mts_scsi_host_template,
sizeof(new_desc));
if (!new_desc->host)
goto out_free_urb;
/* Initialize the host template based on the default one */ new_desc->host->hostdata[0] = (unsigned long)new_desc;
memcpy(&(new_desc->ctempl), &mts_scsi_host_template, sizeof(mts_scsi_host_template)); scsi_add_host(new_desc->host, NULL);
/* HACK from usb-storage - this is needed for scsi detection */
(struct mts_desc *)new_desc->ctempl.proc_dir = new_desc; /* FIXME */
MTS_DEBUG("registering SCSI module\n"); usb_set_intfdata(intf, new_desc);
return 0;
new_desc->ctempl.module = THIS_MODULE;
result = scsi_register_host(&new_desc->ctempl);
/* Will get hit back in microtek_detect by this func */
if ( result )
{
MTS_ERROR( "error %d from scsi_register_host! Help!\n",
(int)result );
/* FIXME: need more cleanup? */ out_free_urb:
kfree( new_desc ); usb_free_urb(new_desc->urb);
out_kfree:
kfree(new_desc);
out:
return -ENOMEM; return -ENOMEM;
} }
MTS_DEBUG_GOT_HERE();
/* FIXME: the bomb is armed, must the host be registered under lock ? */
/* join the list - lock it */
down(&mts_list_semaphore);
mts_add_nolock( new_desc );
up(&mts_list_semaphore); static void mts_usb_disconnect (struct usb_interface *intf)
{
struct mts_desc *desc = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
MTS_DEBUG("completed probe and exiting happily\n"); scsi_remove_host(desc->host);
usb_unlink_urb(desc->urb);
scsi_unregister(desc->host);
usb_set_intfdata(intf, new_desc); usb_free_urb(desc->urb);
return 0; kfree(desc);
} }
static int __init microtek_drv_init(void)
/* get us noticed by the rest of the kernel */
int __init microtek_drv_init(void)
{ {
int result; return usb_register(&mts_usb_driver);
MTS_DEBUG_GOT_HERE();
init_MUTEX(&mts_list_semaphore);
if ((result = usb_register(&mts_usb_driver)) < 0) {
MTS_DEBUG("usb_register returned %d\n", result );
return -1;
} else {
MTS_DEBUG("driver registered.\n");
}
info(DRIVER_VERSION ":" DRIVER_DESC);
return 0;
} }
void __exit microtek_drv_exit(void) static void __exit microtek_drv_exit(void)
{ {
struct mts_desc* next;
MTS_DEBUG_GOT_HERE();
usb_deregister(&mts_usb_driver); usb_deregister(&mts_usb_driver);
down(&mts_list_semaphore);
while (mts_list) {
/* keep track of where the next one is */
next = mts_list->next;
mts_remove_nolock( mts_list );
/* advance the list pointer */
mts_list = next;
}
up(&mts_list_semaphore);
} }
module_init(microtek_drv_init); module_init(microtek_drv_init);
......
...@@ -38,9 +38,6 @@ struct mts_desc { ...@@ -38,9 +38,6 @@ struct mts_desc {
u8 ep_image; u8 ep_image;
struct Scsi_Host * host; struct Scsi_Host * host;
Scsi_Host_Template ctempl;
int host_number;
struct semaphore lock; struct semaphore lock;
struct urb *urb; struct urb *urb;
......
...@@ -171,9 +171,11 @@ static int usb_storage_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *)) ...@@ -171,9 +171,11 @@ static int usb_storage_queuecommand( Scsi_Cmnd *srb , void (*done)(Scsi_Cmnd *))
/* This is always called with scsi_lock(srb->host) held */ /* This is always called with scsi_lock(srb->host) held */
static int usb_storage_command_abort( Scsi_Cmnd *srb ) static int usb_storage_command_abort( Scsi_Cmnd *srb )
{ {
struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; struct Scsi_Host *host = srb->device->host;
struct us_data *us = (struct us_data *) host->hostdata[0];
int state = atomic_read(&us->sm_state);
US_DEBUGP("command_abort() called\n"); US_DEBUGP("%s called\n", __FUNCTION__);
/* Is this command still active? */ /* Is this command still active? */
if (us->srb != srb) { if (us->srb != srb) {
...@@ -181,7 +183,31 @@ static int usb_storage_command_abort( Scsi_Cmnd *srb ) ...@@ -181,7 +183,31 @@ static int usb_storage_command_abort( Scsi_Cmnd *srb )
return FAILED; return FAILED;
} }
return usb_stor_abort_transport(us); /* Normally the current state is RUNNING. If the control thread
* hasn't even started processing this command, the state will be
* IDLE. Anything else is a bug. */
if (state != US_STATE_RUNNING && state != US_STATE_IDLE) {
printk(KERN_ERR USB_STORAGE "Error in %s: "
"invalid state %d\n", __FUNCTION__, state);
return FAILED;
}
/* Set state to ABORTING, set the ABORTING bit, and release the lock */
atomic_set(&us->sm_state, US_STATE_ABORTING);
set_bit(US_FLIDX_ABORTING, &us->flags);
scsi_unlock(host);
/* If the state was RUNNING, stop an ongoing USB transfer */
if (state == US_STATE_RUNNING)
usb_stor_stop_transport(us);
/* Wait for the aborted command to finish */
wait_for_completion(&us->notify);
/* Reacquire the lock and allow USB transfers to resume */
scsi_lock(host);
clear_bit(US_FLIDX_ABORTING, &us->flags);
return SUCCESS;
} }
/* This invokes the transport reset mechanism to reset the state of the /* This invokes the transport reset mechanism to reset the state of the
......
...@@ -69,32 +69,35 @@ ...@@ -69,32 +69,35 @@
* as those occurring during device-specific initialization, must be handled * as those occurring during device-specific initialization, must be handled
* by a separate code path.) * by a separate code path.)
* *
* The abort function first sets the machine state, then atomically * The abort function (usb_storage_command_abort() in scsiglue.c) first
* tests-and-clears the CAN_CANCEL bit in us->flags to see if the current_urb * sets the machine state and the ABORTING bit in us->flags to prevent
* needs to be aborted. * new URBs from being submitted. It then calls usb_stor_stop_transport()
* below, which atomically tests-and-clears the URB_ACTIVE bit in us->flags
* to see if the current_urb needs to be stopped. Likewise, the SG_ACTIVE
* bit is tested to see if the current_sg scatter-gather request needs to be
* stopped.
* *
* The submit function first verifies that the submission completed without * When a disconnect occurs, the DISCONNECTING bit in us->flags is set to
* errors, and only then sets the CAN_CANCEL bit. This prevents the abort * prevent new URBs from being submitted, and usb_stor_stop_transport() is
* function from trying to cancel the URB while the submit call is underway. * called to stop any ongoing requests.
* Next, the submit function must test the state to see if we got aborted
* before the submission or before setting the CAN_CANCEL bit. If so, it's
* essential to abort the URB if it hasn't been cancelled already (i.e.,
* if the CAN_CANCEL bit is still set). Either way, the function must then
* wait for the URB to finish. Note that because the URB_ASYNC_UNLINK flag
* is set, the URB can still be in progress even after a call to
* usb_unlink_urb() returns.
* *
* (It's also permissible, but not necessary, to test the state -before- * The submit function first verifies that the submitting is allowed
* submitting the URB. Doing so would prevent an unnecessary submission if * (neither ABORTING nor DISCONNECTING bits are set) and that the submit
* the transaction had already been aborted, but this is very unlikely to * completes without errors, and only then sets the URB_ACTIVE bit. This
* happen, because the abort would have to have been requested during actual * prevents the stop_transport() function from trying to cancel the URB
* kernel processing rather than during an I/O delay.) * while the submit call is underway. Next, the submit function must test
* the flags to see if an abort or disconnect occurred during the submission
* or before the URB_ACTIVE bit was set. If so, it's essential to cancel
* the URB if it hasn't been cancelled already (i.e., if the URB_ACTIVE bit
* is still set). Either way, the function must then wait for the URB to
* finish. Note that because the URB_ASYNC_UNLINK flag is set, the URB can
* still be in progress even after a call to usb_unlink_urb() returns.
* *
* The idea is that (1) once the state is changed to ABORTING, either the * The idea is that (1) once the ABORTING or DISCONNECTING bit is set,
* aborting function or the submitting function is guaranteed to call * either the stop_transport() function or the submitting function
* usb_unlink_urb() for an active URB, and (2) test_and_clear_bit() prevents * is guaranteed to call usb_unlink_urb() for an active URB,
* usb_unlink_urb() from being called more than once or from being called * and (2) test_and_clear_bit() prevents usb_unlink_urb() from being
* during usb_submit_urb(). * called more than once or from being called during usb_submit_urb().
*/ */
/* This is the completion handler which will wake us up when an URB /* This is the completion handler which will wake us up when an URB
...@@ -118,6 +121,10 @@ static int usb_stor_msg_common(struct us_data *us) ...@@ -118,6 +121,10 @@ static int usb_stor_msg_common(struct us_data *us)
struct completion urb_done; struct completion urb_done;
int status; int status;
/* don't submit URBS during abort/disconnect processing */
if (us->flags & DONT_SUBMIT)
return -ECONNRESET;
/* set up data structures for the wakeup system */ /* set up data structures for the wakeup system */
init_completion(&urb_done); init_completion(&urb_done);
...@@ -137,13 +144,13 @@ static int usb_stor_msg_common(struct us_data *us) ...@@ -137,13 +144,13 @@ static int usb_stor_msg_common(struct us_data *us)
/* since the URB has been submitted successfully, it's now okay /* since the URB has been submitted successfully, it's now okay
* to cancel it */ * to cancel it */
set_bit(US_FLIDX_CAN_CANCEL, &us->flags); set_bit(US_FLIDX_URB_ACTIVE, &us->flags);
/* has the current command been aborted? */ /* did an abort/disconnect occur during the submission? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { if (us->flags & DONT_SUBMIT) {
/* cancel the URB, if it hasn't been cancelled already */ /* cancel the URB, if it hasn't been cancelled already */
if (test_and_clear_bit(US_FLIDX_CAN_CANCEL, &us->flags)) { if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) {
US_DEBUGP("-- cancelling URB\n"); US_DEBUGP("-- cancelling URB\n");
usb_unlink_urb(us->current_urb); usb_unlink_urb(us->current_urb);
} }
...@@ -151,7 +158,7 @@ static int usb_stor_msg_common(struct us_data *us) ...@@ -151,7 +158,7 @@ static int usb_stor_msg_common(struct us_data *us)
/* wait for the completion of the URB */ /* wait for the completion of the URB */
wait_for_completion(&urb_done); wait_for_completion(&urb_done);
clear_bit(US_FLIDX_CAN_CANCEL, &us->flags); clear_bit(US_FLIDX_URB_ACTIVE, &us->flags);
/* return the URB status */ /* return the URB status */
return us->current_urb->status; return us->current_urb->status;
...@@ -185,53 +192,6 @@ int usb_stor_control_msg(struct us_data *us, unsigned int pipe, ...@@ -185,53 +192,6 @@ int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
return status; return status;
} }
/* This is our function to emulate usb_bulk_msg() with enough control
* to make aborts/resets/timeouts work
*/
int usb_stor_bulk_msg(struct us_data *us, void *data, unsigned int pipe,
unsigned int len, unsigned int *act_len)
{
int status;
/* fill and submit the URB */
usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, data, len,
usb_stor_blocking_completion, NULL);
status = usb_stor_msg_common(us);
/* store the actual length of the data transferred */
*act_len = us->current_urb->actual_length;
return status;
}
/* This is our function to submit interrupt URBs with enough control
* to make aborts/resets/timeouts work
*
* This routine always uses us->recv_intr_pipe as the pipe and
* us->ep_bInterval as the interrupt interval.
*/
int usb_stor_interrupt_msg(struct us_data *us, void *data,
unsigned int len, unsigned int *act_len)
{
unsigned int pipe = us->recv_intr_pipe;
unsigned int maxp;
int status;
/* calculate the max packet size */
maxp = usb_maxpacket(us->pusb_dev, pipe, usb_pipeout(pipe));
if (maxp > len)
maxp = len;
/* fill and submit the URB */
usb_fill_int_urb(us->current_urb, us->pusb_dev, pipe, data,
maxp, usb_stor_blocking_completion, NULL,
us->ep_bInterval);
status = usb_stor_msg_common(us);
/* store the actual length of the data transferred */
*act_len = us->current_urb->actual_length;
return status;
}
/* This is a version of usb_clear_halt() that doesn't read the status from /* This is a version of usb_clear_halt() that doesn't read the status from
* the device -- this is because some devices crash their internal firmware * the device -- this is because some devices crash their internal firmware
* when the status is requested after a halt. * when the status is requested after a halt.
...@@ -275,12 +235,12 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe) ...@@ -275,12 +235,12 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
* Interpret the results of a URB transfer * Interpret the results of a URB transfer
* *
* This function prints appropriate debugging messages, clears halts on * This function prints appropriate debugging messages, clears halts on
* bulk endpoints, and translates the status to the corresponding * non-control endpoints, and translates the status to the corresponding
* USB_STOR_XFER_xxx return code. * USB_STOR_XFER_xxx return code.
*/ */
static int interpret_urb_result(struct us_data *us, unsigned int pipe, static int interpret_urb_result(struct us_data *us, unsigned int pipe,
unsigned int length, int result, unsigned int partial) { unsigned int length, int result, unsigned int partial)
{
US_DEBUGP("Status code %d; transferred %u/%u\n", US_DEBUGP("Status code %d; transferred %u/%u\n",
result, partial, length); result, partial, length);
switch (result) { switch (result) {
...@@ -333,95 +293,109 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe, ...@@ -333,95 +293,109 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe,
} }
/* /*
* Transfer one control message * Transfer one control message, without timeouts, but allowing early
* * termination. Return codes are USB_STOR_XFER_xxx.
* This function does basically the same thing as usb_stor_control_msg()
* above, except that return codes are USB_STOR_XFER_xxx rather than the
* urb status or transfer length.
*/ */
int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
u8 request, u8 requesttype, u16 value, u16 index, u8 request, u8 requesttype, u16 value, u16 index,
void *data, u16 size) { void *data, u16 size)
{
int result; int result;
unsigned int partial = 0;
US_DEBUGP("usb_stor_ctrl_transfer(): rq=%02x rqtype=%02x " US_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n",
"value=%04x index=%02x len=%u\n", __FUNCTION__, request, requesttype,
request, requesttype, value, index, size); value, index, size);
result = usb_stor_control_msg(us, pipe, request, requesttype,
value, index, data, size);
if (result > 0) { /* Separate out the amount transferred */ /* fill in the devrequest structure */
partial = result; us->dr->bRequestType = requesttype;
result = 0; us->dr->bRequest = request;
} us->dr->wValue = cpu_to_le16(value);
return interpret_urb_result(us, pipe, size, result, partial); us->dr->wIndex = cpu_to_le16(index);
us->dr->wLength = cpu_to_le16(size);
/* fill and submit the URB */
usb_fill_control_urb(us->current_urb, us->pusb_dev, pipe,
(unsigned char*) us->dr, data, size,
usb_stor_blocking_completion, NULL);
result = usb_stor_msg_common(us);
return interpret_urb_result(us, pipe, size, result,
us->current_urb->actual_length);
} }
/* /*
* Receive one buffer via interrupt transfer * Receive one interrupt buffer, without timeouts, but allowing early
* termination. Return codes are USB_STOR_XFER_xxx.
* *
* This function does basically the same thing as usb_stor_interrupt_msg() * This routine always uses us->recv_intr_pipe as the pipe and
* above, except that return codes are USB_STOR_XFER_xxx rather than the * us->ep_bInterval as the interrupt interval.
* urb status.
*/ */
int usb_stor_intr_transfer(struct us_data *us, void *buf, int usb_stor_intr_transfer(struct us_data *us, void *buf, unsigned int length)
unsigned int length, unsigned int *act_len)
{ {
int result; int result;
unsigned int partial; unsigned int pipe = us->recv_intr_pipe;
unsigned int maxp;
/* transfer the data */ US_DEBUGP("%s: xfer %u bytes\n", __FUNCTION__, length);
US_DEBUGP("usb_stor_intr_transfer(): xfer %u bytes\n", length);
result = usb_stor_interrupt_msg(us, buf, length, &partial); /* calculate the max packet size */
if (act_len) maxp = usb_maxpacket(us->pusb_dev, pipe, usb_pipeout(pipe));
*act_len = partial; if (maxp > length)
maxp = length;
/* fill and submit the URB */
usb_fill_int_urb(us->current_urb, us->pusb_dev, pipe, buf,
maxp, usb_stor_blocking_completion, NULL,
us->ep_bInterval);
result = usb_stor_msg_common(us);
return interpret_urb_result(us, us->recv_intr_pipe, return interpret_urb_result(us, pipe, length, result,
length, result, partial); us->current_urb->actual_length);
} }
/* /*
* Transfer one buffer via bulk transfer * Transfer one buffer via bulk pipe, without timeouts, but allowing early
* * termination. Return codes are USB_STOR_XFER_xxx. If the bulk pipe
* This function does basically the same thing as usb_stor_bulk_msg() * stalls during the transfer, the halt is automatically cleared.
* above, except that:
*
* 1. If the bulk pipe stalls during the transfer, the halt is
* automatically cleared;
* 2. Return codes are USB_STOR_XFER_xxx rather than the
* urb status or transfer length.
*/ */
int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
void *buf, unsigned int length, unsigned int *act_len) void *buf, unsigned int length, unsigned int *act_len)
{ {
int result; int result;
unsigned int partial;
/* transfer the data */ US_DEBUGP("%s: xfer %u bytes\n", __FUNCTION__, length);
US_DEBUGP("usb_stor_bulk_transfer_buf(): xfer %u bytes\n", length);
result = usb_stor_bulk_msg(us, buf, pipe, length, &partial); /* fill and submit the URB */
usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length,
usb_stor_blocking_completion, NULL);
result = usb_stor_msg_common(us);
/* store the actual length of the data transferred */
if (act_len) if (act_len)
*act_len = partial; *act_len = us->current_urb->actual_length;
return interpret_urb_result(us, pipe, length, result, partial); return interpret_urb_result(us, pipe, length, result,
us->current_urb->actual_length);
} }
/* /*
* Transfer a scatter-gather list via bulk transfer * Transfer a scatter-gather list via bulk transfer
* *
* This function does basically the same thing as usb_stor_bulk_transfer_buf() * This function does basically the same thing as usb_stor_bulk_transfer_buf()
* above, but it uses the usbcore scatter-gather primitives * above, but it uses the usbcore scatter-gather library.
*/ */
int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
struct scatterlist *sg, int num_sg, unsigned int length, struct scatterlist *sg, int num_sg, unsigned int length,
unsigned int *act_len) unsigned int *act_len)
{ {
int result; int result;
unsigned int partial;
/* don't submit s-g requests during abort/disconnect processing */
if (us->flags & DONT_SUBMIT)
return USB_STOR_XFER_ERROR;
/* initialize the scatter-gather request block */ /* initialize the scatter-gather request block */
US_DEBUGP("usb_stor_bulk_transfer_sglist(): xfer %u bytes, " US_DEBUGP("%s: xfer %u bytes, %d entries\n", __FUNCTION__,
"%d entries\n", length, num_sg); length, num_sg);
result = usb_sg_init(us->current_sg, us->pusb_dev, pipe, 0, result = usb_sg_init(us->current_sg, us->pusb_dev, pipe, 0,
sg, num_sg, length, SLAB_NOIO); sg, num_sg, length, SLAB_NOIO);
if (result) { if (result) {
...@@ -431,13 +405,13 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, ...@@ -431,13 +405,13 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
/* since the block has been initialized successfully, it's now /* since the block has been initialized successfully, it's now
* okay to cancel it */ * okay to cancel it */
set_bit(US_FLIDX_CANCEL_SG, &us->flags); set_bit(US_FLIDX_SG_ACTIVE, &us->flags);
/* has the current command been aborted? */ /* did an abort/disconnect occur during the submission? */
if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { if (us->flags & DONT_SUBMIT) {
/* cancel the request, if it hasn't been cancelled already */ /* cancel the request, if it hasn't been cancelled already */
if (test_and_clear_bit(US_FLIDX_CANCEL_SG, &us->flags)) { if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) {
US_DEBUGP("-- cancelling sg request\n"); US_DEBUGP("-- cancelling sg request\n");
usb_sg_cancel(us->current_sg); usb_sg_cancel(us->current_sg);
} }
...@@ -445,13 +419,13 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, ...@@ -445,13 +419,13 @@ int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
/* wait for the completion of the transfer */ /* wait for the completion of the transfer */
usb_sg_wait(us->current_sg); usb_sg_wait(us->current_sg);
clear_bit(US_FLIDX_CANCEL_SG, &us->flags); clear_bit(US_FLIDX_SG_ACTIVE, &us->flags);
result = us->current_sg->status; result = us->current_sg->status;
partial = us->current_sg->bytes;
if (act_len) if (act_len)
*act_len = partial; *act_len = us->current_sg->bytes;
return interpret_urb_result(us, pipe, length, result, partial); return interpret_urb_result(us, pipe, length, result,
us->current_sg->bytes);
} }
/* /*
...@@ -693,56 +667,32 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -693,56 +667,32 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
Handle_Abort: Handle_Abort:
srb->result = DID_ABORT << 16; srb->result = DID_ABORT << 16;
if (us->protocol == US_PR_BULK) { if (us->protocol == US_PR_BULK) {
/* permit the reset transfer to take place */
clear_bit(US_FLIDX_ABORTING, &us->flags);
us->transport_reset(us); us->transport_reset(us);
} }
} }
/* Abort the currently running scsi command or device reset. /* Stop the current URB transfer */
* This must be called with scsi_lock(us->srb->host) held */ void usb_stor_stop_transport(struct us_data *us)
int usb_stor_abort_transport(struct us_data *us)
{ {
struct Scsi_Host *host; US_DEBUGP("%s called\n", __FUNCTION__);
int state = atomic_read(&us->sm_state);
US_DEBUGP("usb_stor_abort_transport called\n");
/* Normally the current state is RUNNING. If the control thread
* hasn't even started processing this command, the state will be
* IDLE. Anything else is a bug. */
if (state != US_STATE_RUNNING && state != US_STATE_IDLE) {
printk(KERN_ERR USB_STORAGE "Error in %s: "
"invalid state %d\n", __FUNCTION__, state);
return FAILED;
}
/* set state to abort and release the lock */
atomic_set(&us->sm_state, US_STATE_ABORTING);
host = us->srb->device->host;
scsi_unlock(host);
/* If the state machine is blocked waiting for an URB, /* If the state machine is blocked waiting for an URB,
* let's wake it up */ * let's wake it up. The test_and_clear_bit() call
* guarantees that if a URB has just been submitted,
/* If we have an URB pending, cancel it. The test_and_clear_bit() * it won't be cancelled more than once. */
* call guarantees that if a URB has just been submitted, it if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) {
* won't be cancelled more than once. */
if (test_and_clear_bit(US_FLIDX_CAN_CANCEL, &us->flags)) {
US_DEBUGP("-- cancelling URB\n"); US_DEBUGP("-- cancelling URB\n");
usb_unlink_urb(us->current_urb); usb_unlink_urb(us->current_urb);
} }
/* If we are waiting for a scatter-gather operation, cancel it. */ /* If we are waiting for a scatter-gather operation, cancel it. */
if (test_and_clear_bit(US_FLIDX_CANCEL_SG, &us->flags)) { if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) {
US_DEBUGP("-- cancelling sg request\n"); US_DEBUGP("-- cancelling sg request\n");
usb_sg_cancel(us->current_sg); usb_sg_cancel(us->current_sg);
} }
/* Wait for the aborted command to finish */
wait_for_completion(&us->notify);
/* Reacquire the lock: note that us->srb is now NULL */
scsi_lock(host);
return SUCCESS;
} }
/* /*
...@@ -788,8 +738,7 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us) ...@@ -788,8 +738,7 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
} }
/* STATUS STAGE */ /* STATUS STAGE */
result = usb_stor_intr_transfer(us, us->irqdata, result = usb_stor_intr_transfer(us, us->irqdata, sizeof(us->irqdata));
sizeof(us->irqdata), NULL);
US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n", US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n",
us->irqdata[0], us->irqdata[1]); us->irqdata[0], us->irqdata[1]);
if (result != USB_STOR_XFER_GOOD) if (result != USB_STOR_XFER_GOOD)
......
...@@ -156,22 +156,18 @@ extern int usb_stor_Bulk_max_lun(struct us_data*); ...@@ -156,22 +156,18 @@ extern int usb_stor_Bulk_max_lun(struct us_data*);
extern int usb_stor_Bulk_reset(struct us_data*); extern int usb_stor_Bulk_reset(struct us_data*);
extern void usb_stor_invoke_transport(Scsi_Cmnd*, struct us_data*); extern void usb_stor_invoke_transport(Scsi_Cmnd*, struct us_data*);
extern int usb_stor_abort_transport(struct us_data*); extern void usb_stor_stop_transport(struct us_data*);
extern int usb_stor_bulk_msg(struct us_data *us, void *data,
unsigned int pipe, unsigned int len, unsigned int *act_len);
extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe, extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe,
u8 request, u8 requesttype, u16 value, u16 index, u8 request, u8 requesttype, u16 value, u16 index,
void *data, u16 size); void *data, u16 size);
extern int usb_stor_interrupt_msg(struct us_data *us, void *data,
unsigned int len, unsigned int *act_len);
extern int usb_stor_clear_halt(struct us_data*, unsigned int pipe); extern int usb_stor_clear_halt(struct us_data*, unsigned int pipe);
extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe,
u8 request, u8 requesttype, u16 value, u16 index, u8 request, u8 requesttype, u16 value, u16 index,
void *data, u16 size); void *data, u16 size);
extern int usb_stor_intr_transfer(struct us_data *us, void *buf, extern int usb_stor_intr_transfer(struct us_data *us, void *buf,
unsigned int length, unsigned int *act_len); unsigned int length);
extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
void *buf, unsigned int length, unsigned int *act_len); void *buf, unsigned int length, unsigned int *act_len);
extern int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, extern int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe,
......
...@@ -314,32 +314,17 @@ UNUSUAL_DEV( 0x059f, 0xa601, 0x0200, 0x0200, ...@@ -314,32 +314,17 @@ UNUSUAL_DEV( 0x059f, 0xa601, 0x0200, 0x0200,
* Submitted by James Courtier-Dutton <James@superbug.demon.co.uk> * Submitted by James Courtier-Dutton <James@superbug.demon.co.uk>
*/ */
UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000, UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000,
"ASAHI PENTAX", "Pentax",
"PENTAX OPTIO 430", "Optio 2/3/400",
US_SC_8070, US_PR_CBI, NULL,
US_FL_FIX_INQUIRY ),
/* This Pentax still camera is not conformant
* to the USB storage specification: -
* - It does not like the INQUIRY command. So we must handle this command
* of the SCSI layer ourselves.
* Tested on Rev. 10.00 (0x1000)
* Submitted by James Courtier-Dutton <James@superbug.demon.co.uk>
*/
UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000,
"ASAHI PENTAX",
"PENTAX OPTIO 430",
US_SC_8070, US_PR_CBI, NULL, US_SC_8070, US_PR_CBI, NULL,
US_FL_FIX_INQUIRY ), US_FL_FIX_INQUIRY ),
/* Pentax Optio S digital camera /* Submitted by Per Winkvist <per.winkvist@uk.com> */
* submitted by Stefan M. Brandl <smb@smbnet.de> UNUSUAL_DEV( 0x0a17, 0x006, 0x1000, 0x9009,
*/
UNUSUAL_DEV( 0x0a17, 0x0006, 0x0000, 0xffff,
"Pentax", "Pentax",
"Optio S", "Optio S",
US_SC_8070, US_PR_CB, NULL, US_SC_8070, US_PR_CBI, NULL,
US_FL_MODE_XLATE|US_FL_FIX_INQUIRY), US_FL_FIX_INQUIRY ),
#ifdef CONFIG_USB_STORAGE_ISD200 #ifdef CONFIG_USB_STORAGE_ISD200
UNUSUAL_DEV( 0x05ab, 0x0031, 0x0100, 0x0110, UNUSUAL_DEV( 0x05ab, 0x0031, 0x0100, 0x0110,
...@@ -639,26 +624,6 @@ UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x0001, ...@@ -639,26 +624,6 @@ UNUSUAL_DEV( 0x1065, 0x2136, 0x0000, 0x0001,
US_SC_SCSI, US_PR_BULK, NULL, US_SC_SCSI, US_PR_BULK, NULL,
US_FL_MODE_XLATE | US_FL_START_STOP | US_FL_FIX_INQUIRY ), US_FL_MODE_XLATE | US_FL_START_STOP | US_FL_FIX_INQUIRY ),
/* This Pentax still camera is not conformant
* to the USB storage specification: -
* - It does not like the INQUIRY command. So we must handle this command
* of the SCSI layer ourselves.
* Tested on Rev. 10.00 (0x1000)
* Submitted by James Courtier-Dutton <James@superbug.demon.co.uk>
*/
UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000,
"Pentax",
"Optio 2/3/400",
US_SC_8070, US_PR_CBI, NULL,
US_FL_FIX_INQUIRY ),
/* Submitted by Per Winkvist <per.winkvist@uk.com> */
UNUSUAL_DEV( 0x0a17, 0x006, 0x1000, 0x9009,
"Pentax",
"Optio S",
US_SC_8070, US_PR_CBI, NULL,
US_FL_FIX_INQUIRY ),
/* Submitted by Brian Hall <brihall@pcisys.net> /* Submitted by Brian Hall <brihall@pcisys.net>
* Needed for START_STOP flag */ * Needed for START_STOP flag */
UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100, UNUSUAL_DEV( 0x0c76, 0x0003, 0x0100, 0x0100,
......
...@@ -887,11 +887,8 @@ static int storage_probe(struct usb_interface *intf, ...@@ -887,11 +887,8 @@ static int storage_probe(struct usb_interface *intf,
/* set the hostdata to prepare for scanning */ /* set the hostdata to prepare for scanning */
us->host->hostdata[0] = (unsigned long)us; us->host->hostdata[0] = (unsigned long)us;
/* associate this host with our interface */
scsi_set_device(us->host, &intf->dev);
/* now add the host */ /* now add the host */
result = scsi_add_host(us->host, NULL); result = scsi_add_host(us->host, &intf->dev);
if (result) { if (result) {
printk(KERN_WARNING USB_STORAGE printk(KERN_WARNING USB_STORAGE
"Unable to add the scsi host\n"); "Unable to add the scsi host\n");
...@@ -942,16 +939,13 @@ static void storage_disconnect(struct usb_interface *intf) ...@@ -942,16 +939,13 @@ static void storage_disconnect(struct usb_interface *intf)
sdev->online = 0; sdev->online = 0;
scsi_unlock(us->host); scsi_unlock(us->host);
/* prevent new USB transfers and stop the current command */
set_bit(US_FLIDX_DISCONNECTING, &us->flags);
usb_stor_stop_transport(us);
/* lock device access -- no need to unlock, as we're going away */ /* lock device access -- no need to unlock, as we're going away */
down(&(us->dev_semaphore)); down(&(us->dev_semaphore));
/* Complete all pending commands with * cmd->result = DID_ERROR << 16.
* Since we only queue one command at a time, this is pretty easy. */
if (us->srb) {
us->srb->result = DID_ERROR << 16;
us->srb->scsi_done(us->srb);
}
/* TODO: somehow, wait for the device to /* TODO: somehow, wait for the device to
* be 'idle' (tasklet completion) */ * be 'idle' (tasklet completion) */
......
...@@ -67,7 +67,7 @@ struct us_unusual_dev { ...@@ -67,7 +67,7 @@ struct us_unusual_dev {
unsigned int flags; unsigned int flags;
}; };
/* Flag definitions */ /* Flag definitions: these entries are static */
#define US_FL_SINGLE_LUN 0x00000001 /* allow access to only LUN 0 */ #define US_FL_SINGLE_LUN 0x00000001 /* allow access to only LUN 0 */
#define US_FL_MODE_XLATE 0x00000002 /* translate _6 to _10 commands for #define US_FL_MODE_XLATE 0x00000002 /* translate _6 to _10 commands for
Win/MacOS compatibility */ Win/MacOS compatibility */
...@@ -77,8 +77,13 @@ struct us_unusual_dev { ...@@ -77,8 +77,13 @@ struct us_unusual_dev {
#define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */ #define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */
#define US_FL_FIX_CAPACITY 0x00000080 /* READ CAPACITY response too big */ #define US_FL_FIX_CAPACITY 0x00000080 /* READ CAPACITY response too big */
#define US_FLIDX_CAN_CANCEL 18 /* 0x00040000 okay to cancel current_urb? */ /* Dynamic flag definitions: used in set_bit() etc. */
#define US_FLIDX_CANCEL_SG 19 /* 0x00080000 okay to cancel current_sg? */ #define US_FLIDX_URB_ACTIVE 18 /* 0x00040000 current_urb is in use */
#define US_FLIDX_SG_ACTIVE 19 /* 0x00080000 current_sg is in use */
#define US_FLIDX_ABORTING 20 /* 0x00100000 abort is in progress */
#define US_FLIDX_DISCONNECTING 21 /* 0x00200000 disconnect in progress */
#define DONT_SUBMIT ((1UL << US_FLIDX_ABORTING) || \
(1UL << US_FLIDX_DISCONNECTING))
/* processing state machine states */ /* processing state machine states */
......
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