mirror of
https://github.com/torvalds/linux.git
synced 2024-11-28 15:11:31 +00:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
This commit is contained in:
commit
c6c88bbde4
@ -253,6 +253,7 @@
|
||||
!Edrivers/usb/core/urb.c
|
||||
!Edrivers/usb/core/message.c
|
||||
!Edrivers/usb/core/file.c
|
||||
!Edrivers/usb/core/driver.c
|
||||
!Edrivers/usb/core/usb.c
|
||||
!Edrivers/usb/core/hub.c
|
||||
</chapter>
|
||||
|
@ -2640,6 +2640,12 @@ L: linux-usb-users@lists.sourceforge.net
|
||||
L: linux-usb-devel@lists.sourceforge.net
|
||||
S: Maintained
|
||||
|
||||
USB ISP116X DRIVER
|
||||
P: Olav Kongas
|
||||
M: ok@artecdesign.ee
|
||||
L: linux-usb-devel@lists.sourceforge.net
|
||||
S: Maintained
|
||||
|
||||
USB KAWASAKI LSI DRIVER
|
||||
P: Oliver Neukum
|
||||
M: oliver@neukum.name
|
||||
@ -2651,7 +2657,7 @@ USB MASS STORAGE DRIVER
|
||||
P: Matthew Dharm
|
||||
M: mdharm-usb@one-eyed-alien.net
|
||||
L: linux-usb-users@lists.sourceforge.net
|
||||
L: linux-usb-devel@lists.sourceforge.net
|
||||
L: usb-storage@lists.one-eyed-alien.net
|
||||
S: Maintained
|
||||
W: http://www.one-eyed-alien.net/~mdharm/linux-usb/
|
||||
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include <asm/arch/pxafb.h>
|
||||
#include <asm/arch/mmc.h>
|
||||
#include <asm/arch/irda.h>
|
||||
#include <asm/arch/ohci.h>
|
||||
|
||||
#include "generic.h"
|
||||
|
||||
@ -393,6 +394,25 @@ static struct platform_device *platform_devices[] __initdata = {
|
||||
&mst_flash_device[1],
|
||||
};
|
||||
|
||||
static int mainstone_ohci_init(struct device *dev)
|
||||
{
|
||||
/* setup Port1 GPIO pin. */
|
||||
pxa_gpio_mode( 88 | GPIO_ALT_FN_1_IN); /* USBHPWR1 */
|
||||
pxa_gpio_mode( 89 | GPIO_ALT_FN_2_OUT); /* USBHPEN1 */
|
||||
|
||||
/* Set the Power Control Polarity Low and Power Sense
|
||||
Polarity Low to active low. */
|
||||
UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) &
|
||||
~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pxaohci_platform_data mainstone_ohci_platform_data = {
|
||||
.port_mode = PMM_PERPORT_MODE,
|
||||
.init = mainstone_ohci_init,
|
||||
};
|
||||
|
||||
static void __init mainstone_init(void)
|
||||
{
|
||||
int SW7 = 0; /* FIXME: get from SCR (Mst doc section 3.2.1.1) */
|
||||
@ -424,6 +444,7 @@ static void __init mainstone_init(void)
|
||||
|
||||
pxa_set_mci_info(&mainstone_mci_platform_data);
|
||||
pxa_set_ficp_info(&mainstone_ficp_platform_data);
|
||||
pxa_set_ohci_info(&mainstone_ohci_platform_data);
|
||||
}
|
||||
|
||||
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/arch/pxa-regs.h>
|
||||
#include <asm/arch/ohci.h>
|
||||
|
||||
#include "generic.h"
|
||||
|
||||
@ -194,6 +195,11 @@ static struct platform_device ohci_device = {
|
||||
.resource = pxa27x_ohci_resources,
|
||||
};
|
||||
|
||||
void __init pxa_set_ohci_info(struct pxaohci_platform_data *info)
|
||||
{
|
||||
ohci_device.dev.platform_data = info;
|
||||
}
|
||||
|
||||
static struct platform_device *devices[] __initdata = {
|
||||
&ohci_device,
|
||||
};
|
||||
|
@ -358,7 +358,8 @@ config BLK_DEV_UB
|
||||
This driver supports certain USB attached storage devices
|
||||
such as flash keys.
|
||||
|
||||
Warning: Enabling this cripples the usb-storage driver.
|
||||
If you enable this driver, it is recommended to avoid conflicts
|
||||
with usb-storage by enabling USB_LIBUSUAL.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
*
|
||||
* TODO (sorted by decreasing priority)
|
||||
* -- Kill first_open (Al Viro fixed the block layer now)
|
||||
* -- Do resets with usb_device_reset (needs a thread context, use khubd)
|
||||
* -- set readonly flag for CDs, set removable flag for CF readers
|
||||
* -- do inquiry and verify we got a disk and not a tape (for LUN mismatch)
|
||||
* -- special case some senses, e.g. 3a/0 -> no media present, reduce retries
|
||||
@ -29,6 +28,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb_usual.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/devfs_fs_kernel.h>
|
||||
#include <linux/timer.h>
|
||||
@ -106,16 +106,6 @@
|
||||
* +--------+
|
||||
*/
|
||||
|
||||
/*
|
||||
* Definitions which have to be scattered once we understand the layout better.
|
||||
*/
|
||||
|
||||
/* Transport (despite PR in the name) */
|
||||
#define US_PR_BULK 0x50 /* bulk only */
|
||||
|
||||
/* Protocol */
|
||||
#define US_SC_SCSI 0x06 /* Transparent */
|
||||
|
||||
/*
|
||||
* This many LUNs per USB device.
|
||||
* Every one of them takes a host, see UB_MAX_HOSTS.
|
||||
@ -125,7 +115,7 @@
|
||||
/*
|
||||
*/
|
||||
|
||||
#define UB_MINORS_PER_MAJOR 8
|
||||
#define UB_PARTS_PER_LUN 8
|
||||
|
||||
#define UB_MAX_CDB_SIZE 16 /* Corresponds to Bulk */
|
||||
|
||||
@ -245,6 +235,13 @@ struct ub_scsi_cmd {
|
||||
void *back;
|
||||
};
|
||||
|
||||
struct ub_request {
|
||||
struct request *rq;
|
||||
unsigned int current_try;
|
||||
unsigned int nsg; /* sgv[nsg] */
|
||||
struct scatterlist sgv[UB_MAX_REQ_SG];
|
||||
};
|
||||
|
||||
/*
|
||||
*/
|
||||
struct ub_capacity {
|
||||
@ -340,6 +337,8 @@ struct ub_lun {
|
||||
int readonly;
|
||||
int first_open; /* Kludge. See ub_bd_open. */
|
||||
|
||||
struct ub_request urq;
|
||||
|
||||
/* Use Ingo's mempool if or when we have more than one command. */
|
||||
/*
|
||||
* Currently we never need more than one command for the whole device.
|
||||
@ -360,6 +359,7 @@ struct ub_dev {
|
||||
atomic_t poison; /* The USB device is disconnected */
|
||||
int openc; /* protected by ub_lock! */
|
||||
/* kref is too implicit for our taste */
|
||||
int reset; /* Reset is running */
|
||||
unsigned int tagcnt;
|
||||
char name[12];
|
||||
struct usb_device *dev;
|
||||
@ -387,6 +387,9 @@ struct ub_dev {
|
||||
struct bulk_cs_wrap work_bcs;
|
||||
struct usb_ctrlrequest work_cr;
|
||||
|
||||
struct work_struct reset_work;
|
||||
wait_queue_head_t reset_wait;
|
||||
|
||||
int sg_stat[6];
|
||||
struct ub_scsi_trace tr;
|
||||
};
|
||||
@ -395,12 +398,14 @@ struct ub_dev {
|
||||
*/
|
||||
static void ub_cleanup(struct ub_dev *sc);
|
||||
static int ub_request_fn_1(struct ub_lun *lun, struct request *rq);
|
||||
static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
|
||||
struct ub_scsi_cmd *cmd, struct request *rq);
|
||||
static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
|
||||
struct ub_scsi_cmd *cmd, struct request *rq);
|
||||
static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
|
||||
struct ub_scsi_cmd *cmd, struct ub_request *urq);
|
||||
static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
|
||||
struct ub_scsi_cmd *cmd, struct ub_request *urq);
|
||||
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 int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
|
||||
struct ub_request *urq, struct ub_scsi_cmd *cmd);
|
||||
static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
|
||||
static void ub_urb_complete(struct urb *urb, struct pt_regs *pt);
|
||||
static void ub_scsi_action(unsigned long _dev);
|
||||
@ -415,6 +420,8 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
|
||||
static int ub_submit_clear_stall(struct ub_dev *sc, struct ub_scsi_cmd *cmd,
|
||||
int stalled_pipe);
|
||||
static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd);
|
||||
static void ub_reset_enter(struct ub_dev *sc);
|
||||
static void ub_reset_task(void *arg);
|
||||
static int ub_sync_tur(struct ub_dev *sc, struct ub_lun *lun);
|
||||
static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
|
||||
struct ub_capacity *ret);
|
||||
@ -422,13 +429,18 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum);
|
||||
|
||||
/*
|
||||
*/
|
||||
#ifdef CONFIG_USB_LIBUSUAL
|
||||
|
||||
#define ub_usb_ids storage_usb_ids
|
||||
#else
|
||||
|
||||
static struct usb_device_id ub_usb_ids[] = {
|
||||
// { USB_DEVICE_VER(0x0781, 0x0002, 0x0009, 0x0009) }, /* SDDR-31 */
|
||||
{ USB_INTERFACE_INFO(USB_CLASS_MASS_STORAGE, US_SC_SCSI, US_PR_BULK) },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, ub_usb_ids);
|
||||
#endif /* CONFIG_USB_LIBUSUAL */
|
||||
|
||||
/*
|
||||
* Find me a way to identify "next free minor" for add_disk(),
|
||||
@ -521,6 +533,9 @@ static ssize_t ub_diag_show(struct device *dev, struct device_attribute *attr,
|
||||
cnt = 0;
|
||||
spin_lock_irqsave(&sc->lock, flags);
|
||||
|
||||
cnt += sprintf(page + cnt,
|
||||
"poison %d reset %d\n",
|
||||
atomic_read(&sc->poison), sc->reset);
|
||||
cnt += sprintf(page + cnt,
|
||||
"qlen %d qmax %d\n",
|
||||
sc->cmd_queue.qlen, sc->cmd_queue.qmax);
|
||||
@ -770,7 +785,8 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
|
||||
{
|
||||
struct ub_dev *sc = lun->udev;
|
||||
struct ub_scsi_cmd *cmd;
|
||||
int rc;
|
||||
struct ub_request *urq;
|
||||
int n_elem;
|
||||
|
||||
if (atomic_read(&sc->poison) || lun->changed) {
|
||||
blkdev_dequeue_request(rq);
|
||||
@ -778,66 +794,71 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lun->urq.rq != NULL)
|
||||
return -1;
|
||||
if ((cmd = ub_get_cmd(lun)) == NULL)
|
||||
return -1;
|
||||
memset(cmd, 0, sizeof(struct ub_scsi_cmd));
|
||||
|
||||
blkdev_dequeue_request(rq);
|
||||
if (blk_pc_request(rq)) {
|
||||
rc = ub_cmd_build_packet(sc, lun, cmd, rq);
|
||||
} else {
|
||||
rc = ub_cmd_build_block(sc, lun, cmd, rq);
|
||||
}
|
||||
if (rc != 0) {
|
||||
ub_put_cmd(lun, cmd);
|
||||
ub_end_rq(rq, 0);
|
||||
return 0;
|
||||
}
|
||||
cmd->state = UB_CMDST_INIT;
|
||||
cmd->lun = lun;
|
||||
cmd->done = ub_rw_cmd_done;
|
||||
cmd->back = rq;
|
||||
|
||||
cmd->tag = sc->tagcnt++;
|
||||
if (ub_submit_scsi(sc, cmd) != 0) {
|
||||
ub_put_cmd(lun, cmd);
|
||||
ub_end_rq(rq, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
|
||||
struct ub_scsi_cmd *cmd, struct request *rq)
|
||||
{
|
||||
int ub_dir;
|
||||
int n_elem;
|
||||
unsigned int block, nblks;
|
||||
|
||||
if (rq_data_dir(rq) == WRITE)
|
||||
ub_dir = UB_DIR_WRITE;
|
||||
else
|
||||
ub_dir = UB_DIR_READ;
|
||||
cmd->dir = ub_dir;
|
||||
urq = &lun->urq;
|
||||
memset(urq, 0, sizeof(struct ub_request));
|
||||
urq->rq = rq;
|
||||
|
||||
/*
|
||||
* get scatterlist from block layer
|
||||
*/
|
||||
n_elem = blk_rq_map_sg(lun->disk->queue, rq, &cmd->sgv[0]);
|
||||
if (n_elem <= 0) {
|
||||
n_elem = blk_rq_map_sg(lun->disk->queue, rq, &urq->sgv[0]);
|
||||
if (n_elem < 0) {
|
||||
printk(KERN_INFO "%s: failed request map (%d)\n",
|
||||
sc->name, n_elem); /* P3 */
|
||||
return -1; /* request with no s/g entries? */
|
||||
lun->name, n_elem); /* P3 */
|
||||
goto drop;
|
||||
}
|
||||
if (n_elem > UB_MAX_REQ_SG) { /* Paranoia */
|
||||
printk(KERN_WARNING "%s: request with %d segments\n",
|
||||
sc->name, n_elem);
|
||||
return -1;
|
||||
lun->name, n_elem);
|
||||
goto drop;
|
||||
}
|
||||
cmd->nsg = n_elem;
|
||||
urq->nsg = n_elem;
|
||||
sc->sg_stat[n_elem < 5 ? n_elem : 5]++;
|
||||
|
||||
if (blk_pc_request(rq)) {
|
||||
ub_cmd_build_packet(sc, lun, cmd, urq);
|
||||
} else {
|
||||
ub_cmd_build_block(sc, lun, cmd, urq);
|
||||
}
|
||||
cmd->state = UB_CMDST_INIT;
|
||||
cmd->lun = lun;
|
||||
cmd->done = ub_rw_cmd_done;
|
||||
cmd->back = urq;
|
||||
|
||||
cmd->tag = sc->tagcnt++;
|
||||
if (ub_submit_scsi(sc, cmd) != 0)
|
||||
goto drop;
|
||||
|
||||
return 0;
|
||||
|
||||
drop:
|
||||
ub_put_cmd(lun, cmd);
|
||||
ub_end_rq(rq, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
|
||||
struct ub_scsi_cmd *cmd, struct ub_request *urq)
|
||||
{
|
||||
struct request *rq = urq->rq;
|
||||
unsigned int block, nblks;
|
||||
|
||||
if (rq_data_dir(rq) == WRITE)
|
||||
cmd->dir = UB_DIR_WRITE;
|
||||
else
|
||||
cmd->dir = UB_DIR_READ;
|
||||
|
||||
cmd->nsg = urq->nsg;
|
||||
memcpy(cmd->sgv, urq->sgv, sizeof(struct scatterlist) * cmd->nsg);
|
||||
|
||||
/*
|
||||
* build the command
|
||||
*
|
||||
@ -847,7 +868,7 @@ static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
|
||||
block = rq->sector >> lun->capacity.bshift;
|
||||
nblks = rq->nr_sectors >> lun->capacity.bshift;
|
||||
|
||||
cmd->cdb[0] = (ub_dir == UB_DIR_READ)? READ_10: WRITE_10;
|
||||
cmd->cdb[0] = (cmd->dir == UB_DIR_READ)? READ_10: WRITE_10;
|
||||
/* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */
|
||||
cmd->cdb[2] = block >> 24;
|
||||
cmd->cdb[3] = block >> 16;
|
||||
@ -858,14 +879,12 @@ static int ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
|
||||
cmd->cdb_len = 10;
|
||||
|
||||
cmd->len = rq->nr_sectors * 512;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
|
||||
struct ub_scsi_cmd *cmd, struct request *rq)
|
||||
static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
|
||||
struct ub_scsi_cmd *cmd, struct ub_request *urq)
|
||||
{
|
||||
int n_elem;
|
||||
struct request *rq = urq->rq;
|
||||
|
||||
if (rq->data_len == 0) {
|
||||
cmd->dir = UB_DIR_NONE;
|
||||
@ -874,40 +893,26 @@ static int ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
|
||||
cmd->dir = UB_DIR_WRITE;
|
||||
else
|
||||
cmd->dir = UB_DIR_READ;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* get scatterlist from block layer
|
||||
*/
|
||||
n_elem = blk_rq_map_sg(lun->disk->queue, rq, &cmd->sgv[0]);
|
||||
if (n_elem < 0) {
|
||||
printk(KERN_INFO "%s: failed request map (%d)\n",
|
||||
sc->name, n_elem); /* P3 */
|
||||
return -1;
|
||||
}
|
||||
if (n_elem > UB_MAX_REQ_SG) { /* Paranoia */
|
||||
printk(KERN_WARNING "%s: request with %d segments\n",
|
||||
sc->name, n_elem);
|
||||
return -1;
|
||||
}
|
||||
cmd->nsg = n_elem;
|
||||
sc->sg_stat[n_elem < 5 ? n_elem : 5]++;
|
||||
cmd->nsg = urq->nsg;
|
||||
memcpy(cmd->sgv, urq->sgv, sizeof(struct scatterlist) * cmd->nsg);
|
||||
|
||||
memcpy(&cmd->cdb, rq->cmd, rq->cmd_len);
|
||||
cmd->cdb_len = rq->cmd_len;
|
||||
|
||||
cmd->len = rq->data_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
{
|
||||
struct request *rq = cmd->back;
|
||||
struct ub_lun *lun = cmd->lun;
|
||||
struct ub_request *urq = cmd->back;
|
||||
struct request *rq;
|
||||
int uptodate;
|
||||
|
||||
rq = urq->rq;
|
||||
|
||||
if (cmd->error == 0) {
|
||||
uptodate = 1;
|
||||
|
||||
@ -928,9 +933,16 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
rq->errors = SAM_STAT_CHECK_CONDITION;
|
||||
else
|
||||
rq->errors = DID_ERROR << 16;
|
||||
} else {
|
||||
if (cmd->error == -EIO) {
|
||||
if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
urq->rq = NULL;
|
||||
|
||||
ub_put_cmd(lun, cmd);
|
||||
ub_end_rq(rq, uptodate);
|
||||
blk_start_queue(lun->disk->queue);
|
||||
@ -938,13 +950,45 @@ 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)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = end_that_request_first(rq, uptodate, rq->hard_nr_sectors);
|
||||
// assert(rc == 0);
|
||||
end_that_request_first(rq, uptodate, rq->hard_nr_sectors);
|
||||
end_that_request_last(rq);
|
||||
}
|
||||
|
||||
static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
|
||||
struct ub_request *urq, struct ub_scsi_cmd *cmd)
|
||||
{
|
||||
|
||||
if (atomic_read(&sc->poison))
|
||||
return -ENXIO;
|
||||
|
||||
ub_reset_enter(sc);
|
||||
|
||||
if (urq->current_try >= 3)
|
||||
return -EIO;
|
||||
urq->current_try++;
|
||||
/* P3 */ printk("%s: dir %c len/act %d/%d "
|
||||
"[sense %x %02x %02x] retry %d\n",
|
||||
sc->name, UB_DIR_CHAR(cmd->dir), cmd->len, cmd->act_len,
|
||||
cmd->key, cmd->asc, cmd->ascq, urq->current_try);
|
||||
|
||||
memset(cmd, 0, sizeof(struct ub_scsi_cmd));
|
||||
ub_cmd_build_block(sc, lun, cmd, urq);
|
||||
|
||||
cmd->state = UB_CMDST_INIT;
|
||||
cmd->lun = lun;
|
||||
cmd->done = ub_rw_cmd_done;
|
||||
cmd->back = urq;
|
||||
|
||||
cmd->tag = sc->tagcnt++;
|
||||
|
||||
#if 0 /* Wasteful */
|
||||
return ub_submit_scsi(sc, cmd);
|
||||
#else
|
||||
ub_cmdq_add(sc, cmd);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Submit a regular SCSI operation (not an auto-sense).
|
||||
*
|
||||
@ -1075,7 +1119,7 @@ static void ub_scsi_dispatch(struct ub_dev *sc)
|
||||
struct ub_scsi_cmd *cmd;
|
||||
int rc;
|
||||
|
||||
while ((cmd = ub_cmdq_peek(sc)) != NULL) {
|
||||
while (!sc->reset && (cmd = ub_cmdq_peek(sc)) != NULL) {
|
||||
if (cmd->state == UB_CMDST_DONE) {
|
||||
ub_cmdq_pop(sc);
|
||||
(*cmd->done)(sc, cmd);
|
||||
@ -1098,11 +1142,12 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
{
|
||||
struct urb *urb = &sc->work_urb;
|
||||
struct bulk_cs_wrap *bcs;
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
if (atomic_read(&sc->poison)) {
|
||||
/* A little too simplistic, I feel... */
|
||||
goto Bad_End;
|
||||
ub_state_done(sc, cmd, -ENODEV);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd->state == UB_CMDST_CLEAR) {
|
||||
@ -1110,7 +1155,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
/*
|
||||
* STALL while clearning STALL.
|
||||
* The control pipe clears itself - nothing to do.
|
||||
* XXX Might try to reset the device here and retry.
|
||||
*/
|
||||
printk(KERN_NOTICE "%s: stall on control pipe\n",
|
||||
sc->name);
|
||||
@ -1129,11 +1173,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
|
||||
} else if (cmd->state == UB_CMDST_CLR2STS) {
|
||||
if (urb->status == -EPIPE) {
|
||||
/*
|
||||
* STALL while clearning STALL.
|
||||
* The control pipe clears itself - nothing to do.
|
||||
* XXX Might try to reset the device here and retry.
|
||||
*/
|
||||
printk(KERN_NOTICE "%s: stall on control pipe\n",
|
||||
sc->name);
|
||||
goto Bad_End;
|
||||
@ -1151,11 +1190,6 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
|
||||
} else if (cmd->state == UB_CMDST_CLRRS) {
|
||||
if (urb->status == -EPIPE) {
|
||||
/*
|
||||
* STALL while clearning STALL.
|
||||
* The control pipe clears itself - nothing to do.
|
||||
* XXX Might try to reset the device here and retry.
|
||||
*/
|
||||
printk(KERN_NOTICE "%s: stall on control pipe\n",
|
||||
sc->name);
|
||||
goto Bad_End;
|
||||
@ -1172,7 +1206,12 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
ub_state_stat_counted(sc, cmd);
|
||||
|
||||
} else if (cmd->state == UB_CMDST_CMD) {
|
||||
if (urb->status == -EPIPE) {
|
||||
switch (urb->status) {
|
||||
case 0:
|
||||
break;
|
||||
case -EOVERFLOW:
|
||||
goto Bad_End;
|
||||
case -EPIPE:
|
||||
rc = ub_submit_clear_stall(sc, cmd, sc->last_pipe);
|
||||
if (rc != 0) {
|
||||
printk(KERN_NOTICE "%s: "
|
||||
@ -1182,17 +1221,20 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
* This is typically ENOMEM or some other such shit.
|
||||
* Retrying is pointless. Just do Bad End on it...
|
||||
*/
|
||||
goto Bad_End;
|
||||
ub_state_done(sc, cmd, rc);
|
||||
return;
|
||||
}
|
||||
cmd->state = UB_CMDST_CLEAR;
|
||||
ub_cmdtr_state(sc, cmd);
|
||||
return;
|
||||
}
|
||||
if (urb->status != 0) {
|
||||
case -ESHUTDOWN: /* unplug */
|
||||
case -EILSEQ: /* unplug timeout on uhci */
|
||||
ub_state_done(sc, cmd, -ENODEV);
|
||||
return;
|
||||
default:
|
||||
goto Bad_End;
|
||||
}
|
||||
if (urb->actual_length != US_BULK_CB_WRAP_LEN) {
|
||||
/* XXX Must do reset here to unconfuse the device */
|
||||
goto Bad_End;
|
||||
}
|
||||
|
||||
@ -1211,11 +1253,8 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
printk(KERN_NOTICE "%s: "
|
||||
"unable to submit clear (%d)\n",
|
||||
sc->name, rc);
|
||||
/*
|
||||
* This is typically ENOMEM or some other such shit.
|
||||
* Retrying is pointless. Just do Bad End on it...
|
||||
*/
|
||||
goto Bad_End;
|
||||
ub_state_done(sc, cmd, rc);
|
||||
return;
|
||||
}
|
||||
cmd->state = UB_CMDST_CLR2STS;
|
||||
ub_cmdtr_state(sc, cmd);
|
||||
@ -1224,14 +1263,50 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
if (urb->status == -EOVERFLOW) {
|
||||
/*
|
||||
* A babble? Failure, but we must transfer CSW now.
|
||||
* XXX This is going to end in perpetual babble. Reset.
|
||||
*/
|
||||
cmd->error = -EOVERFLOW; /* A cheap trick... */
|
||||
ub_state_stat(sc, cmd);
|
||||
return;
|
||||
}
|
||||
if (urb->status != 0)
|
||||
goto Bad_End;
|
||||
|
||||
if (cmd->dir == UB_DIR_WRITE) {
|
||||
/*
|
||||
* Do not continue writes in case of a failure.
|
||||
* Doing so would cause sectors to be mixed up,
|
||||
* which is worse than sectors lost.
|
||||
*
|
||||
* We must try to read the CSW, or many devices
|
||||
* get confused.
|
||||
*/
|
||||
len = urb->actual_length;
|
||||
if (urb->status != 0 ||
|
||||
len != cmd->sgv[cmd->current_sg].length) {
|
||||
cmd->act_len += len;
|
||||
ub_cmdtr_act_len(sc, cmd);
|
||||
|
||||
cmd->error = -EIO;
|
||||
ub_state_stat(sc, cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
/*
|
||||
* If an error occurs on read, we record it, and
|
||||
* continue to fetch data in order to avoid bubble.
|
||||
*
|
||||
* As a small shortcut, we stop if we detect that
|
||||
* a CSW mixed into data.
|
||||
*/
|
||||
if (urb->status != 0)
|
||||
cmd->error = -EIO;
|
||||
|
||||
len = urb->actual_length;
|
||||
if (urb->status != 0 ||
|
||||
len != cmd->sgv[cmd->current_sg].length) {
|
||||
if ((len & 0x1FF) == US_BULK_CS_WRAP_LEN)
|
||||
goto Bad_End;
|
||||
}
|
||||
}
|
||||
|
||||
cmd->act_len += urb->actual_length;
|
||||
ub_cmdtr_act_len(sc, cmd);
|
||||
@ -1249,11 +1324,8 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
printk(KERN_NOTICE "%s: "
|
||||
"unable to submit clear (%d)\n",
|
||||
sc->name, rc);
|
||||
/*
|
||||
* This is typically ENOMEM or some other such shit.
|
||||
* Retrying is pointless. Just do Bad End on it...
|
||||
*/
|
||||
goto Bad_End;
|
||||
ub_state_done(sc, cmd, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1266,14 +1338,8 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
ub_cmdtr_state(sc, cmd);
|
||||
return;
|
||||
}
|
||||
if (urb->status == -EOVERFLOW) {
|
||||
/*
|
||||
* XXX We are screwed here. Retrying is pointless,
|
||||
* because the pipelined data will not get in until
|
||||
* we read with a big enough buffer. We must reset XXX.
|
||||
*/
|
||||
goto Bad_End;
|
||||
}
|
||||
|
||||
/* Catch everything, including -EOVERFLOW and other nasties. */
|
||||
if (urb->status != 0)
|
||||
goto Bad_End;
|
||||
|
||||
@ -1319,15 +1385,15 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
return;
|
||||
}
|
||||
|
||||
rc = le32_to_cpu(bcs->Residue);
|
||||
if (rc != cmd->len - cmd->act_len) {
|
||||
len = le32_to_cpu(bcs->Residue);
|
||||
if (len != cmd->len - cmd->act_len) {
|
||||
/*
|
||||
* It is all right to transfer less, the caller has
|
||||
* to check. But it's not all right if the device
|
||||
* counts disagree with our counts.
|
||||
*/
|
||||
/* P3 */ printk("%s: resid %d len %d act %d\n",
|
||||
sc->name, rc, cmd->len, cmd->act_len);
|
||||
sc->name, len, cmd->len, cmd->act_len);
|
||||
goto Bad_End;
|
||||
}
|
||||
|
||||
@ -1338,13 +1404,13 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
ub_state_sense(sc, cmd);
|
||||
return;
|
||||
case US_BULK_STAT_PHASE:
|
||||
/* XXX We must reset the transport here */
|
||||
/* P3 */ printk("%s: status PHASE\n", sc->name);
|
||||
goto Bad_End;
|
||||
default:
|
||||
printk(KERN_INFO "%s: unknown CSW status 0x%x\n",
|
||||
sc->name, bcs->Status);
|
||||
goto Bad_End;
|
||||
ub_state_done(sc, cmd, -EINVAL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Not zeroing error to preserve a babble indicator */
|
||||
@ -1364,7 +1430,8 @@ static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
||||
printk(KERN_WARNING "%s: "
|
||||
"wrong command state %d\n",
|
||||
sc->name, cmd->state);
|
||||
goto Bad_End;
|
||||
ub_state_done(sc, cmd, -EINVAL);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
@ -1611,6 +1678,93 @@ static void ub_top_sense_done(struct ub_dev *sc, struct ub_scsi_cmd *scmd)
|
||||
ub_scsi_urb_compl(sc, cmd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset management
|
||||
*/
|
||||
|
||||
static void ub_reset_enter(struct ub_dev *sc)
|
||||
{
|
||||
|
||||
if (sc->reset) {
|
||||
/* This happens often on multi-LUN devices. */
|
||||
return;
|
||||
}
|
||||
sc->reset = 1;
|
||||
|
||||
#if 0 /* Not needed because the disconnect waits for us. */
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&ub_lock, flags);
|
||||
sc->openc++;
|
||||
spin_unlock_irqrestore(&ub_lock, flags);
|
||||
#endif
|
||||
|
||||
#if 0 /* We let them stop themselves. */
|
||||
struct list_head *p;
|
||||
struct ub_lun *lun;
|
||||
list_for_each(p, &sc->luns) {
|
||||
lun = list_entry(p, struct ub_lun, link);
|
||||
blk_stop_queue(lun->disk->queue);
|
||||
}
|
||||
#endif
|
||||
|
||||
schedule_work(&sc->reset_work);
|
||||
}
|
||||
|
||||
static void ub_reset_task(void *arg)
|
||||
{
|
||||
struct ub_dev *sc = arg;
|
||||
unsigned long flags;
|
||||
struct list_head *p;
|
||||
struct ub_lun *lun;
|
||||
int lkr, rc;
|
||||
|
||||
if (!sc->reset) {
|
||||
printk(KERN_WARNING "%s: Running reset unrequested\n",
|
||||
sc->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (atomic_read(&sc->poison)) {
|
||||
printk(KERN_NOTICE "%s: Not resetting disconnected device\n",
|
||||
sc->name); /* P3 This floods. Remove soon. XXX */
|
||||
} else if (sc->dev->actconfig->desc.bNumInterfaces != 1) {
|
||||
printk(KERN_NOTICE "%s: Not resetting multi-interface device\n",
|
||||
sc->name); /* P3 This floods. Remove soon. XXX */
|
||||
} else {
|
||||
if ((lkr = usb_lock_device_for_reset(sc->dev, sc->intf)) < 0) {
|
||||
printk(KERN_NOTICE
|
||||
"%s: usb_lock_device_for_reset failed (%d)\n",
|
||||
sc->name, lkr);
|
||||
} else {
|
||||
rc = usb_reset_device(sc->dev);
|
||||
if (rc < 0) {
|
||||
printk(KERN_NOTICE "%s: "
|
||||
"usb_lock_device_for_reset failed (%d)\n",
|
||||
sc->name, rc);
|
||||
}
|
||||
|
||||
if (lkr)
|
||||
usb_unlock_device(sc->dev);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* In theory, no commands can be running while reset is active,
|
||||
* so nobody can ask for another reset, and so we do not need any
|
||||
* queues of resets or anything. We do need a spinlock though,
|
||||
* to interact with block layer.
|
||||
*/
|
||||
spin_lock_irqsave(&sc->lock, flags);
|
||||
sc->reset = 0;
|
||||
tasklet_schedule(&sc->tasklet);
|
||||
list_for_each(p, &sc->luns) {
|
||||
lun = list_entry(p, struct ub_lun, link);
|
||||
blk_start_queue(lun->disk->queue);
|
||||
}
|
||||
wake_up(&sc->reset_wait);
|
||||
spin_unlock_irqrestore(&sc->lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is called from a process context.
|
||||
*/
|
||||
@ -2146,7 +2300,7 @@ static int ub_get_pipes(struct ub_dev *sc, struct usb_device *dev,
|
||||
if (ep_in == NULL || ep_out == NULL) {
|
||||
printk(KERN_NOTICE "%s: failed endpoint check\n",
|
||||
sc->name);
|
||||
return -EIO;
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Calculate and store the pipe values */
|
||||
@ -2172,6 +2326,9 @@ static int ub_probe(struct usb_interface *intf,
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
if (usb_usual_check_type(dev_id, USB_US_TYPE_UB))
|
||||
return -ENXIO;
|
||||
|
||||
rc = -ENOMEM;
|
||||
if ((sc = kmalloc(sizeof(struct ub_dev), GFP_KERNEL)) == NULL)
|
||||
goto err_core;
|
||||
@ -2181,6 +2338,8 @@ static int ub_probe(struct usb_interface *intf,
|
||||
usb_init_urb(&sc->work_urb);
|
||||
tasklet_init(&sc->tasklet, ub_scsi_action, (unsigned long)sc);
|
||||
atomic_set(&sc->poison, 0);
|
||||
INIT_WORK(&sc->reset_work, ub_reset_task, sc);
|
||||
init_waitqueue_head(&sc->reset_wait);
|
||||
|
||||
init_timer(&sc->work_timer);
|
||||
sc->work_timer.data = (unsigned long) sc;
|
||||
@ -2201,7 +2360,8 @@ static int ub_probe(struct usb_interface *intf,
|
||||
|
||||
/* XXX Verify that we can handle the device (from descriptors) */
|
||||
|
||||
ub_get_pipes(sc, sc->dev, intf);
|
||||
if (ub_get_pipes(sc, sc->dev, intf) != 0)
|
||||
goto err_dev_desc;
|
||||
|
||||
if (device_create_file(&sc->intf->dev, &dev_attr_diag) != 0)
|
||||
goto err_diag;
|
||||
@ -2272,6 +2432,7 @@ static int ub_probe(struct usb_interface *intf,
|
||||
|
||||
/* device_remove_file(&sc->intf->dev, &dev_attr_diag); */
|
||||
err_diag:
|
||||
err_dev_desc:
|
||||
usb_set_intfdata(intf, NULL);
|
||||
// usb_put_intf(sc->intf);
|
||||
usb_put_dev(sc->dev);
|
||||
@ -2309,14 +2470,14 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
|
||||
ub_revalidate(sc, lun);
|
||||
|
||||
rc = -ENOMEM;
|
||||
if ((disk = alloc_disk(UB_MINORS_PER_MAJOR)) == NULL)
|
||||
if ((disk = alloc_disk(UB_PARTS_PER_LUN)) == NULL)
|
||||
goto err_diskalloc;
|
||||
|
||||
lun->disk = disk;
|
||||
sprintf(disk->disk_name, DRV_NAME "%c", lun->id + 'a');
|
||||
sprintf(disk->devfs_name, DEVFS_NAME "/%c", lun->id + 'a');
|
||||
disk->major = UB_MAJOR;
|
||||
disk->first_minor = lun->id * UB_MINORS_PER_MAJOR;
|
||||
disk->first_minor = lun->id * UB_PARTS_PER_LUN;
|
||||
disk->fops = &ub_bd_fops;
|
||||
disk->private_data = lun;
|
||||
disk->driverfs_dev = &sc->intf->dev;
|
||||
@ -2379,6 +2540,11 @@ static void ub_disconnect(struct usb_interface *intf)
|
||||
*/
|
||||
atomic_set(&sc->poison, 1);
|
||||
|
||||
/*
|
||||
* Wait for reset to end, if any.
|
||||
*/
|
||||
wait_event(sc->reset_wait, !sc->reset);
|
||||
|
||||
/*
|
||||
* Blow away queued commands.
|
||||
*
|
||||
@ -2392,7 +2558,7 @@ static void ub_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct ub_scsi_cmd *cmd;
|
||||
int cnt = 0;
|
||||
while ((cmd = ub_cmdq_pop(sc)) != NULL) {
|
||||
while ((cmd = ub_cmdq_peek(sc)) != NULL) {
|
||||
cmd->error = -ENOTCONN;
|
||||
cmd->state = UB_CMDST_DONE;
|
||||
ub_cmdtr_state(sc, cmd);
|
||||
@ -2461,7 +2627,6 @@ static void ub_disconnect(struct usb_interface *intf)
|
||||
}
|
||||
|
||||
static struct usb_driver ub_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "ub",
|
||||
.probe = ub_probe,
|
||||
.disconnect = ub_disconnect,
|
||||
@ -2479,6 +2644,7 @@ static int __init ub_init(void)
|
||||
if ((rc = usb_register(&ub_driver)) != 0)
|
||||
goto err_register;
|
||||
|
||||
usb_usual_set_present(USB_US_TYPE_UB);
|
||||
return 0;
|
||||
|
||||
err_register:
|
||||
@ -2494,6 +2660,7 @@ static void __exit ub_exit(void)
|
||||
|
||||
devfs_remove(DEVFS_NAME);
|
||||
unregister_blkdev(UB_MAJOR, DRV_NAME);
|
||||
usb_usual_clear_present(USB_US_TYPE_UB);
|
||||
}
|
||||
|
||||
module_init(ub_init);
|
||||
|
@ -275,7 +275,6 @@ static void bcm203x_disconnect(struct usb_interface *intf)
|
||||
}
|
||||
|
||||
static struct usb_driver bcm203x_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "bcm203x",
|
||||
.probe = bcm203x_probe,
|
||||
.disconnect = bcm203x_disconnect,
|
||||
|
@ -768,7 +768,6 @@ static void bfusb_disconnect(struct usb_interface *intf)
|
||||
}
|
||||
|
||||
static struct usb_driver bfusb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "bfusb",
|
||||
.probe = bfusb_probe,
|
||||
.disconnect = bfusb_disconnect,
|
||||
|
@ -619,7 +619,6 @@ static void bpa10x_disconnect(struct usb_interface *intf)
|
||||
}
|
||||
|
||||
static struct usb_driver bpa10x_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "bpa10x",
|
||||
.probe = bpa10x_probe,
|
||||
.disconnect = bpa10x_disconnect,
|
||||
|
@ -1044,7 +1044,6 @@ static void hci_usb_disconnect(struct usb_interface *intf)
|
||||
}
|
||||
|
||||
static struct usb_driver hci_usb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "hci_usb",
|
||||
.probe = hci_usb_probe,
|
||||
.disconnect = hci_usb_disconnect,
|
||||
|
@ -151,7 +151,6 @@ static void usb_pcwd_disconnect (struct usb_interface *interface);
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver usb_pcwd_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRIVER_NAME,
|
||||
.probe = usb_pcwd_probe,
|
||||
.disconnect = usb_pcwd_disconnect,
|
||||
|
@ -235,7 +235,6 @@ static struct usb_device_id iforce_usb_ids [] = {
|
||||
MODULE_DEVICE_TABLE (usb, iforce_usb_ids);
|
||||
|
||||
struct usb_driver iforce_usb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "iforce",
|
||||
.probe = iforce_usb_probe,
|
||||
.disconnect = iforce_usb_disconnect,
|
||||
|
@ -1715,7 +1715,6 @@ hfc_usb_disconnect(struct usb_interface
|
||||
/* our driver information structure */
|
||||
/************************************/
|
||||
static struct usb_driver hfc_drv = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "hfc_usb",
|
||||
.id_table = hfcusb_idtab,
|
||||
.probe = hfc_usb_probe,
|
||||
|
@ -180,7 +180,6 @@ static struct usb_device_id st5481_ids[] = {
|
||||
MODULE_DEVICE_TABLE (usb, st5481_ids);
|
||||
|
||||
static struct usb_driver st5481_usb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "st5481_usb",
|
||||
.probe = probe_st5481,
|
||||
.disconnect = disconnect_st5481,
|
||||
|
@ -544,7 +544,6 @@ static struct usb_device_id flexcop_usb_table [] = {
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver flexcop_usb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "b2c2_flexcop_usb",
|
||||
.probe = flexcop_usb_probe,
|
||||
.disconnect = flexcop_usb_disconnect,
|
||||
|
@ -986,7 +986,6 @@ static const struct usb_device_id cinergyt2_table [] __devinitdata = {
|
||||
MODULE_DEVICE_TABLE(usb, cinergyt2_table);
|
||||
|
||||
static struct usb_driver cinergyt2_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "cinergyT2",
|
||||
.probe = cinergyt2_probe,
|
||||
.disconnect = cinergyt2_disconnect,
|
||||
|
@ -144,7 +144,6 @@ static struct dvb_usb_properties a800_properties = {
|
||||
};
|
||||
|
||||
static struct usb_driver a800_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "dvb_usb_a800",
|
||||
.probe = a800_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
|
@ -241,7 +241,6 @@ static struct dvb_usb_properties cxusb_properties = {
|
||||
};
|
||||
|
||||
static struct usb_driver cxusb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "dvb_usb_cxusb",
|
||||
.probe = cxusb_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
|
@ -373,7 +373,6 @@ static struct dvb_usb_properties artec_t1_usb2_properties = {
|
||||
};
|
||||
|
||||
static struct usb_driver dibusb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "dvb_usb_dibusb_mb",
|
||||
.probe = dibusb_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
|
@ -82,7 +82,6 @@ static struct dvb_usb_properties dibusb_mc_properties = {
|
||||
};
|
||||
|
||||
static struct usb_driver dibusb_mc_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "dvb_usb_dibusb_mc",
|
||||
.probe = dibusb_mc_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
|
@ -233,7 +233,6 @@ static struct dvb_usb_properties digitv_properties = {
|
||||
};
|
||||
|
||||
static struct usb_driver digitv_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "dvb_usb_digitv",
|
||||
.probe = digitv_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
|
@ -198,7 +198,6 @@ static struct dvb_usb_properties wt220u_properties = {
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver dtt200u_usb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "dvb_usb_dtt200u",
|
||||
.probe = dtt200u_usb_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
|
@ -202,7 +202,6 @@ static struct dvb_usb_properties nova_t_properties = {
|
||||
};
|
||||
|
||||
static struct usb_driver nova_t_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "dvb_usb_nova_t_usb2",
|
||||
.probe = nova_t_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
|
@ -128,7 +128,6 @@ static struct dvb_usb_properties umt_properties = {
|
||||
};
|
||||
|
||||
static struct usb_driver umt_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "dvb_usb_umt_010",
|
||||
.probe = umt_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
|
@ -256,7 +256,6 @@ static struct dvb_usb_properties vp702x_properties = {
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver vp702x_usb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "dvb-usb-vp702x",
|
||||
.probe = vp702x_usb_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
|
@ -253,7 +253,6 @@ static struct dvb_usb_properties vp7045_properties = {
|
||||
|
||||
/* usb specific object needed to register this driver with the usb subsystem */
|
||||
static struct usb_driver vp7045_usb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "dvb_usb_vp7045",
|
||||
.probe = vp7045_usb_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
|
@ -582,7 +582,6 @@ MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
static struct usb_driver cpia_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "cpia",
|
||||
.probe = cpia_probe,
|
||||
.disconnect = cpia_disconnect,
|
||||
|
@ -1884,7 +1884,6 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
|
||||
}
|
||||
|
||||
static struct usb_driver em28xx_usb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "em28xx",
|
||||
.probe = em28xx_usb_probe,
|
||||
.disconnect = em28xx_usb_disconnect,
|
||||
|
@ -1539,7 +1539,6 @@ static void irda_usb_disconnect(struct usb_interface *intf)
|
||||
* USB device callbacks
|
||||
*/
|
||||
static struct usb_driver irda_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "irda-usb",
|
||||
.probe = irda_usb_probe,
|
||||
.disconnect = irda_usb_disconnect,
|
||||
|
@ -1152,7 +1152,6 @@ static int stir_resume(struct usb_interface *intf)
|
||||
* USB device callbacks
|
||||
*/
|
||||
static struct usb_driver irda_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "stir4200",
|
||||
.probe = stir_probe,
|
||||
.disconnect = stir_disconnect,
|
||||
|
@ -22,6 +22,7 @@ obj-$(CONFIG_USB_MIDI) += class/
|
||||
obj-$(CONFIG_USB_PRINTER) += class/
|
||||
|
||||
obj-$(CONFIG_USB_STORAGE) += storage/
|
||||
obj-$(CONFIG_USB) += storage/
|
||||
|
||||
obj-$(CONFIG_USB_AIPTEK) += input/
|
||||
obj-$(CONFIG_USB_ATI_REMOTE) += input/
|
||||
|
@ -44,6 +44,19 @@ config USB_CXACRU
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cxacru.
|
||||
|
||||
config USB_UEAGLEATM
|
||||
tristate "ADI 930 and eagle USB DSL modem"
|
||||
depends on USB_ATM
|
||||
select FW_LOADER
|
||||
help
|
||||
Say Y here if you have an ADSL USB modem based on the ADI 930
|
||||
or eagle chipset. In order to use your modem you will need to
|
||||
install firmwares and CMV (Command Management Variables); see
|
||||
<https://gna.org/projects/ueagleatm/> for details.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called ueagle-atm.
|
||||
|
||||
config USB_XUSBATM
|
||||
tristate "Other USB DSL modem support"
|
||||
depends on USB_ATM
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
obj-$(CONFIG_USB_CXACRU) += cxacru.o
|
||||
obj-$(CONFIG_USB_SPEEDTOUCH) += speedtch.o
|
||||
obj-$(CONFIG_USB_UEAGLEATM) += ueagle-atm.o
|
||||
obj-$(CONFIG_USB_ATM) += usbatm.o
|
||||
obj-$(CONFIG_USB_XUSBATM) += xusbatm.o
|
||||
|
||||
|
@ -853,7 +853,6 @@ static int cxacru_usb_probe(struct usb_interface *intf, const struct usb_device_
|
||||
}
|
||||
|
||||
static struct usb_driver cxacru_usb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = cxacru_driver_name,
|
||||
.probe = cxacru_usb_probe,
|
||||
.disconnect = usbatm_usb_disconnect,
|
||||
|
@ -659,7 +659,6 @@ MODULE_DEVICE_TABLE(usb, speedtch_usb_ids);
|
||||
static int speedtch_usb_probe(struct usb_interface *, const struct usb_device_id *);
|
||||
|
||||
static struct usb_driver speedtch_usb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = speedtch_driver_name,
|
||||
.probe = speedtch_usb_probe,
|
||||
.disconnect = usbatm_usb_disconnect,
|
||||
|
1820
drivers/usb/atm/ueagle-atm.c
Normal file
1820
drivers/usb/atm/ueagle-atm.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -646,14 +646,14 @@ static void usbatm_destroy_instance(struct kref *kref)
|
||||
kfree(instance);
|
||||
}
|
||||
|
||||
void usbatm_get_instance(struct usbatm_data *instance)
|
||||
static void usbatm_get_instance(struct usbatm_data *instance)
|
||||
{
|
||||
dbg("%s", __func__);
|
||||
|
||||
kref_get(&instance->refcount);
|
||||
}
|
||||
|
||||
void usbatm_put_instance(struct usbatm_data *instance)
|
||||
static void usbatm_put_instance(struct usbatm_data *instance)
|
||||
{
|
||||
dbg("%s", __func__);
|
||||
|
||||
|
@ -140,7 +140,6 @@ static int xusbatm_usb_probe(struct usb_interface *intf,
|
||||
}
|
||||
|
||||
static struct usb_driver xusbatm_usb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = xusbatm_driver_name,
|
||||
.probe = xusbatm_usb_probe,
|
||||
.disconnect = usbatm_usb_disconnect,
|
||||
|
@ -2732,7 +2732,6 @@ static struct usb_device_id usb_audio_ids [] = {
|
||||
MODULE_DEVICE_TABLE (usb, usb_audio_ids);
|
||||
|
||||
static struct usb_driver usb_audio_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "audio",
|
||||
.probe = usb_audio_probe,
|
||||
.disconnect = usb_audio_disconnect,
|
||||
|
@ -6,6 +6,7 @@
|
||||
* Copyright (c) 1999 Johannes Erdfelt <johannes@erdfelt.com>
|
||||
* Copyright (c) 2000 Vojtech Pavlik <vojtech@suse.cz>
|
||||
* Copyright (c) 2004 Oliver Neukum <oliver@neukum.name>
|
||||
* Copyright (c) 2005 David Kubicek <dave@awk.cz>
|
||||
*
|
||||
* USB Abstract Control Model driver for USB modems and ISDN adapters
|
||||
*
|
||||
@ -29,6 +30,7 @@
|
||||
* config we want, sysadmin changes bConfigurationValue in sysfs.
|
||||
* v0.23 - use softirq for rx processing, as needed by tty layer
|
||||
* v0.24 - change probe method to evaluate CDC union descriptor
|
||||
* v0.25 - downstream tasks paralelized to maximize throughput
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -63,14 +65,15 @@
|
||||
#include <linux/usb_cdc.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#include "cdc-acm.h"
|
||||
|
||||
/*
|
||||
* Version Information
|
||||
*/
|
||||
#define DRIVER_VERSION "v0.23"
|
||||
#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik"
|
||||
#define DRIVER_VERSION "v0.25"
|
||||
#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik, David Kubicek"
|
||||
#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
|
||||
|
||||
static struct usb_driver acm_driver;
|
||||
@ -284,7 +287,9 @@ exit:
|
||||
/* data interface returns incoming bytes, or we got unthrottled */
|
||||
static void acm_read_bulk(struct urb *urb, struct pt_regs *regs)
|
||||
{
|
||||
struct acm *acm = urb->context;
|
||||
struct acm_rb *buf;
|
||||
struct acm_ru *rcv = urb->context;
|
||||
struct acm *acm = rcv->instance;
|
||||
dbg("Entering acm_read_bulk with status %d\n", urb->status);
|
||||
|
||||
if (!ACM_READY(acm))
|
||||
@ -293,49 +298,109 @@ static void acm_read_bulk(struct urb *urb, struct pt_regs *regs)
|
||||
if (urb->status)
|
||||
dev_dbg(&acm->data->dev, "bulk rx status %d\n", urb->status);
|
||||
|
||||
/* calling tty_flip_buffer_push() in_irq() isn't allowed */
|
||||
tasklet_schedule(&acm->bh);
|
||||
buf = rcv->buffer;
|
||||
buf->size = urb->actual_length;
|
||||
|
||||
spin_lock(&acm->read_lock);
|
||||
list_add_tail(&rcv->list, &acm->spare_read_urbs);
|
||||
list_add_tail(&buf->list, &acm->filled_read_bufs);
|
||||
spin_unlock(&acm->read_lock);
|
||||
|
||||
tasklet_schedule(&acm->urb_task);
|
||||
}
|
||||
|
||||
static void acm_rx_tasklet(unsigned long _acm)
|
||||
{
|
||||
struct acm *acm = (void *)_acm;
|
||||
struct urb *urb = acm->readurb;
|
||||
struct acm_rb *buf;
|
||||
struct tty_struct *tty = acm->tty;
|
||||
unsigned char *data = urb->transfer_buffer;
|
||||
struct acm_ru *rcv;
|
||||
//unsigned long flags;
|
||||
int i = 0;
|
||||
dbg("Entering acm_rx_tasklet");
|
||||
|
||||
if (urb->actual_length > 0 && !acm->throttle) {
|
||||
for (i = 0; i < urb->actual_length && !acm->throttle; i++) {
|
||||
/* if we insert more than TTY_FLIPBUF_SIZE characters,
|
||||
* we drop them. */
|
||||
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
tty_insert_flip_char(tty, data[i], 0);
|
||||
}
|
||||
dbg("Handed %d bytes to tty layer", i+1);
|
||||
tty_flip_buffer_push(tty);
|
||||
if (!ACM_READY(acm) || acm->throttle)
|
||||
return;
|
||||
|
||||
next_buffer:
|
||||
spin_lock(&acm->read_lock);
|
||||
if (list_empty(&acm->filled_read_bufs)) {
|
||||
spin_unlock(&acm->read_lock);
|
||||
goto urbs;
|
||||
}
|
||||
buf = list_entry(acm->filled_read_bufs.next,
|
||||
struct acm_rb, list);
|
||||
list_del(&buf->list);
|
||||
spin_unlock(&acm->read_lock);
|
||||
|
||||
dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d\n", buf, buf->size);
|
||||
|
||||
for (i = 0; i < buf->size && !acm->throttle; i++) {
|
||||
/* if we insert more than TTY_FLIPBUF_SIZE characters,
|
||||
we drop them. */
|
||||
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
tty_insert_flip_char(tty, buf->base[i], 0);
|
||||
}
|
||||
tty_flip_buffer_push(tty);
|
||||
|
||||
spin_lock(&acm->throttle_lock);
|
||||
if (acm->throttle) {
|
||||
dbg("Throtteling noticed");
|
||||
memmove(data, data + i, urb->actual_length - i);
|
||||
urb->actual_length -= i;
|
||||
acm->resubmit_to_unthrottle = 1;
|
||||
memmove(buf->base, buf->base + i, buf->size - i);
|
||||
buf->size -= i;
|
||||
spin_unlock(&acm->throttle_lock);
|
||||
spin_lock(&acm->read_lock);
|
||||
list_add(&buf->list, &acm->filled_read_bufs);
|
||||
spin_unlock(&acm->read_lock);
|
||||
return;
|
||||
}
|
||||
spin_unlock(&acm->throttle_lock);
|
||||
|
||||
urb->actual_length = 0;
|
||||
urb->dev = acm->dev;
|
||||
spin_lock(&acm->read_lock);
|
||||
list_add(&buf->list, &acm->spare_read_bufs);
|
||||
spin_unlock(&acm->read_lock);
|
||||
goto next_buffer;
|
||||
|
||||
i = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (i)
|
||||
dev_dbg(&acm->data->dev, "bulk rx resubmit %d\n", i);
|
||||
urbs:
|
||||
while (!list_empty(&acm->spare_read_bufs)) {
|
||||
spin_lock(&acm->read_lock);
|
||||
if (list_empty(&acm->spare_read_urbs)) {
|
||||
spin_unlock(&acm->read_lock);
|
||||
return;
|
||||
}
|
||||
rcv = list_entry(acm->spare_read_urbs.next,
|
||||
struct acm_ru, list);
|
||||
list_del(&rcv->list);
|
||||
spin_unlock(&acm->read_lock);
|
||||
|
||||
buf = list_entry(acm->spare_read_bufs.next,
|
||||
struct acm_rb, list);
|
||||
list_del(&buf->list);
|
||||
|
||||
rcv->buffer = buf;
|
||||
|
||||
usb_fill_bulk_urb(rcv->urb, acm->dev,
|
||||
acm->rx_endpoint,
|
||||
buf->base,
|
||||
acm->readsize,
|
||||
acm_read_bulk, rcv);
|
||||
rcv->urb->transfer_dma = buf->dma;
|
||||
rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
dbg("acm_rx_tasklet: sending urb 0x%p, rcv 0x%p, buf 0x%p\n", rcv->urb, rcv, buf);
|
||||
|
||||
/* This shouldn't kill the driver as unsuccessful URBs are returned to the
|
||||
free-urbs-pool and resubmited ASAP */
|
||||
if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
|
||||
list_add(&buf->list, &acm->spare_read_bufs);
|
||||
spin_lock(&acm->read_lock);
|
||||
list_add(&rcv->list, &acm->spare_read_urbs);
|
||||
spin_unlock(&acm->read_lock);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* data interface wrote those outgoing bytes */
|
||||
@ -369,6 +434,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
struct acm *acm;
|
||||
int rv = -EINVAL;
|
||||
int i;
|
||||
dbg("Entering acm_tty_open.\n");
|
||||
|
||||
down(&open_sem);
|
||||
@ -382,7 +448,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
||||
tty->driver_data = acm;
|
||||
acm->tty = tty;
|
||||
|
||||
|
||||
/* force low_latency on so that our tty_push actually forces the data through,
|
||||
otherwise it is scheduled, and with high data rates data can get lost. */
|
||||
tty->low_latency = 1;
|
||||
|
||||
if (acm->used++) {
|
||||
goto done;
|
||||
@ -394,18 +462,20 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
|
||||
goto bail_out;
|
||||
}
|
||||
|
||||
acm->readurb->dev = acm->dev;
|
||||
if (usb_submit_urb(acm->readurb, GFP_KERNEL)) {
|
||||
dbg("usb_submit_urb(read bulk) failed");
|
||||
goto bail_out_and_unlink;
|
||||
}
|
||||
|
||||
if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS))
|
||||
goto full_bailout;
|
||||
|
||||
/* force low_latency on so that our tty_push actually forces the data through,
|
||||
otherwise it is scheduled, and with high data rates data can get lost. */
|
||||
tty->low_latency = 1;
|
||||
INIT_LIST_HEAD(&acm->spare_read_urbs);
|
||||
INIT_LIST_HEAD(&acm->spare_read_bufs);
|
||||
INIT_LIST_HEAD(&acm->filled_read_bufs);
|
||||
for (i = 0; i < ACM_NRU; i++) {
|
||||
list_add(&(acm->ru[i].list), &acm->spare_read_urbs);
|
||||
}
|
||||
for (i = 0; i < ACM_NRB; i++) {
|
||||
list_add(&(acm->rb[i].list), &acm->spare_read_bufs);
|
||||
}
|
||||
|
||||
tasklet_schedule(&acm->urb_task);
|
||||
|
||||
done:
|
||||
err_out:
|
||||
@ -413,8 +483,6 @@ err_out:
|
||||
return rv;
|
||||
|
||||
full_bailout:
|
||||
usb_kill_urb(acm->readurb);
|
||||
bail_out_and_unlink:
|
||||
usb_kill_urb(acm->ctrlurb);
|
||||
bail_out:
|
||||
acm->used--;
|
||||
@ -424,18 +492,22 @@ bail_out:
|
||||
|
||||
static void acm_tty_unregister(struct acm *acm)
|
||||
{
|
||||
int i;
|
||||
|
||||
tty_unregister_device(acm_tty_driver, acm->minor);
|
||||
usb_put_intf(acm->control);
|
||||
acm_table[acm->minor] = NULL;
|
||||
usb_free_urb(acm->ctrlurb);
|
||||
usb_free_urb(acm->readurb);
|
||||
usb_free_urb(acm->writeurb);
|
||||
for (i = 0; i < ACM_NRU; i++)
|
||||
usb_free_urb(acm->ru[i].urb);
|
||||
kfree(acm);
|
||||
}
|
||||
|
||||
static void acm_tty_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
struct acm *acm = tty->driver_data;
|
||||
int i;
|
||||
|
||||
if (!acm || !acm->used)
|
||||
return;
|
||||
@ -446,7 +518,8 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
|
||||
acm_set_control(acm, acm->ctrlout = 0);
|
||||
usb_kill_urb(acm->ctrlurb);
|
||||
usb_kill_urb(acm->writeurb);
|
||||
usb_kill_urb(acm->readurb);
|
||||
for (i = 0; i < ACM_NRU; i++)
|
||||
usb_kill_urb(acm->ru[i].urb);
|
||||
} else
|
||||
acm_tty_unregister(acm);
|
||||
}
|
||||
@ -528,10 +601,7 @@ static void acm_tty_unthrottle(struct tty_struct *tty)
|
||||
spin_lock_bh(&acm->throttle_lock);
|
||||
acm->throttle = 0;
|
||||
spin_unlock_bh(&acm->throttle_lock);
|
||||
if (acm->resubmit_to_unthrottle) {
|
||||
acm->resubmit_to_unthrottle = 0;
|
||||
acm_read_bulk(acm->readurb, NULL);
|
||||
}
|
||||
tasklet_schedule(&acm->urb_task);
|
||||
}
|
||||
|
||||
static void acm_tty_break_ctl(struct tty_struct *tty, int state)
|
||||
@ -588,7 +658,7 @@ static int acm_tty_ioctl(struct tty_struct *tty, struct file *file, unsigned int
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
static __u32 acm_tty_speed[] = {
|
||||
static const __u32 acm_tty_speed[] = {
|
||||
0, 50, 75, 110, 134, 150, 200, 300, 600,
|
||||
1200, 1800, 2400, 4800, 9600, 19200, 38400,
|
||||
57600, 115200, 230400, 460800, 500000, 576000,
|
||||
@ -596,7 +666,7 @@ static __u32 acm_tty_speed[] = {
|
||||
2500000, 3000000, 3500000, 4000000
|
||||
};
|
||||
|
||||
static __u8 acm_tty_size[] = {
|
||||
static const __u8 acm_tty_size[] = {
|
||||
5, 6, 7, 8
|
||||
};
|
||||
|
||||
@ -694,6 +764,7 @@ static int acm_probe (struct usb_interface *intf,
|
||||
int call_interface_num = -1;
|
||||
int data_interface_num;
|
||||
unsigned long quirks;
|
||||
int i;
|
||||
|
||||
/* handle quirks deadly to normal probing*/
|
||||
quirks = (unsigned long)id->driver_info;
|
||||
@ -833,7 +904,7 @@ skip_normal_probe:
|
||||
}
|
||||
|
||||
ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
|
||||
readsize = le16_to_cpu(epread->wMaxPacketSize);
|
||||
readsize = le16_to_cpu(epread->wMaxPacketSize)*2;
|
||||
acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize);
|
||||
acm->control = control_interface;
|
||||
acm->data = data_interface;
|
||||
@ -842,12 +913,14 @@ skip_normal_probe:
|
||||
acm->ctrl_caps = ac_management_function;
|
||||
acm->ctrlsize = ctrlsize;
|
||||
acm->readsize = readsize;
|
||||
acm->bh.func = acm_rx_tasklet;
|
||||
acm->bh.data = (unsigned long) acm;
|
||||
acm->urb_task.func = acm_rx_tasklet;
|
||||
acm->urb_task.data = (unsigned long) acm;
|
||||
INIT_WORK(&acm->work, acm_softint, acm);
|
||||
spin_lock_init(&acm->throttle_lock);
|
||||
spin_lock_init(&acm->write_lock);
|
||||
spin_lock_init(&acm->read_lock);
|
||||
acm->write_ready = 1;
|
||||
acm->rx_endpoint = usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress);
|
||||
|
||||
buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
|
||||
if (!buf) {
|
||||
@ -856,13 +929,6 @@ skip_normal_probe:
|
||||
}
|
||||
acm->ctrl_buffer = buf;
|
||||
|
||||
buf = usb_buffer_alloc(usb_dev, readsize, GFP_KERNEL, &acm->read_dma);
|
||||
if (!buf) {
|
||||
dev_dbg(&intf->dev, "out of memory (read buffer alloc)\n");
|
||||
goto alloc_fail3;
|
||||
}
|
||||
acm->read_buffer = buf;
|
||||
|
||||
if (acm_write_buffers_alloc(acm) < 0) {
|
||||
dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
|
||||
goto alloc_fail4;
|
||||
@ -873,10 +939,25 @@ skip_normal_probe:
|
||||
dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
|
||||
goto alloc_fail5;
|
||||
}
|
||||
acm->readurb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!acm->readurb) {
|
||||
dev_dbg(&intf->dev, "out of memory (readurb kmalloc)\n");
|
||||
goto alloc_fail6;
|
||||
for (i = 0; i < ACM_NRU; i++) {
|
||||
struct acm_ru *rcv = &(acm->ru[i]);
|
||||
|
||||
if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
|
||||
dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)\n");
|
||||
goto alloc_fail7;
|
||||
}
|
||||
|
||||
rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
rcv->instance = acm;
|
||||
}
|
||||
for (i = 0; i < ACM_NRB; i++) {
|
||||
struct acm_rb *buf = &(acm->rb[i]);
|
||||
|
||||
// Using usb_buffer_alloc instead of kmalloc as Oliver suggested
|
||||
if (!(buf->base = usb_buffer_alloc(acm->dev, readsize, GFP_KERNEL, &buf->dma))) {
|
||||
dev_dbg(&intf->dev, "out of memory (read bufs usb_buffer_alloc)\n");
|
||||
goto alloc_fail7;
|
||||
}
|
||||
}
|
||||
acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!acm->writeurb) {
|
||||
@ -889,15 +970,9 @@ skip_normal_probe:
|
||||
acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
acm->ctrlurb->transfer_dma = acm->ctrl_dma;
|
||||
|
||||
usb_fill_bulk_urb(acm->readurb, usb_dev, usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress),
|
||||
acm->read_buffer, readsize, acm_read_bulk, acm);
|
||||
acm->readurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;
|
||||
acm->readurb->transfer_dma = acm->read_dma;
|
||||
|
||||
usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
|
||||
NULL, acm->writesize, acm_write_bulk, acm);
|
||||
acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;
|
||||
/* acm->writeurb->transfer_dma = 0; */
|
||||
|
||||
dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
|
||||
|
||||
@ -917,14 +992,14 @@ skip_normal_probe:
|
||||
return 0;
|
||||
|
||||
alloc_fail7:
|
||||
usb_free_urb(acm->readurb);
|
||||
alloc_fail6:
|
||||
for (i = 0; i < ACM_NRB; i++)
|
||||
usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
|
||||
for (i = 0; i < ACM_NRU; i++)
|
||||
usb_free_urb(acm->ru[i].urb);
|
||||
usb_free_urb(acm->ctrlurb);
|
||||
alloc_fail5:
|
||||
acm_write_buffers_free(acm);
|
||||
alloc_fail4:
|
||||
usb_buffer_free(usb_dev, readsize, acm->read_buffer, acm->read_dma);
|
||||
alloc_fail3:
|
||||
usb_buffer_free(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
|
||||
alloc_fail2:
|
||||
kfree(acm);
|
||||
@ -936,6 +1011,7 @@ static void acm_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct acm *acm = usb_get_intfdata (intf);
|
||||
struct usb_device *usb_dev = interface_to_usbdev(intf);
|
||||
int i;
|
||||
|
||||
if (!acm || !acm->dev) {
|
||||
dbg("disconnect on nonexisting interface");
|
||||
@ -946,15 +1022,24 @@ static void acm_disconnect(struct usb_interface *intf)
|
||||
acm->dev = NULL;
|
||||
usb_set_intfdata (intf, NULL);
|
||||
|
||||
tasklet_disable(&acm->urb_task);
|
||||
|
||||
usb_kill_urb(acm->ctrlurb);
|
||||
usb_kill_urb(acm->readurb);
|
||||
usb_kill_urb(acm->writeurb);
|
||||
for (i = 0; i < ACM_NRU; i++)
|
||||
usb_kill_urb(acm->ru[i].urb);
|
||||
|
||||
INIT_LIST_HEAD(&acm->filled_read_bufs);
|
||||
INIT_LIST_HEAD(&acm->spare_read_bufs);
|
||||
|
||||
tasklet_enable(&acm->urb_task);
|
||||
|
||||
flush_scheduled_work(); /* wait for acm_softint */
|
||||
|
||||
acm_write_buffers_free(acm);
|
||||
usb_buffer_free(usb_dev, acm->readsize, acm->read_buffer, acm->read_dma);
|
||||
usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
|
||||
for (i = 0; i < ACM_NRB; i++)
|
||||
usb_buffer_free(usb_dev, acm->readsize, acm->rb[i].base, acm->rb[i].dma);
|
||||
|
||||
usb_driver_release_interface(&acm_driver, acm->data);
|
||||
|
||||
@ -1003,7 +1088,6 @@ static struct usb_device_id acm_ids[] = {
|
||||
MODULE_DEVICE_TABLE (usb, acm_ids);
|
||||
|
||||
static struct usb_driver acm_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "cdc_acm",
|
||||
.probe = acm_probe,
|
||||
.disconnect = acm_disconnect,
|
||||
|
@ -59,6 +59,9 @@
|
||||
* when processing onlcr, so we only need 2 buffers.
|
||||
*/
|
||||
#define ACM_NWB 2
|
||||
#define ACM_NRU 16
|
||||
#define ACM_NRB 16
|
||||
|
||||
struct acm_wb {
|
||||
unsigned char *buf;
|
||||
dma_addr_t dmah;
|
||||
@ -66,22 +69,43 @@ struct acm_wb {
|
||||
int use;
|
||||
};
|
||||
|
||||
struct acm_rb {
|
||||
struct list_head list;
|
||||
int size;
|
||||
unsigned char *base;
|
||||
dma_addr_t dma;
|
||||
};
|
||||
|
||||
struct acm_ru {
|
||||
struct list_head list;
|
||||
struct acm_rb *buffer;
|
||||
struct urb *urb;
|
||||
struct acm *instance;
|
||||
};
|
||||
|
||||
struct acm {
|
||||
struct usb_device *dev; /* the corresponding usb device */
|
||||
struct usb_interface *control; /* control interface */
|
||||
struct usb_interface *data; /* data interface */
|
||||
struct tty_struct *tty; /* the corresponding tty */
|
||||
struct urb *ctrlurb, *readurb, *writeurb; /* urbs */
|
||||
u8 *ctrl_buffer, *read_buffer; /* buffers of urbs */
|
||||
dma_addr_t ctrl_dma, read_dma; /* dma handles of buffers */
|
||||
struct urb *ctrlurb, *writeurb; /* urbs */
|
||||
u8 *ctrl_buffer; /* buffers of urbs */
|
||||
dma_addr_t ctrl_dma; /* dma handles of buffers */
|
||||
struct acm_wb wb[ACM_NWB];
|
||||
struct acm_ru ru[ACM_NRU];
|
||||
struct acm_rb rb[ACM_NRB];
|
||||
int rx_endpoint;
|
||||
spinlock_t read_lock;
|
||||
struct list_head spare_read_urbs;
|
||||
struct list_head spare_read_bufs;
|
||||
struct list_head filled_read_bufs;
|
||||
int write_current; /* current write buffer */
|
||||
int write_used; /* number of non-empty write buffers */
|
||||
int write_ready; /* write urb is not running */
|
||||
spinlock_t write_lock;
|
||||
struct usb_cdc_line_coding line; /* bits, stop, parity */
|
||||
struct work_struct work; /* work queue entry for line discipline waking up */
|
||||
struct tasklet_struct bh; /* rx processing */
|
||||
struct tasklet_struct urb_task; /* rx processing */
|
||||
spinlock_t throttle_lock; /* synchronize throtteling and read callback */
|
||||
unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */
|
||||
unsigned int ctrlout; /* output control lines (DTR, RTS) */
|
||||
@ -91,7 +115,6 @@ struct acm {
|
||||
unsigned int minor; /* acm minor number */
|
||||
unsigned char throttle; /* throttled by tty layer */
|
||||
unsigned char clocal; /* termios CLOCAL */
|
||||
unsigned char resubmit_to_unthrottle; /* throtteling has disabled the read urb */
|
||||
unsigned int ctrl_caps; /* control capabilities from the class specific header */
|
||||
};
|
||||
|
||||
|
@ -2027,7 +2027,6 @@ static struct usb_device_id id_table[] = {
|
||||
};
|
||||
|
||||
static struct usb_driver usb_midi_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "midi",
|
||||
.probe = usb_midi_probe,
|
||||
.disconnect = usb_midi_disconnect,
|
||||
|
@ -199,7 +199,7 @@ struct quirk_printer_struct {
|
||||
#define USBLP_QUIRK_BIDIR 0x1 /* reports bidir but requires unidirectional mode (no INs/reads) */
|
||||
#define USBLP_QUIRK_USB_INIT 0x2 /* needs vendor USB init string */
|
||||
|
||||
static struct quirk_printer_struct quirk_printers[] = {
|
||||
static const struct quirk_printer_struct quirk_printers[] = {
|
||||
{ 0x03f0, 0x0004, USBLP_QUIRK_BIDIR }, /* HP DeskJet 895C */
|
||||
{ 0x03f0, 0x0104, USBLP_QUIRK_BIDIR }, /* HP DeskJet 880C */
|
||||
{ 0x03f0, 0x0204, USBLP_QUIRK_BIDIR }, /* HP DeskJet 815C */
|
||||
@ -301,7 +301,7 @@ static void usblp_bulk_write(struct urb *urb, struct pt_regs *regs)
|
||||
* Get and print printer errors.
|
||||
*/
|
||||
|
||||
static char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" };
|
||||
static const char *usblp_messages[] = { "ok", "out of paper", "off-line", "on fire" };
|
||||
|
||||
static int usblp_check_status(struct usblp *usblp, int err)
|
||||
{
|
||||
@ -438,7 +438,7 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait
|
||||
| (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM);
|
||||
}
|
||||
|
||||
static int usblp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
||||
static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct usblp *usblp = file->private_data;
|
||||
int length, err, i;
|
||||
@ -838,7 +838,8 @@ static struct file_operations usblp_fops = {
|
||||
.read = usblp_read,
|
||||
.write = usblp_write,
|
||||
.poll = usblp_poll,
|
||||
.ioctl = usblp_ioctl,
|
||||
.unlocked_ioctl = usblp_ioctl,
|
||||
.compat_ioctl = usblp_ioctl,
|
||||
.open = usblp_open,
|
||||
.release = usblp_release,
|
||||
};
|
||||
@ -849,6 +850,20 @@ static struct usb_class_driver usblp_class = {
|
||||
.minor_base = USBLP_MINOR_BASE,
|
||||
};
|
||||
|
||||
static ssize_t usblp_show_ieee1284_id(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct usblp *usblp = usb_get_intfdata (intf);
|
||||
|
||||
if (usblp->device_id_string[0] == 0 &&
|
||||
usblp->device_id_string[1] == 0)
|
||||
return 0;
|
||||
|
||||
return sprintf(buf, "%s", usblp->device_id_string+2);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(ieee1284_id, S_IRUGO, usblp_show_ieee1284_id, NULL);
|
||||
|
||||
static int usblp_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
@ -933,20 +948,12 @@ static int usblp_probe(struct usb_interface *intf,
|
||||
|
||||
/* Retrieve and store the device ID string. */
|
||||
usblp_cache_device_id_string(usblp);
|
||||
device_create_file(&intf->dev, &dev_attr_ieee1284_id);
|
||||
|
||||
#ifdef DEBUG
|
||||
usblp_check_status(usblp, 0);
|
||||
#endif
|
||||
|
||||
info("usblp%d: USB %sdirectional printer dev %d "
|
||||
"if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X",
|
||||
usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum,
|
||||
usblp->ifnum,
|
||||
usblp->protocol[usblp->current_protocol].alt_setting,
|
||||
usblp->current_protocol,
|
||||
le16_to_cpu(usblp->dev->descriptor.idVendor),
|
||||
le16_to_cpu(usblp->dev->descriptor.idProduct));
|
||||
|
||||
usb_set_intfdata (intf, usblp);
|
||||
|
||||
usblp->present = 1;
|
||||
@ -957,11 +964,20 @@ static int usblp_probe(struct usb_interface *intf,
|
||||
goto abort_intfdata;
|
||||
}
|
||||
usblp->minor = intf->minor;
|
||||
info("usblp%d: USB %sdirectional printer dev %d "
|
||||
"if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X",
|
||||
usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum,
|
||||
usblp->ifnum,
|
||||
usblp->protocol[usblp->current_protocol].alt_setting,
|
||||
usblp->current_protocol,
|
||||
le16_to_cpu(usblp->dev->descriptor.idVendor),
|
||||
le16_to_cpu(usblp->dev->descriptor.idProduct));
|
||||
|
||||
return 0;
|
||||
|
||||
abort_intfdata:
|
||||
usb_set_intfdata (intf, NULL);
|
||||
device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
|
||||
abort:
|
||||
if (usblp) {
|
||||
if (usblp->writebuf)
|
||||
@ -1156,6 +1172,8 @@ static void usblp_disconnect(struct usb_interface *intf)
|
||||
BUG ();
|
||||
}
|
||||
|
||||
device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
|
||||
|
||||
down (&usblp_sem);
|
||||
down (&usblp->sem);
|
||||
usblp->present = 0;
|
||||
@ -1186,7 +1204,6 @@ static struct usb_device_id usblp_ids [] = {
|
||||
MODULE_DEVICE_TABLE (usb, usblp_ids);
|
||||
|
||||
static struct usb_driver usblp_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "usblp",
|
||||
.probe = usblp_probe,
|
||||
.disconnect = usblp_disconnect,
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Makefile for USB Core files and filesystem
|
||||
#
|
||||
|
||||
usbcore-objs := usb.o hub.o hcd.o urb.o message.o \
|
||||
usbcore-objs := usb.o hub.o hcd.o urb.o message.o driver.o \
|
||||
config.o file.o buffer.o sysfs.o devio.o notify.o
|
||||
|
||||
ifeq ($(CONFIG_PCI),y)
|
||||
|
@ -55,6 +55,9 @@ int hcd_buffer_create (struct usb_hcd *hcd)
|
||||
char name [16];
|
||||
int i, size;
|
||||
|
||||
if (!hcd->self.controller->dma_mask)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < HCD_BUFFER_POOLS; i++) {
|
||||
if (!(size = pool_max [i]))
|
||||
continue;
|
||||
|
@ -67,45 +67,45 @@
|
||||
/* Define ALLOW_SERIAL_NUMBER if you want to see the serial number of devices */
|
||||
#define ALLOW_SERIAL_NUMBER
|
||||
|
||||
static char *format_topo =
|
||||
static const char *format_topo =
|
||||
/* T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd */
|
||||
"\nT: Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s MxCh=%2d\n";
|
||||
|
||||
static char *format_string_manufacturer =
|
||||
static const char *format_string_manufacturer =
|
||||
/* S: Manufacturer=xxxx */
|
||||
"S: Manufacturer=%.100s\n";
|
||||
|
||||
static char *format_string_product =
|
||||
static const char *format_string_product =
|
||||
/* S: Product=xxxx */
|
||||
"S: Product=%.100s\n";
|
||||
|
||||
#ifdef ALLOW_SERIAL_NUMBER
|
||||
static char *format_string_serialnumber =
|
||||
static const char *format_string_serialnumber =
|
||||
/* S: SerialNumber=xxxx */
|
||||
"S: SerialNumber=%.100s\n";
|
||||
#endif
|
||||
|
||||
static char *format_bandwidth =
|
||||
static const char *format_bandwidth =
|
||||
/* B: Alloc=ddd/ddd us (xx%), #Int=ddd, #Iso=ddd */
|
||||
"B: Alloc=%3d/%3d us (%2d%%), #Int=%3d, #Iso=%3d\n";
|
||||
|
||||
static char *format_device1 =
|
||||
static const char *format_device1 =
|
||||
/* D: Ver=xx.xx Cls=xx(sssss) Sub=xx Prot=xx MxPS=dd #Cfgs=dd */
|
||||
"D: Ver=%2x.%02x Cls=%02x(%-5s) Sub=%02x Prot=%02x MxPS=%2d #Cfgs=%3d\n";
|
||||
|
||||
static char *format_device2 =
|
||||
static const char *format_device2 =
|
||||
/* P: Vendor=xxxx ProdID=xxxx Rev=xx.xx */
|
||||
"P: Vendor=%04x ProdID=%04x Rev=%2x.%02x\n";
|
||||
|
||||
static char *format_config =
|
||||
static const char *format_config =
|
||||
/* C: #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
|
||||
"C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
|
||||
|
||||
static char *format_iface =
|
||||
static const char *format_iface =
|
||||
/* I: If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
|
||||
"I: If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
|
||||
|
||||
static char *format_endpt =
|
||||
static const char *format_endpt =
|
||||
/* E: Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
|
||||
"E: Ad=%02x(%c) Atr=%02x(%-4s) MxPS=%4d Ivl=%d%cs\n";
|
||||
|
||||
@ -545,10 +545,10 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes, loff_t *ski
|
||||
struct usb_device *childdev = usbdev->children[chix];
|
||||
|
||||
if (childdev) {
|
||||
down(&childdev->serialize);
|
||||
usb_lock_device(childdev);
|
||||
ret = usb_device_dump(buffer, nbytes, skip_bytes, file_offset, childdev,
|
||||
bus, level + 1, chix, ++cnt);
|
||||
up(&childdev->serialize);
|
||||
usb_unlock_device(childdev);
|
||||
if (ret == -EFAULT)
|
||||
return total_written;
|
||||
total_written += ret;
|
||||
|
@ -402,7 +402,6 @@ static void driver_disconnect(struct usb_interface *intf)
|
||||
}
|
||||
|
||||
struct usb_driver usbfs_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "usbfs",
|
||||
.probe = driver_probe,
|
||||
.disconnect = driver_disconnect,
|
||||
@ -1350,9 +1349,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
|
||||
/* let kernel drivers try to (re)bind to the interface */
|
||||
case USBDEVFS_CONNECT:
|
||||
usb_unlock_device(ps->dev);
|
||||
usb_lock_all_devices();
|
||||
bus_rescan_devices(intf->dev.bus);
|
||||
usb_unlock_all_devices();
|
||||
usb_lock_device(ps->dev);
|
||||
break;
|
||||
|
||||
|
472
drivers/usb/core/driver.c
Normal file
472
drivers/usb/core/driver.c
Normal file
@ -0,0 +1,472 @@
|
||||
/*
|
||||
* drivers/usb/driver.c - most of the driver model stuff for usb
|
||||
*
|
||||
* (C) Copyright 2005 Greg Kroah-Hartman <gregkh@suse.de>
|
||||
*
|
||||
* based on drivers/usb/usb.c which had the following copyrights:
|
||||
* (C) Copyright Linus Torvalds 1999
|
||||
* (C) Copyright Johannes Erdfelt 1999-2001
|
||||
* (C) Copyright Andreas Gal 1999
|
||||
* (C) Copyright Gregory P. Smith 1999
|
||||
* (C) Copyright Deti Fliegl 1999 (new USB architecture)
|
||||
* (C) Copyright Randy Dunlap 2000
|
||||
* (C) Copyright David Brownell 2000-2004
|
||||
* (C) Copyright Yggdrasil Computing, Inc. 2000
|
||||
* (usb_device_id matching changes by Adam J. Richter)
|
||||
* (C) Copyright Greg Kroah-Hartman 2002-2003
|
||||
*
|
||||
* NOTE! This is not actually a driver at all, rather this is
|
||||
* just a collection of helper routines that implement the
|
||||
* generic USB things that the real drivers can use..
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/usb.h>
|
||||
#include "hcd.h"
|
||||
#include "usb.h"
|
||||
|
||||
static int usb_match_one_id(struct usb_interface *interface,
|
||||
const struct usb_device_id *id);
|
||||
|
||||
struct usb_dynid {
|
||||
struct list_head node;
|
||||
struct usb_device_id id;
|
||||
};
|
||||
|
||||
|
||||
static int generic_probe(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static int generic_remove(struct device *dev)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
|
||||
/* if this is only an unbind, not a physical disconnect, then
|
||||
* unconfigure the device */
|
||||
if (udev->state == USB_STATE_CONFIGURED)
|
||||
usb_set_configuration(udev, 0);
|
||||
|
||||
/* in case the call failed or the device was suspended */
|
||||
if (udev->state >= USB_STATE_CONFIGURED)
|
||||
usb_disable_device(udev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct device_driver usb_generic_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "usb",
|
||||
.bus = &usb_bus_type,
|
||||
.probe = generic_probe,
|
||||
.remove = generic_remove,
|
||||
};
|
||||
|
||||
/* Fun hack to determine if the struct device is a
|
||||
* usb device or a usb interface. */
|
||||
int usb_generic_driver_data;
|
||||
|
||||
#ifdef CONFIG_HOTPLUG
|
||||
|
||||
/*
|
||||
* Adds a new dynamic USBdevice ID to this driver,
|
||||
* and cause the driver to probe for all devices again.
|
||||
*/
|
||||
static ssize_t store_new_id(struct device_driver *driver,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct usb_driver *usb_drv = to_usb_driver(driver);
|
||||
struct usb_dynid *dynid;
|
||||
u32 idVendor = 0;
|
||||
u32 idProduct = 0;
|
||||
int fields = 0;
|
||||
|
||||
fields = sscanf(buf, "%x %x", &idVendor, &idProduct);
|
||||
if (fields < 2)
|
||||
return -EINVAL;
|
||||
|
||||
dynid = kzalloc(sizeof(*dynid), GFP_KERNEL);
|
||||
if (!dynid)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&dynid->node);
|
||||
dynid->id.idVendor = idVendor;
|
||||
dynid->id.idProduct = idProduct;
|
||||
dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
|
||||
|
||||
spin_lock(&usb_drv->dynids.lock);
|
||||
list_add_tail(&usb_drv->dynids.list, &dynid->node);
|
||||
spin_unlock(&usb_drv->dynids.lock);
|
||||
|
||||
if (get_driver(driver)) {
|
||||
driver_attach(driver);
|
||||
put_driver(driver);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
|
||||
|
||||
static int usb_create_newid_file(struct usb_driver *usb_drv)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
if (usb_drv->no_dynamic_id)
|
||||
goto exit;
|
||||
|
||||
if (usb_drv->probe != NULL)
|
||||
error = sysfs_create_file(&usb_drv->driver.kobj,
|
||||
&driver_attr_new_id.attr);
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
static void usb_remove_newid_file(struct usb_driver *usb_drv)
|
||||
{
|
||||
if (usb_drv->no_dynamic_id)
|
||||
return;
|
||||
|
||||
if (usb_drv->probe != NULL)
|
||||
sysfs_remove_file(&usb_drv->driver.kobj,
|
||||
&driver_attr_new_id.attr);
|
||||
}
|
||||
|
||||
static void usb_free_dynids(struct usb_driver *usb_drv)
|
||||
{
|
||||
struct usb_dynid *dynid, *n;
|
||||
|
||||
spin_lock(&usb_drv->dynids.lock);
|
||||
list_for_each_entry_safe(dynid, n, &usb_drv->dynids.list, node) {
|
||||
list_del(&dynid->node);
|
||||
kfree(dynid);
|
||||
}
|
||||
spin_unlock(&usb_drv->dynids.lock);
|
||||
}
|
||||
#else
|
||||
static inline int usb_create_newid_file(struct usb_driver *usb_drv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void usb_remove_newid_file(struct usb_driver *usb_drv)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void usb_free_dynids(struct usb_driver *usb_drv)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *intf,
|
||||
struct usb_driver *drv)
|
||||
{
|
||||
struct usb_dynid *dynid;
|
||||
|
||||
spin_lock(&drv->dynids.lock);
|
||||
list_for_each_entry(dynid, &drv->dynids.list, node) {
|
||||
if (usb_match_one_id(intf, &dynid->id)) {
|
||||
spin_unlock(&drv->dynids.lock);
|
||||
return &dynid->id;
|
||||
}
|
||||
}
|
||||
spin_unlock(&drv->dynids.lock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/* called from driver core with usb_bus_type.subsys writelock */
|
||||
static int usb_probe_interface(struct device *dev)
|
||||
{
|
||||
struct usb_interface * intf = to_usb_interface(dev);
|
||||
struct usb_driver * driver = to_usb_driver(dev->driver);
|
||||
const struct usb_device_id *id;
|
||||
int error = -ENODEV;
|
||||
|
||||
dev_dbg(dev, "%s\n", __FUNCTION__);
|
||||
|
||||
if (!driver->probe)
|
||||
return error;
|
||||
/* FIXME we'd much prefer to just resume it ... */
|
||||
if (interface_to_usbdev(intf)->state == USB_STATE_SUSPENDED)
|
||||
return -EHOSTUNREACH;
|
||||
|
||||
id = usb_match_id(intf, driver->id_table);
|
||||
if (!id)
|
||||
id = usb_match_dynamic_id(intf, driver);
|
||||
if (id) {
|
||||
dev_dbg(dev, "%s - got id\n", __FUNCTION__);
|
||||
|
||||
/* Interface "power state" doesn't correspond to any hardware
|
||||
* state whatsoever. We use it to record when it's bound to
|
||||
* a driver that may start I/0: it's not frozen/quiesced.
|
||||
*/
|
||||
mark_active(intf);
|
||||
intf->condition = USB_INTERFACE_BINDING;
|
||||
error = driver->probe(intf, id);
|
||||
if (error) {
|
||||
mark_quiesced(intf);
|
||||
intf->condition = USB_INTERFACE_UNBOUND;
|
||||
} else
|
||||
intf->condition = USB_INTERFACE_BOUND;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* called from driver core with usb_bus_type.subsys writelock */
|
||||
static int usb_unbind_interface(struct device *dev)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct usb_driver *driver = to_usb_driver(intf->dev.driver);
|
||||
|
||||
intf->condition = USB_INTERFACE_UNBINDING;
|
||||
|
||||
/* release all urbs for this interface */
|
||||
usb_disable_interface(interface_to_usbdev(intf), intf);
|
||||
|
||||
if (driver && driver->disconnect)
|
||||
driver->disconnect(intf);
|
||||
|
||||
/* reset other interface state */
|
||||
usb_set_interface(interface_to_usbdev(intf),
|
||||
intf->altsetting[0].desc.bInterfaceNumber,
|
||||
0);
|
||||
usb_set_intfdata(intf, NULL);
|
||||
intf->condition = USB_INTERFACE_UNBOUND;
|
||||
mark_quiesced(intf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* returns 0 if no match, 1 if match */
|
||||
static int usb_match_one_id(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_host_interface *intf;
|
||||
struct usb_device *dev;
|
||||
|
||||
/* proc_connectinfo in devio.c may call us with id == NULL. */
|
||||
if (id == NULL)
|
||||
return 0;
|
||||
|
||||
intf = interface->cur_altsetting;
|
||||
dev = interface_to_usbdev(interface);
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
|
||||
id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
|
||||
id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
|
||||
return 0;
|
||||
|
||||
/* No need to test id->bcdDevice_lo != 0, since 0 is never
|
||||
greater than any unsigned number. */
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
|
||||
(id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
|
||||
(id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
|
||||
(id->bDeviceClass != dev->descriptor.bDeviceClass))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
|
||||
(id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
|
||||
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
|
||||
(id->bInterfaceClass != intf->desc.bInterfaceClass))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
|
||||
(id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))
|
||||
return 0;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
|
||||
(id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
/**
|
||||
* usb_match_id - find first usb_device_id matching device or interface
|
||||
* @interface: the interface of interest
|
||||
* @id: array of usb_device_id structures, terminated by zero entry
|
||||
*
|
||||
* usb_match_id searches an array of usb_device_id's and returns
|
||||
* the first one matching the device or interface, or null.
|
||||
* This is used when binding (or rebinding) a driver to an interface.
|
||||
* Most USB device drivers will use this indirectly, through the usb core,
|
||||
* but some layered driver frameworks use it directly.
|
||||
* These device tables are exported with MODULE_DEVICE_TABLE, through
|
||||
* modutils, to support the driver loading functionality of USB hotplugging.
|
||||
*
|
||||
* What Matches:
|
||||
*
|
||||
* The "match_flags" element in a usb_device_id controls which
|
||||
* members are used. If the corresponding bit is set, the
|
||||
* value in the device_id must match its corresponding member
|
||||
* in the device or interface descriptor, or else the device_id
|
||||
* does not match.
|
||||
*
|
||||
* "driver_info" is normally used only by device drivers,
|
||||
* but you can create a wildcard "matches anything" usb_device_id
|
||||
* as a driver's "modules.usbmap" entry if you provide an id with
|
||||
* only a nonzero "driver_info" field. If you do this, the USB device
|
||||
* driver's probe() routine should use additional intelligence to
|
||||
* decide whether to bind to the specified interface.
|
||||
*
|
||||
* What Makes Good usb_device_id Tables:
|
||||
*
|
||||
* The match algorithm is very simple, so that intelligence in
|
||||
* driver selection must come from smart driver id records.
|
||||
* Unless you have good reasons to use another selection policy,
|
||||
* provide match elements only in related groups, and order match
|
||||
* specifiers from specific to general. Use the macros provided
|
||||
* for that purpose if you can.
|
||||
*
|
||||
* The most specific match specifiers use device descriptor
|
||||
* data. These are commonly used with product-specific matches;
|
||||
* the USB_DEVICE macro lets you provide vendor and product IDs,
|
||||
* and you can also match against ranges of product revisions.
|
||||
* These are widely used for devices with application or vendor
|
||||
* specific bDeviceClass values.
|
||||
*
|
||||
* Matches based on device class/subclass/protocol specifications
|
||||
* are slightly more general; use the USB_DEVICE_INFO macro, or
|
||||
* its siblings. These are used with single-function devices
|
||||
* where bDeviceClass doesn't specify that each interface has
|
||||
* its own class.
|
||||
*
|
||||
* Matches based on interface class/subclass/protocol are the
|
||||
* most general; they let drivers bind to any interface on a
|
||||
* multiple-function device. Use the USB_INTERFACE_INFO
|
||||
* macro, or its siblings, to match class-per-interface style
|
||||
* devices (as recorded in bDeviceClass).
|
||||
*
|
||||
* Within those groups, remember that not all combinations are
|
||||
* meaningful. For example, don't give a product version range
|
||||
* without vendor and product IDs; or specify a protocol without
|
||||
* its associated class and subclass.
|
||||
*/
|
||||
const struct usb_device_id *usb_match_id(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
/* proc_connectinfo in devio.c may call us with id == NULL. */
|
||||
if (id == NULL)
|
||||
return NULL;
|
||||
|
||||
/* It is important to check that id->driver_info is nonzero,
|
||||
since an entry that is all zeroes except for a nonzero
|
||||
id->driver_info is the way to create an entry that
|
||||
indicates that the driver want to examine every
|
||||
device and interface. */
|
||||
for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
|
||||
id->driver_info; id++) {
|
||||
if (usb_match_one_id(interface, id))
|
||||
return id;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_match_id);
|
||||
|
||||
int usb_device_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
struct usb_interface *intf;
|
||||
struct usb_driver *usb_drv;
|
||||
const struct usb_device_id *id;
|
||||
|
||||
/* check for generic driver, which we don't match any device with */
|
||||
if (drv == &usb_generic_driver)
|
||||
return 0;
|
||||
|
||||
intf = to_usb_interface(dev);
|
||||
usb_drv = to_usb_driver(drv);
|
||||
|
||||
id = usb_match_id(intf, usb_drv->id_table);
|
||||
if (id)
|
||||
return 1;
|
||||
|
||||
id = usb_match_dynamic_id(intf, usb_drv);
|
||||
if (id)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_register_driver - register a USB driver
|
||||
* @new_driver: USB operations for the driver
|
||||
* @owner: module owner of this driver.
|
||||
*
|
||||
* Registers a USB driver with the USB core. The list of unattached
|
||||
* interfaces will be rescanned whenever a new driver is added, allowing
|
||||
* the new driver to attach to any recognized devices.
|
||||
* Returns a negative error code on failure and 0 on success.
|
||||
*
|
||||
* NOTE: if you want your driver to use the USB major number, you must call
|
||||
* usb_register_dev() to enable that functionality. This function no longer
|
||||
* takes care of that.
|
||||
*/
|
||||
int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
new_driver->driver.name = (char *)new_driver->name;
|
||||
new_driver->driver.bus = &usb_bus_type;
|
||||
new_driver->driver.probe = usb_probe_interface;
|
||||
new_driver->driver.remove = usb_unbind_interface;
|
||||
new_driver->driver.owner = owner;
|
||||
spin_lock_init(&new_driver->dynids.lock);
|
||||
INIT_LIST_HEAD(&new_driver->dynids.list);
|
||||
|
||||
retval = driver_register(&new_driver->driver);
|
||||
|
||||
if (!retval) {
|
||||
pr_info("%s: registered new driver %s\n",
|
||||
usbcore_name, new_driver->name);
|
||||
usbfs_update_special();
|
||||
usb_create_newid_file(new_driver);
|
||||
} else {
|
||||
printk(KERN_ERR "%s: error %d registering driver %s\n",
|
||||
usbcore_name, retval, new_driver->name);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_register_driver);
|
||||
|
||||
/**
|
||||
* usb_deregister - unregister a USB driver
|
||||
* @driver: USB operations of the driver to unregister
|
||||
* Context: must be able to sleep
|
||||
*
|
||||
* Unlinks the specified driver from the internal USB driver list.
|
||||
*
|
||||
* NOTE: If you called usb_register_dev(), you still need to call
|
||||
* usb_deregister_dev() to clean up your driver's allocated minor numbers,
|
||||
* this * call will no longer do it for you.
|
||||
*/
|
||||
void usb_deregister(struct usb_driver *driver)
|
||||
{
|
||||
pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name);
|
||||
|
||||
usb_remove_newid_file(driver);
|
||||
usb_free_dynids(driver);
|
||||
driver_unregister(&driver->driver);
|
||||
|
||||
usbfs_update_special();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_deregister);
|
@ -857,9 +857,7 @@ static int register_root_hub (struct usb_device *usb_dev,
|
||||
return (retval < 0) ? retval : -EMSGSIZE;
|
||||
}
|
||||
|
||||
usb_lock_device (usb_dev);
|
||||
retval = usb_new_device (usb_dev);
|
||||
usb_unlock_device (usb_dev);
|
||||
if (retval) {
|
||||
usb_dev->bus->root_hub = NULL;
|
||||
dev_err (parent_dev, "can't register root hub for %s, %d\n",
|
||||
@ -1827,8 +1825,6 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||
retval = -ENOMEM;
|
||||
goto err_allocate_root_hub;
|
||||
}
|
||||
rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
|
||||
USB_SPEED_FULL;
|
||||
|
||||
/* Although in principle hcd->driver->start() might need to use rhdev,
|
||||
* none of the current drivers do.
|
||||
@ -1846,6 +1842,9 @@ int usb_add_hcd(struct usb_hcd *hcd,
|
||||
dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
|
||||
hcd->remote_wakeup = hcd->can_wakeup;
|
||||
|
||||
rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
|
||||
USB_SPEED_FULL;
|
||||
rhdev->bus_mA = min(500u, hcd->power_budget);
|
||||
if ((retval = register_root_hub(rhdev, hcd)) != 0)
|
||||
goto err_register_root_hub;
|
||||
|
||||
@ -1891,7 +1890,10 @@ void usb_remove_hcd(struct usb_hcd *hcd)
|
||||
spin_lock_irq (&hcd_root_hub_lock);
|
||||
hcd->rh_registered = 0;
|
||||
spin_unlock_irq (&hcd_root_hub_lock);
|
||||
|
||||
down(&usb_bus_list_lock);
|
||||
usb_disconnect(&hcd->self.root_hub);
|
||||
up(&usb_bus_list_lock);
|
||||
|
||||
hcd->poll_rh = 0;
|
||||
del_timer_sync(&hcd->rh_timer);
|
||||
|
@ -380,6 +380,7 @@ extern int usb_find_interface_driver (struct usb_device *dev,
|
||||
#ifdef CONFIG_PM
|
||||
extern void usb_hcd_suspend_root_hub (struct usb_hcd *hcd);
|
||||
extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
|
||||
extern void usb_root_hub_lost_power (struct usb_device *rhdev);
|
||||
extern int hcd_bus_suspend (struct usb_bus *bus);
|
||||
extern int hcd_bus_resume (struct usb_bus *bus);
|
||||
#else
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include "hub.h"
|
||||
|
||||
/* Protect struct usb_device->state and ->children members
|
||||
* Note: Both are also protected by ->serialize, except that ->state can
|
||||
* Note: Both are also protected by ->dev.sem, except that ->state can
|
||||
* change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */
|
||||
static DEFINE_SPINLOCK(device_state_lock);
|
||||
|
||||
@ -515,6 +515,31 @@ static int hub_port_disable(struct usb_hub *hub, int port1, int set_state)
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* caller has locked the hub device */
|
||||
static void hub_pre_reset(struct usb_hub *hub, int disable_ports)
|
||||
{
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
int port1;
|
||||
|
||||
for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
|
||||
if (hdev->children[port1 - 1]) {
|
||||
usb_disconnect(&hdev->children[port1 - 1]);
|
||||
if (disable_ports)
|
||||
hub_port_disable(hub, port1, 0);
|
||||
}
|
||||
}
|
||||
hub_quiesce(hub);
|
||||
}
|
||||
|
||||
/* caller has locked the hub device */
|
||||
static void hub_post_reset(struct usb_hub *hub)
|
||||
{
|
||||
hub_activate(hub);
|
||||
hub_power_on(hub);
|
||||
}
|
||||
|
||||
|
||||
static int hub_configure(struct usb_hub *hub,
|
||||
struct usb_endpoint_descriptor *endpoint)
|
||||
{
|
||||
@ -677,26 +702,40 @@ static int hub_configure(struct usb_hub *hub,
|
||||
* and battery-powered root hubs (may provide just 8 mA).
|
||||
*/
|
||||
ret = usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus);
|
||||
if (ret < 0) {
|
||||
if (ret < 2) {
|
||||
message = "can't get hub status";
|
||||
goto fail;
|
||||
}
|
||||
le16_to_cpus(&hubstatus);
|
||||
if (hdev == hdev->bus->root_hub) {
|
||||
struct usb_hcd *hcd =
|
||||
container_of(hdev->bus, struct usb_hcd, self);
|
||||
|
||||
hub->power_budget = min(500u, hcd->power_budget) / 2;
|
||||
if (hdev->bus_mA == 0 || hdev->bus_mA >= 500)
|
||||
hub->mA_per_port = 500;
|
||||
else {
|
||||
hub->mA_per_port = hdev->bus_mA;
|
||||
hub->limited_power = 1;
|
||||
}
|
||||
} else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
|
||||
dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
|
||||
hub->descriptor->bHubContrCurrent);
|
||||
hub->power_budget = (501 - hub->descriptor->bHubContrCurrent)
|
||||
/ 2;
|
||||
}
|
||||
if (hub->power_budget)
|
||||
dev_dbg(hub_dev, "%dmA bus power budget for children\n",
|
||||
hub->power_budget * 2);
|
||||
hub->limited_power = 1;
|
||||
if (hdev->maxchild > 0) {
|
||||
int remaining = hdev->bus_mA -
|
||||
hub->descriptor->bHubContrCurrent;
|
||||
|
||||
if (remaining < hdev->maxchild * 100)
|
||||
dev_warn(hub_dev,
|
||||
"insufficient power available "
|
||||
"to use all downstream ports\n");
|
||||
hub->mA_per_port = 100; /* 7.2.1.1 */
|
||||
}
|
||||
} else { /* Self-powered external hub */
|
||||
/* FIXME: What about battery-powered external hubs that
|
||||
* provide less current per port? */
|
||||
hub->mA_per_port = 500;
|
||||
}
|
||||
if (hub->mA_per_port < 500)
|
||||
dev_dbg(hub_dev, "%umA bus power budget for each child\n",
|
||||
hub->mA_per_port);
|
||||
|
||||
ret = hub_hub_status(hub, &hubstatus, &hubchange);
|
||||
if (ret < 0) {
|
||||
@ -750,29 +789,10 @@ fail:
|
||||
|
||||
static unsigned highspeed_hubs;
|
||||
|
||||
/* Called after the hub driver is unbound from a hub with children */
|
||||
static void hub_remove_children_work(void *__hub)
|
||||
{
|
||||
struct usb_hub *hub = __hub;
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
int i;
|
||||
|
||||
kfree(hub);
|
||||
|
||||
usb_lock_device(hdev);
|
||||
for (i = 0; i < hdev->maxchild; ++i) {
|
||||
if (hdev->children[i])
|
||||
usb_disconnect(&hdev->children[i]);
|
||||
}
|
||||
usb_unlock_device(hdev);
|
||||
usb_put_dev(hdev);
|
||||
}
|
||||
|
||||
static void hub_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct usb_hub *hub = usb_get_intfdata (intf);
|
||||
struct usb_device *hdev;
|
||||
int n, port1;
|
||||
|
||||
usb_set_intfdata (intf, NULL);
|
||||
hdev = hub->hdev;
|
||||
@ -780,7 +800,9 @@ static void hub_disconnect(struct usb_interface *intf)
|
||||
if (hdev->speed == USB_SPEED_HIGH)
|
||||
highspeed_hubs--;
|
||||
|
||||
hub_quiesce(hub);
|
||||
/* Disconnect all children and quiesce the hub */
|
||||
hub_pre_reset(hub, 1);
|
||||
|
||||
usb_free_urb(hub->urb);
|
||||
hub->urb = NULL;
|
||||
|
||||
@ -800,27 +822,7 @@ static void hub_disconnect(struct usb_interface *intf)
|
||||
hub->buffer = NULL;
|
||||
}
|
||||
|
||||
/* If there are any children then this is an unbind only, not a
|
||||
* physical disconnection. The active ports must be disabled
|
||||
* and later on we must call usb_disconnect(). We can't call
|
||||
* it now because we may not hold the hub's device lock.
|
||||
*/
|
||||
n = 0;
|
||||
for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
|
||||
if (hdev->children[port1 - 1]) {
|
||||
++n;
|
||||
hub_port_disable(hub, port1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 0)
|
||||
kfree(hub);
|
||||
else {
|
||||
/* Reuse the hub->leds work_struct for our own purposes */
|
||||
INIT_WORK(&hub->leds, hub_remove_children_work, hub);
|
||||
schedule_work(&hub->leds);
|
||||
usb_get_dev(hdev);
|
||||
}
|
||||
kfree(hub);
|
||||
}
|
||||
|
||||
static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
@ -917,26 +919,6 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
|
||||
}
|
||||
}
|
||||
|
||||
/* caller has locked the hub device */
|
||||
static void hub_pre_reset(struct usb_hub *hub)
|
||||
{
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < hdev->maxchild; ++i) {
|
||||
if (hdev->children[i])
|
||||
usb_disconnect(&hdev->children[i]);
|
||||
}
|
||||
hub_quiesce(hub);
|
||||
}
|
||||
|
||||
/* caller has locked the hub device */
|
||||
static void hub_post_reset(struct usb_hub *hub)
|
||||
{
|
||||
hub_activate(hub);
|
||||
hub_power_on(hub);
|
||||
}
|
||||
|
||||
|
||||
/* grab device/port lock, returning index of that port (zero based).
|
||||
* protects the upstream link used by this device from concurrent
|
||||
@ -964,24 +946,21 @@ static int locktree(struct usb_device *udev)
|
||||
t = locktree(hdev);
|
||||
if (t < 0)
|
||||
return t;
|
||||
for (t = 0; t < hdev->maxchild; t++) {
|
||||
if (hdev->children[t] == udev) {
|
||||
/* everything is fail-fast once disconnect
|
||||
* processing starts
|
||||
*/
|
||||
if (udev->state == USB_STATE_NOTATTACHED)
|
||||
break;
|
||||
|
||||
/* when everyone grabs locks top->bottom,
|
||||
* non-overlapping work may be concurrent
|
||||
*/
|
||||
down(&udev->serialize);
|
||||
up(&hdev->serialize);
|
||||
return t + 1;
|
||||
}
|
||||
/* everything is fail-fast once disconnect
|
||||
* processing starts
|
||||
*/
|
||||
if (udev->state == USB_STATE_NOTATTACHED) {
|
||||
usb_unlock_device(hdev);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* when everyone grabs locks top->bottom,
|
||||
* non-overlapping work may be concurrent
|
||||
*/
|
||||
usb_lock_device(udev);
|
||||
usb_unlock_device(hdev);
|
||||
return -ENODEV;
|
||||
return udev->portnum;
|
||||
}
|
||||
|
||||
static void recursively_mark_NOTATTACHED(struct usb_device *udev)
|
||||
@ -1039,6 +1018,39 @@ void usb_set_device_state(struct usb_device *udev,
|
||||
EXPORT_SYMBOL(usb_set_device_state);
|
||||
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
/**
|
||||
* usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power
|
||||
* @rhdev: struct usb_device for the root hub
|
||||
*
|
||||
* The USB host controller driver calls this function when its root hub
|
||||
* is resumed and Vbus power has been interrupted or the controller
|
||||
* has been reset. The routine marks all the children of the root hub
|
||||
* as NOTATTACHED and marks logical connect-change events on their ports.
|
||||
*/
|
||||
void usb_root_hub_lost_power(struct usb_device *rhdev)
|
||||
{
|
||||
struct usb_hub *hub;
|
||||
int port1;
|
||||
unsigned long flags;
|
||||
|
||||
dev_warn(&rhdev->dev, "root hub lost power or was reset\n");
|
||||
spin_lock_irqsave(&device_state_lock, flags);
|
||||
hub = hdev_to_hub(rhdev);
|
||||
for (port1 = 1; port1 <= rhdev->maxchild; ++port1) {
|
||||
if (rhdev->children[port1 - 1]) {
|
||||
recursively_mark_NOTATTACHED(
|
||||
rhdev->children[port1 - 1]);
|
||||
set_bit(port1, hub->change_bits);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&device_state_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
|
||||
|
||||
#endif
|
||||
|
||||
static void choose_address(struct usb_device *udev)
|
||||
{
|
||||
int devnum;
|
||||
@ -1099,16 +1111,10 @@ void usb_disconnect(struct usb_device **pdev)
|
||||
* this quiesces everyting except pending urbs.
|
||||
*/
|
||||
usb_set_device_state(udev, USB_STATE_NOTATTACHED);
|
||||
|
||||
/* lock the bus list on behalf of HCDs unregistering their root hubs */
|
||||
if (!udev->parent) {
|
||||
down(&usb_bus_list_lock);
|
||||
usb_lock_device(udev);
|
||||
} else
|
||||
down(&udev->serialize);
|
||||
|
||||
dev_info (&udev->dev, "USB disconnect, address %d\n", udev->devnum);
|
||||
|
||||
usb_lock_device(udev);
|
||||
|
||||
/* Free up all the children before we remove this device */
|
||||
for (i = 0; i < USB_MAXCHILDREN; i++) {
|
||||
if (udev->children[i])
|
||||
@ -1136,54 +1142,112 @@ void usb_disconnect(struct usb_device **pdev)
|
||||
*pdev = NULL;
|
||||
spin_unlock_irq(&device_state_lock);
|
||||
|
||||
if (!udev->parent) {
|
||||
usb_unlock_device(udev);
|
||||
up(&usb_bus_list_lock);
|
||||
} else
|
||||
up(&udev->serialize);
|
||||
usb_unlock_device(udev);
|
||||
|
||||
device_unregister(&udev->dev);
|
||||
}
|
||||
|
||||
static inline const char *plural(int n)
|
||||
{
|
||||
return (n == 1 ? "" : "s");
|
||||
}
|
||||
|
||||
static int choose_configuration(struct usb_device *udev)
|
||||
{
|
||||
int c, i;
|
||||
int i;
|
||||
u16 devstatus;
|
||||
int bus_powered;
|
||||
int num_configs;
|
||||
struct usb_host_config *c, *best;
|
||||
|
||||
/* NOTE: this should interact with hub power budgeting */
|
||||
/* If this fails, assume the device is bus-powered */
|
||||
devstatus = 0;
|
||||
usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
|
||||
le16_to_cpus(&devstatus);
|
||||
bus_powered = ((devstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0);
|
||||
dev_dbg(&udev->dev, "device is %s-powered\n",
|
||||
bus_powered ? "bus" : "self");
|
||||
|
||||
c = udev->config[0].desc.bConfigurationValue;
|
||||
if (udev->descriptor.bNumConfigurations != 1) {
|
||||
for (i = 0; i < udev->descriptor.bNumConfigurations; i++) {
|
||||
struct usb_interface_descriptor *desc;
|
||||
best = NULL;
|
||||
c = udev->config;
|
||||
num_configs = udev->descriptor.bNumConfigurations;
|
||||
for (i = 0; i < num_configs; (i++, c++)) {
|
||||
struct usb_interface_descriptor *desc =
|
||||
&c->intf_cache[0]->altsetting->desc;
|
||||
|
||||
/* heuristic: Linux is more likely to have class
|
||||
* drivers, so avoid vendor-specific interfaces.
|
||||
*/
|
||||
desc = &udev->config[i].intf_cache[0]
|
||||
->altsetting->desc;
|
||||
if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
|
||||
continue;
|
||||
/* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS.
|
||||
* MSFT needs this to be the first config; never use
|
||||
* it as the default unless Linux has host-side RNDIS.
|
||||
* A second config would ideally be CDC-Ethernet, but
|
||||
* may instead be the "vendor specific" CDC subset
|
||||
* long used by ARM Linux for sa1100 or pxa255.
|
||||
*/
|
||||
if (desc->bInterfaceClass == USB_CLASS_COMM
|
||||
&& desc->bInterfaceSubClass == 2
|
||||
&& desc->bInterfaceProtocol == 0xff) {
|
||||
c = udev->config[1].desc.bConfigurationValue;
|
||||
continue;
|
||||
}
|
||||
c = udev->config[i].desc.bConfigurationValue;
|
||||
/*
|
||||
* HP's USB bus-powered keyboard has only one configuration
|
||||
* and it claims to be self-powered; other devices may have
|
||||
* similar errors in their descriptors. If the next test
|
||||
* were allowed to execute, such configurations would always
|
||||
* be rejected and the devices would not work as expected.
|
||||
*/
|
||||
#if 0
|
||||
/* Rule out self-powered configs for a bus-powered device */
|
||||
if (bus_powered && (c->desc.bmAttributes &
|
||||
USB_CONFIG_ATT_SELFPOWER))
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* The next test may not be as effective as it should be.
|
||||
* Some hubs have errors in their descriptor, claiming
|
||||
* to be self-powered when they are really bus-powered.
|
||||
* We will overestimate the amount of current such hubs
|
||||
* make available for each port.
|
||||
*
|
||||
* This is a fairly benign sort of failure. It won't
|
||||
* cause us to reject configurations that we should have
|
||||
* accepted.
|
||||
*/
|
||||
|
||||
/* Rule out configs that draw too much bus current */
|
||||
if (c->desc.bMaxPower * 2 > udev->bus_mA)
|
||||
continue;
|
||||
|
||||
/* If the first config's first interface is COMM/2/0xff
|
||||
* (MSFT RNDIS), rule it out unless Linux has host-side
|
||||
* RNDIS support. */
|
||||
if (i == 0 && desc->bInterfaceClass == USB_CLASS_COMM
|
||||
&& desc->bInterfaceSubClass == 2
|
||||
&& desc->bInterfaceProtocol == 0xff) {
|
||||
#ifndef CONFIG_USB_NET_RNDIS
|
||||
continue;
|
||||
#else
|
||||
best = c;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* From the remaining configs, choose the first one whose
|
||||
* first interface is for a non-vendor-specific class.
|
||||
* Reason: Linux is more likely to have a class driver
|
||||
* than a vendor-specific driver. */
|
||||
else if (udev->descriptor.bDeviceClass !=
|
||||
USB_CLASS_VENDOR_SPEC &&
|
||||
desc->bInterfaceClass !=
|
||||
USB_CLASS_VENDOR_SPEC) {
|
||||
best = c;
|
||||
break;
|
||||
}
|
||||
dev_info(&udev->dev,
|
||||
"configuration #%d chosen from %d choices\n",
|
||||
c, udev->descriptor.bNumConfigurations);
|
||||
|
||||
/* If all the remaining configs are vendor-specific,
|
||||
* choose the first one. */
|
||||
else if (!best)
|
||||
best = c;
|
||||
}
|
||||
return c;
|
||||
|
||||
if (best) {
|
||||
i = best->desc.bConfigurationValue;
|
||||
dev_info(&udev->dev,
|
||||
"configuration #%d chosen from %d choice%s\n",
|
||||
i, num_configs, plural(num_configs));
|
||||
} else {
|
||||
i = -1;
|
||||
dev_warn(&udev->dev,
|
||||
"no configuration chosen from %d choice%s\n",
|
||||
num_configs, plural(num_configs));
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -1210,8 +1274,8 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
|
||||
*
|
||||
* This is called with devices which have been enumerated, but not yet
|
||||
* configured. The device descriptor is available, but not descriptors
|
||||
* for any device configuration. The caller must have locked udev and
|
||||
* either the parent hub (if udev is a normal device) or else the
|
||||
* for any device configuration. The caller must have locked either
|
||||
* the parent hub (if udev is a normal device) or else the
|
||||
* usb_bus_list_lock (if udev is a root hub). The parent's pointer to
|
||||
* udev has already been installed, but udev is not yet visible through
|
||||
* sysfs or other filesystem code.
|
||||
@ -1221,8 +1285,7 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
|
||||
*
|
||||
* This call is synchronous, and may not be used in an interrupt context.
|
||||
*
|
||||
* Only the hub driver should ever call this; root hub registration
|
||||
* uses it indirectly.
|
||||
* Only the hub driver or root-hub registrar should ever call this.
|
||||
*/
|
||||
int usb_new_device(struct usb_device *udev)
|
||||
{
|
||||
@ -1269,15 +1332,9 @@ int usb_new_device(struct usb_device *udev)
|
||||
le16_to_cpu(udev->config[0].desc.wTotalLength),
|
||||
USB_DT_OTG, (void **) &desc) == 0) {
|
||||
if (desc->bmAttributes & USB_OTG_HNP) {
|
||||
unsigned port1;
|
||||
unsigned port1 = udev->portnum;
|
||||
struct usb_device *root = udev->parent;
|
||||
|
||||
for (port1 = 1; port1 <= root->maxchild;
|
||||
port1++) {
|
||||
if (root->children[port1-1] == udev)
|
||||
break;
|
||||
}
|
||||
|
||||
dev_info(&udev->dev,
|
||||
"Dual-Role OTG device on %sHNP port\n",
|
||||
(port1 == bus->otg_port)
|
||||
@ -1331,27 +1388,27 @@ int usb_new_device(struct usb_device *udev)
|
||||
}
|
||||
usb_create_sysfs_dev_files (udev);
|
||||
|
||||
usb_lock_device(udev);
|
||||
|
||||
/* choose and set the configuration. that registers the interfaces
|
||||
* with the driver core, and lets usb device drivers bind to them.
|
||||
*/
|
||||
c = choose_configuration(udev);
|
||||
if (c < 0)
|
||||
dev_warn(&udev->dev,
|
||||
"can't choose an initial configuration\n");
|
||||
else {
|
||||
if (c >= 0) {
|
||||
err = usb_set_configuration(udev, c);
|
||||
if (err) {
|
||||
dev_err(&udev->dev, "can't set config #%d, error %d\n",
|
||||
c, err);
|
||||
usb_remove_sysfs_dev_files(udev);
|
||||
device_del(&udev->dev);
|
||||
goto fail;
|
||||
/* This need not be fatal. The user can try to
|
||||
* set other configurations. */
|
||||
}
|
||||
}
|
||||
|
||||
/* USB device state == configured ... usable */
|
||||
usb_notify_add_device(udev);
|
||||
|
||||
usb_unlock_device(udev);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
@ -1654,15 +1711,9 @@ static int __usb_suspend_device (struct usb_device *udev, int port1)
|
||||
int usb_suspend_device(struct usb_device *udev)
|
||||
{
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
int port1, status;
|
||||
|
||||
port1 = locktree(udev);
|
||||
if (port1 < 0)
|
||||
return port1;
|
||||
|
||||
status = __usb_suspend_device(udev, port1);
|
||||
usb_unlock_device(udev);
|
||||
return status;
|
||||
if (udev->state == USB_STATE_NOTATTACHED)
|
||||
return -ENODEV;
|
||||
return __usb_suspend_device(udev, udev->portnum);
|
||||
#else
|
||||
/* NOTE: udev->state unchanged, it's not lying ... */
|
||||
udev->dev.power.power_state = PMSG_SUSPEND;
|
||||
@ -1694,13 +1745,14 @@ static int finish_device_resume(struct usb_device *udev)
|
||||
usb_set_device_state(udev, udev->actconfig
|
||||
? USB_STATE_CONFIGURED
|
||||
: USB_STATE_ADDRESS);
|
||||
udev->dev.power.power_state = PMSG_ON;
|
||||
|
||||
/* 10.5.4.5 says be sure devices in the tree are still there.
|
||||
* For now let's assume the device didn't go crazy on resume,
|
||||
* and device drivers will know about any resume quirks.
|
||||
*/
|
||||
status = usb_get_status(udev, USB_RECIP_DEVICE, 0, &devstatus);
|
||||
if (status < 0)
|
||||
if (status < 2)
|
||||
dev_dbg(&udev->dev,
|
||||
"gone after usb resume? status %d\n",
|
||||
status);
|
||||
@ -1709,7 +1761,7 @@ static int finish_device_resume(struct usb_device *udev)
|
||||
int (*resume)(struct device *);
|
||||
|
||||
le16_to_cpus(&devstatus);
|
||||
if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)
|
||||
if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
|
||||
&& udev->parent) {
|
||||
status = usb_control_msg(udev,
|
||||
usb_sndctrlpipe(udev, 0),
|
||||
@ -1729,8 +1781,14 @@ static int finish_device_resume(struct usb_device *udev)
|
||||
* may have a child resume event to deal with soon
|
||||
*/
|
||||
resume = udev->dev.bus->resume;
|
||||
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++)
|
||||
(void) resume(&udev->actconfig->interface[i]->dev);
|
||||
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
|
||||
struct device *dev =
|
||||
&udev->actconfig->interface[i]->dev;
|
||||
|
||||
down(&dev->sem);
|
||||
(void) resume(dev);
|
||||
up(&dev->sem);
|
||||
}
|
||||
status = 0;
|
||||
|
||||
} else if (udev->devnum <= 0) {
|
||||
@ -1813,11 +1871,10 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
|
||||
*/
|
||||
int usb_resume_device(struct usb_device *udev)
|
||||
{
|
||||
int port1, status;
|
||||
int status;
|
||||
|
||||
port1 = locktree(udev);
|
||||
if (port1 < 0)
|
||||
return port1;
|
||||
if (udev->state == USB_STATE_NOTATTACHED)
|
||||
return -ENODEV;
|
||||
|
||||
#ifdef CONFIG_USB_SUSPEND
|
||||
/* selective resume of one downstream hub-to-device port */
|
||||
@ -1826,7 +1883,7 @@ int usb_resume_device(struct usb_device *udev)
|
||||
// NOTE swsusp may bork us, device state being wrong...
|
||||
// NOTE this fails if parent is also suspended...
|
||||
status = hub_port_resume(hdev_to_hub(udev->parent),
|
||||
port1, udev);
|
||||
udev->portnum, udev);
|
||||
} else
|
||||
status = 0;
|
||||
} else
|
||||
@ -1836,13 +1893,11 @@ int usb_resume_device(struct usb_device *udev)
|
||||
dev_dbg(&udev->dev, "can't resume, status %d\n",
|
||||
status);
|
||||
|
||||
usb_unlock_device(udev);
|
||||
|
||||
/* rebind drivers that had no suspend() */
|
||||
if (status == 0) {
|
||||
usb_lock_all_devices();
|
||||
usb_unlock_device(udev);
|
||||
bus_rescan_devices(&usb_bus_type);
|
||||
usb_unlock_all_devices();
|
||||
usb_lock_device(udev);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
@ -1856,14 +1911,14 @@ static int remote_wakeup(struct usb_device *udev)
|
||||
/* don't repeat RESUME sequence if this device
|
||||
* was already woken up by some other task
|
||||
*/
|
||||
down(&udev->serialize);
|
||||
usb_lock_device(udev);
|
||||
if (udev->state == USB_STATE_SUSPENDED) {
|
||||
dev_dbg(&udev->dev, "RESUME (wakeup)\n");
|
||||
/* TRSMRCY = 10 msec */
|
||||
msleep(10);
|
||||
status = finish_device_resume(udev);
|
||||
}
|
||||
up(&udev->serialize);
|
||||
usb_unlock_device(udev);
|
||||
#endif
|
||||
return status;
|
||||
}
|
||||
@ -1964,7 +2019,7 @@ static int hub_resume(struct usb_interface *intf)
|
||||
|
||||
if (!udev || status < 0)
|
||||
continue;
|
||||
down (&udev->serialize);
|
||||
usb_lock_device(udev);
|
||||
if (portstat & USB_PORT_STAT_SUSPEND)
|
||||
status = hub_port_resume(hub, port1, udev);
|
||||
else {
|
||||
@ -1975,7 +2030,7 @@ static int hub_resume(struct usb_interface *intf)
|
||||
hub_port_logical_disconnect(hub, port1);
|
||||
}
|
||||
}
|
||||
up(&udev->serialize);
|
||||
usb_unlock_device(udev);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -2359,39 +2414,36 @@ hub_power_remaining (struct usb_hub *hub)
|
||||
{
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
int remaining;
|
||||
unsigned i;
|
||||
int port1;
|
||||
|
||||
remaining = hub->power_budget;
|
||||
if (!remaining) /* self-powered */
|
||||
if (!hub->limited_power)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < hdev->maxchild; i++) {
|
||||
struct usb_device *udev = hdev->children[i];
|
||||
int delta, ceiling;
|
||||
remaining = hdev->bus_mA - hub->descriptor->bHubContrCurrent;
|
||||
for (port1 = 1; port1 <= hdev->maxchild; ++port1) {
|
||||
struct usb_device *udev = hdev->children[port1 - 1];
|
||||
int delta;
|
||||
|
||||
if (!udev)
|
||||
continue;
|
||||
|
||||
/* 100mA per-port ceiling, or 8mA for OTG ports */
|
||||
if (i != (udev->bus->otg_port - 1) || hdev->parent)
|
||||
ceiling = 50;
|
||||
else
|
||||
ceiling = 4;
|
||||
|
||||
/* Unconfigured devices may not use more than 100mA,
|
||||
* or 8mA for OTG ports */
|
||||
if (udev->actconfig)
|
||||
delta = udev->actconfig->desc.bMaxPower;
|
||||
delta = udev->actconfig->desc.bMaxPower * 2;
|
||||
else if (port1 != udev->bus->otg_port || hdev->parent)
|
||||
delta = 100;
|
||||
else
|
||||
delta = ceiling;
|
||||
// dev_dbg(&udev->dev, "budgeted %dmA\n", 2 * delta);
|
||||
if (delta > ceiling)
|
||||
dev_warn(&udev->dev, "%dmA over %dmA budget!\n",
|
||||
2 * (delta - ceiling), 2 * ceiling);
|
||||
delta = 8;
|
||||
if (delta > hub->mA_per_port)
|
||||
dev_warn(&udev->dev, "%dmA is over %umA budget "
|
||||
"for port %d!\n",
|
||||
delta, hub->mA_per_port, port1);
|
||||
remaining -= delta;
|
||||
}
|
||||
if (remaining < 0) {
|
||||
dev_warn(hub->intfdev,
|
||||
"%dmA over power budget!\n",
|
||||
-2 * remaining);
|
||||
dev_warn(hub->intfdev, "%dmA over power budget!\n",
|
||||
- remaining);
|
||||
remaining = 0;
|
||||
}
|
||||
return remaining;
|
||||
@ -2486,7 +2538,8 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||
|
||||
usb_set_device_state(udev, USB_STATE_POWERED);
|
||||
udev->speed = USB_SPEED_UNKNOWN;
|
||||
|
||||
udev->bus_mA = hub->mA_per_port;
|
||||
|
||||
/* set the address */
|
||||
choose_address(udev);
|
||||
if (udev->devnum <= 0) {
|
||||
@ -2506,16 +2559,16 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||
* on the parent.
|
||||
*/
|
||||
if (udev->descriptor.bDeviceClass == USB_CLASS_HUB
|
||||
&& hub->power_budget) {
|
||||
&& udev->bus_mA <= 100) {
|
||||
u16 devstat;
|
||||
|
||||
status = usb_get_status(udev, USB_RECIP_DEVICE, 0,
|
||||
&devstat);
|
||||
if (status < 0) {
|
||||
if (status < 2) {
|
||||
dev_dbg(&udev->dev, "get status %d ?\n", status);
|
||||
goto loop_disable;
|
||||
}
|
||||
cpu_to_le16s(&devstat);
|
||||
le16_to_cpus(&devstat);
|
||||
if ((devstat & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
|
||||
dev_err(&udev->dev,
|
||||
"can't connect bus-powered hub "
|
||||
@ -2540,7 +2593,6 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||
* udev becomes globally accessible, although presumably
|
||||
* no one will look at it until hdev is unlocked.
|
||||
*/
|
||||
down (&udev->serialize);
|
||||
status = 0;
|
||||
|
||||
/* We mustn't add new devices if the parent hub has
|
||||
@ -2564,15 +2616,12 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
||||
}
|
||||
}
|
||||
|
||||
up (&udev->serialize);
|
||||
if (status)
|
||||
goto loop_disable;
|
||||
|
||||
status = hub_power_remaining(hub);
|
||||
if (status)
|
||||
dev_dbg(hub_dev,
|
||||
"%dmA power budget left\n",
|
||||
2 * status);
|
||||
dev_dbg(hub_dev, "%dmA power budget left\n", status);
|
||||
|
||||
return;
|
||||
|
||||
@ -2648,6 +2697,8 @@ static void hub_events(void)
|
||||
if (i) {
|
||||
dpm_runtime_resume(&hdev->dev);
|
||||
dpm_runtime_resume(&intf->dev);
|
||||
usb_put_intf(intf);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Lock the device, then check to see if we were
|
||||
@ -2661,7 +2712,7 @@ static void hub_events(void)
|
||||
|
||||
/* If the hub has died, clean up after it */
|
||||
if (hdev->state == USB_STATE_NOTATTACHED) {
|
||||
hub_pre_reset(hub);
|
||||
hub_pre_reset(hub, 0);
|
||||
goto loop;
|
||||
}
|
||||
|
||||
@ -2784,6 +2835,11 @@ static void hub_events(void)
|
||||
if (hubchange & HUB_CHANGE_LOCAL_POWER) {
|
||||
dev_dbg (hub_dev, "power change\n");
|
||||
clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
|
||||
if (hubstatus & HUB_STATUS_LOCAL_POWER)
|
||||
/* FIXME: Is this always true? */
|
||||
hub->limited_power = 0;
|
||||
else
|
||||
hub->limited_power = 1;
|
||||
}
|
||||
if (hubchange & HUB_CHANGE_OVERCURRENT) {
|
||||
dev_dbg (hub_dev, "overcurrent change\n");
|
||||
@ -2832,7 +2888,6 @@ static struct usb_device_id hub_id_table [] = {
|
||||
MODULE_DEVICE_TABLE (usb, hub_id_table);
|
||||
|
||||
static struct usb_driver hub_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "hub",
|
||||
.probe = hub_probe,
|
||||
.disconnect = hub_disconnect,
|
||||
@ -2944,7 +2999,8 @@ int usb_reset_device(struct usb_device *udev)
|
||||
struct usb_hub *parent_hub;
|
||||
struct usb_device_descriptor descriptor = udev->descriptor;
|
||||
struct usb_hub *hub = NULL;
|
||||
int i, ret = 0, port1 = -1;
|
||||
int i, ret = 0;
|
||||
int port1 = udev->portnum;
|
||||
|
||||
if (udev->state == USB_STATE_NOTATTACHED ||
|
||||
udev->state == USB_STATE_SUSPENDED) {
|
||||
@ -2958,18 +3014,6 @@ int usb_reset_device(struct usb_device *udev)
|
||||
dev_dbg(&udev->dev, "%s for root hub!\n", __FUNCTION__);
|
||||
return -EISDIR;
|
||||
}
|
||||
|
||||
for (i = 0; i < parent_hdev->maxchild; i++)
|
||||
if (parent_hdev->children[i] == udev) {
|
||||
port1 = i + 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (port1 < 0) {
|
||||
/* If this ever happens, it's very bad */
|
||||
dev_err(&udev->dev, "Can't locate device's port!\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
parent_hub = hdev_to_hub(parent_hdev);
|
||||
|
||||
/* If we're resetting an active hub, take some special actions */
|
||||
@ -2977,7 +3021,7 @@ int usb_reset_device(struct usb_device *udev)
|
||||
udev->actconfig->interface[0]->dev.driver ==
|
||||
&hub_driver.driver &&
|
||||
(hub = hdev_to_hub(udev)) != NULL) {
|
||||
hub_pre_reset(hub);
|
||||
hub_pre_reset(hub, 0);
|
||||
}
|
||||
|
||||
set_bit(port1, parent_hub->busy_bits);
|
||||
|
@ -220,8 +220,9 @@ struct usb_hub {
|
||||
struct usb_hub_descriptor *descriptor; /* class descriptor */
|
||||
struct usb_tt tt; /* Transaction Translator */
|
||||
|
||||
u8 power_budget; /* in 2mA units; or zero */
|
||||
unsigned mA_per_port; /* current for each child */
|
||||
|
||||
unsigned limited_power:1;
|
||||
unsigned quiescing:1;
|
||||
unsigned activating:1;
|
||||
unsigned resume_root_hub:1;
|
||||
|
@ -1387,6 +1387,12 @@ free_interfaces:
|
||||
if (dev->state != USB_STATE_ADDRESS)
|
||||
usb_disable_device (dev, 1); // Skip ep0
|
||||
|
||||
i = dev->bus_mA - cp->desc.bMaxPower * 2;
|
||||
if (i < 0)
|
||||
dev_warn(&dev->dev, "new config #%d exceeds power "
|
||||
"limit by %dmA\n",
|
||||
configuration, -i);
|
||||
|
||||
if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
|
||||
USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
|
||||
NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0)
|
||||
|
@ -32,7 +32,6 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
@ -47,165 +46,7 @@
|
||||
const char *usbcore_name = "usbcore";
|
||||
|
||||
static int nousb; /* Disable USB when built into kernel image */
|
||||
/* Not honored on modular build */
|
||||
|
||||
static DECLARE_RWSEM(usb_all_devices_rwsem);
|
||||
|
||||
|
||||
static int generic_probe (struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static int generic_remove (struct device *dev)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
|
||||
/* if this is only an unbind, not a physical disconnect, then
|
||||
* unconfigure the device */
|
||||
if (udev->state == USB_STATE_CONFIGURED)
|
||||
usb_set_configuration(udev, 0);
|
||||
|
||||
/* in case the call failed or the device was suspended */
|
||||
if (udev->state >= USB_STATE_CONFIGURED)
|
||||
usb_disable_device(udev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct device_driver usb_generic_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "usb",
|
||||
.bus = &usb_bus_type,
|
||||
.probe = generic_probe,
|
||||
.remove = generic_remove,
|
||||
};
|
||||
|
||||
static int usb_generic_driver_data;
|
||||
|
||||
/* called from driver core with usb_bus_type.subsys writelock */
|
||||
static int usb_probe_interface(struct device *dev)
|
||||
{
|
||||
struct usb_interface * intf = to_usb_interface(dev);
|
||||
struct usb_driver * driver = to_usb_driver(dev->driver);
|
||||
const struct usb_device_id *id;
|
||||
int error = -ENODEV;
|
||||
|
||||
dev_dbg(dev, "%s\n", __FUNCTION__);
|
||||
|
||||
if (!driver->probe)
|
||||
return error;
|
||||
/* FIXME we'd much prefer to just resume it ... */
|
||||
if (interface_to_usbdev(intf)->state == USB_STATE_SUSPENDED)
|
||||
return -EHOSTUNREACH;
|
||||
|
||||
id = usb_match_id (intf, driver->id_table);
|
||||
if (id) {
|
||||
dev_dbg (dev, "%s - got id\n", __FUNCTION__);
|
||||
|
||||
/* Interface "power state" doesn't correspond to any hardware
|
||||
* state whatsoever. We use it to record when it's bound to
|
||||
* a driver that may start I/0: it's not frozen/quiesced.
|
||||
*/
|
||||
mark_active(intf);
|
||||
intf->condition = USB_INTERFACE_BINDING;
|
||||
error = driver->probe (intf, id);
|
||||
if (error) {
|
||||
mark_quiesced(intf);
|
||||
intf->condition = USB_INTERFACE_UNBOUND;
|
||||
} else
|
||||
intf->condition = USB_INTERFACE_BOUND;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/* called from driver core with usb_bus_type.subsys writelock */
|
||||
static int usb_unbind_interface(struct device *dev)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(dev);
|
||||
struct usb_driver *driver = to_usb_driver(intf->dev.driver);
|
||||
|
||||
intf->condition = USB_INTERFACE_UNBINDING;
|
||||
|
||||
/* release all urbs for this interface */
|
||||
usb_disable_interface(interface_to_usbdev(intf), intf);
|
||||
|
||||
if (driver && driver->disconnect)
|
||||
driver->disconnect(intf);
|
||||
|
||||
/* reset other interface state */
|
||||
usb_set_interface(interface_to_usbdev(intf),
|
||||
intf->altsetting[0].desc.bInterfaceNumber,
|
||||
0);
|
||||
usb_set_intfdata(intf, NULL);
|
||||
intf->condition = USB_INTERFACE_UNBOUND;
|
||||
mark_quiesced(intf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_register - register a USB driver
|
||||
* @new_driver: USB operations for the driver
|
||||
*
|
||||
* Registers a USB driver with the USB core. The list of unattached
|
||||
* interfaces will be rescanned whenever a new driver is added, allowing
|
||||
* the new driver to attach to any recognized devices.
|
||||
* Returns a negative error code on failure and 0 on success.
|
||||
*
|
||||
* NOTE: if you want your driver to use the USB major number, you must call
|
||||
* usb_register_dev() to enable that functionality. This function no longer
|
||||
* takes care of that.
|
||||
*/
|
||||
int usb_register(struct usb_driver *new_driver)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
if (nousb)
|
||||
return -ENODEV;
|
||||
|
||||
new_driver->driver.name = (char *)new_driver->name;
|
||||
new_driver->driver.bus = &usb_bus_type;
|
||||
new_driver->driver.probe = usb_probe_interface;
|
||||
new_driver->driver.remove = usb_unbind_interface;
|
||||
new_driver->driver.owner = new_driver->owner;
|
||||
|
||||
usb_lock_all_devices();
|
||||
retval = driver_register(&new_driver->driver);
|
||||
usb_unlock_all_devices();
|
||||
|
||||
if (!retval) {
|
||||
pr_info("%s: registered new driver %s\n",
|
||||
usbcore_name, new_driver->name);
|
||||
usbfs_update_special();
|
||||
} else {
|
||||
printk(KERN_ERR "%s: error %d registering driver %s\n",
|
||||
usbcore_name, retval, new_driver->name);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_deregister - unregister a USB driver
|
||||
* @driver: USB operations of the driver to unregister
|
||||
* Context: must be able to sleep
|
||||
*
|
||||
* Unlinks the specified driver from the internal USB driver list.
|
||||
*
|
||||
* NOTE: If you called usb_register_dev(), you still need to call
|
||||
* usb_deregister_dev() to clean up your driver's allocated minor numbers,
|
||||
* this * call will no longer do it for you.
|
||||
*/
|
||||
void usb_deregister(struct usb_driver *driver)
|
||||
{
|
||||
pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name);
|
||||
|
||||
usb_lock_all_devices();
|
||||
driver_unregister (&driver->driver);
|
||||
usb_unlock_all_devices();
|
||||
|
||||
usbfs_update_special();
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_ifnum_to_if - get the interface object with a given interface number
|
||||
@ -351,152 +192,23 @@ void usb_driver_release_interface(struct usb_driver *driver,
|
||||
iface->condition = USB_INTERFACE_UNBOUND;
|
||||
mark_quiesced(iface);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_match_id - find first usb_device_id matching device or interface
|
||||
* @interface: the interface of interest
|
||||
* @id: array of usb_device_id structures, terminated by zero entry
|
||||
*
|
||||
* usb_match_id searches an array of usb_device_id's and returns
|
||||
* the first one matching the device or interface, or null.
|
||||
* This is used when binding (or rebinding) a driver to an interface.
|
||||
* Most USB device drivers will use this indirectly, through the usb core,
|
||||
* but some layered driver frameworks use it directly.
|
||||
* These device tables are exported with MODULE_DEVICE_TABLE, through
|
||||
* modutils and "modules.usbmap", to support the driver loading
|
||||
* functionality of USB hotplugging.
|
||||
*
|
||||
* What Matches:
|
||||
*
|
||||
* The "match_flags" element in a usb_device_id controls which
|
||||
* members are used. If the corresponding bit is set, the
|
||||
* value in the device_id must match its corresponding member
|
||||
* in the device or interface descriptor, or else the device_id
|
||||
* does not match.
|
||||
*
|
||||
* "driver_info" is normally used only by device drivers,
|
||||
* but you can create a wildcard "matches anything" usb_device_id
|
||||
* as a driver's "modules.usbmap" entry if you provide an id with
|
||||
* only a nonzero "driver_info" field. If you do this, the USB device
|
||||
* driver's probe() routine should use additional intelligence to
|
||||
* decide whether to bind to the specified interface.
|
||||
*
|
||||
* What Makes Good usb_device_id Tables:
|
||||
*
|
||||
* The match algorithm is very simple, so that intelligence in
|
||||
* driver selection must come from smart driver id records.
|
||||
* Unless you have good reasons to use another selection policy,
|
||||
* provide match elements only in related groups, and order match
|
||||
* specifiers from specific to general. Use the macros provided
|
||||
* for that purpose if you can.
|
||||
*
|
||||
* The most specific match specifiers use device descriptor
|
||||
* data. These are commonly used with product-specific matches;
|
||||
* the USB_DEVICE macro lets you provide vendor and product IDs,
|
||||
* and you can also match against ranges of product revisions.
|
||||
* These are widely used for devices with application or vendor
|
||||
* specific bDeviceClass values.
|
||||
*
|
||||
* Matches based on device class/subclass/protocol specifications
|
||||
* are slightly more general; use the USB_DEVICE_INFO macro, or
|
||||
* its siblings. These are used with single-function devices
|
||||
* where bDeviceClass doesn't specify that each interface has
|
||||
* its own class.
|
||||
*
|
||||
* Matches based on interface class/subclass/protocol are the
|
||||
* most general; they let drivers bind to any interface on a
|
||||
* multiple-function device. Use the USB_INTERFACE_INFO
|
||||
* macro, or its siblings, to match class-per-interface style
|
||||
* devices (as recorded in bDeviceClass).
|
||||
*
|
||||
* Within those groups, remember that not all combinations are
|
||||
* meaningful. For example, don't give a product version range
|
||||
* without vendor and product IDs; or specify a protocol without
|
||||
* its associated class and subclass.
|
||||
*/
|
||||
const struct usb_device_id *
|
||||
usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_host_interface *intf;
|
||||
struct usb_device *dev;
|
||||
|
||||
/* proc_connectinfo in devio.c may call us with id == NULL. */
|
||||
if (id == NULL)
|
||||
return NULL;
|
||||
|
||||
intf = interface->cur_altsetting;
|
||||
dev = interface_to_usbdev(interface);
|
||||
|
||||
/* It is important to check that id->driver_info is nonzero,
|
||||
since an entry that is all zeroes except for a nonzero
|
||||
id->driver_info is the way to create an entry that
|
||||
indicates that the driver want to examine every
|
||||
device and interface. */
|
||||
for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
|
||||
id->driver_info; id++) {
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
|
||||
id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
|
||||
continue;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
|
||||
id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
|
||||
continue;
|
||||
|
||||
/* No need to test id->bcdDevice_lo != 0, since 0 is never
|
||||
greater than any unsigned number. */
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
|
||||
(id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
|
||||
continue;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
|
||||
(id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
|
||||
continue;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
|
||||
(id->bDeviceClass != dev->descriptor.bDeviceClass))
|
||||
continue;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
|
||||
(id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
|
||||
continue;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
|
||||
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
|
||||
continue;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
|
||||
(id->bInterfaceClass != intf->desc.bInterfaceClass))
|
||||
continue;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
|
||||
(id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))
|
||||
continue;
|
||||
|
||||
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
|
||||
(id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
|
||||
continue;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct find_interface_arg {
|
||||
int minor;
|
||||
struct usb_interface *interface;
|
||||
};
|
||||
|
||||
static int __find_interface(struct device * dev, void * data)
|
||||
{
|
||||
struct usb_interface ** ret = (struct usb_interface **)data;
|
||||
struct usb_interface * intf = *ret;
|
||||
int *minor = (int *)data;
|
||||
struct find_interface_arg *arg = data;
|
||||
struct usb_interface *intf;
|
||||
|
||||
/* can't look at usb devices, only interfaces */
|
||||
if (dev->driver == &usb_generic_driver)
|
||||
return 0;
|
||||
|
||||
intf = to_usb_interface(dev);
|
||||
if (intf->minor != -1 && intf->minor == *minor) {
|
||||
*ret = intf;
|
||||
if (intf->minor != -1 && intf->minor == arg->minor) {
|
||||
arg->interface = intf;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
@ -513,35 +225,14 @@ static int __find_interface(struct device * dev, void * data)
|
||||
*/
|
||||
struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
|
||||
{
|
||||
struct usb_interface *intf = (struct usb_interface *)(long)minor;
|
||||
int ret;
|
||||
struct find_interface_arg argb;
|
||||
|
||||
ret = driver_for_each_device(&drv->driver, NULL, &intf, __find_interface);
|
||||
|
||||
return ret ? intf : NULL;
|
||||
argb.minor = minor;
|
||||
argb.interface = NULL;
|
||||
driver_for_each_device(&drv->driver, NULL, &argb, __find_interface);
|
||||
return argb.interface;
|
||||
}
|
||||
|
||||
static int usb_device_match (struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
struct usb_interface *intf;
|
||||
struct usb_driver *usb_drv;
|
||||
const struct usb_device_id *id;
|
||||
|
||||
/* check for generic driver, which we don't match any device with */
|
||||
if (drv == &usb_generic_driver)
|
||||
return 0;
|
||||
|
||||
intf = to_usb_interface(dev);
|
||||
usb_drv = to_usb_driver(drv);
|
||||
|
||||
id = usb_match_id (intf, usb_drv->id_table);
|
||||
if (id)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_HOTPLUG
|
||||
|
||||
/*
|
||||
@ -750,12 +441,11 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
|
||||
/* hub driver sets up TT records */
|
||||
}
|
||||
|
||||
dev->portnum = port1;
|
||||
dev->bus = bus;
|
||||
dev->parent = parent;
|
||||
INIT_LIST_HEAD(&dev->filelist);
|
||||
|
||||
init_MUTEX(&dev->serialize);
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
@ -828,75 +518,20 @@ void usb_put_intf(struct usb_interface *intf)
|
||||
|
||||
/* USB device locking
|
||||
*
|
||||
* Although locking USB devices should be straightforward, it is
|
||||
* complicated by the way the driver-model core works. When a new USB
|
||||
* driver is registered or unregistered, the core will automatically
|
||||
* probe or disconnect all matching interfaces on all USB devices while
|
||||
* holding the USB subsystem writelock. There's no good way for us to
|
||||
* tell which devices will be used or to lock them beforehand; our only
|
||||
* option is to effectively lock all the USB devices.
|
||||
*
|
||||
* We do that by using a private rw-semaphore, usb_all_devices_rwsem.
|
||||
* When locking an individual device you must first acquire the rwsem's
|
||||
* readlock. When a driver is registered or unregistered the writelock
|
||||
* must be held. These actions are encapsulated in the subroutines
|
||||
* below, so all a driver needs to do is call usb_lock_device() and
|
||||
* usb_unlock_device().
|
||||
* USB devices and interfaces are locked using the semaphore in their
|
||||
* embedded struct device. The hub driver guarantees that whenever a
|
||||
* device is connected or disconnected, drivers are called with the
|
||||
* USB device locked as well as their particular interface.
|
||||
*
|
||||
* Complications arise when several devices are to be locked at the same
|
||||
* time. Only hub-aware drivers that are part of usbcore ever have to
|
||||
* do this; nobody else needs to worry about it. The problem is that
|
||||
* usb_lock_device() must not be called to lock a second device since it
|
||||
* would acquire the rwsem's readlock reentrantly, leading to deadlock if
|
||||
* another thread was waiting for the writelock. The solution is simple:
|
||||
*
|
||||
* When locking more than one device, call usb_lock_device()
|
||||
* to lock the first one. Lock the others by calling
|
||||
* down(&udev->serialize) directly.
|
||||
*
|
||||
* When unlocking multiple devices, use up(&udev->serialize)
|
||||
* to unlock all but the last one. Unlock the last one by
|
||||
* calling usb_unlock_device().
|
||||
* do this; nobody else needs to worry about it. The rule for locking
|
||||
* is simple:
|
||||
*
|
||||
* When locking both a device and its parent, always lock the
|
||||
* the parent first.
|
||||
*/
|
||||
|
||||
/**
|
||||
* usb_lock_device - acquire the lock for a usb device structure
|
||||
* @udev: device that's being locked
|
||||
*
|
||||
* Use this routine when you don't hold any other device locks;
|
||||
* to acquire nested inner locks call down(&udev->serialize) directly.
|
||||
* This is necessary for proper interaction with usb_lock_all_devices().
|
||||
*/
|
||||
void usb_lock_device(struct usb_device *udev)
|
||||
{
|
||||
down_read(&usb_all_devices_rwsem);
|
||||
down(&udev->serialize);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_trylock_device - attempt to acquire the lock for a usb device structure
|
||||
* @udev: device that's being locked
|
||||
*
|
||||
* Don't use this routine if you already hold a device lock;
|
||||
* use down_trylock(&udev->serialize) instead.
|
||||
* This is necessary for proper interaction with usb_lock_all_devices().
|
||||
*
|
||||
* Returns 1 if successful, 0 if contention.
|
||||
*/
|
||||
int usb_trylock_device(struct usb_device *udev)
|
||||
{
|
||||
if (!down_read_trylock(&usb_all_devices_rwsem))
|
||||
return 0;
|
||||
if (down_trylock(&udev->serialize)) {
|
||||
up_read(&usb_all_devices_rwsem);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_lock_device_for_reset - cautiously acquire the lock for a
|
||||
* usb device structure
|
||||
@ -935,7 +570,7 @@ int usb_lock_device_for_reset(struct usb_device *udev,
|
||||
}
|
||||
}
|
||||
|
||||
while (!usb_trylock_device(udev)) {
|
||||
while (usb_trylock_device(udev) != 0) {
|
||||
|
||||
/* If we can't acquire the lock after waiting one second,
|
||||
* we're probably deadlocked */
|
||||
@ -953,39 +588,6 @@ int usb_lock_device_for_reset(struct usb_device *udev,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_unlock_device - release the lock for a usb device structure
|
||||
* @udev: device that's being unlocked
|
||||
*
|
||||
* Use this routine when releasing the only device lock you hold;
|
||||
* to release inner nested locks call up(&udev->serialize) directly.
|
||||
* This is necessary for proper interaction with usb_lock_all_devices().
|
||||
*/
|
||||
void usb_unlock_device(struct usb_device *udev)
|
||||
{
|
||||
up(&udev->serialize);
|
||||
up_read(&usb_all_devices_rwsem);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_lock_all_devices - acquire the lock for all usb device structures
|
||||
*
|
||||
* This is necessary when registering a new driver or probing a bus,
|
||||
* since the driver-model core may try to use any usb_device.
|
||||
*/
|
||||
void usb_lock_all_devices(void)
|
||||
{
|
||||
down_write(&usb_all_devices_rwsem);
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_unlock_all_devices - release the lock for all usb device structures
|
||||
*/
|
||||
void usb_unlock_all_devices(void)
|
||||
{
|
||||
up_write(&usb_all_devices_rwsem);
|
||||
}
|
||||
|
||||
|
||||
static struct usb_device *match_device(struct usb_device *dev,
|
||||
u16 vendor_id, u16 product_id)
|
||||
@ -1008,10 +610,10 @@ static struct usb_device *match_device(struct usb_device *dev,
|
||||
/* look through all of the children of this device */
|
||||
for (child = 0; child < dev->maxchild; ++child) {
|
||||
if (dev->children[child]) {
|
||||
down(&dev->children[child]->serialize);
|
||||
usb_lock_device(dev->children[child]);
|
||||
ret_dev = match_device(dev->children[child],
|
||||
vendor_id, product_id);
|
||||
up(&dev->children[child]->serialize);
|
||||
usb_unlock_device(dev->children[child]);
|
||||
if (ret_dev)
|
||||
goto exit;
|
||||
}
|
||||
@ -1496,18 +1098,8 @@ struct bus_type usb_bus_type = {
|
||||
.resume = usb_generic_resume,
|
||||
};
|
||||
|
||||
#ifndef MODULE
|
||||
|
||||
static int __init usb_setup_disable(char *str)
|
||||
{
|
||||
nousb = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* format to disable USB on kernel command line is: nousb */
|
||||
__setup("nousb", usb_setup_disable);
|
||||
|
||||
#endif
|
||||
__module_param_call("", nousb, param_set_bool, param_get_bool, &nousb, 0444);
|
||||
|
||||
/*
|
||||
* for external read access to <nousb>
|
||||
@ -1598,8 +1190,6 @@ module_exit(usb_exit);
|
||||
* driver modules to use.
|
||||
*/
|
||||
|
||||
EXPORT_SYMBOL(usb_register);
|
||||
EXPORT_SYMBOL(usb_deregister);
|
||||
EXPORT_SYMBOL(usb_disabled);
|
||||
|
||||
EXPORT_SYMBOL_GPL(usb_get_intf);
|
||||
@ -1610,14 +1200,10 @@ EXPORT_SYMBOL(usb_put_dev);
|
||||
EXPORT_SYMBOL(usb_get_dev);
|
||||
EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
|
||||
|
||||
EXPORT_SYMBOL(usb_lock_device);
|
||||
EXPORT_SYMBOL(usb_trylock_device);
|
||||
EXPORT_SYMBOL(usb_lock_device_for_reset);
|
||||
EXPORT_SYMBOL(usb_unlock_device);
|
||||
|
||||
EXPORT_SYMBOL(usb_driver_claim_interface);
|
||||
EXPORT_SYMBOL(usb_driver_release_interface);
|
||||
EXPORT_SYMBOL(usb_match_id);
|
||||
EXPORT_SYMBOL(usb_find_interface);
|
||||
EXPORT_SYMBOL(usb_ifnum_to_if);
|
||||
EXPORT_SYMBOL(usb_altnum_to_altsetting);
|
||||
|
@ -16,9 +16,6 @@ extern int usb_get_device_descriptor(struct usb_device *dev,
|
||||
extern char *usb_cache_string(struct usb_device *udev, int index);
|
||||
extern int usb_set_configuration(struct usb_device *dev, int configuration);
|
||||
|
||||
extern void usb_lock_all_devices(void);
|
||||
extern void usb_unlock_all_devices(void);
|
||||
|
||||
extern void usb_kick_khubd(struct usb_device *dev);
|
||||
extern void usb_suspend_root_hub(struct usb_device *hdev);
|
||||
extern void usb_resume_root_hub(struct usb_device *dev);
|
||||
@ -33,6 +30,9 @@ extern void usb_host_cleanup(void);
|
||||
extern int usb_suspend_device(struct usb_device *dev);
|
||||
extern int usb_resume_device(struct usb_device *dev);
|
||||
|
||||
extern struct device_driver usb_generic_driver;
|
||||
extern int usb_generic_driver_data;
|
||||
extern int usb_device_match(struct device *dev, struct device_driver *drv);
|
||||
|
||||
/* Interfaces and their "power state" are owned by usbcore */
|
||||
|
||||
|
@ -138,7 +138,7 @@ static const char *const ep_name [] = {
|
||||
/* or like sa1100: two fixed function endpoints */
|
||||
"ep1out-bulk", "ep2in-bulk",
|
||||
};
|
||||
#define DUMMY_ENDPOINTS (sizeof(ep_name)/sizeof(char *))
|
||||
#define DUMMY_ENDPOINTS ARRAY_SIZE(ep_name)
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
@ -896,7 +896,7 @@ dummy_gadget_release (struct device *dev)
|
||||
#endif
|
||||
}
|
||||
|
||||
static int dummy_udc_probe (struct platform_device *dev)
|
||||
static int dummy_udc_probe (struct platform_device *pdev)
|
||||
{
|
||||
struct dummy *dum = the_controller;
|
||||
int rc;
|
||||
@ -909,7 +909,7 @@ static int dummy_udc_probe (struct platform_device *dev)
|
||||
dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
|
||||
|
||||
strcpy (dum->gadget.dev.bus_id, "gadget");
|
||||
dum->gadget.dev.parent = &dev->dev;
|
||||
dum->gadget.dev.parent = &pdev->dev;
|
||||
dum->gadget.dev.release = dummy_gadget_release;
|
||||
rc = device_register (&dum->gadget.dev);
|
||||
if (rc < 0)
|
||||
@ -919,47 +919,47 @@ static int dummy_udc_probe (struct platform_device *dev)
|
||||
usb_bus_get (&dummy_to_hcd (dum)->self);
|
||||
#endif
|
||||
|
||||
platform_set_drvdata (dev, dum);
|
||||
platform_set_drvdata (pdev, dum);
|
||||
device_create_file (&dum->gadget.dev, &dev_attr_function);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dummy_udc_remove (struct platform_device *dev)
|
||||
static int dummy_udc_remove (struct platform_device *pdev)
|
||||
{
|
||||
struct dummy *dum = platform_get_drvdata (dev);
|
||||
struct dummy *dum = platform_get_drvdata (pdev);
|
||||
|
||||
platform_set_drvdata (dev, NULL);
|
||||
platform_set_drvdata (pdev, NULL);
|
||||
device_remove_file (&dum->gadget.dev, &dev_attr_function);
|
||||
device_unregister (&dum->gadget.dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dummy_udc_suspend (struct platform_device *dev, pm_message_t state)
|
||||
static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct dummy *dum = platform_get_drvdata(dev);
|
||||
struct dummy *dum = platform_get_drvdata(pdev);
|
||||
|
||||
dev_dbg (&dev->dev, "%s\n", __FUNCTION__);
|
||||
dev_dbg (&pdev->dev, "%s\n", __FUNCTION__);
|
||||
spin_lock_irq (&dum->lock);
|
||||
dum->udc_suspended = 1;
|
||||
set_link_state (dum);
|
||||
spin_unlock_irq (&dum->lock);
|
||||
|
||||
dev->dev.power.power_state = state;
|
||||
pdev->dev.power.power_state = state;
|
||||
usb_hcd_poll_rh_status (dummy_to_hcd (dum));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dummy_udc_resume (struct platform_device *dev)
|
||||
static int dummy_udc_resume (struct platform_device *pdev)
|
||||
{
|
||||
struct dummy *dum = platform_get_drvdata(dev);
|
||||
struct dummy *dum = platform_get_drvdata(pdev);
|
||||
|
||||
dev_dbg (&dev->dev, "%s\n", __FUNCTION__);
|
||||
dev_dbg (&pdev->dev, "%s\n", __FUNCTION__);
|
||||
spin_lock_irq (&dum->lock);
|
||||
dum->udc_suspended = 0;
|
||||
set_link_state (dum);
|
||||
spin_unlock_irq (&dum->lock);
|
||||
|
||||
dev->dev.power.power_state = PMSG_ON;
|
||||
pdev->dev.power.power_state = PMSG_ON;
|
||||
usb_hcd_poll_rh_status (dummy_to_hcd (dum));
|
||||
return 0;
|
||||
}
|
||||
@ -1576,7 +1576,7 @@ static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
|
||||
dum = hcd_to_dummy (hcd);
|
||||
|
||||
spin_lock_irqsave (&dum->lock, flags);
|
||||
if (hcd->state != HC_STATE_RUNNING)
|
||||
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
|
||||
goto done;
|
||||
|
||||
if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) {
|
||||
@ -1623,7 +1623,7 @@ static int dummy_hub_control (
|
||||
int retval = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (hcd->state != HC_STATE_RUNNING)
|
||||
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
dum = hcd_to_dummy (hcd);
|
||||
@ -1756,9 +1756,12 @@ static int dummy_bus_suspend (struct usb_hcd *hcd)
|
||||
{
|
||||
struct dummy *dum = hcd_to_dummy (hcd);
|
||||
|
||||
dev_dbg (&hcd->self.root_hub->dev, "%s\n", __FUNCTION__);
|
||||
|
||||
spin_lock_irq (&dum->lock);
|
||||
dum->rh_state = DUMMY_RH_SUSPENDED;
|
||||
set_link_state (dum);
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
spin_unlock_irq (&dum->lock);
|
||||
return 0;
|
||||
}
|
||||
@ -1766,14 +1769,23 @@ static int dummy_bus_suspend (struct usb_hcd *hcd)
|
||||
static int dummy_bus_resume (struct usb_hcd *hcd)
|
||||
{
|
||||
struct dummy *dum = hcd_to_dummy (hcd);
|
||||
int rc = 0;
|
||||
|
||||
dev_dbg (&hcd->self.root_hub->dev, "%s\n", __FUNCTION__);
|
||||
|
||||
spin_lock_irq (&dum->lock);
|
||||
dum->rh_state = DUMMY_RH_RUNNING;
|
||||
set_link_state (dum);
|
||||
if (!list_empty(&dum->urbp_list))
|
||||
mod_timer (&dum->timer, jiffies);
|
||||
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
|
||||
dev_warn (&hcd->self.root_hub->dev, "HC isn't running!\n");
|
||||
rc = -ENODEV;
|
||||
} else {
|
||||
dum->rh_state = DUMMY_RH_RUNNING;
|
||||
set_link_state (dum);
|
||||
if (!list_empty(&dum->urbp_list))
|
||||
mod_timer (&dum->timer, jiffies);
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
}
|
||||
spin_unlock_irq (&dum->lock);
|
||||
return 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
@ -1899,14 +1911,14 @@ static const struct hc_driver dummy_hcd = {
|
||||
.bus_resume = dummy_bus_resume,
|
||||
};
|
||||
|
||||
static int dummy_hcd_probe (struct platform_device *dev)
|
||||
static int dummy_hcd_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
int retval;
|
||||
|
||||
dev_info(&dev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
|
||||
dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
|
||||
|
||||
hcd = usb_create_hcd (&dummy_hcd, &dev->dev, dev->dev.bus_id);
|
||||
hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, pdev->dev.bus_id);
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
the_controller = hcd_to_dummy (hcd);
|
||||
@ -1919,36 +1931,43 @@ static int dummy_hcd_probe (struct platform_device *dev)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int dummy_hcd_remove (struct platform_device *dev)
|
||||
static int dummy_hcd_remove (struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
hcd = platform_get_drvdata (dev);
|
||||
hcd = platform_get_drvdata (pdev);
|
||||
usb_remove_hcd (hcd);
|
||||
usb_put_hcd (hcd);
|
||||
the_controller = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dummy_hcd_suspend (struct platform_device *dev, pm_message_t state)
|
||||
static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct dummy *dum;
|
||||
int rc = 0;
|
||||
|
||||
dev_dbg (&dev->dev, "%s\n", __FUNCTION__);
|
||||
hcd = platform_get_drvdata (dev);
|
||||
dev_dbg (&pdev->dev, "%s\n", __FUNCTION__);
|
||||
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
return 0;
|
||||
hcd = platform_get_drvdata (pdev);
|
||||
dum = hcd_to_dummy (hcd);
|
||||
if (dum->rh_state == DUMMY_RH_RUNNING) {
|
||||
dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
|
||||
rc = -EBUSY;
|
||||
} else
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dummy_hcd_resume (struct platform_device *dev)
|
||||
static int dummy_hcd_resume (struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
|
||||
dev_dbg (&dev->dev, "%s\n", __FUNCTION__);
|
||||
hcd = platform_get_drvdata (dev);
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
dev_dbg (&pdev->dev, "%s\n", __FUNCTION__);
|
||||
|
||||
hcd = platform_get_drvdata (pdev);
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
usb_hcd_poll_rh_status (hcd);
|
||||
return 0;
|
||||
}
|
||||
|
@ -224,6 +224,7 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/limits.h>
|
||||
#include <linux/list.h>
|
||||
@ -238,7 +239,6 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include <linux/usb_ch9.h>
|
||||
#include <linux/usb_gadget.h>
|
||||
@ -250,7 +250,7 @@
|
||||
|
||||
#define DRIVER_DESC "File-backed Storage Gadget"
|
||||
#define DRIVER_NAME "g_file_storage"
|
||||
#define DRIVER_VERSION "20 October 2004"
|
||||
#define DRIVER_VERSION "28 November 2005"
|
||||
|
||||
static const char longname[] = DRIVER_DESC;
|
||||
static const char shortname[] = DRIVER_NAME;
|
||||
@ -335,8 +335,8 @@ MODULE_LICENSE("Dual BSD/GPL");
|
||||
#define MAX_LUNS 8
|
||||
|
||||
/* Arggh! There should be a module_param_array_named macro! */
|
||||
static char *file[MAX_LUNS] = {NULL, };
|
||||
static int ro[MAX_LUNS] = {0, };
|
||||
static char *file[MAX_LUNS];
|
||||
static int ro[MAX_LUNS];
|
||||
|
||||
static struct {
|
||||
int num_filenames;
|
||||
@ -587,7 +587,7 @@ enum fsg_buffer_state {
|
||||
struct fsg_buffhd {
|
||||
void *buf;
|
||||
dma_addr_t dma;
|
||||
volatile enum fsg_buffer_state state;
|
||||
enum fsg_buffer_state state;
|
||||
struct fsg_buffhd *next;
|
||||
|
||||
/* The NetChip 2280 is faster, and handles some protocol faults
|
||||
@ -596,9 +596,9 @@ struct fsg_buffhd {
|
||||
unsigned int bulk_out_intended_length;
|
||||
|
||||
struct usb_request *inreq;
|
||||
volatile int inreq_busy;
|
||||
int inreq_busy;
|
||||
struct usb_request *outreq;
|
||||
volatile int outreq_busy;
|
||||
int outreq_busy;
|
||||
};
|
||||
|
||||
enum fsg_state {
|
||||
@ -631,13 +631,16 @@ struct fsg_dev {
|
||||
/* filesem protects: backing files in use */
|
||||
struct rw_semaphore filesem;
|
||||
|
||||
/* reference counting: wait until all LUNs are released */
|
||||
struct kref ref;
|
||||
|
||||
struct usb_ep *ep0; // Handy copy of gadget->ep0
|
||||
struct usb_request *ep0req; // For control responses
|
||||
volatile unsigned int ep0_req_tag;
|
||||
unsigned int ep0_req_tag;
|
||||
const char *ep0req_name;
|
||||
|
||||
struct usb_request *intreq; // For interrupt responses
|
||||
volatile int intreq_busy;
|
||||
int intreq_busy;
|
||||
struct fsg_buffhd *intr_buffhd;
|
||||
|
||||
unsigned int bulk_out_maxpacket;
|
||||
@ -667,7 +670,6 @@ struct fsg_dev {
|
||||
struct fsg_buffhd *next_buffhd_to_drain;
|
||||
struct fsg_buffhd buffhds[NUM_BUFFERS];
|
||||
|
||||
wait_queue_head_t thread_wqh;
|
||||
int thread_wakeup_needed;
|
||||
struct completion thread_notifier;
|
||||
struct task_struct *thread_task;
|
||||
@ -694,7 +696,6 @@ struct fsg_dev {
|
||||
unsigned int nluns;
|
||||
struct lun *luns;
|
||||
struct lun *curlun;
|
||||
struct completion lun_released;
|
||||
};
|
||||
|
||||
typedef void (*fsg_routine_t)(struct fsg_dev *);
|
||||
@ -1073,11 +1074,13 @@ static int populate_config_buf(struct usb_gadget *gadget,
|
||||
|
||||
/* These routines may be called in process context or in_irq */
|
||||
|
||||
/* Caller must hold fsg->lock */
|
||||
static void wakeup_thread(struct fsg_dev *fsg)
|
||||
{
|
||||
/* Tell the main thread that something has happened */
|
||||
fsg->thread_wakeup_needed = 1;
|
||||
wake_up_all(&fsg->thread_wqh);
|
||||
if (fsg->thread_task)
|
||||
wake_up_process(fsg->thread_task);
|
||||
}
|
||||
|
||||
|
||||
@ -1164,11 +1167,12 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
usb_ep_fifo_flush(ep);
|
||||
|
||||
/* Hold the lock while we update the request and buffer states */
|
||||
smp_wmb();
|
||||
spin_lock(&fsg->lock);
|
||||
bh->inreq_busy = 0;
|
||||
bh->state = BUF_STATE_EMPTY;
|
||||
spin_unlock(&fsg->lock);
|
||||
wakeup_thread(fsg);
|
||||
spin_unlock(&fsg->lock);
|
||||
}
|
||||
|
||||
static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
@ -1185,11 +1189,12 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
usb_ep_fifo_flush(ep);
|
||||
|
||||
/* Hold the lock while we update the request and buffer states */
|
||||
smp_wmb();
|
||||
spin_lock(&fsg->lock);
|
||||
bh->outreq_busy = 0;
|
||||
bh->state = BUF_STATE_FULL;
|
||||
spin_unlock(&fsg->lock);
|
||||
wakeup_thread(fsg);
|
||||
spin_unlock(&fsg->lock);
|
||||
}
|
||||
|
||||
|
||||
@ -1206,11 +1211,12 @@ static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
|
||||
usb_ep_fifo_flush(ep);
|
||||
|
||||
/* Hold the lock while we update the request and buffer states */
|
||||
smp_wmb();
|
||||
spin_lock(&fsg->lock);
|
||||
fsg->intreq_busy = 0;
|
||||
bh->state = BUF_STATE_EMPTY;
|
||||
spin_unlock(&fsg->lock);
|
||||
wakeup_thread(fsg);
|
||||
spin_unlock(&fsg->lock);
|
||||
}
|
||||
|
||||
#else
|
||||
@ -1261,8 +1267,8 @@ static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
||||
fsg->cbbuf_cmnd_size = req->actual;
|
||||
memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size);
|
||||
|
||||
spin_unlock(&fsg->lock);
|
||||
wakeup_thread(fsg);
|
||||
spin_unlock(&fsg->lock);
|
||||
}
|
||||
|
||||
#else
|
||||
@ -1514,8 +1520,8 @@ static int fsg_setup(struct usb_gadget *gadget,
|
||||
|
||||
/* Use this for bulk or interrupt transfers, not ep0 */
|
||||
static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
|
||||
struct usb_request *req, volatile int *pbusy,
|
||||
volatile enum fsg_buffer_state *state)
|
||||
struct usb_request *req, int *pbusy,
|
||||
enum fsg_buffer_state *state)
|
||||
{
|
||||
int rc;
|
||||
|
||||
@ -1523,8 +1529,11 @@ static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
|
||||
dump_msg(fsg, "bulk-in", req->buf, req->length);
|
||||
else if (ep == fsg->intr_in)
|
||||
dump_msg(fsg, "intr-in", req->buf, req->length);
|
||||
|
||||
spin_lock_irq(&fsg->lock);
|
||||
*pbusy = 1;
|
||||
*state = BUF_STATE_BUSY;
|
||||
spin_unlock_irq(&fsg->lock);
|
||||
rc = usb_ep_queue(ep, req, GFP_KERNEL);
|
||||
if (rc != 0) {
|
||||
*pbusy = 0;
|
||||
@ -1544,14 +1553,23 @@ static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep,
|
||||
|
||||
static int sleep_thread(struct fsg_dev *fsg)
|
||||
{
|
||||
int rc;
|
||||
int rc = 0;
|
||||
|
||||
/* Wait until a signal arrives or we are woken up */
|
||||
rc = wait_event_interruptible(fsg->thread_wqh,
|
||||
fsg->thread_wakeup_needed);
|
||||
for (;;) {
|
||||
try_to_freeze();
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (signal_pending(current)) {
|
||||
rc = -EINTR;
|
||||
break;
|
||||
}
|
||||
if (fsg->thread_wakeup_needed)
|
||||
break;
|
||||
schedule();
|
||||
}
|
||||
__set_current_state(TASK_RUNNING);
|
||||
fsg->thread_wakeup_needed = 0;
|
||||
try_to_freeze();
|
||||
return (rc ? -EINTR : 0);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@ -1788,6 +1806,7 @@ static int do_write(struct fsg_dev *fsg)
|
||||
if (bh->state == BUF_STATE_EMPTY && !get_some_more)
|
||||
break; // We stopped early
|
||||
if (bh->state == BUF_STATE_FULL) {
|
||||
smp_rmb();
|
||||
fsg->next_buffhd_to_drain = bh->next;
|
||||
bh->state = BUF_STATE_EMPTY;
|
||||
|
||||
@ -2356,6 +2375,7 @@ static int throw_away_data(struct fsg_dev *fsg)
|
||||
|
||||
/* Throw away the data in a filled buffer */
|
||||
if (bh->state == BUF_STATE_FULL) {
|
||||
smp_rmb();
|
||||
bh->state = BUF_STATE_EMPTY;
|
||||
fsg->next_buffhd_to_drain = bh->next;
|
||||
|
||||
@ -3021,6 +3041,7 @@ static int get_next_command(struct fsg_dev *fsg)
|
||||
if ((rc = sleep_thread(fsg)) != 0)
|
||||
return rc;
|
||||
}
|
||||
smp_rmb();
|
||||
rc = received_cbw(fsg, bh);
|
||||
bh->state = BUF_STATE_EMPTY;
|
||||
|
||||
@ -3642,11 +3663,19 @@ static DEVICE_ATTR(file, 0444, show_file, NULL);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void fsg_release(struct kref *ref)
|
||||
{
|
||||
struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref);
|
||||
|
||||
kfree(fsg->luns);
|
||||
kfree(fsg);
|
||||
}
|
||||
|
||||
static void lun_release(struct device *dev)
|
||||
{
|
||||
struct fsg_dev *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
|
||||
|
||||
complete(&fsg->lun_released);
|
||||
kref_put(&fsg->ref, fsg_release);
|
||||
}
|
||||
|
||||
static void fsg_unbind(struct usb_gadget *gadget)
|
||||
@ -3660,14 +3689,12 @@ static void fsg_unbind(struct usb_gadget *gadget)
|
||||
clear_bit(REGISTERED, &fsg->atomic_bitflags);
|
||||
|
||||
/* Unregister the sysfs attribute files and the LUNs */
|
||||
init_completion(&fsg->lun_released);
|
||||
for (i = 0; i < fsg->nluns; ++i) {
|
||||
curlun = &fsg->luns[i];
|
||||
if (curlun->registered) {
|
||||
device_remove_file(&curlun->dev, &dev_attr_ro);
|
||||
device_remove_file(&curlun->dev, &dev_attr_file);
|
||||
device_unregister(&curlun->dev);
|
||||
wait_for_completion(&fsg->lun_released);
|
||||
curlun->registered = 0;
|
||||
}
|
||||
}
|
||||
@ -3846,6 +3873,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
|
||||
curlun->dev.release = lun_release;
|
||||
device_create_file(&curlun->dev, &dev_attr_ro);
|
||||
device_create_file(&curlun->dev, &dev_attr_file);
|
||||
kref_get(&fsg->ref);
|
||||
}
|
||||
|
||||
if (file[i] && *file[i]) {
|
||||
@ -4061,7 +4089,7 @@ static int __init fsg_alloc(void)
|
||||
return -ENOMEM;
|
||||
spin_lock_init(&fsg->lock);
|
||||
init_rwsem(&fsg->filesem);
|
||||
init_waitqueue_head(&fsg->thread_wqh);
|
||||
kref_init(&fsg->ref);
|
||||
init_completion(&fsg->thread_notifier);
|
||||
|
||||
the_fsg = fsg;
|
||||
@ -4069,13 +4097,6 @@ static int __init fsg_alloc(void)
|
||||
}
|
||||
|
||||
|
||||
static void fsg_free(struct fsg_dev *fsg)
|
||||
{
|
||||
kfree(fsg->luns);
|
||||
kfree(fsg);
|
||||
}
|
||||
|
||||
|
||||
static int __init fsg_init(void)
|
||||
{
|
||||
int rc;
|
||||
@ -4085,7 +4106,7 @@ static int __init fsg_init(void)
|
||||
return rc;
|
||||
fsg = the_fsg;
|
||||
if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0)
|
||||
fsg_free(fsg);
|
||||
kref_put(&fsg->ref, fsg_release);
|
||||
return rc;
|
||||
}
|
||||
module_init(fsg_init);
|
||||
@ -4103,6 +4124,6 @@ static void __exit fsg_cleanup(void)
|
||||
wait_for_completion(&fsg->thread_notifier);
|
||||
|
||||
close_all_backing_files(fsg);
|
||||
fsg_free(fsg);
|
||||
kref_put(&fsg->ref, fsg_release);
|
||||
}
|
||||
module_exit(fsg_cleanup);
|
||||
|
@ -890,10 +890,12 @@ static void gs_close(struct tty_struct *tty, struct file *file)
|
||||
/* wait for write buffer to drain, or */
|
||||
/* at most GS_CLOSE_TIMEOUT seconds */
|
||||
if (gs_buf_data_avail(port->port_write_buf) > 0) {
|
||||
spin_unlock_irqrestore(&port->port_lock, flags);
|
||||
wait_cond_interruptible_timeout(port->port_write_wait,
|
||||
port->port_dev == NULL
|
||||
|| gs_buf_data_avail(port->port_write_buf) == 0,
|
||||
&port->port_lock, flags, GS_CLOSE_TIMEOUT * HZ);
|
||||
spin_lock_irqsave(&port->port_lock, flags);
|
||||
}
|
||||
|
||||
/* free disconnected port on final close */
|
||||
|
@ -2,6 +2,10 @@
|
||||
# Makefile for USB Host Controller Drivers
|
||||
#
|
||||
|
||||
ifeq ($(CONFIG_USB_DEBUG),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_PCI) += pci-quirks.o
|
||||
|
||||
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
|
||||
|
@ -17,13 +17,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
|
||||
#ifdef CONFIG_USB_DEBUG
|
||||
#define DEBUG
|
||||
#else
|
||||
#undef DEBUG
|
||||
#endif
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/dmapool.h>
|
||||
@ -624,7 +617,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
|
||||
}
|
||||
|
||||
/* remote wakeup [4.3.1] */
|
||||
if ((status & STS_PCD) && hcd->remote_wakeup) {
|
||||
if (status & STS_PCD) {
|
||||
unsigned i = HCS_N_PORTS (ehci->hcs_params);
|
||||
|
||||
/* resume root hub? */
|
||||
|
@ -59,7 +59,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
|
||||
|
||||
if ((t1 & PORT_PE) && !(t1 & PORT_OWNER))
|
||||
t2 |= PORT_SUSPEND;
|
||||
if (hcd->remote_wakeup)
|
||||
if (device_may_wakeup(&hcd->self.root_hub->dev))
|
||||
t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E;
|
||||
else
|
||||
t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
|
||||
@ -517,7 +517,7 @@ static int ehci_hub_control (
|
||||
if ((temp & PORT_PE) == 0
|
||||
|| (temp & PORT_RESET) != 0)
|
||||
goto error;
|
||||
if (hcd->remote_wakeup)
|
||||
if (device_may_wakeup(&hcd->self.root_hub->dev))
|
||||
temp |= PORT_WAKE_BITS;
|
||||
writel (temp | PORT_SUSPEND,
|
||||
&ehci->regs->port_status [wIndex]);
|
||||
|
@ -210,7 +210,16 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
|
||||
/* Serial Bus Release Number is at PCI 0x60 offset */
|
||||
pci_read_config_byte(pdev, 0x60, &ehci->sbrn);
|
||||
|
||||
/* REVISIT: per-port wake capability (PCI 0x62) currently unused */
|
||||
/* Workaround current PCI init glitch: wakeup bits aren't
|
||||
* being set from PCI PM capability.
|
||||
*/
|
||||
if (!device_can_wakeup(&pdev->dev)) {
|
||||
u16 port_wake;
|
||||
|
||||
pci_read_config_word(pdev, 0x62, &port_wake);
|
||||
if (port_wake & 0x0001)
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
}
|
||||
|
||||
retval = ehci_pci_reinit(ehci, pdev);
|
||||
done:
|
||||
@ -269,7 +278,6 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
unsigned port;
|
||||
struct usb_device *root = hcd->self.root_hub;
|
||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
int retval = -EINVAL;
|
||||
|
||||
@ -303,13 +311,7 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
|
||||
|
||||
restart:
|
||||
ehci_dbg(ehci, "lost power, restarting\n");
|
||||
for (port = HCS_N_PORTS(ehci->hcs_params); port > 0; ) {
|
||||
port--;
|
||||
if (!root->children [port])
|
||||
continue;
|
||||
usb_set_device_state(root->children[port],
|
||||
USB_STATE_NOTATTACHED);
|
||||
}
|
||||
usb_root_hub_lost_power(hcd->self.root_hub);
|
||||
|
||||
/* Else reset, to cope with power loss or flush-to-storage
|
||||
* style "resume" having let BIOS kick in during reboot.
|
||||
|
@ -514,18 +514,18 @@ qh_urb_transaction (
|
||||
qtd->urb = urb;
|
||||
qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
|
||||
list_add_tail (&qtd->qtd_list, head);
|
||||
|
||||
/* for zero length DATA stages, STATUS is always IN */
|
||||
if (len == 0)
|
||||
token |= (1 /* "in" */ << 8);
|
||||
}
|
||||
|
||||
/*
|
||||
* data transfer stage: buffer setup
|
||||
*/
|
||||
if (likely (len > 0))
|
||||
buf = urb->transfer_dma;
|
||||
else
|
||||
buf = 0;
|
||||
buf = urb->transfer_dma;
|
||||
|
||||
/* for zero length DATA stages, STATUS is always IN */
|
||||
if (!buf || is_input)
|
||||
if (is_input)
|
||||
token |= (1 /* "in" */ << 8);
|
||||
/* else it's already initted to "out" pid (0 << 8) */
|
||||
|
||||
@ -572,7 +572,7 @@ qh_urb_transaction (
|
||||
* control requests may need a terminating data "status" ack;
|
||||
* bulk ones may need a terminating short packet (zero length).
|
||||
*/
|
||||
if (likely (buf != 0)) {
|
||||
if (likely (urb->transfer_buffer_length != 0)) {
|
||||
int one_more = 0;
|
||||
|
||||
if (usb_pipecontrol (urb->pipe)) {
|
||||
|
@ -55,19 +55,13 @@
|
||||
/* enqueuing/finishing log of urbs */
|
||||
//#define URB_TRACE
|
||||
|
||||
#include <linux/config.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/smp_lock.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb_isp116x.h>
|
||||
#include <linux/platform_device.h>
|
||||
@ -77,14 +71,10 @@
|
||||
#include <asm/system.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
#ifndef DEBUG
|
||||
# define STUB_DEBUG_FILE
|
||||
#endif
|
||||
|
||||
#include "../core/hcd.h"
|
||||
#include "isp116x.h"
|
||||
|
||||
#define DRIVER_VERSION "05 Aug 2005"
|
||||
#define DRIVER_VERSION "03 Nov 2005"
|
||||
#define DRIVER_DESC "ISP116x USB Host Controller Driver"
|
||||
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
@ -164,13 +154,11 @@ static void pack_fifo(struct isp116x *isp116x)
|
||||
struct ptd *ptd;
|
||||
int buflen = isp116x->atl_last_dir == PTD_DIR_IN
|
||||
? isp116x->atl_bufshrt : isp116x->atl_buflen;
|
||||
int ptd_count = 0;
|
||||
|
||||
isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
|
||||
isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
|
||||
isp116x_write_addr(isp116x, HCATLPORT | ISP116x_WRITE_OFFSET);
|
||||
for (ep = isp116x->atl_active; ep; ep = ep->active) {
|
||||
++ptd_count;
|
||||
ptd = &ep->ptd;
|
||||
dump_ptd(ptd);
|
||||
dump_ptd_out_data(ptd, ep->data);
|
||||
@ -305,9 +293,8 @@ static void postproc_atl_queue(struct isp116x *isp116x)
|
||||
udev = urb->dev;
|
||||
ptd = &ep->ptd;
|
||||
cc = PTD_GET_CC(ptd);
|
||||
|
||||
spin_lock(&urb->lock);
|
||||
short_not_ok = 1;
|
||||
spin_lock(&urb->lock);
|
||||
|
||||
/* Data underrun is special. For allowed underrun
|
||||
we clear the error and continue as normal. For
|
||||
@ -420,7 +407,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
|
||||
ep->nextpid = 0;
|
||||
break;
|
||||
default:
|
||||
BUG_ON(1);
|
||||
BUG();
|
||||
}
|
||||
spin_unlock(&urb->lock);
|
||||
}
|
||||
@ -628,8 +615,12 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs)
|
||||
u32 intstat = isp116x_read_reg32(isp116x, HCINTSTAT);
|
||||
isp116x_write_reg32(isp116x, HCINTSTAT, intstat);
|
||||
if (intstat & HCINT_UE) {
|
||||
ERR("Unrecoverable error\n");
|
||||
/* What should we do here? Reset? */
|
||||
ERR("Unrecoverable error, HC is dead!\n");
|
||||
/* IRQ's are off, we do no DMA,
|
||||
perfectly ready to die ... */
|
||||
hcd->state = HC_STATE_HALT;
|
||||
ret = IRQ_HANDLED;
|
||||
goto done;
|
||||
}
|
||||
if (intstat & HCINT_RHSC)
|
||||
/* When root hub or any of its ports is going
|
||||
@ -640,7 +631,6 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs)
|
||||
if (intstat & HCINT_RD) {
|
||||
DBG("---- remote wakeup\n");
|
||||
usb_hcd_resume_root_hub(hcd);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
irqstat &= ~HCuPINT_OPR;
|
||||
ret = IRQ_HANDLED;
|
||||
@ -651,6 +641,7 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs)
|
||||
}
|
||||
|
||||
isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb);
|
||||
done:
|
||||
spin_unlock(&isp116x->lock);
|
||||
return ret;
|
||||
}
|
||||
@ -724,6 +715,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
|
||||
|
||||
spin_lock_irqsave(&isp116x->lock, flags);
|
||||
if (!HC_IS_RUNNING(hcd->state)) {
|
||||
kfree(ep);
|
||||
ret = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
@ -888,7 +880,7 @@ static void isp116x_endpoint_disable(struct usb_hcd *hcd,
|
||||
struct usb_host_endpoint *hep)
|
||||
{
|
||||
int i;
|
||||
struct isp116x_ep *ep = hep->hcpriv;;
|
||||
struct isp116x_ep *ep = hep->hcpriv;
|
||||
|
||||
if (!ep)
|
||||
return;
|
||||
@ -916,8 +908,6 @@ static int isp116x_get_frame(struct usb_hcd *hcd)
|
||||
return (int)fmnum;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Adapted from ohci-hub.c. Currently we don't support autosuspend.
|
||||
*/
|
||||
@ -968,11 +958,10 @@ static void isp116x_hub_descriptor(struct isp116x *isp116x,
|
||||
desc->bHubContrCurrent = 0;
|
||||
desc->bNbrPorts = (u8) (reg & 0x3);
|
||||
/* Power switching, device type, overcurrent. */
|
||||
desc->wHubCharacteristics =
|
||||
(__force __u16) cpu_to_le16((u16) ((reg >> 8) & 0x1f));
|
||||
desc->wHubCharacteristics = cpu_to_le16((u16) ((reg >> 8) & 0x1f));
|
||||
desc->bPwrOn2PwrGood = (u8) ((reg >> 24) & 0xff);
|
||||
/* two bitmaps: ports removable, and legacy PortPwrCtrlMask */
|
||||
desc->bitmap[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1;
|
||||
desc->bitmap[0] = 0;
|
||||
desc->bitmap[1] = ~0;
|
||||
}
|
||||
|
||||
@ -1159,135 +1148,9 @@ static int isp116x_hub_control(struct usb_hcd *hcd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int isp116x_bus_suspend(struct usb_hcd *hcd)
|
||||
{
|
||||
struct isp116x *isp116x = hcd_to_isp116x(hcd);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&isp116x->lock, flags);
|
||||
|
||||
val = isp116x_read_reg32(isp116x, HCCONTROL);
|
||||
switch (val & HCCONTROL_HCFS) {
|
||||
case HCCONTROL_USB_OPER:
|
||||
hcd->state = HC_STATE_QUIESCING;
|
||||
val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE);
|
||||
val |= HCCONTROL_USB_SUSPEND;
|
||||
if (hcd->remote_wakeup)
|
||||
val |= HCCONTROL_RWE;
|
||||
/* Wait for usb transfers to finish */
|
||||
mdelay(2);
|
||||
isp116x_write_reg32(isp116x, HCCONTROL, val);
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
/* Wait for devices to suspend */
|
||||
mdelay(5);
|
||||
case HCCONTROL_USB_SUSPEND:
|
||||
break;
|
||||
case HCCONTROL_USB_RESUME:
|
||||
isp116x_write_reg32(isp116x, HCCONTROL,
|
||||
(val & ~HCCONTROL_HCFS) |
|
||||
HCCONTROL_USB_RESET);
|
||||
case HCCONTROL_USB_RESET:
|
||||
ret = -EBUSY;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&isp116x->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int isp116x_bus_resume(struct usb_hcd *hcd)
|
||||
{
|
||||
struct isp116x *isp116x = hcd_to_isp116x(hcd);
|
||||
u32 val;
|
||||
int ret = -EINPROGRESS;
|
||||
|
||||
msleep(5);
|
||||
spin_lock_irq(&isp116x->lock);
|
||||
|
||||
val = isp116x_read_reg32(isp116x, HCCONTROL);
|
||||
switch (val & HCCONTROL_HCFS) {
|
||||
case HCCONTROL_USB_SUSPEND:
|
||||
val &= ~HCCONTROL_HCFS;
|
||||
val |= HCCONTROL_USB_RESUME;
|
||||
isp116x_write_reg32(isp116x, HCCONTROL, val);
|
||||
case HCCONTROL_USB_RESUME:
|
||||
break;
|
||||
case HCCONTROL_USB_OPER:
|
||||
/* Without setting power_state here the
|
||||
SUSPENDED state won't be removed from
|
||||
sysfs/usbN/power.state as a response to remote
|
||||
wakeup. Maybe in the future. */
|
||||
hcd->self.root_hub->dev.power.power_state = PMSG_ON;
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
ret = -EBUSY;
|
||||
}
|
||||
|
||||
if (ret != -EINPROGRESS) {
|
||||
spin_unlock_irq(&isp116x->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
val = isp116x->rhdesca & RH_A_NDP;
|
||||
while (val--) {
|
||||
u32 stat =
|
||||
isp116x_read_reg32(isp116x, val ? HCRHPORT2 : HCRHPORT1);
|
||||
/* force global, not selective, resume */
|
||||
if (!(stat & RH_PS_PSS))
|
||||
continue;
|
||||
DBG("%s: Resuming port %d\n", __func__, val);
|
||||
isp116x_write_reg32(isp116x, RH_PS_POCI, val
|
||||
? HCRHPORT2 : HCRHPORT1);
|
||||
}
|
||||
spin_unlock_irq(&isp116x->lock);
|
||||
|
||||
hcd->state = HC_STATE_RESUMING;
|
||||
mdelay(20);
|
||||
|
||||
/* Go operational */
|
||||
spin_lock_irq(&isp116x->lock);
|
||||
val = isp116x_read_reg32(isp116x, HCCONTROL);
|
||||
isp116x_write_reg32(isp116x, HCCONTROL,
|
||||
(val & ~HCCONTROL_HCFS) | HCCONTROL_USB_OPER);
|
||||
spin_unlock_irq(&isp116x->lock);
|
||||
/* see analogous comment above */
|
||||
hcd->self.root_hub->dev.power.power_state = PMSG_ON;
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#define isp116x_bus_suspend NULL
|
||||
#define isp116x_bus_resume NULL
|
||||
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
|
||||
#ifdef STUB_DEBUG_FILE
|
||||
|
||||
static inline void create_debug_file(struct isp116x *isp116x)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void remove_debug_file(struct isp116x *isp116x)
|
||||
{
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
static void dump_irq(struct seq_file *s, char *label, u16 mask)
|
||||
{
|
||||
@ -1311,13 +1174,9 @@ static void dump_int(struct seq_file *s, char *label, u32 mask)
|
||||
mask & HCINT_SF ? " sof" : "", mask & HCINT_SO ? " so" : "");
|
||||
}
|
||||
|
||||
static int proc_isp116x_show(struct seq_file *s, void *unused)
|
||||
static int isp116x_show_dbg(struct seq_file *s, void *unused)
|
||||
{
|
||||
struct isp116x *isp116x = s->private;
|
||||
struct isp116x_ep *ep;
|
||||
struct urb *urb;
|
||||
unsigned i;
|
||||
char *str;
|
||||
|
||||
seq_printf(s, "%s\n%s version %s\n",
|
||||
isp116x_to_hcd(isp116x)->product_desc, hcd_name,
|
||||
@ -1333,105 +1192,50 @@ static int proc_isp116x_show(struct seq_file *s, void *unused)
|
||||
}
|
||||
|
||||
spin_lock_irq(&isp116x->lock);
|
||||
|
||||
dump_irq(s, "hc_irq_enable", isp116x_read_reg16(isp116x, HCuPINTENB));
|
||||
dump_irq(s, "hc_irq_status", isp116x_read_reg16(isp116x, HCuPINT));
|
||||
dump_int(s, "hc_int_enable", isp116x_read_reg32(isp116x, HCINTENB));
|
||||
dump_int(s, "hc_int_status", isp116x_read_reg32(isp116x, HCINTSTAT));
|
||||
|
||||
list_for_each_entry(ep, &isp116x->async, schedule) {
|
||||
|
||||
switch (ep->nextpid) {
|
||||
case USB_PID_IN:
|
||||
str = "in";
|
||||
break;
|
||||
case USB_PID_OUT:
|
||||
str = "out";
|
||||
break;
|
||||
case USB_PID_SETUP:
|
||||
str = "setup";
|
||||
break;
|
||||
case USB_PID_ACK:
|
||||
str = "status";
|
||||
break;
|
||||
default:
|
||||
str = "?";
|
||||
break;
|
||||
};
|
||||
seq_printf(s, "%p, ep%d%s, maxpacket %d:\n", ep,
|
||||
ep->epnum, str, ep->maxpacket);
|
||||
list_for_each_entry(urb, &ep->hep->urb_list, urb_list) {
|
||||
seq_printf(s, " urb%p, %d/%d\n", urb,
|
||||
urb->actual_length,
|
||||
urb->transfer_buffer_length);
|
||||
}
|
||||
}
|
||||
if (!list_empty(&isp116x->async))
|
||||
seq_printf(s, "\n");
|
||||
|
||||
seq_printf(s, "periodic size= %d\n", PERIODIC_SIZE);
|
||||
|
||||
for (i = 0; i < PERIODIC_SIZE; i++) {
|
||||
ep = isp116x->periodic[i];
|
||||
if (!ep)
|
||||
continue;
|
||||
seq_printf(s, "%2d [%3d]:\n", i, isp116x->load[i]);
|
||||
|
||||
/* DUMB: prints shared entries multiple times */
|
||||
do {
|
||||
seq_printf(s, " %d/%p (%sdev%d ep%d%s max %d)\n",
|
||||
ep->period, ep,
|
||||
(ep->udev->speed ==
|
||||
USB_SPEED_FULL) ? "" : "ls ",
|
||||
ep->udev->devnum, ep->epnum,
|
||||
(ep->epnum ==
|
||||
0) ? "" : ((ep->nextpid ==
|
||||
USB_PID_IN) ? "in" : "out"),
|
||||
ep->maxpacket);
|
||||
ep = ep->next;
|
||||
} while (ep);
|
||||
}
|
||||
isp116x_show_regs_seq(isp116x, s);
|
||||
spin_unlock_irq(&isp116x->lock);
|
||||
seq_printf(s, "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int proc_isp116x_open(struct inode *inode, struct file *file)
|
||||
static int isp116x_open_seq(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, proc_isp116x_show, PDE(inode)->data);
|
||||
return single_open(file, isp116x_show_dbg, inode->u.generic_ip);
|
||||
}
|
||||
|
||||
static struct file_operations proc_ops = {
|
||||
.open = proc_isp116x_open,
|
||||
static struct file_operations isp116x_debug_fops = {
|
||||
.open = isp116x_open_seq,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
/* expect just one isp116x per system */
|
||||
static const char proc_filename[] = "driver/isp116x";
|
||||
|
||||
static void create_debug_file(struct isp116x *isp116x)
|
||||
static int create_debug_file(struct isp116x *isp116x)
|
||||
{
|
||||
struct proc_dir_entry *pde;
|
||||
|
||||
pde = create_proc_entry(proc_filename, 0, NULL);
|
||||
if (pde == NULL)
|
||||
return;
|
||||
|
||||
pde->proc_fops = &proc_ops;
|
||||
pde->data = isp116x;
|
||||
isp116x->pde = pde;
|
||||
isp116x->dentry = debugfs_create_file(hcd_name,
|
||||
S_IRUGO, NULL, isp116x,
|
||||
&isp116x_debug_fops);
|
||||
if (!isp116x->dentry)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void remove_debug_file(struct isp116x *isp116x)
|
||||
{
|
||||
if (isp116x->pde)
|
||||
remove_proc_entry(proc_filename, NULL);
|
||||
debugfs_remove(isp116x->dentry);
|
||||
}
|
||||
|
||||
#endif
|
||||
#else
|
||||
|
||||
#define create_debug_file(d) 0
|
||||
#define remove_debug_file(d) do{}while(0)
|
||||
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
|
||||
@ -1466,7 +1270,7 @@ static int isp116x_reset(struct usb_hcd *hcd)
|
||||
struct isp116x *isp116x = hcd_to_isp116x(hcd);
|
||||
unsigned long t;
|
||||
u16 clkrdy = 0;
|
||||
int ret = 0, timeout = 15 /* ms */ ;
|
||||
int ret, timeout = 15 /* ms */ ;
|
||||
|
||||
ret = isp116x_sw_reset(isp116x);
|
||||
if (ret)
|
||||
@ -1482,7 +1286,7 @@ static int isp116x_reset(struct usb_hcd *hcd)
|
||||
break;
|
||||
}
|
||||
if (!clkrdy) {
|
||||
ERR("Clock not ready after 20ms\n");
|
||||
ERR("Clock not ready after %dms\n", timeout);
|
||||
/* After sw_reset the clock won't report to be ready, if
|
||||
H_WAKEUP pin is high. */
|
||||
ERR("Please make sure that the H_WAKEUP pin is pulled low!\n");
|
||||
@ -1572,7 +1376,8 @@ static int isp116x_start(struct usb_hcd *hcd)
|
||||
|
||||
val = 0;
|
||||
if (board->remote_wakeup_enable) {
|
||||
hcd->can_wakeup = 1;
|
||||
if (!device_can_wakeup(hcd->self.controller))
|
||||
device_init_wakeup(hcd->self.controller, 1);
|
||||
val |= RH_HS_DRWE;
|
||||
}
|
||||
isp116x_write_reg32(isp116x, HCRHSTATUS, val);
|
||||
@ -1600,12 +1405,126 @@ static int isp116x_start(struct usb_hcd *hcd)
|
||||
isp116x_write_reg32(isp116x, HCRHPORT1, RH_PS_CCS);
|
||||
isp116x_write_reg32(isp116x, HCRHPORT2, RH_PS_CCS);
|
||||
|
||||
isp116x_show_regs(isp116x);
|
||||
isp116x_show_regs_log(isp116x);
|
||||
spin_unlock_irqrestore(&isp116x->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
static int isp116x_bus_suspend(struct usb_hcd *hcd)
|
||||
{
|
||||
struct isp116x *isp116x = hcd_to_isp116x(hcd);
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&isp116x->lock, flags);
|
||||
|
||||
val = isp116x_read_reg32(isp116x, HCCONTROL);
|
||||
switch (val & HCCONTROL_HCFS) {
|
||||
case HCCONTROL_USB_OPER:
|
||||
val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE);
|
||||
val |= HCCONTROL_USB_SUSPEND;
|
||||
if (device_may_wakeup(&hcd->self.root_hub->dev))
|
||||
val |= HCCONTROL_RWE;
|
||||
/* Wait for usb transfers to finish */
|
||||
mdelay(2);
|
||||
isp116x_write_reg32(isp116x, HCCONTROL, val);
|
||||
/* Wait for devices to suspend */
|
||||
mdelay(5);
|
||||
case HCCONTROL_USB_SUSPEND:
|
||||
break;
|
||||
case HCCONTROL_USB_RESUME:
|
||||
isp116x_write_reg32(isp116x, HCCONTROL,
|
||||
(val & ~HCCONTROL_HCFS) |
|
||||
HCCONTROL_USB_RESET);
|
||||
case HCCONTROL_USB_RESET:
|
||||
ret = -EBUSY;
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&isp116x->lock, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int isp116x_bus_resume(struct usb_hcd *hcd)
|
||||
{
|
||||
struct isp116x *isp116x = hcd_to_isp116x(hcd);
|
||||
u32 val;
|
||||
|
||||
msleep(5);
|
||||
spin_lock_irq(&isp116x->lock);
|
||||
|
||||
val = isp116x_read_reg32(isp116x, HCCONTROL);
|
||||
switch (val & HCCONTROL_HCFS) {
|
||||
case HCCONTROL_USB_SUSPEND:
|
||||
val &= ~HCCONTROL_HCFS;
|
||||
val |= HCCONTROL_USB_RESUME;
|
||||
isp116x_write_reg32(isp116x, HCCONTROL, val);
|
||||
case HCCONTROL_USB_RESUME:
|
||||
break;
|
||||
case HCCONTROL_USB_OPER:
|
||||
spin_unlock_irq(&isp116x->lock);
|
||||
/* Without setting power_state here the
|
||||
SUSPENDED state won't be removed from
|
||||
sysfs/usbN/power.state as a response to remote
|
||||
wakeup. Maybe in the future. */
|
||||
hcd->self.root_hub->dev.power.power_state = PMSG_ON;
|
||||
return 0;
|
||||
default:
|
||||
/* HCCONTROL_USB_RESET: this may happen, when during
|
||||
suspension the HC lost power. Reinitialize completely */
|
||||
spin_unlock_irq(&isp116x->lock);
|
||||
DBG("Chip has been reset while suspended. Reinit from scratch.\n");
|
||||
isp116x_reset(hcd);
|
||||
isp116x_start(hcd);
|
||||
isp116x_hub_control(hcd, SetPortFeature,
|
||||
USB_PORT_FEAT_POWER, 1, NULL, 0);
|
||||
if ((isp116x->rhdesca & RH_A_NDP) == 2)
|
||||
isp116x_hub_control(hcd, SetPortFeature,
|
||||
USB_PORT_FEAT_POWER, 2, NULL, 0);
|
||||
hcd->self.root_hub->dev.power.power_state = PMSG_ON;
|
||||
return 0;
|
||||
}
|
||||
|
||||
val = isp116x->rhdesca & RH_A_NDP;
|
||||
while (val--) {
|
||||
u32 stat =
|
||||
isp116x_read_reg32(isp116x, val ? HCRHPORT2 : HCRHPORT1);
|
||||
/* force global, not selective, resume */
|
||||
if (!(stat & RH_PS_PSS))
|
||||
continue;
|
||||
DBG("%s: Resuming port %d\n", __func__, val);
|
||||
isp116x_write_reg32(isp116x, RH_PS_POCI, val
|
||||
? HCRHPORT2 : HCRHPORT1);
|
||||
}
|
||||
spin_unlock_irq(&isp116x->lock);
|
||||
|
||||
hcd->state = HC_STATE_RESUMING;
|
||||
msleep(20);
|
||||
|
||||
/* Go operational */
|
||||
spin_lock_irq(&isp116x->lock);
|
||||
val = isp116x_read_reg32(isp116x, HCCONTROL);
|
||||
isp116x_write_reg32(isp116x, HCCONTROL,
|
||||
(val & ~HCCONTROL_HCFS) | HCCONTROL_USB_OPER);
|
||||
spin_unlock_irq(&isp116x->lock);
|
||||
/* see analogous comment above */
|
||||
hcd->self.root_hub->dev.power.power_state = PMSG_ON;
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define isp116x_bus_suspend NULL
|
||||
#define isp116x_bus_resume NULL
|
||||
|
||||
#endif
|
||||
|
||||
static struct hc_driver isp116x_hc_driver = {
|
||||
.description = hcd_name,
|
||||
@ -1735,12 +1654,19 @@ static int __init isp116x_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, SA_INTERRUPT);
|
||||
if (ret != 0)
|
||||
if (ret)
|
||||
goto err6;
|
||||
|
||||
create_debug_file(isp116x);
|
||||
ret = create_debug_file(isp116x);
|
||||
if (ret) {
|
||||
ERR("Couldn't create debugfs entry\n");
|
||||
goto err7;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err7:
|
||||
usb_remove_hcd(hcd);
|
||||
err6:
|
||||
usb_put_hcd(hcd);
|
||||
err5:
|
||||
@ -1762,13 +1688,9 @@ static int __init isp116x_probe(struct platform_device *pdev)
|
||||
*/
|
||||
static int isp116x_suspend(struct platform_device *dev, pm_message_t state)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
VDBG("%s: state %x\n", __func__, state);
|
||||
|
||||
VDBG("%s: state %x\n", __func__, state.event);
|
||||
dev->dev.power.power_state = state;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1776,13 +1698,9 @@ static int isp116x_suspend(struct platform_device *dev, pm_message_t state)
|
||||
*/
|
||||
static int isp116x_resume(struct platform_device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
VDBG("%s: state %x\n", __func__, dev->dev.power.power_state);
|
||||
|
||||
VDBG("%s: state %x\n", __func__, dev->power.power_state.event);
|
||||
dev->dev.power.power_state = PMSG_ON;
|
||||
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -259,7 +259,7 @@ struct isp116x {
|
||||
|
||||
struct isp116x_platform_data *board;
|
||||
|
||||
struct proc_dir_entry *pde;
|
||||
struct dentry *dentry;
|
||||
unsigned long stat1, stat2, stat4, stat8, stat16;
|
||||
|
||||
/* HC registers */
|
||||
@ -450,7 +450,7 @@ static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg,
|
||||
isp116x_write_data32(isp116x, (u32) val);
|
||||
}
|
||||
|
||||
#define isp116x_show_reg(d,r) { \
|
||||
#define isp116x_show_reg_log(d,r,s) { \
|
||||
if ((r) < 0x20) { \
|
||||
DBG("%-12s[%02x]: %08x\n", #r, \
|
||||
r, isp116x_read_reg32(d, r)); \
|
||||
@ -459,35 +459,60 @@ static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg,
|
||||
r, isp116x_read_reg16(d, r)); \
|
||||
} \
|
||||
}
|
||||
#define isp116x_show_reg_seq(d,r,s) { \
|
||||
if ((r) < 0x20) { \
|
||||
seq_printf(s, "%-12s[%02x]: %08x\n", #r, \
|
||||
r, isp116x_read_reg32(d, r)); \
|
||||
} else { \
|
||||
seq_printf(s, "%-12s[%02x]: %04x\n", #r, \
|
||||
r, isp116x_read_reg16(d, r)); \
|
||||
} \
|
||||
}
|
||||
|
||||
static inline void isp116x_show_regs(struct isp116x *isp116x)
|
||||
#define isp116x_show_regs(d,type,s) { \
|
||||
isp116x_show_reg_##type(d, HCREVISION, s); \
|
||||
isp116x_show_reg_##type(d, HCCONTROL, s); \
|
||||
isp116x_show_reg_##type(d, HCCMDSTAT, s); \
|
||||
isp116x_show_reg_##type(d, HCINTSTAT, s); \
|
||||
isp116x_show_reg_##type(d, HCINTENB, s); \
|
||||
isp116x_show_reg_##type(d, HCFMINTVL, s); \
|
||||
isp116x_show_reg_##type(d, HCFMREM, s); \
|
||||
isp116x_show_reg_##type(d, HCFMNUM, s); \
|
||||
isp116x_show_reg_##type(d, HCLSTHRESH, s); \
|
||||
isp116x_show_reg_##type(d, HCRHDESCA, s); \
|
||||
isp116x_show_reg_##type(d, HCRHDESCB, s); \
|
||||
isp116x_show_reg_##type(d, HCRHSTATUS, s); \
|
||||
isp116x_show_reg_##type(d, HCRHPORT1, s); \
|
||||
isp116x_show_reg_##type(d, HCRHPORT2, s); \
|
||||
isp116x_show_reg_##type(d, HCHWCFG, s); \
|
||||
isp116x_show_reg_##type(d, HCDMACFG, s); \
|
||||
isp116x_show_reg_##type(d, HCXFERCTR, s); \
|
||||
isp116x_show_reg_##type(d, HCuPINT, s); \
|
||||
isp116x_show_reg_##type(d, HCuPINTENB, s); \
|
||||
isp116x_show_reg_##type(d, HCCHIPID, s); \
|
||||
isp116x_show_reg_##type(d, HCSCRATCH, s); \
|
||||
isp116x_show_reg_##type(d, HCITLBUFLEN, s); \
|
||||
isp116x_show_reg_##type(d, HCATLBUFLEN, s); \
|
||||
isp116x_show_reg_##type(d, HCBUFSTAT, s); \
|
||||
isp116x_show_reg_##type(d, HCRDITL0LEN, s); \
|
||||
isp116x_show_reg_##type(d, HCRDITL1LEN, s); \
|
||||
}
|
||||
|
||||
/*
|
||||
Dump registers for debugfs.
|
||||
*/
|
||||
static inline void isp116x_show_regs_seq(struct isp116x *isp116x,
|
||||
struct seq_file *s)
|
||||
{
|
||||
isp116x_show_reg(isp116x, HCREVISION);
|
||||
isp116x_show_reg(isp116x, HCCONTROL);
|
||||
isp116x_show_reg(isp116x, HCCMDSTAT);
|
||||
isp116x_show_reg(isp116x, HCINTSTAT);
|
||||
isp116x_show_reg(isp116x, HCINTENB);
|
||||
isp116x_show_reg(isp116x, HCFMINTVL);
|
||||
isp116x_show_reg(isp116x, HCFMREM);
|
||||
isp116x_show_reg(isp116x, HCFMNUM);
|
||||
isp116x_show_reg(isp116x, HCLSTHRESH);
|
||||
isp116x_show_reg(isp116x, HCRHDESCA);
|
||||
isp116x_show_reg(isp116x, HCRHDESCB);
|
||||
isp116x_show_reg(isp116x, HCRHSTATUS);
|
||||
isp116x_show_reg(isp116x, HCRHPORT1);
|
||||
isp116x_show_reg(isp116x, HCRHPORT2);
|
||||
isp116x_show_reg(isp116x, HCHWCFG);
|
||||
isp116x_show_reg(isp116x, HCDMACFG);
|
||||
isp116x_show_reg(isp116x, HCXFERCTR);
|
||||
isp116x_show_reg(isp116x, HCuPINT);
|
||||
isp116x_show_reg(isp116x, HCuPINTENB);
|
||||
isp116x_show_reg(isp116x, HCCHIPID);
|
||||
isp116x_show_reg(isp116x, HCSCRATCH);
|
||||
isp116x_show_reg(isp116x, HCITLBUFLEN);
|
||||
isp116x_show_reg(isp116x, HCATLBUFLEN);
|
||||
isp116x_show_reg(isp116x, HCBUFSTAT);
|
||||
isp116x_show_reg(isp116x, HCRDITL0LEN);
|
||||
isp116x_show_reg(isp116x, HCRDITL1LEN);
|
||||
isp116x_show_regs(isp116x, seq, s);
|
||||
}
|
||||
|
||||
/*
|
||||
Dump registers to syslog.
|
||||
*/
|
||||
static inline void isp116x_show_regs_log(struct isp116x *isp116x)
|
||||
{
|
||||
isp116x_show_regs(isp116x, log, NULL);
|
||||
}
|
||||
|
||||
#if defined(URB_TRACE)
|
||||
|
@ -75,13 +75,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
|
||||
#ifdef CONFIG_USB_DEBUG
|
||||
# define DEBUG
|
||||
#else
|
||||
# undef DEBUG
|
||||
#endif
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/pci.h>
|
||||
@ -802,7 +795,6 @@ static int ohci_restart (struct ohci_hcd *ohci)
|
||||
int temp;
|
||||
int i;
|
||||
struct urb_priv *priv;
|
||||
struct usb_device *root = ohci_to_hcd(ohci)->self.root_hub;
|
||||
|
||||
/* mark any devices gone, so they do nothing till khubd disconnects.
|
||||
* recycle any "live" eds/tds (and urbs) right away.
|
||||
@ -811,11 +803,7 @@ static int ohci_restart (struct ohci_hcd *ohci)
|
||||
*/
|
||||
spin_lock_irq(&ohci->lock);
|
||||
disable (ohci);
|
||||
for (i = 0; i < root->maxchild; i++) {
|
||||
if (root->children [i])
|
||||
usb_set_device_state (root->children[i],
|
||||
USB_STATE_NOTATTACHED);
|
||||
}
|
||||
usb_root_hub_lost_power(ohci_to_hcd(ohci)->self.root_hub);
|
||||
if (!list_empty (&ohci->pending))
|
||||
ohci_dbg(ohci, "abort schedule...\n");
|
||||
list_for_each_entry (priv, &ohci->pending, pending) {
|
||||
|
@ -372,7 +372,7 @@ done:
|
||||
& ohci->hc_control)
|
||||
== OHCI_USB_OPER
|
||||
&& time_after (jiffies, ohci->next_statechange)
|
||||
&& usb_trylock_device (hcd->self.root_hub)
|
||||
&& usb_trylock_device (hcd->self.root_hub) == 0
|
||||
) {
|
||||
ohci_vdbg (ohci, "autosuspend\n");
|
||||
(void) ohci_bus_suspend (hcd);
|
||||
|
@ -26,18 +26,12 @@
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/hardware.h>
|
||||
#include <asm/arch/pxa-regs.h>
|
||||
|
||||
|
||||
#define PMM_NPS_MODE 1
|
||||
#define PMM_GLOBAL_MODE 2
|
||||
#define PMM_PERPORT_MODE 3
|
||||
#include <asm/arch/ohci.h>
|
||||
|
||||
#define PXA_UHC_MAX_PORTNUM 3
|
||||
|
||||
#define UHCRHPS(x) __REG2( 0x4C000050, (x)<<2 )
|
||||
|
||||
static int pxa27x_ohci_pmm_state;
|
||||
|
||||
/*
|
||||
PMM_NPS_MODE -- PMM Non-power switching mode
|
||||
Ports are powered continuously.
|
||||
@ -50,8 +44,6 @@ static int pxa27x_ohci_pmm_state;
|
||||
*/
|
||||
static int pxa27x_ohci_select_pmm( int mode )
|
||||
{
|
||||
pxa27x_ohci_pmm_state = mode;
|
||||
|
||||
switch ( mode ) {
|
||||
case PMM_NPS_MODE:
|
||||
UHCRHDA |= RH_A_NPS;
|
||||
@ -71,7 +63,6 @@ static int pxa27x_ohci_select_pmm( int mode )
|
||||
"Invalid mode %d, set to non-power switch mode.\n",
|
||||
mode );
|
||||
|
||||
pxa27x_ohci_pmm_state = PMM_NPS_MODE;
|
||||
UHCRHDA |= RH_A_NPS;
|
||||
}
|
||||
|
||||
@ -82,8 +73,13 @@ extern int usb_disabled(void);
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static void pxa27x_start_hc(struct platform_device *dev)
|
||||
static int pxa27x_start_hc(struct device *dev)
|
||||
{
|
||||
int retval = 0;
|
||||
struct pxaohci_platform_data *inf;
|
||||
|
||||
inf = dev->platform_data;
|
||||
|
||||
pxa_set_cken(CKEN10_USBHOST, 1);
|
||||
|
||||
UHCHR |= UHCHR_FHR;
|
||||
@ -94,21 +90,11 @@ static void pxa27x_start_hc(struct platform_device *dev)
|
||||
while (UHCHR & UHCHR_FSBIR)
|
||||
cpu_relax();
|
||||
|
||||
/* This could be properly abstracted away through the
|
||||
device data the day more machines are supported and
|
||||
their differences can be figured out correctly. */
|
||||
if (machine_is_mainstone()) {
|
||||
/* setup Port1 GPIO pin. */
|
||||
pxa_gpio_mode( 88 | GPIO_ALT_FN_1_IN); /* USBHPWR1 */
|
||||
pxa_gpio_mode( 89 | GPIO_ALT_FN_2_OUT); /* USBHPEN1 */
|
||||
if (inf->init)
|
||||
retval = inf->init(dev);
|
||||
|
||||
/* Set the Power Control Polarity Low and Power Sense
|
||||
Polarity Low to active low. Supply power to USB ports. */
|
||||
UHCHR = (UHCHR | UHCHR_PCPL | UHCHR_PSPL) &
|
||||
~(UHCHR_SSEP1 | UHCHR_SSEP2 | UHCHR_SSEP3 | UHCHR_SSE);
|
||||
|
||||
pxa27x_ohci_pmm_state = PMM_PERPORT_MODE;
|
||||
}
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
UHCHR &= ~UHCHR_SSE;
|
||||
|
||||
@ -117,10 +103,19 @@ static void pxa27x_start_hc(struct platform_device *dev)
|
||||
/* Clear any OTG Pin Hold */
|
||||
if (PSSR & PSSR_OTGPH)
|
||||
PSSR |= PSSR_OTGPH;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pxa27x_stop_hc(struct platform_device *dev)
|
||||
static void pxa27x_stop_hc(struct device *dev)
|
||||
{
|
||||
struct pxaohci_platform_data *inf;
|
||||
|
||||
inf = dev->platform_data;
|
||||
|
||||
if (inf->exit)
|
||||
inf->exit(dev);
|
||||
|
||||
UHCHR |= UHCHR_FHR;
|
||||
udelay(11);
|
||||
UHCHR &= ~UHCHR_FHR;
|
||||
@ -147,22 +142,27 @@ static void pxa27x_stop_hc(struct platform_device *dev)
|
||||
* through the hotplug entry's driver_data.
|
||||
*
|
||||
*/
|
||||
int usb_hcd_pxa27x_probe (const struct hc_driver *driver,
|
||||
struct platform_device *dev)
|
||||
int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device *pdev)
|
||||
{
|
||||
int retval;
|
||||
struct usb_hcd *hcd;
|
||||
struct pxaohci_platform_data *inf;
|
||||
|
||||
if (dev->resource[1].flags != IORESOURCE_IRQ) {
|
||||
inf = pdev->dev.platform_data;
|
||||
|
||||
if (!inf)
|
||||
return -ENODEV;
|
||||
|
||||
if (pdev->resource[1].flags != IORESOURCE_IRQ) {
|
||||
pr_debug ("resource[1] is not IORESOURCE_IRQ");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
hcd = usb_create_hcd (driver, &dev->dev, "pxa27x");
|
||||
hcd = usb_create_hcd (driver, &pdev->dev, "pxa27x");
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
hcd->rsrc_start = dev->resource[0].start;
|
||||
hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
|
||||
hcd->rsrc_start = pdev->resource[0].start;
|
||||
hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
|
||||
|
||||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
|
||||
pr_debug("request_mem_region failed");
|
||||
@ -177,18 +177,22 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver,
|
||||
goto err2;
|
||||
}
|
||||
|
||||
pxa27x_start_hc(dev);
|
||||
if ((retval = pxa27x_start_hc(&pdev->dev)) < 0) {
|
||||
pr_debug("pxa27x_start_hc failed");
|
||||
goto err3;
|
||||
}
|
||||
|
||||
/* Select Power Management Mode */
|
||||
pxa27x_ohci_select_pmm(pxa27x_ohci_pmm_state);
|
||||
pxa27x_ohci_select_pmm(inf->port_mode);
|
||||
|
||||
ohci_hcd_init(hcd_to_ohci(hcd));
|
||||
|
||||
retval = usb_add_hcd(hcd, dev->resource[1].start, SA_INTERRUPT);
|
||||
retval = usb_add_hcd(hcd, pdev->resource[1].start, SA_INTERRUPT);
|
||||
if (retval == 0)
|
||||
return retval;
|
||||
|
||||
pxa27x_stop_hc(dev);
|
||||
pxa27x_stop_hc(&pdev->dev);
|
||||
err3:
|
||||
iounmap(hcd->regs);
|
||||
err2:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
@ -211,10 +215,10 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver,
|
||||
* context, normally "rmmod", "apmd", or something similar.
|
||||
*
|
||||
*/
|
||||
void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *dev)
|
||||
void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev)
|
||||
{
|
||||
usb_remove_hcd(hcd);
|
||||
pxa27x_stop_hc(dev);
|
||||
pxa27x_stop_hc(&pdev->dev);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
@ -292,15 +296,12 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
|
||||
|
||||
static int ohci_hcd_pxa27x_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pr_debug ("In ohci_hcd_pxa27x_drv_probe");
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
ret = usb_hcd_pxa27x_probe(&ohci_pxa27x_hc_driver, pdev);
|
||||
return ret;
|
||||
return usb_hcd_pxa27x_probe(&ohci_pxa27x_hc_driver, pdev);
|
||||
}
|
||||
|
||||
static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev)
|
||||
@ -308,31 +309,55 @@ static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev)
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
|
||||
usb_hcd_pxa27x_remove(hcd, pdev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ohci_hcd_pxa27x_drv_suspend(struct platform_device *dev, pm_message_t state)
|
||||
#ifdef CONFIG_PM
|
||||
static int ohci_hcd_pxa27x_drv_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
// struct usb_hcd *hcd = platform_get_drvdata(dev);
|
||||
printk("%s: not implemented yet\n", __FUNCTION__);
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
|
||||
|
||||
if (time_before(jiffies, ohci->next_statechange))
|
||||
msleep(5);
|
||||
ohci->next_statechange = jiffies;
|
||||
|
||||
pxa27x_stop_hc(&pdev->dev);
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
pdev->dev.power.power_state = PMSG_SUSPEND;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ohci_hcd_pxa27x_drv_resume(struct platform_device *dev)
|
||||
static int ohci_hcd_pxa27x_drv_resume(struct platform_device *pdev)
|
||||
{
|
||||
// struct usb_hcd *hcd = platform_get_drvdata(dev);
|
||||
printk("%s: not implemented yet\n", __FUNCTION__);
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
|
||||
int status;
|
||||
|
||||
if (time_before(jiffies, ohci->next_statechange))
|
||||
msleep(5);
|
||||
ohci->next_statechange = jiffies;
|
||||
|
||||
if ((status = pxa27x_start_hc(&pdev->dev)) < 0)
|
||||
return status;
|
||||
|
||||
pdev->dev.power.power_state = PMSG_ON;
|
||||
usb_hcd_resume_root_hub(hcd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static struct platform_driver ohci_hcd_pxa27x_driver = {
|
||||
.probe = ohci_hcd_pxa27x_drv_probe,
|
||||
.remove = ohci_hcd_pxa27x_drv_remove,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = ohci_hcd_pxa27x_drv_suspend,
|
||||
.resume = ohci_hcd_pxa27x_drv_resume,
|
||||
#endif
|
||||
.driver = {
|
||||
.name = "pxa27x-ohci",
|
||||
},
|
||||
|
@ -9,12 +9,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#ifdef CONFIG_USB_DEBUG
|
||||
#define DEBUG
|
||||
#else
|
||||
#undef DEBUG
|
||||
#endif
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
|
@ -32,13 +32,6 @@
|
||||
#undef PACKET_TRACE
|
||||
|
||||
#include <linux/config.h>
|
||||
|
||||
#ifdef CONFIG_USB_DEBUG
|
||||
# define DEBUG
|
||||
#else
|
||||
# undef DEBUG
|
||||
#endif
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -1581,7 +1574,9 @@ sl811h_start(struct usb_hcd *hcd)
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
|
||||
if (sl811->board) {
|
||||
hcd->can_wakeup = sl811->board->can_wakeup;
|
||||
if (!device_can_wakeup(hcd->self.controller))
|
||||
device_init_wakeup(hcd->self.controller,
|
||||
sl811->board->can_wakeup);
|
||||
hcd->power_budget = sl811->board->power * 2;
|
||||
}
|
||||
|
||||
@ -1805,9 +1800,10 @@ sl811h_resume(struct platform_device *dev)
|
||||
* let's assume it'd only be powered to enable remote wakeup.
|
||||
*/
|
||||
if (dev->dev.power.power_state.event == PM_EVENT_SUSPEND
|
||||
|| !hcd->can_wakeup) {
|
||||
|| !device_can_wakeup(&hcd->self.root_hub->dev)) {
|
||||
sl811->port1 = 0;
|
||||
port_power(sl811, 1);
|
||||
usb_root_hub_lost_power(hcd->self.root_hub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ MODULE_LICENSE("GPL");
|
||||
/* MACROS */
|
||||
/*====================================================================*/
|
||||
|
||||
#if defined(DEBUG) || defined(CONFIG_USB_DEBUG) || defined(PCMCIA_DEBUG)
|
||||
#if defined(DEBUG) || defined(PCMCIA_DEBUG)
|
||||
|
||||
static int pc_debug = 0;
|
||||
module_param(pc_debug, int, 0644);
|
||||
@ -129,7 +129,8 @@ static int sl811_hc_init(struct device *parent, ioaddr_t base_addr, int irq)
|
||||
resources[2].end = base_addr + 1;
|
||||
|
||||
/* The driver core will probe for us. We know sl811-hcd has been
|
||||
* initialized already because of the link order dependency.
|
||||
* initialized already because of the link order dependency created
|
||||
* by referencing "sl811h_driver".
|
||||
*/
|
||||
platform_dev.name = sl811h_driver.name;
|
||||
return platform_device_register(&platform_dev);
|
||||
|
@ -2,8 +2,8 @@
|
||||
* UHCI-specific debugging code. Invaluable when something
|
||||
* goes wrong, but don't get in my face.
|
||||
*
|
||||
* Kernel visible pointers are surrounded in []'s and bus
|
||||
* visible pointers are surrounded in ()'s
|
||||
* Kernel visible pointers are surrounded in []s and bus
|
||||
* visible pointers are surrounded in ()s
|
||||
*
|
||||
* (C) Copyright 1999 Linus Torvalds
|
||||
* (C) Copyright 1999-2001 Johannes Erdfelt
|
||||
@ -19,7 +19,7 @@
|
||||
|
||||
static struct dentry *uhci_debugfs_root = NULL;
|
||||
|
||||
/* Handle REALLY large printk's so we don't overflow buffers */
|
||||
/* Handle REALLY large printks so we don't overflow buffers */
|
||||
static inline void lprintk(char *buf)
|
||||
{
|
||||
char *p;
|
||||
@ -160,7 +160,7 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
|
||||
}
|
||||
|
||||
if (active && ni > i) {
|
||||
out += sprintf(out, "%*s[skipped %d active TD's]\n", space, "", ni - i);
|
||||
out += sprintf(out, "%*s[skipped %d active TDs]\n", space, "", ni - i);
|
||||
tmp = ntmp;
|
||||
td = ntd;
|
||||
i = ni;
|
||||
@ -173,7 +173,7 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
|
||||
if (list_empty(&urbp->queue_list) || urbp->queued)
|
||||
goto out;
|
||||
|
||||
out += sprintf(out, "%*sQueued QH's:\n", -space, "--");
|
||||
out += sprintf(out, "%*sQueued QHs:\n", -space, "--");
|
||||
|
||||
head = &urbp->queue_list;
|
||||
tmp = head->next;
|
||||
@ -197,7 +197,7 @@ out:
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static const char *qh_names[] = {
|
||||
static const char * const qh_names[] = {
|
||||
"skel_int128_qh", "skel_int64_qh",
|
||||
"skel_int32_qh", "skel_int16_qh",
|
||||
"skel_int8_qh", "skel_int4_qh",
|
||||
@ -464,7 +464,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
|
||||
} while (tmp != head);
|
||||
}
|
||||
|
||||
out += sprintf(out, "Skeleton QH's\n");
|
||||
out += sprintf(out, "Skeleton QHs\n");
|
||||
|
||||
for (i = 0; i < UHCI_NUM_SKELQH; ++i) {
|
||||
int shown = 0;
|
||||
|
@ -23,11 +23,6 @@
|
||||
*/
|
||||
|
||||
#include <linux/config.h>
|
||||
#ifdef CONFIG_USB_DEBUG
|
||||
#define DEBUG
|
||||
#else
|
||||
#undef DEBUG
|
||||
#endif
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/kernel.h>
|
||||
@ -67,10 +62,10 @@ Alan Stern"
|
||||
|
||||
/*
|
||||
* debug = 0, no debugging messages
|
||||
* debug = 1, dump failed URB's except for stalls
|
||||
* debug = 2, dump all failed URB's (including stalls)
|
||||
* debug = 1, dump failed URBs except for stalls
|
||||
* debug = 2, dump all failed URBs (including stalls)
|
||||
* show all queues in /debug/uhci/[pci_addr]
|
||||
* debug = 3, show all TD's in URB's when dumping
|
||||
* debug = 3, show all TDs in URBs when dumping
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
static int debug = 1;
|
||||
@ -93,7 +88,7 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
|
||||
#define FSBR_DELAY msecs_to_jiffies(50)
|
||||
|
||||
/* When we timeout an idle transfer for FSBR, we'll switch it over to */
|
||||
/* depth first traversal. We'll do it in groups of this number of TD's */
|
||||
/* depth first traversal. We'll do it in groups of this number of TDs */
|
||||
/* to make sure it doesn't hog all of the bandwidth */
|
||||
#define DEPTH_INTERVAL 5
|
||||
|
||||
@ -478,8 +473,6 @@ static int uhci_start(struct usb_hcd *hcd)
|
||||
struct dentry *dentry;
|
||||
|
||||
hcd->uses_new_polling = 1;
|
||||
if (pci_find_capability(to_pci_dev(uhci_dev(uhci)), PCI_CAP_ID_PM))
|
||||
hcd->can_wakeup = 1; /* Assume it supports PME# */
|
||||
|
||||
dentry = debugfs_create_file(hcd->self.bus_name,
|
||||
S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci,
|
||||
@ -573,7 +566,7 @@ static int uhci_start(struct usb_hcd *hcd)
|
||||
uhci->skel_bulk_qh->link = cpu_to_le32(uhci->skel_term_qh->dma_handle) | UHCI_PTR_QH;
|
||||
|
||||
/* This dummy TD is to work around a bug in Intel PIIX controllers */
|
||||
uhci_fill_td(uhci->term_td, 0, (UHCI_NULL_DATA_SIZE << 21) |
|
||||
uhci_fill_td(uhci->term_td, 0, uhci_explen(0) |
|
||||
(0x7f << TD_TOKEN_DEVADDR_SHIFT) | USB_PID_IN, 0);
|
||||
uhci->term_td->link = cpu_to_le32(uhci->term_td->dma_handle);
|
||||
|
||||
@ -735,8 +728,9 @@ static int uhci_resume(struct usb_hcd *hcd)
|
||||
|
||||
dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
|
||||
|
||||
/* We aren't in D3 state anymore, we do that even if dead as I
|
||||
* really don't want to keep a stale HCD_FLAG_HW_ACCESSIBLE=0
|
||||
/* Since we aren't in D3 any more, it's safe to set this flag
|
||||
* even if the controller was dead. It might not even be dead
|
||||
* any more, if the firmware or quirks code has reset it.
|
||||
*/
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
mb();
|
||||
@ -755,8 +749,12 @@ static int uhci_resume(struct usb_hcd *hcd)
|
||||
check_and_reset_hc(uhci);
|
||||
configure_hc(uhci);
|
||||
|
||||
if (uhci->rh_state == UHCI_RH_RESET)
|
||||
if (uhci->rh_state == UHCI_RH_RESET) {
|
||||
|
||||
/* The controller had to be reset */
|
||||
usb_root_hub_lost_power(hcd->self.root_hub);
|
||||
suspend_rh(uhci, UHCI_RH_SUSPENDED);
|
||||
}
|
||||
|
||||
spin_unlock_irq(&uhci->lock);
|
||||
|
||||
@ -882,7 +880,7 @@ static int __init uhci_hcd_init(void)
|
||||
|
||||
init_failed:
|
||||
if (kmem_cache_destroy(uhci_up_cachep))
|
||||
warn("not all urb_priv's were freed!");
|
||||
warn("not all urb_privs were freed!");
|
||||
|
||||
up_failed:
|
||||
debugfs_remove(uhci_debugfs_root);
|
||||
@ -900,7 +898,7 @@ static void __exit uhci_hcd_cleanup(void)
|
||||
pci_unregister_driver(&uhci_pci_driver);
|
||||
|
||||
if (kmem_cache_destroy(uhci_up_cachep))
|
||||
warn("not all urb_priv's were freed!");
|
||||
warn("not all urb_privs were freed!");
|
||||
|
||||
debugfs_remove(uhci_debugfs_root);
|
||||
kfree(errbuf);
|
||||
|
@ -71,8 +71,6 @@
|
||||
#define USBLEGSUP_RWC 0x8f00 /* the R/WC bits */
|
||||
#define USBLEGSUP_RO 0x5040 /* R/O and reserved bits */
|
||||
|
||||
#define UHCI_NULL_DATA_SIZE 0x7FF /* for UHCI controller TD */
|
||||
|
||||
#define UHCI_PTR_BITS cpu_to_le32(0x000F)
|
||||
#define UHCI_PTR_TERM cpu_to_le32(0x0001)
|
||||
#define UHCI_PTR_QH cpu_to_le32(0x0002)
|
||||
@ -168,9 +166,11 @@ static __le32 inline qh_element(struct uhci_qh *qh) {
|
||||
#define TD_TOKEN_EXPLEN_MASK 0x7FF /* expected length, encoded as n - 1 */
|
||||
#define TD_TOKEN_PID_MASK 0xFF
|
||||
|
||||
#define uhci_explen(len) ((len) << TD_TOKEN_EXPLEN_SHIFT)
|
||||
#define uhci_explen(len) ((((len) - 1) & TD_TOKEN_EXPLEN_MASK) << \
|
||||
TD_TOKEN_EXPLEN_SHIFT)
|
||||
|
||||
#define uhci_expected_length(token) ((((token) >> 21) + 1) & TD_TOKEN_EXPLEN_MASK)
|
||||
#define uhci_expected_length(token) ((((token) >> TD_TOKEN_EXPLEN_SHIFT) + \
|
||||
1) & TD_TOKEN_EXPLEN_MASK)
|
||||
#define uhci_toggle(token) (((token) >> TD_TOKEN_TOGGLE_SHIFT) & 1)
|
||||
#define uhci_endpoint(token) (((token) >> 15) & 0xf)
|
||||
#define uhci_devaddr(token) (((token) >> TD_TOKEN_DEVADDR_SHIFT) & 0x7f)
|
||||
@ -223,10 +223,10 @@ static u32 inline td_status(struct uhci_td *td) {
|
||||
*/
|
||||
|
||||
/*
|
||||
* The UHCI driver places Interrupt, Control and Bulk into QH's both
|
||||
* to group together TD's for one transfer, and also to faciliate queuing
|
||||
* of URB's. To make it easy to insert entries into the schedule, we have
|
||||
* a skeleton of QH's for each predefined Interrupt latency, low-speed
|
||||
* The UHCI driver places Interrupt, Control and Bulk into QHs both
|
||||
* to group together TDs for one transfer, and also to facilitate queuing
|
||||
* of URBs. To make it easy to insert entries into the schedule, we have
|
||||
* a skeleton of QHs for each predefined Interrupt latency, low-speed
|
||||
* control, full-speed control and terminating QH (see explanation for
|
||||
* the terminating QH below).
|
||||
*
|
||||
@ -257,8 +257,8 @@ static u32 inline td_status(struct uhci_td *td) {
|
||||
* reclamation.
|
||||
*
|
||||
* Isochronous transfers are stored before the start of the skeleton
|
||||
* schedule and don't use QH's. While the UHCI spec doesn't forbid the
|
||||
* use of QH's for Isochronous, it doesn't use them either. And the spec
|
||||
* schedule and don't use QHs. While the UHCI spec doesn't forbid the
|
||||
* use of QHs for Isochronous, it doesn't use them either. And the spec
|
||||
* says that queues never advance on an error completion status, which
|
||||
* makes them totally unsuitable for Isochronous transfers.
|
||||
*/
|
||||
@ -359,7 +359,7 @@ struct uhci_hcd {
|
||||
struct dma_pool *td_pool;
|
||||
|
||||
struct uhci_td *term_td; /* Terminating TD, see UHCI bug */
|
||||
struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */
|
||||
struct uhci_qh *skelqh[UHCI_NUM_SKELQH]; /* Skeleton QHs */
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
@ -389,22 +389,22 @@ struct uhci_hcd {
|
||||
unsigned long resuming_ports;
|
||||
unsigned long ports_timeout; /* Time to stop signalling */
|
||||
|
||||
/* Main list of URB's currently controlled by this HC */
|
||||
/* Main list of URBs currently controlled by this HC */
|
||||
struct list_head urb_list;
|
||||
|
||||
/* List of QH's that are done, but waiting to be unlinked (race) */
|
||||
/* List of QHs that are done, but waiting to be unlinked (race) */
|
||||
struct list_head qh_remove_list;
|
||||
unsigned int qh_remove_age; /* Age in frames */
|
||||
|
||||
/* List of TD's that are done, but waiting to be freed (race) */
|
||||
/* List of TDs that are done, but waiting to be freed (race) */
|
||||
struct list_head td_remove_list;
|
||||
unsigned int td_remove_age; /* Age in frames */
|
||||
|
||||
/* List of asynchronously unlinked URB's */
|
||||
/* List of asynchronously unlinked URBs */
|
||||
struct list_head urb_remove_list;
|
||||
unsigned int urb_remove_age; /* Age in frames */
|
||||
|
||||
/* List of URB's awaiting completion callback */
|
||||
/* List of URBs awaiting completion callback */
|
||||
struct list_head complete_list;
|
||||
|
||||
int rh_numports; /* Number of root-hub ports */
|
||||
|
@ -80,7 +80,7 @@ static inline void uhci_fill_td(struct uhci_td *td, u32 status,
|
||||
}
|
||||
|
||||
/*
|
||||
* We insert Isochronous URB's directly into the frame list at the beginning
|
||||
* We insert Isochronous URBs directly into the frame list at the beginning
|
||||
*/
|
||||
static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td, unsigned framenum)
|
||||
{
|
||||
@ -369,7 +369,7 @@ static void uhci_append_queued_urb(struct uhci_hcd *uhci, struct urb *eurb, stru
|
||||
uhci_fixup_toggle(urb,
|
||||
uhci_toggle(td_token(lltd)) ^ 1));
|
||||
|
||||
/* All qh's in the queue need to link to the next queue */
|
||||
/* All qhs in the queue need to link to the next queue */
|
||||
urbp->qh->link = eurbp->qh->link;
|
||||
|
||||
wmb(); /* Make sure we flush everything */
|
||||
@ -502,7 +502,7 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
|
||||
}
|
||||
|
||||
/* Check to see if the remove list is empty. Set the IOC bit */
|
||||
/* to force an interrupt so we can remove the TD's*/
|
||||
/* to force an interrupt so we can remove the TDs*/
|
||||
if (list_empty(&uhci->td_remove_list))
|
||||
uhci_set_next_interrupt(uhci);
|
||||
|
||||
@ -596,7 +596,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
|
||||
return -ENOMEM;
|
||||
|
||||
uhci_add_td_to_urb(urb, td);
|
||||
uhci_fill_td(td, status, destination | uhci_explen(7),
|
||||
uhci_fill_td(td, status, destination | uhci_explen(8),
|
||||
urb->setup_dma);
|
||||
|
||||
/*
|
||||
@ -612,7 +612,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
|
||||
}
|
||||
|
||||
/*
|
||||
* Build the DATA TD's
|
||||
* Build the DATA TDs
|
||||
*/
|
||||
while (len > 0) {
|
||||
int pktsze = len;
|
||||
@ -628,7 +628,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
|
||||
destination ^= TD_TOKEN_TOGGLE;
|
||||
|
||||
uhci_add_td_to_urb(urb, td);
|
||||
uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1),
|
||||
uhci_fill_td(td, status, destination | uhci_explen(pktsze),
|
||||
data);
|
||||
|
||||
data += pktsze;
|
||||
@ -658,7 +658,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
|
||||
|
||||
uhci_add_td_to_urb(urb, td);
|
||||
uhci_fill_td(td, status | TD_CTRL_IOC,
|
||||
destination | uhci_explen(UHCI_NULL_DATA_SIZE), 0);
|
||||
destination | uhci_explen(0), 0);
|
||||
|
||||
qh = uhci_alloc_qh(uhci);
|
||||
if (!qh)
|
||||
@ -744,7 +744,7 @@ static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb)
|
||||
|
||||
urb->actual_length = 0;
|
||||
|
||||
/* The rest of the TD's (but the last) are data */
|
||||
/* The rest of the TDs (but the last) are data */
|
||||
tmp = tmp->next;
|
||||
while (tmp != head && tmp->next != head) {
|
||||
unsigned int ctrlstat;
|
||||
@ -848,7 +848,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb
|
||||
status |= TD_CTRL_SPD;
|
||||
|
||||
/*
|
||||
* Build the DATA TD's
|
||||
* Build the DATA TDs
|
||||
*/
|
||||
do { /* Allow zero length packets */
|
||||
int pktsze = maxsze;
|
||||
@ -864,7 +864,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb
|
||||
return -ENOMEM;
|
||||
|
||||
uhci_add_td_to_urb(urb, td);
|
||||
uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1) |
|
||||
uhci_fill_td(td, status, destination | uhci_explen(pktsze) |
|
||||
(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
|
||||
usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
|
||||
data);
|
||||
@ -890,7 +890,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb
|
||||
return -ENOMEM;
|
||||
|
||||
uhci_add_td_to_urb(urb, td);
|
||||
uhci_fill_td(td, status, destination | uhci_explen(UHCI_NULL_DATA_SIZE) |
|
||||
uhci_fill_td(td, status, destination | uhci_explen(0) |
|
||||
(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
|
||||
usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),
|
||||
data);
|
||||
@ -1025,7 +1025,7 @@ static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsig
|
||||
list_for_each_entry(up, &uhci->urb_list, urb_list) {
|
||||
struct urb *u = up->urb;
|
||||
|
||||
/* look for pending URB's with identical pipe handle */
|
||||
/* look for pending URBs with identical pipe handle */
|
||||
if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&
|
||||
(u->status == -EINPROGRESS) && (u != urb)) {
|
||||
if (!last_urb)
|
||||
@ -1092,7 +1092,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
|
||||
return -ENOMEM;
|
||||
|
||||
uhci_add_td_to_urb(urb, td);
|
||||
uhci_fill_td(td, status, destination | uhci_explen(urb->iso_frame_desc[i].length - 1),
|
||||
uhci_fill_td(td, status, destination | uhci_explen(urb->iso_frame_desc[i].length),
|
||||
urb->transfer_dma + urb->iso_frame_desc[i].offset);
|
||||
|
||||
if (i + 1 >= urb->number_of_packets)
|
||||
@ -1355,7 +1355,7 @@ static void uhci_unlink_generic(struct uhci_hcd *uhci, struct urb *urb)
|
||||
|
||||
uhci_delete_queued_urb(uhci, urb);
|
||||
|
||||
/* The interrupt loop will reclaim the QH's */
|
||||
/* The interrupt loop will reclaim the QHs */
|
||||
uhci_remove_qh(uhci, urbp->qh);
|
||||
urbp->qh = NULL;
|
||||
}
|
||||
@ -1413,7 +1413,7 @@ static int uhci_fsbr_timeout(struct uhci_hcd *uhci, struct urb *urb)
|
||||
list_for_each_entry(td, head, list) {
|
||||
/*
|
||||
* Make sure we don't do the last one (since it'll have the
|
||||
* TERM bit set) as well as we skip every so many TD's to
|
||||
* TERM bit set) as well as we skip every so many TDs to
|
||||
* make sure it doesn't hog the bandwidth
|
||||
*/
|
||||
if (td->list.next != head && (count % DEPTH_INTERVAL) ==
|
||||
|
@ -962,7 +962,6 @@ MODULE_DEVICE_TABLE (usb, mdc800_table);
|
||||
*/
|
||||
static struct usb_driver mdc800_usb_driver =
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.name = "mdc800",
|
||||
.probe = mdc800_usb_probe,
|
||||
.disconnect = mdc800_usb_disconnect,
|
||||
|
@ -160,7 +160,6 @@ static void mts_usb_disconnect(struct usb_interface *intf);
|
||||
static struct usb_device_id mts_usb_ids [];
|
||||
|
||||
static struct usb_driver mts_usb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "microtekX6",
|
||||
.probe = mts_usb_probe,
|
||||
.disconnect = mts_usb_disconnect,
|
||||
|
@ -273,6 +273,20 @@ config USB_ATI_REMOTE
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ati_remote.
|
||||
|
||||
config USB_ATI_REMOTE2
|
||||
tristate "ATI / Philips USB RF remote control"
|
||||
depends on USB && INPUT
|
||||
---help---
|
||||
Say Y here if you want to use an ATI or Philips USB RF remote control.
|
||||
These are RF remotes with USB receivers.
|
||||
ATI Remote Wonder II comes with some ATI's All-In-Wonder video cards
|
||||
and is also available as a separate product.
|
||||
This driver provides mouse pointer, left and right mouse buttons,
|
||||
and maps all the other remote buttons to keypress events.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will be
|
||||
called ati_remote2.
|
||||
|
||||
config USB_KEYSPAN_REMOTE
|
||||
tristate "Keyspan DMR USB remote control (EXPERIMENTAL)"
|
||||
depends on USB && INPUT && EXPERIMENTAL
|
||||
|
@ -28,6 +28,7 @@ endif
|
||||
|
||||
obj-$(CONFIG_USB_AIPTEK) += aiptek.o
|
||||
obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o
|
||||
obj-$(CONFIG_USB_ATI_REMOTE2) += ati_remote2.o
|
||||
obj-$(CONFIG_USB_HID) += usbhid.o
|
||||
obj-$(CONFIG_USB_KBD) += usbkbd.o
|
||||
obj-$(CONFIG_USB_KBTAB) += kbtab.o
|
||||
|
@ -261,7 +261,6 @@ static struct usb_device_id usb_acecad_id_table [] = {
|
||||
MODULE_DEVICE_TABLE(usb, usb_acecad_id_table);
|
||||
|
||||
static struct usb_driver usb_acecad_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "usb_acecad",
|
||||
.probe = usb_acecad_probe,
|
||||
.disconnect = usb_acecad_disconnect,
|
||||
|
@ -338,7 +338,7 @@ struct aiptek {
|
||||
* the bitmap which comes from the tablet. This hides the
|
||||
* issue that the F_keys are not sequentially numbered.
|
||||
*/
|
||||
static int macroKeyEvents[] = {
|
||||
static const int macroKeyEvents[] = {
|
||||
KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5,
|
||||
KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11,
|
||||
KEY_F12, KEY_F13, KEY_F14, KEY_F15, KEY_F16, KEY_F17,
|
||||
@ -2093,7 +2093,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
/* Programming the tablet macro keys needs to be done with a for loop
|
||||
* as the keycodes are discontiguous.
|
||||
*/
|
||||
for (i = 0; i < sizeof(macroKeyEvents) / sizeof(macroKeyEvents[0]); ++i)
|
||||
for (i = 0; i < ARRAY_SIZE(macroKeyEvents); ++i)
|
||||
set_bit(macroKeyEvents[i], inputdev->keybit);
|
||||
|
||||
/*
|
||||
@ -2135,7 +2135,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
* not an error :-)
|
||||
*/
|
||||
|
||||
for (i = 0; i < sizeof(speeds) / sizeof(speeds[0]); ++i) {
|
||||
for (i = 0; i < ARRAY_SIZE(speeds); ++i) {
|
||||
aiptek->curSetting.programmableDelay = speeds[i];
|
||||
(void)aiptek_program_tablet(aiptek);
|
||||
if (aiptek->inputdev->absmax[ABS_X] > 0) {
|
||||
@ -2190,7 +2190,6 @@ fail1: input_free_device(inputdev);
|
||||
static void aiptek_disconnect(struct usb_interface *intf);
|
||||
|
||||
static struct usb_driver aiptek_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "aiptek",
|
||||
.probe = aiptek_probe,
|
||||
.disconnect = aiptek_disconnect,
|
||||
|
@ -452,7 +452,6 @@ static int atp_resume(struct usb_interface *iface)
|
||||
}
|
||||
|
||||
static struct usb_driver atp_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "appletouch",
|
||||
.probe = atp_probe,
|
||||
.disconnect = atp_disconnect,
|
||||
|
@ -96,6 +96,7 @@
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb_input.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/jiffies.h>
|
||||
|
||||
/*
|
||||
* Module and Version Information, Module Parameters
|
||||
@ -146,7 +147,7 @@ static char init1[] = { 0x01, 0x00, 0x20, 0x14 };
|
||||
static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
|
||||
|
||||
/* Acceleration curve for directional control pad */
|
||||
static char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
|
||||
static const char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
|
||||
|
||||
/* Duplicate event filtering time.
|
||||
* Sequential, identical KIND_FILTERED inputs with less than
|
||||
@ -197,7 +198,7 @@ struct ati_remote {
|
||||
#define KIND_ACCEL 7 /* Directional keypad - left, right, up, down.*/
|
||||
|
||||
/* Translation table from hardware messages to input events. */
|
||||
static struct {
|
||||
static const struct {
|
||||
short kind;
|
||||
unsigned char data1, data2;
|
||||
int type;
|
||||
@ -295,7 +296,6 @@ static void ati_remote_disconnect (struct usb_interface *interface);
|
||||
|
||||
/* usb specific object to register with the usb subsystem */
|
||||
static struct usb_driver ati_remote_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "ati_remote",
|
||||
.probe = ati_remote_probe,
|
||||
.disconnect = ati_remote_disconnect,
|
||||
@ -472,7 +472,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
|
||||
/* Filter duplicate events which happen "too close" together. */
|
||||
if ((ati_remote->old_data[0] == data[1]) &&
|
||||
(ati_remote->old_data[1] == data[2]) &&
|
||||
((ati_remote->old_jiffies + FILTER_TIME) > jiffies)) {
|
||||
time_before(jiffies, ati_remote->old_jiffies + FILTER_TIME)) {
|
||||
ati_remote->repeat_count++;
|
||||
} else {
|
||||
ati_remote->repeat_count = 0;
|
||||
@ -507,16 +507,16 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
|
||||
* pad down, so we increase acceleration, ramping up over two seconds to
|
||||
* a maximum speed. The acceleration curve is #defined above.
|
||||
*/
|
||||
if ((jiffies - ati_remote->old_jiffies) > (HZ >> 2)) {
|
||||
if (time_after(jiffies, ati_remote->old_jiffies + (HZ >> 2))) {
|
||||
acc = 1;
|
||||
ati_remote->acc_jiffies = jiffies;
|
||||
}
|
||||
else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 3)) acc = accel[0];
|
||||
else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 2)) acc = accel[1];
|
||||
else if ((jiffies - ati_remote->acc_jiffies) < (HZ >> 1)) acc = accel[2];
|
||||
else if ((jiffies - ati_remote->acc_jiffies) < HZ ) acc = accel[3];
|
||||
else if ((jiffies - ati_remote->acc_jiffies) < HZ+(HZ>>1)) acc = accel[4];
|
||||
else if ((jiffies - ati_remote->acc_jiffies) < (HZ << 1)) acc = accel[5];
|
||||
else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ >> 3))) acc = accel[0];
|
||||
else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ >> 2))) acc = accel[1];
|
||||
else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ >> 1))) acc = accel[2];
|
||||
else if (time_before(jiffies, ati_remote->acc_jiffies + HZ)) acc = accel[3];
|
||||
else if (time_before(jiffies, ati_remote->acc_jiffies + HZ+(HZ>>1))) acc = accel[4];
|
||||
else if (time_before(jiffies, ati_remote->acc_jiffies + (HZ << 1))) acc = accel[5];
|
||||
else acc = accel[6];
|
||||
|
||||
input_regs(dev, regs);
|
||||
|
477
drivers/usb/input/ati_remote2.c
Normal file
477
drivers/usb/input/ati_remote2.c
Normal file
@ -0,0 +1,477 @@
|
||||
/*
|
||||
* ati_remote2 - ATI/Philips USB RF remote driver
|
||||
*
|
||||
* Copyright (C) 2005 Ville Syrjala <syrjala@sci.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/usb_input.h>
|
||||
|
||||
#define DRIVER_DESC "ATI/Philips USB RF remote driver"
|
||||
#define DRIVER_VERSION "0.1"
|
||||
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_VERSION(DRIVER_VERSION);
|
||||
MODULE_AUTHOR("Ville Syrjala <syrjala@sci.fi>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static unsigned int mode_mask = 0x1F;
|
||||
module_param(mode_mask, uint, 0644);
|
||||
MODULE_PARM_DESC(mode_mask, "Bitmask of modes to accept <4:PC><3:AUX4><2:AUX3><1:AUX2><0:AUX1>");
|
||||
|
||||
static struct usb_device_id ati_remote2_id_table[] = {
|
||||
{ USB_DEVICE(0x0471, 0x0602) }, /* ATI Remote Wonder II */
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, ati_remote2_id_table);
|
||||
|
||||
static struct {
|
||||
int hw_code;
|
||||
int key_code;
|
||||
} ati_remote2_key_table[] = {
|
||||
{ 0x00, KEY_0 },
|
||||
{ 0x01, KEY_1 },
|
||||
{ 0x02, KEY_2 },
|
||||
{ 0x03, KEY_3 },
|
||||
{ 0x04, KEY_4 },
|
||||
{ 0x05, KEY_5 },
|
||||
{ 0x06, KEY_6 },
|
||||
{ 0x07, KEY_7 },
|
||||
{ 0x08, KEY_8 },
|
||||
{ 0x09, KEY_9 },
|
||||
{ 0x0c, KEY_POWER },
|
||||
{ 0x0d, KEY_MUTE },
|
||||
{ 0x10, KEY_VOLUMEUP },
|
||||
{ 0x11, KEY_VOLUMEDOWN },
|
||||
{ 0x20, KEY_CHANNELUP },
|
||||
{ 0x21, KEY_CHANNELDOWN },
|
||||
{ 0x28, KEY_FORWARD },
|
||||
{ 0x29, KEY_REWIND },
|
||||
{ 0x2c, KEY_PLAY },
|
||||
{ 0x30, KEY_PAUSE },
|
||||
{ 0x31, KEY_STOP },
|
||||
{ 0x37, KEY_RECORD },
|
||||
{ 0x38, KEY_DVD },
|
||||
{ 0x39, KEY_TV },
|
||||
{ 0x54, KEY_MENU },
|
||||
{ 0x58, KEY_UP },
|
||||
{ 0x59, KEY_DOWN },
|
||||
{ 0x5a, KEY_LEFT },
|
||||
{ 0x5b, KEY_RIGHT },
|
||||
{ 0x5c, KEY_OK },
|
||||
{ 0x78, KEY_A },
|
||||
{ 0x79, KEY_B },
|
||||
{ 0x7a, KEY_C },
|
||||
{ 0x7b, KEY_D },
|
||||
{ 0x7c, KEY_E },
|
||||
{ 0x7d, KEY_F },
|
||||
{ 0x82, KEY_ENTER },
|
||||
{ 0x8e, KEY_VENDOR },
|
||||
{ 0x96, KEY_COFFEE },
|
||||
{ 0xa9, BTN_LEFT },
|
||||
{ 0xaa, BTN_RIGHT },
|
||||
{ 0xbe, KEY_QUESTION },
|
||||
{ 0xd5, KEY_FRONT },
|
||||
{ 0xd0, KEY_EDIT },
|
||||
{ 0xf9, KEY_INFO },
|
||||
{ (0x00 << 8) | 0x3f, KEY_PROG1 },
|
||||
{ (0x01 << 8) | 0x3f, KEY_PROG2 },
|
||||
{ (0x02 << 8) | 0x3f, KEY_PROG3 },
|
||||
{ (0x03 << 8) | 0x3f, KEY_PROG4 },
|
||||
{ (0x04 << 8) | 0x3f, KEY_PC },
|
||||
{ 0, KEY_RESERVED }
|
||||
};
|
||||
|
||||
struct ati_remote2 {
|
||||
struct input_dev *idev;
|
||||
struct usb_device *udev;
|
||||
|
||||
struct usb_interface *intf[2];
|
||||
struct usb_endpoint_descriptor *ep[2];
|
||||
struct urb *urb[2];
|
||||
void *buf[2];
|
||||
dma_addr_t buf_dma[2];
|
||||
|
||||
unsigned long jiffies;
|
||||
int mode;
|
||||
|
||||
char name[64];
|
||||
char phys[64];
|
||||
};
|
||||
|
||||
static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id);
|
||||
static void ati_remote2_disconnect(struct usb_interface *interface);
|
||||
|
||||
static struct usb_driver ati_remote2_driver = {
|
||||
.name = "ati_remote2",
|
||||
.probe = ati_remote2_probe,
|
||||
.disconnect = ati_remote2_disconnect,
|
||||
.id_table = ati_remote2_id_table,
|
||||
};
|
||||
|
||||
static int ati_remote2_open(struct input_dev *idev)
|
||||
{
|
||||
struct ati_remote2 *ar2 = idev->private;
|
||||
int r;
|
||||
|
||||
r = usb_submit_urb(ar2->urb[0], GFP_KERNEL);
|
||||
if (r) {
|
||||
dev_err(&ar2->intf[0]->dev,
|
||||
"%s: usb_submit_urb() = %d\n", __FUNCTION__, r);
|
||||
return r;
|
||||
}
|
||||
r = usb_submit_urb(ar2->urb[1], GFP_KERNEL);
|
||||
if (r) {
|
||||
usb_kill_urb(ar2->urb[0]);
|
||||
dev_err(&ar2->intf[1]->dev,
|
||||
"%s: usb_submit_urb() = %d\n", __FUNCTION__, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ati_remote2_close(struct input_dev *idev)
|
||||
{
|
||||
struct ati_remote2 *ar2 = idev->private;
|
||||
|
||||
usb_kill_urb(ar2->urb[0]);
|
||||
usb_kill_urb(ar2->urb[1]);
|
||||
}
|
||||
|
||||
static void ati_remote2_input_mouse(struct ati_remote2 *ar2, struct pt_regs *regs)
|
||||
{
|
||||
struct input_dev *idev = ar2->idev;
|
||||
u8 *data = ar2->buf[0];
|
||||
|
||||
if (data[0] > 4) {
|
||||
dev_err(&ar2->intf[0]->dev,
|
||||
"Unknown mode byte (%02x %02x %02x %02x)\n",
|
||||
data[3], data[2], data[1], data[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!((1 << data[0]) & mode_mask))
|
||||
return;
|
||||
|
||||
input_regs(idev, regs);
|
||||
input_event(idev, EV_REL, REL_X, (s8) data[1]);
|
||||
input_event(idev, EV_REL, REL_Y, (s8) data[2]);
|
||||
input_sync(idev);
|
||||
}
|
||||
|
||||
static int ati_remote2_lookup(unsigned int hw_code)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++)
|
||||
if (ati_remote2_key_table[i].hw_code == hw_code)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void ati_remote2_input_key(struct ati_remote2 *ar2, struct pt_regs *regs)
|
||||
{
|
||||
struct input_dev *idev = ar2->idev;
|
||||
u8 *data = ar2->buf[1];
|
||||
int hw_code, index;
|
||||
|
||||
if (data[0] > 4) {
|
||||
dev_err(&ar2->intf[1]->dev,
|
||||
"Unknown mode byte (%02x %02x %02x %02x)\n",
|
||||
data[3], data[2], data[1], data[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
hw_code = data[2];
|
||||
/*
|
||||
* Mode keys (AUX1-AUX4, PC) all generate the same code byte.
|
||||
* Use the mode byte to figure out which one was pressed.
|
||||
*/
|
||||
if (hw_code == 0x3f) {
|
||||
/*
|
||||
* For some incomprehensible reason the mouse pad generates
|
||||
* events which look identical to the events from the last
|
||||
* pressed mode key. Naturally we don't want to generate key
|
||||
* events for the mouse pad so we filter out any subsequent
|
||||
* events from the same mode key.
|
||||
*/
|
||||
if (ar2->mode == data[0])
|
||||
return;
|
||||
|
||||
if (data[1] == 0)
|
||||
ar2->mode = data[0];
|
||||
|
||||
hw_code |= data[0] << 8;
|
||||
}
|
||||
|
||||
if (!((1 << data[0]) & mode_mask))
|
||||
return;
|
||||
|
||||
index = ati_remote2_lookup(hw_code);
|
||||
if (index < 0) {
|
||||
dev_err(&ar2->intf[1]->dev,
|
||||
"Unknown code byte (%02x %02x %02x %02x)\n",
|
||||
data[3], data[2], data[1], data[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (data[1]) {
|
||||
case 0: /* release */
|
||||
break;
|
||||
case 1: /* press */
|
||||
ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_DELAY]);
|
||||
break;
|
||||
case 2: /* repeat */
|
||||
|
||||
/* No repeat for mouse buttons. */
|
||||
if (ati_remote2_key_table[index].key_code == BTN_LEFT ||
|
||||
ati_remote2_key_table[index].key_code == BTN_RIGHT)
|
||||
return;
|
||||
|
||||
if (!time_after_eq(jiffies, ar2->jiffies))
|
||||
return;
|
||||
|
||||
ar2->jiffies = jiffies + msecs_to_jiffies(idev->rep[REP_PERIOD]);
|
||||
break;
|
||||
default:
|
||||
dev_err(&ar2->intf[1]->dev,
|
||||
"Unknown state byte (%02x %02x %02x %02x)\n",
|
||||
data[3], data[2], data[1], data[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
input_regs(idev, regs);
|
||||
input_event(idev, EV_KEY, ati_remote2_key_table[index].key_code, data[1]);
|
||||
input_sync(idev);
|
||||
}
|
||||
|
||||
static void ati_remote2_complete_mouse(struct urb *urb, struct pt_regs *regs)
|
||||
{
|
||||
struct ati_remote2 *ar2 = urb->context;
|
||||
int r;
|
||||
|
||||
switch (urb->status) {
|
||||
case 0:
|
||||
ati_remote2_input_mouse(ar2, regs);
|
||||
break;
|
||||
case -ENOENT:
|
||||
case -EILSEQ:
|
||||
case -ECONNRESET:
|
||||
case -ESHUTDOWN:
|
||||
dev_dbg(&ar2->intf[0]->dev,
|
||||
"%s(): urb status = %d\n", __FUNCTION__, urb->status);
|
||||
return;
|
||||
default:
|
||||
dev_err(&ar2->intf[0]->dev,
|
||||
"%s(): urb status = %d\n", __FUNCTION__, urb->status);
|
||||
}
|
||||
|
||||
r = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (r)
|
||||
dev_err(&ar2->intf[0]->dev,
|
||||
"%s(): usb_submit_urb() = %d\n", __FUNCTION__, r);
|
||||
}
|
||||
|
||||
static void ati_remote2_complete_key(struct urb *urb, struct pt_regs *regs)
|
||||
{
|
||||
struct ati_remote2 *ar2 = urb->context;
|
||||
int r;
|
||||
|
||||
switch (urb->status) {
|
||||
case 0:
|
||||
ati_remote2_input_key(ar2, regs);
|
||||
break;
|
||||
case -ENOENT:
|
||||
case -EILSEQ:
|
||||
case -ECONNRESET:
|
||||
case -ESHUTDOWN:
|
||||
dev_dbg(&ar2->intf[1]->dev,
|
||||
"%s(): urb status = %d\n", __FUNCTION__, urb->status);
|
||||
return;
|
||||
default:
|
||||
dev_err(&ar2->intf[1]->dev,
|
||||
"%s(): urb status = %d\n", __FUNCTION__, urb->status);
|
||||
}
|
||||
|
||||
r = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (r)
|
||||
dev_err(&ar2->intf[1]->dev,
|
||||
"%s(): usb_submit_urb() = %d\n", __FUNCTION__, r);
|
||||
}
|
||||
|
||||
static int ati_remote2_input_init(struct ati_remote2 *ar2)
|
||||
{
|
||||
struct input_dev *idev;
|
||||
int i;
|
||||
|
||||
idev = input_allocate_device();
|
||||
if (!idev)
|
||||
return -ENOMEM;
|
||||
|
||||
ar2->idev = idev;
|
||||
idev->private = ar2;
|
||||
|
||||
idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_REL);
|
||||
idev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
|
||||
idev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
|
||||
for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++)
|
||||
set_bit(ati_remote2_key_table[i].key_code, idev->keybit);
|
||||
|
||||
idev->rep[REP_DELAY] = 250;
|
||||
idev->rep[REP_PERIOD] = 33;
|
||||
|
||||
idev->open = ati_remote2_open;
|
||||
idev->close = ati_remote2_close;
|
||||
|
||||
idev->name = ar2->name;
|
||||
idev->phys = ar2->phys;
|
||||
|
||||
usb_to_input_id(ar2->udev, &idev->id);
|
||||
idev->cdev.dev = &ar2->udev->dev;
|
||||
|
||||
i = input_register_device(idev);
|
||||
if (i)
|
||||
input_free_device(idev);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static int ati_remote2_urb_init(struct ati_remote2 *ar2)
|
||||
{
|
||||
struct usb_device *udev = ar2->udev;
|
||||
int i, pipe, maxp;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
ar2->buf[i] = usb_buffer_alloc(udev, 4, GFP_KERNEL, &ar2->buf_dma[i]);
|
||||
if (!ar2->buf[i])
|
||||
return -ENOMEM;
|
||||
|
||||
ar2->urb[i] = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!ar2->urb[i])
|
||||
return -ENOMEM;
|
||||
|
||||
pipe = usb_rcvintpipe(udev, ar2->ep[i]->bEndpointAddress);
|
||||
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
|
||||
maxp = maxp > 4 ? 4 : maxp;
|
||||
|
||||
usb_fill_int_urb(ar2->urb[i], udev, pipe, ar2->buf[i], maxp,
|
||||
i ? ati_remote2_complete_key : ati_remote2_complete_mouse,
|
||||
ar2, ar2->ep[i]->bInterval);
|
||||
ar2->urb[i]->transfer_dma = ar2->buf_dma[i];
|
||||
ar2->urb[i]->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ati_remote2_urb_cleanup(struct ati_remote2 *ar2)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (ar2->urb[i])
|
||||
usb_free_urb(ar2->urb[i]);
|
||||
|
||||
if (ar2->buf[i])
|
||||
usb_buffer_free(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(interface);
|
||||
struct usb_host_interface *alt = interface->cur_altsetting;
|
||||
struct ati_remote2 *ar2;
|
||||
int r;
|
||||
|
||||
if (alt->desc.bInterfaceNumber)
|
||||
return -ENODEV;
|
||||
|
||||
ar2 = kzalloc(sizeof (struct ati_remote2), GFP_KERNEL);
|
||||
if (!ar2)
|
||||
return -ENOMEM;
|
||||
|
||||
ar2->udev = udev;
|
||||
|
||||
ar2->intf[0] = interface;
|
||||
ar2->ep[0] = &alt->endpoint[0].desc;
|
||||
|
||||
ar2->intf[1] = usb_ifnum_to_if(udev, 1);
|
||||
r = usb_driver_claim_interface(&ati_remote2_driver, ar2->intf[1], ar2);
|
||||
if (r)
|
||||
goto fail1;
|
||||
alt = ar2->intf[1]->cur_altsetting;
|
||||
ar2->ep[1] = &alt->endpoint[0].desc;
|
||||
|
||||
r = ati_remote2_urb_init(ar2);
|
||||
if (r)
|
||||
goto fail2;
|
||||
|
||||
usb_make_path(udev, ar2->phys, sizeof(ar2->phys));
|
||||
strlcat(ar2->phys, "/input0", sizeof(ar2->phys));
|
||||
|
||||
strlcat(ar2->name, "ATI Remote Wonder II", sizeof(ar2->name));
|
||||
|
||||
r = ati_remote2_input_init(ar2);
|
||||
if (r)
|
||||
goto fail2;
|
||||
|
||||
usb_set_intfdata(interface, ar2);
|
||||
|
||||
return 0;
|
||||
|
||||
fail2:
|
||||
ati_remote2_urb_cleanup(ar2);
|
||||
|
||||
usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
|
||||
fail1:
|
||||
kfree(ar2);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void ati_remote2_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct ati_remote2 *ar2;
|
||||
struct usb_host_interface *alt = interface->cur_altsetting;
|
||||
|
||||
if (alt->desc.bInterfaceNumber)
|
||||
return;
|
||||
|
||||
ar2 = usb_get_intfdata(interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
|
||||
input_unregister_device(ar2->idev);
|
||||
|
||||
ati_remote2_urb_cleanup(ar2);
|
||||
|
||||
usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
|
||||
|
||||
kfree(ar2);
|
||||
}
|
||||
|
||||
static int __init ati_remote2_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
r = usb_register(&ati_remote2_driver);
|
||||
if (r)
|
||||
printk(KERN_ERR "ati_remote2: usb_register() = %d\n", r);
|
||||
else
|
||||
printk(KERN_INFO "ati_remote2: " DRIVER_DESC " " DRIVER_VERSION "\n");
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static void __exit ati_remote2_exit(void)
|
||||
{
|
||||
usb_deregister(&ati_remote2_driver);
|
||||
}
|
||||
|
||||
module_init(ati_remote2_init);
|
||||
module_exit(ati_remote2_exit);
|
@ -38,7 +38,7 @@ typedef s16 fixp_t;
|
||||
#define FRAC_MASK ((1<<FRAC_N)-1)
|
||||
|
||||
// Not to be used directly. Use fixp_{cos,sin}
|
||||
static fixp_t cos_table[45] = {
|
||||
static const fixp_t cos_table[45] = {
|
||||
0x0100, 0x00FF, 0x00FF, 0x00FE, 0x00FD, 0x00FC, 0x00FA, 0x00F8,
|
||||
0x00F6, 0x00F3, 0x00F0, 0x00ED, 0x00E9, 0x00E6, 0x00E2, 0x00DD,
|
||||
0x00D9, 0x00D4, 0x00CF, 0x00C9, 0x00C4, 0x00BE, 0x00B8, 0x00B1,
|
||||
|
@ -1454,7 +1454,7 @@ void hid_init_reports(struct hid_device *hid)
|
||||
* Alphabetically sorted blacklist by quirk type.
|
||||
*/
|
||||
|
||||
static struct hid_blacklist {
|
||||
static const struct hid_blacklist {
|
||||
__u16 idVendor;
|
||||
__u16 idProduct;
|
||||
unsigned quirks;
|
||||
@ -1930,7 +1930,6 @@ static struct usb_device_id hid_usb_ids [] = {
|
||||
MODULE_DEVICE_TABLE (usb, hid_usb_ids);
|
||||
|
||||
static struct usb_driver hid_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "usbhid",
|
||||
.probe = hid_probe,
|
||||
.disconnect = hid_disconnect,
|
||||
|
@ -39,7 +39,7 @@
|
||||
|
||||
#define unk KEY_UNKNOWN
|
||||
|
||||
static unsigned char hid_keyboard[256] = {
|
||||
static const unsigned char hid_keyboard[256] = {
|
||||
0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
|
||||
50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
|
||||
4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
|
||||
@ -58,7 +58,7 @@ static unsigned char hid_keyboard[256] = {
|
||||
150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
|
||||
};
|
||||
|
||||
static struct {
|
||||
static const struct {
|
||||
__s32 x;
|
||||
__s32 y;
|
||||
} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
|
||||
|
@ -826,7 +826,6 @@ static int hiddev_usbd_probe(struct usb_interface *intf,
|
||||
|
||||
|
||||
static /* const */ struct usb_driver hiddev_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "hiddev",
|
||||
.probe = hiddev_usbd_probe,
|
||||
};
|
||||
|
@ -250,7 +250,6 @@ static void itmtouch_disconnect(struct usb_interface *intf)
|
||||
MODULE_DEVICE_TABLE(usb, itmtouch_ids);
|
||||
|
||||
static struct usb_driver itmtouch_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "itmtouch",
|
||||
.probe = itmtouch_probe,
|
||||
.disconnect = itmtouch_disconnect,
|
||||
|
@ -197,7 +197,6 @@ static void kbtab_disconnect(struct usb_interface *intf)
|
||||
}
|
||||
|
||||
static struct usb_driver kbtab_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "kbtab",
|
||||
.probe = kbtab_probe,
|
||||
.disconnect = kbtab_disconnect,
|
||||
|
@ -95,7 +95,7 @@ struct usb_keyspan {
|
||||
* Currently there are 15 and 17 button models so RESERVED codes
|
||||
* are blank areas in the mapping.
|
||||
*/
|
||||
static int keyspan_key_table[] = {
|
||||
static const int keyspan_key_table[] = {
|
||||
KEY_RESERVED, /* 0 is just a place holder. */
|
||||
KEY_RESERVED,
|
||||
KEY_STOP,
|
||||
@ -559,7 +559,6 @@ static void keyspan_disconnect(struct usb_interface *interface)
|
||||
*/
|
||||
static struct usb_driver keyspan_driver =
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.name = "keyspan_remote",
|
||||
.probe = keyspan_probe,
|
||||
.disconnect = keyspan_disconnect,
|
||||
|
@ -310,7 +310,6 @@ static void mtouchusb_disconnect(struct usb_interface *intf)
|
||||
MODULE_DEVICE_TABLE(usb, mtouchusb_devices);
|
||||
|
||||
static struct usb_driver mtouchusb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "mtouchusb",
|
||||
.probe = mtouchusb_probe,
|
||||
.disconnect = mtouchusb_disconnect,
|
||||
|
@ -441,7 +441,6 @@ static struct usb_device_id powermate_devices [] = {
|
||||
MODULE_DEVICE_TABLE (usb, powermate_devices);
|
||||
|
||||
static struct usb_driver powermate_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "powermate",
|
||||
.probe = powermate_probe,
|
||||
.disconnect = powermate_disconnect,
|
||||
|
@ -1,7 +1,7 @@
|
||||
/******************************************************************************
|
||||
* touchkitusb.c -- Driver for eGalax TouchKit USB Touchscreens
|
||||
*
|
||||
* Copyright (C) 2004 by Daniel Ritz
|
||||
* Copyright (C) 2004-2005 by Daniel Ritz <daniel.ritz@gmx.ch>
|
||||
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@ -41,15 +41,13 @@
|
||||
#define TOUCHKIT_MAX_YC 0x07ff
|
||||
#define TOUCHKIT_YC_FUZZ 0x0
|
||||
#define TOUCHKIT_YC_FLAT 0x0
|
||||
#define TOUCHKIT_REPORT_DATA_SIZE 8
|
||||
#define TOUCHKIT_REPORT_DATA_SIZE 16
|
||||
|
||||
#define TOUCHKIT_DOWN 0x01
|
||||
#define TOUCHKIT_POINT_TOUCH 0x81
|
||||
#define TOUCHKIT_POINT_NOTOUCH 0x80
|
||||
|
||||
#define TOUCHKIT_GET_TOUCHED(dat) ((((dat)[0]) & TOUCHKIT_DOWN) ? 1 : 0)
|
||||
#define TOUCHKIT_GET_X(dat) (((dat)[3] << 7) | (dat)[4])
|
||||
#define TOUCHKIT_GET_Y(dat) (((dat)[1] << 7) | (dat)[2])
|
||||
#define TOUCHKIT_PKT_TYPE_MASK 0xFE
|
||||
#define TOUCHKIT_PKT_TYPE_REPT 0x80
|
||||
#define TOUCHKIT_PKT_TYPE_DIAG 0x0A
|
||||
|
||||
#define DRIVER_VERSION "v0.1"
|
||||
#define DRIVER_AUTHOR "Daniel Ritz <daniel.ritz@gmx.ch>"
|
||||
@ -62,6 +60,8 @@ MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped.");
|
||||
struct touchkit_usb {
|
||||
unsigned char *data;
|
||||
dma_addr_t data_dma;
|
||||
char buffer[TOUCHKIT_REPORT_DATA_SIZE];
|
||||
int buf_len;
|
||||
struct urb *irq;
|
||||
struct usb_device *udev;
|
||||
struct input_dev *input;
|
||||
@ -77,11 +77,128 @@ static struct usb_device_id touchkit_devices[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
/* helpers to read the data */
|
||||
static inline int touchkit_get_touched(char *data)
|
||||
{
|
||||
return (data[0] & TOUCHKIT_DOWN) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline int touchkit_get_x(char *data)
|
||||
{
|
||||
return ((data[3] & 0x0F) << 7) | (data[4] & 0x7F);
|
||||
}
|
||||
|
||||
static inline int touchkit_get_y(char *data)
|
||||
{
|
||||
return ((data[1] & 0x0F) << 7) | (data[2] & 0x7F);
|
||||
}
|
||||
|
||||
|
||||
/* processes one input packet. */
|
||||
static void touchkit_process_pkt(struct touchkit_usb *touchkit,
|
||||
struct pt_regs *regs, char *pkt)
|
||||
{
|
||||
int x, y;
|
||||
|
||||
/* only process report packets */
|
||||
if ((pkt[0] & TOUCHKIT_PKT_TYPE_MASK) != TOUCHKIT_PKT_TYPE_REPT)
|
||||
return;
|
||||
|
||||
if (swap_xy) {
|
||||
y = touchkit_get_x(pkt);
|
||||
x = touchkit_get_y(pkt);
|
||||
} else {
|
||||
x = touchkit_get_x(pkt);
|
||||
y = touchkit_get_y(pkt);
|
||||
}
|
||||
|
||||
input_regs(touchkit->input, regs);
|
||||
input_report_key(touchkit->input, BTN_TOUCH, touchkit_get_touched(pkt));
|
||||
input_report_abs(touchkit->input, ABS_X, x);
|
||||
input_report_abs(touchkit->input, ABS_Y, y);
|
||||
input_sync(touchkit->input);
|
||||
}
|
||||
|
||||
|
||||
static int touchkit_get_pkt_len(char *buf)
|
||||
{
|
||||
switch (buf[0] & TOUCHKIT_PKT_TYPE_MASK) {
|
||||
case TOUCHKIT_PKT_TYPE_REPT:
|
||||
return 5;
|
||||
|
||||
case TOUCHKIT_PKT_TYPE_DIAG:
|
||||
return buf[1] + 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void touchkit_process(struct touchkit_usb *touchkit, int len,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
char *buffer;
|
||||
int pkt_len, buf_len, pos;
|
||||
|
||||
/* if the buffer contains data, append */
|
||||
if (unlikely(touchkit->buf_len)) {
|
||||
int tmp;
|
||||
|
||||
/* if only 1 byte in buffer, add another one to get length */
|
||||
if (touchkit->buf_len == 1)
|
||||
touchkit->buffer[1] = touchkit->data[0];
|
||||
|
||||
pkt_len = touchkit_get_pkt_len(touchkit->buffer);
|
||||
|
||||
/* unknown packet: drop everything */
|
||||
if (!pkt_len)
|
||||
return;
|
||||
|
||||
/* append, process */
|
||||
tmp = pkt_len - touchkit->buf_len;
|
||||
memcpy(touchkit->buffer + touchkit->buf_len, touchkit->data, tmp);
|
||||
touchkit_process_pkt(touchkit, regs, touchkit->buffer);
|
||||
|
||||
buffer = touchkit->data + tmp;
|
||||
buf_len = len - tmp;
|
||||
} else {
|
||||
buffer = touchkit->data;
|
||||
buf_len = len;
|
||||
}
|
||||
|
||||
/* only one byte left in buffer */
|
||||
if (unlikely(buf_len == 1)) {
|
||||
touchkit->buffer[0] = buffer[0];
|
||||
touchkit->buf_len = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* loop over the buffer */
|
||||
pos = 0;
|
||||
while (pos < buf_len) {
|
||||
/* get packet len */
|
||||
pkt_len = touchkit_get_pkt_len(buffer + pos);
|
||||
|
||||
/* unknown packet: drop everything */
|
||||
if (unlikely(!pkt_len))
|
||||
return;
|
||||
|
||||
/* full packet: process */
|
||||
if (likely(pkt_len <= buf_len)) {
|
||||
touchkit_process_pkt(touchkit, regs, buffer + pos);
|
||||
} else {
|
||||
/* incomplete packet: save in buffer */
|
||||
memcpy(touchkit->buffer, buffer + pos, buf_len - pos);
|
||||
touchkit->buf_len = buf_len - pos;
|
||||
}
|
||||
pos += pkt_len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void touchkit_irq(struct urb *urb, struct pt_regs *regs)
|
||||
{
|
||||
struct touchkit_usb *touchkit = urb->context;
|
||||
int retval;
|
||||
int x, y;
|
||||
|
||||
switch (urb->status) {
|
||||
case 0:
|
||||
@ -105,20 +222,7 @@ static void touchkit_irq(struct urb *urb, struct pt_regs *regs)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (swap_xy) {
|
||||
y = TOUCHKIT_GET_X(touchkit->data);
|
||||
x = TOUCHKIT_GET_Y(touchkit->data);
|
||||
} else {
|
||||
x = TOUCHKIT_GET_X(touchkit->data);
|
||||
y = TOUCHKIT_GET_Y(touchkit->data);
|
||||
}
|
||||
|
||||
input_regs(touchkit->input, regs);
|
||||
input_report_key(touchkit->input, BTN_TOUCH,
|
||||
TOUCHKIT_GET_TOUCHED(touchkit->data));
|
||||
input_report_abs(touchkit->input, ABS_X, x);
|
||||
input_report_abs(touchkit->input, ABS_Y, y);
|
||||
input_sync(touchkit->input);
|
||||
touchkit_process(touchkit, urb->actual_length, regs);
|
||||
|
||||
exit:
|
||||
retval = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
@ -267,7 +371,6 @@ static void touchkit_disconnect(struct usb_interface *intf)
|
||||
MODULE_DEVICE_TABLE(usb, touchkit_devices);
|
||||
|
||||
static struct usb_driver touchkit_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "touchkitusb",
|
||||
.probe = touchkit_probe,
|
||||
.disconnect = touchkit_disconnect,
|
||||
|
@ -345,7 +345,6 @@ static struct usb_device_id usb_kbd_id_table [] = {
|
||||
MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);
|
||||
|
||||
static struct usb_driver usb_kbd_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "usbkbd",
|
||||
.probe = usb_kbd_probe,
|
||||
.disconnect = usb_kbd_disconnect,
|
||||
|
@ -226,7 +226,6 @@ static struct usb_device_id usb_mouse_id_table [] = {
|
||||
MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
|
||||
|
||||
static struct usb_driver usb_mouse_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "usbmouse",
|
||||
.probe = usb_mouse_probe,
|
||||
.disconnect = usb_mouse_disconnect,
|
||||
|
@ -945,7 +945,6 @@ static void wacom_disconnect(struct usb_interface *intf)
|
||||
}
|
||||
|
||||
static struct usb_driver wacom_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "wacom",
|
||||
.probe = wacom_probe,
|
||||
.disconnect = wacom_disconnect,
|
||||
|
@ -70,7 +70,7 @@
|
||||
|
||||
#define XPAD_PKT_LEN 32
|
||||
|
||||
static struct xpad_device {
|
||||
static const struct xpad_device {
|
||||
u16 idVendor;
|
||||
u16 idProduct;
|
||||
char *name;
|
||||
@ -81,13 +81,13 @@ static struct xpad_device {
|
||||
{ 0x0000, 0x0000, "X-Box pad" }
|
||||
};
|
||||
|
||||
static signed short xpad_btn[] = {
|
||||
static const signed short xpad_btn[] = {
|
||||
BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, /* "analog" buttons */
|
||||
BTN_START, BTN_BACK, BTN_THUMBL, BTN_THUMBR, /* start/back/sticks */
|
||||
-1 /* terminating entry */
|
||||
};
|
||||
|
||||
static signed short xpad_abs[] = {
|
||||
static const signed short xpad_abs[] = {
|
||||
ABS_X, ABS_Y, /* left stick */
|
||||
ABS_RX, ABS_RY, /* right stick */
|
||||
ABS_Z, ABS_RZ, /* triggers left/right */
|
||||
@ -316,7 +316,6 @@ static void xpad_disconnect(struct usb_interface *intf)
|
||||
}
|
||||
|
||||
static struct usb_driver xpad_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "xpad",
|
||||
.probe = xpad_probe,
|
||||
.disconnect = xpad_disconnect,
|
||||
|
@ -987,7 +987,6 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
}
|
||||
|
||||
static struct usb_driver yealink_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "yealink",
|
||||
.probe = usb_probe,
|
||||
.disconnect = usb_disconnect,
|
||||
|
@ -812,7 +812,6 @@ static struct usb_device_id dabusb_ids [] = {
|
||||
MODULE_DEVICE_TABLE (usb, dabusb_ids);
|
||||
|
||||
static struct usb_driver dabusb_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "dabusb",
|
||||
.probe = dabusb_probe,
|
||||
.disconnect = dabusb_disconnect,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user