diff options
Diffstat (limited to 'drivers/usb')
155 files changed, 5839 insertions, 5119 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index f9b1719b9a37..9980a4ddfed9 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -24,7 +24,7 @@ config USB_ARCH_HAS_OHCI default y if ARCH_S3C2410 default y if PXA27x default y if ARCH_EP93XX - default y if (ARCH_AT91RM9200 || ARCH_AT91SAM9261) + default y if ARCH_AT91 default y if ARCH_PNX4008 # PPC: default y if STB03xxx diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 97d57cfc343b..825bf884537a 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -33,7 +33,6 @@ obj-$(CONFIG_USB_KBTAB) += input/ obj-$(CONFIG_USB_MOUSE) += input/ obj-$(CONFIG_USB_MTOUCH) += input/ obj-$(CONFIG_USB_POWERMATE) += input/ -obj-$(CONFIG_USB_TRANCEVIBRATOR)+= input/ obj-$(CONFIG_USB_WACOM) += input/ obj-$(CONFIG_USB_XPAD) += input/ @@ -66,6 +65,7 @@ obj-$(CONFIG_USB_PHIDGETSERVO) += misc/ obj-$(CONFIG_USB_RIO500) += misc/ obj-$(CONFIG_USB_SISUSBVGA) += misc/ obj-$(CONFIG_USB_TEST) += misc/ +obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/ obj-$(CONFIG_USB_USS720) += misc/ obj-$(CONFIG_USB_ATM) += atm/ diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 3892a9e9aee3..3dfa3e40e148 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -158,7 +158,7 @@ struct cxacru_data { const struct cxacru_modem_type *modem_type; int line_status; - struct work_struct poll_work; + struct delayed_work poll_work; /* contol handles */ struct mutex cm_serialize; @@ -347,7 +347,7 @@ static int cxacru_card_status(struct cxacru_data *instance) return 0; } -static void cxacru_poll_status(struct cxacru_data *instance); +static void cxacru_poll_status(struct work_struct *work); static int cxacru_atm_start(struct usbatm_data *usbatm_instance, struct atm_dev *atm_dev) @@ -376,12 +376,14 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance, } /* Start status polling */ - cxacru_poll_status(instance); + cxacru_poll_status(&instance->poll_work.work); return 0; } -static void cxacru_poll_status(struct cxacru_data *instance) +static void cxacru_poll_status(struct work_struct *work) { + struct cxacru_data *instance = + container_of(work, struct cxacru_data, poll_work.work); u32 buf[CXINF_MAX] = {}; struct usbatm_data *usbatm = instance->usbatm; struct atm_dev *atm_dev = usbatm->atm_dev; @@ -720,7 +722,7 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, mutex_init(&instance->cm_serialize); - INIT_WORK(&instance->poll_work, (void *)cxacru_poll_status, instance); + INIT_DELAYED_WORK(&instance->poll_work, cxacru_poll_status); usbatm_instance->driver_data = instance; @@ -793,6 +795,9 @@ static const struct usb_device_id cxacru_usb_ids[] = { { /* V = Conexant P = ADSL modem */ USB_DEVICE(0x0572, 0xcb06), .driver_info = (unsigned long) &cxacru_cb00 }, + { /* V = Conexant P = ADSL modem (ZTE ZXDSL 852) */ + USB_DEVICE(0x0572, 0xcb07), .driver_info = (unsigned long) &cxacru_cb00 + }, { /* V = Olitec P = ADSL modem version 2 */ USB_DEVICE(0x08e3, 0x0100), .driver_info = (unsigned long) &cxacru_cafe }, diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 7c7b507af29d..8ed6c75adf0f 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -55,7 +55,6 @@ static const char speedtch_driver_name[] = "speedtch"; #define OFFSET_d 9 /* size 4 */ #define OFFSET_e 13 /* size 1 */ #define OFFSET_f 14 /* size 1 */ -#define TOTAL 15 #define SIZE_7 1 #define SIZE_b 8 @@ -79,6 +78,18 @@ static int dl_512_first = DEFAULT_DL_512_FIRST; static int enable_isoc = DEFAULT_ENABLE_ISOC; static int sw_buffering = DEFAULT_SW_BUFFERING; +#define DEFAULT_B_MAX_DSL 8128 +#define DEFAULT_MODEM_MODE 11 +#define MODEM_OPTION_LENGTH 16 +static const unsigned char DEFAULT_MODEM_OPTION[MODEM_OPTION_LENGTH] = { + 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static unsigned int BMaxDSL = DEFAULT_B_MAX_DSL; +static unsigned char ModemMode = DEFAULT_MODEM_MODE; +static unsigned char ModemOption[MODEM_OPTION_LENGTH]; +static int num_ModemOption; + module_param(altsetting, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(altsetting, "Alternative setting for data interface (bulk_default: " @@ -100,6 +111,17 @@ MODULE_PARM_DESC(sw_buffering, "Enable software buffering (default: " __MODULE_STRING(DEFAULT_SW_BUFFERING) ")"); +module_param(BMaxDSL, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(BMaxDSL, + "default: " __MODULE_STRING(DEFAULT_B_MAX_DSL)); + +module_param(ModemMode, byte, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(ModemMode, + "default: " __MODULE_STRING(DEFAULT_MODEM_MODE)); + +module_param_array(ModemOption, byte, &num_ModemOption, S_IRUGO); +MODULE_PARM_DESC(ModemOption, "default: 0x10,0x00,0x00,0x00,0x20"); + #define INTERFACE_DATA 1 #define ENDPOINT_INT 0x81 #define ENDPOINT_BULK_DATA 0x07 @@ -108,12 +130,19 @@ MODULE_PARM_DESC(sw_buffering, #define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) ) +struct speedtch_params { + unsigned int altsetting; + unsigned int BMaxDSL; + unsigned char ModemMode; + unsigned char ModemOption[MODEM_OPTION_LENGTH]; +}; + struct speedtch_instance_data { struct usbatm_data *usbatm; - unsigned int altsetting; + struct speedtch_params params; /* set in probe, constant afterwards */ - struct work_struct status_checker; + struct delayed_work status_checker; unsigned char last_status; @@ -123,7 +152,7 @@ struct speedtch_instance_data { struct urb *int_urb; unsigned char int_data[16]; - unsigned char scratch_buffer[TOTAL]; + unsigned char scratch_buffer[16]; }; /*************** @@ -186,6 +215,34 @@ static void speedtch_test_sequence(struct speedtch_instance_data *instance) 0x01, 0x40, 0x04, 0x00, buf, 3, CTRL_TIMEOUT); if (ret < 0) usb_warn(usbatm, "%s failed on URB150: %d\n", __func__, ret); + + /* Extra initialisation in recent drivers - gives higher speeds */ + + /* URBext1 */ + buf[0] = instance->params.ModemMode; + ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + 0x01, 0x40, 0x11, 0x00, buf, 1, CTRL_TIMEOUT); + if (ret < 0) + usb_warn(usbatm, "%s failed on URBext1: %d\n", __func__, ret); + + /* URBext2 */ + /* This seems to be the one which actually triggers the higher sync + rate -- it does require the new firmware too, although it works OK + with older firmware */ + ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + 0x01, 0x40, 0x14, 0x00, + instance->params.ModemOption, + MODEM_OPTION_LENGTH, CTRL_TIMEOUT); + if (ret < 0) + usb_warn(usbatm, "%s failed on URBext2: %d\n", __func__, ret); + + /* URBext3 */ + buf[0] = instance->params.BMaxDSL & 0xff; + buf[1] = instance->params.BMaxDSL >> 8; + ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), + 0x01, 0x40, 0x12, 0x00, buf, 2, CTRL_TIMEOUT); + if (ret < 0) + usb_warn(usbatm, "%s failed on URBext3: %d\n", __func__, ret); } static int speedtch_upload_firmware(struct speedtch_instance_data *instance, @@ -285,8 +342,8 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance, because we're in our own kernel thread anyway. */ msleep_interruptible(1000); - if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) { - usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->altsetting, ret); + if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) { + usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->params.altsetting, ret); goto out_free; } @@ -372,7 +429,7 @@ static int speedtch_read_status(struct speedtch_instance_data *instance) unsigned char *buf = instance->scratch_buffer; int ret; - memset(buf, 0, TOTAL); + memset(buf, 0, 16); ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), 0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7, @@ -441,8 +498,11 @@ static int speedtch_start_synchro(struct speedtch_instance_data *instance) return ret; } -static void speedtch_check_status(struct speedtch_instance_data *instance) +static void speedtch_check_status(struct work_struct *work) { + struct speedtch_instance_data *instance = + container_of(work, struct speedtch_instance_data, + status_checker.work); struct usbatm_data *usbatm = instance->usbatm; struct atm_dev *atm_dev = usbatm->atm_dev; unsigned char *buf = instance->scratch_buffer; @@ -519,7 +579,7 @@ static void speedtch_status_poll(unsigned long data) { struct speedtch_instance_data *instance = (void *)data; - schedule_work(&instance->status_checker); + schedule_delayed_work(&instance->status_checker, 0); /* The following check is racy, but the race is harmless */ if (instance->poll_delay < MAX_POLL_DELAY) @@ -539,7 +599,7 @@ static void speedtch_resubmit_int(unsigned long data) if (int_urb) { ret = usb_submit_urb(int_urb, GFP_ATOMIC); if (!ret) - schedule_work(&instance->status_checker); + schedule_delayed_work(&instance->status_checker, 0); else { atm_dbg(instance->usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret); mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY)); @@ -583,7 +643,7 @@ static void speedtch_handle_int(struct urb *int_urb) if ((int_urb = instance->int_urb)) { ret = usb_submit_urb(int_urb, GFP_ATOMIC); - schedule_work(&instance->status_checker); + schedule_delayed_work(&instance->status_checker, 0); if (ret < 0) { atm_dbg(usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret); goto fail; @@ -746,17 +806,21 @@ static int speedtch_bind(struct usbatm_data *usbatm, instance->usbatm = usbatm; - /* altsetting and enable_isoc may change at any moment, so take a snapshot */ - instance->altsetting = altsetting; + /* module parameters may change at any moment, so take a snapshot */ + instance->params.altsetting = altsetting; + instance->params.BMaxDSL = BMaxDSL; + instance->params.ModemMode = ModemMode; + memcpy(instance->params.ModemOption, DEFAULT_MODEM_OPTION, MODEM_OPTION_LENGTH); + memcpy(instance->params.ModemOption, ModemOption, num_ModemOption); use_isoc = enable_isoc; - if (instance->altsetting) - if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) { - usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->altsetting, ret); - instance->altsetting = 0; /* fall back to default */ + if (instance->params.altsetting) + if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) { + usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->params.altsetting, ret); + instance->params.altsetting = 0; /* fall back to default */ } - if (!instance->altsetting && use_isoc) + if (!instance->params.altsetting && use_isoc) if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_ISOC_ALTSETTING)) < 0) { usb_dbg(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_ISOC_ALTSETTING, ret); use_isoc = 0; /* fall back to bulk */ @@ -773,8 +837,8 @@ static int speedtch_bind(struct usbatm_data *usbatm, const struct usb_endpoint_descriptor *endpoint_desc = &desc->endpoint[i].desc; if ((endpoint_desc->bEndpointAddress == target_address)) { - use_isoc = (endpoint_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_ISOC; + use_isoc = + usb_endpoint_xfer_isoc(endpoint_desc); break; } } @@ -783,18 +847,18 @@ static int speedtch_bind(struct usbatm_data *usbatm, usb_info(usbatm, "isochronous transfer not supported - using bulk\n"); } - if (!use_isoc && !instance->altsetting) + if (!use_isoc && !instance->params.altsetting) if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_BULK_ALTSETTING)) < 0) { usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_BULK_ALTSETTING, ret); goto fail_free; } - if (!instance->altsetting) - instance->altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING; + if (!instance->params.altsetting) + instance->params.altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING; usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0); - INIT_WORK(&instance->status_checker, (void *)speedtch_check_status, instance); + INIT_DELAYED_WORK(&instance->status_checker, speedtch_check_status); instance->status_checker.timer.function = speedtch_status_poll; instance->status_checker.timer.data = (unsigned long)instance; diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index f5434b1cbb1e..dae4ef1e8fe5 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -64,11 +64,13 @@ #include <linux/kthread.h> #include <linux/version.h> #include <linux/mutex.h> +#include <linux/freezer.h> + #include <asm/unaligned.h> #include "usbatm.h" -#define EAGLEUSBVERSION "ueagle 1.3" +#define EAGLEUSBVERSION "ueagle 1.4" /* @@ -80,14 +82,14 @@ dev_dbg(&(usb_dev)->dev, \ "[ueagle-atm dbg] %s: " format, \ __FUNCTION__, ##args); \ - } while (0) + } while (0) #define uea_vdbg(usb_dev, format, args...) \ do { \ if (debug >= 2) \ dev_dbg(&(usb_dev)->dev, \ "[ueagle-atm vdbg] " format, ##args); \ - } while (0) + } while (0) #define uea_enters(usb_dev) \ uea_vdbg(usb_dev, "entering %s\n", __FUNCTION__) @@ -218,8 +220,8 @@ enum { #define UEA_CHIP_VERSION(x) \ ((x)->driver_info & 0xf) -#define IS_ISDN(sc) \ - (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80) +#define IS_ISDN(usb_dev) \ + (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80) #define INS_TO_USBDEV(ins) ins->usb_dev @@ -401,9 +403,8 @@ static int uea_send_modem_cmd(struct usb_device *usb, int ret = -ENOMEM; u8 *xfer_buff; - xfer_buff = kmalloc(size, GFP_KERNEL); + xfer_buff = kmemdup(buff, size, GFP_KERNEL); if (xfer_buff) { - memcpy(xfer_buff, buff, size); ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), LOAD_INTERNAL, @@ -595,14 +596,12 @@ static int uea_idma_write(struct uea_softc *sc, void *data, u32 size) u8 *xfer_buff; int bytes_read; - xfer_buff = kmalloc(size, GFP_KERNEL); + xfer_buff = kmemdup(data, size, GFP_KERNEL); if (!xfer_buff) { uea_err(INS_TO_USBDEV(sc), "can't allocate xfer_buff\n"); return ret; } - memcpy(xfer_buff, data, size); - ret = usb_bulk_msg(sc->usb_dev, usb_sndbulkpipe(sc->usb_dev, UEA_IDMA_PIPE), xfer_buff, size, &bytes_read, BULK_TIMEOUT); @@ -625,12 +624,12 @@ static int request_dsp(struct uea_softc *sc) char *dsp_name; if (UEA_CHIP_VERSION(sc) == ADI930) { - if (IS_ISDN(sc)) + if (IS_ISDN(sc->usb_dev)) dsp_name = FW_DIR "DSP9i.bin"; else dsp_name = FW_DIR "DSP9p.bin"; } else { - if (IS_ISDN(sc)) + if (IS_ISDN(sc->usb_dev)) dsp_name = FW_DIR "DSPei.bin"; else dsp_name = FW_DIR "DSPep.bin"; @@ -658,9 +657,9 @@ static int request_dsp(struct uea_softc *sc) /* * The uea_load_page() function must be called within a process context */ -static void uea_load_page(void *xsc) +static void uea_load_page(struct work_struct *work) { - struct uea_softc *sc = xsc; + struct uea_softc *sc = container_of(work, struct uea_softc, task); u16 pageno = sc->pageno; u16 ovl = sc->ovl; struct block_info bi; @@ -744,7 +743,7 @@ static inline void wake_up_cmv_ack(struct uea_softc *sc) static inline int wait_cmv_ack(struct uea_softc *sc) { - int ret = wait_event_timeout(sc->cmv_ack_wait, + int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait, sc->cmv_ack, ACK_TIMEOUT); sc->cmv_ack = 0; @@ -765,12 +764,11 @@ static int uea_request(struct uea_softc *sc, u8 *xfer_buff; int ret = -ENOMEM; - xfer_buff = kmalloc(size, GFP_KERNEL); + xfer_buff = kmemdup(data, size, GFP_KERNEL); if (!xfer_buff) { uea_err(INS_TO_USBDEV(sc), "can't allocate xfer_buff\n"); return ret; } - memcpy(xfer_buff, data, size); ret = usb_control_msg(sc->usb_dev, usb_sndctrlpipe(sc->usb_dev, 0), UCDC_SEND_ENCAPSULATED_COMMAND, @@ -885,7 +883,8 @@ static int uea_stat(struct uea_softc *sc) break; case 3: /* fail ... */ - uea_info(INS_TO_USBDEV(sc), "modem synchronization failed\n"); + uea_info(INS_TO_USBDEV(sc), "modem synchronization failed" + " (may be try other cmv/dsp)\n"); return -EAGAIN; case 4 ... 6: /* test state */ @@ -913,12 +912,6 @@ static int uea_stat(struct uea_softc *sc) release_firmware(sc->dsp_firm); sc->dsp_firm = NULL; } - - ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid); - if (ret < 0) - return ret; - uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", - sc->stats.phy.firmid); } /* always update it as atm layer could not be init when we switch to @@ -1033,9 +1026,9 @@ static int request_cmvs(struct uea_softc *sc, if (cmv_file[sc->modem_index] == NULL) { if (UEA_CHIP_VERSION(sc) == ADI930) - file = (IS_ISDN(sc)) ? "CMV9i.bin" : "CMV9p.bin"; + file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin"; else - file = (IS_ISDN(sc)) ? "CMVei.bin" : "CMVep.bin"; + file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin"; } else file = cmv_file[sc->modem_index]; @@ -1131,6 +1124,13 @@ static int uea_start_reset(struct uea_softc *sc) if (ret < 0) return ret; + /* Dump firmware version */ + ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid); + if (ret < 0) + return ret; + uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n", + sc->stats.phy.firmid); + /* get options */ ret = len = request_cmvs(sc, &cmvs, &cmvs_fw); if (ret < 0) @@ -1147,6 +1147,8 @@ static int uea_start_reset(struct uea_softc *sc) /* Enter in R-ACT-REQ */ ret = uea_write_cmv(sc, SA_CNTL, 0, 2); uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n"); + uea_info(INS_TO_USBDEV(sc), "Modem started, " + "waiting synchronization\n"); out: release_firmware(cmvs_fw); sc->reset = 0; @@ -1172,7 +1174,10 @@ static int uea_kthread(void *data) if (!ret) ret = uea_stat(sc); if (ret != -EAGAIN) - msleep(1000); + msleep_interruptible(1000); + if (try_to_freeze()) + uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, " + "please unplug/replug your modem\n"); } uea_leaves(INS_TO_USBDEV(sc)); return ret; @@ -1345,7 +1350,7 @@ static int uea_boot(struct uea_softc *sc) uea_enters(INS_TO_USBDEV(sc)); - INIT_WORK(&sc->task, uea_load_page, sc); + INIT_WORK(&sc->task, uea_load_page); init_waitqueue_head(&sc->sync_q); init_waitqueue_head(&sc->cmv_ack_wait); @@ -1566,6 +1571,7 @@ UEA_ATTR(uscorr, 0); UEA_ATTR(dscorr, 0); UEA_ATTR(usunc, 0); UEA_ATTR(dsunc, 0); +UEA_ATTR(firmid, 0); /* Retrieve the device End System Identifier (MAC) */ @@ -1597,7 +1603,7 @@ static int uea_heavy(struct usbatm_data *usbatm, struct usb_interface *intf) { struct uea_softc *sc = usbatm->driver_data; - wait_event(sc->sync_q, IS_OPERATIONAL(sc)); + wait_event_interruptible(sc->sync_q, IS_OPERATIONAL(sc)); return 0; @@ -1639,16 +1645,13 @@ static struct attribute *attrs[] = { &dev_attr_stat_dscorr.attr, &dev_attr_stat_usunc.attr, &dev_attr_stat_dsunc.attr, + &dev_attr_stat_firmid.attr, + NULL, }; static struct attribute_group attr_grp = { .attrs = attrs, }; -static int create_fs_entries(struct usb_interface *intf) -{ - return sysfs_create_group(&intf->dev.kobj, &attr_grp); -} - static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, const struct usb_device_id *id) { @@ -1708,31 +1711,25 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf, } } + ret = sysfs_create_group(&intf->dev.kobj, &attr_grp); + if (ret < 0) + goto error; + ret = uea_boot(sc); - if (ret < 0) { - kfree(sc); - return ret; - } + if (ret < 0) + goto error; - ret = create_fs_entries(intf); - if (ret) { - uea_stop(sc); - kfree(sc); - return ret; - } return 0; -} - -static void destroy_fs_entries(struct usb_interface *intf) -{ - sysfs_remove_group(&intf->dev.kobj, &attr_grp); +error: + kfree(sc); + return ret; } static void uea_unbind(struct usbatm_data *usbatm, struct usb_interface *intf) { struct uea_softc *sc = usbatm->driver_data; - destroy_fs_entries(intf); + sysfs_remove_group(&intf->dev.kobj, &attr_grp); uea_stop(sc); kfree(sc); } @@ -1753,10 +1750,10 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id) struct usb_device *usb = interface_to_usbdev(intf); uea_enters(usb); - uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s\n", + uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n", le16_to_cpu(usb->descriptor.idVendor), le16_to_cpu(usb->descriptor.idProduct), - chip_name[UEA_CHIP_VERSION(id)]); + chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots"); usb_reset_device(usb); diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 309073f6433a..ec63b0ee0743 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -1001,6 +1001,7 @@ static int usbatm_do_heavy_init(void *arg) daemonize(instance->driver->driver_name); allow_signal(SIGTERM); + instance->thread_pid = current->pid; complete(&instance->thread_started); @@ -1025,10 +1026,6 @@ static int usbatm_heavy_init(struct usbatm_data *instance) return ret; } - mutex_lock(&instance->serialize); - instance->thread_pid = ret; - mutex_unlock(&instance->serialize); - wait_for_completion(&instance->thread_started); return 0; diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index ec4d1d756725..98199628e394 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -325,7 +325,7 @@ static void acm_rx_tasklet(unsigned long _acm) struct acm_rb *buf; struct tty_struct *tty = acm->tty; struct acm_ru *rcv; - //unsigned long flags; + unsigned long flags; int i = 0; dbg("Entering acm_rx_tasklet"); @@ -333,15 +333,15 @@ static void acm_rx_tasklet(unsigned long _acm) return; next_buffer: - spin_lock(&acm->read_lock); + spin_lock_irqsave(&acm->read_lock, flags); if (list_empty(&acm->filled_read_bufs)) { - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); goto urbs; } buf = list_entry(acm->filled_read_bufs.next, struct acm_rb, list); list_del(&buf->list); - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size); @@ -356,29 +356,29 @@ next_buffer: memmove(buf->base, buf->base + i, buf->size - i); buf->size -= i; spin_unlock(&acm->throttle_lock); - spin_lock(&acm->read_lock); + spin_lock_irqsave(&acm->read_lock, flags); list_add(&buf->list, &acm->filled_read_bufs); - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); return; } spin_unlock(&acm->throttle_lock); - spin_lock(&acm->read_lock); + spin_lock_irqsave(&acm->read_lock, flags); list_add(&buf->list, &acm->spare_read_bufs); - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); goto next_buffer; urbs: while (!list_empty(&acm->spare_read_bufs)) { - spin_lock(&acm->read_lock); + spin_lock_irqsave(&acm->read_lock, flags); if (list_empty(&acm->spare_read_urbs)) { - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); return; } rcv = list_entry(acm->spare_read_urbs.next, struct acm_ru, list); list_del(&rcv->list); - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); buf = list_entry(acm->spare_read_bufs.next, struct acm_rb, list); @@ -400,9 +400,9 @@ urbs: 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); + spin_lock_irqsave(&acm->read_lock, flags); list_add(&rcv->list, &acm->spare_read_urbs); - spin_unlock(&acm->read_lock); + spin_unlock_irqrestore(&acm->read_lock, flags); return; } } @@ -421,9 +421,9 @@ static void acm_write_bulk(struct urb *urb) schedule_work(&acm->work); } -static void acm_softint(void *private) +static void acm_softint(struct work_struct *work) { - struct acm *acm = private; + struct acm *acm = container_of(work, struct acm, work); dbg("Entering acm_softint."); if (!ACM_READY(acm)) @@ -677,10 +677,10 @@ static const __u8 acm_tty_size[] = { 5, 6, 7, 8 }; -static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_old) +static void acm_tty_set_termios(struct tty_struct *tty, struct ktermios *termios_old) { struct acm *acm = tty->driver_data; - struct termios *termios = tty->termios; + struct ktermios *termios = tty->termios; struct usb_cdc_line_coding newline; int newctrl = acm->ctrlout; @@ -892,7 +892,7 @@ skip_normal_probe: /* workaround for switched endpoints */ - if ((epread->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN) { + if (!usb_endpoint_dir_in(epread)) { /* descriptors are swapped */ struct usb_endpoint_descriptor *t; dev_dbg(&intf->dev,"The data interface has switched endpoints"); @@ -927,7 +927,7 @@ skip_normal_probe: acm->rx_buflimit = num_rx_buf; acm->urb_task.func = acm_rx_tasklet; acm->urb_task.data = (unsigned long) acm; - INIT_WORK(&acm->work, acm_softint, acm); + INIT_WORK(&acm->work, acm_softint); spin_lock_init(&acm->throttle_lock); spin_lock_init(&acm->write_lock); spin_lock_init(&acm->read_lock); @@ -1083,6 +1083,9 @@ static struct usb_device_id acm_ids[] = { { USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ }, + { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */ + .driver_info = NO_UNION_NORMAL, /* has no union descriptor */ + }, { USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */ .driver_info = SINGLE_RX_URB, /* firmware bug */ }, diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index a161d70e1e42..6303970e93c1 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -154,6 +154,7 @@ struct usblp { unsigned char used; /* True if open */ unsigned char present; /* True if not disconnected */ unsigned char bidir; /* interface is bidirectional */ + unsigned char sleeping; /* interface is suspended */ unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */ /* first 2 bytes are (big-endian) length */ }; @@ -183,6 +184,7 @@ static void usblp_dump(struct usblp *usblp) { dbg("quirks=%d", usblp->quirks); dbg("used=%d", usblp->used); dbg("bidir=%d", usblp->bidir); + dbg("sleeping=%d", usblp->sleeping); dbg("device_id_string=\"%s\"", usblp->device_id_string ? usblp->device_id_string + 2 : @@ -338,6 +340,20 @@ static int usblp_check_status(struct usblp *usblp, int err) return newerr; } +static int handle_bidir (struct usblp *usblp) +{ + if (usblp->bidir && usblp->used && !usblp->sleeping) { + usblp->readcount = 0; + usblp->readurb->dev = usblp->dev; + if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) { + usblp->used = 0; + return -EIO; + } + } + + return 0; +} + /* * File op functions. */ @@ -390,14 +406,9 @@ static int usblp_open(struct inode *inode, struct file *file) usblp->writeurb->status = 0; usblp->readurb->status = 0; - if (usblp->bidir) { - usblp->readcount = 0; - usblp->readurb->dev = usblp->dev; - if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) { - retval = -EIO; - usblp->used = 0; - file->private_data = NULL; - } + if (handle_bidir(usblp) < 0) { + file->private_data = NULL; + retval = -EIO; } out: mutex_unlock (&usblp_mutex); @@ -460,6 +471,11 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto done; } + if (usblp->sleeping) { + retval = -ENODEV; + goto done; + } + dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) ); @@ -658,6 +674,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t return -ENODEV; } + if (usblp->sleeping) { + up (&usblp->sem); + return writecount ? writecount : -ENODEV; + } + if (usblp->writeurb->status != 0) { if (usblp->quirks & USBLP_QUIRK_BIDIR) { if (!usblp->wcomplete) @@ -701,6 +722,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t usblp->wcomplete = 0; err = usb_submit_urb(usblp->writeurb, GFP_KERNEL); if (err) { + usblp->wcomplete = 1; if (err != -ENOMEM) count = -EIO; else @@ -749,6 +771,11 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, goto done; } + if (usblp->sleeping) { + count = -ENODEV; + goto done; + } + if (usblp->readurb->status) { err("usblp%d: error %d reading from printer", usblp->minor, usblp->readurb->status); @@ -1167,6 +1194,39 @@ static void usblp_disconnect(struct usb_interface *intf) mutex_unlock (&usblp_mutex); } +static int usblp_suspend (struct usb_interface *intf, pm_message_t message) +{ + struct usblp *usblp = usb_get_intfdata (intf); + + /* this races against normal access and open */ + mutex_lock (&usblp_mutex); + down (&usblp->sem); + /* we take no more IO */ + usblp->sleeping = 1; + usblp_unlink_urbs(usblp); + up (&usblp->sem); + mutex_unlock (&usblp_mutex); + + return 0; +} + +static int usblp_resume (struct usb_interface *intf) +{ + struct usblp *usblp = usb_get_intfdata (intf); + int r; + + mutex_lock (&usblp_mutex); + down (&usblp->sem); + + usblp->sleeping = 0; + r = handle_bidir (usblp); + + up (&usblp->sem); + mutex_unlock (&usblp_mutex); + + return r; +} + static struct usb_device_id usblp_ids [] = { { USB_DEVICE_INFO(7, 1, 1) }, { USB_DEVICE_INFO(7, 1, 2) }, @@ -1183,6 +1243,8 @@ static struct usb_driver usblp_driver = { .name = "usblp", .probe = usblp_probe, .disconnect = usblp_disconnect, + .suspend = usblp_suspend, + .resume = usblp_resume, .id_table = usblp_ids, }; diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 6e3b5358a760..f8324d8d06ac 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -72,6 +72,21 @@ config USB_SUSPEND If you are unsure about this, say N here. +config USB_MULTITHREAD_PROBE + bool "USB Multi-threaded probe (EXPERIMENTAL)" + depends on USB && EXPERIMENTAL + default n + help + Say Y here if you want the USB core to spawn a new thread for + every USB device that is probed. This can cause a small speedup + in boot times on systems with a lot of different USB devices. + + This option should be safe to enable, but if any odd probing + problems are found, please disable it, or dynamically turn it + off in the /sys/module/usbcore/parameters/multithread_probe + file + + When in doubt, say N. config USB_OTG bool diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c index 840442a25b61..c3915dc28608 100644 --- a/drivers/usb/core/buffer.c +++ b/drivers/usb/core/buffer.c @@ -93,7 +93,7 @@ void hcd_buffer_destroy (struct usb_hcd *hcd) } -/* sometimes alloc/free could use kmalloc with SLAB_DMA, for +/* sometimes alloc/free could use kmalloc with GFP_DMA, for * better sharing and to leverage mm/slab.c intelligence. */ diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c index 3538c2fdadfe..ea398e5d50af 100644 --- a/drivers/usb/core/devices.c +++ b/drivers/usb/core/devices.c @@ -175,12 +175,13 @@ static char *usb_dump_endpoint_descriptor ( ) { char dir, unit, *type; - unsigned interval, in, bandwidth = 1; + unsigned interval, bandwidth = 1; if (start > end) return start; - in = (desc->bEndpointAddress & USB_DIR_IN); - dir = in ? 'I' : 'O'; + + dir = usb_endpoint_dir_in(desc) ? 'I' : 'O'; + if (speed == USB_SPEED_HIGH) { switch (le16_to_cpu(desc->wMaxPacketSize) & (0x03 << 11)) { case 1 << 11: bandwidth = 2; break; @@ -204,7 +205,7 @@ static char *usb_dump_endpoint_descriptor ( break; case USB_ENDPOINT_XFER_BULK: type = "Bulk"; - if (speed == USB_SPEED_HIGH && !in) /* uframes per NAK */ + if (speed == USB_SPEED_HIGH && dir == 'O') /* uframes per NAK */ interval = desc->bInterval; else interval = 0; diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 724822cac2b1..3ed4cb2d56d9 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -561,7 +561,7 @@ static int usbdev_open(struct inode *inode, struct file *file) dev = inode->i_private; if (!dev) goto out; - ret = usb_autoresume_device(dev, 1); + ret = usb_autoresume_device(dev); if (ret) goto out; @@ -609,7 +609,7 @@ static int usbdev_release(struct inode *inode, struct file *file) releaseintf(ps, ifnum); } destroy_all_async(ps); - usb_autosuspend_device(dev, 1); + usb_autosuspend_device(dev); usb_unlock_device(dev); usb_put_dev(dev); put_pid(ps->disc_pid); @@ -1588,15 +1588,18 @@ const struct file_operations usbfs_device_file_operations = { .release = usbdev_release, }; -static void usbdev_add(struct usb_device *dev) +static int usbdev_add(struct usb_device *dev) { int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1); dev->class_dev = class_device_create(usb_device_class, NULL, MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev, "usbdev%d.%d", dev->bus->busnum, dev->devnum); + if (IS_ERR(dev->class_dev)) + return PTR_ERR(dev->class_dev); dev->class_dev->class_data = dev; + return 0; } static void usbdev_remove(struct usb_device *dev) @@ -1609,7 +1612,8 @@ static int usbdev_notify(struct notifier_block *self, unsigned long action, { switch (action) { case USB_DEVICE_ADD: - usbdev_add(dev); + if (usbdev_add(dev)) + return NOTIFY_BAD; break; case USB_DEVICE_REMOVE: usbdev_remove(dev); diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 113e484c763e..d6eb5ce1dd1d 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -205,7 +205,7 @@ static int usb_probe_interface(struct device *dev) if (id) { dev_dbg(dev, "%s - got id\n", __FUNCTION__); - error = usb_autoresume_device(udev, 1); + error = usb_autoresume_device(udev); if (error) return error; @@ -229,7 +229,7 @@ static int usb_probe_interface(struct device *dev) } else intf->condition = USB_INTERFACE_BOUND; - usb_autosuspend_device(udev, 1); + usb_autosuspend_device(udev); } return error; @@ -247,7 +247,7 @@ static int usb_unbind_interface(struct device *dev) /* Autoresume for set_interface call below */ udev = interface_to_usbdev(intf); - error = usb_autoresume_device(udev, 1); + error = usb_autoresume_device(udev); /* release all urbs for this interface */ usb_disable_interface(interface_to_usbdev(intf), intf); @@ -265,7 +265,7 @@ static int usb_unbind_interface(struct device *dev) intf->needs_remote_wakeup = 0; if (!error) - usb_autosuspend_device(udev, 1); + usb_autosuspend_device(udev); return 0; } @@ -408,6 +408,16 @@ static int usb_match_one_id(struct usb_interface *interface, (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol)) return 0; + /* The interface class, subclass, and protocol should never be + * checked for a match if the device class is Vendor Specific, + * unless the match record specifies the Vendor ID. */ + if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC && + !(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && + (id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS | + USB_DEVICE_ID_MATCH_INT_SUBCLASS | + USB_DEVICE_ID_MATCH_INT_PROTOCOL))) + return 0; + if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) && (id->bInterfaceClass != intf->desc.bInterfaceClass)) return 0; @@ -476,7 +486,17 @@ static int usb_match_one_id(struct usb_interface *interface, * 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). + * devices (as recorded in bInterfaceClass). + * + * Note that an entry created by USB_INTERFACE_INFO won't match + * any interface if the device class is set to Vendor-Specific. + * This is deliberate; according to the USB spec the meanings of + * the interface class/subclass/protocol for these devices are also + * vendor-specific, and hence matching against a standard product + * class wouldn't work anyway. If you really want to use an + * interface-based match for such a device, create a match record + * that also specifies the vendor ID. (Unforunately there isn't a + * standard macro for creating records like this.) * * Within those groups, remember that not all combinations are * meaningful. For example, don't give a product version range @@ -505,7 +525,7 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface, } EXPORT_SYMBOL_GPL_FUTURE(usb_match_id); -int usb_device_match(struct device *dev, struct device_driver *drv) +static int usb_device_match(struct device *dev, struct device_driver *drv) { /* devices and interfaces are handled separately */ if (is_usb_device(dev)) { @@ -790,7 +810,7 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_deregister); #ifdef CONFIG_PM /* Caller has locked udev's pm_mutex */ -static int suspend_device(struct usb_device *udev, pm_message_t msg) +static int usb_suspend_device(struct usb_device *udev, pm_message_t msg) { struct usb_device_driver *udriver; int status = 0; @@ -817,7 +837,7 @@ done: } /* Caller has locked udev's pm_mutex */ -static int resume_device(struct usb_device *udev) +static int usb_resume_device(struct usb_device *udev) { struct usb_device_driver *udriver; int status = 0; @@ -843,7 +863,7 @@ done: } /* Caller has locked intf's usb_device's pm mutex */ -static int suspend_interface(struct usb_interface *intf, pm_message_t msg) +static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg) { struct usb_driver *driver; int status = 0; @@ -880,7 +900,7 @@ done: } /* Caller has locked intf's usb_device's pm_mutex */ -static int resume_interface(struct usb_interface *intf) +static int usb_resume_interface(struct usb_interface *intf) { struct usb_driver *driver; int status = 0; @@ -920,6 +940,44 @@ done: return status; } +#ifdef CONFIG_USB_SUSPEND + +/* Internal routine to check whether we may autosuspend a device. */ +static int autosuspend_check(struct usb_device *udev) +{ + int i; + struct usb_interface *intf; + + /* For autosuspend, fail fast if anything is in use. + * Also fail if any interfaces require remote wakeup but it + * isn't available. */ + udev->do_remote_wakeup = device_may_wakeup(&udev->dev); + if (udev->pm_usage_cnt > 0) + return -EBUSY; + if (udev->actconfig) { + for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { + intf = udev->actconfig->interface[i]; + if (!is_active(intf)) + continue; + if (intf->pm_usage_cnt > 0) + return -EBUSY; + if (intf->needs_remote_wakeup && + !udev->do_remote_wakeup) { + dev_dbg(&udev->dev, "remote wakeup needed " + "for autosuspend\n"); + return -EOPNOTSUPP; + } + } + } + return 0; +} + +#else + +#define autosuspend_check(udev) 0 + +#endif + /** * usb_suspend_both - suspend a USB device and its interfaces * @udev: the usb_device to suspend @@ -971,52 +1029,34 @@ int usb_suspend_both(struct usb_device *udev, pm_message_t msg) udev->do_remote_wakeup = device_may_wakeup(&udev->dev); - /* For autosuspend, fail fast if anything is in use. - * Also fail if any interfaces require remote wakeup but it - * isn't available. */ if (udev->auto_pm) { - if (udev->pm_usage_cnt > 0) - return -EBUSY; - if (udev->actconfig) { - for (; i < udev->actconfig->desc.bNumInterfaces; i++) { - intf = udev->actconfig->interface[i]; - if (!is_active(intf)) - continue; - if (intf->pm_usage_cnt > 0) - return -EBUSY; - if (intf->needs_remote_wakeup && - !udev->do_remote_wakeup) { - dev_dbg(&udev->dev, - "remote wakeup needed for autosuspend\n"); - return -EOPNOTSUPP; - } - } - i = 0; - } + status = autosuspend_check(udev); + if (status < 0) + return status; } /* Suspend all the interfaces and then udev itself */ if (udev->actconfig) { for (; i < udev->actconfig->desc.bNumInterfaces; i++) { intf = udev->actconfig->interface[i]; - status = suspend_interface(intf, msg); + status = usb_suspend_interface(intf, msg); if (status != 0) break; } } if (status == 0) - status = suspend_device(udev, msg); + status = usb_suspend_device(udev, msg); /* If the suspend failed, resume interfaces that did get suspended */ if (status != 0) { while (--i >= 0) { intf = udev->actconfig->interface[i]; - resume_interface(intf); + usb_resume_interface(intf); } /* If the suspend succeeded, propagate it up the tree */ } else if (parent) - usb_autosuspend_device(parent, 0); + usb_autosuspend_device(parent); // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status); return status; @@ -1064,9 +1104,25 @@ int usb_resume_both(struct usb_device *udev) /* Propagate the resume up the tree, if necessary */ if (udev->state == USB_STATE_SUSPENDED) { if (parent) { - usb_pm_lock(parent); - parent->auto_pm = 1; - status = usb_resume_both(parent); + status = usb_autoresume_device(parent); + if (status == 0) { + status = usb_resume_device(udev); + if (status) { + usb_autosuspend_device(parent); + + /* It's possible usb_resume_device() + * failed after the port was + * unsuspended, causing udev to be + * logically disconnected. We don't + * want usb_disconnect() to autosuspend + * the parent again, so tell it that + * udev disconnected while still + * suspended. */ + if (udev->state == + USB_STATE_NOTATTACHED) + udev->discon_suspended = 1; + } + } } else { /* We can't progagate beyond the USB subsystem, @@ -1075,24 +1131,20 @@ int usb_resume_both(struct usb_device *udev) if (udev->dev.parent->power.power_state.event != PM_EVENT_ON) status = -EHOSTUNREACH; - } - if (status == 0) - status = resume_device(udev); - if (parent) - usb_pm_unlock(parent); + else + status = usb_resume_device(udev); + } } else { /* Needed only for setting udev->dev.power.power_state.event * and for possible debugging message. */ - status = resume_device(udev); + status = usb_resume_device(udev); } - /* Now the parent won't suspend until we are finished */ - if (status == 0 && udev->actconfig) { for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) { intf = udev->actconfig->interface[i]; - resume_interface(intf); + usb_resume_interface(intf); } } @@ -1102,39 +1154,53 @@ int usb_resume_both(struct usb_device *udev) #ifdef CONFIG_USB_SUSPEND +/* Internal routine to adjust a device's usage counter and change + * its autosuspend state. + */ +static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt) +{ + int status = 0; + + usb_pm_lock(udev); + udev->pm_usage_cnt += inc_usage_cnt; + WARN_ON(udev->pm_usage_cnt < 0); + if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) { + udev->auto_pm = 1; + status = usb_resume_both(udev); + if (status != 0) + udev->pm_usage_cnt -= inc_usage_cnt; + } else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0) + queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, + USB_AUTOSUSPEND_DELAY); + usb_pm_unlock(udev); + return status; +} + /** * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces * @udev: the usb_device to autosuspend - * @dec_usage_cnt: flag to decrement @udev's PM-usage counter * * This routine should be called when a core subsystem is finished using * @udev and wants to allow it to autosuspend. Examples would be when * @udev's device file in usbfs is closed or after a configuration change. * - * @dec_usage_cnt should be 1 if the subsystem previously incremented - * @udev's usage counter (such as by passing 1 to usb_autoresume_device); - * otherwise it should be 0. - * - * If the usage counter for @udev or any of its active interfaces is greater - * than 0, the autosuspend request will not be queued. (If an interface - * driver does not support autosuspend then its usage counter is permanently - * positive.) Likewise, if an interface driver requires remote-wakeup - * capability during autosuspend but remote wakeup is disabled, the - * autosuspend will fail. + * @udev's usage counter is decremented. If it or any of the usage counters + * for an active interface is greater than 0, no autosuspend request will be + * queued. (If an interface driver does not support autosuspend then its + * usage counter is permanently positive.) Furthermore, if an interface + * driver requires remote-wakeup capability during autosuspend but remote + * wakeup is disabled, the autosuspend will fail. * * Often the caller will hold @udev's device lock, but this is not * necessary. * * This routine can run only in process context. */ -void usb_autosuspend_device(struct usb_device *udev, int dec_usage_cnt) +void usb_autosuspend_device(struct usb_device *udev) { - usb_pm_lock(udev); - udev->pm_usage_cnt -= dec_usage_cnt; - if (udev->pm_usage_cnt <= 0) - queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, - USB_AUTOSUSPEND_DELAY); - usb_pm_unlock(udev); + int status; + + status = usb_autopm_do_device(udev, -1); // dev_dbg(&udev->dev, "%s: cnt %d\n", // __FUNCTION__, udev->pm_usage_cnt); } @@ -1142,44 +1208,59 @@ void usb_autosuspend_device(struct usb_device *udev, int dec_usage_cnt) /** * usb_autoresume_device - immediately autoresume a USB device and its interfaces * @udev: the usb_device to autoresume - * @inc_usage_cnt: flag to increment @udev's PM-usage counter * * This routine should be called when a core subsystem wants to use @udev - * and needs to guarantee that it is not suspended. In addition, the - * caller can prevent @udev from being autosuspended subsequently. (Note - * that this will not prevent suspend events originating in the PM core.) - * Examples would be when @udev's device file in usbfs is opened (autosuspend - * should be prevented until the file is closed) or when a remote-wakeup - * request is received (later autosuspends should not be prevented). + * and needs to guarantee that it is not suspended. No autosuspend will + * occur until usb_autosuspend_device is called. (Note that this will not + * prevent suspend events originating in the PM core.) Examples would be + * when @udev's device file in usbfs is opened or when a remote-wakeup + * request is received. * - * @inc_usage_cnt should be 1 to increment @udev's usage counter and prevent - * autosuspends. This prevention will persist until the usage counter is - * decremented again (such as by passing 1 to usb_autosuspend_device). - * Otherwise @inc_usage_cnt should be 0 to leave the usage counter unchanged. - * Regardless, if the autoresume fails then the usage counter is not - * incremented. + * @udev's usage counter is incremented to prevent subsequent autosuspends. + * However if the autoresume fails then the usage counter is re-decremented. * * Often the caller will hold @udev's device lock, but this is not * necessary (and attempting it might cause deadlock). * * This routine can run only in process context. */ -int usb_autoresume_device(struct usb_device *udev, int inc_usage_cnt) +int usb_autoresume_device(struct usb_device *udev) { int status; - usb_pm_lock(udev); - udev->pm_usage_cnt += inc_usage_cnt; - udev->auto_pm = 1; - status = usb_resume_both(udev); - if (status != 0) - udev->pm_usage_cnt -= inc_usage_cnt; - usb_pm_unlock(udev); + status = usb_autopm_do_device(udev, 1); // dev_dbg(&udev->dev, "%s: status %d cnt %d\n", // __FUNCTION__, status, udev->pm_usage_cnt); return status; } +/* Internal routine to adjust an interface's usage counter and change + * its device's autosuspend state. + */ +static int usb_autopm_do_interface(struct usb_interface *intf, + int inc_usage_cnt) +{ + struct usb_device *udev = interface_to_usbdev(intf); + int status = 0; + + usb_pm_lock(udev); + if (intf->condition == USB_INTERFACE_UNBOUND) + status = -ENODEV; + else { + intf->pm_usage_cnt += inc_usage_cnt; + if (inc_usage_cnt >= 0 && intf->pm_usage_cnt > 0) { + udev->auto_pm = 1; + status = usb_resume_both(udev); + if (status != 0) + intf->pm_usage_cnt -= inc_usage_cnt; + } else if (inc_usage_cnt <= 0 && autosuspend_check(udev) == 0) + queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, + USB_AUTOSUSPEND_DELAY); + } + usb_pm_unlock(udev); + return status; +} + /** * usb_autopm_put_interface - decrement a USB interface's PM-usage counter * @intf: the usb_interface whose counter should be decremented @@ -1213,17 +1294,11 @@ int usb_autoresume_device(struct usb_device *udev, int inc_usage_cnt) */ void usb_autopm_put_interface(struct usb_interface *intf) { - struct usb_device *udev = interface_to_usbdev(intf); + int status; - usb_pm_lock(udev); - if (intf->condition != USB_INTERFACE_UNBOUND && - --intf->pm_usage_cnt <= 0) { - queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, - USB_AUTOSUSPEND_DELAY); - } - usb_pm_unlock(udev); - // dev_dbg(&intf->dev, "%s: cnt %d\n", - // __FUNCTION__, intf->pm_usage_cnt); + status = usb_autopm_do_interface(intf, -1); + // dev_dbg(&intf->dev, "%s: status %d cnt %d\n", + // __FUNCTION__, status, intf->pm_usage_cnt); } EXPORT_SYMBOL_GPL(usb_autopm_put_interface); @@ -1260,26 +1335,37 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface); */ int usb_autopm_get_interface(struct usb_interface *intf) { - struct usb_device *udev = interface_to_usbdev(intf); - int status; + int status; - usb_pm_lock(udev); - if (intf->condition == USB_INTERFACE_UNBOUND) - status = -ENODEV; - else { - ++intf->pm_usage_cnt; - udev->auto_pm = 1; - status = usb_resume_both(udev); - if (status != 0) - --intf->pm_usage_cnt; - } - usb_pm_unlock(udev); + status = usb_autopm_do_interface(intf, 1); // dev_dbg(&intf->dev, "%s: status %d cnt %d\n", // __FUNCTION__, status, intf->pm_usage_cnt); return status; } EXPORT_SYMBOL_GPL(usb_autopm_get_interface); +/** + * usb_autopm_set_interface - set a USB interface's autosuspend state + * @intf: the usb_interface whose state should be set + * + * This routine sets the autosuspend state of @intf's device according + * to @intf's usage counter, which the caller must have set previously. + * If the counter is <= 0, the device is autosuspended (if it isn't + * already suspended and if nothing else prevents the autosuspend). If + * the counter is > 0, the device is autoresumed (if it isn't already + * awake). + */ +int usb_autopm_set_interface(struct usb_interface *intf) +{ + int status; + + status = usb_autopm_do_interface(intf, 0); + // dev_dbg(&intf->dev, "%s: status %d cnt %d\n", + // __FUNCTION__, status, intf->pm_usage_cnt); + return status; +} +EXPORT_SYMBOL_GPL(usb_autopm_set_interface); + #endif /* CONFIG_USB_SUSPEND */ static int usb_suspend(struct device *dev, pm_message_t message) diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c index 3ebb90149e93..c505b767cee1 100644 --- a/drivers/usb/core/endpoint.c +++ b/drivers/usb/core/endpoint.c @@ -10,15 +10,20 @@ */ #include <linux/kernel.h> +#include <linux/spinlock.h> +#include <linux/idr.h> #include <linux/usb.h> #include "usb.h" -/* endpoint stuff */ +#define MAX_ENDPOINT_MINORS (64*128*32) +static int usb_endpoint_major; +static DEFINE_IDR(endpoint_idr); struct ep_device { struct usb_endpoint_descriptor *desc; struct usb_device *udev; struct device dev; + int minor; }; #define to_ep_device(_dev) \ container_of(_dev, struct ep_device, dev) @@ -152,6 +157,55 @@ static struct attribute_group ep_dev_attr_grp = { .attrs = ep_dev_attrs, }; +static int usb_endpoint_major_init(void) +{ + dev_t dev; + int error; + + error = alloc_chrdev_region(&dev, 0, MAX_ENDPOINT_MINORS, + "usb_endpoint"); + if (error) { + err("unable to get a dynamic major for usb endpoints"); + return error; + } + usb_endpoint_major = MAJOR(dev); + + return error; +} + +static void usb_endpoint_major_cleanup(void) +{ + unregister_chrdev_region(MKDEV(usb_endpoint_major, 0), + MAX_ENDPOINT_MINORS); +} + +static int endpoint_get_minor(struct ep_device *ep_dev) +{ + static DEFINE_MUTEX(minor_lock); + int retval = -ENOMEM; + int id; + + mutex_lock(&minor_lock); + if (idr_pre_get(&endpoint_idr, GFP_KERNEL) == 0) + goto exit; + + retval = idr_get_new(&endpoint_idr, ep_dev, &id); + if (retval < 0) { + if (retval == -EAGAIN) + retval = -ENOMEM; + goto exit; + } + ep_dev->minor = id & MAX_ID_MASK; +exit: + mutex_unlock(&minor_lock); + return retval; +} + +static void endpoint_free_minor(struct ep_device *ep_dev) +{ + idr_remove(&endpoint_idr, ep_dev->minor); +} + static struct endpoint_class { struct kref kref; struct class *class; @@ -176,11 +230,20 @@ static int init_endpoint_class(void) ep_class->class = class_create(THIS_MODULE, "usb_endpoint"); if (IS_ERR(ep_class->class)) { result = IS_ERR(ep_class->class); - kfree(ep_class); - ep_class = NULL; - goto exit; + goto class_create_error; } + result = usb_endpoint_major_init(); + if (result) + goto endpoint_major_error; + + goto exit; + +endpoint_major_error: + class_destroy(ep_class->class); +class_create_error: + kfree(ep_class); + ep_class = NULL; exit: return result; } @@ -191,6 +254,7 @@ static void release_endpoint_class(struct kref *kref) class_destroy(ep_class->class); kfree(ep_class); ep_class = NULL; + usb_endpoint_major_cleanup(); } static void destroy_endpoint_class(void) @@ -213,7 +277,6 @@ int usb_create_ep_files(struct device *parent, { char name[8]; struct ep_device *ep_dev; - int minor; int retval; retval = init_endpoint_class(); @@ -223,15 +286,19 @@ int usb_create_ep_files(struct device *parent, ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL); if (!ep_dev) { retval = -ENOMEM; - goto exit; + goto error_alloc; } - /* fun calculation to determine the minor of this endpoint */ - minor = (((udev->bus->busnum - 1) * 128) * 16) + (udev->devnum - 1); + retval = endpoint_get_minor(ep_dev); + if (retval) { + dev_err(parent, "can not allocate minor number for %s", + ep_dev->dev.bus_id); + goto error_register; + } ep_dev->desc = &endpoint->desc; ep_dev->udev = udev; - ep_dev->dev.devt = MKDEV(442, minor); // FIXME fake number... + ep_dev->dev.devt = MKDEV(usb_endpoint_major, ep_dev->minor); ep_dev->dev.class = ep_class->class; ep_dev->dev.parent = parent; ep_dev->dev.release = ep_device_release; @@ -241,49 +308,50 @@ int usb_create_ep_files(struct device *parent, retval = device_register(&ep_dev->dev); if (retval) - goto error; + goto error_chrdev; retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); if (retval) goto error_group; - endpoint->ep_dev = ep_dev; - /* create the symlink to the old-style "ep_XX" directory */ sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); - retval = sysfs_create_link(&parent->kobj, - &endpoint->ep_dev->dev.kobj, name); + retval = sysfs_create_link(&parent->kobj, &ep_dev->dev.kobj, name); if (retval) goto error_link; -exit: + endpoint->ep_dev = ep_dev; return retval; error_link: sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); - error_group: device_unregister(&ep_dev->dev); - endpoint->ep_dev = NULL; destroy_endpoint_class(); return retval; -error: + +error_chrdev: + endpoint_free_minor(ep_dev); + +error_register: kfree(ep_dev); +error_alloc: destroy_endpoint_class(); +exit: return retval; } void usb_remove_ep_files(struct usb_host_endpoint *endpoint) { + struct ep_device *ep_dev = endpoint->ep_dev; - if (endpoint->ep_dev) { + if (ep_dev) { char name[8]; sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress); - sysfs_remove_link(&endpoint->ep_dev->dev.parent->kobj, name); - sysfs_remove_group(&endpoint->ep_dev->dev.kobj, &ep_dev_attr_grp); - device_unregister(&endpoint->ep_dev->dev); + sysfs_remove_link(&ep_dev->dev.parent->kobj, name); + sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp); + endpoint_free_minor(ep_dev); + device_unregister(&ep_dev->dev); endpoint->ep_dev = NULL; + destroy_endpoint_class(); } - destroy_endpoint_class(); } - - diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index afa2dd203329..10064af65d17 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -256,7 +256,9 @@ static const u8 hs_rh_config_descriptor [] = { 0x05, /* __u8 ep_bDescriptorType; Endpoint */ 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */ 0x03, /* __u8 ep_bmAttributes; Interrupt */ - 0x02, 0x00, /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) */ + /* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8) + * see hub.c:hub_configure() for details. */ + (USB_MAXCHILDREN + 1 + 7) / 8, 0x00, 0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */ }; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 66bff184a30c..2651c2e2a89f 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -22,6 +22,7 @@ #include <linux/usbdevice_fs.h> #include <linux/kthread.h> #include <linux/mutex.h> +#include <linux/freezer.h> #include <asm/semaphore.h> #include <asm/uaccess.h> @@ -31,6 +32,47 @@ #include "hcd.h" #include "hub.h" +struct usb_hub { + struct device *intfdev; /* the "interface" device */ + struct usb_device *hdev; + struct urb *urb; /* for interrupt polling pipe */ + + /* buffer for urb ... with extra space in case of babble */ + char (*buffer)[8]; + dma_addr_t buffer_dma; /* DMA address for buffer */ + union { + struct usb_hub_status hub; + struct usb_port_status port; + } *status; /* buffer for status reports */ + + int error; /* last reported error */ + int nerrors; /* track consecutive errors */ + + struct list_head event_list; /* hubs w/data or errs ready */ + unsigned long event_bits[1]; /* status change bitmask */ + unsigned long change_bits[1]; /* ports with logical connect + status change */ + unsigned long busy_bits[1]; /* ports being reset or + resumed */ +#if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */ +#error event_bits[] is too short! +#endif + + struct usb_hub_descriptor *descriptor; /* class descriptor */ + struct usb_tt tt; /* Transaction Translator */ + + unsigned mA_per_port; /* current for each child */ + + unsigned limited_power:1; + unsigned quiescing:1; + unsigned activating:1; + + unsigned has_indicators:1; + u8 indicator[USB_MAXCHILDREN]; + struct delayed_work leds; +}; + + /* Protect struct usb_device->state and ->children members * Note: Both are also protected by ->dev.sem, except that ->state can * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */ @@ -45,6 +87,16 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); static struct task_struct *khubd_task; +/* multithreaded probe logic */ +static int multithread_probe = +#ifdef CONFIG_USB_MULTITHREAD_PROBE + 1; +#else + 0; +#endif +module_param(multithread_probe, bool, S_IRUGO); +MODULE_PARM_DESC(multithread_probe, "Run each USB device probe in a new thread"); + /* cycle leds on hubs that aren't blinking for attention */ static int blinkenlights = 0; module_param (blinkenlights, bool, S_IRUGO); @@ -167,9 +219,10 @@ static void set_port_led( #define LED_CYCLE_PERIOD ((2*HZ)/3) -static void led_work (void *__hub) +static void led_work (struct work_struct *work) { - struct usb_hub *hub = __hub; + struct usb_hub *hub = + container_of(work, struct usb_hub, leds.work); struct usb_device *hdev = hub->hdev; unsigned i; unsigned changed = 0; @@ -276,6 +329,9 @@ static void kick_khubd(struct usb_hub *hub) { unsigned long flags; + /* Suppress autosuspend until khubd runs */ + to_usb_interface(hub->intfdev)->pm_usage_cnt = 1; + spin_lock_irqsave(&hub_event_lock, flags); if (list_empty(&hub->event_list)) { list_add_tail(&hub->event_list, &hub_event_list); @@ -351,9 +407,10 @@ hub_clear_tt_buffer (struct usb_device *hdev, u16 devinfo, u16 tt) * talking to TTs must queue control transfers (not just bulk and iso), so * both can talk to the same hub concurrently. */ -static void hub_tt_kevent (void *arg) +static void hub_tt_kevent (struct work_struct *work) { - struct usb_hub *hub = arg; + struct usb_hub *hub = + container_of(work, struct usb_hub, tt.kevent); unsigned long flags; spin_lock_irqsave (&hub->tt.lock, flags); @@ -404,7 +461,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe) * since each TT has "at least two" buffers that can need it (and * there can be many TTs per hub). even if they're uncommon. */ - if ((clear = kmalloc (sizeof *clear, SLAB_ATOMIC)) == NULL) { + if ((clear = kmalloc (sizeof *clear, GFP_ATOMIC)) == NULL) { dev_err (&udev->dev, "can't save CLEAR_TT_BUFFER state\n"); /* FIXME recover somehow ... RESET_TT? */ return; @@ -457,7 +514,6 @@ static void hub_quiesce(struct usb_hub *hub) /* (nonblocking) khubd and related activity won't re-trigger */ hub->quiescing = 1; hub->activating = 0; - hub->resume_root_hub = 0; /* (blocking) stop khubd and related activity */ usb_kill_urb(hub->urb); @@ -473,7 +529,7 @@ static void hub_activate(struct usb_hub *hub) hub->quiescing = 0; hub->activating = 1; - hub->resume_root_hub = 0; + status = usb_submit_urb(hub->urb, GFP_NOIO); if (status < 0) dev_err(hub->intfdev, "activate --> %d\n", status); @@ -641,7 +697,7 @@ static int hub_configure(struct usb_hub *hub, spin_lock_init (&hub->tt.lock); INIT_LIST_HEAD (&hub->tt.clear_list); - INIT_WORK (&hub->tt.kevent, hub_tt_kevent, hub); + INIT_WORK (&hub->tt.kevent, hub_tt_kevent); switch (hdev->descriptor.bDeviceProtocol) { case 0: break; @@ -759,7 +815,12 @@ static int hub_configure(struct usb_hub *hub, dev_dbg(hub_dev, "%sover-current condition exists\n", (hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no "); - /* set up the interrupt endpoint */ + /* set up the interrupt endpoint + * We use the EP's maxpacket size instead of (PORTS+1+7)/8 + * bytes as USB2.0[11.12.3] says because some hubs are known + * to send more data (and thus cause overflow). For root hubs, + * maxpktsize is defined in hcd.c's fake endpoint descriptors + * to be big enough for at least USB_MAXCHILDREN ports. */ pipe = usb_rcvintpipe(hdev, endpoint->bEndpointAddress); maxp = usb_maxpacket(hdev, pipe, usb_pipeout(pipe)); @@ -880,9 +941,10 @@ descriptor_error: INIT_LIST_HEAD(&hub->event_list); hub->intfdev = &intf->dev; hub->hdev = hdev; - INIT_WORK(&hub->leds, led_work, hub); + INIT_DELAYED_WORK(&hub->leds, led_work); usb_set_intfdata (intf, hub); + intf->needs_remote_wakeup = 1; if (hdev->speed == USB_SPEED_HIGH) highspeed_hubs++; @@ -980,6 +1042,8 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev) if (udev->children[i]) recursively_mark_NOTATTACHED(udev->children[i]); } + if (udev->state == USB_STATE_SUSPENDED) + udev->discon_suspended = 1; udev->state = USB_STATE_NOTATTACHED; } @@ -1169,6 +1233,14 @@ void usb_disconnect(struct usb_device **pdev) *pdev = NULL; spin_unlock_irq(&device_state_lock); + /* Decrement the parent's count of unsuspended children */ + if (udev->parent) { + usb_pm_lock(udev); + if (!udev->discon_suspended) + usb_autosuspend_device(udev->parent); + usb_pm_unlock(udev); + } + put_device(&udev->dev); } @@ -1188,31 +1260,20 @@ static inline void show_string(struct usb_device *udev, char *id, char *string) #ifdef CONFIG_USB_OTG #include "otg_whitelist.h" +static int __usb_port_suspend(struct usb_device *, int port1); #endif -/** - * usb_new_device - perform initial device setup (usbcore-internal) - * @udev: newly addressed device (in ADDRESS state) - * - * 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 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. - * - * Returns 0 for success (device is configured and listed, with its - * interfaces, in sysfs); else a negative errno value. - * - * This call is synchronous, and may not be used in an interrupt context. - * - * Only the hub driver or root-hub registrar should ever call this. - */ -int usb_new_device(struct usb_device *udev) +static int __usb_new_device(void *void_data) { + struct usb_device *udev = void_data; int err; + /* Lock ourself into memory in order to keep a probe sequence + * sleeping in a new thread from allowing us to be unloaded. + */ + if (!try_module_get(THIS_MODULE)) + return -EINVAL; + err = usb_get_configuration(udev); if (err < 0) { dev_err(&udev->dev, "can't read configurations, error %d\n", @@ -1289,8 +1350,6 @@ int usb_new_device(struct usb_device *udev) * (Includes HNP test device.) */ if (udev->bus->b_hnp_enable || udev->bus->is_b_host) { - static int __usb_port_suspend(struct usb_device *, - int port1); err = __usb_port_suspend(udev, udev->bus->otg_port); if (err < 0) dev_dbg(&udev->dev, "HNP fail, %d\n", err); @@ -1310,13 +1369,56 @@ int usb_new_device(struct usb_device *udev) goto fail; } - return 0; + /* Increment the parent's count of unsuspended children */ + if (udev->parent) + usb_autoresume_device(udev->parent); + +exit: + module_put(THIS_MODULE); + return err; fail: usb_set_device_state(udev, USB_STATE_NOTATTACHED); - return err; + goto exit; } +/** + * usb_new_device - perform initial device setup (usbcore-internal) + * @udev: newly addressed device (in ADDRESS state) + * + * 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 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. + * + * The return value for this function depends on if the + * multithread_probe variable is set or not. If it's set, it will + * return a if the probe thread was successfully created or not. If the + * variable is not set, it will return if the device is configured + * properly or not. interfaces, in sysfs); else a negative errno value. + * + * This call is synchronous, and may not be used in an interrupt context. + * + * Only the hub driver or root-hub registrar should ever call this. + */ +int usb_new_device(struct usb_device *udev) +{ + struct task_struct *probe_task; + int ret = 0; + + if (multithread_probe) { + probe_task = kthread_run(__usb_new_device, udev, + "usb-probe-%s", udev->devnum); + if (IS_ERR(probe_task)) + ret = PTR_ERR(probe_task); + } else + ret = __usb_new_device(udev); + + return ret; +} static int hub_port_status(struct usb_hub *hub, int port1, u16 *status, u16 *change) @@ -1324,10 +1426,12 @@ static int hub_port_status(struct usb_hub *hub, int port1, int ret; ret = get_port_status(hub->hdev, port1, &hub->status->port); - if (ret < 0) + if (ret < 4) { dev_err (hub->intfdev, "%s failed (err = %d)\n", __FUNCTION__, ret); - else { + if (ret >= 0) + ret = -EIO; + } else { *status = le16_to_cpu(hub->status->port.wPortStatus); *change = le16_to_cpu(hub->status->port.wPortChange); ret = 0; @@ -1675,6 +1779,12 @@ static int hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) { int status; + u16 portchange, portstatus; + + /* Skip the initial Clear-Suspend step for a remote wakeup */ + status = hub_port_status(hub, port1, &portstatus, &portchange); + if (status == 0 && !(portstatus & USB_PORT_STAT_SUSPEND)) + goto SuspendCleared; // dev_dbg(hub->intfdev, "resume port %d\n", port1); @@ -1688,9 +1798,6 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) "can't resume port %d, status %d\n", port1, status); } else { - u16 devstatus; - u16 portchange; - /* drive resume for at least 20 msec */ if (udev) dev_dbg(&udev->dev, "usb %sresume\n", @@ -1705,16 +1812,15 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev) * stop resume signaling. Then finish the resume * sequence. */ - devstatus = portchange = 0; - status = hub_port_status(hub, port1, - &devstatus, &portchange); + status = hub_port_status(hub, port1, &portstatus, &portchange); +SuspendCleared: if (status < 0 - || (devstatus & LIVE_FLAGS) != LIVE_FLAGS - || (devstatus & USB_PORT_STAT_SUSPEND) != 0 + || (portstatus & LIVE_FLAGS) != LIVE_FLAGS + || (portstatus & USB_PORT_STAT_SUSPEND) != 0 ) { dev_dbg(hub->intfdev, "port %d status %04x.%04x after resume, %d\n", - port1, portchange, devstatus, status); + port1, portchange, portstatus, status); if (status >= 0) status = -ENODEV; } else { @@ -1775,23 +1881,16 @@ static int remote_wakeup(struct usb_device *udev) { int status = 0; - /* All this just to avoid sending a port-resume message - * to the parent hub! */ - usb_lock_device(udev); - usb_pm_lock(udev); if (udev->state == USB_STATE_SUSPENDED) { dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); - /* TRSMRCY = 10 msec */ - msleep(10); - status = finish_port_resume(udev); + status = usb_autoresume_device(udev); + + /* Give the interface drivers a chance to do something, + * then autosuspend the device again. */ if (status == 0) - udev->dev.power.power_state.event = PM_EVENT_ON; + usb_autosuspend_device(udev); } - usb_pm_unlock(udev); - - if (status == 0) - usb_autoresume_device(udev, 0); usb_unlock_device(udev); return status; } @@ -1855,6 +1954,8 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) } } + dev_dbg(&intf->dev, "%s\n", __FUNCTION__); + /* "global suspend" of the downstream HC-to-USB interface */ if (!hdev->parent) { struct usb_bus *bus = hdev->bus; @@ -1877,10 +1978,12 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg) static int hub_resume(struct usb_interface *intf) { - struct usb_device *hdev = interface_to_usbdev(intf); struct usb_hub *hub = usb_get_intfdata (intf); + struct usb_device *hdev = hub->hdev; int status; + dev_dbg(&intf->dev, "%s\n", __FUNCTION__); + /* "global resume" of the downstream HC-to-USB interface */ if (!hdev->parent) { struct usb_bus *bus = hdev->bus; @@ -1919,7 +2022,6 @@ void usb_resume_root_hub(struct usb_device *hdev) { struct usb_hub *hub = hdev_to_hub(hdev); - hub->resume_root_hub = 1; kick_khubd(hub); } @@ -2270,7 +2372,7 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1) struct usb_qualifier_descriptor *qual; int status; - qual = kmalloc (sizeof *qual, SLAB_KERNEL); + qual = kmalloc (sizeof *qual, GFP_KERNEL); if (qual == NULL) return; @@ -2282,7 +2384,7 @@ check_highspeed (struct usb_hub *hub, struct usb_device *udev, int port1) /* hub LEDs are probably harder to miss than syslog */ if (hub->has_indicators) { hub->indicator[port1-1] = INDICATOR_GREEN_BLINK; - schedule_work (&hub->leds); + schedule_delayed_work (&hub->leds, 0); } } kfree(qual); @@ -2456,7 +2558,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, if (hub->has_indicators) { hub->indicator[port1-1] = INDICATOR_AMBER_BLINK; - schedule_work (&hub->leds); + schedule_delayed_work (&hub->leds, 0); } status = -ENOTCONN; /* Don't retry */ goto loop_disable; @@ -2556,16 +2658,13 @@ static void hub_events(void) intf = to_usb_interface(hub->intfdev); hub_dev = &intf->dev; - i = hub->resume_root_hub; - - dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x%s\n", + dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n", hdev->state, hub->descriptor ? hub->descriptor->bNbrPorts : 0, /* NOTE: expects max 15 ports... */ (u16) hub->change_bits[0], - (u16) hub->event_bits[0], - i ? ", resume root" : ""); + (u16) hub->event_bits[0]); usb_get_intf(intf); spin_unlock_irq(&hub_event_lock); @@ -2586,16 +2685,16 @@ static void hub_events(void) goto loop; } - /* Is this is a root hub wanting to reactivate the downstream - * ports? If so, be sure the interface resumes even if its - * stub "device" node was never suspended. - */ - if (i) - usb_autoresume_device(hdev, 0); + /* Autoresume */ + ret = usb_autopm_get_interface(intf); + if (ret) { + dev_dbg(hub_dev, "Can't autoresume: %d\n", ret); + goto loop; + } - /* If this is an inactive or suspended hub, do nothing */ + /* If this is an inactive hub, do nothing */ if (hub->quiescing) - goto loop; + goto loop_autopm; if (hub->error) { dev_dbg (hub_dev, "resetting for error %d\n", @@ -2605,7 +2704,7 @@ static void hub_events(void) if (ret) { dev_dbg (hub_dev, "error resetting hub: %d\n", ret); - goto loop; + goto loop_autopm; } hub->nerrors = 0; @@ -2733,6 +2832,10 @@ static void hub_events(void) if (!hdev->parent && !hub->busy_bits[0]) usb_enable_root_hub_irq(hdev->bus); +loop_autopm: + /* Allow autosuspend if we're not going to run again */ + if (list_empty(&hub->event_list)) + usb_autopm_enable(intf); loop: usb_unlock_device(hdev); usb_put_intf(intf); @@ -2774,6 +2877,7 @@ static struct usb_driver hub_driver = { .post_reset = hub_post_reset, .ioctl = hub_ioctl, .id_table = hub_id_table, + .supports_autosuspend = 1, }; int usb_hub_init(void) @@ -2819,7 +2923,7 @@ static int config_descriptors_changed(struct usb_device *udev) if (len < le16_to_cpu(udev->config[index].desc.wTotalLength)) len = le16_to_cpu(udev->config[index].desc.wTotalLength); } - buf = kmalloc (len, SLAB_KERNEL); + buf = kmalloc (len, GFP_KERNEL); if (buf == NULL) { dev_err(&udev->dev, "no mem to re-read configs after reset\n"); /* assume the worst */ @@ -2998,7 +3102,7 @@ int usb_reset_composite_device(struct usb_device *udev, } /* Prevent autosuspend during the reset */ - usb_autoresume_device(udev, 1); + usb_autoresume_device(udev); if (iface && iface->condition != USB_INTERFACE_BINDING) iface = NULL; @@ -3041,7 +3145,7 @@ int usb_reset_composite_device(struct usb_device *udev, } } - usb_autosuspend_device(udev, 1); + usb_autosuspend_device(udev); return ret; } EXPORT_SYMBOL(usb_reset_composite_device); diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h index 0f8e82a4d480..cf9559c6c9b6 100644 --- a/drivers/usb/core/hub.h +++ b/drivers/usb/core/hub.h @@ -192,45 +192,4 @@ struct usb_tt_clear { extern void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe); -struct usb_hub { - struct device *intfdev; /* the "interface" device */ - struct usb_device *hdev; - struct urb *urb; /* for interrupt polling pipe */ - - /* buffer for urb ... with extra space in case of babble */ - char (*buffer)[8]; - dma_addr_t buffer_dma; /* DMA address for buffer */ - union { - struct usb_hub_status hub; - struct usb_port_status port; - } *status; /* buffer for status reports */ - - int error; /* last reported error */ - int nerrors; /* track consecutive errors */ - - struct list_head event_list; /* hubs w/data or errs ready */ - unsigned long event_bits[1]; /* status change bitmask */ - unsigned long change_bits[1]; /* ports with logical connect - status change */ - unsigned long busy_bits[1]; /* ports being reset or - resumed */ -#if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */ -#error event_bits[] is too short! -#endif - - struct usb_hub_descriptor *descriptor; /* class descriptor */ - struct usb_tt tt; /* Transaction Translator */ - - unsigned mA_per_port; /* current for each child */ - - unsigned limited_power:1; - unsigned quiescing:1; - unsigned activating:1; - unsigned resume_root_hub:1; - - unsigned has_indicators:1; - enum hub_led_mode indicator[USB_MAXCHILDREN]; - struct work_struct leds; -}; - #endif /* __LINUX_HUB_H */ diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c index b5d6a79af0be..11dad22da41c 100644 --- a/drivers/usb/core/inode.c +++ b/drivers/usb/core/inode.c @@ -379,7 +379,7 @@ static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) { loff_t retval = -EINVAL; - mutex_lock(&file->f_dentry->d_inode->i_mutex); + mutex_lock(&file->f_path.dentry->d_inode->i_mutex); switch(orig) { case 0: if (offset > 0) { @@ -396,7 +396,7 @@ static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) default: break; } - mutex_unlock(&file->f_dentry->d_inode->i_mutex); + mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); return retval; } diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index fccd1952bad3..149aa8bfb1fe 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -488,7 +488,7 @@ void usb_sg_wait (struct usb_sg_request *io) int retval; io->urbs [i]->dev = io->dev; - retval = usb_submit_urb (io->urbs [i], SLAB_ATOMIC); + retval = usb_submit_urb (io->urbs [i], GFP_ATOMIC); /* after we submit, let completions or cancelations fire; * we handshake using io->status. @@ -764,7 +764,7 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size) err = -EINVAL; goto errout; } else { - dev->have_langid = -1; + dev->have_langid = 1; dev->string_langid = tbuf[2] | (tbuf[3]<< 8); /* always use the first langid listed */ dev_dbg (&dev->dev, "default language 0x%04x\n", @@ -828,10 +828,7 @@ char *usb_cache_string(struct usb_device *udev, int index) * Context: !in_interrupt () * * Updates the copy of the device descriptor stored in the device structure, - * which dedicates space for this purpose. Note that several fields are - * converted to the host CPU's byte order: the USB version (bcdUSB), and - * vendors product and version fields (idVendor, idProduct, and bcdDevice). - * That lets device drivers compare against non-byteswapped constants. + * which dedicates space for this purpose. * * Not exported, only for use by the core. If drivers really want to read * the device descriptor directly, they can call usb_get_descriptor() with @@ -1401,7 +1398,7 @@ free_interfaces: } /* Wake up the device so we can send it the Set-Config request */ - ret = usb_autoresume_device(dev, 1); + ret = usb_autoresume_device(dev); if (ret) goto free_interfaces; @@ -1424,7 +1421,7 @@ free_interfaces: dev->actconfig = cp; if (!cp) { usb_set_device_state(dev, USB_STATE_ADDRESS); - usb_autosuspend_device(dev, 1); + usb_autosuspend_device(dev); goto free_interfaces; } usb_set_device_state(dev, USB_STATE_CONFIGURED); @@ -1493,7 +1490,7 @@ free_interfaces: usb_create_sysfs_intf_files (intf); } - usb_autosuspend_device(dev, 1); + usb_autosuspend_device(dev); return 0; } @@ -1504,9 +1501,10 @@ struct set_config_request { }; /* Worker routine for usb_driver_set_configuration() */ -static void driver_set_config_work(void *_req) +static void driver_set_config_work(struct work_struct *work) { - struct set_config_request *req = _req; + struct set_config_request *req = + container_of(work, struct set_config_request, work); usb_lock_device(req->udev); usb_set_configuration(req->udev, req->config); @@ -1544,7 +1542,7 @@ int usb_driver_set_configuration(struct usb_device *udev, int config) return -ENOMEM; req->udev = udev; req->config = config; - INIT_WORK(&req->work, driver_set_config_work, req); + INIT_WORK(&req->work, driver_set_config_work); usb_get_dev(udev); if (!schedule_work(&req->work)) { diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 467cb02832f3..02426d0b9a34 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -200,19 +200,13 @@ static void ksuspend_usb_cleanup(void) destroy_workqueue(ksuspend_usb_wq); } -#else - -#define ksuspend_usb_init() 0 -#define ksuspend_usb_cleanup() do {} while (0) - -#endif - #ifdef CONFIG_USB_SUSPEND /* usb_autosuspend_work - callback routine to autosuspend a USB device */ -static void usb_autosuspend_work(void *_udev) +static void usb_autosuspend_work(struct work_struct *work) { - struct usb_device *udev = _udev; + struct usb_device *udev = + container_of(work, struct usb_device, autosuspend.work); usb_pm_lock(udev); udev->auto_pm = 1; @@ -222,10 +216,17 @@ static void usb_autosuspend_work(void *_udev) #else -static void usb_autosuspend_work(void *_udev) +static void usb_autosuspend_work(struct work_struct *work) {} -#endif +#endif /* CONFIG_USB_SUSPEND */ + +#else + +#define ksuspend_usb_init() 0 +#define ksuspend_usb_cleanup() do {} while (0) + +#endif /* CONFIG_PM */ /** * usb_alloc_dev - usb device constructor (usbcore-internal) @@ -304,7 +305,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1) #ifdef CONFIG_PM mutex_init(&dev->pm_mutex); - INIT_WORK(&dev->autosuspend, usb_autosuspend_work, dev); + INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work); #endif return dev; } @@ -537,138 +538,6 @@ int usb_get_current_frame_number(struct usb_device *dev) return usb_hcd_get_frame_number (dev); } -/** - * usb_endpoint_dir_in - check if the endpoint has IN direction - * @epd: endpoint to be checked - * - * Returns true if the endpoint is of type IN, otherwise it returns false. - */ -int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN); -} - -/** - * usb_endpoint_dir_out - check if the endpoint has OUT direction - * @epd: endpoint to be checked - * - * Returns true if the endpoint is of type OUT, otherwise it returns false. - */ -int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT); -} - -/** - * usb_endpoint_xfer_bulk - check if the endpoint has bulk transfer type - * @epd: endpoint to be checked - * - * Returns true if the endpoint is of type bulk, otherwise it returns false. - */ -int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_BULK); -} - -/** - * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type - * @epd: endpoint to be checked - * - * Returns true if the endpoint is of type interrupt, otherwise it returns - * false. - */ -int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_INT); -} - -/** - * usb_endpoint_xfer_isoc - check if the endpoint has isochronous transfer type - * @epd: endpoint to be checked - * - * Returns true if the endpoint is of type isochronous, otherwise it returns - * false. - */ -int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd) -{ - return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_ISOC); -} - -/** - * usb_endpoint_is_bulk_in - check if the endpoint is bulk IN - * @epd: endpoint to be checked - * - * Returns true if the endpoint has bulk transfer type and IN direction, - * otherwise it returns false. - */ -int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd)); -} - -/** - * usb_endpoint_is_bulk_out - check if the endpoint is bulk OUT - * @epd: endpoint to be checked - * - * Returns true if the endpoint has bulk transfer type and OUT direction, - * otherwise it returns false. - */ -int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd)); -} - -/** - * usb_endpoint_is_int_in - check if the endpoint is interrupt IN - * @epd: endpoint to be checked - * - * Returns true if the endpoint has interrupt transfer type and IN direction, - * otherwise it returns false. - */ -int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd)); -} - -/** - * usb_endpoint_is_int_out - check if the endpoint is interrupt OUT - * @epd: endpoint to be checked - * - * Returns true if the endpoint has interrupt transfer type and OUT direction, - * otherwise it returns false. - */ -int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd)); -} - -/** - * usb_endpoint_is_isoc_in - check if the endpoint is isochronous IN - * @epd: endpoint to be checked - * - * Returns true if the endpoint has isochronous transfer type and IN direction, - * otherwise it returns false. - */ -int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd)); -} - -/** - * usb_endpoint_is_isoc_out - check if the endpoint is isochronous OUT - * @epd: endpoint to be checked - * - * Returns true if the endpoint has isochronous transfer type and OUT direction, - * otherwise it returns false. - */ -int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd) -{ - return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd)); -} - /*-------------------------------------------------------------------*/ /* * __usb_get_extra_descriptor() finds a descriptor of specific type in the @@ -1102,18 +971,6 @@ EXPORT_SYMBOL(__usb_get_extra_descriptor); EXPORT_SYMBOL(usb_find_device); EXPORT_SYMBOL(usb_get_current_frame_number); -EXPORT_SYMBOL_GPL(usb_endpoint_dir_in); -EXPORT_SYMBOL_GPL(usb_endpoint_dir_out); -EXPORT_SYMBOL_GPL(usb_endpoint_xfer_bulk); -EXPORT_SYMBOL_GPL(usb_endpoint_xfer_int); -EXPORT_SYMBOL_GPL(usb_endpoint_xfer_isoc); -EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_in); -EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_out); -EXPORT_SYMBOL_GPL(usb_endpoint_is_int_in); -EXPORT_SYMBOL_GPL(usb_endpoint_is_int_out); -EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_in); -EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_out); - EXPORT_SYMBOL (usb_buffer_alloc); EXPORT_SYMBOL (usb_buffer_free); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 13322e33f912..17830a81be14 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -64,14 +64,13 @@ static inline void usb_pm_unlock(struct usb_device *udev) {} #define USB_AUTOSUSPEND_DELAY (HZ*2) -extern void usb_autosuspend_device(struct usb_device *udev, int dec_busy_cnt); -extern int usb_autoresume_device(struct usb_device *udev, int inc_busy_cnt); +extern void usb_autosuspend_device(struct usb_device *udev); +extern int usb_autoresume_device(struct usb_device *udev); #else -#define usb_autosuspend_device(udev, dec_busy_cnt) do {} while (0) -static inline int usb_autoresume_device(struct usb_device *udev, - int inc_busy_cnt) +#define usb_autosuspend_device(udev) do {} while (0) +static inline int usb_autoresume_device(struct usb_device *udev) { return 0; } diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index bbbc82a8336a..4097a86c4b5e 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -189,7 +189,7 @@ config USB_OTG config USB_GADGET_AT91 boolean "AT91 USB Device Port" - depends on ARCH_AT91RM9200 + depends on ARCH_AT91 select USB_GADGET_SELECTED help Many Atmel AT91 processors (such as the AT91RM2000) have a diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index 1c17d26d03b8..d15bf22b9a03 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -1833,9 +1833,9 @@ static void rx_fill (struct eth_dev *dev, gfp_t gfp_flags) spin_unlock_irqrestore(&dev->req_lock, flags); } -static void eth_work (void *_dev) +static void eth_work (struct work_struct *work) { - struct eth_dev *dev = _dev; + struct eth_dev *dev = container_of(work, struct eth_dev, work); if (test_and_clear_bit (WORK_RX_MEMORY, &dev->todo)) { if (netif_running (dev->net)) @@ -1894,13 +1894,13 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) if (!eth_is_promisc (dev)) { u8 *dest = skb->data; - if (dest [0] & 0x01) { + if (is_multicast_ether_addr(dest)) { u16 type; /* ignores USB_CDC_PACKET_TYPE_MULTICAST and host * SET_ETHERNET_MULTICAST_FILTERS requests */ - if (memcmp (dest, net->broadcast, ETH_ALEN) == 0) + if (is_broadcast_ether_addr(dest)) type = USB_CDC_PACKET_TYPE_BROADCAST; else type = USB_CDC_PACKET_TYPE_ALL_MULTICAST; @@ -2398,7 +2398,7 @@ autoconf_fail: dev = netdev_priv(net); spin_lock_init (&dev->lock); spin_lock_init (&dev->req_lock); - INIT_WORK (&dev->work, eth_work, dev); + INIT_WORK (&dev->work, eth_work); INIT_LIST_HEAD (&dev->tx_reqs); INIT_LIST_HEAD (&dev->rx_reqs); diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 8b975d15538d..a265e262a2ee 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -250,7 +250,7 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/string.h> -#include <linux/suspend.h> +#include <linux/freezer.h> #include <linux/utsname.h> #include <linux/usb_ch9.h> @@ -1909,10 +1909,10 @@ static int fsync_sub(struct lun *curlun) if (!filp->f_op->fsync) return -EINVAL; - inode = filp->f_dentry->d_inode; + inode = filp->f_path.dentry->d_inode; mutex_lock(&inode->i_mutex); rc = filemap_fdatawrite(inode->i_mapping); - err = filp->f_op->fsync(filp, filp->f_dentry, 1); + err = filp->f_op->fsync(filp, filp->f_path.dentry, 1); if (!rc) rc = err; err = filemap_fdatawait(inode->i_mapping); @@ -1950,7 +1950,7 @@ static int do_synchronize_cache(struct fsg_dev *fsg) static void invalidate_sub(struct lun *curlun) { struct file *filp = curlun->filp; - struct inode *inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_path.dentry->d_inode; unsigned long rc; rc = invalidate_inode_pages(inode->i_mapping); @@ -3526,8 +3526,8 @@ static int open_backing_file(struct lun *curlun, const char *filename) if (!(filp->f_mode & FMODE_WRITE)) ro = 1; - if (filp->f_dentry) - inode = filp->f_dentry->d_inode; + if (filp->f_path.dentry) + inode = filp->f_path.dentry->d_inode; if (inode && S_ISBLK(inode->i_mode)) { if (bdev_read_only(inode->i_bdev)) ro = 1; @@ -3606,7 +3606,7 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char down_read(&fsg->filesem); if (backing_file_is_open(curlun)) { // Get the complete pathname - p = d_path(curlun->filp->f_dentry, curlun->filp->f_vfsmnt, + p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1); if (IS_ERR(p)) rc = PTR_ERR(p); @@ -4030,8 +4030,8 @@ static int __init fsg_bind(struct usb_gadget *gadget) if (backing_file_is_open(curlun)) { p = NULL; if (pathbuf) { - p = d_path(curlun->filp->f_dentry, - curlun->filp->f_vfsmnt, + p = d_path(curlun->filp->f_path.dentry, + curlun->filp->f_path.mnt, pathbuf, PATH_MAX); if (IS_ERR(p)) p = NULL; diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index 64554acad63f..31351826f2ba 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c @@ -1236,7 +1236,7 @@ autoconf_fail: /* ok, we made sense of the hardware ... */ - dev = kzalloc(sizeof(*dev), SLAB_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { return -ENOMEM; } diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index a3076da3f4eb..805a9826842d 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -1864,7 +1864,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id) } /* alloc, and start init */ - dev = kmalloc (sizeof *dev, SLAB_KERNEL); + dev = kmalloc (sizeof *dev, GFP_KERNEL); if (dev == NULL){ pr_debug("enomem %s\n", pci_name(pdev)); retval = -ENOMEM; diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index 86924f9cdd7e..3fb1044a4db0 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -412,7 +412,7 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr) /* FIXME readahead for O_NONBLOCK and poll(); careful with ZLPs */ value = -ENOMEM; - kbuf = kmalloc (len, SLAB_KERNEL); + kbuf = kmalloc (len, GFP_KERNEL); if (unlikely (!kbuf)) goto free1; @@ -456,7 +456,7 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) /* FIXME writebehind for O_NONBLOCK and poll(), qlen = 1 */ value = -ENOMEM; - kbuf = kmalloc (len, SLAB_KERNEL); + kbuf = kmalloc (len, GFP_KERNEL); if (!kbuf) goto free1; if (copy_from_user (kbuf, buf, len)) { @@ -1898,7 +1898,7 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr) buf += 4; length -= 4; - kbuf = kmalloc (length, SLAB_KERNEL); + kbuf = kmalloc (length, GFP_KERNEL); if (!kbuf) return -ENOMEM; if (copy_from_user (kbuf, buf, length)) { diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c index 179259664c18..4a991564a03e 100644 --- a/drivers/usb/gadget/lh7a40x_udc.c +++ b/drivers/usb/gadget/lh7a40x_udc.c @@ -83,7 +83,6 @@ static int lh7a40x_queue(struct usb_ep *ep, struct usb_request *, gfp_t); static int lh7a40x_dequeue(struct usb_ep *ep, struct usb_request *); static int lh7a40x_set_halt(struct usb_ep *ep, int); static int lh7a40x_fifo_status(struct usb_ep *ep); -static int lh7a40x_fifo_status(struct usb_ep *ep); static void lh7a40x_fifo_flush(struct usb_ep *ep); static void lh7a40x_ep0_kick(struct lh7a40x_udc *dev, struct lh7a40x_ep *ep); static void lh7a40x_handle_ep0(struct lh7a40x_udc *dev, u32 intr); diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c index d954daa8e9e0..3024c679e38e 100644 --- a/drivers/usb/gadget/net2280.c +++ b/drivers/usb/gadget/net2280.c @@ -1040,6 +1040,7 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) } /* else the irq handler advances the queue. */ + ep->responded = 1; if (req) list_add_tail (&req->queue, &ep->queue); done: @@ -1774,8 +1775,8 @@ static DEVICE_ATTR (queues, S_IRUGO, show_queues, NULL); #else -#define device_create_file(a,b) do {} while (0) -#define device_remove_file device_create_file +#define device_create_file(a,b) (0) +#define device_remove_file(a,b) do { } while (0) #endif @@ -2044,8 +2045,10 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) return retval; } - device_create_file (&dev->pdev->dev, &dev_attr_function); - device_create_file (&dev->pdev->dev, &dev_attr_queues); + retval = device_create_file (&dev->pdev->dev, &dev_attr_function); + if (retval) goto err_unbind; + retval = device_create_file (&dev->pdev->dev, &dev_attr_queues); + if (retval) goto err_func; /* ... then enable host detection and ep0; and we're ready * for set_configuration as well as eventual disconnect. @@ -2060,6 +2063,14 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver) /* pci writes may still be posted */ return 0; + +err_func: + device_remove_file (&dev->pdev->dev, &dev_attr_function); +err_unbind: + driver->unbind (&dev->gadget); + dev->gadget.dev.driver = NULL; + dev->driver = NULL; + return retval; } EXPORT_SYMBOL (usb_gadget_register_driver); @@ -2178,7 +2189,8 @@ static void handle_ep_small (struct net2280_ep *ep) ep->stopped = 1; set_halt (ep); mode = 2; - } else if (!req && !ep->stopped) + } else if (ep->responded && + !req && !ep->stopped) write_fifo (ep, NULL); } } else { @@ -2193,7 +2205,7 @@ static void handle_ep_small (struct net2280_ep *ep) } else if (((t & (1 << DATA_OUT_PING_TOKEN_INTERRUPT)) && req && req->req.actual == req->req.length) - || !req) { + || (ep->responded && !req)) { ep->dev->protocol_stall = 1; set_halt (ep); ep->stopped = 1; @@ -2459,6 +2471,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat) /* we made the hardware handle most lowlevel requests; * everything else goes uplevel to the gadget code. */ + ep->responded = 1; switch (u.r.bRequest) { case USB_REQ_GET_STATUS: { struct net2280_ep *e; @@ -2527,6 +2540,7 @@ delegate: u.r.bRequestType, u.r.bRequest, w_value, w_index, w_length, readl (&ep->regs->ep_cfg)); + ep->responded = 0; spin_unlock (&dev->lock); tmp = dev->driver->setup (&dev->gadget, &u.r); spin_lock (&dev->lock); @@ -2847,7 +2861,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) } /* alloc, and start init */ - dev = kzalloc (sizeof *dev, SLAB_KERNEL); + dev = kzalloc (sizeof *dev, GFP_KERNEL); if (dev == NULL){ retval = -ENOMEM; goto done; @@ -2974,8 +2988,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id) : "disabled"); the_controller = dev; - device_register (&dev->gadget.dev); - device_create_file (&pdev->dev, &dev_attr_registers); + retval = device_register (&dev->gadget.dev); + if (retval) goto done; + retval = device_create_file (&pdev->dev, &dev_attr_registers); + if (retval) goto done; return 0; diff --git a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h index 957d6df34015..44ca139983d8 100644 --- a/drivers/usb/gadget/net2280.h +++ b/drivers/usb/gadget/net2280.h @@ -110,7 +110,8 @@ struct net2280_ep { out_overflow : 1, stopped : 1, is_in : 1, - is_iso : 1; + is_iso : 1, + responded : 1; }; static inline void allow_status (struct net2280_ep *ep) diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 48a09fd89d18..030d87c28c2f 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -2581,7 +2581,7 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv) /* UDC_PULLUP_EN gates the chip clock */ // OTG_SYSCON_1_REG |= DEV_IDLE_EN; - udc = kzalloc(sizeof(*udc), SLAB_KERNEL); + udc = kzalloc(sizeof(*udc), GFP_KERNEL); if (!udc) return -ENOMEM; diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c index f42c00ef0bca..1ed506e95985 100644 --- a/drivers/usb/gadget/pxa2xx_udc.c +++ b/drivers/usb/gadget/pxa2xx_udc.c @@ -43,11 +43,11 @@ #include <linux/mm.h> #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#include <linux/irq.h> #include <asm/byteorder.h> #include <asm/dma.h> #include <asm/io.h> -#include <asm/irq.h> #include <asm/system.h> #include <asm/mach-types.h> #include <asm/unaligned.h> @@ -2472,6 +2472,7 @@ static struct pxa2xx_udc memory = { #define PXA210_B1 0x00000123 #define PXA210_B0 0x00000122 #define IXP425_A0 0x000001c1 +#define IXP425_B0 0x000001f1 #define IXP465_AD 0x00000200 /* @@ -2509,6 +2510,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev) break; #elif defined(CONFIG_ARCH_IXP4XX) case IXP425_A0: + case IXP425_B0: case IXP465_AD: dev->has_cfr = 1; out_dma = 0; diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 208e55a667ac..5516c59ed5ec 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -200,7 +200,7 @@ static void gs_unthrottle(struct tty_struct * tty); static void gs_break(struct tty_struct *tty, int break_state); static int gs_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg); -static void gs_set_termios(struct tty_struct *tty, struct termios *old); +static void gs_set_termios(struct tty_struct *tty, struct ktermios *old); static int gs_send(struct gs_dev *dev); static int gs_send_packet(struct gs_dev *dev, char *packet, @@ -1077,7 +1077,7 @@ static int gs_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, /* * gs_set_termios */ -static void gs_set_termios(struct tty_struct *tty, struct termios *old) +static void gs_set_termios(struct tty_struct *tty, struct ktermios *old) { } diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 0f809dd68492..40710ea1b490 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -1190,7 +1190,7 @@ autoconf_fail: /* ok, we made sense of the hardware ... */ - dev = kzalloc(sizeof(*dev), SLAB_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; spin_lock_init (&dev->lock); diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index cf10cbc98f80..cc60759083bf 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -153,7 +153,7 @@ config USB_U132_HCD adapter will *NOT* work with PC cards that do not contain an OHCI controller. - For those PC cards that contain multiple OHCI controllers only ther + For those PC cards that contain multiple OHCI controllers only the first one is used. The driver consists of two modules, the "ftdi-elan" module is a diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 23b95b2bfe15..56349d21e6ea 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -492,7 +492,7 @@ show_periodic (struct class_device *class_dev, char *buf) unsigned i; __le32 tag; - if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC))) + if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC))) return 0; seen_count = 0; @@ -754,7 +754,9 @@ show_registers (struct class_device *class_dev, char *buf) } if (ehci->reclaim) { - temp = scnprintf (next, size, "reclaim qh %p\n", ehci->reclaim); + temp = scnprintf (next, size, "reclaim qh %p%s\n", + ehci->reclaim, + ehci->reclaim_ready ? " ready" : ""); size -= temp; next += temp; } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index aac6ec5dd7cf..025d33313681 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -111,7 +111,7 @@ static const char hcd_name [] = "ehci_hcd"; #define EHCI_TUNE_MULT_TT 1 #define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */ -#define EHCI_IAA_MSECS 10 /* arbitrary */ +#define EHCI_IAA_JIFFIES (HZ/100) /* arbitrary; ~10 msec */ #define EHCI_IO_JIFFIES (HZ/10) /* io watchdog > irq_thresh */ #define EHCI_ASYNC_JIFFIES (HZ/20) /* async idle timeout */ #define EHCI_SHRINK_JIFFIES (HZ/200) /* async qh unlink delay */ @@ -126,6 +126,11 @@ static unsigned park = 0; module_param (park, uint, S_IRUGO); MODULE_PARM_DESC (park, "park setting; 1-3 back-to-back async packets"); +/* for flakey hardware, ignore overcurrent indicators */ +static int ignore_oc = 0; +module_param (ignore_oc, bool, S_IRUGO); +MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications"); + #define INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT) /*-------------------------------------------------------------------------*/ @@ -254,7 +259,6 @@ static void ehci_quiesce (struct ehci_hcd *ehci) /*-------------------------------------------------------------------------*/ -static void end_unlink_async (struct ehci_hcd *ehci); static void ehci_work(struct ehci_hcd *ehci); #include "ehci-hub.c" @@ -264,37 +268,25 @@ static void ehci_work(struct ehci_hcd *ehci); /*-------------------------------------------------------------------------*/ -static void ehci_iaa_watchdog (unsigned long param) +static void ehci_watchdog (unsigned long param) { struct ehci_hcd *ehci = (struct ehci_hcd *) param; unsigned long flags; - u32 status; spin_lock_irqsave (&ehci->lock, flags); - WARN_ON(!ehci->reclaim); - /* lost IAA irqs wedge things badly; seen first with a vt8235 */ + /* lost IAA irqs wedge things badly; seen with a vt8235 */ if (ehci->reclaim) { - status = readl (&ehci->regs->status); + u32 status = readl (&ehci->regs->status); if (status & STS_IAA) { ehci_vdbg (ehci, "lost IAA\n"); COUNT (ehci->stats.lost_iaa); writel (STS_IAA, &ehci->regs->status); - end_unlink_async (ehci); + ehci->reclaim_ready = 1; } } - spin_unlock_irqrestore (&ehci->lock, flags); -} - -static void ehci_watchdog (unsigned long param) -{ - struct ehci_hcd *ehci = (struct ehci_hcd *) param; - unsigned long flags; - - spin_lock_irqsave (&ehci->lock, flags); - - /* stop async processing after it's idled a bit */ + /* stop async processing after it's idled a bit */ if (test_bit (TIMER_ASYNC_OFF, &ehci->actions)) start_unlink_async (ehci, ehci->async); @@ -345,6 +337,8 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on) static void ehci_work (struct ehci_hcd *ehci) { timer_action_done (ehci, TIMER_IO_WATCHDOG); + if (ehci->reclaim_ready) + end_unlink_async (ehci); /* another CPU may drop ehci->lock during a schedule scan while * it reports urb completions. this flag guards against bogus @@ -379,7 +373,6 @@ static void ehci_stop (struct usb_hcd *hcd) /* no more interrupts ... */ del_timer_sync (&ehci->watchdog); - del_timer_sync (&ehci->iaa_watchdog); spin_lock_irq(&ehci->lock); if (HC_IS_RUNNING (hcd->state)) @@ -426,10 +419,6 @@ static int ehci_init(struct usb_hcd *hcd) ehci->watchdog.function = ehci_watchdog; ehci->watchdog.data = (unsigned long) ehci; - init_timer(&ehci->iaa_watchdog); - ehci->iaa_watchdog.function = ehci_iaa_watchdog; - ehci->iaa_watchdog.data = (unsigned long) ehci; - /* * hw default: 1K periodic list heads, one per frame. * periodic_size can shrink by USBCMD update if hcc_params allows. @@ -446,6 +435,7 @@ static int ehci_init(struct usb_hcd *hcd) ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params); ehci->reclaim = NULL; + ehci->reclaim_ready = 0; ehci->next_uframe = -1; /* @@ -556,9 +546,10 @@ static int ehci_run (struct usb_hcd *hcd) temp = HC_VERSION(readl (&ehci->caps->hc_capbase)); ehci_info (ehci, - "USB %x.%x started, EHCI %x.%02x, driver %s\n", + "USB %x.%x started, EHCI %x.%02x, driver %s%s\n", ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f), - temp >> 8, temp & 0xff, DRIVER_VERSION); + temp >> 8, temp & 0xff, DRIVER_VERSION, + ignore_oc ? ", overcurrent ignored" : ""); writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */ @@ -619,7 +610,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* complete the unlinking of some qh [4.15.2.3] */ if (status & STS_IAA) { COUNT (ehci->stats.reclaim); - end_unlink_async (ehci); + ehci->reclaim_ready = 1; bh = 1; } @@ -628,9 +619,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) unsigned i = HCS_N_PORTS (ehci->hcs_params); /* resume root hub? */ - status = readl (&ehci->regs->command); - if (!(status & CMD_RUN)) - writel (status | CMD_RUN, &ehci->regs->command); + if (!(readl(&ehci->regs->command) & CMD_RUN)) + usb_hcd_resume_root_hub(hcd); while (i--) { int pstatus = readl (&ehci->regs->port_status [i]); @@ -647,7 +637,6 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) */ ehci->reset_done [i] = jiffies + msecs_to_jiffies (20); ehci_dbg (ehci, "port %d remote wakeup\n", i + 1); - usb_hcd_resume_root_hub(hcd); } } @@ -723,14 +712,10 @@ static int ehci_urb_enqueue ( static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) { - // BUG_ON(qh->qh_state != QH_STATE_LINKED); - - /* failfast */ - if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) - end_unlink_async (ehci); - - /* defer till later if busy */ - else if (ehci->reclaim) { + /* if we need to use IAA and it's busy, defer */ + if (qh->qh_state == QH_STATE_LINKED + && ehci->reclaim + && HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) { struct ehci_qh *last; for (last = ehci->reclaim; @@ -740,8 +725,12 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) qh->qh_state = QH_STATE_UNLINK_WAIT; last->reclaim = qh; - /* start IAA cycle */ - } else + /* bypass IAA if the hc can't care */ + } else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim) + end_unlink_async (ehci); + + /* something else might have unlinked the qh by now */ + if (qh->qh_state == QH_STATE_LINKED) start_unlink_async (ehci, qh); } @@ -763,19 +752,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) qh = (struct ehci_qh *) urb->hcpriv; if (!qh) break; - switch (qh->qh_state) { - case QH_STATE_LINKED: - case QH_STATE_COMPLETING: - unlink_async (ehci, qh); - break; - case QH_STATE_UNLINK: - case QH_STATE_UNLINK_WAIT: - /* already started */ - break; - case QH_STATE_IDLE: - WARN_ON(1); - break; - } + unlink_async (ehci, qh); break; case PIPE_INTERRUPT: @@ -867,7 +844,6 @@ rescan: unlink_async (ehci, qh); /* FALL THROUGH */ case QH_STATE_UNLINK: /* wait for hw to finish? */ - case QH_STATE_UNLINK_WAIT: idle_timeout: spin_unlock_irqrestore (&ehci->lock, flags); schedule_timeout_uninterruptible(1); diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 2012213c0a25..bfe5f307cba6 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -34,6 +34,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); int port; + int mask; if (time_before (jiffies, ehci->next_statechange)) msleep(5); @@ -48,17 +49,28 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) } ehci->command = readl (&ehci->regs->command); if (ehci->reclaim) - end_unlink_async (ehci); + ehci->reclaim_ready = 1; ehci_work(ehci); - /* suspend any active/unsuspended ports, maybe allow wakeup */ + /* Unlike other USB host controller types, EHCI doesn't have + * any notion of "global" or bus-wide suspend. The driver has + * to manually suspend all the active unsuspended ports, and + * then manually resume them in the bus_resume() routine. + */ + ehci->bus_suspended = 0; while (port--) { u32 __iomem *reg = &ehci->regs->port_status [port]; u32 t1 = readl (reg) & ~PORT_RWC_BITS; u32 t2 = t1; - if ((t1 & PORT_PE) && !(t1 & PORT_OWNER)) + /* keep track of which ports we suspend */ + if ((t1 & PORT_PE) && !(t1 & PORT_OWNER) && + !(t1 & PORT_SUSPEND)) { t2 |= PORT_SUSPEND; + set_bit(port, &ehci->bus_suspended); + } + + /* enable remote wakeup on all ports */ if (device_may_wakeup(&hcd->self.root_hub->dev)) t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E; else @@ -76,6 +88,13 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) ehci_halt (ehci); hcd->state = HC_STATE_SUSPENDED; + /* allow remote wakeup */ + mask = INTR_MASK; + if (!device_may_wakeup(&hcd->self.root_hub->dev)) + mask &= ~STS_PCD; + writel(mask, &ehci->regs->intr_enable); + readl(&ehci->regs->intr_enable); + ehci->next_statechange = jiffies + msecs_to_jiffies(10); spin_unlock_irq (&ehci->lock); return 0; @@ -88,7 +107,6 @@ static int ehci_bus_resume (struct usb_hcd *hcd) struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 temp; int i; - int intr_enable; if (time_before (jiffies, ehci->next_statechange)) msleep(5); @@ -100,31 +118,30 @@ static int ehci_bus_resume (struct usb_hcd *hcd) * the last user of the controller, not reset/pm hardware keeping * state we gave to it. */ + temp = readl(&ehci->regs->intr_enable); + ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss"); - /* re-init operational registers in case we lost power */ - if (readl (&ehci->regs->intr_enable) == 0) { - /* at least some APM implementations will try to deliver - * IRQs right away, so delay them until we're ready. - */ - intr_enable = 1; - writel (0, &ehci->regs->segment); - writel (ehci->periodic_dma, &ehci->regs->frame_list); - writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next); - } else - intr_enable = 0; - ehci_dbg(ehci, "resume root hub%s\n", - intr_enable ? " after power loss" : ""); + /* at least some APM implementations will try to deliver + * IRQs right away, so delay them until we're ready. + */ + writel(0, &ehci->regs->intr_enable); + + /* re-init operational registers */ + writel(0, &ehci->regs->segment); + writel(ehci->periodic_dma, &ehci->regs->frame_list); + writel((u32) ehci->async->qh_dma, &ehci->regs->async_next); /* restore CMD_RUN, framelist size, and irq threshold */ writel (ehci->command, &ehci->regs->command); - /* take ports out of suspend */ + /* manually resume the ports we suspended during bus_suspend() */ i = HCS_N_PORTS (ehci->hcs_params); while (i--) { temp = readl (&ehci->regs->port_status [i]); temp &= ~(PORT_RWC_BITS | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E); - if (temp & PORT_SUSPEND) { + if (test_bit(i, &ehci->bus_suspended) && + (temp & PORT_SUSPEND)) { ehci->reset_done [i] = jiffies + msecs_to_jiffies (20); temp |= PORT_RESUME; } @@ -134,11 +151,12 @@ static int ehci_bus_resume (struct usb_hcd *hcd) mdelay (20); while (i--) { temp = readl (&ehci->regs->port_status [i]); - if ((temp & PORT_SUSPEND) == 0) - continue; - temp &= ~(PORT_RWC_BITS | PORT_RESUME); - writel (temp, &ehci->regs->port_status [i]); - ehci_vdbg (ehci, "resumed port %d\n", i + 1); + if (test_bit(i, &ehci->bus_suspended) && + (temp & PORT_SUSPEND)) { + temp &= ~(PORT_RWC_BITS | PORT_RESUME); + writel (temp, &ehci->regs->port_status [i]); + ehci_vdbg (ehci, "resumed port %d\n", i + 1); + } } (void) readl (&ehci->regs->command); @@ -157,8 +175,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) hcd->state = HC_STATE_RUNNING; /* Now we can safely re-enable irqs */ - if (intr_enable) - writel (INTR_MASK, &ehci->regs->intr_enable); + writel(INTR_MASK, &ehci->regs->intr_enable); spin_unlock_irq (&ehci->lock); return 0; @@ -218,6 +235,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) { struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 temp, status = 0; + u32 mask; int ports, i, retval = 1; unsigned long flags; @@ -233,6 +251,18 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) retval++; } + /* Some boards (mostly VIA?) report bogus overcurrent indications, + * causing massive log spam unless we completely ignore them. It + * may be relevant that VIA VT8235 controlers, where PORT_POWER is + * always set, seem to clear PORT_OCC and PORT_CSC when writing to + * PORT_POWER; that's surprising, but maybe within-spec. + */ + if (!ignore_oc) + mask = PORT_CSC | PORT_PEC | PORT_OCC; + else + mask = PORT_CSC | PORT_PEC; + // PORT_RESUME from hardware ~= PORT_STAT_C_SUSPEND + /* no hub change reports (bit 0) for now (power, ...) */ /* port N changes (bit N)? */ @@ -250,8 +280,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) } if (!(temp & PORT_CONNECT)) ehci->reset_done [i] = 0; - if ((temp & (PORT_CSC | PORT_PEC | PORT_OCC)) != 0 - // PORT_STAT_C_SUSPEND? + if ((temp & mask) != 0 || ((temp & PORT_RESUME) != 0 && time_after (jiffies, ehci->reset_done [i]))) { @@ -319,6 +348,7 @@ static int ehci_hub_control ( u32 temp, status; unsigned long flags; int retval = 0; + unsigned selector; /* * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR. @@ -417,7 +447,7 @@ static int ehci_hub_control ( status |= 1 << USB_PORT_FEAT_C_CONNECTION; if (temp & PORT_PEC) status |= 1 << USB_PORT_FEAT_C_ENABLE; - if (temp & PORT_OCC) + if ((temp & PORT_OCC) && !ignore_oc) status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT; /* whoever resumes must GetPortStatus to complete it!! */ @@ -506,6 +536,8 @@ static int ehci_hub_control ( } break; case SetPortFeature: + selector = wIndex >> 8; + wIndex &= 0xff; if (!wIndex || wIndex > ports) goto error; wIndex--; @@ -559,6 +591,22 @@ static int ehci_hub_control ( } writel (temp, &ehci->regs->port_status [wIndex]); break; + + /* For downstream facing ports (these): one hub port is put + * into test mode according to USB2 11.24.2.13, then the hub + * must be reset (which for root hub now means rmmod+modprobe, + * or else system reboot). See EHCI 2.3.9 and 4.14 for info + * about the EHCI-specific stuff. + */ + case USB_PORT_FEAT_TEST: + if (!selector || selector > 5) + goto error; + ehci_quiesce(ehci); + ehci_halt(ehci); + temp |= selector << 16; + writel (temp, &ehci->regs->port_status [wIndex]); + break; + default: goto error; } diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index 35e3fab6fc4e..4bc7970ba3ef 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -257,9 +257,7 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message) static int ehci_pci_resume(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); - unsigned port; struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - int retval = -EINVAL; // maybe restore FLADJ @@ -269,27 +267,19 @@ static int ehci_pci_resume(struct usb_hcd *hcd) /* Mark hardware accessible again as we are out of D3 state by now */ set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - /* If CF is clear, we lost PCI Vaux power and need to restart. */ - if (readl(&ehci->regs->configured_flag) != FLAG_CF) - goto restart; - - /* If any port is suspended (or owned by the companion), - * we know we can/must resume the HC (and mustn't reset it). - * We just defer that to the root hub code. + /* If CF is still set, we maintained PCI Vaux power. + * Just undo the effect of ehci_pci_suspend(). */ - for (port = HCS_N_PORTS(ehci->hcs_params); port > 0; ) { - u32 status; - port--; - status = readl(&ehci->regs->port_status [port]); - if (!(status & PORT_POWER)) - continue; - if (status & (PORT_SUSPEND | PORT_RESUME | PORT_OWNER)) { - usb_hcd_resume_root_hub(hcd); - return 0; - } + if (readl(&ehci->regs->configured_flag) == FLAG_CF) { + int mask = INTR_MASK; + + if (!device_may_wakeup(&hcd->self.root_hub->dev)) + mask &= ~STS_PCD; + writel(mask, &ehci->regs->intr_enable); + readl(&ehci->regs->intr_enable); + return 0; } -restart: ehci_dbg(ehci, "lost power, restarting\n"); usb_root_hub_lost_power(hcd->self.root_hub); @@ -303,17 +293,19 @@ restart: /* emptying the schedule aborts any urbs */ spin_lock_irq(&ehci->lock); if (ehci->reclaim) - end_unlink_async (ehci); + ehci->reclaim_ready = 1; ehci_work(ehci); spin_unlock_irq(&ehci->lock); - /* restart; khubd will disconnect devices */ - retval = ehci_run(hcd); - /* here we "know" root ports should always stay powered */ ehci_port_power(ehci, 1); - return retval; + writel(ehci->command, &ehci->regs->command); + writel(FLAG_CF, &ehci->regs->configured_flag); + readl(&ehci->regs->command); /* unblock posted writes */ + + hcd->state = HC_STATE_SUSPENDED; + return 0; } #endif diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 46327272f614..62e46dc60e86 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -967,7 +967,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) struct ehci_qh *qh = ehci->reclaim; struct ehci_qh *next; - iaa_watchdog_done (ehci); + timer_action_done (ehci, TIMER_IAA_WATCHDOG); // qh->hw_next = cpu_to_le32 (qh->qh_dma); qh->qh_state = QH_STATE_IDLE; @@ -977,6 +977,7 @@ static void end_unlink_async (struct ehci_hcd *ehci) /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ next = qh->reclaim; ehci->reclaim = next; + ehci->reclaim_ready = 0; qh->reclaim = NULL; qh_completions (ehci, qh); @@ -1051,10 +1052,11 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) return; } + ehci->reclaim_ready = 0; cmd |= CMD_IAAD; writel (cmd, &ehci->regs->command); (void) readl (&ehci->regs->command); - iaa_watchdog_start (ehci); + timer_action (ehci, TIMER_IAA_WATCHDOG); } /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 6aac39f50e07..74dbc6c8228f 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -58,6 +58,7 @@ struct ehci_hcd { /* one per controller */ /* async schedule support */ struct ehci_qh *async; struct ehci_qh *reclaim; + unsigned reclaim_ready : 1; unsigned scanning : 1; /* periodic schedule support */ @@ -73,6 +74,7 @@ struct ehci_hcd { /* one per controller */ /* per root hub port */ unsigned long reset_done [EHCI_MAX_ROOT_PORTS]; + unsigned long bus_suspended; /* per-HC memory pools (could be per-bus, but ...) */ struct dma_pool *qh_pool; /* qh per active urb */ @@ -80,7 +82,6 @@ struct ehci_hcd { /* one per controller */ struct dma_pool *itd_pool; /* itd per iso urb */ struct dma_pool *sitd_pool; /* sitd per split iso urb */ - struct timer_list iaa_watchdog; struct timer_list watchdog; unsigned long actions; unsigned stamp; @@ -114,21 +115,9 @@ static inline struct usb_hcd *ehci_to_hcd (struct ehci_hcd *ehci) } -static inline void -iaa_watchdog_start (struct ehci_hcd *ehci) -{ - WARN_ON(timer_pending(&ehci->iaa_watchdog)); - mod_timer (&ehci->iaa_watchdog, - jiffies + msecs_to_jiffies(EHCI_IAA_MSECS)); -} - -static inline void iaa_watchdog_done (struct ehci_hcd *ehci) -{ - del_timer (&ehci->iaa_watchdog); -} - enum ehci_timer_action { TIMER_IO_WATCHDOG, + TIMER_IAA_WATCHDOG, TIMER_ASYNC_SHRINK, TIMER_ASYNC_OFF, }; @@ -146,6 +135,9 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) unsigned long t; switch (action) { + case TIMER_IAA_WATCHDOG: + t = EHCI_IAA_JIFFIES; + break; case TIMER_IO_WATCHDOG: t = EHCI_IO_JIFFIES; break; @@ -162,7 +154,8 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) // async queue SHRINK often precedes IAA. while it's ready // to go OFF neither can matter, and afterwards the IO // watchdog stops unless there's still periodic traffic. - if (time_before_eq(t, ehci->watchdog.expires) + if (action != TIMER_IAA_WATCHDOG + && t > ehci->watchdog.expires && timer_pending (&ehci->watchdog)) return; mod_timer (&ehci->watchdog, t); diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c index 87eca6aeacf2..9325e46a68c0 100644 --- a/drivers/usb/host/hc_crisv10.c +++ b/drivers/usb/host/hc_crisv10.c @@ -188,7 +188,7 @@ static DEFINE_TIMER(bulk_eot_timer, NULL, 0, 0); #define CHECK_ALIGN(x) if (((__u32)(x)) & 0x00000003) \ {panic("Alignment check (DWORD) failed at %s:%s:%d\n", __FILE__, __FUNCTION__, __LINE__);} -#define SLAB_FLAG (in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL) +#define SLAB_FLAG (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL) #define KMALLOC_FLAG (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL) /* Most helpful debugging aid */ @@ -275,13 +275,13 @@ static volatile USB_SB_Desc_t TxIntrSB_zout __attribute__ ((aligned (4))); static int zout_buffer[4] __attribute__ ((aligned (4))); /* Cache for allocating new EP and SB descriptors. */ -static kmem_cache_t *usb_desc_cache; +static struct kmem_cache *usb_desc_cache; /* Cache for the registers allocated in the top half. */ -static kmem_cache_t *top_half_reg_cache; +static struct kmem_cache *top_half_reg_cache; /* Cache for the data allocated in the isoc descr top half. */ -static kmem_cache_t *isoc_compl_cache; +static struct kmem_cache *isoc_compl_cache; static struct usb_bus *etrax_usb_bus; @@ -1743,7 +1743,7 @@ static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc) *R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do); - comp_data = (usb_isoc_complete_data_t*)kmem_cache_alloc(isoc_compl_cache, SLAB_ATOMIC); + comp_data = (usb_isoc_complete_data_t*)kmem_cache_alloc(isoc_compl_cache, GFP_ATOMIC); assert(comp_data != NULL); INIT_WORK(&comp_data->usb_bh, etrax_usb_isoc_descr_interrupt_bottom_half, comp_data); @@ -3010,7 +3010,7 @@ static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid) if (!urb->iso_frame_desc[i].length) continue; - next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_ATOMIC); + next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_ATOMIC); assert(next_sb_desc != NULL); if (urb->iso_frame_desc[i].length > 0) { @@ -3063,7 +3063,7 @@ static void etrax_usb_add_to_isoc_sb_list(struct urb *urb, int epid) if (TxIsocEPList[epid].sub == 0) { dbg_isoc("Isoc traffic not already running, allocating SB"); - next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, SLAB_ATOMIC); + next_sb_desc = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_ATOMIC); assert(next_sb_desc != NULL); next_sb_desc->command = (IO_STATE(USB_SB_command, tt, in) | @@ -3317,7 +3317,7 @@ static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc) restore_flags(flags); - reg = (usb_interrupt_registers_t *)kmem_cache_alloc(top_half_reg_cache, SLAB_ATOMIC); + reg = (usb_interrupt_registers_t *)kmem_cache_alloc(top_half_reg_cache, GFP_ATOMIC); assert(reg != NULL); diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index 8293c1d4be3f..0f47a57dac28 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -505,7 +505,7 @@ show_periodic (struct class_device *class_dev, char *buf) char *next; unsigned i; - if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, SLAB_ATOMIC))) + if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC))) return 0; seen_count = 0; diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 9be6b303e784..b28a9b602066 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -715,13 +715,6 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) return IRQ_NOTMINE; } - if (ints & OHCI_INTR_RHSC) { - ohci_vdbg (ohci, "rhsc\n"); - ohci->next_statechange = jiffies + STATECHANGE_DELAY; - ohci_writel (ohci, OHCI_INTR_RHSC, ®s->intrstatus); - usb_hcd_poll_rh_status(hcd); - } - if (ints & OHCI_INTR_UE) { disable (ohci); ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n"); @@ -731,9 +724,31 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd) ohci_usb_reset (ohci); } - if (ints & OHCI_INTR_RD) { - ohci_vdbg (ohci, "resume detect\n"); - ohci_writel (ohci, OHCI_INTR_RD, ®s->intrstatus); + if (ints & OHCI_INTR_RHSC) { + ohci_vdbg(ohci, "rhsc\n"); + ohci->next_statechange = jiffies + STATECHANGE_DELAY; + ohci_writel(ohci, OHCI_INTR_RD | OHCI_INTR_RHSC, + ®s->intrstatus); + + /* NOTE: Vendors didn't always make the same implementation + * choices for RHSC. Many followed the spec; RHSC triggers + * on an edge, like setting and maybe clearing a port status + * change bit. With others it's level-triggered, active + * until khubd clears all the port status change bits. We'll + * always disable it here and rely on polling until khubd + * re-enables it. + */ + ohci_writel(ohci, OHCI_INTR_RHSC, ®s->intrdisable); + usb_hcd_poll_rh_status(hcd); + } + + /* For connect and disconnect events, we expect the controller + * to turn on RHSC along with RD. But for remote wakeup events + * this might not happen. + */ + else if (ints & OHCI_INTR_RD) { + ohci_vdbg(ohci, "resume detect\n"); + ohci_writel(ohci, OHCI_INTR_RD, ®s->intrstatus); hcd->poll_rh = 1; if (ohci->autostop) { spin_lock (&ohci->lock); @@ -930,7 +945,7 @@ MODULE_LICENSE ("GPL"); #include "ohci-ppc-soc.c" #endif -#if defined(CONFIG_ARCH_AT91RM9200) || defined(CONFIG_ARCH_AT91SAM9261) +#ifdef CONFIG_ARCH_AT91 #include "ohci-at91.c" #endif @@ -947,8 +962,7 @@ MODULE_LICENSE ("GPL"); || defined (CONFIG_ARCH_EP93XX) \ || defined (CONFIG_SOC_AU1X00) \ || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \ - || defined (CONFIG_ARCH_AT91RM9200) \ - || defined (CONFIG_ARCH_AT91SAM9261) \ + || defined (CONFIG_ARCH_AT91) \ || defined (CONFIG_ARCH_PNX4008) \ ) #error "missing bus glue for ohci-hcd" diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 6f113596af66..2441642cb7b4 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -41,7 +41,11 @@ static void ohci_rhsc_enable (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); - ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); + spin_lock_irq(&ohci->lock); + if (!ohci->autostop) + del_timer(&hcd->rh_timer); /* Prevent next poll */ + ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); + spin_unlock_irq(&ohci->lock); } #define OHCI_SCHED_ENABLES \ @@ -50,6 +54,9 @@ static void ohci_rhsc_enable (struct usb_hcd *hcd) static void dl_done_list (struct ohci_hcd *); static void finish_unlinks (struct ohci_hcd *, u16); +#ifdef CONFIG_PM +static int ohci_restart(struct ohci_hcd *ohci); + static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop) __releases(ohci->lock) __acquires(ohci->lock) @@ -132,8 +139,6 @@ static inline struct ed *find_head (struct ed *ed) return ed; } -static int ohci_restart (struct ohci_hcd *ohci); - /* caller has locked the root hub */ static int ohci_rh_resume (struct ohci_hcd *ohci) __releases(ohci->lock) @@ -169,7 +174,8 @@ __acquires(ohci->lock) break; case OHCI_USB_RESUME: /* HCFS changes sometime after INTR_RD */ - ohci_info (ohci, "wakeup\n"); + ohci_dbg(ohci, "%swakeup root hub\n", + autostopped ? "auto-" : ""); break; case OHCI_USB_OPER: /* this can happen after resuming a swsusp snapshot */ @@ -180,7 +186,6 @@ __acquires(ohci->lock) ohci_dbg (ohci, "lost power\n"); status = -EBUSY; } -#ifdef CONFIG_PM if (status == -EBUSY) { if (!autostopped) { spin_unlock_irq (&ohci->lock); @@ -190,25 +195,12 @@ __acquires(ohci->lock) } return status; } -#endif if (status != -EINPROGRESS) return status; if (autostopped) goto skip_resume; spin_unlock_irq (&ohci->lock); - temp = ohci->num_ports; - while (temp--) { - u32 stat = ohci_readl (ohci, - &ohci->regs->roothub.portstatus [temp]); - - /* force global, not selective, resume */ - if (!(stat & RH_PS_PSS)) - continue; - ohci_writel (ohci, RH_PS_POCI, - &ohci->regs->roothub.portstatus [temp]); - } - /* Some controllers (lucent erratum) need extra-long delays */ msleep (20 /* usb 11.5.1.10 */ + 12 /* 32 msec counter */ + 1); @@ -216,6 +208,7 @@ __acquires(ohci->lock) temp &= OHCI_CTRL_HCFS; if (temp != OHCI_USB_RESUME) { ohci_err (ohci, "controller won't resume\n"); + spin_lock_irq(&ohci->lock); return -EBUSY; } @@ -295,8 +288,6 @@ skip_resume: return 0; } -#ifdef CONFIG_PM - static int ohci_bus_suspend (struct usb_hcd *hcd) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); @@ -334,6 +325,83 @@ static int ohci_bus_resume (struct usb_hcd *hcd) return rc; } +/* Carry out polling-, autostop-, and autoresume-related state changes */ +static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, + int any_connected) +{ + int poll_rh = 1; + + switch (ohci->hc_control & OHCI_CTRL_HCFS) { + + case OHCI_USB_OPER: + /* keep on polling until we know a device is connected + * and RHSC is enabled */ + if (!ohci->autostop) { + if (any_connected || + !device_may_wakeup(&ohci_to_hcd(ohci) + ->self.root_hub->dev)) { + if (ohci_readl(ohci, &ohci->regs->intrenable) & + OHCI_INTR_RHSC) + poll_rh = 0; + } else { + ohci->autostop = 1; + ohci->next_statechange = jiffies + HZ; + } + + /* if no devices have been attached for one second, autostop */ + } else { + if (changed || any_connected) { + ohci->autostop = 0; + ohci->next_statechange = jiffies + + STATECHANGE_DELAY; + } else if (time_after_eq(jiffies, + ohci->next_statechange) + && !ohci->ed_rm_list + && !(ohci->hc_control & + OHCI_SCHED_ENABLES)) { + ohci_rh_suspend(ohci, 1); + } + } + break; + + /* if there is a port change, autostart or ask to be resumed */ + case OHCI_USB_SUSPEND: + case OHCI_USB_RESUME: + if (changed) { + if (ohci->autostop) + ohci_rh_resume(ohci); + else + usb_hcd_resume_root_hub(ohci_to_hcd(ohci)); + } else { + /* everything is idle, no need for polling */ + poll_rh = 0; + } + break; + } + return poll_rh; +} + +#else /* CONFIG_PM */ + +static inline int ohci_rh_resume(struct ohci_hcd *ohci) +{ + return 0; +} + +/* Carry out polling-related state changes. + * autostop isn't used when CONFIG_PM is turned off. + */ +static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, + int any_connected) +{ + int poll_rh = 1; + + /* keep on polling until RHSC is enabled */ + if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC) + poll_rh = 0; + return poll_rh; +} + #endif /* CONFIG_PM */ /*-------------------------------------------------------------------------*/ @@ -345,7 +413,7 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int i, changed = 0, length = 1; - int any_connected = 0, rhsc_enabled = 1; + int any_connected = 0; unsigned long flags; spin_lock_irqsave (&ohci->lock, flags); @@ -386,66 +454,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) } } - /* NOTE: vendors didn't always make the same implementation - * choices for RHSC. Sometimes it triggers on an edge (like - * setting and maybe clearing a port status change bit); and - * it's level-triggered on other silicon, active until khubd - * clears all active port status change bits. If it's still - * set (level-triggered) we must disable it and rely on - * polling until khubd re-enables it. - */ - if (ohci_readl (ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC) { - ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable); - (void) ohci_readl (ohci, &ohci->regs->intrdisable); - rhsc_enabled = 0; - } - hcd->poll_rh = 1; - - /* carry out appropriate state changes */ - switch (ohci->hc_control & OHCI_CTRL_HCFS) { - - case OHCI_USB_OPER: - /* keep on polling until we know a device is connected - * and RHSC is enabled */ - if (!ohci->autostop) { - if (any_connected) { - if (rhsc_enabled) - hcd->poll_rh = 0; - } else { - ohci->autostop = 1; - ohci->next_statechange = jiffies + HZ; - } - - /* if no devices have been attached for one second, autostop */ - } else { - if (changed || any_connected) { - ohci->autostop = 0; - ohci->next_statechange = jiffies + - STATECHANGE_DELAY; - } else if (time_after_eq (jiffies, - ohci->next_statechange) - && !ohci->ed_rm_list - && !(ohci->hc_control & - OHCI_SCHED_ENABLES)) { - ohci_rh_suspend (ohci, 1); - } - } - break; - - /* if there is a port change, autostart or ask to be resumed */ - case OHCI_USB_SUSPEND: - case OHCI_USB_RESUME: - if (changed) { - if (ohci->autostop) - ohci_rh_resume (ohci); - else - usb_hcd_resume_root_hub (hcd); - } else { - /* everything is idle, no need for polling */ - hcd->poll_rh = 0; - } - break; - } + hcd->poll_rh = ohci_root_hub_state_changes(ohci, changed, + any_connected); done: spin_unlock_irqrestore (&ohci->lock, flags); diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c index 82cb22f002e7..7f26f9bdbaf1 100644 --- a/drivers/usb/host/ohci-pnx4008.c +++ b/drivers/usb/host/ohci-pnx4008.c @@ -134,7 +134,7 @@ static int isp1301_attach(struct i2c_adapter *adap, int addr, int kind) { struct i2c_client *c; - c = (struct i2c_client *)kzalloc(sizeof(*c), SLAB_KERNEL); + c = (struct i2c_client *)kzalloc(sizeof(*c), GFP_KERNEL); if (!c) return -ENOMEM; @@ -262,6 +262,7 @@ static const struct hc_driver ohci_pnx4008_hc_driver = { */ .start = ohci_pnx4008_start, .stop = ohci_stop, + .shutdown = ohci_shutdown, /* * managing i/o requests and associated device resources @@ -280,7 +281,11 @@ static const struct hc_driver ohci_pnx4008_hc_driver = { */ .hub_status_data = ohci_hub_status_data, .hub_control = ohci_hub_control, - + .hub_irq_enable = ohci_rhsc_enable, +#ifdef CONFIG_PM + .bus_suspend = ohci_bus_suspend, + .bus_resume = ohci_bus_resume, +#endif .start_port_reset = ohci_start_port_reset, }; @@ -410,8 +415,6 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev) goto out4; } - hcd->self.hcpriv = (void *)hcd; - pnx4008_start_hc(); platform_set_drvdata(pdev, hcd); ohci = hcd_to_ohci(hcd); diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c index 54f554e0f0ad..ac9f11d19817 100644 --- a/drivers/usb/host/sl811_cs.c +++ b/drivers/usb/host/sl811_cs.c @@ -169,21 +169,14 @@ static int sl811_cs_config(struct pcmcia_device *link) DBG(0, "sl811_cs_config(0x%p)\n", link); - tuple.DesiredTuple = CISTPL_CONFIG; - tuple.Attributes = 0; - tuple.TupleData = buf; - tuple.TupleDataMax = sizeof(buf); - tuple.TupleOffset = 0; - CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); - CS_CHECK(GetTupleData, pcmcia_get_tuple_data(link, &tuple)); - CS_CHECK(ParseTuple, pcmcia_parse_tuple(link, &tuple, &parse)); - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - /* Look up the current Vcc */ CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(link, &conf)); + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(link, &tuple)); while (1) { diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 32c635ecbf31..a9d7119e3176 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -71,7 +71,7 @@ static int distrust_firmware = 1; module_param(distrust_firmware, bool, 0); MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren" "t setup"); -DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait); +static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait); /* * u132_module_lock exists to protect access to global variables * @@ -163,7 +163,7 @@ struct u132_endp { u16 queue_next; struct urb *urb_list[ENDP_QUEUE_SIZE]; struct list_head urb_more; - struct work_struct scheduler; + struct delayed_work scheduler; }; struct u132_ring { unsigned in_use:1; @@ -171,7 +171,7 @@ struct u132_ring { u8 number; struct u132 *u132; struct u132_endp *curr_endp; - struct work_struct scheduler; + struct delayed_work scheduler; }; #define OHCI_QUIRK_AMD756 0x01 #define OHCI_QUIRK_SUPERIO 0x02 @@ -198,20 +198,16 @@ struct u132 { u32 hc_roothub_portstatus[MAX_ROOT_PORTS]; int flags; unsigned long next_statechange; - struct work_struct monitor; + struct delayed_work monitor; int num_endpoints; struct u132_addr addr[MAX_U132_ADDRS]; struct u132_udev udev[MAX_U132_UDEVS]; struct u132_port port[MAX_U132_PORTS]; struct u132_endp *endp[MAX_U132_ENDPS]; }; -int usb_ftdi_elan_read_reg(struct platform_device *pdev, u32 *data); -int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, u8 addressofs, - u8 width, u32 *data); -int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, u8 addressofs, - u8 width, u32 data); + /* -* these can not be inlines because we need the structure offset!! +* these cannot be inlines because we need the structure offset!! * Does anyone have a better way????? */ #define u132_read_pcimem(u132, member, data) \ @@ -314,7 +310,7 @@ static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring, if (delta > 0) { if (queue_delayed_work(workqueue, &ring->scheduler, delta)) return; - } else if (queue_work(workqueue, &ring->scheduler)) + } else if (queue_delayed_work(workqueue, &ring->scheduler, 0)) return; kref_put(&u132->kref, u132_hcd_delete); return; @@ -393,12 +389,8 @@ static inline void u132_endp_init_kref(struct u132 *u132, static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(workqueue, &endp->scheduler, delta)) - kref_get(&endp->kref); - } else if (queue_work(workqueue, &endp->scheduler)) - kref_get(&endp->kref); - return; + if (queue_delayed_work(workqueue, &endp->scheduler, delta)) + kref_get(&endp->kref); } static void u132_endp_cancel_work(struct u132 *u132, struct u132_endp *endp) @@ -414,24 +406,14 @@ static inline void u132_monitor_put_kref(struct u132 *u132) static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(workqueue, &u132->monitor, delta)) { - kref_get(&u132->kref); - } - } else if (queue_work(workqueue, &u132->monitor)) - kref_get(&u132->kref); - return; + if (queue_delayed_work(workqueue, &u132->monitor, delta)) + kref_get(&u132->kref); } static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(workqueue, &u132->monitor, delta)) - return; - } else if (queue_work(workqueue, &u132->monitor)) - return; - kref_put(&u132->kref, u132_hcd_delete); - return; + if (!queue_delayed_work(workqueue, &u132->monitor, delta)) + kref_put(&u132->kref, u132_hcd_delete); } static void u132_monitor_cancel_work(struct u132 *u132) @@ -493,9 +475,9 @@ static int read_roothub_info(struct u132 *u132) return 0; } -static void u132_hcd_monitor_work(void *data) +static void u132_hcd_monitor_work(struct work_struct *work) { - struct u132 *u132 = data; + struct u132 *u132 = container_of(work, struct u132, monitor.work); if (u132->going > 1) { dev_err(&u132->platform_dev->dev, "device has been removed %d\n" , u132->going); @@ -1319,15 +1301,14 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, } } -static void u132_hcd_ring_work_scheduler(void *data); -static void u132_hcd_endp_work_scheduler(void *data); /* * this work function is only executed from the work queue * */ -static void u132_hcd_ring_work_scheduler(void *data) +static void u132_hcd_ring_work_scheduler(struct work_struct *work) { - struct u132_ring *ring = data; + struct u132_ring *ring = + container_of(work, struct u132_ring, scheduler.work); struct u132 *u132 = ring->u132; down(&u132->scheduler_lock); if (ring->in_use) { @@ -1386,10 +1367,11 @@ static void u132_hcd_ring_work_scheduler(void *data) } } -static void u132_hcd_endp_work_scheduler(void *data) +static void u132_hcd_endp_work_scheduler(struct work_struct *work) { struct u132_ring *ring; - struct u132_endp *endp = data; + struct u132_endp *endp = + container_of(work, struct u132_endp, scheduler.work); struct u132 *u132 = endp->u132; down(&u132->scheduler_lock); ring = endp->ring; @@ -1947,7 +1929,7 @@ static int create_endpoint_and_queue_int(struct u132 *u132, if (!endp) { return -ENOMEM; } - INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp); + INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); ring = endp->ring = &u132->ring[0]; @@ -2036,7 +2018,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132, if (!endp) { return -ENOMEM; } - INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp); + INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); endp->dequeueing = 0; @@ -2121,7 +2103,7 @@ static int create_endpoint_and_queue_control(struct u132 *u132, if (!endp) { return -ENOMEM; } - INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp); + INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); spin_lock_init(&endp->queue_lock.slock); INIT_LIST_HEAD(&endp->urb_more); ring = endp->ring = &u132->ring[0]; @@ -3045,7 +3027,7 @@ static struct hc_driver u132_hc_driver = { * This function may be called by the USB core whilst the "usb_all_devices_rwsem" * is held for writing, thus this module must not call usb_remove_hcd() * synchronously - but instead should immediately stop activity to the -* device and ansynchronously call usb_remove_hcd() +* device and asynchronously call usb_remove_hcd() */ static int __devexit u132_remove(struct platform_device *pdev) { @@ -3100,10 +3082,10 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev) ring->number = rings + 1; ring->length = 0; ring->curr_endp = NULL; - INIT_WORK(&ring->scheduler, u132_hcd_ring_work_scheduler, - (void *)ring); + INIT_DELAYED_WORK(&ring->scheduler, + u132_hcd_ring_work_scheduler); } down(&u132->sw_lock); - INIT_WORK(&u132->monitor, u132_hcd_monitor_work, (void *)u132); + INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work); while (ports-- > 0) { struct u132_port *port = &u132->port[ports]; port->u132 = u132; @@ -3241,7 +3223,7 @@ static int u132_resume(struct platform_device *pdev) #define u132_resume NULL #endif /* -* this driver is loaded explicitely by ftdi_u132 +* this driver is loaded explicitly by ftdi_u132 * * the platform_driver struct is static because it is per type of module */ diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 45ee6920a850..e87692c31be4 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -40,6 +40,7 @@ #include <linux/dma-mapping.h> #include <linux/usb.h> #include <linux/bitops.h> +#include <linux/dmi.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -80,7 +81,7 @@ MODULE_PARM_DESC(debug, "Debug level"); static char *errbuf; #define ERRBUF_LEN (32 * 1024) -static kmem_cache_t *uhci_up_cachep; /* urb_priv */ +static struct kmem_cache *uhci_up_cachep; /* urb_priv */ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state); static void wakeup_rh(struct uhci_hcd *uhci); @@ -196,12 +197,42 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci) return 0; } +static int remote_wakeup_is_broken(struct uhci_hcd *uhci) +{ + static struct dmi_system_id broken_wakeup_table[] = { + { + .ident = "Asus A7V8X", + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK"), + DMI_MATCH(DMI_BOARD_NAME, "A7V8X"), + DMI_MATCH(DMI_BOARD_VERSION, "REV 1.xx"), + } + }, + { } + }; + int port; + + /* One of Asus's motherboards has a bug which causes it to + * wake up immediately from suspend-to-RAM if any of the ports + * are connected. In such cases we will not set EGSM. + */ + if (dmi_check_system(broken_wakeup_table)) { + for (port = 0; port < uhci->rh_numports; ++port) { + if (inw(uhci->io_addr + USBPORTSC1 + port * 2) & + USBPORTSC_CCS) + return 1; + } + } + + return 0; +} + static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state) __releases(uhci->lock) __acquires(uhci->lock) { int auto_stop; - int int_enable; + int int_enable, egsm_enable; auto_stop = (new_state == UHCI_RH_AUTO_STOPPED); dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev, @@ -217,15 +248,18 @@ __acquires(uhci->lock) } /* Enable resume-detect interrupts if they work. - * Then enter Global Suspend mode, still configured. + * Then enter Global Suspend mode if _it_ works, still configured. */ + egsm_enable = USBCMD_EGSM; uhci->working_RD = 1; int_enable = USBINTR_RESUME; - if (resume_detect_interrupts_are_broken(uhci)) { + if (remote_wakeup_is_broken(uhci)) + egsm_enable = 0; + if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable) uhci->working_RD = int_enable = 0; - } + outw(int_enable, uhci->io_addr + USBINTR); - outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD); + outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD); mb(); udelay(5); diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c index 06115f22a4fa..30b88459ac7d 100644 --- a/drivers/usb/host/uhci-q.c +++ b/drivers/usb/host/uhci-q.c @@ -498,7 +498,7 @@ static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, { struct urb_priv *urbp; - urbp = kmem_cache_alloc(uhci_up_cachep, SLAB_ATOMIC); + urbp = kmem_cache_alloc(uhci_up_cachep, GFP_ATOMIC); if (!urbp) return NULL; diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index 3038ed0700d3..8ccddf74534a 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -796,7 +796,7 @@ static int mts_usb_probe(struct usb_interface *intf, new_desc->context.scsi_status = kmalloc(1, GFP_KERNEL); if (!new_desc->context.scsi_status) - goto out_kfree2; + goto out_free_urb; new_desc->usb_dev = dev; new_desc->usb_intf = intf; @@ -822,18 +822,20 @@ static int mts_usb_probe(struct usb_interface *intf, new_desc->host = scsi_host_alloc(&mts_scsi_host_template, sizeof(new_desc)); if (!new_desc->host) - goto out_free_urb; + goto out_kfree2; new_desc->host->hostdata[0] = (unsigned long)new_desc; if (scsi_add_host(new_desc->host, NULL)) { err_retval = -EIO; - goto out_free_urb; + goto out_host_put; } scsi_scan_host(new_desc->host); usb_set_intfdata(intf, new_desc); return 0; + out_host_put: + scsi_host_put(new_desc->host); out_kfree2: kfree(new_desc->context.scsi_status); out_free_urb: diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index 21cd22640080..8a62d4785755 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -6,9 +6,10 @@ comment "USB Input Devices" config USB_HID tristate "USB Human Interface Device (full HID) support" - depends on USB + default y + depends on USB && HID ---help--- - Say Y here if you want full HID support to connect keyboards, + Say Y here if you want full HID support to connect USB keyboards, mice, joysticks, graphic tablets, or any other HID based devices to your computer via USB. You also need to select HID Input layer support (below) if you want to use keyboards, mice, joysticks and @@ -27,20 +28,10 @@ config USB_HID comment "Input core support is needed for USB HID input layer or HIDBP support" depends on USB_HID && INPUT=n -config USB_HIDINPUT - bool "HID input layer support" - default y - depends on INPUT && USB_HID - help - Say Y here if you want to use a USB keyboard, mouse or joystick, - or any other HID input device. - - If unsure, say Y. - -config USB_HIDINPUT_POWERBOOK +config USB_HID_POWERBOOK bool "Enable support for iBook/PowerBook special keys" default n - depends on USB_HIDINPUT + depends on USB_HID help Say Y here if you want support for the special keys (Fn, Numlock) on Apple iBooks and PowerBooks. @@ -49,7 +40,7 @@ config USB_HIDINPUT_POWERBOOK config HID_FF bool "Force feedback support (EXPERIMENTAL)" - depends on USB_HIDINPUT && EXPERIMENTAL + depends on USB_HID && EXPERIMENTAL help Say Y here is you want force feedback support for a few HID devices. See below for a list of supported devices. @@ -221,6 +212,7 @@ config USB_TOUCHSCREEN - ITM - some other eTurboTouch - Gunze AHL61 + - DMC TSC-10/25 Have a look at <http://linux.chapter7.ch/touchkit/> for a usage description and the required user-space stuff. @@ -258,6 +250,11 @@ config USB_TOUCHSCREEN_GUNZE bool "Gunze AHL61 device support" if EMBEDDED depends on USB_TOUCHSCREEN +config USB_TOUCHSCREEN_DMC_TSC10 + default y + bool "DMC TSC-10/25 device support" if EMBEDDED + depends on USB_TOUCHSCREEN + config USB_YEALINK tristate "Yealink usb-p1k voip phone" depends on USB && INPUT && EXPERIMENTAL @@ -348,13 +345,3 @@ config USB_APPLETOUCH To compile this driver as a module, choose M here: the module will be called appletouch. - -config USB_TRANCEVIBRATOR - tristate "PlayStation 2 Trance Vibrator driver support" - depends on USB - help - Say Y here if you want to connect a PlayStation 2 Trance Vibrator - device to your computer's USB port. - - To compile this driver as a module, choose M here: the - module will be called trancevibrator. diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 295f459d1079..1a24b5bfa05f 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -3,7 +3,7 @@ # # Multipart objects. -wacom-objs := wacom_sys.o wacom_wac.o +wacom-objs := wacom_wac.o wacom_sys.o usbhid-objs := hid-core.o # Optional parts of multipart objects. @@ -11,9 +11,6 @@ usbhid-objs := hid-core.o ifeq ($(CONFIG_USB_HIDDEV),y) usbhid-objs += hiddev.o endif -ifeq ($(CONFIG_USB_HIDINPUT),y) - usbhid-objs += hid-input.o -endif ifeq ($(CONFIG_HID_PID),y) usbhid-objs += hid-pidff.o endif @@ -48,7 +45,6 @@ obj-$(CONFIG_USB_ACECAD) += acecad.o obj-$(CONFIG_USB_YEALINK) += yealink.o obj-$(CONFIG_USB_XPAD) += xpad.o obj-$(CONFIG_USB_APPLETOUCH) += appletouch.o -obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o ifeq ($(CONFIG_USB_DEBUG),y) EXTRA_CFLAGS += -DDEBUG diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c index 0096373b5f98..909138e5aa04 100644 --- a/drivers/usb/input/acecad.c +++ b/drivers/usb/input/acecad.c @@ -152,7 +152,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_ if (!acecad || !input_dev) goto fail1; - acecad->data = usb_buffer_alloc(dev, 8, SLAB_KERNEL, &acecad->data_dma); + acecad->data = usb_buffer_alloc(dev, 8, GFP_KERNEL, &acecad->data_dma); if (!acecad->data) goto fail1; diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c index bf428184608f..9f52429ce654 100644 --- a/drivers/usb/input/aiptek.c +++ b/drivers/usb/input/aiptek.c @@ -1988,7 +1988,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id) goto fail1; aiptek->data = usb_buffer_alloc(usbdev, AIPTEK_PACKET_LENGTH, - SLAB_ATOMIC, &aiptek->data_dma); + GFP_ATOMIC, &aiptek->data_dma); if (!aiptek->data) goto fail1; diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c index 4c213513484d..c77291d3d063 100644 --- a/drivers/usb/input/appletouch.c +++ b/drivers/usb/input/appletouch.c @@ -38,14 +38,29 @@ #define APPLE_VENDOR_ID 0x05AC /* These names come from Info.plist in AppleUSBTrackpad.kext */ -#define GEYSER_ANSI_PRODUCT_ID 0x0214 -#define GEYSER_ISO_PRODUCT_ID 0x0215 -#define GEYSER_JIS_PRODUCT_ID 0x0216 +#define FOUNTAIN_ANSI_PRODUCT_ID 0x020E +#define FOUNTAIN_ISO_PRODUCT_ID 0x020F + +#define FOUNTAIN_TP_ONLY_PRODUCT_ID 0x030A + +#define GEYSER1_TP_ONLY_PRODUCT_ID 0x030B + +#define GEYSER_ANSI_PRODUCT_ID 0x0214 +#define GEYSER_ISO_PRODUCT_ID 0x0215 +#define GEYSER_JIS_PRODUCT_ID 0x0216 /* MacBook devices */ -#define GEYSER3_ANSI_PRODUCT_ID 0x0217 -#define GEYSER3_ISO_PRODUCT_ID 0x0218 -#define GEYSER3_JIS_PRODUCT_ID 0x0219 +#define GEYSER3_ANSI_PRODUCT_ID 0x0217 +#define GEYSER3_ISO_PRODUCT_ID 0x0218 +#define GEYSER3_JIS_PRODUCT_ID 0x0219 + +/* + * Geyser IV: same as Geyser III according to Info.plist in AppleUSBTrackpad.kext + * -> same IOClass (AppleUSBGrIIITrackpad), same acceleration tables + */ +#define GEYSER4_ANSI_PRODUCT_ID 0x021A +#define GEYSER4_ISO_PRODUCT_ID 0x021B +#define GEYSER4_JIS_PRODUCT_ID 0x021C #define ATP_DEVICE(prod) \ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \ @@ -58,20 +73,26 @@ /* table of devices that work with this driver */ static struct usb_device_id atp_table [] = { - { ATP_DEVICE(0x020E) }, - { ATP_DEVICE(0x020F) }, - { ATP_DEVICE(0x030A) }, - { ATP_DEVICE(0x030B) }, + { ATP_DEVICE(FOUNTAIN_ANSI_PRODUCT_ID) }, + { ATP_DEVICE(FOUNTAIN_ISO_PRODUCT_ID) }, + { ATP_DEVICE(FOUNTAIN_TP_ONLY_PRODUCT_ID) }, + { ATP_DEVICE(GEYSER1_TP_ONLY_PRODUCT_ID) }, /* PowerBooks Oct 2005 */ { ATP_DEVICE(GEYSER_ANSI_PRODUCT_ID) }, { ATP_DEVICE(GEYSER_ISO_PRODUCT_ID) }, { ATP_DEVICE(GEYSER_JIS_PRODUCT_ID) }, + /* Core Duo MacBook & MacBook Pro */ { ATP_DEVICE(GEYSER3_ANSI_PRODUCT_ID) }, { ATP_DEVICE(GEYSER3_ISO_PRODUCT_ID) }, { ATP_DEVICE(GEYSER3_JIS_PRODUCT_ID) }, + /* Core2 Duo MacBook & MacBook Pro */ + { ATP_DEVICE(GEYSER4_ANSI_PRODUCT_ID) }, + { ATP_DEVICE(GEYSER4_ISO_PRODUCT_ID) }, + { ATP_DEVICE(GEYSER4_JIS_PRODUCT_ID) }, + /* Terminating entry */ { } }; @@ -108,7 +129,7 @@ MODULE_DEVICE_TABLE (usb, atp_table); */ #define ATP_THRESHOLD 5 -/* MacBook Pro (Geyser 3) initialization constants */ +/* MacBook Pro (Geyser 3 & 4) initialization constants */ #define ATP_GEYSER3_MODE_READ_REQUEST_ID 1 #define ATP_GEYSER3_MODE_WRITE_REQUEST_ID 9 #define ATP_GEYSER3_MODE_REQUEST_VALUE 0x300 @@ -154,6 +175,13 @@ MODULE_AUTHOR("Johannes Berg, Stelian Pop, Frank Arnold, Michael Hanselmann"); MODULE_DESCRIPTION("Apple PowerBooks USB touchpad driver"); MODULE_LICENSE("GPL"); +/* + * Make the threshold a module parameter + */ +static int threshold = ATP_THRESHOLD; +module_param(threshold, int, 0644); +MODULE_PARM_DESC(threshold, "Discards any change in data from a sensor (trackpad has hundreds of these sensors) less than this value"); + static int debug = 1; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Activate debugging output"); @@ -174,7 +202,10 @@ static inline int atp_is_geyser_3(struct atp *dev) return (productId == GEYSER3_ANSI_PRODUCT_ID) || (productId == GEYSER3_ISO_PRODUCT_ID) || - (productId == GEYSER3_JIS_PRODUCT_ID); + (productId == GEYSER3_JIS_PRODUCT_ID) || + (productId == GEYSER4_ANSI_PRODUCT_ID) || + (productId == GEYSER4_ISO_PRODUCT_ID) || + (productId == GEYSER4_JIS_PRODUCT_ID); } static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, @@ -183,16 +214,48 @@ static int atp_calculate_abs(int *xy_sensors, int nb_sensors, int fact, int i; /* values to calculate mean */ int pcum = 0, psum = 0; + int is_increasing = 0; *fingers = 0; for (i = 0; i < nb_sensors; i++) { - if (xy_sensors[i] < ATP_THRESHOLD) + if (xy_sensors[i] < threshold) { + if (is_increasing) + is_increasing = 0; + continue; - if ((i - 1 < 0) || (xy_sensors[i - 1] < ATP_THRESHOLD)) + } + + /* + * Makes the finger detection more versatile. For example, + * two fingers with no gap will be detected. Also, my + * tests show it less likely to have intermittent loss + * of multiple finger readings while moving around (scrolling). + * + * Changes the multiple finger detection to counting humps on + * sensors (transitions from nonincreasing to increasing) + * instead of counting transitions from low sensors (no + * finger reading) to high sensors (finger above + * sensor) + * + * - Jason Parekh <jasonparekh@gmail.com> + */ + if (i < 1 || (!is_increasing && xy_sensors[i - 1] < xy_sensors[i])) { (*fingers)++; - pcum += xy_sensors[i] * i; - psum += xy_sensors[i]; + is_increasing = 1; + } else if (i > 0 && xy_sensors[i - 1] >= xy_sensors[i]) { + is_increasing = 0; + } + + /* + * Subtracts threshold so a high sensor that just passes the threshold + * won't skew the calculated absolute coordinate. Fixes an issue + * where slowly moving the mouse would occassionaly jump a number of + * pixels (let me restate--slowly moving the mouse makes this issue + * most apparent). + */ + pcum += (xy_sensors[i] - threshold) * i; + psum += (xy_sensors[i] - threshold); } if (psum > 0) { diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c index f659f3028ad2..b724e36f7b92 100644 --- a/drivers/usb/input/ati_remote.c +++ b/drivers/usb/input/ati_remote.c @@ -592,7 +592,7 @@ static void ati_remote_irq_in(struct urb *urb) __FUNCTION__, urb->status); } - retval = usb_submit_urb(urb, SLAB_ATOMIC); + retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n", __FUNCTION__, retval); @@ -604,12 +604,12 @@ static void ati_remote_irq_in(struct urb *urb) static int ati_remote_alloc_buffers(struct usb_device *udev, struct ati_remote *ati_remote) { - ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC, + ati_remote->inbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC, &ati_remote->inbuf_dma); if (!ati_remote->inbuf) return -1; - ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, SLAB_ATOMIC, + ati_remote->outbuf = usb_buffer_alloc(udev, DATA_BUFSIZE, GFP_ATOMIC, &ati_remote->outbuf_dma); if (!ati_remote->outbuf) return -1; @@ -630,19 +630,14 @@ static int ati_remote_alloc_buffers(struct usb_device *udev, */ static void ati_remote_free_buffers(struct ati_remote *ati_remote) { - if (ati_remote->irq_urb) - usb_free_urb(ati_remote->irq_urb); + usb_free_urb(ati_remote->irq_urb); + usb_free_urb(ati_remote->out_urb); - if (ati_remote->out_urb) - usb_free_urb(ati_remote->out_urb); + usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, + ati_remote->inbuf, ati_remote->inbuf_dma); - if (ati_remote->inbuf) - usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, - ati_remote->inbuf, ati_remote->inbuf_dma); - - if (ati_remote->outbuf) - usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, - ati_remote->inbuf, ati_remote->outbuf_dma); + usb_buffer_free(ati_remote->udev, DATA_BUFSIZE, + ati_remote->outbuf, ati_remote->outbuf_dma); } static void ati_remote_input_init(struct ati_remote *ati_remote) diff --git a/drivers/usb/input/ati_remote2.c b/drivers/usb/input/ati_remote2.c index f982a2b4a7f9..83f1f79db7c7 100644 --- a/drivers/usb/input/ati_remote2.c +++ b/drivers/usb/input/ati_remote2.c @@ -372,8 +372,7 @@ 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]); + usb_free_urb(ar2->urb[i]); if (ar2->buf[i]) usb_buffer_free(ar2->udev, 4, ar2->buf[i], ar2->buf_dma[i]); diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index a6738a83ff5b..89fa6885709b 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -4,6 +4,7 @@ * Copyright (c) 1999 Andreas Gal * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc + * Copyright (c) 2006 Jiri Kosina */ /* @@ -32,8 +33,9 @@ #include <linux/usb.h> -#include "hid.h" +#include <linux/hid.h> #include <linux/hiddev.h> +#include "usbhid.h" /* * Version Information @@ -54,851 +56,10 @@ static unsigned int hid_mousepoll_interval; module_param_named(mousepoll, hid_mousepoll_interval, uint, 0644); MODULE_PARM_DESC(mousepoll, "Polling interval of mice"); -/* - * Register a new report for a device. - */ - -static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id) -{ - struct hid_report_enum *report_enum = device->report_enum + type; - struct hid_report *report; - - if (report_enum->report_id_hash[id]) - return report_enum->report_id_hash[id]; - - if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL))) - return NULL; - - if (id != 0) - report_enum->numbered = 1; - - report->id = id; - report->type = type; - report->size = 0; - report->device = device; - report_enum->report_id_hash[id] = report; - - list_add_tail(&report->list, &report_enum->report_list); - - return report; -} - -/* - * Register a new field for this report. - */ - -static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values) -{ - struct hid_field *field; - - if (report->maxfield == HID_MAX_FIELDS) { - dbg("too many fields in report"); - return NULL; - } - - if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage) - + values * sizeof(unsigned), GFP_KERNEL))) return NULL; - - field->index = report->maxfield++; - report->field[field->index] = field; - field->usage = (struct hid_usage *)(field + 1); - field->value = (unsigned *)(field->usage + usages); - field->report = report; - - return field; -} - -/* - * Open a collection. The type/usage is pushed on the stack. - */ - -static int open_collection(struct hid_parser *parser, unsigned type) -{ - struct hid_collection *collection; - unsigned usage; - - usage = parser->local.usage[0]; - - if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) { - dbg("collection stack overflow"); - return -1; - } - - if (parser->device->maxcollection == parser->device->collection_size) { - collection = kmalloc(sizeof(struct hid_collection) * - parser->device->collection_size * 2, GFP_KERNEL); - if (collection == NULL) { - dbg("failed to reallocate collection array"); - return -1; - } - memcpy(collection, parser->device->collection, - sizeof(struct hid_collection) * - parser->device->collection_size); - memset(collection + parser->device->collection_size, 0, - sizeof(struct hid_collection) * - parser->device->collection_size); - kfree(parser->device->collection); - parser->device->collection = collection; - parser->device->collection_size *= 2; - } - - parser->collection_stack[parser->collection_stack_ptr++] = - parser->device->maxcollection; - - collection = parser->device->collection + - parser->device->maxcollection++; - collection->type = type; - collection->usage = usage; - collection->level = parser->collection_stack_ptr - 1; - - if (type == HID_COLLECTION_APPLICATION) - parser->device->maxapplication++; - - return 0; -} - -/* - * Close a collection. - */ - -static int close_collection(struct hid_parser *parser) -{ - if (!parser->collection_stack_ptr) { - dbg("collection stack underflow"); - return -1; - } - parser->collection_stack_ptr--; - return 0; -} - -/* - * Climb up the stack, search for the specified collection type - * and return the usage. - */ - -static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type) -{ - int n; - for (n = parser->collection_stack_ptr - 1; n >= 0; n--) - if (parser->device->collection[parser->collection_stack[n]].type == type) - return parser->device->collection[parser->collection_stack[n]].usage; - return 0; /* we know nothing about this usage type */ -} - -/* - * Add a usage to the temporary parser table. - */ - -static int hid_add_usage(struct hid_parser *parser, unsigned usage) -{ - if (parser->local.usage_index >= HID_MAX_USAGES) { - dbg("usage index exceeded"); - return -1; - } - parser->local.usage[parser->local.usage_index] = usage; - parser->local.collection_index[parser->local.usage_index] = - parser->collection_stack_ptr ? - parser->collection_stack[parser->collection_stack_ptr - 1] : 0; - parser->local.usage_index++; - return 0; -} - -/* - * Register a new field for this report. - */ - -static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags) -{ - struct hid_report *report; - struct hid_field *field; - int usages; - unsigned offset; - int i; - - if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) { - dbg("hid_register_report failed"); - return -1; - } - - if (parser->global.logical_maximum < parser->global.logical_minimum) { - dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum); - return -1; - } - - offset = report->size; - report->size += parser->global.report_size * parser->global.report_count; - - if (!parser->local.usage_index) /* Ignore padding fields */ - return 0; - - usages = max_t(int, parser->local.usage_index, parser->global.report_count); - - if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL) - return 0; - - field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL); - field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL); - field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); - - for (i = 0; i < usages; i++) { - int j = i; - /* Duplicate the last usage we parsed if we have excess values */ - if (i >= parser->local.usage_index) - j = parser->local.usage_index - 1; - field->usage[i].hid = parser->local.usage[j]; - field->usage[i].collection_index = - parser->local.collection_index[j]; - } - - field->maxusage = usages; - field->flags = flags; - field->report_offset = offset; - field->report_type = report_type; - field->report_size = parser->global.report_size; - field->report_count = parser->global.report_count; - field->logical_minimum = parser->global.logical_minimum; - field->logical_maximum = parser->global.logical_maximum; - field->physical_minimum = parser->global.physical_minimum; - field->physical_maximum = parser->global.physical_maximum; - field->unit_exponent = parser->global.unit_exponent; - field->unit = parser->global.unit; - - return 0; -} - -/* - * Read data value from item. - */ - -static __inline__ __u32 item_udata(struct hid_item *item) -{ - switch (item->size) { - case 1: return item->data.u8; - case 2: return item->data.u16; - case 4: return item->data.u32; - } - return 0; -} - -static __inline__ __s32 item_sdata(struct hid_item *item) -{ - switch (item->size) { - case 1: return item->data.s8; - case 2: return item->data.s16; - case 4: return item->data.s32; - } - return 0; -} - -/* - * Process a global item. - */ - -static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) -{ - switch (item->tag) { - - case HID_GLOBAL_ITEM_TAG_PUSH: - - if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) { - dbg("global enviroment stack overflow"); - return -1; - } - - memcpy(parser->global_stack + parser->global_stack_ptr++, - &parser->global, sizeof(struct hid_global)); - return 0; - - case HID_GLOBAL_ITEM_TAG_POP: - - if (!parser->global_stack_ptr) { - dbg("global enviroment stack underflow"); - return -1; - } - - memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr, - sizeof(struct hid_global)); - return 0; - - case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: - parser->global.usage_page = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM: - parser->global.logical_minimum = item_sdata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM: - if (parser->global.logical_minimum < 0) - parser->global.logical_maximum = item_sdata(item); - else - parser->global.logical_maximum = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM: - parser->global.physical_minimum = item_sdata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM: - if (parser->global.physical_minimum < 0) - parser->global.physical_maximum = item_sdata(item); - else - parser->global.physical_maximum = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: - parser->global.unit_exponent = item_sdata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_UNIT: - parser->global.unit = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: - if ((parser->global.report_size = item_udata(item)) > 32) { - dbg("invalid report_size %d", parser->global.report_size); - return -1; - } - return 0; - - case HID_GLOBAL_ITEM_TAG_REPORT_COUNT: - if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) { - dbg("invalid report_count %d", parser->global.report_count); - return -1; - } - return 0; - - case HID_GLOBAL_ITEM_TAG_REPORT_ID: - if ((parser->global.report_id = item_udata(item)) == 0) { - dbg("report_id 0 is invalid"); - return -1; - } - return 0; - - default: - dbg("unknown global tag 0x%x", item->tag); - return -1; - } -} - -/* - * Process a local item. - */ - -static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) -{ - __u32 data; - unsigned n; - - if (item->size == 0) { - dbg("item data expected for local item"); - return -1; - } - - data = item_udata(item); - - switch (item->tag) { - - case HID_LOCAL_ITEM_TAG_DELIMITER: - - if (data) { - /* - * We treat items before the first delimiter - * as global to all usage sets (branch 0). - * In the moment we process only these global - * items and the first delimiter set. - */ - if (parser->local.delimiter_depth != 0) { - dbg("nested delimiters"); - return -1; - } - parser->local.delimiter_depth++; - parser->local.delimiter_branch++; - } else { - if (parser->local.delimiter_depth < 1) { - dbg("bogus close delimiter"); - return -1; - } - parser->local.delimiter_depth--; - } - return 1; - - case HID_LOCAL_ITEM_TAG_USAGE: - - if (parser->local.delimiter_branch > 1) { - dbg("alternative usage ignored"); - return 0; - } - - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - - return hid_add_usage(parser, data); - - case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: - - if (parser->local.delimiter_branch > 1) { - dbg("alternative usage ignored"); - return 0; - } - - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - - parser->local.usage_minimum = data; - return 0; - - case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: - - if (parser->local.delimiter_branch > 1) { - dbg("alternative usage ignored"); - return 0; - } - - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - - for (n = parser->local.usage_minimum; n <= data; n++) - if (hid_add_usage(parser, n)) { - dbg("hid_add_usage failed\n"); - return -1; - } - return 0; - - default: - - dbg("unknown local item tag 0x%x", item->tag); - return 0; - } - return 0; -} - -/* - * Process a main item. - */ - -static int hid_parser_main(struct hid_parser *parser, struct hid_item *item) -{ - __u32 data; - int ret; - - data = item_udata(item); - - switch (item->tag) { - case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: - ret = open_collection(parser, data & 0xff); - break; - case HID_MAIN_ITEM_TAG_END_COLLECTION: - ret = close_collection(parser); - break; - case HID_MAIN_ITEM_TAG_INPUT: - ret = hid_add_field(parser, HID_INPUT_REPORT, data); - break; - case HID_MAIN_ITEM_TAG_OUTPUT: - ret = hid_add_field(parser, HID_OUTPUT_REPORT, data); - break; - case HID_MAIN_ITEM_TAG_FEATURE: - ret = hid_add_field(parser, HID_FEATURE_REPORT, data); - break; - default: - dbg("unknown main item tag 0x%x", item->tag); - ret = 0; - } - - memset(&parser->local, 0, sizeof(parser->local)); /* Reset the local parser environment */ - - return ret; -} - -/* - * Process a reserved item. - */ - -static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item) -{ - dbg("reserved item type, tag 0x%x", item->tag); - return 0; -} - -/* - * Free a report and all registered fields. The field->usage and - * field->value table's are allocated behind the field, so we need - * only to free(field) itself. - */ - -static void hid_free_report(struct hid_report *report) -{ - unsigned n; - - for (n = 0; n < report->maxfield; n++) - kfree(report->field[n]); - kfree(report); -} - -/* - * Free a device structure, all reports, and all fields. - */ - -static void hid_free_device(struct hid_device *device) -{ - unsigned i,j; - - for (i = 0; i < HID_REPORT_TYPES; i++) { - struct hid_report_enum *report_enum = device->report_enum + i; - - for (j = 0; j < 256; j++) { - struct hid_report *report = report_enum->report_id_hash[j]; - if (report) - hid_free_report(report); - } - } - - kfree(device->rdesc); - kfree(device); -} - -/* - * Fetch a report description item from the data stream. We support long - * items, though they are not used yet. - */ - -static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) -{ - u8 b; - - if ((end - start) <= 0) - return NULL; - - b = *start++; - - item->type = (b >> 2) & 3; - item->tag = (b >> 4) & 15; - - if (item->tag == HID_ITEM_TAG_LONG) { - - item->format = HID_ITEM_FORMAT_LONG; - - if ((end - start) < 2) - return NULL; - - item->size = *start++; - item->tag = *start++; - - if ((end - start) < item->size) - return NULL; - - item->data.longdata = start; - start += item->size; - return start; - } - - item->format = HID_ITEM_FORMAT_SHORT; - item->size = b & 3; - - switch (item->size) { - - case 0: - return start; - - case 1: - if ((end - start) < 1) - return NULL; - item->data.u8 = *start++; - return start; - - case 2: - if ((end - start) < 2) - return NULL; - item->data.u16 = le16_to_cpu(get_unaligned((__le16*)start)); - start = (__u8 *)((__le16 *)start + 1); - return start; - - case 3: - item->size++; - if ((end - start) < 4) - return NULL; - item->data.u32 = le32_to_cpu(get_unaligned((__le32*)start)); - start = (__u8 *)((__le32 *)start + 1); - return start; - } - - return NULL; -} - -/* - * Parse a report description into a hid_device structure. Reports are - * enumerated, fields are attached to these reports. - */ - -static struct hid_device *hid_parse_report(__u8 *start, unsigned size) -{ - struct hid_device *device; - struct hid_parser *parser; - struct hid_item item; - __u8 *end; - unsigned i; - static int (*dispatch_type[])(struct hid_parser *parser, - struct hid_item *item) = { - hid_parser_main, - hid_parser_global, - hid_parser_local, - hid_parser_reserved - }; - - if (!(device = kzalloc(sizeof(struct hid_device), GFP_KERNEL))) - return NULL; - - if (!(device->collection = kzalloc(sizeof(struct hid_collection) * - HID_DEFAULT_NUM_COLLECTIONS, GFP_KERNEL))) { - kfree(device); - return NULL; - } - device->collection_size = HID_DEFAULT_NUM_COLLECTIONS; - - for (i = 0; i < HID_REPORT_TYPES; i++) - INIT_LIST_HEAD(&device->report_enum[i].report_list); - - if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) { - kfree(device->collection); - kfree(device); - return NULL; - } - memcpy(device->rdesc, start, size); - device->rsize = size; - - if (!(parser = kzalloc(sizeof(struct hid_parser), GFP_KERNEL))) { - kfree(device->rdesc); - kfree(device->collection); - kfree(device); - return NULL; - } - parser->device = device; - - end = start + size; - while ((start = fetch_item(start, end, &item)) != NULL) { - - if (item.format != HID_ITEM_FORMAT_SHORT) { - dbg("unexpected long global item"); - kfree(device->collection); - hid_free_device(device); - kfree(parser); - return NULL; - } - - if (dispatch_type[item.type](parser, &item)) { - dbg("item %u %u %u %u parsing failed\n", - item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag); - kfree(device->collection); - hid_free_device(device); - kfree(parser); - return NULL; - } - - if (start == end) { - if (parser->collection_stack_ptr) { - dbg("unbalanced collection at end of report description"); - kfree(device->collection); - hid_free_device(device); - kfree(parser); - return NULL; - } - if (parser->local.delimiter_depth) { - dbg("unbalanced delimiter at end of report description"); - kfree(device->collection); - hid_free_device(device); - kfree(parser); - return NULL; - } - kfree(parser); - return device; - } - } - - dbg("item fetching failed at offset %d\n", (int)(end - start)); - kfree(device->collection); - hid_free_device(device); - kfree(parser); - return NULL; -} - -/* - * Convert a signed n-bit integer to signed 32-bit integer. Common - * cases are done through the compiler, the screwed things has to be - * done by hand. - */ - -static __inline__ __s32 snto32(__u32 value, unsigned n) -{ - switch (n) { - case 8: return ((__s8)value); - case 16: return ((__s16)value); - case 32: return ((__s32)value); - } - return value & (1 << (n - 1)) ? value | (-1 << n) : value; -} - -/* - * Convert a signed 32-bit integer to a signed n-bit integer. - */ - -static __inline__ __u32 s32ton(__s32 value, unsigned n) -{ - __s32 a = value >> (n - 1); - if (a && a != -1) - return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; - return value & ((1 << n) - 1); -} - -/* - * Extract/implement a data field from/to a report. - */ - -static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n) -{ - report += (offset >> 5) << 2; offset &= 31; - return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1ULL << n) - 1); -} - -static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value) -{ - report += (offset >> 5) << 2; offset &= 31; - put_unaligned((get_unaligned((__le64*)report) - & cpu_to_le64(~((((__u64) 1 << n) - 1) << offset))) - | cpu_to_le64((__u64)value << offset), (__le64*)report); -} - -/* - * Search an array for a value. - */ - -static __inline__ int search(__s32 *array, __s32 value, unsigned n) -{ - while (n--) { - if (*array++ == value) - return 0; - } - return -1; -} - -static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt) -{ - hid_dump_input(usage, value); - if (hid->claimed & HID_CLAIMED_INPUT) - hidinput_hid_event(hid, field, usage, value); - if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt) - hiddev_hid_event(hid, field, usage, value); -} - -/* - * Analyse a received field, and fetch the data from it. The field - * content is stored for next report processing (we do differential - * reporting to the layer). - */ - -static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt) -{ - unsigned n; - unsigned count = field->report_count; - unsigned offset = field->report_offset; - unsigned size = field->report_size; - __s32 min = field->logical_minimum; - __s32 max = field->logical_maximum; - __s32 *value; - - if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC))) - return; - - for (n = 0; n < count; n++) { - - value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : - extract(data, offset + n * size, size); - - if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */ - && value[n] >= min && value[n] <= max - && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) - goto exit; - } - - for (n = 0; n < count; n++) { - - if (HID_MAIN_ITEM_VARIABLE & field->flags) { - hid_process_event(hid, field, &field->usage[n], value[n], interrupt); - continue; - } - - if (field->value[n] >= min && field->value[n] <= max - && field->usage[field->value[n] - min].hid - && search(value, field->value[n], count)) - hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt); - - if (value[n] >= min && value[n] <= max - && field->usage[value[n] - min].hid - && search(field->value, value[n], count)) - hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt); - } - - memcpy(field->value, value, count * sizeof(__s32)); -exit: - kfree(value); -} - -static int hid_input_report(int type, struct urb *urb, int interrupt) -{ - struct hid_device *hid = urb->context; - struct hid_report_enum *report_enum = hid->report_enum + type; - u8 *data = urb->transfer_buffer; - int len = urb->actual_length; - struct hid_report *report; - int n, size; - - if (!len) { - dbg("empty report"); - return -1; - } - -#ifdef DEBUG_DATA - printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un"); -#endif - - n = 0; /* Normally report number is 0 */ - if (report_enum->numbered) { /* Device uses numbered reports, data[0] is report number */ - n = *data++; - len--; - } - -#ifdef DEBUG_DATA - { - int i; - printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len); - for (i = 0; i < len; i++) - printk(" %02x", data[i]); - printk("\n"); - } -#endif - - if (!(report = report_enum->report_id_hash[n])) { - dbg("undefined report_id %d received", n); - return -1; - } - - size = ((report->size - 1) >> 3) + 1; - - if (len < size) { - dbg("report %d is too short, (%d < %d)", report->id, len, size); - memset(data + len, 0, size - len); - } - - if (hid->claimed & HID_CLAIMED_HIDDEV) - hiddev_report_event(hid, report); - - for (n = 0; n < report->maxfield; n++) - hid_input_field(hid, report->field[n], data, interrupt); - - if (hid->claimed & HID_CLAIMED_INPUT) - hidinput_report_event(hid, report); - - return 0; -} +static int usbhid_pb_fnmode = 1; +module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644); +MODULE_PARM_DESC(pb_fnmode, + "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); /* * Input submission and I/O error handler. @@ -911,15 +72,16 @@ static int hid_start_in(struct hid_device *hid) { unsigned long flags; int rc = 0; + struct usbhid_device *usbhid = hid->driver_data; - spin_lock_irqsave(&hid->inlock, flags); - if (hid->open > 0 && !test_bit(HID_SUSPENDED, &hid->iofl) && - !test_and_set_bit(HID_IN_RUNNING, &hid->iofl)) { - rc = usb_submit_urb(hid->urbin, GFP_ATOMIC); + spin_lock_irqsave(&usbhid->inlock, flags); + if (hid->open > 0 && !test_bit(HID_SUSPENDED, &usbhid->iofl) && + !test_and_set_bit(HID_IN_RUNNING, &usbhid->iofl)) { + rc = usb_submit_urb(usbhid->urbin, GFP_ATOMIC); if (rc != 0) - clear_bit(HID_IN_RUNNING, &hid->iofl); + clear_bit(HID_IN_RUNNING, &usbhid->iofl); } - spin_unlock_irqrestore(&hid->inlock, flags); + spin_unlock_irqrestore(&usbhid->inlock, flags); return rc; } @@ -927,37 +89,49 @@ static int hid_start_in(struct hid_device *hid) static void hid_retry_timeout(unsigned long _hid) { struct hid_device *hid = (struct hid_device *) _hid; + struct usbhid_device *usbhid = hid->driver_data; - dev_dbg(&hid->intf->dev, "retrying intr urb\n"); + dev_dbg(&usbhid->intf->dev, "retrying intr urb\n"); if (hid_start_in(hid)) hid_io_error(hid); } -/* Workqueue routine to reset the device */ -static void hid_reset(void *_hid) +/* Workqueue routine to reset the device or clear a halt */ +static void hid_reset(struct work_struct *work) { - struct hid_device *hid = (struct hid_device *) _hid; - int rc_lock, rc; - - dev_dbg(&hid->intf->dev, "resetting device\n"); - rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf); - if (rc_lock >= 0) { - rc = usb_reset_composite_device(hid->dev, hid->intf); - if (rc_lock) - usb_unlock_device(hid->dev); + struct usbhid_device *usbhid = + container_of(work, struct usbhid_device, reset_work); + struct hid_device *hid = usbhid->hid; + int rc_lock, rc = 0; + + if (test_bit(HID_CLEAR_HALT, &usbhid->iofl)) { + dev_dbg(&usbhid->intf->dev, "clear halt\n"); + rc = usb_clear_halt(to_usb_device(hid->dev), usbhid->urbin->pipe); + clear_bit(HID_CLEAR_HALT, &usbhid->iofl); + hid_start_in(hid); + } + + else if (test_bit(HID_RESET_PENDING, &usbhid->iofl)) { + dev_dbg(&usbhid->intf->dev, "resetting device\n"); + rc = rc_lock = usb_lock_device_for_reset(to_usb_device(hid->dev), usbhid->intf); + if (rc_lock >= 0) { + rc = usb_reset_composite_device(to_usb_device(hid->dev), usbhid->intf); + if (rc_lock) + usb_unlock_device(to_usb_device(hid->dev)); + } + clear_bit(HID_RESET_PENDING, &usbhid->iofl); } - clear_bit(HID_RESET_PENDING, &hid->iofl); switch (rc) { case 0: - if (!test_bit(HID_IN_RUNNING, &hid->iofl)) + if (!test_bit(HID_IN_RUNNING, &usbhid->iofl)) hid_io_error(hid); break; default: err("can't reset device, %s-%s/input%d, status %d", - hid->dev->bus->bus_name, - hid->dev->devpath, - hid->ifnum, rc); + to_usb_device(hid->dev)->bus->bus_name, + to_usb_device(hid->dev)->devpath, + usbhid->ifnum, rc); /* FALLTHROUGH */ case -EHOSTUNREACH: case -ENODEV: @@ -970,34 +144,34 @@ static void hid_reset(void *_hid) static void hid_io_error(struct hid_device *hid) { unsigned long flags; + struct usbhid_device *usbhid = hid->driver_data; - spin_lock_irqsave(&hid->inlock, flags); + spin_lock_irqsave(&usbhid->inlock, flags); /* Stop when disconnected */ - if (usb_get_intfdata(hid->intf) == NULL) + if (usb_get_intfdata(usbhid->intf) == NULL) goto done; /* When an error occurs, retry at increasing intervals */ - if (hid->retry_delay == 0) { - hid->retry_delay = 13; /* Then 26, 52, 104, 104, ... */ - hid->stop_retry = jiffies + msecs_to_jiffies(1000); - } else if (hid->retry_delay < 100) - hid->retry_delay *= 2; + if (usbhid->retry_delay == 0) { + usbhid->retry_delay = 13; /* Then 26, 52, 104, 104, ... */ + usbhid->stop_retry = jiffies + msecs_to_jiffies(1000); + } else if (usbhid->retry_delay < 100) + usbhid->retry_delay *= 2; - if (time_after(jiffies, hid->stop_retry)) { + if (time_after(jiffies, usbhid->stop_retry)) { /* Retries failed, so do a port reset */ - if (!test_and_set_bit(HID_RESET_PENDING, &hid->iofl)) { - if (schedule_work(&hid->reset_work)) - goto done; - clear_bit(HID_RESET_PENDING, &hid->iofl); + if (!test_and_set_bit(HID_RESET_PENDING, &usbhid->iofl)) { + schedule_work(&usbhid->reset_work); + goto done; } } - mod_timer(&hid->io_retry, - jiffies + msecs_to_jiffies(hid->retry_delay)); + mod_timer(&usbhid->io_retry, + jiffies + msecs_to_jiffies(usbhid->retry_delay)); done: - spin_unlock_irqrestore(&hid->inlock, flags); + spin_unlock_irqrestore(&usbhid->inlock, flags); } /* @@ -1007,104 +181,51 @@ done: static void hid_irq_in(struct urb *urb) { struct hid_device *hid = urb->context; + struct usbhid_device *usbhid = hid->driver_data; int status; switch (urb->status) { case 0: /* success */ - hid->retry_delay = 0; - hid_input_report(HID_INPUT_REPORT, urb, 1); + usbhid->retry_delay = 0; + hid_input_report(urb->context, HID_INPUT_REPORT, + urb->transfer_buffer, + urb->actual_length, 1); break; + case -EPIPE: /* stall */ + clear_bit(HID_IN_RUNNING, &usbhid->iofl); + set_bit(HID_CLEAR_HALT, &usbhid->iofl); + schedule_work(&usbhid->reset_work); + return; case -ECONNRESET: /* unlink */ case -ENOENT: case -ESHUTDOWN: /* unplug */ - clear_bit(HID_IN_RUNNING, &hid->iofl); + clear_bit(HID_IN_RUNNING, &usbhid->iofl); return; case -EILSEQ: /* protocol error or unplug */ case -EPROTO: /* protocol error or unplug */ case -ETIME: /* protocol error or unplug */ case -ETIMEDOUT: /* Should never happen, but... */ - clear_bit(HID_IN_RUNNING, &hid->iofl); + clear_bit(HID_IN_RUNNING, &usbhid->iofl); hid_io_error(hid); return; default: /* error */ warn("input irq status %d received", urb->status); } - status = usb_submit_urb(urb, SLAB_ATOMIC); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { - clear_bit(HID_IN_RUNNING, &hid->iofl); + clear_bit(HID_IN_RUNNING, &usbhid->iofl); if (status != -EPERM) { err("can't resubmit intr, %s-%s/input%d, status %d", - hid->dev->bus->bus_name, - hid->dev->devpath, - hid->ifnum, status); + to_usb_device(hid->dev)->bus->bus_name, + to_usb_device(hid->dev)->devpath, + usbhid->ifnum, status); hid_io_error(hid); } } } /* - * Output the field into the report. - */ - -static void hid_output_field(struct hid_field *field, __u8 *data) -{ - unsigned count = field->report_count; - unsigned offset = field->report_offset; - unsigned size = field->report_size; - unsigned n; - - for (n = 0; n < count; n++) { - if (field->logical_minimum < 0) /* signed values */ - implement(data, offset + n * size, size, s32ton(field->value[n], size)); - else /* unsigned values */ - implement(data, offset + n * size, size, field->value[n]); - } -} - -/* - * Create a report. - */ - -static void hid_output_report(struct hid_report *report, __u8 *data) -{ - unsigned n; - - if (report->id > 0) - *data++ = report->id; - - for (n = 0; n < report->maxfield; n++) - hid_output_field(report->field[n], data); -} - -/* - * Set a field value. The report this field belongs to has to be - * created and transferred to the device, to set this value in the - * device. - */ - -int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) -{ - unsigned size = field->report_size; - - hid_dump_input(field->usage + offset, value); - - if (offset >= field->report_count) { - dbg("offset (%d) exceeds report_count (%d)", offset, field->report_count); - hid_dump_field(field, 8); - return -1; - } - if (field->logical_minimum < 0) { - if (value != snto32(s32ton(value, size), size)) { - dbg("value %d is out of range", value); - return -1; - } - } - field->value[offset] = value; - return 0; -} - -/* * Find a report field with a specified HID usage. */ #if 0 @@ -1124,16 +245,17 @@ struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_u static int hid_submit_out(struct hid_device *hid) { struct hid_report *report; + struct usbhid_device *usbhid = hid->driver_data; - report = hid->out[hid->outtail]; + report = usbhid->out[usbhid->outtail]; - hid_output_report(report, hid->outbuf); - hid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); - hid->urbout->dev = hid->dev; + hid_output_report(report, usbhid->outbuf); + usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); + usbhid->urbout->dev = to_usb_device(hid->dev); dbg("submitting out urb"); - if (usb_submit_urb(hid->urbout, GFP_ATOMIC)) { + if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) { err("usb_submit_urb(out) failed"); return -1; } @@ -1146,42 +268,43 @@ static int hid_submit_ctrl(struct hid_device *hid) struct hid_report *report; unsigned char dir; int len; + struct usbhid_device *usbhid = hid->driver_data; - report = hid->ctrl[hid->ctrltail].report; - dir = hid->ctrl[hid->ctrltail].dir; + report = usbhid->ctrl[usbhid->ctrltail].report; + dir = usbhid->ctrl[usbhid->ctrltail].dir; len = ((report->size - 1) >> 3) + 1 + (report->id > 0); if (dir == USB_DIR_OUT) { - hid_output_report(report, hid->ctrlbuf); - hid->urbctrl->pipe = usb_sndctrlpipe(hid->dev, 0); - hid->urbctrl->transfer_buffer_length = len; + hid_output_report(report, usbhid->ctrlbuf); + usbhid->urbctrl->pipe = usb_sndctrlpipe(to_usb_device(hid->dev), 0); + usbhid->urbctrl->transfer_buffer_length = len; } else { int maxpacket, padlen; - hid->urbctrl->pipe = usb_rcvctrlpipe(hid->dev, 0); - maxpacket = usb_maxpacket(hid->dev, hid->urbctrl->pipe, 0); + usbhid->urbctrl->pipe = usb_rcvctrlpipe(to_usb_device(hid->dev), 0); + maxpacket = usb_maxpacket(to_usb_device(hid->dev), usbhid->urbctrl->pipe, 0); if (maxpacket > 0) { padlen = (len + maxpacket - 1) / maxpacket; padlen *= maxpacket; - if (padlen > hid->bufsize) - padlen = hid->bufsize; + if (padlen > usbhid->bufsize) + padlen = usbhid->bufsize; } else padlen = 0; - hid->urbctrl->transfer_buffer_length = padlen; + usbhid->urbctrl->transfer_buffer_length = padlen; } - hid->urbctrl->dev = hid->dev; + usbhid->urbctrl->dev = to_usb_device(hid->dev); - hid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; - hid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; - hid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id); - hid->cr->wIndex = cpu_to_le16(hid->ifnum); - hid->cr->wLength = cpu_to_le16(len); + usbhid->cr->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; + usbhid->cr->bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; + usbhid->cr->wValue = cpu_to_le16(((report->type + 1) << 8) | report->id); + usbhid->cr->wIndex = cpu_to_le16(usbhid->ifnum); + usbhid->cr->wLength = cpu_to_le16(len); dbg("submitting ctrl urb: %s wValue=0x%04x wIndex=0x%04x wLength=%u", - hid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report", - hid->cr->wValue, hid->cr->wIndex, hid->cr->wLength); + usbhid->cr->bRequest == HID_REQ_SET_REPORT ? "Set_Report" : "Get_Report", + usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength); - if (usb_submit_urb(hid->urbctrl, GFP_ATOMIC)) { + if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) { err("usb_submit_urb(ctrl) failed"); return -1; } @@ -1196,6 +319,7 @@ static int hid_submit_ctrl(struct hid_device *hid) static void hid_irq_out(struct urb *urb) { struct hid_device *hid = urb->context; + struct usbhid_device *usbhid = hid->driver_data; unsigned long flags; int unplug = 0; @@ -1213,24 +337,24 @@ static void hid_irq_out(struct urb *urb) warn("output irq status %d received", urb->status); } - spin_lock_irqsave(&hid->outlock, flags); + spin_lock_irqsave(&usbhid->outlock, flags); if (unplug) - hid->outtail = hid->outhead; + usbhid->outtail = usbhid->outhead; else - hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); + usbhid->outtail = (usbhid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); - if (hid->outhead != hid->outtail) { + if (usbhid->outhead != usbhid->outtail) { if (hid_submit_out(hid)) { - clear_bit(HID_OUT_RUNNING, &hid->iofl); + clear_bit(HID_OUT_RUNNING, &usbhid->iofl); wake_up(&hid->wait); } - spin_unlock_irqrestore(&hid->outlock, flags); + spin_unlock_irqrestore(&usbhid->outlock, flags); return; } - clear_bit(HID_OUT_RUNNING, &hid->iofl); - spin_unlock_irqrestore(&hid->outlock, flags); + clear_bit(HID_OUT_RUNNING, &usbhid->iofl); + spin_unlock_irqrestore(&usbhid->outlock, flags); wake_up(&hid->wait); } @@ -1241,15 +365,17 @@ static void hid_irq_out(struct urb *urb) static void hid_ctrl(struct urb *urb) { struct hid_device *hid = urb->context; + struct usbhid_device *usbhid = hid->driver_data; unsigned long flags; int unplug = 0; - spin_lock_irqsave(&hid->ctrllock, flags); + spin_lock_irqsave(&usbhid->ctrllock, flags); switch (urb->status) { case 0: /* success */ - if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) - hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0); + if (usbhid->ctrl[usbhid->ctrltail].dir == USB_DIR_IN) + hid_input_report(urb->context, usbhid->ctrl[usbhid->ctrltail].report->type, + urb->transfer_buffer, urb->actual_length, 0); break; case -ESHUTDOWN: /* unplug */ unplug = 1; @@ -1264,76 +390,102 @@ static void hid_ctrl(struct urb *urb) } if (unplug) - hid->ctrltail = hid->ctrlhead; + usbhid->ctrltail = usbhid->ctrlhead; else - hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); + usbhid->ctrltail = (usbhid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); - if (hid->ctrlhead != hid->ctrltail) { + if (usbhid->ctrlhead != usbhid->ctrltail) { if (hid_submit_ctrl(hid)) { - clear_bit(HID_CTRL_RUNNING, &hid->iofl); + clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); wake_up(&hid->wait); } - spin_unlock_irqrestore(&hid->ctrllock, flags); + spin_unlock_irqrestore(&usbhid->ctrllock, flags); return; } - clear_bit(HID_CTRL_RUNNING, &hid->iofl); - spin_unlock_irqrestore(&hid->ctrllock, flags); + clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); + spin_unlock_irqrestore(&usbhid->ctrllock, flags); wake_up(&hid->wait); } -void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) +void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) { int head; unsigned long flags; + struct usbhid_device *usbhid = hid->driver_data; if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN) return; - if (hid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) { + if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) { - spin_lock_irqsave(&hid->outlock, flags); + spin_lock_irqsave(&usbhid->outlock, flags); - if ((head = (hid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == hid->outtail) { - spin_unlock_irqrestore(&hid->outlock, flags); + if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) { + spin_unlock_irqrestore(&usbhid->outlock, flags); warn("output queue full"); return; } - hid->out[hid->outhead] = report; - hid->outhead = head; + usbhid->out[usbhid->outhead] = report; + usbhid->outhead = head; - if (!test_and_set_bit(HID_OUT_RUNNING, &hid->iofl)) + if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) if (hid_submit_out(hid)) - clear_bit(HID_OUT_RUNNING, &hid->iofl); + clear_bit(HID_OUT_RUNNING, &usbhid->iofl); - spin_unlock_irqrestore(&hid->outlock, flags); + spin_unlock_irqrestore(&usbhid->outlock, flags); return; } - spin_lock_irqsave(&hid->ctrllock, flags); + spin_lock_irqsave(&usbhid->ctrllock, flags); - if ((head = (hid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == hid->ctrltail) { - spin_unlock_irqrestore(&hid->ctrllock, flags); + if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) { + spin_unlock_irqrestore(&usbhid->ctrllock, flags); warn("control queue full"); return; } - hid->ctrl[hid->ctrlhead].report = report; - hid->ctrl[hid->ctrlhead].dir = dir; - hid->ctrlhead = head; + usbhid->ctrl[usbhid->ctrlhead].report = report; + usbhid->ctrl[usbhid->ctrlhead].dir = dir; + usbhid->ctrlhead = head; - if (!test_and_set_bit(HID_CTRL_RUNNING, &hid->iofl)) + if (!test_and_set_bit(HID_CTRL_RUNNING, &usbhid->iofl)) if (hid_submit_ctrl(hid)) - clear_bit(HID_CTRL_RUNNING, &hid->iofl); + clear_bit(HID_CTRL_RUNNING, &usbhid->iofl); + + spin_unlock_irqrestore(&usbhid->ctrllock, flags); +} + +static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct hid_device *hid = dev->private; + struct hid_field *field; + int offset; + + if (type == EV_FF) + return input_ff_event(dev, type, code, value); + + if (type != EV_LED) + return -1; + + if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) { + warn("event field not found"); + return -1; + } + + hid_set_field(field, offset, value); + usbhid_submit_report(hid, field->report, USB_DIR_OUT); - spin_unlock_irqrestore(&hid->ctrllock, flags); + return 0; } -int hid_wait_io(struct hid_device *hid) +int usbhid_wait_io(struct hid_device *hid) { - if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &hid->iofl) && - !test_bit(HID_OUT_RUNNING, &hid->iofl)), + struct usbhid_device *usbhid = hid->driver_data; + + if (!wait_event_timeout(hid->wait, (!test_bit(HID_CTRL_RUNNING, &usbhid->iofl) && + !test_bit(HID_OUT_RUNNING, &usbhid->iofl)), 10*HZ)) { dbg("timeout waiting for ctrl or out queue to clear"); return -1; @@ -1365,7 +517,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, return result; } -int hid_open(struct hid_device *hid) +int usbhid_open(struct hid_device *hid) { ++hid->open; if (hid_start_in(hid)) @@ -1373,38 +525,56 @@ int hid_open(struct hid_device *hid) return 0; } -void hid_close(struct hid_device *hid) +void usbhid_close(struct hid_device *hid) { + struct usbhid_device *usbhid = hid->driver_data; + if (!--hid->open) - usb_kill_urb(hid->urbin); + usb_kill_urb(usbhid->urbin); +} + +static int hidinput_open(struct input_dev *dev) +{ + struct hid_device *hid = dev->private; + return usbhid_open(hid); +} + +static void hidinput_close(struct input_dev *dev) +{ + struct hid_device *hid = dev->private; + usbhid_close(hid); } #define USB_VENDOR_ID_PANJIT 0x134c +#define USB_VENDOR_ID_TURBOX 0x062a +#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 + /* * Initialize all reports */ -void hid_init_reports(struct hid_device *hid) +void usbhid_init_reports(struct hid_device *hid) { struct hid_report *report; + struct usbhid_device *usbhid = hid->driver_data; int err, ret; list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].report_list, list) - hid_submit_report(hid, report, USB_DIR_IN); + usbhid_submit_report(hid, report, USB_DIR_IN); list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list) - hid_submit_report(hid, report, USB_DIR_IN); + usbhid_submit_report(hid, report, USB_DIR_IN); err = 0; - ret = hid_wait_io(hid); + ret = usbhid_wait_io(hid); while (ret) { err |= ret; - if (test_bit(HID_CTRL_RUNNING, &hid->iofl)) - usb_kill_urb(hid->urbctrl); - if (test_bit(HID_OUT_RUNNING, &hid->iofl)) - usb_kill_urb(hid->urbout); - ret = hid_wait_io(hid); + if (test_bit(HID_CTRL_RUNNING, &usbhid->iofl)) + usb_kill_urb(usbhid->urbctrl); + if (test_bit(HID_OUT_RUNNING, &usbhid->iofl)) + usb_kill_urb(usbhid->urbout); + ret = usbhid_wait_io(hid); } if (err) @@ -1589,6 +759,19 @@ void hid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_APPLE 0x05ac #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304 +#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e +#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f +#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214 +#define USB_DEVICE_ID_APPLE_GEYSER_ISO 0x0215 +#define USB_DEVICE_ID_APPLE_GEYSER_JIS 0x0216 +#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI 0x0217 +#define USB_DEVICE_ID_APPLE_GEYSER3_ISO 0x0218 +#define USB_DEVICE_ID_APPLE_GEYSER3_JIS 0x0219 +#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI 0x021a +#define USB_DEVICE_ID_APPLE_GEYSER4_ISO 0x021b +#define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c +#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a +#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b #define USB_VENDOR_ID_CHERRY 0x046a #define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023 @@ -1602,6 +785,12 @@ void hid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_SUN 0x0430 #define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab +#define USB_VENDOR_ID_AIRCABLE 0x16CA +#define USB_DEVICE_ID_AIRCABLE1 0x1502 + +#define USB_VENDOR_ID_LOGITECH 0x046d +#define USB_DEVICE_ID_LOGITECH_USB_RECEIVER 0xc101 + /* * Alphabetically sorted blacklist by quirk type. */ @@ -1619,6 +808,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE }, @@ -1752,22 +942,29 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION }, - { USB_VENDOR_ID_APPLE, 0x020E, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, 0x020F, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, 0x0214, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, 0x0215, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, 0x0216, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, 0x0217, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, 0x0218, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, 0x0219, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, 0x030A, HID_QUIRK_POWERBOOK_HAS_FN }, - { USB_VENDOR_ID_APPLE, 0x030B, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD}, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN }, + { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN }, { USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE }, + { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, + + { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS }, + { 0, 0 } }; @@ -1790,13 +987,15 @@ static void hid_find_max_report(struct hid_device *hid, unsigned int type, int * static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) { - if (!(hid->inbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->inbuf_dma))) + struct usbhid_device *usbhid = hid->driver_data; + + if (!(usbhid->inbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->inbuf_dma))) return -1; - if (!(hid->outbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->outbuf_dma))) + if (!(usbhid->outbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->outbuf_dma))) return -1; - if (!(hid->cr = usb_buffer_alloc(dev, sizeof(*(hid->cr)), SLAB_ATOMIC, &hid->cr_dma))) + if (!(usbhid->cr = usb_buffer_alloc(dev, sizeof(*(usbhid->cr)), GFP_ATOMIC, &usbhid->cr_dma))) return -1; - if (!(hid->ctrlbuf = usb_buffer_alloc(dev, hid->bufsize, SLAB_ATOMIC, &hid->ctrlbuf_dma))) + if (!(usbhid->ctrlbuf = usb_buffer_alloc(dev, usbhid->bufsize, GFP_ATOMIC, &usbhid->ctrlbuf_dma))) return -1; return 0; @@ -1804,14 +1003,16 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid) static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid) { - if (hid->inbuf) - usb_buffer_free(dev, hid->bufsize, hid->inbuf, hid->inbuf_dma); - if (hid->outbuf) - usb_buffer_free(dev, hid->bufsize, hid->outbuf, hid->outbuf_dma); - if (hid->cr) - usb_buffer_free(dev, sizeof(*(hid->cr)), hid->cr, hid->cr_dma); - if (hid->ctrlbuf) - usb_buffer_free(dev, hid->bufsize, hid->ctrlbuf, hid->ctrlbuf_dma); + struct usbhid_device *usbhid = hid->driver_data; + + if (usbhid->inbuf) + usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma); + if (usbhid->outbuf) + usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma); + if (usbhid->cr) + usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma); + if (usbhid->ctrlbuf) + usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma); } /* @@ -1837,6 +1038,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) unsigned quirks = 0, rsize = 0; char *rdesc; int n, len, insize = 0; + struct usbhid_device *usbhid; /* Ignore all Wacom devices */ if (le16_to_cpu(dev->descriptor.idVendor) == USB_VENDOR_ID_WACOM) @@ -1906,13 +1108,19 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) kfree(rdesc); hid->quirks = quirks; - hid->bufsize = HID_MIN_BUFFER_SIZE; - hid_find_max_report(hid, HID_INPUT_REPORT, &hid->bufsize); - hid_find_max_report(hid, HID_OUTPUT_REPORT, &hid->bufsize); - hid_find_max_report(hid, HID_FEATURE_REPORT, &hid->bufsize); + if (!(usbhid = kzalloc(sizeof(struct usbhid_device), GFP_KERNEL))) + goto fail; + + hid->driver_data = usbhid; + usbhid->hid = hid; + + usbhid->bufsize = HID_MIN_BUFFER_SIZE; + hid_find_max_report(hid, HID_INPUT_REPORT, &usbhid->bufsize); + hid_find_max_report(hid, HID_OUTPUT_REPORT, &usbhid->bufsize); + hid_find_max_report(hid, HID_FEATURE_REPORT, &usbhid->bufsize); - if (hid->bufsize > HID_MAX_BUFFER_SIZE) - hid->bufsize = HID_MAX_BUFFER_SIZE; + if (usbhid->bufsize > HID_MAX_BUFFER_SIZE) + usbhid->bufsize = HID_MAX_BUFFER_SIZE; hid_find_max_report(hid, HID_INPUT_REPORT, &insize); @@ -1940,48 +1148,48 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0) interval = hid_mousepoll_interval; - if (endpoint->bEndpointAddress & USB_DIR_IN) { - if (hid->urbin) + if (usb_endpoint_dir_in(endpoint)) { + if (usbhid->urbin) continue; - if (!(hid->urbin = usb_alloc_urb(0, GFP_KERNEL))) + if (!(usbhid->urbin = usb_alloc_urb(0, GFP_KERNEL))) goto fail; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); - usb_fill_int_urb(hid->urbin, dev, pipe, hid->inbuf, insize, + usb_fill_int_urb(usbhid->urbin, dev, pipe, usbhid->inbuf, insize, hid_irq_in, hid, interval); - hid->urbin->transfer_dma = hid->inbuf_dma; - hid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + usbhid->urbin->transfer_dma = usbhid->inbuf_dma; + usbhid->urbin->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; } else { - if (hid->urbout) + if (usbhid->urbout) continue; - if (!(hid->urbout = usb_alloc_urb(0, GFP_KERNEL))) + if (!(usbhid->urbout = usb_alloc_urb(0, GFP_KERNEL))) goto fail; pipe = usb_sndintpipe(dev, endpoint->bEndpointAddress); - usb_fill_int_urb(hid->urbout, dev, pipe, hid->outbuf, 0, + usb_fill_int_urb(usbhid->urbout, dev, pipe, usbhid->outbuf, 0, hid_irq_out, hid, interval); - hid->urbout->transfer_dma = hid->outbuf_dma; - hid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + usbhid->urbout->transfer_dma = usbhid->outbuf_dma; + usbhid->urbout->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; } } - if (!hid->urbin) { + if (!usbhid->urbin) { err("couldn't find an input interrupt endpoint"); goto fail; } init_waitqueue_head(&hid->wait); - INIT_WORK(&hid->reset_work, hid_reset, hid); - setup_timer(&hid->io_retry, hid_retry_timeout, (unsigned long) hid); + INIT_WORK(&usbhid->reset_work, hid_reset); + setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid); - spin_lock_init(&hid->inlock); - spin_lock_init(&hid->outlock); - spin_lock_init(&hid->ctrllock); + spin_lock_init(&usbhid->inlock); + spin_lock_init(&usbhid->outlock); + spin_lock_init(&usbhid->ctrllock); hid->version = le16_to_cpu(hdesc->bcdHID); hid->country = hdesc->bCountryCode; - hid->dev = dev; - hid->intf = intf; - hid->ifnum = interface->desc.bInterfaceNumber; + hid->dev = &dev->dev; + usbhid->intf = intf; + usbhid->ifnum = interface->desc.bInterfaceNumber; hid->name[0] = 0; @@ -1999,6 +1207,10 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct)); + hid->bus = BUS_USB; + hid->vendor = dev->descriptor.idVendor; + hid->product = dev->descriptor.idProduct; + usb_make_path(dev, hid->phys, sizeof(hid->phys)); strlcat(hid->phys, "/input", sizeof(hid->phys)); len = strlen(hid->phys); @@ -2009,26 +1221,32 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf) if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0) hid->uniq[0] = 0; - hid->urbctrl = usb_alloc_urb(0, GFP_KERNEL); - if (!hid->urbctrl) + usbhid->urbctrl = usb_alloc_urb(0, GFP_KERNEL); + if (!usbhid->urbctrl) goto fail; - usb_fill_control_urb(hid->urbctrl, dev, 0, (void *) hid->cr, - hid->ctrlbuf, 1, hid_ctrl, hid); - hid->urbctrl->setup_dma = hid->cr_dma; - hid->urbctrl->transfer_dma = hid->ctrlbuf_dma; - hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); + usb_fill_control_urb(usbhid->urbctrl, dev, 0, (void *) usbhid->cr, + usbhid->ctrlbuf, 1, hid_ctrl, hid); + usbhid->urbctrl->setup_dma = usbhid->cr_dma; + usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma; + usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP); + hid->hidinput_input_event = usb_hidinput_input_event; + hid->hidinput_open = hidinput_open; + hid->hidinput_close = hidinput_close; +#ifdef CONFIG_USB_HIDDEV + hid->hiddev_hid_event = hiddev_hid_event; + hid->hiddev_report_event = hiddev_report_event; +#endif +#ifdef CONFIG_USB_HIDINPUT_POWERBOOK + hid->pb_fnmode = usbhid_pb_fnmode; +#endif return hid; fail: - - if (hid->urbin) - usb_free_urb(hid->urbin); - if (hid->urbout) - usb_free_urb(hid->urbout); - if (hid->urbctrl) - usb_free_urb(hid->urbctrl); + usb_free_urb(usbhid->urbin); + usb_free_urb(usbhid->urbout); + usb_free_urb(usbhid->urbctrl); hid_free_buffers(dev, hid); hid_free_device(hid); @@ -2038,18 +1256,21 @@ fail: static void hid_disconnect(struct usb_interface *intf) { struct hid_device *hid = usb_get_intfdata (intf); + struct usbhid_device *usbhid; if (!hid) return; - spin_lock_irq(&hid->inlock); /* Sync with error handler */ + usbhid = hid->driver_data; + + spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ usb_set_intfdata(intf, NULL); - spin_unlock_irq(&hid->inlock); - usb_kill_urb(hid->urbin); - usb_kill_urb(hid->urbout); - usb_kill_urb(hid->urbctrl); + spin_unlock_irq(&usbhid->inlock); + usb_kill_urb(usbhid->urbin); + usb_kill_urb(usbhid->urbout); + usb_kill_urb(usbhid->urbctrl); - del_timer_sync(&hid->io_retry); + del_timer_sync(&usbhid->io_retry); flush_scheduled_work(); if (hid->claimed & HID_CLAIMED_INPUT) @@ -2057,12 +1278,11 @@ static void hid_disconnect(struct usb_interface *intf) if (hid->claimed & HID_CLAIMED_HIDDEV) hiddev_disconnect(hid); - usb_free_urb(hid->urbin); - usb_free_urb(hid->urbctrl); - if (hid->urbout) - usb_free_urb(hid->urbout); + usb_free_urb(usbhid->urbin); + usb_free_urb(usbhid->urbctrl); + usb_free_urb(usbhid->urbout); - hid_free_buffers(hid->dev, hid); + hid_free_buffers(to_usb_device(hid->dev), hid); hid_free_device(hid); } @@ -2079,7 +1299,7 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) if (!(hid = usb_hid_configure(intf))) return -ENODEV; - hid_init_reports(hid); + usbhid_init_reports(hid); hid_dump_device(hid); if (!hidinput_connect(hid)) @@ -2095,6 +1315,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) return -ENODEV; } + /* This only gets called when we are a single-input (most of the + * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is + * only useful in this case, and not for multi-input quirks. */ + if ((hid->claimed & HID_CLAIMED_INPUT) && + !(hid->quirks & HID_QUIRK_MULTI_INPUT)) + hid_ff_init(hid); + printk(KERN_INFO); if (hid->claimed & HID_CLAIMED_INPUT) @@ -2125,12 +1352,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id) static int hid_suspend(struct usb_interface *intf, pm_message_t message) { struct hid_device *hid = usb_get_intfdata (intf); + struct usbhid_device *usbhid = hid->driver_data; - spin_lock_irq(&hid->inlock); /* Sync with error handler */ - set_bit(HID_SUSPENDED, &hid->iofl); - spin_unlock_irq(&hid->inlock); - del_timer(&hid->io_retry); - usb_kill_urb(hid->urbin); + spin_lock_irq(&usbhid->inlock); /* Sync with error handler */ + set_bit(HID_SUSPENDED, &usbhid->iofl); + spin_unlock_irq(&usbhid->inlock); + del_timer(&usbhid->io_retry); + usb_kill_urb(usbhid->urbin); dev_dbg(&intf->dev, "suspend\n"); return 0; } @@ -2138,10 +1366,11 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) static int hid_resume(struct usb_interface *intf) { struct hid_device *hid = usb_get_intfdata (intf); + struct usbhid_device *usbhid = hid->driver_data; int status; - clear_bit(HID_SUSPENDED, &hid->iofl); - hid->retry_delay = 0; + clear_bit(HID_SUSPENDED, &usbhid->iofl); + usbhid->retry_delay = 0; status = hid_start_in(hid); dev_dbg(&intf->dev, "resume status %d\n", status); return status; diff --git a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h deleted file mode 100644 index f04d6d75c098..000000000000 --- a/drivers/usb/input/hid-debug.h +++ /dev/null @@ -1,757 +0,0 @@ -/* - * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $ - * - * (c) 1999 Andreas Gal <gal@cs.uni-magdeburg.de> - * (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz> - * - * Some debug stuff for the HID parser. - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include <linux/input.h> - -struct hid_usage_entry { - unsigned page; - unsigned usage; - char *description; -}; - -static const struct hid_usage_entry hid_usage_table[] = { - { 0, 0, "Undefined" }, - { 1, 0, "GenericDesktop" }, - {0, 0x01, "Pointer"}, - {0, 0x02, "Mouse"}, - {0, 0x04, "Joystick"}, - {0, 0x05, "GamePad"}, - {0, 0x06, "Keyboard"}, - {0, 0x07, "Keypad"}, - {0, 0x08, "MultiAxis"}, - {0, 0x30, "X"}, - {0, 0x31, "Y"}, - {0, 0x32, "Z"}, - {0, 0x33, "Rx"}, - {0, 0x34, "Ry"}, - {0, 0x35, "Rz"}, - {0, 0x36, "Slider"}, - {0, 0x37, "Dial"}, - {0, 0x38, "Wheel"}, - {0, 0x39, "HatSwitch"}, - {0, 0x3a, "CountedBuffer"}, - {0, 0x3b, "ByteCount"}, - {0, 0x3c, "MotionWakeup"}, - {0, 0x3d, "Start"}, - {0, 0x3e, "Select"}, - {0, 0x40, "Vx"}, - {0, 0x41, "Vy"}, - {0, 0x42, "Vz"}, - {0, 0x43, "Vbrx"}, - {0, 0x44, "Vbry"}, - {0, 0x45, "Vbrz"}, - {0, 0x46, "Vno"}, - {0, 0x80, "SystemControl"}, - {0, 0x81, "SystemPowerDown"}, - {0, 0x82, "SystemSleep"}, - {0, 0x83, "SystemWakeUp"}, - {0, 0x84, "SystemContextMenu"}, - {0, 0x85, "SystemMainMenu"}, - {0, 0x86, "SystemAppMenu"}, - {0, 0x87, "SystemMenuHelp"}, - {0, 0x88, "SystemMenuExit"}, - {0, 0x89, "SystemMenuSelect"}, - {0, 0x8a, "SystemMenuRight"}, - {0, 0x8b, "SystemMenuLeft"}, - {0, 0x8c, "SystemMenuUp"}, - {0, 0x8d, "SystemMenuDown"}, - {0, 0x90, "D-PadUp"}, - {0, 0x91, "D-PadDown"}, - {0, 0x92, "D-PadRight"}, - {0, 0x93, "D-PadLeft"}, - { 2, 0, "Simulation" }, - {0, 0xb0, "Aileron"}, - {0, 0xb1, "AileronTrim"}, - {0, 0xb2, "Anti-Torque"}, - {0, 0xb3, "Autopilot"}, - {0, 0xb4, "Chaff"}, - {0, 0xb5, "Collective"}, - {0, 0xb6, "DiveBrake"}, - {0, 0xb7, "ElectronicCountermeasures"}, - {0, 0xb8, "Elevator"}, - {0, 0xb9, "ElevatorTrim"}, - {0, 0xba, "Rudder"}, - {0, 0xbb, "Throttle"}, - {0, 0xbc, "FlightCommunications"}, - {0, 0xbd, "FlareRelease"}, - {0, 0xbe, "LandingGear"}, - {0, 0xbf, "ToeBrake"}, - { 7, 0, "Keyboard" }, - { 8, 0, "LED" }, - {0, 0x01, "NumLock"}, - {0, 0x02, "CapsLock"}, - {0, 0x03, "ScrollLock"}, - {0, 0x04, "Compose"}, - {0, 0x05, "Kana"}, - {0, 0x4b, "GenericIndicator"}, - { 9, 0, "Button" }, - { 10, 0, "Ordinal" }, - { 12, 0, "Consumer" }, - {0, 0x238, "HorizontalWheel"}, - { 13, 0, "Digitizers" }, - {0, 0x01, "Digitizer"}, - {0, 0x02, "Pen"}, - {0, 0x03, "LightPen"}, - {0, 0x04, "TouchScreen"}, - {0, 0x05, "TouchPad"}, - {0, 0x20, "Stylus"}, - {0, 0x21, "Puck"}, - {0, 0x22, "Finger"}, - {0, 0x30, "TipPressure"}, - {0, 0x31, "BarrelPressure"}, - {0, 0x32, "InRange"}, - {0, 0x33, "Touch"}, - {0, 0x34, "UnTouch"}, - {0, 0x35, "Tap"}, - {0, 0x39, "TabletFunctionKey"}, - {0, 0x3a, "ProgramChangeKey"}, - {0, 0x3c, "Invert"}, - {0, 0x42, "TipSwitch"}, - {0, 0x43, "SecondaryTipSwitch"}, - {0, 0x44, "BarrelSwitch"}, - {0, 0x45, "Eraser"}, - {0, 0x46, "TabletPick"}, - { 15, 0, "PhysicalInterfaceDevice" }, - {0, 0x00, "Undefined"}, - {0, 0x01, "Physical_Interface_Device"}, - {0, 0x20, "Normal"}, - {0, 0x21, "Set_Effect_Report"}, - {0, 0x22, "Effect_Block_Index"}, - {0, 0x23, "Parameter_Block_Offset"}, - {0, 0x24, "ROM_Flag"}, - {0, 0x25, "Effect_Type"}, - {0, 0x26, "ET_Constant_Force"}, - {0, 0x27, "ET_Ramp"}, - {0, 0x28, "ET_Custom_Force_Data"}, - {0, 0x30, "ET_Square"}, - {0, 0x31, "ET_Sine"}, - {0, 0x32, "ET_Triangle"}, - {0, 0x33, "ET_Sawtooth_Up"}, - {0, 0x34, "ET_Sawtooth_Down"}, - {0, 0x40, "ET_Spring"}, - {0, 0x41, "ET_Damper"}, - {0, 0x42, "ET_Inertia"}, - {0, 0x43, "ET_Friction"}, - {0, 0x50, "Duration"}, - {0, 0x51, "Sample_Period"}, - {0, 0x52, "Gain"}, - {0, 0x53, "Trigger_Button"}, - {0, 0x54, "Trigger_Repeat_Interval"}, - {0, 0x55, "Axes_Enable"}, - {0, 0x56, "Direction_Enable"}, - {0, 0x57, "Direction"}, - {0, 0x58, "Type_Specific_Block_Offset"}, - {0, 0x59, "Block_Type"}, - {0, 0x5A, "Set_Envelope_Report"}, - {0, 0x5B, "Attack_Level"}, - {0, 0x5C, "Attack_Time"}, - {0, 0x5D, "Fade_Level"}, - {0, 0x5E, "Fade_Time"}, - {0, 0x5F, "Set_Condition_Report"}, - {0, 0x60, "CP_Offset"}, - {0, 0x61, "Positive_Coefficient"}, - {0, 0x62, "Negative_Coefficient"}, - {0, 0x63, "Positive_Saturation"}, - {0, 0x64, "Negative_Saturation"}, - {0, 0x65, "Dead_Band"}, - {0, 0x66, "Download_Force_Sample"}, - {0, 0x67, "Isoch_Custom_Force_Enable"}, - {0, 0x68, "Custom_Force_Data_Report"}, - {0, 0x69, "Custom_Force_Data"}, - {0, 0x6A, "Custom_Force_Vendor_Defined_Data"}, - {0, 0x6B, "Set_Custom_Force_Report"}, - {0, 0x6C, "Custom_Force_Data_Offset"}, - {0, 0x6D, "Sample_Count"}, - {0, 0x6E, "Set_Periodic_Report"}, - {0, 0x6F, "Offset"}, - {0, 0x70, "Magnitude"}, - {0, 0x71, "Phase"}, - {0, 0x72, "Period"}, - {0, 0x73, "Set_Constant_Force_Report"}, - {0, 0x74, "Set_Ramp_Force_Report"}, - {0, 0x75, "Ramp_Start"}, - {0, 0x76, "Ramp_End"}, - {0, 0x77, "Effect_Operation_Report"}, - {0, 0x78, "Effect_Operation"}, - {0, 0x79, "Op_Effect_Start"}, - {0, 0x7A, "Op_Effect_Start_Solo"}, - {0, 0x7B, "Op_Effect_Stop"}, - {0, 0x7C, "Loop_Count"}, - {0, 0x7D, "Device_Gain_Report"}, - {0, 0x7E, "Device_Gain"}, - {0, 0x7F, "PID_Pool_Report"}, - {0, 0x80, "RAM_Pool_Size"}, - {0, 0x81, "ROM_Pool_Size"}, - {0, 0x82, "ROM_Effect_Block_Count"}, - {0, 0x83, "Simultaneous_Effects_Max"}, - {0, 0x84, "Pool_Alignment"}, - {0, 0x85, "PID_Pool_Move_Report"}, - {0, 0x86, "Move_Source"}, - {0, 0x87, "Move_Destination"}, - {0, 0x88, "Move_Length"}, - {0, 0x89, "PID_Block_Load_Report"}, - {0, 0x8B, "Block_Load_Status"}, - {0, 0x8C, "Block_Load_Success"}, - {0, 0x8D, "Block_Load_Full"}, - {0, 0x8E, "Block_Load_Error"}, - {0, 0x8F, "Block_Handle"}, - {0, 0x90, "PID_Block_Free_Report"}, - {0, 0x91, "Type_Specific_Block_Handle"}, - {0, 0x92, "PID_State_Report"}, - {0, 0x94, "Effect_Playing"}, - {0, 0x95, "PID_Device_Control_Report"}, - {0, 0x96, "PID_Device_Control"}, - {0, 0x97, "DC_Enable_Actuators"}, - {0, 0x98, "DC_Disable_Actuators"}, - {0, 0x99, "DC_Stop_All_Effects"}, - {0, 0x9A, "DC_Device_Reset"}, - {0, 0x9B, "DC_Device_Pause"}, - {0, 0x9C, "DC_Device_Continue"}, - {0, 0x9F, "Device_Paused"}, - {0, 0xA0, "Actuators_Enabled"}, - {0, 0xA4, "Safety_Switch"}, - {0, 0xA5, "Actuator_Override_Switch"}, - {0, 0xA6, "Actuator_Power"}, - {0, 0xA7, "Start_Delay"}, - {0, 0xA8, "Parameter_Block_Size"}, - {0, 0xA9, "Device_Managed_Pool"}, - {0, 0xAA, "Shared_Parameter_Blocks"}, - {0, 0xAB, "Create_New_Effect_Report"}, - {0, 0xAC, "RAM_Pool_Available"}, - { 0x84, 0, "Power Device" }, - { 0x84, 0x02, "PresentStatus" }, - { 0x84, 0x03, "ChangeStatus" }, - { 0x84, 0x04, "UPS" }, - { 0x84, 0x05, "PowerSupply" }, - { 0x84, 0x10, "BatterySystem" }, - { 0x84, 0x11, "BatterySystemID" }, - { 0x84, 0x12, "Battery" }, - { 0x84, 0x13, "BatteryID" }, - { 0x84, 0x14, "Charger" }, - { 0x84, 0x15, "ChargerID" }, - { 0x84, 0x16, "PowerConverter" }, - { 0x84, 0x17, "PowerConverterID" }, - { 0x84, 0x18, "OutletSystem" }, - { 0x84, 0x19, "OutletSystemID" }, - { 0x84, 0x1a, "Input" }, - { 0x84, 0x1b, "InputID" }, - { 0x84, 0x1c, "Output" }, - { 0x84, 0x1d, "OutputID" }, - { 0x84, 0x1e, "Flow" }, - { 0x84, 0x1f, "FlowID" }, - { 0x84, 0x20, "Outlet" }, - { 0x84, 0x21, "OutletID" }, - { 0x84, 0x22, "Gang" }, - { 0x84, 0x24, "PowerSummary" }, - { 0x84, 0x25, "PowerSummaryID" }, - { 0x84, 0x30, "Voltage" }, - { 0x84, 0x31, "Current" }, - { 0x84, 0x32, "Frequency" }, - { 0x84, 0x33, "ApparentPower" }, - { 0x84, 0x35, "PercentLoad" }, - { 0x84, 0x40, "ConfigVoltage" }, - { 0x84, 0x41, "ConfigCurrent" }, - { 0x84, 0x43, "ConfigApparentPower" }, - { 0x84, 0x53, "LowVoltageTransfer" }, - { 0x84, 0x54, "HighVoltageTransfer" }, - { 0x84, 0x56, "DelayBeforeStartup" }, - { 0x84, 0x57, "DelayBeforeShutdown" }, - { 0x84, 0x58, "Test" }, - { 0x84, 0x5a, "AudibleAlarmControl" }, - { 0x84, 0x60, "Present" }, - { 0x84, 0x61, "Good" }, - { 0x84, 0x62, "InternalFailure" }, - { 0x84, 0x65, "Overload" }, - { 0x84, 0x66, "OverCharged" }, - { 0x84, 0x67, "OverTemperature" }, - { 0x84, 0x68, "ShutdownRequested" }, - { 0x84, 0x69, "ShutdownImminent" }, - { 0x84, 0x6b, "SwitchOn/Off" }, - { 0x84, 0x6c, "Switchable" }, - { 0x84, 0x6d, "Used" }, - { 0x84, 0x6e, "Boost" }, - { 0x84, 0x73, "CommunicationLost" }, - { 0x84, 0xfd, "iManufacturer" }, - { 0x84, 0xfe, "iProduct" }, - { 0x84, 0xff, "iSerialNumber" }, - { 0x85, 0, "Battery System" }, - { 0x85, 0x01, "SMBBatteryMode" }, - { 0x85, 0x02, "SMBBatteryStatus" }, - { 0x85, 0x03, "SMBAlarmWarning" }, - { 0x85, 0x04, "SMBChargerMode" }, - { 0x85, 0x05, "SMBChargerStatus" }, - { 0x85, 0x06, "SMBChargerSpecInfo" }, - { 0x85, 0x07, "SMBSelectorState" }, - { 0x85, 0x08, "SMBSelectorPresets" }, - { 0x85, 0x09, "SMBSelectorInfo" }, - { 0x85, 0x29, "RemainingCapacityLimit" }, - { 0x85, 0x2c, "CapacityMode" }, - { 0x85, 0x42, "BelowRemainingCapacityLimit" }, - { 0x85, 0x44, "Charging" }, - { 0x85, 0x45, "Discharging" }, - { 0x85, 0x4b, "NeedReplacement" }, - { 0x85, 0x66, "RemainingCapacity" }, - { 0x85, 0x68, "RunTimeToEmpty" }, - { 0x85, 0x6a, "AverageTimeToFull" }, - { 0x85, 0x83, "DesignCapacity" }, - { 0x85, 0x85, "ManufacturerDate" }, - { 0x85, 0x89, "iDeviceChemistry" }, - { 0x85, 0x8b, "Rechargable" }, - { 0x85, 0x8f, "iOEMInformation" }, - { 0x85, 0x8d, "CapacityGranularity1" }, - { 0x85, 0xd0, "ACPresent" }, - /* pages 0xff00 to 0xffff are vendor-specific */ - { 0xffff, 0, "Vendor-specific-FF" }, - { 0, 0, NULL } -}; - -static void resolv_usage_page(unsigned page) { - const struct hid_usage_entry *p; - - for (p = hid_usage_table; p->description; p++) - if (p->page == page) { - printk("%s", p->description); - return; - } - printk("%04x", page); -} - -static void resolv_usage(unsigned usage) { - const struct hid_usage_entry *p; - - resolv_usage_page(usage >> 16); - printk("."); - for (p = hid_usage_table; p->description; p++) - if (p->page == (usage >> 16)) { - for(++p; p->description && p->usage != 0; p++) - if (p->usage == (usage & 0xffff)) { - printk("%s", p->description); - return; - } - break; - } - printk("%04x", usage & 0xffff); -} - -__inline__ static void tab(int n) { - while (n--) printk(" "); -} - -static void hid_dump_field(struct hid_field *field, int n) { - int j; - - if (field->physical) { - tab(n); - printk("Physical("); - resolv_usage(field->physical); printk(")\n"); - } - if (field->logical) { - tab(n); - printk("Logical("); - resolv_usage(field->logical); printk(")\n"); - } - tab(n); printk("Usage(%d)\n", field->maxusage); - for (j = 0; j < field->maxusage; j++) { - tab(n+2);resolv_usage(field->usage[j].hid); printk("\n"); - } - if (field->logical_minimum != field->logical_maximum) { - tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum); - tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum); - } - if (field->physical_minimum != field->physical_maximum) { - tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum); - tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum); - } - if (field->unit_exponent) { - tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent); - } - if (field->unit) { - char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" }; - char *units[5][8] = { - { "None", "None", "None", "None", "None", "None", "None", "None" }, - { "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, - { "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, - { "None", "Inch", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }, - { "None", "Degrees", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" } - }; - - int i; - int sys; - __u32 data = field->unit; - - /* First nibble tells us which system we're in. */ - sys = data & 0xf; - data >>= 4; - - if(sys > 4) { - tab(n); printk("Unit(Invalid)\n"); - } - else { - int earlier_unit = 0; - - tab(n); printk("Unit(%s : ", systems[sys]); - - for (i=1 ; i<sizeof(__u32)*2 ; i++) { - char nibble = data & 0xf; - data >>= 4; - if (nibble != 0) { - if(earlier_unit++ > 0) - printk("*"); - printk("%s", units[sys][i]); - if(nibble != 1) { - /* This is a _signed_ nibble(!) */ - - int val = nibble & 0x7; - if(nibble & 0x08) - val = -((0x7 & ~val) +1); - printk("^%d", val); - } - } - } - printk(")\n"); - } - } - tab(n); printk("Report Size(%u)\n", field->report_size); - tab(n); printk("Report Count(%u)\n", field->report_count); - tab(n); printk("Report Offset(%u)\n", field->report_offset); - - tab(n); printk("Flags( "); - j = field->flags; - printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : ""); - printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array "); - printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute "); - printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : ""); - printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : ""); - printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : ""); - printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : ""); - printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : ""); - printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : ""); - printk(")\n"); -} - -static void __attribute__((unused)) hid_dump_device(struct hid_device *device) { - struct hid_report_enum *report_enum; - struct hid_report *report; - struct list_head *list; - unsigned i,k; - static char *table[] = {"INPUT", "OUTPUT", "FEATURE"}; - - for (i = 0; i < HID_REPORT_TYPES; i++) { - report_enum = device->report_enum + i; - list = report_enum->report_list.next; - while (list != &report_enum->report_list) { - report = (struct hid_report *) list; - tab(2); - printk("%s", table[i]); - if (report->id) - printk("(%d)", report->id); - printk("[%s]", table[report->type]); - printk("\n"); - for (k = 0; k < report->maxfield; k++) { - tab(4); - printk("Field(%d)\n", k); - hid_dump_field(report->field[k], 6); - } - list = list->next; - } - } -} - -static void __attribute__((unused)) hid_dump_input(struct hid_usage *usage, __s32 value) { - printk("hid-debug: input "); - resolv_usage(usage->hid); - printk(" = %d\n", value); -} - - -static char *events[EV_MAX + 1] = { - [EV_SYN] = "Sync", [EV_KEY] = "Key", - [EV_REL] = "Relative", [EV_ABS] = "Absolute", - [EV_MSC] = "Misc", [EV_LED] = "LED", - [EV_SND] = "Sound", [EV_REP] = "Repeat", - [EV_FF] = "ForceFeedback", [EV_PWR] = "Power", - [EV_FF_STATUS] = "ForceFeedbackStatus", -}; - -static char *syncs[2] = { - [SYN_REPORT] = "Report", [SYN_CONFIG] = "Config", -}; -static char *keys[KEY_MAX + 1] = { - [KEY_RESERVED] = "Reserved", [KEY_ESC] = "Esc", - [KEY_1] = "1", [KEY_2] = "2", - [KEY_3] = "3", [KEY_4] = "4", - [KEY_5] = "5", [KEY_6] = "6", - [KEY_7] = "7", [KEY_8] = "8", - [KEY_9] = "9", [KEY_0] = "0", - [KEY_MINUS] = "Minus", [KEY_EQUAL] = "Equal", - [KEY_BACKSPACE] = "Backspace", [KEY_TAB] = "Tab", - [KEY_Q] = "Q", [KEY_W] = "W", - [KEY_E] = "E", [KEY_R] = "R", - [KEY_T] = "T", [KEY_Y] = "Y", - [KEY_U] = "U", [KEY_I] = "I", - [KEY_O] = "O", [KEY_P] = "P", - [KEY_LEFTBRACE] = "LeftBrace", [KEY_RIGHTBRACE] = "RightBrace", - [KEY_ENTER] = "Enter", [KEY_LEFTCTRL] = "LeftControl", - [KEY_A] = "A", [KEY_S] = "S", - [KEY_D] = "D", [KEY_F] = "F", - [KEY_G] = "G", [KEY_H] = "H", - [KEY_J] = "J", [KEY_K] = "K", - [KEY_L] = "L", [KEY_SEMICOLON] = "Semicolon", - [KEY_APOSTROPHE] = "Apostrophe", [KEY_GRAVE] = "Grave", - [KEY_LEFTSHIFT] = "LeftShift", [KEY_BACKSLASH] = "BackSlash", - [KEY_Z] = "Z", [KEY_X] = "X", - [KEY_C] = "C", [KEY_V] = "V", - [KEY_B] = "B", [KEY_N] = "N", - [KEY_M] = "M", [KEY_COMMA] = "Comma", - [KEY_DOT] = "Dot", [KEY_SLASH] = "Slash", - [KEY_RIGHTSHIFT] = "RightShift", [KEY_KPASTERISK] = "KPAsterisk", - [KEY_LEFTALT] = "LeftAlt", [KEY_SPACE] = "Space", - [KEY_CAPSLOCK] = "CapsLock", [KEY_F1] = "F1", - [KEY_F2] = "F2", [KEY_F3] = "F3", - [KEY_F4] = "F4", [KEY_F5] = "F5", - [KEY_F6] = "F6", [KEY_F7] = "F7", - [KEY_F8] = "F8", [KEY_F9] = "F9", - [KEY_F10] = "F10", [KEY_NUMLOCK] = "NumLock", - [KEY_SCROLLLOCK] = "ScrollLock", [KEY_KP7] = "KP7", - [KEY_KP8] = "KP8", [KEY_KP9] = "KP9", - [KEY_KPMINUS] = "KPMinus", [KEY_KP4] = "KP4", - [KEY_KP5] = "KP5", [KEY_KP6] = "KP6", - [KEY_KPPLUS] = "KPPlus", [KEY_KP1] = "KP1", - [KEY_KP2] = "KP2", [KEY_KP3] = "KP3", - [KEY_KP0] = "KP0", [KEY_KPDOT] = "KPDot", - [KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd", - [KEY_F11] = "F11", [KEY_F12] = "F12", - [KEY_RO] = "RO", [KEY_KATAKANA] = "Katakana", - [KEY_HIRAGANA] = "HIRAGANA", [KEY_HENKAN] = "Henkan", - [KEY_KATAKANAHIRAGANA] = "Katakana/Hiragana", [KEY_MUHENKAN] = "Muhenkan", - [KEY_KPJPCOMMA] = "KPJpComma", [KEY_KPENTER] = "KPEnter", - [KEY_RIGHTCTRL] = "RightCtrl", [KEY_KPSLASH] = "KPSlash", - [KEY_SYSRQ] = "SysRq", [KEY_RIGHTALT] = "RightAlt", - [KEY_LINEFEED] = "LineFeed", [KEY_HOME] = "Home", - [KEY_UP] = "Up", [KEY_PAGEUP] = "PageUp", - [KEY_LEFT] = "Left", [KEY_RIGHT] = "Right", - [KEY_END] = "End", [KEY_DOWN] = "Down", - [KEY_PAGEDOWN] = "PageDown", [KEY_INSERT] = "Insert", - [KEY_DELETE] = "Delete", [KEY_MACRO] = "Macro", - [KEY_MUTE] = "Mute", [KEY_VOLUMEDOWN] = "VolumeDown", - [KEY_VOLUMEUP] = "VolumeUp", [KEY_POWER] = "Power", - [KEY_KPEQUAL] = "KPEqual", [KEY_KPPLUSMINUS] = "KPPlusMinus", - [KEY_PAUSE] = "Pause", [KEY_KPCOMMA] = "KPComma", - [KEY_HANGUEL] = "Hangeul", [KEY_HANJA] = "Hanja", - [KEY_YEN] = "Yen", [KEY_LEFTMETA] = "LeftMeta", - [KEY_RIGHTMETA] = "RightMeta", [KEY_COMPOSE] = "Compose", - [KEY_STOP] = "Stop", [KEY_AGAIN] = "Again", - [KEY_PROPS] = "Props", [KEY_UNDO] = "Undo", - [KEY_FRONT] = "Front", [KEY_COPY] = "Copy", - [KEY_OPEN] = "Open", [KEY_PASTE] = "Paste", - [KEY_FIND] = "Find", [KEY_CUT] = "Cut", - [KEY_HELP] = "Help", [KEY_MENU] = "Menu", - [KEY_CALC] = "Calc", [KEY_SETUP] = "Setup", - [KEY_SLEEP] = "Sleep", [KEY_WAKEUP] = "WakeUp", - [KEY_FILE] = "File", [KEY_SENDFILE] = "SendFile", - [KEY_DELETEFILE] = "DeleteFile", [KEY_XFER] = "X-fer", - [KEY_PROG1] = "Prog1", [KEY_PROG2] = "Prog2", - [KEY_WWW] = "WWW", [KEY_MSDOS] = "MSDOS", - [KEY_COFFEE] = "Coffee", [KEY_DIRECTION] = "Direction", - [KEY_CYCLEWINDOWS] = "CycleWindows", [KEY_MAIL] = "Mail", - [KEY_BOOKMARKS] = "Bookmarks", [KEY_COMPUTER] = "Computer", - [KEY_BACK] = "Back", [KEY_FORWARD] = "Forward", - [KEY_CLOSECD] = "CloseCD", [KEY_EJECTCD] = "EjectCD", - [KEY_EJECTCLOSECD] = "EjectCloseCD", [KEY_NEXTSONG] = "NextSong", - [KEY_PLAYPAUSE] = "PlayPause", [KEY_PREVIOUSSONG] = "PreviousSong", - [KEY_STOPCD] = "StopCD", [KEY_RECORD] = "Record", - [KEY_REWIND] = "Rewind", [KEY_PHONE] = "Phone", - [KEY_ISO] = "ISOKey", [KEY_CONFIG] = "Config", - [KEY_HOMEPAGE] = "HomePage", [KEY_REFRESH] = "Refresh", - [KEY_EXIT] = "Exit", [KEY_MOVE] = "Move", - [KEY_EDIT] = "Edit", [KEY_SCROLLUP] = "ScrollUp", - [KEY_SCROLLDOWN] = "ScrollDown", [KEY_KPLEFTPAREN] = "KPLeftParenthesis", - [KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_NEW] = "New", - [KEY_REDO] = "Redo", [KEY_F13] = "F13", - [KEY_F14] = "F14", [KEY_F15] = "F15", - [KEY_F16] = "F16", [KEY_F17] = "F17", - [KEY_F18] = "F18", [KEY_F19] = "F19", - [KEY_F20] = "F20", [KEY_F21] = "F21", - [KEY_F22] = "F22", [KEY_F23] = "F23", - [KEY_F24] = "F24", [KEY_PLAYCD] = "PlayCD", - [KEY_PAUSECD] = "PauseCD", [KEY_PROG3] = "Prog3", - [KEY_PROG4] = "Prog4", [KEY_SUSPEND] = "Suspend", - [KEY_CLOSE] = "Close", [KEY_PLAY] = "Play", - [KEY_FASTFORWARD] = "FastForward", [KEY_BASSBOOST] = "BassBoost", - [KEY_PRINT] = "Print", [KEY_HP] = "HP", - [KEY_CAMERA] = "Camera", [KEY_SOUND] = "Sound", - [KEY_QUESTION] = "Question", [KEY_EMAIL] = "Email", - [KEY_CHAT] = "Chat", [KEY_SEARCH] = "Search", - [KEY_CONNECT] = "Connect", [KEY_FINANCE] = "Finance", - [KEY_SPORT] = "Sport", [KEY_SHOP] = "Shop", - [KEY_ALTERASE] = "AlternateErase", [KEY_CANCEL] = "Cancel", - [KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp", - [KEY_MEDIA] = "Media", [KEY_UNKNOWN] = "Unknown", - [BTN_0] = "Btn0", [BTN_1] = "Btn1", - [BTN_2] = "Btn2", [BTN_3] = "Btn3", - [BTN_4] = "Btn4", [BTN_5] = "Btn5", - [BTN_6] = "Btn6", [BTN_7] = "Btn7", - [BTN_8] = "Btn8", [BTN_9] = "Btn9", - [BTN_LEFT] = "LeftBtn", [BTN_RIGHT] = "RightBtn", - [BTN_MIDDLE] = "MiddleBtn", [BTN_SIDE] = "SideBtn", - [BTN_EXTRA] = "ExtraBtn", [BTN_FORWARD] = "ForwardBtn", - [BTN_BACK] = "BackBtn", [BTN_TASK] = "TaskBtn", - [BTN_TRIGGER] = "Trigger", [BTN_THUMB] = "ThumbBtn", - [BTN_THUMB2] = "ThumbBtn2", [BTN_TOP] = "TopBtn", - [BTN_TOP2] = "TopBtn2", [BTN_PINKIE] = "PinkieBtn", - [BTN_BASE] = "BaseBtn", [BTN_BASE2] = "BaseBtn2", - [BTN_BASE3] = "BaseBtn3", [BTN_BASE4] = "BaseBtn4", - [BTN_BASE5] = "BaseBtn5", [BTN_BASE6] = "BaseBtn6", - [BTN_DEAD] = "BtnDead", [BTN_A] = "BtnA", - [BTN_B] = "BtnB", [BTN_C] = "BtnC", - [BTN_X] = "BtnX", [BTN_Y] = "BtnY", - [BTN_Z] = "BtnZ", [BTN_TL] = "BtnTL", - [BTN_TR] = "BtnTR", [BTN_TL2] = "BtnTL2", - [BTN_TR2] = "BtnTR2", [BTN_SELECT] = "BtnSelect", - [BTN_START] = "BtnStart", [BTN_MODE] = "BtnMode", - [BTN_THUMBL] = "BtnThumbL", [BTN_THUMBR] = "BtnThumbR", - [BTN_TOOL_PEN] = "ToolPen", [BTN_TOOL_RUBBER] = "ToolRubber", - [BTN_TOOL_BRUSH] = "ToolBrush", [BTN_TOOL_PENCIL] = "ToolPencil", - [BTN_TOOL_AIRBRUSH] = "ToolAirbrush", [BTN_TOOL_FINGER] = "ToolFinger", - [BTN_TOOL_MOUSE] = "ToolMouse", [BTN_TOOL_LENS] = "ToolLens", - [BTN_TOUCH] = "Touch", [BTN_STYLUS] = "Stylus", - [BTN_STYLUS2] = "Stylus2", [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap", - [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn", - [BTN_GEAR_UP] = "Gear up", [KEY_OK] = "Ok", - [KEY_SELECT] = "Select", [KEY_GOTO] = "Goto", - [KEY_CLEAR] = "Clear", [KEY_POWER2] = "Power2", - [KEY_OPTION] = "Option", [KEY_INFO] = "Info", - [KEY_TIME] = "Time", [KEY_VENDOR] = "Vendor", - [KEY_ARCHIVE] = "Archive", [KEY_PROGRAM] = "Program", - [KEY_CHANNEL] = "Channel", [KEY_FAVORITES] = "Favorites", - [KEY_EPG] = "EPG", [KEY_PVR] = "PVR", - [KEY_MHP] = "MHP", [KEY_LANGUAGE] = "Language", - [KEY_TITLE] = "Title", [KEY_SUBTITLE] = "Subtitle", - [KEY_ANGLE] = "Angle", [KEY_ZOOM] = "Zoom", - [KEY_MODE] = "Mode", [KEY_KEYBOARD] = "Keyboard", - [KEY_SCREEN] = "Screen", [KEY_PC] = "PC", - [KEY_TV] = "TV", [KEY_TV2] = "TV2", - [KEY_VCR] = "VCR", [KEY_VCR2] = "VCR2", - [KEY_SAT] = "Sat", [KEY_SAT2] = "Sat2", - [KEY_CD] = "CD", [KEY_TAPE] = "Tape", - [KEY_RADIO] = "Radio", [KEY_TUNER] = "Tuner", - [KEY_PLAYER] = "Player", [KEY_TEXT] = "Text", - [KEY_DVD] = "DVD", [KEY_AUX] = "Aux", - [KEY_MP3] = "MP3", [KEY_AUDIO] = "Audio", - [KEY_VIDEO] = "Video", [KEY_DIRECTORY] = "Directory", - [KEY_LIST] = "List", [KEY_MEMO] = "Memo", - [KEY_CALENDAR] = "Calendar", [KEY_RED] = "Red", - [KEY_GREEN] = "Green", [KEY_YELLOW] = "Yellow", - [KEY_BLUE] = "Blue", [KEY_CHANNELUP] = "ChannelUp", - [KEY_CHANNELDOWN] = "ChannelDown", [KEY_FIRST] = "First", - [KEY_LAST] = "Last", [KEY_AB] = "AB", - [KEY_NEXT] = "Next", [KEY_RESTART] = "Restart", - [KEY_SLOW] = "Slow", [KEY_SHUFFLE] = "Shuffle", - [KEY_BREAK] = "Break", [KEY_PREVIOUS] = "Previous", - [KEY_DIGITS] = "Digits", [KEY_TEEN] = "TEEN", - [KEY_TWEN] = "TWEN", [KEY_DEL_EOL] = "DeleteEOL", - [KEY_DEL_EOS] = "DeleteEOS", [KEY_INS_LINE] = "InsertLine", - [KEY_DEL_LINE] = "DeleteLine", - [KEY_SEND] = "Send", [KEY_REPLY] = "Reply", - [KEY_FORWARDMAIL] = "ForwardMail", [KEY_SAVE] = "Save", - [KEY_DOCUMENTS] = "Documents", - [KEY_FN] = "Fn", [KEY_FN_ESC] = "Fn+ESC", - [KEY_FN_1] = "Fn+1", [KEY_FN_2] = "Fn+2", - [KEY_FN_B] = "Fn+B", [KEY_FN_D] = "Fn+D", - [KEY_FN_E] = "Fn+E", [KEY_FN_F] = "Fn+F", - [KEY_FN_S] = "Fn+S", - [KEY_FN_F1] = "Fn+F1", [KEY_FN_F2] = "Fn+F2", - [KEY_FN_F3] = "Fn+F3", [KEY_FN_F4] = "Fn+F4", - [KEY_FN_F5] = "Fn+F5", [KEY_FN_F6] = "Fn+F6", - [KEY_FN_F7] = "Fn+F7", [KEY_FN_F8] = "Fn+F8", - [KEY_FN_F9] = "Fn+F9", [KEY_FN_F10] = "Fn+F10", - [KEY_FN_F11] = "Fn+F11", [KEY_FN_F12] = "Fn+F12", - [KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle", - [KEY_KBDILLUMDOWN] = "KbdIlluminationDown", - [KEY_KBDILLUMUP] = "KbdIlluminationUp", - [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode", -}; - -static char *relatives[REL_MAX + 1] = { - [REL_X] = "X", [REL_Y] = "Y", - [REL_Z] = "Z", [REL_HWHEEL] = "HWheel", - [REL_DIAL] = "Dial", [REL_WHEEL] = "Wheel", - [REL_MISC] = "Misc", -}; - -static char *absolutes[ABS_MAX + 1] = { - [ABS_X] = "X", [ABS_Y] = "Y", - [ABS_Z] = "Z", [ABS_RX] = "Rx", - [ABS_RY] = "Ry", [ABS_RZ] = "Rz", - [ABS_THROTTLE] = "Throttle", [ABS_RUDDER] = "Rudder", - [ABS_WHEEL] = "Wheel", [ABS_GAS] = "Gas", - [ABS_BRAKE] = "Brake", [ABS_HAT0X] = "Hat0X", - [ABS_HAT0Y] = "Hat0Y", [ABS_HAT1X] = "Hat1X", - [ABS_HAT1Y] = "Hat1Y", [ABS_HAT2X] = "Hat2X", - [ABS_HAT2Y] = "Hat2Y", [ABS_HAT3X] = "Hat3X", - [ABS_HAT3Y] = "Hat 3Y", [ABS_PRESSURE] = "Pressure", - [ABS_DISTANCE] = "Distance", [ABS_TILT_X] = "XTilt", - [ABS_TILT_Y] = "YTilt", [ABS_TOOL_WIDTH] = "Tool Width", - [ABS_VOLUME] = "Volume", [ABS_MISC] = "Misc", -}; - -static char *misc[MSC_MAX + 1] = { - [MSC_SERIAL] = "Serial", [MSC_PULSELED] = "Pulseled", - [MSC_GESTURE] = "Gesture", [MSC_RAW] = "RawData" -}; - -static char *leds[LED_MAX + 1] = { - [LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock", - [LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose", - [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep", - [LED_SUSPEND] = "Suspend", [LED_MUTE] = "Mute", - [LED_MISC] = "Misc", -}; - -static char *repeats[REP_MAX + 1] = { - [REP_DELAY] = "Delay", [REP_PERIOD] = "Period" -}; - -static char *sounds[SND_MAX + 1] = { - [SND_CLICK] = "Click", [SND_BELL] = "Bell", - [SND_TONE] = "Tone" -}; - -static char **names[EV_MAX + 1] = { - [EV_SYN] = syncs, [EV_KEY] = keys, - [EV_REL] = relatives, [EV_ABS] = absolutes, - [EV_MSC] = misc, [EV_LED] = leds, - [EV_SND] = sounds, [EV_REP] = repeats, -}; - -static void __attribute__((unused)) resolv_event(__u8 type, __u16 code) { - - printk("%s.%s", events[type] ? events[type] : "?", - names[type] ? (names[type][code] ? names[type][code] : "?") : "?"); -} diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index a8fc46c721c5..f8f660ee3fac 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c @@ -32,7 +32,7 @@ #undef DEBUG #include <linux/usb.h> -#include "hid.h" +#include <linux/hid.h> /* * This table contains pointers to initializers. To add support for new @@ -70,8 +70,8 @@ static struct hid_ff_initializer inits[] = { int hid_ff_init(struct hid_device* hid) { struct hid_ff_initializer *init; - int vendor = le16_to_cpu(hid->dev->descriptor.idVendor); - int product = le16_to_cpu(hid->dev->descriptor.idProduct); + int vendor = le16_to_cpu(to_usb_device(hid->dev)->descriptor.idVendor); + int product = le16_to_cpu(to_usb_device(hid->dev)->descriptor.idProduct); for (init = inits; init->idVendor; init++) if (init->idVendor == vendor && init->idProduct == product) @@ -79,3 +79,5 @@ int hid_ff_init(struct hid_device* hid) return init->init(hid); } +EXPORT_SYMBOL_GPL(hid_ff_init); + diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c deleted file mode 100644 index 9a808a3b4d37..000000000000 --- a/drivers/usb/input/hid-input.c +++ /dev/null @@ -1,851 +0,0 @@ -/* - * $Id: hid-input.c,v 1.2 2002/04/23 00:59:25 rdamazio Exp $ - * - * Copyright (c) 2000-2001 Vojtech Pavlik - * - * USB HID to Linux Input mapping - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/kernel.h> -#include <linux/usb/input.h> - -#undef DEBUG - -#include "hid.h" - -#define unk KEY_UNKNOWN - -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, - 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, - 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, - 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, - 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, - 115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk, - 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, - 150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk -}; - -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}}; - -#define map_abs(c) do { usage->code = c; usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; } while (0) -#define map_rel(c) do { usage->code = c; usage->type = EV_REL; bit = input->relbit; max = REL_MAX; } while (0) -#define map_key(c) do { usage->code = c; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; } while (0) -#define map_led(c) do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0) - -#define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0) -#define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0) - -#ifdef CONFIG_USB_HIDINPUT_POWERBOOK - -struct hidinput_key_translation { - u16 from; - u16 to; - u8 flags; -}; - -#define POWERBOOK_FLAG_FKEY 0x01 - -static struct hidinput_key_translation powerbook_fn_keys[] = { - { KEY_BACKSPACE, KEY_DELETE }, - { KEY_F1, KEY_BRIGHTNESSDOWN, POWERBOOK_FLAG_FKEY }, - { KEY_F2, KEY_BRIGHTNESSUP, POWERBOOK_FLAG_FKEY }, - { KEY_F3, KEY_MUTE, POWERBOOK_FLAG_FKEY }, - { KEY_F4, KEY_VOLUMEDOWN, POWERBOOK_FLAG_FKEY }, - { KEY_F5, KEY_VOLUMEUP, POWERBOOK_FLAG_FKEY }, - { KEY_F6, KEY_NUMLOCK, POWERBOOK_FLAG_FKEY }, - { KEY_F7, KEY_SWITCHVIDEOMODE, POWERBOOK_FLAG_FKEY }, - { KEY_F8, KEY_KBDILLUMTOGGLE, POWERBOOK_FLAG_FKEY }, - { KEY_F9, KEY_KBDILLUMDOWN, POWERBOOK_FLAG_FKEY }, - { KEY_F10, KEY_KBDILLUMUP, POWERBOOK_FLAG_FKEY }, - { KEY_UP, KEY_PAGEUP }, - { KEY_DOWN, KEY_PAGEDOWN }, - { KEY_LEFT, KEY_HOME }, - { KEY_RIGHT, KEY_END }, - { } -}; - -static struct hidinput_key_translation powerbook_numlock_keys[] = { - { KEY_J, KEY_KP1 }, - { KEY_K, KEY_KP2 }, - { KEY_L, KEY_KP3 }, - { KEY_U, KEY_KP4 }, - { KEY_I, KEY_KP5 }, - { KEY_O, KEY_KP6 }, - { KEY_7, KEY_KP7 }, - { KEY_8, KEY_KP8 }, - { KEY_9, KEY_KP9 }, - { KEY_M, KEY_KP0 }, - { KEY_DOT, KEY_KPDOT }, - { KEY_SLASH, KEY_KPPLUS }, - { KEY_SEMICOLON, KEY_KPMINUS }, - { KEY_P, KEY_KPASTERISK }, - { KEY_MINUS, KEY_KPEQUAL }, - { KEY_0, KEY_KPSLASH }, - { KEY_F6, KEY_NUMLOCK }, - { KEY_KPENTER, KEY_KPENTER }, - { KEY_BACKSPACE, KEY_BACKSPACE }, - { } -}; - -static int usbhid_pb_fnmode = 1; -module_param_named(pb_fnmode, usbhid_pb_fnmode, int, 0644); -MODULE_PARM_DESC(pb_fnmode, - "Mode of fn key on PowerBooks (0 = disabled, 1 = fkeyslast, 2 = fkeysfirst)"); - -static struct hidinput_key_translation *find_translation(struct hidinput_key_translation *table, u16 from) -{ - struct hidinput_key_translation *trans; - - /* Look for the translation */ - for (trans = table; trans->from; trans++) - if (trans->from == from) - return trans; - - return NULL; -} - -static int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, - struct hid_usage *usage, __s32 value) -{ - struct hidinput_key_translation *trans; - - if (usage->code == KEY_FN) { - if (value) hid->quirks |= HID_QUIRK_POWERBOOK_FN_ON; - else hid->quirks &= ~HID_QUIRK_POWERBOOK_FN_ON; - - input_event(input, usage->type, usage->code, value); - - return 1; - } - - if (usbhid_pb_fnmode) { - int do_translate; - - trans = find_translation(powerbook_fn_keys, usage->code); - if (trans) { - if (test_bit(usage->code, hid->pb_pressed_fn)) - do_translate = 1; - else if (trans->flags & POWERBOOK_FLAG_FKEY) - do_translate = - (usbhid_pb_fnmode == 2 && (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)) || - (usbhid_pb_fnmode == 1 && !(hid->quirks & HID_QUIRK_POWERBOOK_FN_ON)); - else - do_translate = (hid->quirks & HID_QUIRK_POWERBOOK_FN_ON); - - if (do_translate) { - if (value) - set_bit(usage->code, hid->pb_pressed_fn); - else - clear_bit(usage->code, hid->pb_pressed_fn); - - input_event(input, usage->type, trans->to, value); - - return 1; - } - } - - if (test_bit(usage->code, hid->pb_pressed_numlock) || - test_bit(LED_NUML, input->led)) { - trans = find_translation(powerbook_numlock_keys, usage->code); - - if (trans) { - if (value) - set_bit(usage->code, hid->pb_pressed_numlock); - else - clear_bit(usage->code, hid->pb_pressed_numlock); - - input_event(input, usage->type, trans->to, value); - } - - return 1; - } - } - - return 0; -} - -static void hidinput_pb_setup(struct input_dev *input) -{ - struct hidinput_key_translation *trans; - - set_bit(KEY_NUMLOCK, input->keybit); - - /* Enable all needed keys */ - for (trans = powerbook_fn_keys; trans->from; trans++) - set_bit(trans->to, input->keybit); - - for (trans = powerbook_numlock_keys; trans->from; trans++) - set_bit(trans->to, input->keybit); -} -#else -static inline int hidinput_pb_event(struct hid_device *hid, struct input_dev *input, - struct hid_usage *usage, __s32 value) -{ - return 0; -} - -static inline void hidinput_pb_setup(struct input_dev *input) -{ -} -#endif - -static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, - struct hid_usage *usage) -{ - struct input_dev *input = hidinput->input; - struct hid_device *device = input->private; - int max = 0, code; - unsigned long *bit = NULL; - - field->hidinput = hidinput; - -#ifdef DEBUG - printk(KERN_DEBUG "Mapping: "); - resolv_usage(usage->hid); - printk(" ---> "); -#endif - - if (field->flags & HID_MAIN_ITEM_CONSTANT) - goto ignore; - - switch (usage->hid & HID_USAGE_PAGE) { - - case HID_UP_UNDEFINED: - goto ignore; - - case HID_UP_KEYBOARD: - - set_bit(EV_REP, input->evbit); - - if ((usage->hid & HID_USAGE) < 256) { - if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore; - map_key_clear(hid_keyboard[usage->hid & HID_USAGE]); - } else - map_key(KEY_UNKNOWN); - - break; - - case HID_UP_BUTTON: - - code = ((usage->hid - 1) & 0xf); - - switch (field->application) { - case HID_GD_MOUSE: - case HID_GD_POINTER: code += 0x110; break; - case HID_GD_JOYSTICK: code += 0x120; break; - case HID_GD_GAMEPAD: code += 0x130; break; - default: - switch (field->physical) { - case HID_GD_MOUSE: - case HID_GD_POINTER: code += 0x110; break; - case HID_GD_JOYSTICK: code += 0x120; break; - case HID_GD_GAMEPAD: code += 0x130; break; - default: code += 0x100; - } - } - - map_key(code); - break; - - - case HID_UP_SIMULATION: - - switch (usage->hid & 0xffff) { - case 0xba: map_abs(ABS_RUDDER); break; - case 0xbb: map_abs(ABS_THROTTLE); break; - case 0xc4: map_abs(ABS_GAS); break; - case 0xc5: map_abs(ABS_BRAKE); break; - case 0xc8: map_abs(ABS_WHEEL); break; - default: goto ignore; - } - break; - - case HID_UP_GENDESK: - - if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */ - switch (usage->hid & 0xf) { - case 0x1: map_key_clear(KEY_POWER); break; - case 0x2: map_key_clear(KEY_SLEEP); break; - case 0x3: map_key_clear(KEY_WAKEUP); break; - default: goto unknown; - } - break; - } - - if ((usage->hid & 0xf0) == 0x90) { /* D-pad */ - switch (usage->hid) { - case HID_GD_UP: usage->hat_dir = 1; break; - case HID_GD_DOWN: usage->hat_dir = 5; break; - case HID_GD_RIGHT: usage->hat_dir = 3; break; - case HID_GD_LEFT: usage->hat_dir = 7; break; - default: goto unknown; - } - if (field->dpad) { - map_abs(field->dpad); - goto ignore; - } - map_abs(ABS_HAT0X); - break; - } - - switch (usage->hid) { - - /* These usage IDs map directly to the usage codes. */ - case HID_GD_X: case HID_GD_Y: case HID_GD_Z: - case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ: - case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL: - if (field->flags & HID_MAIN_ITEM_RELATIVE) - map_rel(usage->hid & 0xf); - else - map_abs(usage->hid & 0xf); - break; - - case HID_GD_HATSWITCH: - usage->hat_min = field->logical_minimum; - usage->hat_max = field->logical_maximum; - map_abs(ABS_HAT0X); - break; - - case HID_GD_START: map_key_clear(BTN_START); break; - case HID_GD_SELECT: map_key_clear(BTN_SELECT); break; - - default: goto unknown; - } - - break; - - case HID_UP_LED: - if (((usage->hid - 1) & 0xffff) >= LED_MAX) - goto ignore; - map_led((usage->hid - 1) & 0xffff); - break; - - case HID_UP_DIGITIZER: - - switch (usage->hid & 0xff) { - - case 0x30: /* TipPressure */ - if (!test_bit(BTN_TOUCH, input->keybit)) { - device->quirks |= HID_QUIRK_NOTOUCH; - set_bit(EV_KEY, input->evbit); - set_bit(BTN_TOUCH, input->keybit); - } - - map_abs_clear(ABS_PRESSURE); - break; - - case 0x32: /* InRange */ - switch (field->physical & 0xff) { - case 0x21: map_key(BTN_TOOL_MOUSE); break; - case 0x22: map_key(BTN_TOOL_FINGER); break; - default: map_key(BTN_TOOL_PEN); break; - } - break; - - case 0x3c: /* Invert */ - map_key_clear(BTN_TOOL_RUBBER); - break; - - case 0x33: /* Touch */ - case 0x42: /* TipSwitch */ - case 0x43: /* TipSwitch2 */ - device->quirks &= ~HID_QUIRK_NOTOUCH; - map_key_clear(BTN_TOUCH); - break; - - case 0x44: /* BarrelSwitch */ - map_key_clear(BTN_STYLUS); - break; - - default: goto unknown; - } - break; - - case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */ - - switch (usage->hid & HID_USAGE) { - case 0x000: goto ignore; - case 0x034: map_key_clear(KEY_SLEEP); break; - case 0x036: map_key_clear(BTN_MISC); break; - case 0x045: map_key_clear(KEY_RADIO); break; - case 0x08a: map_key_clear(KEY_WWW); break; - case 0x08d: map_key_clear(KEY_PROGRAM); break; - case 0x095: map_key_clear(KEY_HELP); break; - case 0x09c: map_key_clear(KEY_CHANNELUP); break; - case 0x09d: map_key_clear(KEY_CHANNELDOWN); break; - case 0x0b0: map_key_clear(KEY_PLAY); break; - case 0x0b1: map_key_clear(KEY_PAUSE); break; - case 0x0b2: map_key_clear(KEY_RECORD); break; - case 0x0b3: map_key_clear(KEY_FASTFORWARD); break; - case 0x0b4: map_key_clear(KEY_REWIND); break; - case 0x0b5: map_key_clear(KEY_NEXTSONG); break; - case 0x0b6: map_key_clear(KEY_PREVIOUSSONG); break; - case 0x0b7: map_key_clear(KEY_STOPCD); break; - case 0x0b8: map_key_clear(KEY_EJECTCD); break; - case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break; - case 0x0e0: map_abs_clear(ABS_VOLUME); break; - case 0x0e2: map_key_clear(KEY_MUTE); break; - case 0x0e5: map_key_clear(KEY_BASSBOOST); break; - case 0x0e9: map_key_clear(KEY_VOLUMEUP); break; - case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break; - case 0x183: map_key_clear(KEY_CONFIG); break; - case 0x18a: map_key_clear(KEY_MAIL); break; - case 0x192: map_key_clear(KEY_CALC); break; - case 0x194: map_key_clear(KEY_FILE); break; - case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; - case 0x201: map_key_clear(KEY_NEW); break; - case 0x207: map_key_clear(KEY_SAVE); break; - case 0x208: map_key_clear(KEY_PRINT); break; - case 0x209: map_key_clear(KEY_PROPS); break; - case 0x21a: map_key_clear(KEY_UNDO); break; - case 0x21b: map_key_clear(KEY_COPY); break; - case 0x21c: map_key_clear(KEY_CUT); break; - case 0x21d: map_key_clear(KEY_PASTE); break; - case 0x221: map_key_clear(KEY_FIND); break; - case 0x223: map_key_clear(KEY_HOMEPAGE); break; - case 0x224: map_key_clear(KEY_BACK); break; - case 0x225: map_key_clear(KEY_FORWARD); break; - case 0x226: map_key_clear(KEY_STOP); break; - case 0x227: map_key_clear(KEY_REFRESH); break; - case 0x22a: map_key_clear(KEY_BOOKMARKS); break; - case 0x233: map_key_clear(KEY_SCROLLUP); break; - case 0x234: map_key_clear(KEY_SCROLLDOWN); break; - case 0x238: map_rel(REL_HWHEEL); break; - case 0x279: map_key_clear(KEY_REDO); break; - case 0x289: map_key_clear(KEY_REPLY); break; - case 0x28b: map_key_clear(KEY_FORWARDMAIL); break; - case 0x28c: map_key_clear(KEY_SEND); break; - - /* Reported on a Cherry Cymotion keyboard */ - case 0x301: map_key_clear(KEY_PROG1); break; - case 0x302: map_key_clear(KEY_PROG2); break; - case 0x303: map_key_clear(KEY_PROG3); break; - - default: goto ignore; - } - break; - - case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */ - - set_bit(EV_REP, input->evbit); - switch (usage->hid & HID_USAGE) { - case 0x021: map_key_clear(KEY_PRINT); break; - case 0x070: map_key_clear(KEY_HP); break; - case 0x071: map_key_clear(KEY_CAMERA); break; - case 0x072: map_key_clear(KEY_SOUND); break; - case 0x073: map_key_clear(KEY_QUESTION); break; - case 0x080: map_key_clear(KEY_EMAIL); break; - case 0x081: map_key_clear(KEY_CHAT); break; - case 0x082: map_key_clear(KEY_SEARCH); break; - case 0x083: map_key_clear(KEY_CONNECT); break; - case 0x084: map_key_clear(KEY_FINANCE); break; - case 0x085: map_key_clear(KEY_SPORT); break; - case 0x086: map_key_clear(KEY_SHOP); break; - default: goto ignore; - } - break; - - case HID_UP_MSVENDOR: - goto ignore; - - case HID_UP_CUSTOM: /* Reported on Logitech and Powerbook USB keyboards */ - - set_bit(EV_REP, input->evbit); - switch(usage->hid & HID_USAGE) { - case 0x003: - /* The fn key on Apple PowerBooks */ - map_key_clear(KEY_FN); - hidinput_pb_setup(input); - break; - - default: goto ignore; - } - break; - - case HID_UP_LOGIVENDOR: /* Reported on Logitech Ultra X Media Remote */ - - set_bit(EV_REP, input->evbit); - switch(usage->hid & HID_USAGE) { - case 0x004: map_key_clear(KEY_AGAIN); break; - case 0x00d: map_key_clear(KEY_HOME); break; - case 0x024: map_key_clear(KEY_SHUFFLE); break; - case 0x025: map_key_clear(KEY_TV); break; - case 0x026: map_key_clear(KEY_MENU); break; - case 0x031: map_key_clear(KEY_AUDIO); break; - case 0x032: map_key_clear(KEY_TEXT); break; - case 0x033: map_key_clear(KEY_LAST); break; - case 0x047: map_key_clear(KEY_MP3); break; - case 0x048: map_key_clear(KEY_DVD); break; - case 0x049: map_key_clear(KEY_MEDIA); break; - case 0x04a: map_key_clear(KEY_VIDEO); break; - case 0x04b: map_key_clear(KEY_ANGLE); break; - case 0x04c: map_key_clear(KEY_LANGUAGE); break; - case 0x04d: map_key_clear(KEY_SUBTITLE); break; - case 0x051: map_key_clear(KEY_RED); break; - case 0x052: map_key_clear(KEY_CLOSE); break; - default: goto ignore; - } - break; - - case HID_UP_PID: - - switch(usage->hid & HID_USAGE) { - case 0xa4: map_key_clear(BTN_DEAD); break; - default: goto ignore; - } - break; - - default: - unknown: - if (field->report_size == 1) { - if (field->report->type == HID_OUTPUT_REPORT) { - map_led(LED_MISC); - break; - } - map_key(BTN_MISC); - break; - } - if (field->flags & HID_MAIN_ITEM_RELATIVE) { - map_rel(REL_MISC); - break; - } - map_abs(ABS_MISC); - break; - } - - if (device->quirks & HID_QUIRK_MIGHTYMOUSE) { - if (usage->hid == HID_GD_Z) - map_rel(REL_HWHEEL); - else if (usage->code == BTN_1) - map_key(BTN_2); - else if (usage->code == BTN_2) - map_key(BTN_1); - } - - if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) && - (usage->type == EV_REL) && (usage->code == REL_WHEEL)) - set_bit(REL_HWHEEL, bit); - - if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005)) - || ((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) - goto ignore; - - set_bit(usage->type, input->evbit); - - while (usage->code <= max && test_and_set_bit(usage->code, bit)) - usage->code = find_next_zero_bit(bit, max + 1, usage->code); - - if (usage->code > max) - goto ignore; - - - if (usage->type == EV_ABS) { - - int a = field->logical_minimum; - int b = field->logical_maximum; - - if ((device->quirks & HID_QUIRK_BADPAD) && (usage->code == ABS_X || usage->code == ABS_Y)) { - a = field->logical_minimum = 0; - b = field->logical_maximum = 255; - } - - if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK) - input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4); - else input_set_abs_params(input, usage->code, a, b, 0, 0); - - } - - if (usage->type == EV_ABS && - (usage->hat_min < usage->hat_max || usage->hat_dir)) { - int i; - for (i = usage->code; i < usage->code + 2 && i <= max; i++) { - input_set_abs_params(input, i, -1, 1, 0, 0); - set_bit(i, input->absbit); - } - if (usage->hat_dir && !field->dpad) - field->dpad = usage->code; - } - -#ifdef DEBUG - resolv_event(usage->type, usage->code); - printk("\n"); -#endif - return; - -ignore: -#ifdef DEBUG - printk("IGNORED\n"); -#endif - return; -} - -void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) -{ - struct input_dev *input; - int *quirks = &hid->quirks; - - if (!field->hidinput) - return; - - input = field->hidinput->input; - - if (!usage->type) - return; - - if (((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005)) - || ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_7) && (usage->hid == 0x00090007))) { - if (value) hid->quirks |= HID_QUIRK_2WHEEL_MOUSE_HACK_ON; - else hid->quirks &= ~HID_QUIRK_2WHEEL_MOUSE_HACK_ON; - return; - } - - if ((hid->quirks & HID_QUIRK_INVERT_HWHEEL) && (usage->code == REL_HWHEEL)) { - input_event(input, usage->type, usage->code, -value); - return; - } - - if ((hid->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_ON) && (usage->code == REL_WHEEL)) { - input_event(input, usage->type, REL_HWHEEL, value); - return; - } - - if ((hid->quirks & HID_QUIRK_POWERBOOK_HAS_FN) && hidinput_pb_event(hid, input, usage, value)) - return; - - if (usage->hat_min < usage->hat_max || usage->hat_dir) { - int hat_dir = usage->hat_dir; - if (!hat_dir) - hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1; - if (hat_dir < 0 || hat_dir > 8) hat_dir = 0; - input_event(input, usage->type, usage->code , hid_hat_to_axis[hat_dir].x); - input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y); - return; - } - - if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */ - *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT); - return; - } - - if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */ - if (value) { - input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1); - return; - } - input_event(input, usage->type, usage->code, 0); - input_event(input, usage->type, BTN_TOOL_RUBBER, 0); - return; - } - - if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */ - int a = field->logical_minimum; - int b = field->logical_maximum; - input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3)); - } - - if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */ - dbg("Maximum Effects - %d",value); - return; - } - - if (usage->hid == (HID_UP_PID | 0x7fUL)) { - dbg("PID Pool Report\n"); - return; - } - - if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ - return; - - input_event(input, usage->type, usage->code, value); - - if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) - input_event(input, usage->type, usage->code, 0); -} - -void hidinput_report_event(struct hid_device *hid, struct hid_report *report) -{ - struct hid_input *hidinput; - - list_for_each_entry(hidinput, &hid->inputs, list) - input_sync(hidinput->input); -} - -static int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field) -{ - struct hid_report *report; - int i, j; - - list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) { - for (i = 0; i < report->maxfield; i++) { - *field = report->field[i]; - for (j = 0; j < (*field)->maxusage; j++) - if ((*field)->usage[j].type == type && (*field)->usage[j].code == code) - return j; - } - } - return -1; -} - -static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) -{ - struct hid_device *hid = dev->private; - struct hid_field *field; - int offset; - - if (type == EV_FF) - return input_ff_event(dev, type, code, value); - - if (type != EV_LED) - return -1; - - if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) { - warn("event field not found"); - return -1; - } - - hid_set_field(field, offset, value); - hid_submit_report(hid, field->report, USB_DIR_OUT); - - return 0; -} - -static int hidinput_open(struct input_dev *dev) -{ - struct hid_device *hid = dev->private; - return hid_open(hid); -} - -static void hidinput_close(struct input_dev *dev) -{ - struct hid_device *hid = dev->private; - hid_close(hid); -} - -/* - * Register the input device; print a message. - * Configure the input layer interface - * Read all reports and initialize the absolute field values. - */ - -int hidinput_connect(struct hid_device *hid) -{ - struct usb_device *dev = hid->dev; - struct hid_report *report; - struct hid_input *hidinput = NULL; - struct input_dev *input_dev; - int i, j, k; - - INIT_LIST_HEAD(&hid->inputs); - - for (i = 0; i < hid->maxcollection; i++) - if (hid->collection[i].type == HID_COLLECTION_APPLICATION || - hid->collection[i].type == HID_COLLECTION_PHYSICAL) - if (IS_INPUT_APPLICATION(hid->collection[i].usage)) - break; - - if (i == hid->maxcollection) - return -1; - - for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) - list_for_each_entry(report, &hid->report_enum[k].report_list, list) { - - if (!report->maxfield) - continue; - - if (!hidinput) { - hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!hidinput || !input_dev) { - kfree(hidinput); - input_free_device(input_dev); - err("Out of memory during hid input probe"); - return -1; - } - - input_dev->private = hid; - input_dev->event = hidinput_input_event; - input_dev->open = hidinput_open; - input_dev->close = hidinput_close; - - input_dev->name = hid->name; - input_dev->phys = hid->phys; - input_dev->uniq = hid->uniq; - usb_to_input_id(dev, &input_dev->id); - input_dev->cdev.dev = &hid->intf->dev; - - hidinput->input = input_dev; - list_add_tail(&hidinput->list, &hid->inputs); - } - - for (i = 0; i < report->maxfield; i++) - for (j = 0; j < report->field[i]->maxusage; j++) - hidinput_configure_usage(hidinput, report->field[i], - report->field[i]->usage + j); - - if (hid->quirks & HID_QUIRK_MULTI_INPUT) { - /* This will leave hidinput NULL, so that it - * allocates another one if we have more inputs on - * the same interface. Some devices (e.g. Happ's - * UGCI) cram a lot of unrelated inputs into the - * same interface. */ - hidinput->report = report; - input_register_device(hidinput->input); - hidinput = NULL; - } - } - - /* This only gets called when we are a single-input (most of the - * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is - * only useful in this case, and not for multi-input quirks. */ - if (hidinput) { - hid_ff_init(hid); - input_register_device(hidinput->input); - } - - return 0; -} - -void hidinput_disconnect(struct hid_device *hid) -{ - struct hid_input *hidinput, *next; - - list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { - list_del(&hidinput->list); - input_unregister_device(hidinput->input); - kfree(hidinput); - } -} diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c index 93da222b6da8..e47466268565 100644 --- a/drivers/usb/input/hid-lgff.c +++ b/drivers/usb/input/hid-lgff.c @@ -29,7 +29,8 @@ #include <linux/input.h> #include <linux/usb.h> -#include "hid.h" +#include <linux/hid.h> +#include "usbhid.h" struct device_type { u16 idVendor; @@ -75,7 +76,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef report->field[0]->value[2] = x; report->field[0]->value[3] = y; dbg("(x, y)=(%04x, %04x)", x, y); - hid_submit_report(hid, report, USB_DIR_OUT); + usbhid_submit_report(hid, report, USB_DIR_OUT); break; case FF_RUMBLE: @@ -90,7 +91,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef report->field[0]->value[2] = left; report->field[0]->value[3] = right; dbg("(left, right)=(%04x, %04x)", left, right); - hid_submit_report(hid, report, USB_DIR_OUT); + usbhid_submit_report(hid, report, USB_DIR_OUT); break; } return 0; diff --git a/drivers/usb/input/hid-pidff.c b/drivers/usb/input/hid-pidff.c index 5420c13eb8eb..cbd2d53fefff 100644 --- a/drivers/usb/input/hid-pidff.c +++ b/drivers/usb/input/hid-pidff.c @@ -28,7 +28,9 @@ #include <linux/input.h> #include <linux/usb.h> -#include "hid.h" +#include <linux/hid.h> + +#include "usbhid.h" #define PID_EFFECTS_MAX 64 @@ -260,7 +262,7 @@ static void pidff_set_envelope_report(struct pidff_device *pidff, debug("attack %u => %d", envelope->attack_level, pidff->set_envelope[PID_ATTACK_LEVEL].value[0]); - hid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE], USB_DIR_OUT); } @@ -287,7 +289,7 @@ static void pidff_set_constant_force_report(struct pidff_device *pidff, pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE], effect->u.constant.level); - hid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT], USB_DIR_OUT); } @@ -322,7 +324,7 @@ static void pidff_set_effect_report(struct pidff_device *pidff, pidff->effect_direction); pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay; - hid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], USB_DIR_OUT); } @@ -354,7 +356,7 @@ static void pidff_set_periodic_report(struct pidff_device *pidff, pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase); pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period; - hid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC], USB_DIR_OUT); } @@ -396,8 +398,8 @@ static void pidff_set_condition_report(struct pidff_device *pidff, effect->u.condition[i].left_saturation); pidff_set(&pidff->set_condition[PID_DEAD_BAND], effect->u.condition[i].deadband); - hid_wait_io(pidff->hid); - hid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION], + usbhid_wait_io(pidff->hid); + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION], USB_DIR_OUT); } } @@ -438,7 +440,7 @@ static void pidff_set_ramp_force_report(struct pidff_device *pidff, effect->u.ramp.start_level); pidff_set_signed(&pidff->set_ramp[PID_RAMP_END], effect->u.ramp.end_level); - hid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP], USB_DIR_OUT); } @@ -463,19 +465,19 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum) int j; pidff->create_new_effect_type->value[0] = efnum; - hid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT], + usbhid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT], USB_DIR_OUT); debug("create_new_effect sent, type: %d", efnum); pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0; pidff->block_load_status->value[0] = 0; - hid_wait_io(pidff->hid); + usbhid_wait_io(pidff->hid); for (j = 0; j < 60; j++) { debug("pid_block_load requested"); - hid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD], + usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD], USB_DIR_IN); - hid_wait_io(pidff->hid); + usbhid_wait_io(pidff->hid); if (pidff->block_load_status->value[0] == pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) { debug("device reported free memory: %d bytes", @@ -511,8 +513,8 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n) pidff->effect_operation[PID_LOOP_COUNT].value[0] = n; } - hid_wait_io(pidff->hid); - hid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION], + usbhid_wait_io(pidff->hid); + usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION], USB_DIR_OUT); } @@ -534,7 +536,7 @@ static int pidff_playback(struct input_dev *dev, int effect_id, int value) static void pidff_erase_pid(struct pidff_device *pidff, int pid_id) { pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id; - hid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE], + usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE], USB_DIR_OUT); } @@ -714,7 +716,7 @@ static void pidff_set_gain(struct input_dev *dev, u16 gain) struct pidff_device *pidff = dev->ff->private; pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain); - hid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], + usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], USB_DIR_OUT); } @@ -739,7 +741,7 @@ static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude) pidff_set(&pidff->set_effect[PID_GAIN], magnitude); pidff->set_effect[PID_START_DELAY].value[0] = 0; - hid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], + usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT], USB_DIR_OUT); } @@ -1163,19 +1165,19 @@ static void pidff_reset(struct pidff_device *pidff) pidff->device_control->value[0] = pidff->control_id[PID_RESET]; /* We reset twice as sometimes hid_wait_io isn't waiting long enough */ - hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); - hid_wait_io(hid); - hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); - hid_wait_io(hid); + usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); + usbhid_wait_io(hid); + usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); + usbhid_wait_io(hid); pidff->device_control->value[0] = pidff->control_id[PID_ENABLE_ACTUATORS]; - hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); - hid_wait_io(hid); + usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT); + usbhid_wait_io(hid); /* pool report is sometimes messed up, refetch it */ - hid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN); - hid_wait_io(hid); + usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN); + usbhid_wait_io(hid); if (pidff->pool[PID_SIMULTANEOUS_MAX].value) { int sim_effects = pidff->pool[PID_SIMULTANEOUS_MAX].value[0]; @@ -1187,9 +1189,9 @@ static void pidff_reset(struct pidff_device *pidff) break; } debug("pid_pool requested again"); - hid_submit_report(hid, pidff->reports[PID_POOL], + usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN); - hid_wait_io(hid); + usbhid_wait_io(hid); } } } @@ -1275,7 +1277,7 @@ int hid_pidff_init(struct hid_device *hid) if (test_bit(FF_GAIN, dev->ffbit)) { pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff); - hid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], + usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN], USB_DIR_OUT); } diff --git a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c index 2d5be4c318ac..ab67331620d0 100644 --- a/drivers/usb/input/hid-tmff.c +++ b/drivers/usb/input/hid-tmff.c @@ -32,7 +32,8 @@ #undef DEBUG #include <linux/usb.h> -#include "hid.h" +#include <linux/hid.h> +#include "usbhid.h" /* Usages for thrustmaster devices I know about */ #define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb) @@ -70,7 +71,7 @@ static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *ef tmff->rumble->value[0] = left; tmff->rumble->value[1] = right; dbg("(left,right)=(%08x, %08x)", left, right); - hid_submit_report(hid, tmff->report, USB_DIR_OUT); + usbhid_submit_report(hid, tmff->report, USB_DIR_OUT); return 0; } diff --git a/drivers/usb/input/hid-zpff.c b/drivers/usb/input/hid-zpff.c index d2ce3214572c..7bd8238ca212 100644 --- a/drivers/usb/input/hid-zpff.c +++ b/drivers/usb/input/hid-zpff.c @@ -27,7 +27,8 @@ #include <linux/input.h> #include <linux/usb.h> -#include "hid.h" +#include <linux/hid.h> +#include "usbhid.h" struct zpff_device { struct hid_report *report; @@ -56,7 +57,7 @@ static int hid_zpff_play(struct input_dev *dev, void *data, zpff->report->field[2]->value[0] = left; zpff->report->field[3]->value[0] = right; debug("running with 0x%02x 0x%02x", left, right); - hid_submit_report(hid, zpff->report, USB_DIR_OUT); + usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); return 0; } @@ -101,7 +102,7 @@ int hid_zpff_init(struct hid_device *hid) zpff->report->field[1]->value[0] = 0x02; zpff->report->field[2]->value[0] = 0x00; zpff->report->field[3]->value[0] = 0x00; - hid_submit_report(hid, zpff->report, USB_DIR_OUT); + usbhid_submit_report(hid, zpff->report, USB_DIR_OUT); printk(KERN_INFO "Force feedback for Zeroplus based devices by " "Anssi Hannula <anssi.hannula@gmail.com>\n"); diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h deleted file mode 100644 index 9b50effef758..000000000000 --- a/drivers/usb/input/hid.h +++ /dev/null @@ -1,537 +0,0 @@ -#ifndef __HID_H -#define __HID_H - -/* - * $Id: hid.h,v 1.24 2001/12/27 10:37:41 vojtech Exp $ - * - * Copyright (c) 1999 Andreas Gal - * Copyright (c) 2000-2001 Vojtech Pavlik - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/list.h> -#include <linux/timer.h> -#include <linux/workqueue.h> - -/* - * USB HID (Human Interface Device) interface class code - */ - -#define USB_INTERFACE_CLASS_HID 3 - -/* - * USB HID interface subclass and protocol codes - */ - -#define USB_INTERFACE_SUBCLASS_BOOT 1 -#define USB_INTERFACE_PROTOCOL_KEYBOARD 1 -#define USB_INTERFACE_PROTOCOL_MOUSE 2 - -/* - * HID class requests - */ - -#define HID_REQ_GET_REPORT 0x01 -#define HID_REQ_GET_IDLE 0x02 -#define HID_REQ_GET_PROTOCOL 0x03 -#define HID_REQ_SET_REPORT 0x09 -#define HID_REQ_SET_IDLE 0x0A -#define HID_REQ_SET_PROTOCOL 0x0B - -/* - * HID class descriptor types - */ - -#define HID_DT_HID (USB_TYPE_CLASS | 0x01) -#define HID_DT_REPORT (USB_TYPE_CLASS | 0x02) -#define HID_DT_PHYSICAL (USB_TYPE_CLASS | 0x03) - -/* - * We parse each description item into this structure. Short items data - * values are expanded to 32-bit signed int, long items contain a pointer - * into the data area. - */ - -struct hid_item { - unsigned format; - __u8 size; - __u8 type; - __u8 tag; - union { - __u8 u8; - __s8 s8; - __u16 u16; - __s16 s16; - __u32 u32; - __s32 s32; - __u8 *longdata; - } data; -}; - -/* - * HID report item format - */ - -#define HID_ITEM_FORMAT_SHORT 0 -#define HID_ITEM_FORMAT_LONG 1 - -/* - * Special tag indicating long items - */ - -#define HID_ITEM_TAG_LONG 15 - -/* - * HID report descriptor item type (prefix bit 2,3) - */ - -#define HID_ITEM_TYPE_MAIN 0 -#define HID_ITEM_TYPE_GLOBAL 1 -#define HID_ITEM_TYPE_LOCAL 2 -#define HID_ITEM_TYPE_RESERVED 3 - -/* - * HID report descriptor main item tags - */ - -#define HID_MAIN_ITEM_TAG_INPUT 8 -#define HID_MAIN_ITEM_TAG_OUTPUT 9 -#define HID_MAIN_ITEM_TAG_FEATURE 11 -#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10 -#define HID_MAIN_ITEM_TAG_END_COLLECTION 12 - -/* - * HID report descriptor main item contents - */ - -#define HID_MAIN_ITEM_CONSTANT 0x001 -#define HID_MAIN_ITEM_VARIABLE 0x002 -#define HID_MAIN_ITEM_RELATIVE 0x004 -#define HID_MAIN_ITEM_WRAP 0x008 -#define HID_MAIN_ITEM_NONLINEAR 0x010 -#define HID_MAIN_ITEM_NO_PREFERRED 0x020 -#define HID_MAIN_ITEM_NULL_STATE 0x040 -#define HID_MAIN_ITEM_VOLATILE 0x080 -#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100 - -/* - * HID report descriptor collection item types - */ - -#define HID_COLLECTION_PHYSICAL 0 -#define HID_COLLECTION_APPLICATION 1 -#define HID_COLLECTION_LOGICAL 2 - -/* - * HID report descriptor global item tags - */ - -#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0 -#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1 -#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2 -#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3 -#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4 -#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5 -#define HID_GLOBAL_ITEM_TAG_UNIT 6 -#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7 -#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8 -#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9 -#define HID_GLOBAL_ITEM_TAG_PUSH 10 -#define HID_GLOBAL_ITEM_TAG_POP 11 - -/* - * HID report descriptor local item tags - */ - -#define HID_LOCAL_ITEM_TAG_USAGE 0 -#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1 -#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5 -#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7 -#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8 -#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9 -#define HID_LOCAL_ITEM_TAG_DELIMITER 10 - -/* - * HID usage tables - */ - -#define HID_USAGE_PAGE 0xffff0000 - -#define HID_UP_UNDEFINED 0x00000000 -#define HID_UP_GENDESK 0x00010000 -#define HID_UP_SIMULATION 0x00020000 -#define HID_UP_KEYBOARD 0x00070000 -#define HID_UP_LED 0x00080000 -#define HID_UP_BUTTON 0x00090000 -#define HID_UP_ORDINAL 0x000a0000 -#define HID_UP_CONSUMER 0x000c0000 -#define HID_UP_DIGITIZER 0x000d0000 -#define HID_UP_PID 0x000f0000 -#define HID_UP_HPVENDOR 0xff7f0000 -#define HID_UP_MSVENDOR 0xff000000 -#define HID_UP_CUSTOM 0x00ff0000 -#define HID_UP_LOGIVENDOR 0xffbc0000 - -#define HID_USAGE 0x0000ffff - -#define HID_GD_POINTER 0x00010001 -#define HID_GD_MOUSE 0x00010002 -#define HID_GD_JOYSTICK 0x00010004 -#define HID_GD_GAMEPAD 0x00010005 -#define HID_GD_KEYBOARD 0x00010006 -#define HID_GD_KEYPAD 0x00010007 -#define HID_GD_MULTIAXIS 0x00010008 -#define HID_GD_X 0x00010030 -#define HID_GD_Y 0x00010031 -#define HID_GD_Z 0x00010032 -#define HID_GD_RX 0x00010033 -#define HID_GD_RY 0x00010034 -#define HID_GD_RZ 0x00010035 -#define HID_GD_SLIDER 0x00010036 -#define HID_GD_DIAL 0x00010037 -#define HID_GD_WHEEL 0x00010038 -#define HID_GD_HATSWITCH 0x00010039 -#define HID_GD_BUFFER 0x0001003a -#define HID_GD_BYTECOUNT 0x0001003b -#define HID_GD_MOTION 0x0001003c -#define HID_GD_START 0x0001003d -#define HID_GD_SELECT 0x0001003e -#define HID_GD_VX 0x00010040 -#define HID_GD_VY 0x00010041 -#define HID_GD_VZ 0x00010042 -#define HID_GD_VBRX 0x00010043 -#define HID_GD_VBRY 0x00010044 -#define HID_GD_VBRZ 0x00010045 -#define HID_GD_VNO 0x00010046 -#define HID_GD_FEATURE 0x00010047 -#define HID_GD_UP 0x00010090 -#define HID_GD_DOWN 0x00010091 -#define HID_GD_RIGHT 0x00010092 -#define HID_GD_LEFT 0x00010093 - -/* - * HID report types --- Ouch! HID spec says 1 2 3! - */ - -#define HID_INPUT_REPORT 0 -#define HID_OUTPUT_REPORT 1 -#define HID_FEATURE_REPORT 2 - -/* - * HID device quirks. - */ - -#define HID_QUIRK_INVERT 0x00000001 -#define HID_QUIRK_NOTOUCH 0x00000002 -#define HID_QUIRK_IGNORE 0x00000004 -#define HID_QUIRK_NOGET 0x00000008 -#define HID_QUIRK_HIDDEV 0x00000010 -#define HID_QUIRK_BADPAD 0x00000020 -#define HID_QUIRK_MULTI_INPUT 0x00000040 -#define HID_QUIRK_2WHEEL_MOUSE_HACK_7 0x00000080 -#define HID_QUIRK_2WHEEL_MOUSE_HACK_5 0x00000100 -#define HID_QUIRK_2WHEEL_MOUSE_HACK_ON 0x00000200 -#define HID_QUIRK_MIGHTYMOUSE 0x00000400 -#define HID_QUIRK_CYMOTION 0x00000800 -#define HID_QUIRK_POWERBOOK_HAS_FN 0x00001000 -#define HID_QUIRK_POWERBOOK_FN_ON 0x00002000 -#define HID_QUIRK_INVERT_HWHEEL 0x00004000 - -/* - * This is the global environment of the parser. This information is - * persistent for main-items. The global environment can be saved and - * restored with PUSH/POP statements. - */ - -struct hid_global { - unsigned usage_page; - __s32 logical_minimum; - __s32 logical_maximum; - __s32 physical_minimum; - __s32 physical_maximum; - __s32 unit_exponent; - unsigned unit; - unsigned report_id; - unsigned report_size; - unsigned report_count; -}; - -/* - * This is the local environment. It is persistent up the next main-item. - */ - -#define HID_MAX_DESCRIPTOR_SIZE 4096 -#define HID_MAX_USAGES 1024 -#define HID_DEFAULT_NUM_COLLECTIONS 16 - -struct hid_local { - unsigned usage[HID_MAX_USAGES]; /* usage array */ - unsigned collection_index[HID_MAX_USAGES]; /* collection index array */ - unsigned usage_index; - unsigned usage_minimum; - unsigned delimiter_depth; - unsigned delimiter_branch; -}; - -/* - * This is the collection stack. We climb up the stack to determine - * application and function of each field. - */ - -struct hid_collection { - unsigned type; - unsigned usage; - unsigned level; -}; - -struct hid_usage { - unsigned hid; /* hid usage code */ - unsigned collection_index; /* index into collection array */ - /* hidinput data */ - __u16 code; /* input driver code */ - __u8 type; /* input driver type */ - __s8 hat_min; /* hat switch fun */ - __s8 hat_max; /* ditto */ - __s8 hat_dir; /* ditto */ -}; - -struct hid_input; - -struct hid_field { - unsigned physical; /* physical usage for this field */ - unsigned logical; /* logical usage for this field */ - unsigned application; /* application usage for this field */ - struct hid_usage *usage; /* usage table for this function */ - unsigned maxusage; /* maximum usage index */ - unsigned flags; /* main-item flags (i.e. volatile,array,constant) */ - unsigned report_offset; /* bit offset in the report */ - unsigned report_size; /* size of this field in the report */ - unsigned report_count; /* number of this field in the report */ - unsigned report_type; /* (input,output,feature) */ - __s32 *value; /* last known value(s) */ - __s32 logical_minimum; - __s32 logical_maximum; - __s32 physical_minimum; - __s32 physical_maximum; - __s32 unit_exponent; - unsigned unit; - struct hid_report *report; /* associated report */ - unsigned index; /* index into report->field[] */ - /* hidinput data */ - struct hid_input *hidinput; /* associated input structure */ - __u16 dpad; /* dpad input code */ -}; - -#define HID_MAX_FIELDS 64 - -struct hid_report { - struct list_head list; - unsigned id; /* id of this report */ - unsigned type; /* report type */ - struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */ - unsigned maxfield; /* maximum valid field index */ - unsigned size; /* size of the report (bits) */ - struct hid_device *device; /* associated device */ -}; - -struct hid_report_enum { - unsigned numbered; - struct list_head report_list; - struct hid_report *report_id_hash[256]; -}; - -#define HID_REPORT_TYPES 3 - -#define HID_MIN_BUFFER_SIZE 64 /* make sure there is at least a packet size of space */ -#define HID_MAX_BUFFER_SIZE 4096 /* 4kb */ -#define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */ -#define HID_OUTPUT_FIFO_SIZE 64 - -struct hid_control_fifo { - unsigned char dir; - struct hid_report *report; -}; - -#define HID_CLAIMED_INPUT 1 -#define HID_CLAIMED_HIDDEV 2 - -#define HID_CTRL_RUNNING 1 -#define HID_OUT_RUNNING 2 -#define HID_IN_RUNNING 3 -#define HID_RESET_PENDING 4 -#define HID_SUSPENDED 5 - -struct hid_input { - struct list_head list; - struct hid_report *report; - struct input_dev *input; -}; - -struct hid_device { /* device report descriptor */ - __u8 *rdesc; - unsigned rsize; - struct hid_collection *collection; /* List of HID collections */ - unsigned collection_size; /* Number of allocated hid_collections */ - unsigned maxcollection; /* Number of parsed collections */ - unsigned maxapplication; /* Number of applications */ - unsigned version; /* HID version */ - unsigned country; /* HID country */ - struct hid_report_enum report_enum[HID_REPORT_TYPES]; - - struct usb_device *dev; /* USB device */ - struct usb_interface *intf; /* USB interface */ - int ifnum; /* USB interface number */ - - unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ - struct timer_list io_retry; /* Retry timer */ - unsigned long stop_retry; /* Time to give up, in jiffies */ - unsigned int retry_delay; /* Delay length in ms */ - struct work_struct reset_work; /* Task context for resets */ - - unsigned int bufsize; /* URB buffer size */ - - struct urb *urbin; /* Input URB */ - char *inbuf; /* Input buffer */ - dma_addr_t inbuf_dma; /* Input buffer dma */ - spinlock_t inlock; /* Input fifo spinlock */ - - struct urb *urbctrl; /* Control URB */ - struct usb_ctrlrequest *cr; /* Control request struct */ - dma_addr_t cr_dma; /* Control request struct dma */ - struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */ - unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ - char *ctrlbuf; /* Control buffer */ - dma_addr_t ctrlbuf_dma; /* Control buffer dma */ - spinlock_t ctrllock; /* Control fifo spinlock */ - - struct urb *urbout; /* Output URB */ - struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ - unsigned char outhead, outtail; /* Output pipe fifo head & tail */ - char *outbuf; /* Output buffer */ - dma_addr_t outbuf_dma; /* Output buffer dma */ - spinlock_t outlock; /* Output fifo spinlock */ - - unsigned claimed; /* Claimed by hidinput, hiddev? */ - unsigned quirks; /* Various quirks the device can pull on us */ - - struct list_head inputs; /* The list of inputs */ - void *hiddev; /* The hiddev structure */ - int minor; /* Hiddev minor number */ - - wait_queue_head_t wait; /* For sleeping */ - - int open; /* is the device open by anyone? */ - char name[128]; /* Device name */ - char phys[64]; /* Device physical location */ - char uniq[64]; /* Device unique identifier (serial #) */ - -#ifdef CONFIG_USB_HIDINPUT_POWERBOOK - unsigned long pb_pressed_fn[NBITS(KEY_MAX)]; - unsigned long pb_pressed_numlock[NBITS(KEY_MAX)]; -#endif -}; - -#define HID_GLOBAL_STACK_SIZE 4 -#define HID_COLLECTION_STACK_SIZE 4 - -struct hid_parser { - struct hid_global global; - struct hid_global global_stack[HID_GLOBAL_STACK_SIZE]; - unsigned global_stack_ptr; - struct hid_local local; - unsigned collection_stack[HID_COLLECTION_STACK_SIZE]; - unsigned collection_stack_ptr; - struct hid_device *device; -}; - -struct hid_class_descriptor { - __u8 bDescriptorType; - __u16 wDescriptorLength; -} __attribute__ ((packed)); - -struct hid_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u16 bcdHID; - __u8 bCountryCode; - __u8 bNumDescriptors; - - struct hid_class_descriptor desc[1]; -} __attribute__ ((packed)); - -#ifdef DEBUG -#include "hid-debug.h" -#else -#define hid_dump_input(a,b) do { } while (0) -#define hid_dump_device(c) do { } while (0) -#define hid_dump_field(a,b) do { } while (0) -#define resolv_usage(a) do { } while (0) -#define resolv_event(a,b) do { } while (0) -#endif - -#endif - -#ifdef CONFIG_USB_HIDINPUT -/* Applications from HID Usage Tables 4/8/99 Version 1.1 */ -/* We ignore a few input applications that are not widely used */ -#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001)) -extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); -extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report); -extern int hidinput_connect(struct hid_device *); -extern void hidinput_disconnect(struct hid_device *); -#else -#define IS_INPUT_APPLICATION(a) (0) -static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { } -static inline void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { } -static inline int hidinput_connect(struct hid_device *hid) { return -ENODEV; } -static inline void hidinput_disconnect(struct hid_device *hid) { } -#endif - -int hid_open(struct hid_device *); -void hid_close(struct hid_device *); -int hid_set_field(struct hid_field *, unsigned, __s32); -void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir); -void hid_init_reports(struct hid_device *hid); -int hid_wait_io(struct hid_device* hid); - - -#ifdef CONFIG_HID_FF -int hid_ff_init(struct hid_device *hid); - -int hid_lgff_init(struct hid_device *hid); -int hid_tmff_init(struct hid_device *hid); -int hid_zpff_init(struct hid_device *hid); -#ifdef CONFIG_HID_PID -int hid_pidff_init(struct hid_device *hid); -#else -static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; } -#endif - -#else -static inline int hid_ff_init(struct hid_device *hid) { return -1; } -#endif - diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 7dc14d0cacc1..114d6c9f64b1 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c @@ -32,8 +32,9 @@ #include <linux/smp_lock.h> #include <linux/input.h> #include <linux/usb.h> -#include "hid.h" +#include <linux/hid.h> #include <linux/hiddev.h> +#include "usbhid.h" #ifdef CONFIG_USB_DYNAMIC_MINORS #define HIDDEV_MINOR_BASE 0 @@ -196,7 +197,7 @@ void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, hiddev_send_event(hid, &uref); } - +EXPORT_SYMBOL_GPL(hiddev_hid_event); void hiddev_report_event(struct hid_device *hid, struct hid_report *report) { @@ -213,6 +214,7 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report) hiddev_send_event(hid, &uref); } + /* * fasync file op */ @@ -239,7 +241,7 @@ static int hiddev_release(struct inode * inode, struct file * file) if (!--list->hiddev->open) { if (list->hiddev->exist) - hid_close(list->hiddev->hid); + usbhid_close(list->hiddev->hid); else kfree(list->hiddev); } @@ -270,7 +272,7 @@ static int hiddev_open(struct inode *inode, struct file *file) if (!list->hiddev->open++) if (list->hiddev->exist) - hid_open(hiddev_table[i]->hid); + usbhid_open(hiddev_table[i]->hid); return 0; } @@ -382,7 +384,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd struct hiddev_list *list = file->private_data; struct hiddev *hiddev = list->hiddev; struct hid_device *hid = hiddev->hid; - struct usb_device *dev = hid->dev; + struct usb_device *dev = to_usb_device(hid->dev); struct hiddev_collection_info cinfo; struct hiddev_report_info rinfo; struct hiddev_field_info finfo; @@ -391,6 +393,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd struct hiddev_devinfo dinfo; struct hid_report *report; struct hid_field *field; + struct usbhid_device *usbhid = hid->driver_data; void __user *user_arg = (void __user *)arg; int i; @@ -420,7 +423,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd dinfo.bustype = BUS_USB; dinfo.busnum = dev->bus->busnum; dinfo.devnum = dev->devnum; - dinfo.ifnum = hid->ifnum; + dinfo.ifnum = usbhid->ifnum; dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor); dinfo.product = le16_to_cpu(dev->descriptor.idProduct); dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice); @@ -479,7 +482,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd } case HIDIOCINITREPORT: - hid_init_reports(hid); + usbhid_init_reports(hid); return 0; @@ -493,8 +496,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) return -EINVAL; - hid_submit_report(hid, report, USB_DIR_IN); - hid_wait_io(hid); + usbhid_submit_report(hid, report, USB_DIR_IN); + usbhid_wait_io(hid); return 0; @@ -508,8 +511,8 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) return -EINVAL; - hid_submit_report(hid, report, USB_DIR_OUT); - hid_wait_io(hid); + usbhid_submit_report(hid, report, USB_DIR_OUT); + usbhid_wait_io(hid); return 0; @@ -745,6 +748,7 @@ static struct usb_class_driver hiddev_class = { int hiddev_connect(struct hid_device *hid) { struct hiddev *hiddev; + struct usbhid_device *usbhid = hid->driver_data; int i; int retval; @@ -760,7 +764,7 @@ int hiddev_connect(struct hid_device *hid) if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL))) return -1; - retval = usb_register_dev(hid->intf, &hiddev_class); + retval = usb_register_dev(usbhid->intf, &hiddev_class); if (retval) { err("Not able to get a minor for this device."); kfree(hiddev); @@ -772,10 +776,10 @@ int hiddev_connect(struct hid_device *hid) hiddev->hid = hid; hiddev->exist = 1; - hid->minor = hid->intf->minor; + hid->minor = usbhid->intf->minor; hid->hiddev = hiddev; - hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev; + hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev; return 0; } @@ -788,14 +792,15 @@ static struct usb_class_driver hiddev_class; void hiddev_disconnect(struct hid_device *hid) { struct hiddev *hiddev = hid->hiddev; + struct usbhid_device *usbhid = hid->driver_data; hiddev->exist = 0; hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL; - usb_deregister_dev(hiddev->hid->intf, &hiddev_class); + usb_deregister_dev(usbhid->intf, &hiddev_class); if (hiddev->open) { - hid_close(hiddev->hid); + usbhid_close(hiddev->hid); wake_up_interruptible(&hiddev->wait); } else { kfree(hiddev); diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c index 50aa8108a50b..98bd323369c7 100644 --- a/drivers/usb/input/keyspan_remote.c +++ b/drivers/usb/input/keyspan_remote.c @@ -456,7 +456,7 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic remote->in_endpoint = endpoint; remote->toggle = -1; /* Set to -1 so we will always not match the toggle from the first remote message. */ - remote->in_buffer = usb_buffer_alloc(udev, RECV_SIZE, SLAB_ATOMIC, &remote->in_dma); + remote->in_buffer = usb_buffer_alloc(udev, RECV_SIZE, GFP_ATOMIC, &remote->in_dma); if (!remote->in_buffer) { retval = -ENOMEM; goto fail1; diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c index 79a85d46cb13..92c4e07da4c8 100644 --- a/drivers/usb/input/mtouchusb.c +++ b/drivers/usb/input/mtouchusb.c @@ -164,7 +164,7 @@ static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *m dbg("%s - called", __FUNCTION__); mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE, - SLAB_ATOMIC, &mtouch->data_dma); + GFP_ATOMIC, &mtouch->data_dma); if (!mtouch->data) return -1; diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c index 0bf91778c40d..fea97e5437f8 100644 --- a/drivers/usb/input/powermate.c +++ b/drivers/usb/input/powermate.c @@ -277,12 +277,12 @@ static int powermate_input_event(struct input_dev *dev, unsigned int type, unsig static int powermate_alloc_buffers(struct usb_device *udev, struct powermate_device *pm) { pm->data = usb_buffer_alloc(udev, POWERMATE_PAYLOAD_SIZE_MAX, - SLAB_ATOMIC, &pm->data_dma); + GFP_ATOMIC, &pm->data_dma); if (!pm->data) return -1; pm->configcr = usb_buffer_alloc(udev, sizeof(*(pm->configcr)), - SLAB_ATOMIC, &pm->configcr_dma); + GFP_ATOMIC, &pm->configcr_dma); if (!pm->configcr) return -1; diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c index 05c0d1ca39ab..2a314b065922 100644 --- a/drivers/usb/input/touchkitusb.c +++ b/drivers/usb/input/touchkitusb.c @@ -248,7 +248,7 @@ static int touchkit_alloc_buffers(struct usb_device *udev, struct touchkit_usb *touchkit) { touchkit->data = usb_buffer_alloc(udev, TOUCHKIT_REPORT_DATA_SIZE, - SLAB_ATOMIC, &touchkit->data_dma); + GFP_ATOMIC, &touchkit->data_dma); if (!touchkit->data) return -1; diff --git a/drivers/usb/input/usbhid.h b/drivers/usb/input/usbhid.h new file mode 100644 index 000000000000..830107e5251f --- /dev/null +++ b/drivers/usb/input/usbhid.h @@ -0,0 +1,84 @@ +#ifndef __USBHID_H +#define __USBHID_H + +/* + * Copyright (c) 1999 Andreas Gal + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2006 Jiri Kosina + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/list.h> +#include <linux/timer.h> +#include <linux/workqueue.h> +#include <linux/input.h> + +/* API provided by hid-core.c for USB HID drivers */ +int usbhid_wait_io(struct hid_device* hid); +void usbhid_close(struct hid_device *hid); +int usbhid_open(struct hid_device *hid); +void usbhid_init_reports(struct hid_device *hid); +void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir); + +/* + * USB-specific HID struct, to be pointed to + * from struct hid_device->driver_data + */ + +struct usbhid_device { + struct hid_device *hid; /* pointer to corresponding HID dev */ + + struct usb_interface *intf; /* USB interface */ + int ifnum; /* USB interface number */ + + unsigned int bufsize; /* URB buffer size */ + + struct urb *urbin; /* Input URB */ + char *inbuf; /* Input buffer */ + dma_addr_t inbuf_dma; /* Input buffer dma */ + spinlock_t inlock; /* Input fifo spinlock */ + + struct urb *urbctrl; /* Control URB */ + struct usb_ctrlrequest *cr; /* Control request struct */ + dma_addr_t cr_dma; /* Control request struct dma */ + struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */ + unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ + char *ctrlbuf; /* Control buffer */ + dma_addr_t ctrlbuf_dma; /* Control buffer dma */ + spinlock_t ctrllock; /* Control fifo spinlock */ + + struct urb *urbout; /* Output URB */ + struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ + unsigned char outhead, outtail; /* Output pipe fifo head & tail */ + char *outbuf; /* Output buffer */ + dma_addr_t outbuf_dma; /* Output buffer dma */ + spinlock_t outlock; /* Output fifo spinlock */ + + unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ + struct timer_list io_retry; /* Retry timer */ + unsigned long stop_retry; /* Time to give up, in jiffies */ + unsigned int retry_delay; /* Delay length in ms */ + struct work_struct reset_work; /* Task context for resets */ + +}; + +#endif + diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c index c73285cf8558..8505824848f6 100644 --- a/drivers/usb/input/usbkbd.c +++ b/drivers/usb/input/usbkbd.c @@ -122,7 +122,7 @@ static void usb_kbd_irq(struct urb *urb) memcpy(kbd->old, kbd->new, 8); resubmit: - i = usb_submit_urb (urb, SLAB_ATOMIC); + i = usb_submit_urb (urb, GFP_ATOMIC); if (i) err ("can't resubmit intr, %s-%s/input0, status %d", kbd->usbdev->bus->bus_name, @@ -196,11 +196,11 @@ static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd) return -1; if (!(kbd->led = usb_alloc_urb(0, GFP_KERNEL))) return -1; - if (!(kbd->new = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &kbd->new_dma))) + if (!(kbd->new = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &kbd->new_dma))) return -1; - if (!(kbd->cr = usb_buffer_alloc(dev, sizeof(struct usb_ctrlrequest), SLAB_ATOMIC, &kbd->cr_dma))) + if (!(kbd->cr = usb_buffer_alloc(dev, sizeof(struct usb_ctrlrequest), GFP_ATOMIC, &kbd->cr_dma))) return -1; - if (!(kbd->leds = usb_buffer_alloc(dev, 1, SLAB_ATOMIC, &kbd->leds_dma))) + if (!(kbd->leds = usb_buffer_alloc(dev, 1, GFP_ATOMIC, &kbd->leds_dma))) return -1; return 0; @@ -208,10 +208,8 @@ static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd) static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd) { - if (kbd->irq) - usb_free_urb(kbd->irq); - if (kbd->led) - usb_free_urb(kbd->led); + usb_free_urb(kbd->irq); + usb_free_urb(kbd->led); if (kbd->new) usb_buffer_free(dev, 8, kbd->new, kbd->new_dma); if (kbd->cr) @@ -236,9 +234,7 @@ static int usb_kbd_probe(struct usb_interface *iface, return -ENODEV; endpoint = &interface->endpoint[0].desc; - if (!(endpoint->bEndpointAddress & USB_DIR_IN)) - return -ENODEV; - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) + if (!usb_endpoint_is_int_in(endpoint)) return -ENODEV; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c index cbbbea332ed7..64a33e420cfb 100644 --- a/drivers/usb/input/usbmouse.c +++ b/drivers/usb/input/usbmouse.c @@ -86,7 +86,7 @@ static void usb_mouse_irq(struct urb *urb) input_sync(dev); resubmit: - status = usb_submit_urb (urb, SLAB_ATOMIC); + status = usb_submit_urb (urb, GFP_ATOMIC); if (status) err ("can't resubmit intr, %s-%s/input0, status %d", mouse->usbdev->bus->bus_name, @@ -126,9 +126,7 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i return -ENODEV; endpoint = &interface->endpoint[0].desc; - if (!(endpoint->bEndpointAddress & USB_DIR_IN)) - return -ENODEV; - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) + if (!usb_endpoint_is_int_in(endpoint)) return -ENODEV; pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); @@ -139,7 +137,7 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i if (!mouse || !input_dev) goto fail1; - mouse->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &mouse->data_dma); + mouse->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse->data_dma); if (!mouse->data) goto fail1; diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c index f26c1cd1129f..7f3c57da9bc0 100644 --- a/drivers/usb/input/usbtouchscreen.c +++ b/drivers/usb/input/usbtouchscreen.c @@ -8,6 +8,7 @@ * - PanJit TouchSet * - eTurboTouch * - Gunze AHL61 + * - DMC TSC-10/25 * * Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch> * Copyright (C) by Todd E. Johnson (mtouchusb.c) @@ -30,6 +31,8 @@ * - ITM parts are from itmtouch.c * - 3M parts are from mtouchusb.c * - PanJit parts are from an unmerged driver by Lanslott Gish + * - DMC TSC 10/25 are from Holger Schurig, with ideas from an unmerged + * driver from Marius Vollmer * *****************************************************************************/ @@ -44,7 +47,7 @@ #include <linux/usb/input.h> -#define DRIVER_VERSION "v0.4" +#define DRIVER_VERSION "v0.5" #define DRIVER_AUTHOR "Daniel Ritz <daniel.ritz@gmx.ch>" #define DRIVER_DESC "USB Touchscreen Driver" @@ -103,6 +106,7 @@ enum { DEVTYPE_ITM, DEVTYPE_ETURBO, DEVTYPE_GUNZE, + DEVTYPE_DMC_TSC10, }; static struct usb_device_id usbtouch_devices[] = { @@ -139,6 +143,10 @@ static struct usb_device_id usbtouch_devices[] = { {USB_DEVICE(0x0637, 0x0001), .driver_info = DEVTYPE_GUNZE}, #endif +#ifdef CONFIG_USB_TOUCHSCREEN_DMC_TSC10 + {USB_DEVICE(0x0afa, 0x03e8), .driver_info = DEVTYPE_DMC_TSC10}, +#endif + {} }; @@ -256,10 +264,10 @@ static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *pr { *x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F); *y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F); - *press = ((pkt[2] & 0x1F) << 7) | (pkt[5] & 0x7F); + *press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F); *touch = ~pkt[7] & 0x20; - return 1; + return *touch; } #endif @@ -313,6 +321,80 @@ static int gunze_read_data(unsigned char *pkt, int *x, int *y, int *touch, int * #endif /***************************************************************************** + * DMC TSC-10/25 Part + * + * Documentation about the controller and it's protocol can be found at + * http://www.dmccoltd.com/files/controler/tsc10usb_pi_e.pdf + * http://www.dmccoltd.com/files/controler/tsc25_usb_e.pdf + */ +#ifdef CONFIG_USB_TOUCHSCREEN_DMC_TSC10 + +/* supported data rates. currently using 130 */ +#define TSC10_RATE_POINT 0x50 +#define TSC10_RATE_30 0x40 +#define TSC10_RATE_50 0x41 +#define TSC10_RATE_80 0x42 +#define TSC10_RATE_100 0x43 +#define TSC10_RATE_130 0x44 +#define TSC10_RATE_150 0x45 + +/* commands */ +#define TSC10_CMD_RESET 0x55 +#define TSC10_CMD_RATE 0x05 +#define TSC10_CMD_DATA1 0x01 + +static int dmc_tsc10_init(struct usbtouch_usb *usbtouch) +{ + struct usb_device *dev = usbtouch->udev; + int ret; + unsigned char buf[2]; + + /* reset */ + buf[0] = buf[1] = 0xFF; + ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0), + TSC10_CMD_RESET, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, 0, buf, 2, USB_CTRL_SET_TIMEOUT); + if (ret < 0) + return ret; + if (buf[0] != 0x06 || buf[1] != 0x00) + return -ENODEV; + + /* set coordinate output rate */ + buf[0] = buf[1] = 0xFF; + ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0), + TSC10_CMD_RATE, + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT); + if (ret < 0) + return ret; + if (buf[0] != 0x06 || buf[1] != 0x00) + return -ENODEV; + + /* start sending data */ + ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0), + TSC10_CMD_DATA1, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT); + if (ret < 0) + return ret; + + return 0; +} + + +static int dmc_tsc10_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press) +{ + *x = ((pkt[2] & 0x03) << 8) | pkt[1]; + *y = ((pkt[4] & 0x03) << 8) | pkt[3]; + *touch = pkt[0] & 0x01; + + return 1; +} +#endif + + +/***************************************************************************** * the different device descriptors */ static struct usbtouch_device_info usbtouch_dev_info[] = { @@ -389,6 +471,18 @@ static struct usbtouch_device_info usbtouch_dev_info[] = { .read_data = gunze_read_data, }, #endif + +#ifdef CONFIG_USB_TOUCHSCREEN_DMC_TSC10 + [DEVTYPE_DMC_TSC10] = { + .min_xc = 0x0, + .max_xc = 0x03ff, + .min_yc = 0x0, + .max_yc = 0x03ff, + .rept_size = 5, + .init = dmc_tsc10_init, + .read_data = dmc_tsc10_read_data, + }, +#endif }; @@ -586,7 +680,7 @@ static int usbtouch_probe(struct usb_interface *intf, type->process_pkt = usbtouch_process_pkt; usbtouch->data = usb_buffer_alloc(udev, type->rept_size, - SLAB_KERNEL, &usbtouch->data_dma); + GFP_KERNEL, &usbtouch->data_dma); if (!usbtouch->data) goto out_free; @@ -640,7 +734,7 @@ static int usbtouch_probe(struct usb_interface *intf, type->max_press, 0, 0); usb_fill_int_urb(usbtouch->irq, usbtouch->udev, - usb_rcvintpipe(usbtouch->udev, 0x81), + usb_rcvintpipe(usbtouch->udev, endpoint->bEndpointAddress), usbtouch->data, type->rept_size, usbtouch_irq, usbtouch, endpoint->bInterval); diff --git a/drivers/usb/input/wacom.h b/drivers/usb/input/wacom.h index 7b3840e378a8..d85abfc5ab58 100644 --- a/drivers/usb/input/wacom.h +++ b/drivers/usb/input/wacom.h @@ -63,6 +63,7 @@ * v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c, * - where wacom_sys.c deals with system specific code, * - and wacom_wac.c deals with Wacom specific code + * - Support Intuos3 4x6 */ /* @@ -109,7 +110,6 @@ struct wacom_combo { }; extern int wacom_wac_irq(struct wacom_wac * wacom_wac, void * wcombo); -extern void wacom_sys_irq(struct urb *urb); extern void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data); extern void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data); extern void wacom_report_key(void *wcombo, unsigned int key_type, int key_data); @@ -118,6 +118,7 @@ extern void wacom_input_sync(void *wcombo); extern void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac); +extern void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac); extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac); diff --git a/drivers/usb/input/wacom_sys.c b/drivers/usb/input/wacom_sys.c index d233c37bd533..e7cc20ab8155 100644 --- a/drivers/usb/input/wacom_sys.c +++ b/drivers/usb/input/wacom_sys.c @@ -42,7 +42,7 @@ static struct input_dev * get_input_dev(struct wacom_combo *wcombo) return wcombo->wacom->dev; } -void wacom_sys_irq(struct urb *urb) +static void wacom_sys_irq(struct urb *urb) { struct wacom *wacom = urb->context; struct wacom_combo wcombo; @@ -110,7 +110,7 @@ __u16 wacom_be16_to_cpu(unsigned char *data) __u16 wacom_le16_to_cpu(unsigned char *data) { __u16 value; - value = be16_to_cpu(*(__be16 *) data); + value = le16_to_cpu(*(__le16 *) data); return value; } @@ -143,7 +143,7 @@ void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac) input_dev->evbit[0] |= BIT(EV_MSC); input_dev->mscbit[0] |= BIT(MSC_SERIAL); input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); - input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); + input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_4); } void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac) @@ -155,11 +155,16 @@ void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac) input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0); } -void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac) +void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER); - input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); + input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3); input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0); +} + +void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac) +{ + input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7); input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0); } @@ -218,8 +223,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i strlcat(wacom->phys, "/input0", sizeof(wacom->phys)); wacom_wac->features = get_wacom_feature(id); - if (wacom_wac->features->pktlen > 10) - BUG(); + BUG_ON(wacom_wac->features->pktlen > 10); input_dev->name = wacom_wac->features->name; wacom->wacom_wac = wacom_wac; @@ -244,7 +248,7 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i usb_fill_int_urb(wacom->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress), wacom_wac->data, wacom_wac->features->pktlen, - wacom_wac->features->irq, wacom, endpoint->bInterval); + wacom_sys_irq, wacom, endpoint->bInterval); wacom->irq->transfer_dma = wacom->data_dma; wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; @@ -278,8 +282,8 @@ static void wacom_disconnect(struct usb_interface *intf) input_unregister_device(wacom->dev); usb_free_urb(wacom->irq); usb_buffer_free(interface_to_usbdev(intf), 10, wacom->wacom_wac->data, wacom->data_dma); - kfree(wacom); kfree(wacom->wacom_wac); + kfree(wacom); } } diff --git a/drivers/usb/input/wacom_wac.c b/drivers/usb/input/wacom_wac.c index aa31d22d4f05..92726fe89379 100644 --- a/drivers/usb/input/wacom_wac.c +++ b/drivers/usb/input/wacom_wac.c @@ -191,9 +191,9 @@ static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01); wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02); if (wacom->features->type == WACOM_G4) - wacom_report_abs(wcombo, ABS_DISTANCE, data[6]); + wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f); else - wacom_report_abs(wcombo, ABS_DISTANCE, data[7]); + wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f); break; } } @@ -303,8 +303,9 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) wacom->tool[idx] = BTN_TOOL_PEN; } /* only large I3 support Lens Cursor */ - if(!((wacom->tool[idx] == BTN_TOOL_LENS) && - (wacom->features->type == INTUOS3))) { + if(!((wacom->tool[idx] == BTN_TOOL_LENS) + && ((wacom->features->type == INTUOS3) + || (wacom->features->type == INTUOS3S)))) { wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */ wacom_report_key(wcombo, wacom->tool[idx], 1); wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); @@ -315,10 +316,14 @@ static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo) /* Exit report */ if ((data[1] & 0xfe) == 0x80) { - wacom_report_key(wcombo, wacom->tool[idx], 0); - wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ - wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); - return 2; + if(!((wacom->tool[idx] == BTN_TOOL_LENS) + && ((wacom->features->type == INTUOS3) + || (wacom->features->type == INTUOS3S)))) { + wacom_report_key(wcombo, wacom->tool[idx], 0); + wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */ + wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]); + return 2; + } } return 0; } @@ -382,7 +387,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]); wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]); - if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) | data[2]) + if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) | + data[2] | (data[3] & 0x1f) | data[4]) wacom_report_key(wcombo, wacom->tool[1], 1); else wacom_report_key(wcombo, wacom->tool[1], 0); @@ -432,7 +438,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) ((t - 1) / 2) : -t / 2); } - } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3) { + } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3S) { /* 4D mouse packet */ wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01); wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02); @@ -452,12 +458,12 @@ static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo) - ((data[8] & 0x02) >> 1)); /* I3 2D mouse side buttons */ - if (wacom->features->type == INTUOS3) { + if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) { wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x40); wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x20); } - } else if (wacom->features->type < INTUOS3) { + } else if (wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L) { /* Lens cursor packets */ wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01); wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02); @@ -490,6 +496,7 @@ int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo) return (wacom_ptu_irq(wacom_wac, wcombo)); break; case INTUOS: + case INTUOS3S: case INTUOS3: case INTUOS3L: case CINTIQ: @@ -515,6 +522,8 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w case CINTIQ: input_dev_i3(input_dev, wacom_wac); /* fall through */ + case INTUOS3S: + input_dev_i3s(input_dev, wacom_wac); case INTUOS: input_dev_i(input_dev, wacom_wac); break; @@ -530,49 +539,50 @@ void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_w } static struct wacom_features wacom_features[] = { - { "Wacom Penpartner", 7, 5040, 3780, 255, 32, PENPARTNER, wacom_sys_irq }, - { "Wacom Graphire", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Graphire3", 8, 10208, 7424, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 32, WACOM_G4, wacom_sys_irq }, - { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 32, WACOM_G4, wacom_sys_irq }, - { "Wacom Volito", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom PenStation2", 8, 3250, 2320, 255, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom PenPartner2", 8, 3250, 2320, 255, 32, GRAPHIRE, wacom_sys_irq }, - { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_sys_irq}, - { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_sys_irq}, - { "Wacom PL400", 8, 5408, 4056, 255, 32, PL, wacom_sys_irq }, - { "Wacom PL500", 8, 6144, 4608, 255, 32, PL, wacom_sys_irq }, - { "Wacom PL600", 8, 6126, 4604, 255, 32, PL, wacom_sys_irq }, - { "Wacom PL600SX", 8, 6260, 5016, 255, 32, PL, wacom_sys_irq }, - { "Wacom PL550", 8, 6144, 4608, 511, 32, PL, wacom_sys_irq }, - { "Wacom PL800", 8, 7220, 5780, 511, 32, PL, wacom_sys_irq }, - { "Wacom PL700", 8, 6758, 5406, 511, 32, PL, wacom_sys_irq }, - { "Wacom PL510", 8, 6282, 4762, 511, 32, PL, wacom_sys_irq }, - { "Wacom DTU710", 8, 34080, 27660, 511, 32, PL, wacom_sys_irq }, - { "Wacom DTF521", 8, 6282, 4762, 511, 32, PL, wacom_sys_irq }, - { "Wacom DTF720", 8, 6858, 5506, 511, 32, PL, wacom_sys_irq }, - { "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, PTU, wacom_sys_irq }, - { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_sys_irq }, - { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 15, INTUOS3, wacom_sys_irq }, - { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, INTUOS3, wacom_sys_irq }, - { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, INTUOS3, wacom_sys_irq }, - { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 15, INTUOS3L, wacom_sys_irq }, - { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 15, INTUOS3L, wacom_sys_irq }, - { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 15, INTUOS3, wacom_sys_irq }, - { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 15, CINTIQ, wacom_sys_irq }, - { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_sys_irq }, + { "Wacom Penpartner", 7, 5040, 3780, 255, 0, PENPARTNER }, + { "Wacom Graphire", 8, 10206, 7422, 511, 63, GRAPHIRE }, + { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 63, GRAPHIRE }, + { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 63, GRAPHIRE }, + { "Wacom Graphire3", 8, 10208, 7424, 511, 63, GRAPHIRE }, + { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 63, GRAPHIRE }, + { "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 63, WACOM_G4 }, + { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 63, WACOM_G4 }, + { "Wacom Volito", 8, 5104, 3712, 511, 0, GRAPHIRE }, + { "Wacom PenStation2", 8, 3250, 2320, 255, 0, GRAPHIRE }, + { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 0, GRAPHIRE }, + { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 0, GRAPHIRE }, + { "Wacom PenPartner2", 8, 3250, 2320, 255, 0, GRAPHIRE }, + { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 63, INTUOS }, + { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, + { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 63, INTUOS }, + { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 63, INTUOS }, + { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 63, INTUOS }, + { "Wacom PL400", 8, 5408, 4056, 255, 0, PL }, + { "Wacom PL500", 8, 6144, 4608, 255, 0, PL }, + { "Wacom PL600", 8, 6126, 4604, 255, 0, PL }, + { "Wacom PL600SX", 8, 6260, 5016, 255, 0, PL }, + { "Wacom PL550", 8, 6144, 4608, 511, 0, PL }, + { "Wacom PL800", 8, 7220, 5780, 511, 0, PL }, + { "Wacom PL700", 8, 6758, 5406, 511, 0, PL }, + { "Wacom PL510", 8, 6282, 4762, 511, 0, PL }, + { "Wacom DTU710", 8, 34080, 27660, 511, 0, PL }, + { "Wacom DTF521", 8, 6282, 4762, 511, 0, PL }, + { "Wacom DTF720", 8, 6858, 5506, 511, 0, PL }, + { "Wacom Cintiq Partner",8, 20480, 15360, 511, 0, PTU }, + { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 63, INTUOS }, + { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, + { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 63, INTUOS }, + { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 63, INTUOS }, + { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 63, INTUOS }, + { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 63, INTUOS3S }, + { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 63, INTUOS3 }, + { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 63, INTUOS3 }, + { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 63, INTUOS3L }, + { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L }, + { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 }, + { "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 15, INTUOS3S }, + { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ }, + { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS }, { } }; @@ -618,6 +628,7 @@ static struct usb_device_id wacom_ids[] = { { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) }, + { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) }, { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) }, { } diff --git a/drivers/usb/input/wacom_wac.h b/drivers/usb/input/wacom_wac.h index ceae7bf59d9f..a1d9ce007970 100644 --- a/drivers/usb/input/wacom_wac.h +++ b/drivers/usb/input/wacom_wac.h @@ -20,6 +20,7 @@ enum { PTU, PL, INTUOS, + INTUOS3S, INTUOS3, INTUOS3L, CINTIQ, @@ -34,7 +35,6 @@ struct wacom_features { int pressure_max; int distance_max; int type; - usb_complete_t irq; }; struct wacom_wac { diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c index cebb6c463bfb..e4bc76ebc835 100644 --- a/drivers/usb/input/xpad.c +++ b/drivers/usb/input/xpad.c @@ -1,8 +1,13 @@ /* - * X-Box gamepad - v0.0.5 + * X-Box gamepad - v0.0.6 * * Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de> - * + * 2004 Oliver Schwartz <Oliver.Schwartz@gmx.de>, + * Steven Toth <steve@toth.demon.co.uk>, + * Franz Lehner <franz@caos.at>, + * Ivan Hawkes <blackhawk@ivanhawkes.com> + * 2005 Dominic Cerquetti <binary1230@yahoo.com> + * 2006 Adam Buchbinder <adam.buchbinder@gmail.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -28,11 +33,13 @@ * - ITO Takayuki for providing essential xpad information on his website * - Vojtech Pavlik - iforce driver / input subsystem * - Greg Kroah-Hartman - usb-skeleton driver + * - XBOX Linux project - extra USB id's * * TODO: - * - fine tune axes + * - fine tune axes (especially trigger axes) * - fix "analog" buttons (reported as digital now) * - get rumble working + * - need USB IDs for other dance pads * * History: * @@ -52,30 +59,79 @@ * - fixed d-pad to axes mapping * * 2002-07-17 - 0.0.5 : simplified d-pad handling + * + * 2004-10-02 - 0.0.6 : DDR pad support + * - borrowed from the XBOX linux kernel + * - USB id's for commonly used dance pads are present + * - dance pads will map D-PAD to buttons, not axes + * - pass the module paramater 'dpad_to_buttons' to force + * the D-PAD to map to buttons if your pad is not detected */ #include <linux/kernel.h> #include <linux/init.h> #include <linux/slab.h> +#include <linux/stat.h> #include <linux/module.h> +#include <linux/moduleparam.h> #include <linux/smp_lock.h> #include <linux/usb/input.h> -#define DRIVER_VERSION "v0.0.5" +#define DRIVER_VERSION "v0.0.6" #define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>" #define DRIVER_DESC "X-Box pad driver" #define XPAD_PKT_LEN 32 +/* xbox d-pads should map to buttons, as is required for DDR pads + but we map them to axes when possible to simplify things */ +#define MAP_DPAD_TO_BUTTONS 0 +#define MAP_DPAD_TO_AXES 1 +#define MAP_DPAD_UNKNOWN -1 + +static int dpad_to_buttons; +module_param(dpad_to_buttons, bool, S_IRUGO); +MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads"); + static const struct xpad_device { u16 idVendor; u16 idProduct; char *name; + u8 dpad_mapping; } xpad_device[] = { - { 0x045e, 0x0202, "Microsoft X-Box pad (US)" }, - { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)" }, - { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)" }, - { 0x0000, 0x0000, "X-Box pad" } + { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES }, + { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES }, + { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES }, + { 0x045e, 0x0287, "Microsoft Xbox Controller S", MAP_DPAD_TO_AXES }, + { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS }, + { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", MAP_DPAD_TO_AXES }, + { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", MAP_DPAD_TO_AXES }, + { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", MAP_DPAD_TO_AXES }, + { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", MAP_DPAD_TO_AXES }, + { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES }, + { 0x0738, 0x4516, "Mad Catz Control Pad", MAP_DPAD_TO_AXES }, + { 0x0738, 0x4522, "Mad Catz LumiCON", MAP_DPAD_TO_AXES }, + { 0x0738, 0x4526, "Mad Catz Control Pad Pro", MAP_DPAD_TO_AXES }, + { 0x0738, 0x4536, "Mad Catz MicroCON", MAP_DPAD_TO_AXES }, + { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS }, + { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", MAP_DPAD_TO_AXES }, + { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS }, + { 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES }, + { 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES }, + { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES }, + { 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES }, + { 0x0e4c, 0x2390, "Radica Games Jtech Controller", MAP_DPAD_TO_AXES}, + { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", MAP_DPAD_TO_AXES }, + { 0x0e6f, 0x0005, "Eclipse wireless Controller", MAP_DPAD_TO_AXES }, + { 0x0e6f, 0x0006, "Edge wireless Controller", MAP_DPAD_TO_AXES }, + { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", MAP_DPAD_TO_AXES }, + { 0x0f30, 0x0202, "Joytech Advanced Controller", MAP_DPAD_TO_AXES }, + { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", MAP_DPAD_TO_AXES }, + { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", MAP_DPAD_TO_AXES }, + { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS }, + { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS }, + { 0xffff, 0xffff, "Chinese-made Xbox Controller", MAP_DPAD_TO_AXES }, + { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN } }; static const signed short xpad_btn[] = { @@ -84,11 +140,23 @@ static const signed short xpad_btn[] = { -1 /* terminating entry */ }; +/* only used if MAP_DPAD_TO_BUTTONS */ +static const signed short xpad_btn_pad[] = { + BTN_LEFT, BTN_RIGHT, /* d-pad left, right */ + BTN_0, BTN_1, /* d-pad up, down (XXX names??) */ + -1 /* terminating entry */ +}; + 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 */ - ABS_HAT0X, ABS_HAT0Y, /* digital pad */ + -1 /* terminating entry */ +}; + +/* only used if MAP_DPAD_TO_AXES */ +static const signed short xpad_abs_pad[] = { + ABS_HAT0X, ABS_HAT0Y, /* d-pad axes */ -1 /* terminating entry */ }; @@ -100,14 +168,16 @@ static struct usb_device_id xpad_table [] = { MODULE_DEVICE_TABLE (usb, xpad_table); struct usb_xpad { - struct input_dev *dev; /* input device interface */ - struct usb_device *udev; /* usb device */ + struct input_dev *dev; /* input device interface */ + struct usb_device *udev; /* usb device */ - struct urb *irq_in; /* urb for interrupt in report */ - unsigned char *idata; /* input data */ + struct urb *irq_in; /* urb for interrupt in report */ + unsigned char *idata; /* input data */ dma_addr_t idata_dma; - char phys[65]; /* physical device path */ + char phys[65]; /* physical device path */ + + int dpad_mapping; /* map d-pad to buttons or to axes */ }; /* @@ -137,14 +207,21 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d input_report_abs(dev, ABS_RZ, data[11]); /* digital pad */ - input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); - input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01)); + if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) { + input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04)); + input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01)); + } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ { + input_report_key(dev, BTN_LEFT, data[2] & 0x04); + input_report_key(dev, BTN_RIGHT, data[2] & 0x08); + input_report_key(dev, BTN_0, data[2] & 0x01); // up + input_report_key(dev, BTN_1, data[2] & 0x02); // down + } /* start/back buttons and stick press left/right */ - input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4); - input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5); - input_report_key(dev, BTN_THUMBL, (data[2] & 0x40) >> 6); - input_report_key(dev, BTN_THUMBR, data[2] >> 7); + input_report_key(dev, BTN_START, data[2] & 0x10); + input_report_key(dev, BTN_BACK, data[2] & 0x20); + input_report_key(dev, BTN_THUMBL, data[2] & 0x40); + input_report_key(dev, BTN_THUMBR, data[2] & 0x80); /* "analog" buttons A, B, X, Y */ input_report_key(dev, BTN_A, data[4]); @@ -206,6 +283,28 @@ static void xpad_close (struct input_dev *dev) usb_kill_urb(xpad->irq_in); } +static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs) +{ + set_bit(abs, input_dev->absbit); + + switch (abs) { + case ABS_X: + case ABS_Y: + case ABS_RX: + case ABS_RY: /* the two sticks */ + input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128); + break; + case ABS_Z: + case ABS_RZ: /* the triggers */ + input_set_abs_params(input_dev, abs, 0, 255, 0, 0); + break; + case ABS_HAT0X: + case ABS_HAT0Y: /* the d-pad (only if MAP_DPAD_TO_AXES) */ + input_set_abs_params(input_dev, abs, -1, 1, 0, 0); + break; + } +} + static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev (intf); @@ -226,7 +325,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id goto fail1; xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN, - SLAB_ATOMIC, &xpad->idata_dma); + GFP_ATOMIC, &xpad->idata_dma); if (!xpad->idata) goto fail1; @@ -235,6 +334,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id goto fail2; xpad->udev = udev; + xpad->dpad_mapping = xpad_device[i].dpad_mapping; + if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN) + xpad->dpad_mapping = dpad_to_buttons; xpad->dev = input_dev; usb_make_path(udev, xpad->phys, sizeof(xpad->phys)); strlcat(xpad->phys, "/input0", sizeof(xpad->phys)); @@ -249,32 +351,19 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS); + /* set up buttons */ for (i = 0; xpad_btn[i] >= 0; i++) set_bit(xpad_btn[i], input_dev->keybit); + if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS) + for (i = 0; xpad_btn_pad[i] >= 0; i++) + set_bit(xpad_btn_pad[i], input_dev->keybit); - for (i = 0; xpad_abs[i] >= 0; i++) { - - signed short t = xpad_abs[i]; - - set_bit(t, input_dev->absbit); - - switch (t) { - case ABS_X: - case ABS_Y: - case ABS_RX: - case ABS_RY: /* the two sticks */ - input_set_abs_params(input_dev, t, -32768, 32767, 16, 128); - break; - case ABS_Z: - case ABS_RZ: /* the triggers */ - input_set_abs_params(input_dev, t, 0, 255, 0, 0); - break; - case ABS_HAT0X: - case ABS_HAT0Y: /* the d-pad */ - input_set_abs_params(input_dev, t, -1, 1, 0, 0); - break; - } - } + /* set up axes */ + for (i = 0; xpad_abs[i] >= 0; i++) + xpad_set_up_abs(input_dev, xpad_abs[i]); + if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) + for (i = 0; xpad_abs_pad[i] >= 0; i++) + xpad_set_up_abs(input_dev, xpad_abs_pad[i]); ep_irq_in = &intf->cur_altsetting->endpoint[0].desc; usb_fill_int_urb(xpad->irq_in, udev, @@ -305,7 +394,8 @@ static void xpad_disconnect(struct usb_interface *intf) usb_kill_urb(xpad->irq_in); input_unregister_device(xpad->dev); usb_free_urb(xpad->irq_in); - usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, xpad->idata, xpad->idata_dma); + usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, + xpad->idata, xpad->idata_dma); kfree(xpad); } } diff --git a/drivers/usb/input/yealink.c b/drivers/usb/input/yealink.c index 905bf6398257..caff8e6d7448 100644 --- a/drivers/usb/input/yealink.c +++ b/drivers/usb/input/yealink.c @@ -859,10 +859,8 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id) interface = intf->cur_altsetting; endpoint = &interface->endpoint[0].desc; - if (!(endpoint->bEndpointAddress & USB_DIR_IN)) - return -EIO; - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) - return -EIO; + if (!usb_endpoint_is_int_in(endpoint)) + return -ENODEV; yld = kzalloc(sizeof(struct yealink_dev), GFP_KERNEL); if (!yld) @@ -876,17 +874,17 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id) /* allocate usb buffers */ yld->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN, - SLAB_ATOMIC, &yld->irq_dma); + GFP_ATOMIC, &yld->irq_dma); if (yld->irq_data == NULL) return usb_cleanup(yld, -ENOMEM); yld->ctl_data = usb_buffer_alloc(udev, USB_PKT_LEN, - SLAB_ATOMIC, &yld->ctl_dma); + GFP_ATOMIC, &yld->ctl_dma); if (!yld->ctl_data) return usb_cleanup(yld, -ENOMEM); yld->ctl_req = usb_buffer_alloc(udev, sizeof(*(yld->ctl_req)), - SLAB_ATOMIC, &yld->ctl_req_dma); + GFP_ATOMIC, &yld->ctl_req_dma); if (yld->ctl_req == NULL) return usb_cleanup(yld, -ENOMEM); diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index c29658f69e2a..a74bf8617e7f 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -223,6 +223,16 @@ config USB_LD To compile this driver as a module, choose M here: the module will be called ldusb. +config USB_TRANCEVIBRATOR + tristate "PlayStation 2 Trance Vibrator driver support" + depends on USB + help + Say Y here if you want to connect a PlayStation 2 Trance Vibrator + device to your computer's USB port. + + To compile this driver as a module, choose M here: the + module will be called trancevibrator. + config USB_TEST tristate "USB testing driver (DEVELOPMENT)" depends on USB && USB_DEVICEFS && EXPERIMENTAL diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 2be70fa259bf..2cba07d31971 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -4,6 +4,7 @@ # obj-$(CONFIG_USB_ADUTUX) += adutux.o +obj-$(CONFIG_USB_APPLEDISPLAY) += appledisplay.o obj-$(CONFIG_USB_AUERSWALD) += auerswald.o obj-$(CONFIG_USB_CYPRESS_CY7C63)+= cypress_cy7c63.o obj-$(CONFIG_USB_CYTHERM) += cytherm.o @@ -21,6 +22,7 @@ obj-$(CONFIG_USB_PHIDGETMOTORCONTROL) += phidgetmotorcontrol.o obj-$(CONFIG_USB_PHIDGETSERVO) += phidgetservo.o obj-$(CONFIG_USB_RIO500) += rio500.o obj-$(CONFIG_USB_TEST) += usbtest.o +obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o obj-$(CONFIG_USB_USS720) += uss720.o obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/ diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c index aecd633fe9f6..af2934e016a7 100644 --- a/drivers/usb/misc/adutux.c +++ b/drivers/usb/misc/adutux.c @@ -370,7 +370,8 @@ static int adu_release(struct inode *inode, struct file *file) retval = adu_release_internal(dev); exit: - up(&dev->sem); + if (dev) + up(&dev->sem); dbg(2," %s : leave, return value %d", __FUNCTION__, retval); return retval; } diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index 6b23a1def9fe..02cbb7fff24f 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -76,7 +76,7 @@ struct appledisplay { char *urbdata; /* interrupt URB data buffer */ char *msgdata; /* control message data buffer */ - struct work_struct work; + struct delayed_work work; int button_pressed; spinlock_t lock; }; @@ -117,7 +117,7 @@ static void appledisplay_complete(struct urb *urb) case ACD_BTN_BRIGHT_UP: case ACD_BTN_BRIGHT_DOWN: pdata->button_pressed = 1; - queue_work(wq, &pdata->work); + queue_delayed_work(wq, &pdata->work, 0); break; case ACD_BTN_NONE: default: @@ -184,9 +184,10 @@ static struct backlight_properties appledisplay_bl_data = { .max_brightness = 0xFF }; -static void appledisplay_work(void *private) +static void appledisplay_work(struct work_struct *work) { - struct appledisplay *pdata = private; + struct appledisplay *pdata = + container_of(work, struct appledisplay, work.work); int retval; up(&pdata->bd->sem); @@ -216,10 +217,7 @@ static int appledisplay_probe(struct usb_interface *iface, iface_desc = iface->cur_altsetting; for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { endpoint = &iface_desc->endpoint[i].desc; - if (!int_in_endpointAddr && - (endpoint->bEndpointAddress & USB_DIR_IN) && - ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_INT)) { + if (!int_in_endpointAddr && usb_endpoint_is_int_in(endpoint)) { /* we found an interrupt in endpoint */ int_in_endpointAddr = endpoint->bEndpointAddress; break; @@ -241,7 +239,7 @@ static int appledisplay_probe(struct usb_interface *iface, pdata->udev = udev; spin_lock_init(&pdata->lock); - INIT_WORK(&pdata->work, appledisplay_work, pdata); + INIT_DELAYED_WORK(&pdata->work, appledisplay_work); /* Allocate buffer for control messages */ pdata->msgdata = kmalloc(ACD_MSG_BUFFER_LEN, GFP_KERNEL); diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c index 0be9d62d62ae..c703f73e1655 100644 --- a/drivers/usb/misc/auerswald.c +++ b/drivers/usb/misc/auerswald.c @@ -704,9 +704,7 @@ static void auerbuf_free (pauerbuf_t bp) { kfree(bp->bufp); kfree(bp->dr); - if (bp->urbp) { - usb_free_urb(bp->urbp); - } + usb_free_urb(bp->urbp); kfree(bp); } @@ -780,7 +778,7 @@ static int auerbuf_setup (pauerbufctl_t bcp, unsigned int numElements, unsigned bl_fail:/* not enough memory. Free allocated elements */ dbg ("auerbuf_setup: no more memory"); - kfree(bep); + auerbuf_free(bep); auerbuf_free_buffers (bcp); return -ENOMEM; } @@ -1155,8 +1153,7 @@ static void auerswald_int_release (pauerswald_t cp) dbg ("auerswald_int_release"); /* stop the int endpoint */ - if (cp->inturbp) - usb_kill_urb (cp->inturbp); + usb_kill_urb (cp->inturbp); /* deallocate memory */ auerswald_int_free (cp); diff --git a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c index 1fd9cb85f4ca..5c0a26cbd128 100644 --- a/drivers/usb/misc/emi26.c +++ b/drivers/usb/misc/emi26.c @@ -53,13 +53,12 @@ static void __exit emi26_exit (void); static int emi26_writememory (struct usb_device *dev, int address, unsigned char *data, int length, __u8 request) { int result; - unsigned char *buffer = kmalloc (length, GFP_KERNEL); + unsigned char *buffer = kmemdup(data, length, GFP_KERNEL); if (!buffer) { err("emi26: kmalloc(%d) failed.", length); return -ENOMEM; } - memcpy (buffer, data, length); /* Note: usb_control_msg returns negative value on error or length of the * data that was written! */ result = usb_control_msg (dev, usb_sndctrlpipe(dev, 0), request, 0x40, address, 0, buffer, length, 300); diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c index fe351371f274..23153eac0dfa 100644 --- a/drivers/usb/misc/emi62.c +++ b/drivers/usb/misc/emi62.c @@ -61,13 +61,12 @@ static void __exit emi62_exit (void); static int emi62_writememory (struct usb_device *dev, int address, unsigned char *data, int length, __u8 request) { int result; - unsigned char *buffer = kmalloc (length, GFP_KERNEL); + unsigned char *buffer = kmemdup(data, length, GFP_KERNEL); if (!buffer) { err("emi62: kmalloc(%d) failed.", length); return -ENOMEM; } - memcpy (buffer, data, length); /* Note: usb_control_msg returns negative value on error or length of the * data that was written! */ result = usb_control_msg (dev, usb_sndctrlpipe(dev, 0), request, 0x40, address, 0, buffer, length, 300); diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 0eb26a26115b..18b1925032a8 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -156,9 +156,9 @@ struct usb_ftdi { struct usb_device *udev; struct usb_interface *interface; struct usb_class_driver *class; - struct work_struct status_work; - struct work_struct command_work; - struct work_struct respond_work; + struct delayed_work status_work; + struct delayed_work command_work; + struct delayed_work respond_work; struct u132_platform_data platform_data; struct resource resources[0]; struct platform_device platform_dev; @@ -210,23 +210,14 @@ static void ftdi_elan_init_kref(struct usb_ftdi *ftdi) static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(status_queue, &ftdi->status_work, delta)) - return; - } else if (queue_work(status_queue, &ftdi->status_work)) - return; - kref_put(&ftdi->kref, ftdi_elan_delete); - return; + if (!queue_delayed_work(status_queue, &ftdi->status_work, delta)) + kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(status_queue, &ftdi->status_work, delta)) - kref_get(&ftdi->kref); - } else if (queue_work(status_queue, &ftdi->status_work)) - kref_get(&ftdi->kref); - return; + if (queue_delayed_work(status_queue, &ftdi->status_work, delta)) + kref_get(&ftdi->kref); } static void ftdi_status_cancel_work(struct usb_ftdi *ftdi) @@ -237,25 +228,14 @@ static void ftdi_status_cancel_work(struct usb_ftdi *ftdi) static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(command_queue, &ftdi->command_work, - delta)) - return; - } else if (queue_work(command_queue, &ftdi->command_work)) - return; - kref_put(&ftdi->kref, ftdi_elan_delete); - return; + if (!queue_delayed_work(command_queue, &ftdi->command_work, delta)) + kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(command_queue, &ftdi->command_work, - delta)) - kref_get(&ftdi->kref); - } else if (queue_work(command_queue, &ftdi->command_work)) - kref_get(&ftdi->kref); - return; + if (queue_delayed_work(command_queue, &ftdi->command_work, delta)) + kref_get(&ftdi->kref); } static void ftdi_command_cancel_work(struct usb_ftdi *ftdi) @@ -267,25 +247,14 @@ static void ftdi_command_cancel_work(struct usb_ftdi *ftdi) static void ftdi_response_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(respond_queue, &ftdi->respond_work, - delta)) - return; - } else if (queue_work(respond_queue, &ftdi->respond_work)) - return; - kref_put(&ftdi->kref, ftdi_elan_delete); - return; + if (!queue_delayed_work(respond_queue, &ftdi->respond_work, delta)) + kref_put(&ftdi->kref, ftdi_elan_delete); } static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta) { - if (delta > 0) { - if (queue_delayed_work(respond_queue, &ftdi->respond_work, - delta)) - kref_get(&ftdi->kref); - } else if (queue_work(respond_queue, &ftdi->respond_work)) - kref_get(&ftdi->kref); - return; + if (queue_delayed_work(respond_queue, &ftdi->respond_work, delta)) + kref_get(&ftdi->kref); } static void ftdi_response_cancel_work(struct usb_ftdi *ftdi) @@ -303,7 +272,7 @@ void ftdi_elan_gone_away(struct platform_device *pdev) EXPORT_SYMBOL_GPL(ftdi_elan_gone_away); -void ftdi_release_platform_dev(struct device *dev) +static void ftdi_release_platform_dev(struct device *dev) { dev->parent = NULL; } @@ -475,9 +444,11 @@ static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi) return; } -static void ftdi_elan_command_work(void *data) +static void ftdi_elan_command_work(struct work_struct *work) { - struct usb_ftdi *ftdi = data; + struct usb_ftdi *ftdi = + container_of(work, struct usb_ftdi, command_work.work); + if (ftdi->disconnected > 0) { ftdi_elan_put_kref(ftdi); return; @@ -500,9 +471,10 @@ static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi) return; } -static void ftdi_elan_respond_work(void *data) +static void ftdi_elan_respond_work(struct work_struct *work) { - struct usb_ftdi *ftdi = data; + struct usb_ftdi *ftdi = + container_of(work, struct usb_ftdi, respond_work.work); if (ftdi->disconnected > 0) { ftdi_elan_put_kref(ftdi); return; @@ -513,8 +485,6 @@ static void ftdi_elan_respond_work(void *data) ftdi->disconnected += 1; } else if (retval == -ENODEV) { ftdi->disconnected += 1; - } else if (retval == -ENODEV) { - ftdi->disconnected += 1; } else if (retval == -EILSEQ) { ftdi->disconnected += 1; } else { @@ -536,9 +506,10 @@ static void ftdi_elan_respond_work(void *data) * after the FTDI has been synchronized * */ -static void ftdi_elan_status_work(void *data) +static void ftdi_elan_status_work(struct work_struct *work) { - struct usb_ftdi *ftdi = data; + struct usb_ftdi *ftdi = + container_of(work, struct usb_ftdi, status_work.work); int work_delay_in_msec = 0; if (ftdi->disconnected > 0) { ftdi_elan_put_kref(ftdi); @@ -1186,11 +1157,8 @@ static ssize_t ftdi_elan_write(struct file *file, int retval = 0; struct urb *urb; char *buf; - char data[30 *3 + 4]; - char *d = data; - const char __user *s = user_buffer; - int m = (sizeof(data) - 1) / 3; - struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data; + struct usb_ftdi *ftdi = file->private_data; + if (ftdi->disconnected > 0) { return -ENODEV; } @@ -1220,27 +1188,18 @@ static ssize_t ftdi_elan_write(struct file *file, if (retval) { dev_err(&ftdi->udev->dev, "failed submitting write urb, error %" "d\n", retval); - goto error_4; + goto error_3; } usb_free_urb(urb); - exit:; - if (count > m) { - int I = m - 1; - while (I-- > 0) { - d += sprintf(d, " %02X", 0x000000FF & *s++); - } - d += sprintf(d, " .."); - } else { - int I = count; - while (I-- > 0) { - d += sprintf(d, " %02X", 0x000000FF & *s++); - } - } + +exit: return count; - error_4: error_3:usb_buffer_free(ftdi->udev, count, buf, - urb->transfer_dma); - error_2:usb_free_urb(urb); - error_1:return retval; +error_3: + usb_buffer_free(ftdi->udev, count, buf, urb->transfer_dma); +error_2: + usb_free_urb(urb); +error_1: + return retval; } static struct file_operations ftdi_elan_fops = { @@ -1440,14 +1399,6 @@ static int ftdi_elan_read_reg(struct usb_ftdi *ftdi, u32 *data) } } -int usb_ftdi_elan_read_reg(struct platform_device *pdev, u32 *data) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_read_reg(ftdi, data); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_read_reg); static int ftdi_elan_read_config(struct usb_ftdi *ftdi, int config_offset, u8 width, u32 *data) { @@ -2647,10 +2598,7 @@ static int ftdi_elan_probe(struct usb_interface *interface, for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; if (!ftdi->bulk_in_endpointAddr && - ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - == USB_DIR_IN) && ((endpoint->bmAttributes & - USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) - { + usb_endpoint_is_bulk_in(endpoint)) { buffer_size = le16_to_cpu(endpoint->wMaxPacketSize); ftdi->bulk_in_size = buffer_size; ftdi->bulk_in_endpointAddr = endpoint->bEndpointAddress; @@ -2663,10 +2611,7 @@ static int ftdi_elan_probe(struct usb_interface *interface, } } if (!ftdi->bulk_out_endpointAddr && - ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) - == USB_DIR_OUT) && ((endpoint->bmAttributes & - USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) - { + usb_endpoint_is_bulk_out(endpoint)) { ftdi->bulk_out_endpointAddr = endpoint->bEndpointAddress; } @@ -2705,12 +2650,9 @@ static int ftdi_elan_probe(struct usb_interface *interface, ftdi->class = NULL; dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now a" "ctivated\n", ftdi, iface_desc->desc.bInterfaceNumber); - INIT_WORK(&ftdi->status_work, ftdi_elan_status_work, - (void *)ftdi); - INIT_WORK(&ftdi->command_work, ftdi_elan_command_work, - (void *)ftdi); - INIT_WORK(&ftdi->respond_work, ftdi_elan_respond_work, - (void *)ftdi); + INIT_DELAYED_WORK(&ftdi->status_work, ftdi_elan_status_work); + INIT_DELAYED_WORK(&ftdi->command_work, ftdi_elan_command_work); + INIT_DELAYED_WORK(&ftdi->respond_work, ftdi_elan_respond_work); ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000)); return 0; } else { diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index 8e6e195a22ba..c9418535bef8 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -125,12 +125,12 @@ static DEFINE_MUTEX(disconnect_mutex); static int idmouse_create_image(struct usb_idmouse *dev) { - int bytes_read = 0; - int bulk_read = 0; - int result = 0; + int bytes_read; + int bulk_read; + int result; memcpy(dev->bulk_in_buffer, HEADER, sizeof(HEADER)-1); - bytes_read += sizeof(HEADER)-1; + bytes_read = sizeof(HEADER)-1; /* reset the device and set a fast blink rate */ result = ftip_command(dev, FTIP_RELEASE, 0, 0); @@ -208,9 +208,9 @@ static inline void idmouse_delete(struct usb_idmouse *dev) static int idmouse_open(struct inode *inode, struct file *file) { - struct usb_idmouse *dev = NULL; + struct usb_idmouse *dev; struct usb_interface *interface; - int result = 0; + int result; /* prevent disconnects */ mutex_lock(&disconnect_mutex); @@ -305,7 +305,7 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count loff_t * ppos) { struct usb_idmouse *dev; - int result = 0; + int result; dev = (struct usb_idmouse *) file->private_data; @@ -329,7 +329,7 @@ static int idmouse_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_device *udev = interface_to_usbdev(interface); - struct usb_idmouse *dev = NULL; + struct usb_idmouse *dev; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; int result; @@ -350,11 +350,7 @@ static int idmouse_probe(struct usb_interface *interface, /* set up the endpoint information - use only the first bulk-in endpoint */ endpoint = &iface_desc->endpoint[0].desc; - if (!dev->bulk_in_endpointAddr - && (endpoint->bEndpointAddress & USB_DIR_IN) - && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_BULK)) { - + if (!dev->bulk_in_endpointAddr && usb_endpoint_is_bulk_in(endpoint)) { /* we found a bulk in endpoint */ dev->orig_bi_size = le16_to_cpu(endpoint->wMaxPacketSize); dev->bulk_in_size = 0x200; /* works _much_ faster */ diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 27089497e717..5dce797bddb7 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -317,12 +317,8 @@ static inline void tower_delete (struct lego_usb_tower *dev) tower_abort_transfers (dev); /* free data structures */ - if (dev->interrupt_in_urb != NULL) { - usb_free_urb (dev->interrupt_in_urb); - } - if (dev->interrupt_out_urb != NULL) { - usb_free_urb (dev->interrupt_out_urb); - } + usb_free_urb(dev->interrupt_in_urb); + usb_free_urb(dev->interrupt_out_urb); kfree (dev->read_buffer); kfree (dev->interrupt_in_buffer); kfree (dev->interrupt_out_buffer); @@ -502,15 +498,11 @@ static void tower_abort_transfers (struct lego_usb_tower *dev) if (dev->interrupt_in_running) { dev->interrupt_in_running = 0; mb(); - if (dev->interrupt_in_urb != NULL && dev->udev) { + if (dev->udev) usb_kill_urb (dev->interrupt_in_urb); - } - } - if (dev->interrupt_out_busy) { - if (dev->interrupt_out_urb != NULL && dev->udev) { - usb_kill_urb (dev->interrupt_out_urb); - } } + if (dev->interrupt_out_busy && dev->udev) + usb_kill_urb(dev->interrupt_out_urb); exit: dbg(2, "%s: leave", __FUNCTION__); @@ -898,14 +890,11 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { endpoint = &iface_desc->endpoint[i].desc; - if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && - ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { - dev->interrupt_in_endpoint = endpoint; - } - - if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) && - ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { - dev->interrupt_out_endpoint = endpoint; + if (usb_endpoint_xfer_int(endpoint)) { + if (usb_endpoint_dir_in(endpoint)) + dev->interrupt_in_endpoint = endpoint; + else + dev->interrupt_out_endpoint = endpoint; } } if(dev->interrupt_in_endpoint == NULL) { diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c index abb4dcd811ac..371bf2b1197d 100644 --- a/drivers/usb/misc/phidgetkit.c +++ b/drivers/usb/misc/phidgetkit.c @@ -81,8 +81,8 @@ struct interfacekit { unsigned char *data; dma_addr_t data_dma; - struct work_struct do_notify; - struct work_struct do_resubmit; + struct delayed_work do_notify; + struct delayed_work do_resubmit; unsigned long input_events; unsigned long sensor_events; }; @@ -374,19 +374,20 @@ static void interfacekit_irq(struct urb *urb) } if (kit->input_events || kit->sensor_events) - schedule_work(&kit->do_notify); + schedule_delayed_work(&kit->do_notify, 0); resubmit: - status = usb_submit_urb(urb, SLAB_ATOMIC); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) err("can't resubmit intr, %s-%s/interfacekit0, status %d", kit->udev->bus->bus_name, kit->udev->devpath, status); } -static void do_notify(void *data) +static void do_notify(struct work_struct *work) { - struct interfacekit *kit = data; + struct interfacekit *kit = + container_of(work, struct interfacekit, do_notify.work); int i; char sysfs_file[8]; @@ -405,9 +406,11 @@ static void do_notify(void *data) } } -static void do_resubmit(void *data) +static void do_resubmit(struct work_struct *work) { - set_outputs(data); + struct interfacekit *kit = + container_of(work, struct interfacekit, do_resubmit.work); + set_outputs(kit); } #define show_set_output(value) \ @@ -551,7 +554,7 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic return -ENODEV; endpoint = &interface->endpoint[0].desc; - if (!(endpoint->bEndpointAddress & 0x80)) + if (!usb_endpoint_dir_in(endpoint)) return -ENODEV; /* * bmAttributes @@ -565,7 +568,7 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic kit->dev_no = -1; kit->ifkit = ifkit; - kit->data = usb_buffer_alloc(dev, URB_INT_SIZE, SLAB_ATOMIC, &kit->data_dma); + kit->data = usb_buffer_alloc(dev, URB_INT_SIZE, GFP_ATOMIC, &kit->data_dma); if (!kit->data) goto out; @@ -575,8 +578,8 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic kit->udev = usb_get_dev(dev); kit->intf = intf; - INIT_WORK(&kit->do_notify, do_notify, kit); - INIT_WORK(&kit->do_resubmit, do_resubmit, kit); + INIT_DELAYED_WORK(&kit->do_notify, do_notify); + INIT_DELAYED_WORK(&kit->do_resubmit, do_resubmit); usb_fill_int_urb(kit->irq, kit->udev, pipe, kit->data, maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp, interfacekit_irq, kit, endpoint->bInterval); @@ -650,8 +653,7 @@ out2: device_remove_file(kit->dev, &dev_output_attrs[i]); out: if (kit) { - if (kit->irq) - usb_free_urb(kit->irq); + usb_free_urb(kit->irq); if (kit->data) usb_buffer_free(dev, URB_INT_SIZE, kit->data, kit->data_dma); if (kit->dev) diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c index 5c780cab92e0..5727e1ea2f91 100644 --- a/drivers/usb/misc/phidgetmotorcontrol.c +++ b/drivers/usb/misc/phidgetmotorcontrol.c @@ -41,7 +41,7 @@ struct motorcontrol { unsigned char *data; dma_addr_t data_dma; - struct work_struct do_notify; + struct delayed_work do_notify; unsigned long input_events; unsigned long speed_events; unsigned long exceed_events; @@ -148,10 +148,10 @@ static void motorcontrol_irq(struct urb *urb) set_bit(1, &mc->exceed_events); if (mc->input_events || mc->exceed_events || mc->speed_events) - schedule_work(&mc->do_notify); + schedule_delayed_work(&mc->do_notify, 0); resubmit: - status = usb_submit_urb(urb, SLAB_ATOMIC); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status) dev_err(&mc->intf->dev, "can't resubmit intr, %s-%s/motorcontrol0, status %d", @@ -159,9 +159,10 @@ resubmit: mc->udev->devpath, status); } -static void do_notify(void *data) +static void do_notify(struct work_struct *work) { - struct motorcontrol *mc = data; + struct motorcontrol *mc = + container_of(work, struct motorcontrol, do_notify.work); int i; char sysfs_file[8]; @@ -323,7 +324,7 @@ static int motorcontrol_probe(struct usb_interface *intf, const struct usb_devic return -ENODEV; endpoint = &interface->endpoint[0].desc; - if (!(endpoint->bEndpointAddress & 0x80)) + if (!usb_endpoint_dir_in(endpoint)) return -ENODEV; /* @@ -337,7 +338,7 @@ static int motorcontrol_probe(struct usb_interface *intf, const struct usb_devic goto out; mc->dev_no = -1; - mc->data = usb_buffer_alloc(dev, URB_INT_SIZE, SLAB_ATOMIC, &mc->data_dma); + mc->data = usb_buffer_alloc(dev, URB_INT_SIZE, GFP_ATOMIC, &mc->data_dma); if (!mc->data) goto out; @@ -348,7 +349,7 @@ static int motorcontrol_probe(struct usb_interface *intf, const struct usb_devic mc->udev = usb_get_dev(dev); mc->intf = intf; mc->acceleration[0] = mc->acceleration[1] = 10; - INIT_WORK(&mc->do_notify, do_notify, mc); + INIT_DELAYED_WORK(&mc->do_notify, do_notify); usb_fill_int_urb(mc->irq, mc->udev, pipe, mc->data, maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp, motorcontrol_irq, mc, endpoint->bInterval); @@ -392,8 +393,7 @@ out2: device_remove_file(mc->dev, &dev_attrs[i]); out: if (mc) { - if (mc->irq) - usb_free_urb(mc->irq); + usb_free_urb(mc->irq); if (mc->data) usb_buffer_free(dev, URB_INT_SIZE, mc->data, mc->data_dma); if (mc->dev) diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c index b99ca9c79821..0398908b15d4 100644 --- a/drivers/usb/misc/sisusbvga/sisusb.c +++ b/drivers/usb/misc/sisusbvga/sisusb.c @@ -3168,7 +3168,7 @@ sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg) case SISUSB_GET_CONFIG: case SISUSB_COMMAND: lock_kernel(); - retval = sisusb_ioctl(f->f_dentry->d_inode, f, cmd, arg); + retval = sisusb_ioctl(f->f_path.dentry->d_inode, f, cmd, arg); unlock_kernel(); return retval; diff --git a/drivers/usb/input/trancevibrator.c b/drivers/usb/misc/trancevibrator.c index 33cd91d11eca..33cd91d11eca 100644 --- a/drivers/usb/input/trancevibrator.c +++ b/drivers/usb/misc/trancevibrator.c diff --git a/drivers/usb/misc/usb_u132.h b/drivers/usb/misc/usb_u132.h index 551ba8906d62..dc2e5a31caec 100644 --- a/drivers/usb/misc/usb_u132.h +++ b/drivers/usb/misc/usb_u132.h @@ -52,7 +52,7 @@ * the kernel to load the "u132-hcd" module. * * The "ftdi-u132" module provides the interface to the inserted -* PC card and the "u132-hcd" module uses the API to send and recieve +* PC card and the "u132-hcd" module uses the API to send and receive * data. The API features call-backs, so that part of the "u132-hcd" * module code will run in the context of one of the kernel threads * of the "ftdi-u132" module. @@ -95,3 +95,7 @@ int usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number, int halted, int skipped, int actual, int non_null)); int usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number, void *endp); +int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, int mem_offset, + u8 width, u32 *data); +int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, int mem_offset, + u8 width, u32 data); diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 7c2cbdf81d20..fb321864a92d 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -138,7 +138,7 @@ get_endpoints (struct usbtest_dev *dev, struct usb_interface *intf) default: continue; } - if (e->desc.bEndpointAddress & USB_DIR_IN) { + if (usb_endpoint_dir_in(&e->desc)) { if (!in) in = e; } else { @@ -147,7 +147,7 @@ get_endpoints (struct usbtest_dev *dev, struct usb_interface *intf) } continue; try_iso: - if (e->desc.bEndpointAddress & USB_DIR_IN) { + if (usb_endpoint_dir_in(&e->desc)) { if (!iso_in) iso_in = e; } else { @@ -213,7 +213,7 @@ static struct urb *simple_alloc_urb ( if (bytes < 0) return NULL; - urb = usb_alloc_urb (0, SLAB_KERNEL); + urb = usb_alloc_urb (0, GFP_KERNEL); if (!urb) return urb; usb_fill_bulk_urb (urb, udev, pipe, NULL, bytes, simple_callback, NULL); @@ -223,7 +223,7 @@ static struct urb *simple_alloc_urb ( urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; if (usb_pipein (pipe)) urb->transfer_flags |= URB_SHORT_NOT_OK; - urb->transfer_buffer = usb_buffer_alloc (udev, bytes, SLAB_KERNEL, + urb->transfer_buffer = usb_buffer_alloc (udev, bytes, GFP_KERNEL, &urb->transfer_dma); if (!urb->transfer_buffer) { usb_free_urb (urb); @@ -315,7 +315,7 @@ static int simple_io ( init_completion (&completion); if (usb_pipeout (urb->pipe)) simple_fill_buf (urb); - if ((retval = usb_submit_urb (urb, SLAB_KERNEL)) != 0) + if ((retval = usb_submit_urb (urb, GFP_KERNEL)) != 0) break; /* NOTE: no timeouts; can't be broken out of by interrupt */ @@ -374,7 +374,7 @@ alloc_sglist (int nents, int max, int vary) unsigned i; unsigned size = max; - sg = kmalloc (nents * sizeof *sg, SLAB_KERNEL); + sg = kmalloc (nents * sizeof *sg, GFP_KERNEL); if (!sg) return NULL; @@ -382,7 +382,7 @@ alloc_sglist (int nents, int max, int vary) char *buf; unsigned j; - buf = kzalloc (size, SLAB_KERNEL); + buf = kzalloc (size, GFP_KERNEL); if (!buf) { free_sglist (sg, i); return NULL; @@ -428,7 +428,7 @@ static int perform_sglist ( (udev->speed == USB_SPEED_HIGH) ? (INTERRUPT_RATE << 3) : INTERRUPT_RATE, - sg, nents, 0, SLAB_KERNEL); + sg, nents, 0, GFP_KERNEL); if (retval) break; @@ -819,7 +819,7 @@ error: /* resubmit if we need to, else mark this as done */ if ((status == 0) && (ctx->pending < ctx->count)) { - if ((status = usb_submit_urb (urb, SLAB_ATOMIC)) != 0) { + if ((status = usb_submit_urb (urb, GFP_ATOMIC)) != 0) { dbg ("can't resubmit ctrl %02x.%02x, err %d", reqp->bRequestType, reqp->bRequest, status); urb->dev = NULL; @@ -855,7 +855,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) * as with bulk/intr sglists, sglen is the queue depth; it also * controls which subtests run (more tests than sglen) or rerun. */ - urb = kcalloc(param->sglen, sizeof(struct urb *), SLAB_KERNEL); + urb = kcalloc(param->sglen, sizeof(struct urb *), GFP_KERNEL); if (!urb) return -ENOMEM; for (i = 0; i < param->sglen; i++) { @@ -981,7 +981,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) if (!u) goto cleanup; - reqp = usb_buffer_alloc (udev, sizeof *reqp, SLAB_KERNEL, + reqp = usb_buffer_alloc (udev, sizeof *reqp, GFP_KERNEL, &u->setup_dma); if (!reqp) goto cleanup; @@ -999,7 +999,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param) context.urb = urb; spin_lock_irq (&context.lock); for (i = 0; i < param->sglen; i++) { - context.status = usb_submit_urb (urb [i], SLAB_ATOMIC); + context.status = usb_submit_urb (urb [i], GFP_ATOMIC); if (context.status != 0) { dbg ("can't submit urb[%d], status %d", i, context.status); @@ -1041,7 +1041,7 @@ static void unlink1_callback (struct urb *urb) // we "know" -EPIPE (stall) never happens if (!status) - status = usb_submit_urb (urb, SLAB_ATOMIC); + status = usb_submit_urb (urb, GFP_ATOMIC); if (status) { urb->status = status; complete ((struct completion *) urb->context); @@ -1067,7 +1067,7 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async) * FIXME want additional tests for when endpoint is STALLing * due to errors, or is just NAKing requests. */ - if ((retval = usb_submit_urb (urb, SLAB_KERNEL)) != 0) { + if ((retval = usb_submit_urb (urb, GFP_KERNEL)) != 0) { dev_dbg (&dev->intf->dev, "submit fail %d\n", retval); return retval; } @@ -1251,7 +1251,7 @@ static int ctrl_out (struct usbtest_dev *dev, if (length < 1 || length > 0xffff || vary >= length) return -EINVAL; - buf = kmalloc(length, SLAB_KERNEL); + buf = kmalloc(length, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -1403,7 +1403,7 @@ static struct urb *iso_alloc_urb ( maxp *= 1 + (0x3 & (le16_to_cpu(desc->wMaxPacketSize) >> 11)); packets = (bytes + maxp - 1) / maxp; - urb = usb_alloc_urb (packets, SLAB_KERNEL); + urb = usb_alloc_urb (packets, GFP_KERNEL); if (!urb) return urb; urb->dev = udev; @@ -1411,7 +1411,7 @@ static struct urb *iso_alloc_urb ( urb->number_of_packets = packets; urb->transfer_buffer_length = bytes; - urb->transfer_buffer = usb_buffer_alloc (udev, bytes, SLAB_KERNEL, + urb->transfer_buffer = usb_buffer_alloc (udev, bytes, GFP_KERNEL, &urb->transfer_dma); if (!urb->transfer_buffer) { usb_free_urb (urb); @@ -1481,7 +1481,7 @@ test_iso_queue (struct usbtest_dev *dev, struct usbtest_param *param, spin_lock_irq (&context.lock); for (i = 0; i < param->sglen; i++) { ++context.pending; - status = usb_submit_urb (urbs [i], SLAB_ATOMIC); + status = usb_submit_urb (urbs [i], GFP_ATOMIC); if (status < 0) { ERROR (dev, "submit iso[%d], error %d\n", i, status); if (i == 0) { @@ -1900,7 +1900,7 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) } #endif - dev = kzalloc(sizeof(*dev), SLAB_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; info = (struct usbtest_info *) id->driver_info; @@ -1910,7 +1910,7 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) dev->intf = intf; /* cacheline-aligned scratch for i/o */ - if ((dev->buf = kmalloc (TBUF_SIZE, SLAB_KERNEL)) == NULL) { + if ((dev->buf = kmalloc (TBUF_SIZE, GFP_KERNEL)) == NULL) { kfree (dev); return -ENOMEM; } diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index 7a2346c53284..05cf2c9a8f84 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -50,7 +50,7 @@ struct mon_event_text { #define SLAB_NAME_SZ 30 struct mon_reader_text { - kmem_cache_t *e_slab; + struct kmem_cache *e_slab; int nevents; struct list_head e_list; struct mon_reader r; /* In C, parent class can be placed anywhere */ @@ -63,7 +63,7 @@ struct mon_reader_text { char slab_name[SLAB_NAME_SZ]; }; -static void mon_text_ctor(void *, kmem_cache_t *, unsigned long); +static void mon_text_ctor(void *, struct kmem_cache *, unsigned long); /* * mon_text_submit @@ -147,7 +147,7 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb, stamp = mon_get_timestamp(); if (rp->nevents >= EVENT_MAX || - (ep = kmem_cache_alloc(rp->e_slab, SLAB_ATOMIC)) == NULL) { + (ep = kmem_cache_alloc(rp->e_slab, GFP_ATOMIC)) == NULL) { rp->r.m_bus->cnt_text_lost++; return; } @@ -188,7 +188,7 @@ static void mon_text_error(void *data, struct urb *urb, int error) struct mon_event_text *ep; if (rp->nevents >= EVENT_MAX || - (ep = kmem_cache_alloc(rp->e_slab, SLAB_ATOMIC)) == NULL) { + (ep = kmem_cache_alloc(rp->e_slab, GFP_ATOMIC)) == NULL) { rp->r.m_bus->cnt_text_lost++; return; } @@ -450,7 +450,7 @@ const struct file_operations mon_fops_text = { /* * Slab interface: constructor. */ -static void mon_text_ctor(void *mem, kmem_cache_t *slab, unsigned long sflags) +static void mon_text_ctor(void *mem, struct kmem_cache *slab, unsigned long sflags) { /* * Nothing to initialize. No, really! diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig index 054059632a21..e081836014ac 100644 --- a/drivers/usb/net/Kconfig +++ b/drivers/usb/net/Kconfig @@ -92,8 +92,13 @@ config USB_RTL8150 To compile this driver as a module, choose M here: the module will be called rtl8150. +config USB_USBNET_MII + tristate + default n + config USB_USBNET tristate "Multi-purpose USB Networking Framework" + select MII if USBNET_MII != n ---help--- This driver supports several kinds of network links over USB, with "minidrivers" built around a common network driver core @@ -129,7 +134,7 @@ config USB_NET_AX8817X tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters" depends on USB_USBNET && NET_ETHERNET select CRC32 - select MII + select USB_USBNET_MII default y help This option adds support for ASIX AX88xxx based USB 2.0 @@ -207,6 +212,15 @@ config USB_NET_PLUSB Choose this option if you're using a host-to-host cable with one of these chips. +config USB_NET_MCS7830 + tristate "MosChip MCS7830 based Ethernet adapters" + depends on USB_USBNET + select USB_USBNET_MII + help + Choose this option if you're using a 10/100 Ethernet USB2 + adapter based on the MosChip 7830 controller. This includes + adapters marketed under the DeLOCK brand. + config USB_NET_RNDIS_HOST tristate "Host for RNDIS devices (EXPERIMENTAL)" depends on USB_USBNET && EXPERIMENTAL diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile index 160f19dbdf12..7b51964de171 100644 --- a/drivers/usb/net/Makefile +++ b/drivers/usb/net/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_PLUSB) += plusb.o obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o +obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o obj-$(CONFIG_USB_USBNET) += usbnet.o ifeq ($(CONFIG_USB_DEBUG),y) diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index c73dd224aa76..95e682e2c9d6 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -249,9 +249,9 @@ asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; req->bRequest = cmd; - req->wValue = value; - req->wIndex = index; - req->wLength = size; + req->wValue = cpu_to_le16(value); + req->wIndex = cpu_to_le16(index); + req->wLength = cpu_to_le16(size); usb_fill_control_urb(urb, dev->udev, usb_sndctrlpipe(dev->udev, 0), @@ -569,10 +569,12 @@ static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc) struct usbnet *dev = netdev_priv(netdev); u16 res; + mutex_lock(&dev->phy_mutex); asix_set_sw_mii(dev); asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); asix_set_hw_mii(dev); + mutex_unlock(&dev->phy_mutex); devdbg(dev, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", phy_id, loc, le16_to_cpu(res & 0xffff)); @@ -586,10 +588,12 @@ asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val) u16 res = cpu_to_le16(val); devdbg(dev, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", phy_id, loc, val); + mutex_lock(&dev->phy_mutex); asix_set_sw_mii(dev); asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, (u16 *)&res); asix_set_hw_mii(dev); + mutex_unlock(&dev->phy_mutex); } /* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ @@ -700,32 +704,6 @@ static void asix_get_drvinfo (struct net_device *net, info->eedump_len = data->eeprom_len; } -static int asix_get_settings(struct net_device *net, struct ethtool_cmd *cmd) -{ - struct usbnet *dev = netdev_priv(net); - - return mii_ethtool_gset(&dev->mii,cmd); -} - -static int asix_set_settings(struct net_device *net, struct ethtool_cmd *cmd) -{ - struct usbnet *dev = netdev_priv(net); - int res = mii_ethtool_sset(&dev->mii,cmd); - - /* link speed/duplex might have changed */ - if (dev->driver_info->link_reset) - dev->driver_info->link_reset(dev); - - return res; -} - -static int asix_nway_reset(struct net_device *net) -{ - struct usbnet *dev = netdev_priv(net); - - return mii_nway_restart(&dev->mii); -} - static u32 asix_get_link(struct net_device *net) { struct usbnet *dev = netdev_priv(net); @@ -746,15 +724,15 @@ static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd) static struct ethtool_ops ax88172_ethtool_ops = { .get_drvinfo = asix_get_drvinfo, .get_link = asix_get_link, - .nway_reset = asix_nway_reset, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, .get_wol = asix_get_wol, .set_wol = asix_set_wol, .get_eeprom_len = asix_get_eeprom_len, .get_eeprom = asix_get_eeprom, - .get_settings = asix_get_settings, - .set_settings = asix_set_settings, + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, + .nway_reset = usbnet_nway_reset, }; static void ax88172_set_multicast(struct net_device *net) @@ -885,15 +863,15 @@ out1: static struct ethtool_ops ax88772_ethtool_ops = { .get_drvinfo = asix_get_drvinfo, .get_link = asix_get_link, - .nway_reset = asix_nway_reset, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, .get_wol = asix_get_wol, .set_wol = asix_set_wol, .get_eeprom_len = asix_get_eeprom_len, .get_eeprom = asix_get_eeprom, - .get_settings = asix_get_settings, - .set_settings = asix_set_settings, + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, + .nway_reset = usbnet_nway_reset, }; static int ax88772_link_reset(struct usbnet *dev) @@ -1046,15 +1024,15 @@ out1: static struct ethtool_ops ax88178_ethtool_ops = { .get_drvinfo = asix_get_drvinfo, .get_link = asix_get_link, - .nway_reset = asix_nway_reset, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, .get_wol = asix_get_wol, .set_wol = asix_set_wol, .get_eeprom_len = asix_get_eeprom_len, .get_eeprom = asix_get_eeprom, - .get_settings = asix_get_settings, - .set_settings = asix_set_settings, + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, + .nway_reset = usbnet_nway_reset, }; static int marvell_phy_init(struct usbnet *dev) diff --git a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c index f740325abac4..4852012735f6 100644 --- a/drivers/usb/net/catc.c +++ b/drivers/usb/net/catc.c @@ -345,7 +345,7 @@ static void catc_irq_done(struct urb *urb) } } resubmit: - status = usb_submit_urb (urb, SLAB_ATOMIC); + status = usb_submit_urb (urb, GFP_ATOMIC); if (status) err ("can't resubmit intr, %s-%s, status %d", catc->usbdev->bus->bus_name, @@ -786,14 +786,10 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id if ((!catc->ctrl_urb) || (!catc->tx_urb) || (!catc->rx_urb) || (!catc->irq_urb)) { err("No free urbs available."); - if (catc->ctrl_urb) - usb_free_urb(catc->ctrl_urb); - if (catc->tx_urb) - usb_free_urb(catc->tx_urb); - if (catc->rx_urb) - usb_free_urb(catc->rx_urb); - if (catc->irq_urb) - usb_free_urb(catc->irq_urb); + usb_free_urb(catc->ctrl_urb); + usb_free_urb(catc->tx_urb); + usb_free_urb(catc->rx_urb); + usb_free_urb(catc->irq_urb); free_netdev(netdev); return -ENOMEM; } diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c index 82ce0358d9a3..44a91547146e 100644 --- a/drivers/usb/net/cdc_ether.c +++ b/drivers/usb/net/cdc_ether.c @@ -200,8 +200,7 @@ next_desc: dev->status = &info->control->cur_altsetting->endpoint [0]; desc = &dev->status->desc; - if (desc->bmAttributes != USB_ENDPOINT_XFER_INT - || !(desc->bEndpointAddress & USB_DIR_IN) + if (!usb_endpoint_is_int_in(desc) || (le16_to_cpu(desc->wMaxPacketSize) < sizeof(struct usb_cdc_notification)) || !desc->bInterval) { @@ -498,7 +497,7 @@ static struct usb_driver cdc_driver = { static int __init cdc_init(void) { - BUG_ON((sizeof(((struct usbnet *)0)->data) + BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data) < sizeof(struct cdc_state))); return usb_register(&cdc_driver); diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index 957d4ad316f9..fa78326d0bf0 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -65,16 +65,6 @@ #undef DEBUG -#ifdef DEBUG -#define kaweth_dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" ,##arg) -#else -#define kaweth_dbg(format, arg...) do {} while (0) -#endif -#define kaweth_err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" ,##arg) -#define kaweth_info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ##arg) -#define kaweth_warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ##arg) - - #include "kawethfw.h" #define KAWETH_MTU 1514 @@ -86,6 +76,9 @@ #define KAWETH_STATUS_BROKEN 0x0000001 #define KAWETH_STATUS_CLOSING 0x0000002 +#define KAWETH_STATUS_SUSPENDING 0x0000004 + +#define KAWETH_STATUS_BLOCKED (KAWETH_STATUS_CLOSING | KAWETH_STATUS_SUSPENDING) #define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01 #define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02 @@ -112,6 +105,8 @@ #define STATE_MASK 0x40 #define STATE_SHIFT 5 +#define IS_BLOCKED(s) (s & KAWETH_STATUS_BLOCKED) + MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr>, Brad Hards <bhards@bigpond.net.au> and Oliver Neukum <oliver@neukum.org>"); MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver"); @@ -128,6 +123,8 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe, struct usb_ctrlrequest *cmd, void *data, int len, int timeout); +static int kaweth_suspend(struct usb_interface *intf, pm_message_t message); +static int kaweth_resume(struct usb_interface *intf); /**************************************************************** * usb_device_id @@ -179,6 +176,8 @@ static struct usb_driver kaweth_driver = { .name = driver_name, .probe = kaweth_probe, .disconnect = kaweth_disconnect, + .suspend = kaweth_suspend, + .resume = kaweth_resume, .id_table = usb_klsi_table, }; @@ -222,7 +221,8 @@ struct kaweth_device int suspend_lowmem_rx; int suspend_lowmem_ctrl; int linkstate; - struct work_struct lowmem_work; + int opened; + struct delayed_work lowmem_work; struct usb_device *dev; struct net_device *net; @@ -265,17 +265,17 @@ static int kaweth_control(struct kaweth_device *kaweth, { struct usb_ctrlrequest *dr; - kaweth_dbg("kaweth_control()"); + dbg("kaweth_control()"); if(in_interrupt()) { - kaweth_dbg("in_interrupt()"); + dbg("in_interrupt()"); return -EBUSY; } dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC); if (!dr) { - kaweth_dbg("kmalloc() failed"); + dbg("kmalloc() failed"); return -ENOMEM; } @@ -300,7 +300,7 @@ static int kaweth_read_configuration(struct kaweth_device *kaweth) { int retval; - kaweth_dbg("Reading kaweth configuration"); + dbg("Reading kaweth configuration"); retval = kaweth_control(kaweth, usb_rcvctrlpipe(kaweth->dev, 0), @@ -322,7 +322,7 @@ static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size) { int retval; - kaweth_dbg("Setting URB size to %d", (unsigned)urb_size); + dbg("Setting URB size to %d", (unsigned)urb_size); retval = kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), @@ -344,7 +344,7 @@ static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait) { int retval; - kaweth_dbg("Set SOFS wait to %d", (unsigned)sofs_wait); + dbg("Set SOFS wait to %d", (unsigned)sofs_wait); retval = kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), @@ -367,7 +367,7 @@ static int kaweth_set_receive_filter(struct kaweth_device *kaweth, { int retval; - kaweth_dbg("Set receive filter to %d", (unsigned)receive_filter); + dbg("Set receive filter to %d", (unsigned)receive_filter); retval = kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), @@ -392,7 +392,7 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth, __u8 type) { if(data_len > KAWETH_FIRMWARE_BUF_SIZE) { - kaweth_err("Firmware too big: %d", data_len); + err("Firmware too big: %d", data_len); return -ENOSPC; } @@ -403,13 +403,13 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth, kaweth->firmware_buf[4] = type; kaweth->firmware_buf[5] = interrupt; - kaweth_dbg("High: %i, Low:%i", kaweth->firmware_buf[3], + dbg("High: %i, Low:%i", kaweth->firmware_buf[3], kaweth->firmware_buf[2]); - kaweth_dbg("Downloading firmware at %p to kaweth device at %p", + dbg("Downloading firmware at %p to kaweth device at %p", data, kaweth); - kaweth_dbg("Firmware length: %d", data_len); + dbg("Firmware length: %d", data_len); return kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), @@ -437,7 +437,7 @@ static int kaweth_trigger_firmware(struct kaweth_device *kaweth, kaweth->firmware_buf[6] = 0x00; kaweth->firmware_buf[7] = 0x00; - kaweth_dbg("Triggering firmware"); + dbg("Triggering firmware"); return kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), @@ -457,7 +457,7 @@ static int kaweth_reset(struct kaweth_device *kaweth) { int result; - kaweth_dbg("kaweth_reset(%p)", kaweth); + dbg("kaweth_reset(%p)", kaweth); result = kaweth_control(kaweth, usb_sndctrlpipe(kaweth->dev, 0), USB_REQ_SET_CONFIGURATION, @@ -470,7 +470,7 @@ static int kaweth_reset(struct kaweth_device *kaweth) mdelay(10); - kaweth_dbg("kaweth_reset() returns %d.",result); + dbg("kaweth_reset() returns %d.",result); return result; } @@ -530,11 +530,12 @@ resubmit: kaweth_resubmit_int_urb(kaweth, GFP_ATOMIC); } -static void kaweth_resubmit_tl(void *d) +static void kaweth_resubmit_tl(struct work_struct *work) { - struct kaweth_device *kaweth = (struct kaweth_device *)d; + struct kaweth_device *kaweth = + container_of(work, struct kaweth_device, lowmem_work.work); - if (kaweth->status | KAWETH_STATUS_CLOSING) + if (IS_BLOCKED(kaweth->status)) return; if (kaweth->suspend_lowmem_rx) @@ -568,7 +569,7 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth, kaweth->suspend_lowmem_rx = 1; schedule_delayed_work(&kaweth->lowmem_work, HZ/4); } - kaweth_err("resubmitting rx_urb %d failed", result); + err("resubmitting rx_urb %d failed", result); } else { kaweth->suspend_lowmem_rx = 0; } @@ -601,11 +602,15 @@ static void kaweth_usb_receive(struct urb *urb) return; } - if (kaweth->status & KAWETH_STATUS_CLOSING) + spin_lock(&kaweth->device_lock); + if (IS_BLOCKED(kaweth->status)) { + spin_unlock(&kaweth->device_lock); return; + } + spin_unlock(&kaweth->device_lock); if(urb->status && urb->status != -EREMOTEIO && count != 1) { - kaweth_err("%s RX status: %d count: %d packet_len: %d", + err("%s RX status: %d count: %d packet_len: %d", net->name, urb->status, count, @@ -616,9 +621,9 @@ static void kaweth_usb_receive(struct urb *urb) if(kaweth->net && (count > 2)) { if(pkt_len > (count - 2)) { - kaweth_err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count); - kaweth_err("Packet len & 2047: %x", pkt_len & 2047); - kaweth_err("Count 2: %x", count2); + err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count); + err("Packet len & 2047: %x", pkt_len & 2047); + err("Count 2: %x", count2); kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); return; } @@ -655,7 +660,7 @@ static int kaweth_open(struct net_device *net) struct kaweth_device *kaweth = netdev_priv(net); int res; - kaweth_dbg("Opening network device."); + dbg("Opening network device."); res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL); if (res) @@ -678,6 +683,7 @@ static int kaweth_open(struct net_device *net) usb_kill_urb(kaweth->rx_urb); return -EIO; } + kaweth->opened = 1; netif_start_queue(net); @@ -688,14 +694,8 @@ static int kaweth_open(struct net_device *net) /**************************************************************** * kaweth_close ****************************************************************/ -static int kaweth_close(struct net_device *net) +static void kaweth_kill_urbs(struct kaweth_device *kaweth) { - struct kaweth_device *kaweth = netdev_priv(net); - - netif_stop_queue(net); - - kaweth->status |= KAWETH_STATUS_CLOSING; - usb_kill_urb(kaweth->irq_urb); usb_kill_urb(kaweth->rx_urb); usb_kill_urb(kaweth->tx_urb); @@ -706,6 +706,21 @@ static int kaweth_close(struct net_device *net) we hit them again */ usb_kill_urb(kaweth->irq_urb); usb_kill_urb(kaweth->rx_urb); +} + +/**************************************************************** + * kaweth_close + ****************************************************************/ +static int kaweth_close(struct net_device *net) +{ + struct kaweth_device *kaweth = netdev_priv(net); + + netif_stop_queue(net); + kaweth->opened = 0; + + kaweth->status |= KAWETH_STATUS_CLOSING; + + kaweth_kill_urbs(kaweth); kaweth->status &= ~KAWETH_STATUS_CLOSING; @@ -732,7 +747,7 @@ static void kaweth_usb_transmit_complete(struct urb *urb) if (unlikely(urb->status != 0)) if (urb->status != -ENOENT) - kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status); + dbg("%s: TX status %d.", kaweth->net->name, urb->status); netif_wake_queue(kaweth->net); dev_kfree_skb_irq(skb); @@ -752,6 +767,9 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) kaweth_async_set_rx_mode(kaweth); netif_stop_queue(net); + if (IS_BLOCKED(kaweth->status)) { + goto skip; + } /* We now decide whether we can put our special header into the sk_buff */ if (skb_cloned(skb) || skb_headroom(skb) < 2) { @@ -783,7 +801,8 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net) if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC))) { - kaweth_warn("kaweth failed tx_urb %d", res); + warn("kaweth failed tx_urb %d", res); +skip: kaweth->stats.tx_errors++; netif_start_queue(net); @@ -812,7 +831,7 @@ static void kaweth_set_rx_mode(struct net_device *net) KAWETH_PACKET_FILTER_BROADCAST | KAWETH_PACKET_FILTER_MULTICAST; - kaweth_dbg("Setting Rx mode to %d", packet_filter_bitmap); + dbg("Setting Rx mode to %d", packet_filter_bitmap); netif_stop_queue(net); @@ -850,10 +869,10 @@ static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth) KAWETH_CONTROL_TIMEOUT); if(result < 0) { - kaweth_err("Failed to set Rx mode: %d", result); + err("Failed to set Rx mode: %d", result); } else { - kaweth_dbg("Set Rx mode to %d", packet_filter_bitmap); + dbg("Set Rx mode to %d", packet_filter_bitmap); } } } @@ -874,7 +893,7 @@ static void kaweth_tx_timeout(struct net_device *net) { struct kaweth_device *kaweth = netdev_priv(net); - kaweth_warn("%s: Tx timed out. Resetting.", net->name); + warn("%s: Tx timed out. Resetting.", net->name); kaweth->stats.tx_errors++; net->trans_start = jiffies; @@ -882,6 +901,42 @@ static void kaweth_tx_timeout(struct net_device *net) } /**************************************************************** + * kaweth_suspend + ****************************************************************/ +static int kaweth_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct kaweth_device *kaweth = usb_get_intfdata(intf); + unsigned long flags; + + spin_lock_irqsave(&kaweth->device_lock, flags); + kaweth->status |= KAWETH_STATUS_SUSPENDING; + spin_unlock_irqrestore(&kaweth->device_lock, flags); + + kaweth_kill_urbs(kaweth); + return 0; +} + +/**************************************************************** + * kaweth_resume + ****************************************************************/ +static int kaweth_resume(struct usb_interface *intf) +{ + struct kaweth_device *kaweth = usb_get_intfdata(intf); + unsigned long flags; + + spin_lock_irqsave(&kaweth->device_lock, flags); + kaweth->status &= ~KAWETH_STATUS_SUSPENDING; + spin_unlock_irqrestore(&kaweth->device_lock, flags); + + if (!kaweth->opened) + return 0; + kaweth_resubmit_rx_urb(kaweth, GFP_NOIO); + kaweth_resubmit_int_urb(kaweth, GFP_NOIO); + + return 0; +} + +/**************************************************************** * kaweth_probe ****************************************************************/ static int kaweth_probe( @@ -895,15 +950,15 @@ static int kaweth_probe( const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; int result = 0; - kaweth_dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x", + dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x", dev->devnum, le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct), le16_to_cpu(dev->descriptor.bcdDevice)); - kaweth_dbg("Device at %p", dev); + dbg("Device at %p", dev); - kaweth_dbg("Descriptor length: %x type: %x", + dbg("Descriptor length: %x type: %x", (int)dev->descriptor.bLength, (int)dev->descriptor.bDescriptorType); @@ -918,7 +973,7 @@ static int kaweth_probe( spin_lock_init(&kaweth->device_lock); init_waitqueue_head(&kaweth->term_wait); - kaweth_dbg("Resetting."); + dbg("Resetting."); kaweth_reset(kaweth); @@ -928,17 +983,17 @@ static int kaweth_probe( */ if (le16_to_cpu(dev->descriptor.bcdDevice) >> 8) { - kaweth_info("Firmware present in device."); + info("Firmware present in device."); } else { /* Download the firmware */ - kaweth_info("Downloading firmware..."); + info("Downloading firmware..."); kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL); if ((result = kaweth_download_firmware(kaweth, kaweth_new_code, len_kaweth_new_code, 100, 2)) < 0) { - kaweth_err("Error downloading firmware (%d)", result); + err("Error downloading firmware (%d)", result); goto err_fw; } @@ -947,7 +1002,7 @@ static int kaweth_probe( len_kaweth_new_code_fix, 100, 3)) < 0) { - kaweth_err("Error downloading firmware fix (%d)", result); + err("Error downloading firmware fix (%d)", result); goto err_fw; } @@ -956,7 +1011,7 @@ static int kaweth_probe( len_kaweth_trigger_code, 126, 2)) < 0) { - kaweth_err("Error downloading trigger code (%d)", result); + err("Error downloading trigger code (%d)", result); goto err_fw; } @@ -966,18 +1021,18 @@ static int kaweth_probe( len_kaweth_trigger_code_fix, 126, 3)) < 0) { - kaweth_err("Error downloading trigger code fix (%d)", result); + err("Error downloading trigger code fix (%d)", result); goto err_fw; } if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) { - kaweth_err("Error triggering firmware (%d)", result); + err("Error triggering firmware (%d)", result); goto err_fw; } /* Device will now disappear for a moment... */ - kaweth_info("Firmware loaded. I'll be back..."); + info("Firmware loaded. I'll be back..."); err_fw: free_page((unsigned long)kaweth->firmware_buf); free_netdev(netdev); @@ -987,14 +1042,14 @@ err_fw: result = kaweth_read_configuration(kaweth); if(result < 0) { - kaweth_err("Error reading configuration (%d), no net device created", result); + err("Error reading configuration (%d), no net device created", result); goto err_free_netdev; } - kaweth_info("Statistics collection: %x", kaweth->configuration.statistics_mask); - kaweth_info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); - kaweth_info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size)); - kaweth_info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", + info("Statistics collection: %x", kaweth->configuration.statistics_mask); + info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1)); + info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size)); + info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", (int)kaweth->configuration.hw_addr[0], (int)kaweth->configuration.hw_addr[1], (int)kaweth->configuration.hw_addr[2], @@ -1005,17 +1060,17 @@ err_fw: if(!memcmp(&kaweth->configuration.hw_addr, &bcast_addr, sizeof(bcast_addr))) { - kaweth_err("Firmware not functioning properly, no net device created"); + err("Firmware not functioning properly, no net device created"); goto err_free_netdev; } if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) { - kaweth_dbg("Error setting URB size"); + dbg("Error setting URB size"); goto err_free_netdev; } if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) { - kaweth_err("Error setting SOFS wait"); + err("Error setting SOFS wait"); goto err_free_netdev; } @@ -1025,11 +1080,11 @@ err_fw: KAWETH_PACKET_FILTER_MULTICAST); if(result < 0) { - kaweth_err("Error setting receive filter"); + err("Error setting receive filter"); goto err_free_netdev; } - kaweth_dbg("Initializing net device."); + dbg("Initializing net device."); kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL); if (!kaweth->tx_urb) @@ -1072,7 +1127,7 @@ err_fw: /* kaweth is zeroed as part of alloc_netdev */ - INIT_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl, (void *)kaweth); + INIT_DELAYED_WORK(&kaweth->lowmem_work, kaweth_resubmit_tl); SET_MODULE_OWNER(netdev); @@ -1086,13 +1141,13 @@ err_fw: SET_NETDEV_DEV(netdev, &intf->dev); if (register_netdev(netdev) != 0) { - kaweth_err("Error registering netdev."); + err("Error registering netdev."); goto err_intfdata; } - kaweth_info("kaweth interface created at %s", kaweth->net->name); + info("kaweth interface created at %s", kaweth->net->name); - kaweth_dbg("Kaweth probe returning."); + dbg("Kaweth probe returning."); return 0; @@ -1121,16 +1176,16 @@ static void kaweth_disconnect(struct usb_interface *intf) struct kaweth_device *kaweth = usb_get_intfdata(intf); struct net_device *netdev; - kaweth_info("Unregistering"); + info("Unregistering"); usb_set_intfdata(intf, NULL); if (!kaweth) { - kaweth_warn("unregistering non-existant device"); + warn("unregistering non-existant device"); return; } netdev = kaweth->net; - kaweth_dbg("Unregistering net device"); + dbg("Unregistering net device"); unregister_netdev(netdev); usb_free_urb(kaweth->rx_urb); @@ -1185,7 +1240,7 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length) if (!wait_event_timeout(awd.wqh, awd.done, timeout)) { // timeout - kaweth_warn("usb_control/bulk_msg: timeout"); + warn("usb_control/bulk_msg: timeout"); usb_kill_urb(urb); // remove urb safely status = -ETIMEDOUT; } @@ -1234,7 +1289,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev, ****************************************************************/ static int __init kaweth_init(void) { - kaweth_dbg("Driver loading"); + dbg("Driver loading"); return usb_register(&kaweth_driver); } diff --git a/drivers/usb/net/mcs7830.c b/drivers/usb/net/mcs7830.c new file mode 100644 index 000000000000..6240b978fe3d --- /dev/null +++ b/drivers/usb/net/mcs7830.c @@ -0,0 +1,534 @@ +/* + * MosChips MCS7830 based USB 2.0 Ethernet Devices + * + * based on usbnet.c, asix.c and the vendor provided mcs7830 driver + * + * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de> + * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com> + * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net> + * Copyright (c) 2002-2003 TiVo Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/crc32.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/init.h> +#include <linux/mii.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/usb.h> + +#include "usbnet.h" + +/* requests */ +#define MCS7830_RD_BMREQ (USB_DIR_IN | USB_TYPE_VENDOR | \ + USB_RECIP_DEVICE) +#define MCS7830_WR_BMREQ (USB_DIR_OUT | USB_TYPE_VENDOR | \ + USB_RECIP_DEVICE) +#define MCS7830_RD_BREQ 0x0E +#define MCS7830_WR_BREQ 0x0D + +#define MCS7830_CTRL_TIMEOUT 1000 +#define MCS7830_MAX_MCAST 64 + +#define MCS7830_VENDOR_ID 0x9710 +#define MCS7830_PRODUCT_ID 0x7830 + +#define MCS7830_MII_ADVERTISE (ADVERTISE_PAUSE_CAP | ADVERTISE_100FULL | \ + ADVERTISE_100HALF | ADVERTISE_10FULL | \ + ADVERTISE_10HALF | ADVERTISE_CSMA) + +/* HIF_REG_XX coressponding index value */ +enum { + HIF_REG_MULTICAST_HASH = 0x00, + HIF_REG_PACKET_GAP1 = 0x08, + HIF_REG_PACKET_GAP2 = 0x09, + HIF_REG_PHY_DATA = 0x0a, + HIF_REG_PHY_CMD1 = 0x0c, + HIF_REG_PHY_CMD1_READ = 0x40, + HIF_REG_PHY_CMD1_WRITE = 0x20, + HIF_REG_PHY_CMD1_PHYADDR = 0x01, + HIF_REG_PHY_CMD2 = 0x0d, + HIF_REG_PHY_CMD2_PEND_FLAG_BIT = 0x80, + HIF_REG_PHY_CMD2_READY_FLAG_BIT = 0x40, + HIF_REG_CONFIG = 0x0e, + HIF_REG_CONFIG_CFG = 0x80, + HIF_REG_CONFIG_SPEED100 = 0x40, + HIF_REG_CONFIG_FULLDUPLEX_ENABLE = 0x20, + HIF_REG_CONFIG_RXENABLE = 0x10, + HIF_REG_CONFIG_TXENABLE = 0x08, + HIF_REG_CONFIG_SLEEPMODE = 0x04, + HIF_REG_CONFIG_ALLMULTICAST = 0x02, + HIF_REG_CONFIG_PROMISCIOUS = 0x01, + HIF_REG_ETHERNET_ADDR = 0x0f, + HIF_REG_22 = 0x15, + HIF_REG_PAUSE_THRESHOLD = 0x16, + HIF_REG_PAUSE_THRESHOLD_DEFAULT = 0, +}; + +struct mcs7830_data { + u8 multi_filter[8]; + u8 config; +}; + +static const char driver_name[] = "MOSCHIP usb-ethernet driver"; + +static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data) +{ + struct usb_device *xdev = dev->udev; + int ret; + + ret = usb_control_msg(xdev, usb_rcvctrlpipe(xdev, 0), MCS7830_RD_BREQ, + MCS7830_RD_BMREQ, 0x0000, index, data, + size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT)); + return ret; +} + +static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data) +{ + struct usb_device *xdev = dev->udev; + int ret; + + ret = usb_control_msg(xdev, usb_sndctrlpipe(xdev, 0), MCS7830_WR_BREQ, + MCS7830_WR_BMREQ, 0x0000, index, data, + size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT)); + return ret; +} + +static void mcs7830_async_cmd_callback(struct urb *urb) +{ + struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; + + if (urb->status < 0) + printk(KERN_DEBUG "mcs7830_async_cmd_callback() failed with %d", + urb->status); + + kfree(req); + usb_free_urb(urb); +} + +static void mcs7830_set_reg_async(struct usbnet *dev, u16 index, u16 size, void *data) +{ + struct usb_ctrlrequest *req; + int ret; + struct urb *urb; + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) { + dev_dbg(&dev->udev->dev, "Error allocating URB " + "in write_cmd_async!"); + return; + } + + req = kmalloc(sizeof *req, GFP_ATOMIC); + if (!req) { + dev_err(&dev->udev->dev, "Failed to allocate memory for " + "control request"); + goto out; + } + req->bRequestType = MCS7830_WR_BMREQ; + req->bRequest = MCS7830_WR_BREQ; + req->wValue = 0; + req->wIndex = cpu_to_le16(index); + req->wLength = cpu_to_le16(size); + + usb_fill_control_urb(urb, dev->udev, + usb_sndctrlpipe(dev->udev, 0), + (void *)req, data, size, + mcs7830_async_cmd_callback, req); + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + dev_err(&dev->udev->dev, "Error submitting the control " + "message: ret=%d", ret); + goto out; + } + return; +out: + kfree(req); + usb_free_urb(urb); +} + +static int mcs7830_get_address(struct usbnet *dev) +{ + int ret; + ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN, + dev->net->dev_addr); + if (ret < 0) + return ret; + return 0; +} + +static int mcs7830_read_phy(struct usbnet *dev, u8 index) +{ + int ret; + int i; + __le16 val; + + u8 cmd[2] = { + HIF_REG_PHY_CMD1_READ | HIF_REG_PHY_CMD1_PHYADDR, + HIF_REG_PHY_CMD2_PEND_FLAG_BIT | index, + }; + + mutex_lock(&dev->phy_mutex); + /* write the MII command */ + ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); + if (ret < 0) + goto out; + + /* wait for the data to become valid, should be within < 1ms */ + for (i = 0; i < 10; i++) { + ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); + if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT)) + break; + ret = -EIO; + msleep(1); + } + if (ret < 0) + goto out; + + /* read actual register contents */ + ret = mcs7830_get_reg(dev, HIF_REG_PHY_DATA, 2, &val); + if (ret < 0) + goto out; + ret = le16_to_cpu(val); + dev_dbg(&dev->udev->dev, "read PHY reg %02x: %04x (%d tries)\n", + index, val, i); +out: + mutex_unlock(&dev->phy_mutex); + return ret; +} + +static int mcs7830_write_phy(struct usbnet *dev, u8 index, u16 val) +{ + int ret; + int i; + __le16 le_val; + + u8 cmd[2] = { + HIF_REG_PHY_CMD1_WRITE | HIF_REG_PHY_CMD1_PHYADDR, + HIF_REG_PHY_CMD2_PEND_FLAG_BIT | (index & 0x1F), + }; + + mutex_lock(&dev->phy_mutex); + + /* write the new register contents */ + le_val = cpu_to_le16(val); + ret = mcs7830_set_reg(dev, HIF_REG_PHY_DATA, 2, &le_val); + if (ret < 0) + goto out; + + /* write the MII command */ + ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); + if (ret < 0) + goto out; + + /* wait for the command to be accepted by the PHY */ + for (i = 0; i < 10; i++) { + ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd); + if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT)) + break; + ret = -EIO; + msleep(1); + } + if (ret < 0) + goto out; + + ret = 0; + dev_dbg(&dev->udev->dev, "write PHY reg %02x: %04x (%d tries)\n", + index, val, i); +out: + mutex_unlock(&dev->phy_mutex); + return ret; +} + +/* + * This algorithm comes from the original mcs7830 version 1.4 driver, + * not sure if it is needed. + */ +static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode) +{ + int ret; + /* Enable all media types */ + ret = mcs7830_write_phy(dev, MII_ADVERTISE, MCS7830_MII_ADVERTISE); + + /* First reset BMCR */ + if (!ret) + ret = mcs7830_write_phy(dev, MII_BMCR, 0x0000); + /* Enable Auto Neg */ + if (!ret) + ret = mcs7830_write_phy(dev, MII_BMCR, BMCR_ANENABLE); + /* Restart Auto Neg (Keep the Enable Auto Neg Bit Set) */ + if (!ret) + ret = mcs7830_write_phy(dev, MII_BMCR, + BMCR_ANENABLE | BMCR_ANRESTART ); + return ret < 0 ? : 0; +} + + +/* + * if we can read register 22, the chip revision is C or higher + */ +static int mcs7830_get_rev(struct usbnet *dev) +{ + u8 dummy[2]; + int ret; + ret = mcs7830_get_reg(dev, HIF_REG_22, 2, dummy); + if (ret > 0) + return 2; /* Rev C or later */ + return 1; /* earlier revision */ +} + +/* + * On rev. C we need to set the pause threshold + */ +static void mcs7830_rev_C_fixup(struct usbnet *dev) +{ + u8 pause_threshold = HIF_REG_PAUSE_THRESHOLD_DEFAULT; + int retry; + + for (retry = 0; retry < 2; retry++) { + if (mcs7830_get_rev(dev) == 2) { + dev_info(&dev->udev->dev, "applying rev.C fixup\n"); + mcs7830_set_reg(dev, HIF_REG_PAUSE_THRESHOLD, + 1, &pause_threshold); + } + msleep(1); + } +} + +static int mcs7830_init_dev(struct usbnet *dev) +{ + int ret; + int retry; + + /* Read MAC address from EEPROM */ + ret = -EINVAL; + for (retry = 0; retry < 5 && ret; retry++) + ret = mcs7830_get_address(dev); + if (ret) { + dev_warn(&dev->udev->dev, "Cannot read MAC address\n"); + goto out; + } + + /* Set up PHY */ + ret = mcs7830_set_autoneg(dev, 0); + if (ret) { + dev_info(&dev->udev->dev, "Cannot set autoneg\n"); + goto out; + } + + mcs7830_rev_C_fixup(dev); + ret = 0; +out: + return ret; +} + +static int mcs7830_mdio_read(struct net_device *netdev, int phy_id, + int location) +{ + struct usbnet *dev = netdev->priv; + return mcs7830_read_phy(dev, location); +} + +static void mcs7830_mdio_write(struct net_device *netdev, int phy_id, + int location, int val) +{ + struct usbnet *dev = netdev->priv; + mcs7830_write_phy(dev, location, val); +} + +static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd) +{ + struct usbnet *dev = netdev_priv(net); + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); +} + +/* credits go to asix_set_multicast */ +static void mcs7830_set_multicast(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + struct mcs7830_data *data = (struct mcs7830_data *)&dev->data; + + data->config = HIF_REG_CONFIG_TXENABLE; + + /* this should not be needed, but it doesn't work otherwise */ + data->config |= HIF_REG_CONFIG_ALLMULTICAST; + + if (net->flags & IFF_PROMISC) { + data->config |= HIF_REG_CONFIG_PROMISCIOUS; + } else if (net->flags & IFF_ALLMULTI + || net->mc_count > MCS7830_MAX_MCAST) { + data->config |= HIF_REG_CONFIG_ALLMULTICAST; + } else if (net->mc_count == 0) { + /* just broadcast and directed */ + } else { + /* We use the 20 byte dev->data + * for our 8 byte filter buffer + * to avoid allocating memory that + * is tricky to free later */ + struct dev_mc_list *mc_list = net->mc_list; + u32 crc_bits; + int i; + + memset(data->multi_filter, 0, sizeof data->multi_filter); + + /* Build the multicast hash filter. */ + for (i = 0; i < net->mc_count; i++) { + crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26; + data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7); + mc_list = mc_list->next; + } + + mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH, + sizeof data->multi_filter, + data->multi_filter); + } + + mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config); +} + +static int mcs7830_get_regs_len(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + switch (mcs7830_get_rev(dev)) { + case 1: + return 21; + case 2: + return 32; + } + return 0; +} + +static void mcs7830_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *drvinfo) +{ + usbnet_get_drvinfo(net, drvinfo); + drvinfo->regdump_len = mcs7830_get_regs_len(net); +} + +static void mcs7830_get_regs(struct net_device *net, struct ethtool_regs *regs, void *data) +{ + struct usbnet *dev = netdev_priv(net); + + regs->version = mcs7830_get_rev(dev); + mcs7830_get_reg(dev, 0, regs->len, data); +} + +static struct ethtool_ops mcs7830_ethtool_ops = { + .get_drvinfo = mcs7830_get_drvinfo, + .get_regs_len = mcs7830_get_regs_len, + .get_regs = mcs7830_get_regs, + + /* common usbnet calls */ + .get_link = usbnet_get_link, + .get_msglevel = usbnet_get_msglevel, + .set_msglevel = usbnet_set_msglevel, + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, + .nway_reset = usbnet_nway_reset, +}; + +static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev) +{ + struct net_device *net = dev->net; + int ret; + + ret = mcs7830_init_dev(dev); + if (ret) + goto out; + + net->do_ioctl = mcs7830_ioctl; + net->ethtool_ops = &mcs7830_ethtool_ops; + net->set_multicast_list = mcs7830_set_multicast; + mcs7830_set_multicast(net); + + /* reserve space for the status byte on rx */ + dev->rx_urb_size = ETH_FRAME_LEN + 1; + + dev->mii.mdio_read = mcs7830_mdio_read; + dev->mii.mdio_write = mcs7830_mdio_write; + dev->mii.dev = net; + dev->mii.phy_id_mask = 0x3f; + dev->mii.reg_num_mask = 0x1f; + dev->mii.phy_id = *((u8 *) net->dev_addr + 1); + + ret = usbnet_get_endpoints(dev, udev); +out: + return ret; +} + +/* The chip always appends a status bytes that we need to strip */ +static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + u8 status; + + if (skb->len == 0) { + dev_err(&dev->udev->dev, "unexpected empty rx frame\n"); + return 0; + } + + skb_trim(skb, skb->len - 1); + status = skb->data[skb->len]; + + if (status != 0x20) + dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status); + + return skb->len > 0; +} + +static const struct driver_info moschip_info = { + .description = "MOSCHIP 7830 usb-NET adapter", + .bind = mcs7830_bind, + .rx_fixup = mcs7830_rx_fixup, + .flags = FLAG_ETHER, + .in = 1, + .out = 2, +}; + +static const struct usb_device_id products[] = { + { + USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID), + .driver_info = (unsigned long) &moschip_info, + }, + {}, +}; +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver mcs7830_driver = { + .name = driver_name, + .id_table = products, + .probe = usbnet_probe, + .disconnect = usbnet_disconnect, + .suspend = usbnet_suspend, + .resume = usbnet_resume, +}; + +static int __init mcs7830_init(void) +{ + return usb_register(&mcs7830_driver); +} +module_init(mcs7830_init); + +static void __exit mcs7830_exit(void) +{ + usb_deregister(&mcs7830_driver); +} +module_exit(mcs7830_exit); + +MODULE_DESCRIPTION("USB to network adapter MCS7830)"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/net/net1080.c b/drivers/usb/net/net1080.c index ce00de8f13a1..493635954513 100644 --- a/drivers/usb/net/net1080.c +++ b/drivers/usb/net/net1080.c @@ -237,12 +237,12 @@ static inline void nc_dump_usbctl(struct usbnet *dev, u16 usbctl) #define STATUS_CONN_OTHER (1 << 14) #define STATUS_SUSPEND_OTHER (1 << 13) #define STATUS_MAILBOX_OTHER (1 << 12) -#define STATUS_PACKETS_OTHER(n) (((n) >> 8) && 0x03) +#define STATUS_PACKETS_OTHER(n) (((n) >> 8) & 0x03) #define STATUS_CONN_THIS (1 << 6) #define STATUS_SUSPEND_THIS (1 << 5) #define STATUS_MAILBOX_THIS (1 << 4) -#define STATUS_PACKETS_THIS(n) (((n) >> 0) && 0x03) +#define STATUS_PACKETS_THIS(n) (((n) >> 0) & 0x03) #define STATUS_UNSPEC_MASK 0x0c8c #define STATUS_NOISE_MASK ((u16)~(0x0303|STATUS_UNSPEC_MASK)) @@ -383,7 +383,7 @@ static void nc_ensure_sync(struct usbnet *dev) int status; /* Send a flush */ - urb = usb_alloc_urb(0, SLAB_ATOMIC); + urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) return; diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index 33abbd2176b6..d48c024cff59 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -163,6 +163,7 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size, /* using ATOMIC, we'd never wake up if we slept */ if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) { + set_current_state(TASK_RUNNING); if (ret == -ENODEV) netif_device_detach(pegasus->net); if (netif_msg_drv(pegasus)) @@ -855,7 +856,7 @@ static void intr_callback(struct urb *urb) pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4]; } - status = usb_submit_urb(urb, SLAB_ATOMIC); + status = usb_submit_urb(urb, GFP_ATOMIC); if (status == -ENODEV) netif_device_detach(pegasus->net); if (status && netif_msg_timer(pegasus)) @@ -1280,9 +1281,9 @@ static inline void setup_pegasus_II(pegasus_t * pegasus) static struct workqueue_struct *pegasus_workqueue = NULL; #define CARRIER_CHECK_DELAY (2 * HZ) -static void check_carrier(void *data) +static void check_carrier(struct work_struct *work) { - pegasus_t *pegasus = data; + pegasus_t *pegasus = container_of(work, pegasus_t, carrier_check.work); set_carrier(pegasus->net); if (!(pegasus->flags & PEGASUS_UNPLUG)) { queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, @@ -1318,7 +1319,7 @@ static int pegasus_probe(struct usb_interface *intf, tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long) pegasus); - INIT_WORK(&pegasus->carrier_check, check_carrier, pegasus); + INIT_DELAYED_WORK(&pegasus->carrier_check, check_carrier); pegasus->intf = intf; pegasus->usb = dev; diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h index 006438069b66..98f6898cae1f 100644 --- a/drivers/usb/net/pegasus.h +++ b/drivers/usb/net/pegasus.h @@ -95,7 +95,7 @@ typedef struct pegasus { int dev_index; int intr_interval; struct tasklet_struct rx_tl; - struct work_struct carrier_check; + struct delayed_work carrier_check; struct urb *ctrl_urb, *rx_urb, *tx_urb, *intr_urb; struct sk_buff *rx_pool[RX_SKBS]; struct sk_buff *rx_skb; diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c index c2a28d88ef3c..99f26b3e502f 100644 --- a/drivers/usb/net/rndis_host.c +++ b/drivers/usb/net/rndis_host.c @@ -469,7 +469,7 @@ static void rndis_unbind(struct usbnet *dev, struct usb_interface *intf) struct rndis_halt *halt; /* try to clear any rndis state/activity (no i/o from stack!) */ - halt = kcalloc(1, sizeof *halt, SLAB_KERNEL); + halt = kcalloc(1, sizeof *halt, GFP_KERNEL); if (halt) { halt->msg_type = RNDIS_MSG_HALT; halt->msg_len = ccpu2(sizeof *halt); diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c index 72171f94ded4..c54235f73cb6 100644 --- a/drivers/usb/net/rtl8150.c +++ b/drivers/usb/net/rtl8150.c @@ -587,7 +587,7 @@ static void intr_callback(struct urb *urb) } resubmit: - status = usb_submit_urb (urb, SLAB_ATOMIC); + status = usb_submit_urb (urb, GFP_ATOMIC); if (status == -ENODEV) netif_device_detach(dev->netdev); else if (status) diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c index 24bd3486ee63..6e39e9988259 100644 --- a/drivers/usb/net/usbnet.c +++ b/drivers/usb/net/usbnet.c @@ -116,7 +116,7 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) e = alt->endpoint + ep; switch (e->desc.bmAttributes) { case USB_ENDPOINT_XFER_INT: - if (!(e->desc.bEndpointAddress & USB_DIR_IN)) + if (!usb_endpoint_dir_in(&e->desc)) continue; intr = 1; /* FALLTHROUGH */ @@ -125,7 +125,7 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf) default: continue; } - if (e->desc.bEndpointAddress & USB_DIR_IN) { + if (usb_endpoint_dir_in(&e->desc)) { if (!intr && !in) in = e; else if (intr && !status) @@ -179,9 +179,9 @@ static int init_status (struct usbnet *dev, struct usb_interface *intf) period = max ((int) dev->status->desc.bInterval, (dev->udev->speed == USB_SPEED_HIGH) ? 7 : 3); - buf = kmalloc (maxp, SLAB_KERNEL); + buf = kmalloc (maxp, GFP_KERNEL); if (buf) { - dev->interrupt = usb_alloc_urb (0, SLAB_KERNEL); + dev->interrupt = usb_alloc_urb (0, GFP_KERNEL); if (!dev->interrupt) { kfree (buf); return -ENOMEM; @@ -554,7 +554,7 @@ static int usbnet_stop (struct net_device *net) { struct usbnet *dev = netdev_priv(net); int temp; - DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK (unlink_wakeup); DECLARE_WAITQUEUE (wait, current); netif_stop_queue (net); @@ -669,20 +669,40 @@ done: * they'll probably want to use this base set. */ -void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) +#if defined(CONFIG_MII) || defined(CONFIG_MII_MODULE) +#define HAVE_MII + +int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd) { struct usbnet *dev = netdev_priv(net); - /* REVISIT don't always return "usbnet" */ - strncpy (info->driver, driver_name, sizeof info->driver); - strncpy (info->version, DRIVER_VERSION, sizeof info->version); - strncpy (info->fw_version, dev->driver_info->description, - sizeof info->fw_version); - usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info); + if (!dev->mii.mdio_read) + return -EOPNOTSUPP; + + return mii_ethtool_gset(&dev->mii, cmd); } -EXPORT_SYMBOL_GPL(usbnet_get_drvinfo); +EXPORT_SYMBOL_GPL(usbnet_get_settings); + +int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd) +{ + struct usbnet *dev = netdev_priv(net); + int retval; + + if (!dev->mii.mdio_write) + return -EOPNOTSUPP; -static u32 usbnet_get_link (struct net_device *net) + retval = mii_ethtool_sset(&dev->mii, cmd); + + /* link speed/duplex might have changed */ + if (dev->driver_info->link_reset) + dev->driver_info->link_reset(dev); + + return retval; + +} +EXPORT_SYMBOL_GPL(usbnet_set_settings); + +u32 usbnet_get_link (struct net_device *net) { struct usbnet *dev = netdev_priv(net); @@ -690,9 +710,40 @@ static u32 usbnet_get_link (struct net_device *net) if (dev->driver_info->check_connect) return dev->driver_info->check_connect (dev) == 0; + /* if the device has mii operations, use those */ + if (dev->mii.mdio_read) + return mii_link_ok(&dev->mii); + /* Otherwise, say we're up (to avoid breaking scripts) */ return 1; } +EXPORT_SYMBOL_GPL(usbnet_get_link); + +int usbnet_nway_reset(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + if (!dev->mii.mdio_write) + return -EOPNOTSUPP; + + return mii_nway_restart(&dev->mii); +} +EXPORT_SYMBOL_GPL(usbnet_nway_reset); + +#endif /* HAVE_MII */ + +void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info) +{ + struct usbnet *dev = netdev_priv(net); + + /* REVISIT don't always return "usbnet" */ + strncpy (info->driver, driver_name, sizeof info->driver); + strncpy (info->version, DRIVER_VERSION, sizeof info->version); + strncpy (info->fw_version, dev->driver_info->description, + sizeof info->fw_version); + usb_make_path (dev->udev, info->bus_info, sizeof info->bus_info); +} +EXPORT_SYMBOL_GPL(usbnet_get_drvinfo); u32 usbnet_get_msglevel (struct net_device *net) { @@ -712,8 +763,13 @@ EXPORT_SYMBOL_GPL(usbnet_set_msglevel); /* drivers may override default ethtool_ops in their bind() routine */ static struct ethtool_ops usbnet_ethtool_ops = { - .get_drvinfo = usbnet_get_drvinfo, +#ifdef HAVE_MII + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, .get_link = usbnet_get_link, + .nway_reset = usbnet_nway_reset, +#endif + .get_drvinfo = usbnet_get_drvinfo, .get_msglevel = usbnet_get_msglevel, .set_msglevel = usbnet_set_msglevel, }; @@ -726,9 +782,10 @@ static struct ethtool_ops usbnet_ethtool_ops = { * especially now that control transfers can be queued. */ static void -kevent (void *data) +kevent (struct work_struct *work) { - struct usbnet *dev = data; + struct usbnet *dev = + container_of(work, struct usbnet, kevent); int status; /* usb_clear_halt() needs a thread context */ @@ -1090,10 +1147,11 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) skb_queue_head_init (&dev->done); dev->bh.func = usbnet_bh; dev->bh.data = (unsigned long) dev; - INIT_WORK (&dev->kevent, kevent, dev); + INIT_WORK (&dev->kevent, kevent); dev->delay.function = usbnet_bh; dev->delay.data = (unsigned long) dev; init_timer (&dev->delay); + mutex_init (&dev->phy_mutex); SET_MODULE_OWNER (net); dev->net = net; @@ -1225,7 +1283,7 @@ EXPORT_SYMBOL_GPL(usbnet_resume); static int __init usbnet_init(void) { /* compiler should optimize this out */ - BUG_ON (sizeof (((struct sk_buff *)0)->cb) + BUILD_BUG_ON (sizeof (((struct sk_buff *)0)->cb) < sizeof (struct skb_data)); random_ether_addr(node_id); diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h index c0746f0454af..07c70abbe0ec 100644 --- a/drivers/usb/net/usbnet.h +++ b/drivers/usb/net/usbnet.h @@ -30,6 +30,7 @@ struct usbnet { struct usb_device *udev; struct driver_info *driver_info; wait_queue_head_t *wait; + struct mutex phy_mutex; /* i/o info: pipes etc */ unsigned in, out; @@ -168,9 +169,13 @@ extern void usbnet_defer_kevent (struct usbnet *, int); extern void usbnet_skb_return (struct usbnet *, struct sk_buff *); extern void usbnet_unlink_rx_urbs(struct usbnet *); +extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd); +extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd); +extern u32 usbnet_get_link (struct net_device *net); extern u32 usbnet_get_msglevel (struct net_device *); extern void usbnet_set_msglevel (struct net_device *, u32); extern void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *); +extern int usbnet_nway_reset(struct net_device *net); /* messaging support includes the interface name, so it must not be * used before it has one ... notably, in minidriver bind() calls. diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 5076b9d97057..2f4d303ee36f 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -54,10 +54,10 @@ config USB_SERIAL_GENERIC properly. config USB_SERIAL_AIRCABLE - tristate "AIRcable USB Bluetooth Dongle Driver (EXPERIMENTAL)" + tristate "USB AIRcable Bluetooth Dongle Driver (EXPERIMENTAL)" depends on USB_SERIAL && EXPERIMENTAL help - Say Y here if you want to use AIRcable USB Bluetoot Dongle. + Say Y here if you want to use USB AIRcable Bluetooth Dongle. To compile this driver as a module, choose M here: the module will be called aircable. @@ -422,6 +422,16 @@ config USB_SERIAL_MCT_U232 To compile this driver as a module, choose M here: the module will be called mct_u232. +config USB_SERIAL_MOS7720 + tristate "USB Moschip 7720 Single Port Serial Driver" + depends on USB_SERIAL + ---help--- + Say Y here if you want to use a USB Serial single port adapter from + Moschip Semiconductor Tech. + + To compile this driver as a module, choose M here: the + module will be called mos7720. + config USB_SERIAL_MOS7840 tristate "USB Moschip 7840/7820 USB Serial Driver" depends on USB_SERIAL @@ -527,8 +537,7 @@ config USB_SERIAL_OPTION The USB bus on these cards is not accessible externally. Supported devices include (some of?) those made by: - Option, Huawei, Audiovox, Sierra Wireless, Novatel Wireless, or - Anydata. + Option, Huawei, Audiovox, Novatel Wireless, or Anydata. To compile this driver as a module, choose M here: the module will be called option. @@ -545,6 +554,17 @@ config USB_SERIAL_OMNINET To compile this driver as a module, choose M here: the module will be called omninet. +config USB_SERIAL_DEBUG + tristate "USB Debugging Device" + depends on USB_SERIAL + help + Say Y here if you have a USB debugging device used to recieve + debugging data from another machine. The most common of these + devices is the NetChip TurboCONNECT device. + + To compile this driver as a module, choose M here: the + module will be called usb-debug. + config USB_EZUSB bool depends on USB_SERIAL_KEYSPAN_PDA || USB_SERIAL_XIRCOM || USB_SERIAL_KEYSPAN || USB_SERIAL_WHITEHEAT diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 8dce83340e31..61166ad450e6 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o obj-$(CONFIG_USB_SERIAL_CP2101) += cp2101.o obj-$(CONFIG_USB_SERIAL_CYBERJACK) += cyberjack.o obj-$(CONFIG_USB_SERIAL_CYPRESS_M8) += cypress_m8.o +obj-$(CONFIG_USB_SERIAL_DEBUG) += usb_debug.o obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT) += digi_acceleport.o obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += io_ti.o @@ -34,6 +35,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o +obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index 812275509137..86bcf63b6ba5 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -92,6 +92,7 @@ struct aircable_private { struct circ_buf *rx_buf; /* read buffer */ int rx_flags; /* for throttilng */ struct work_struct rx_work; /* work cue for the receiving line */ + struct usb_serial_port *port; /* USB port with which associated */ }; /* Private methods */ @@ -251,10 +252,11 @@ static void aircable_send(struct usb_serial_port *port) schedule_work(&port->work); } -static void aircable_read(void *params) +static void aircable_read(struct work_struct *work) { - struct usb_serial_port *port = params; - struct aircable_private *priv = usb_get_serial_port_data(port); + struct aircable_private *priv = + container_of(work, struct aircable_private, rx_work); + struct usb_serial_port *port = priv->port; struct tty_struct *tty; unsigned char *data; int count; @@ -270,8 +272,11 @@ static void aircable_read(void *params) */ tty = port->tty; - if (!tty) + if (!tty) { schedule_work(&priv->rx_work); + err("%s - No tty available", __FUNCTION__); + return ; + } count = min(64, serial_buf_data_avail(priv->rx_buf)); @@ -305,9 +310,7 @@ static int aircable_probe(struct usb_serial *serial, for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { endpoint = &iface_desc->endpoint[i].desc; - if (((endpoint->bEndpointAddress & 0x80) == 0x00) && - ((endpoint->bmAttributes & 3) == 0x02)) { - /* we found our bulk out endpoint */ + if (usb_endpoint_is_bulk_out(endpoint)) { dbg("found bulk out on endpoint %d", i); ++num_bulk_out; } @@ -348,7 +351,8 @@ static int aircable_attach (struct usb_serial *serial) } priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED); - INIT_WORK(&priv->rx_work, aircable_read, port); + priv->port = port; + INIT_WORK(&priv->rx_work, aircable_read); usb_set_serial_port_data(serial->port[0], priv); @@ -515,7 +519,7 @@ static void aircable_read_bulk_callback(struct urb *urb) package_length - shift); } } - aircable_read(port); + aircable_read(&priv->rx_work); } /* Schedule the next read _if_ we are still open */ diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c index 2c19f19b255c..96c73726d74a 100644 --- a/drivers/usb/serial/airprime.c +++ b/drivers/usb/serial/airprime.c @@ -18,12 +18,9 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */ - { USB_DEVICE(0x0f3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */ - { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ - { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ - { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */ - { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */ + { USB_DEVICE(0x1410, 0x1430) }, /* Novatel Merlin XU870 HSDPA/3G */ + { USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */ { }, }; MODULE_DEVICE_TABLE(usb, id_table); @@ -133,6 +130,7 @@ static int airprime_open(struct usb_serial_port *port, struct file *filp) } urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) { + kfree(buffer); dev_err(&port->dev, "%s - no more urbs?\n", __FUNCTION__); result = -ENOMEM; diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index ca52f12f0e24..5261cd22ee6b 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -85,10 +85,9 @@ static int ark3116_attach(struct usb_serial *serial) int i; for (i = 0; i < serial->num_ports; ++i) { - priv = kmalloc(sizeof (struct ark3116_private), GFP_KERNEL); + priv = kzalloc(sizeof(struct ark3116_private), GFP_KERNEL); if (!priv) goto cleanup; - memset(priv, 0x00, sizeof (struct ark3116_private)); spin_lock_init(&priv->lock); usb_set_serial_port_data(serial->port[i], priv); @@ -157,7 +156,7 @@ cleanup: } static void ark3116_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct ark3116_private *priv = usb_get_serial_port_data(port); @@ -327,7 +326,7 @@ static void ark3116_set_termios(struct usb_serial_port *port, static int ark3116_open(struct usb_serial_port *port, struct file *filp) { - struct termios tmp_termios; + struct ktermios tmp_termios; struct usb_serial *serial = port->serial; char *buf; int result = 0; diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index 8835bb58ca9b..38b4dae319ee 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -92,7 +92,7 @@ static void belkin_sa_shutdown (struct usb_serial *serial); static int belkin_sa_open (struct usb_serial_port *port, struct file *filp); static void belkin_sa_close (struct usb_serial_port *port, struct file *filp); static void belkin_sa_read_int_callback (struct urb *urb); -static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios * old); +static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios * old); static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); static void belkin_sa_break_ctl (struct usb_serial_port *port, int break_state ); static int belkin_sa_tiocmget (struct usb_serial_port *port, struct file *file); @@ -333,7 +333,7 @@ exit: __FUNCTION__, retval); } -static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct belkin_sa_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 3a9073dbfe6a..9386e216d681 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -65,7 +65,7 @@ static int usb_console_setup(struct console *co, char *options) struct usb_serial_port *port; int retval = 0; struct tty_struct *tty; - struct termios *termios; + struct ktermios *termios; dbg ("%s", __FUNCTION__); @@ -166,19 +166,17 @@ static int usb_console_setup(struct console *co, char *options) if (serial->type->set_termios) { /* build up a fake tty structure so that the open call has something * to look at to get the cflag value */ - tty = kmalloc (sizeof (*tty), GFP_KERNEL); + tty = kzalloc(sizeof(*tty), GFP_KERNEL); if (!tty) { err ("no more memory"); return -ENOMEM; } - termios = kmalloc (sizeof (*termios), GFP_KERNEL); + termios = kzalloc(sizeof(*termios), GFP_KERNEL); if (!termios) { err ("no more memory"); kfree (tty); return -ENOMEM; } - memset (tty, 0x00, sizeof(*tty)); - memset (termios, 0x00, sizeof(*termios)); termios->c_cflag = cflag; tty->termios = termios; port->tty = tty; diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c index 486c7411b9a7..2f9b7ac32663 100644 --- a/drivers/usb/serial/cp2101.c +++ b/drivers/usb/serial/cp2101.c @@ -41,7 +41,7 @@ static int cp2101_open(struct usb_serial_port*, struct file*); static void cp2101_cleanup(struct usb_serial_port*); static void cp2101_close(struct usb_serial_port*, struct file*); static void cp2101_get_termios(struct usb_serial_port*); -static void cp2101_set_termios(struct usb_serial_port*, struct termios*); +static void cp2101_set_termios(struct usb_serial_port*, struct ktermios*); static int cp2101_tiocmget (struct usb_serial_port *, struct file *); static int cp2101_tiocmset (struct usb_serial_port *, struct file *, unsigned int, unsigned int); @@ -64,7 +64,11 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(0x10C4, 0x80F6) }, /* Suunto sports instrument */ { USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */ { USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */ + { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */ + { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */ + { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */ { USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */ + { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */ { USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */ { } /* Terminating Entry */ }; @@ -502,7 +506,7 @@ static void cp2101_get_termios (struct usb_serial_port *port) } static void cp2101_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { unsigned int cflag, old_cflag=0; int baud=0, bits; diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index f2e89a083659..a1fdb85b8c0a 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -143,7 +143,7 @@ struct cypress_private { wait_queue_head_t delta_msr_wait; /* used for TIOCMIWAIT */ char prev_status, diff_status; /* used for TIOCMIWAIT */ /* we pass a pointer to this as the arguement sent to cypress_set_termios old_termios */ - struct termios tmp_termios; /* stores the old termios settings */ + struct ktermios tmp_termios; /* stores the old termios settings */ }; /* write buffer structure */ @@ -165,7 +165,7 @@ static int cypress_write (struct usb_serial_port *port, const unsigned char *b static void cypress_send (struct usb_serial_port *port); static int cypress_write_room (struct usb_serial_port *port); static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); -static void cypress_set_termios (struct usb_serial_port *port, struct termios * old); +static void cypress_set_termios (struct usb_serial_port *port, struct ktermios * old); static int cypress_tiocmget (struct usb_serial_port *port, struct file *file); static int cypress_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); static int cypress_chars_in_buffer (struct usb_serial_port *port); @@ -949,13 +949,13 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi switch (cmd) { case TIOCGSERIAL: - if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct termios))) { + if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct ktermios))) { return -EFAULT; } return (0); break; case TIOCSSERIAL: - if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct termios))) { + if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct ktermios))) { return -EFAULT; } /* here we need to call cypress_set_termios to invoke the new settings */ @@ -1019,7 +1019,7 @@ static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsi static void cypress_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct cypress_private *priv = usb_get_serial_port_data(port); struct tty_struct *tty; @@ -1684,15 +1684,14 @@ static int __init cypress_init(void) info(DRIVER_DESC " " DRIVER_VERSION); return 0; + failed_usb_register: - usb_deregister(&cypress_driver); -failed_ca42v2_register: usb_serial_deregister(&cypress_ca42v2_device); -failed_hidcom_register: +failed_ca42v2_register: usb_serial_deregister(&cypress_hidcom_device); -failed_em_register: +failed_hidcom_register: usb_serial_deregister(&cypress_earthmate_device); - +failed_em_register: return retval; } diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index bdb58100fc1d..9d9ea874639c 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -157,7 +157,7 @@ * to TASK_RUNNING will be lost and write_chan's subsequent call to * schedule() will never return (unless it catches a signal). * This race condition occurs because write_bulk_callback() (and thus -* the wakeup) are called asynchonously from an interrupt, rather than +* the wakeup) are called asynchronously from an interrupt, rather than * from the scheduler. We can avoid the race by calling the wakeup * from the scheduler queue and that's our fix: Now, at the end of * write_bulk_callback() we queue up a wakeup call on the scheduler @@ -430,13 +430,14 @@ struct digi_port { int dp_in_close; /* close in progress */ wait_queue_head_t dp_close_wait; /* wait queue for close */ struct work_struct dp_wakeup_work; + struct usb_serial_port *dp_port; }; /* Local Function Declarations */ static void digi_wakeup_write( struct usb_serial_port *port ); -static void digi_wakeup_write_lock(void *); +static void digi_wakeup_write_lock(struct work_struct *work); static int digi_write_oob_command( struct usb_serial_port *port, unsigned char *buf, int count, int interruptible ); static int digi_write_inb_command( struct usb_serial_port *port, @@ -448,7 +449,7 @@ static int digi_transmit_idle( struct usb_serial_port *port, static void digi_rx_throttle (struct usb_serial_port *port); static void digi_rx_unthrottle (struct usb_serial_port *port); static void digi_set_termios( struct usb_serial_port *port, - struct termios *old_termios ); + struct ktermios *old_termios ); static void digi_break_ctl( struct usb_serial_port *port, int break_state ); static int digi_ioctl( struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg ); @@ -598,11 +599,12 @@ static inline long cond_wait_interruptible_timeout_irqrestore( * on writes. */ -static void digi_wakeup_write_lock(void *arg) +static void digi_wakeup_write_lock(struct work_struct *work) { - struct usb_serial_port *port = arg; + struct digi_port *priv = + container_of(work, struct digi_port, dp_wakeup_work); + struct usb_serial_port *port = priv->dp_port; unsigned long flags; - struct digi_port *priv = usb_get_serial_port_data(port); spin_lock_irqsave( &priv->dp_port_lock, flags ); @@ -974,7 +976,7 @@ dbg( "digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num ); static void digi_set_termios( struct usb_serial_port *port, - struct termios *old_termios ) + struct ktermios *old_termios ) { struct digi_port *priv = usb_get_serial_port_data(port); @@ -1461,7 +1463,7 @@ static int digi_open( struct usb_serial_port *port, struct file *filp ) int ret; unsigned char buf[32]; struct digi_port *priv = usb_get_serial_port_data(port); - struct termios not_termios; + struct ktermios not_termios; unsigned long flags = 0; @@ -1702,8 +1704,8 @@ dbg( "digi_startup: TOP" ); init_waitqueue_head( &priv->dp_flush_wait ); priv->dp_in_close = 0; init_waitqueue_head( &priv->dp_close_wait ); - INIT_WORK(&priv->dp_wakeup_work, - digi_wakeup_write_lock, serial->port[i]); + INIT_WORK(&priv->dp_wakeup_work, digi_wakeup_write_lock); + priv->dp_port = serial->port[i]; /* initialize write wait queue for this port */ init_waitqueue_head( &serial->port[i]->write_wait ); diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 4ce10a831953..92beeb19795f 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -92,7 +92,7 @@ static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); -static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static void empeg_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static void empeg_write_bulk_callback (struct urb *urb); static void empeg_read_bulk_callback (struct urb *urb); @@ -442,7 +442,7 @@ static int empeg_ioctl (struct usb_serial_port *port, struct file * file, unsign } -static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void empeg_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { dbg("%s - port %d", __FUNCTION__, port->number); diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c index 5169c2d154ab..97ee718b1da2 100644 --- a/drivers/usb/serial/ezusb.c +++ b/drivers/usb/serial/ezusb.c @@ -31,12 +31,11 @@ int ezusb_writememory (struct usb_serial *serial, int address, unsigned char *da return -ENODEV; } - transfer_buffer = kmalloc (length, GFP_KERNEL); + transfer_buffer = kmemdup(data, length, GFP_KERNEL); if (!transfer_buffer) { dev_err(&serial->dev->dev, "%s - kmalloc(%d) failed.\n", __FUNCTION__, length); return -ENOMEM; } - memcpy (transfer_buffer, data, length); result = usb_control_msg (serial->dev, usb_sndctrlpipe(serial->dev, 0), bRequest, 0x40, address, 0, transfer_buffer, length, 3000); kfree (transfer_buffer); return result; diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index d3dc1a15ec6c..41b0ad2d56ac 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1,16 +1,16 @@ /* * USB FTDI SIO driver * - * Copyright (C) 1999 - 2001 - * Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 1999 - 2001 + * Greg Kroah-Hartman (greg@kroah.com) * Bill Ryder (bryder@sgi.com) * Copyright (C) 2002 * Kuba Ober (kuba@mareimbrium.org) * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * * See Documentation/usb/usb-serial.txt for more information on using this driver * @@ -32,7 +32,7 @@ * Changed full name of USB-UIRT device to avoid "/" character. * Added FTDI's alternate PID (0x6006) for FT232/245 devices. * Added PID for "ELV USB Module UO100" from Stefan Frings. - * + * * (21/Oct/2003) Ian Abbott * Renamed some VID/PID macros for Matrix Orbital and Perle Systems * devices. Removed Matrix Orbital and Perle Systems devices from the @@ -69,7 +69,7 @@ * does not incure any measurable overhead. This also relies on the fact * that we have proper reference counting logic for urbs. I nicked this * from Greg KH's Visor driver. - * + * * (23/Jun/2003) Ian Abbott * Reduced flip buffer pushes and corrected a data length test in * ftdi_read_bulk_callback. @@ -77,7 +77,7 @@ * * (21/Jun/2003) Erik Nygren * Added support for Home Electronics Tira-1 IR transceiver using FT232BM chip. - * See <http://www.home-electro.com/tira1.htm>. Only operates properly + * See <http://www.home-electro.com/tira1.htm>. Only operates properly * at 100000 and RTS-CTS, so set custom divisor mode on startup. * Also force the Tira-1 and USB-UIRT to only use their custom baud rates. * @@ -137,17 +137,17 @@ * (17/Feb/2003) Bill Ryder * Added write urb buffer pool on a per device basis * Added more checking for open file on callbacks (fixed OOPS) - * Added CrystalFontz 632 and 634 PIDs + * Added CrystalFontz 632 and 634 PIDs * (thanx to CrystalFontz for the sample devices - they flushed out * some driver bugs) * Minor debugging message changes * Added throttle, unthrottle and chars_in_buffer functions * Fixed FTDI_SIO (the original device) bug * Fixed some shutdown handling - * - * - * - * + * + * + * + * * (07/Jun/2002) Kuba Ober * Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor * function. It was getting too complex. @@ -158,7 +158,7 @@ * * (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch * Not tested by me but it doesn't break anything I use. - * + * * (04/Jan/2002) Kuba Ober * Implemented 38400 baudrate kludge, where it can be substituted with other * values. That's the only way to set custom baudrates. @@ -179,7 +179,7 @@ * (the previous version caused panics) * Removed port iteration code since the device only has one I/O port and it * was wrong anyway. - * + * * (31/May/2001) gkh * Switched from using spinlock to a semaphore, which fixes lots of problems. * @@ -188,16 +188,16 @@ * Cleaned up comments for 8U232 * Added parity, framing and overrun error handling * Added receive break handling. - * + * * (04/08/2001) gb * Identify version on module load. - * + * * (18/March/2001) Bill Ryder * (Not released) * Added send break handling. (requires kernel patch too) * Fixed 8U232AM hardware RTS/CTS etc status reporting. * Added flipbuf fix copied from generic device - * + * * (12/3/2000) Bill Ryder * Added support for 8U232AM device. * Moved PID and VIDs into header file only. @@ -211,14 +211,14 @@ * Cleaned up comments. Removed multiple PID/VID definitions. * Factorised cts/dtr code * Made use of __FUNCTION__ in dbg's - * + * * (11/01/2000) Adam J. Richter * usb_device_id table support - * + * * (10/05/2000) gkh * Fixed bug with urb->dev not being set properly, now that the usb * core needs it. - * + * * (09/11/2000) gkh * Removed DEBUG #ifdefs with call to usb_serial_debug_data * @@ -226,11 +226,11 @@ * Added module_init and module_exit functions to handle the fact that this * driver is a loadable module now. * - * (04/04/2000) Bill Ryder + * (04/04/2000) Bill Ryder * Fixed bugs in TCGET/TCSET ioctls (by removing them - they are * handled elsewhere in the tty io driver chain). * - * (03/30/2000) Bill Ryder + * (03/30/2000) Bill Ryder * Implemented lots of ioctls * Fixed a race condition in write * Changed some dbg's to errs @@ -311,6 +311,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_ACTZWAVE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IRTRANS_PID) }, { USB_DEVICE(FTDI_VID, FTDI_IPLUS_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_DMX4ALL) }, { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_PID) }, { USB_DEVICE(FTDI_VID, FTDI_8U232AM_ALT_PID) }, @@ -444,13 +445,13 @@ static struct usb_device_id id_table_combined [] = { /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */ /* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */ - { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, - { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, - { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) }, - { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) }, - { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, - { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, + { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) }, + { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) }, + { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) }, { USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) }, { USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) }, { USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) }, @@ -511,6 +512,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) }, { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) }, + { USB_DEVICE(ELEKTOR_VID, ELEKTOR_FT323R_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; @@ -522,7 +524,7 @@ static struct usb_driver ftdi_driver = { .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, .id_table = id_table_combined, - .no_dynamic_id = 1, + .no_dynamic_id = 1, }; static const char *ftdi_chip_name[] = { @@ -548,16 +550,17 @@ struct ftdi_private { int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */ __u16 last_set_data_urb_value ; /* the last data state set - needed for doing a break */ - int write_offset; /* This is the offset in the usb data block to write the serial data - + int write_offset; /* This is the offset in the usb data block to write the serial data - * it is different between devices */ int flags; /* some ASYNC_xxxx flags are supported */ unsigned long last_dtr_rts; /* saved modem control outputs */ wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ - char prev_status, diff_status; /* Used for TIOCMIWAIT */ + char prev_status, diff_status; /* Used for TIOCMIWAIT */ __u8 rx_flags; /* receive state flags (throttling) */ spinlock_t rx_lock; /* spinlock for receive state */ - struct work_struct rx_work; + struct delayed_work rx_work; + struct usb_serial_port *port; int rx_processed; unsigned long rx_bytes; @@ -591,8 +594,8 @@ static int ftdi_write_room (struct usb_serial_port *port); static int ftdi_chars_in_buffer (struct usb_serial_port *port); static void ftdi_write_bulk_callback (struct urb *urb); static void ftdi_read_bulk_callback (struct urb *urb); -static void ftdi_process_read (void *param); -static void ftdi_set_termios (struct usb_serial_port *port, struct termios * old); +static void ftdi_process_read (struct work_struct *work); +static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios * old); static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file); static int ftdi_tiocmset (struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear); static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); @@ -721,7 +724,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned urb_value |= FTDI_SIO_SET_RTS_HIGH; rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), - FTDI_SIO_SET_MODEM_CTRL_REQUEST, + FTDI_SIO_SET_MODEM_CTRL_REQUEST, FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE, urb_value, priv->interface, buf, 0, WDR_TIMEOUT); @@ -768,7 +771,7 @@ static int change_speed(struct usb_serial_port *port) if (priv->interface) { /* FT2232C */ urb_index = (__u16)((urb_index << 8) | priv->interface); } - + rv = usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_BAUDRATE_REQUEST, @@ -827,7 +830,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port) /* 3. Convert baudrate to device-specific divisor */ - if (!baud) baud = 9600; + if (!baud) baud = 9600; switch(priv->chip_type) { case SIO: /* SIO chip */ switch(baud) { @@ -843,7 +846,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port) case 115200: div_value = ftdi_sio_b115200; break; } /* baud */ if (div_value == 0) { - dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud); + dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud); div_value = ftdi_sio_b9600; div_okay = 0; } @@ -925,7 +928,7 @@ static int set_serial_info(struct usb_serial_port * port, struct serial_struct _ /* Make the changes - these are privileged changes! */ priv->flags = ((priv->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); + (new_serial.flags & ASYNC_FLAGS)); priv->custom_divisor = new_serial.custom_divisor; port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0; @@ -950,7 +953,7 @@ check_and_exit: (old_priv.custom_divisor != priv->custom_divisor))) { change_speed(port); } - + return (0); } /* set_serial_info */ @@ -1022,18 +1025,18 @@ static ssize_t show_latency_timer(struct device *dev, struct device_attribute *a struct usb_device *udev; unsigned short latency = 0; int rv = 0; - + udev = to_usb_device(dev); - + dbg("%s",__FUNCTION__); - + rv = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), FTDI_SIO_GET_LATENCY_TIMER_REQUEST, FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE, - 0, priv->interface, + 0, priv->interface, (char*) &latency, 1, WDR_TIMEOUT); - + if (rv < 0) { dev_err(dev, "Unable to read latency timer: %i", rv); return -EIO; @@ -1051,23 +1054,23 @@ static ssize_t store_latency_timer(struct device *dev, struct device_attribute * char buf[1]; int v = simple_strtoul(valbuf, NULL, 10); int rv = 0; - + udev = to_usb_device(dev); - + dbg("%s: setting latency timer = %i", __FUNCTION__, v); - + rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), FTDI_SIO_SET_LATENCY_TIMER_REQUEST, FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE, - v, priv->interface, + v, priv->interface, buf, 0, WDR_TIMEOUT); - + if (rv < 0) { dev_err(dev, "Unable to write latency timer: %i", rv); return -EIO; } - + return count; } @@ -1082,23 +1085,23 @@ static ssize_t store_event_char(struct device *dev, struct device_attribute *att char buf[1]; int v = simple_strtoul(valbuf, NULL, 10); int rv = 0; - + udev = to_usb_device(dev); - + dbg("%s: setting event char = %i", __FUNCTION__, v); - + rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), FTDI_SIO_SET_EVENT_CHAR_REQUEST, FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE, - v, priv->interface, + v, priv->interface, buf, 0, WDR_TIMEOUT); - + if (rv < 0) { dbg("Unable to write event character: %i", rv); return -EIO; } - + return count; } @@ -1135,11 +1138,11 @@ static void remove_sysfs_attrs(struct usb_serial *serial) struct ftdi_private *priv; struct usb_device *udev; - dbg("%s",__FUNCTION__); + dbg("%s",__FUNCTION__); priv = usb_get_serial_port_data(serial->port[0]); udev = serial->dev; - + /* XXX see create_sysfs_attrs */ if (priv->chip_type != SIO) { device_remove_file(&udev->dev, &dev_attr_event_char); @@ -1147,7 +1150,7 @@ static void remove_sysfs_attrs(struct usb_serial *serial) device_remove_file(&udev->dev, &dev_attr_latency_timer); } } - + } /* @@ -1199,7 +1202,8 @@ static int ftdi_sio_attach (struct usb_serial *serial) port->read_urb->transfer_buffer_length = BUFSZ; } - INIT_WORK(&priv->rx_work, ftdi_process_read, port); + INIT_DELAYED_WORK(&priv->rx_work, ftdi_process_read); + priv->port = port; /* Free port's existing write urb and transfer buffer. */ if (port->write_urb) { @@ -1258,7 +1262,7 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial) } /* ftdi_HE_TIRA1_setup */ -/* ftdi_shutdown is called from usbserial:usb_serial_disconnect +/* ftdi_shutdown is called from usbserial:usb_serial_disconnect * it is called when the usb device is disconnected * * usbserial:usb_serial_disconnect @@ -1269,16 +1273,16 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial) static void ftdi_shutdown (struct usb_serial *serial) { /* ftdi_shutdown */ - + struct usb_serial_port *port = serial->port[0]; struct ftdi_private *priv = usb_get_serial_port_data(port); dbg("%s", __FUNCTION__); remove_sysfs_attrs(serial); - - /* all open ports are closed at this point - * (by usbserial.c:__serial_close, which calls ftdi_close) + + /* all open ports are closed at this point + * (by usbserial.c:__serial_close, which calls ftdi_close) */ if (priv) { @@ -1293,7 +1297,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) struct usb_device *dev = port->serial->dev; struct ftdi_private *priv = usb_get_serial_port_data(port); unsigned long flags; - + int result = 0; char buf[1]; /* Needed for the usb_control_msg I think */ @@ -1312,8 +1316,8 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) /* No error checking for this (will get errors later anyway) */ /* See ftdi_sio.h for description of what is reset */ usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, - FTDI_SIO_RESET_SIO, + FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE, + FTDI_SIO_RESET_SIO, priv->interface, buf, 0, WDR_TIMEOUT); /* Termios defaults are set by usb_serial_init. We don't change @@ -1350,12 +1354,12 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp) -/* +/* * usbserial:__serial_close only calls ftdi_close if the point is open * * This only gets called when it is the last close - * - * + * + * */ static void ftdi_close (struct usb_serial_port *port, struct file *filp) @@ -1368,14 +1372,14 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) if (c_cflag & HUPCL){ /* Disable flow control */ - if (usb_control_msg(port->serial->dev, + if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("error from flowcontrol urb"); - } + } /* drop RTS and DTR */ clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); @@ -1384,14 +1388,13 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp) /* cancel any scheduled reading */ cancel_delayed_work(&priv->rx_work); flush_scheduled_work(); - + /* shutdown our bulk read */ - if (port->read_urb) - usb_kill_urb(port->read_urb); + usb_kill_urb(port->read_urb); } /* ftdi_close */ - + /* The SIO requires the first byte to have: * B0 1 * B1 0 @@ -1423,7 +1426,7 @@ static int ftdi_write (struct usb_serial_port *port, return 0; } spin_unlock_irqrestore(&priv->tx_lock, flags); - + data_offset = priv->write_offset; dbg("data_offset set to %d",data_offset); @@ -1462,7 +1465,7 @@ static int ftdi_write (struct usb_serial_port *port, user_pktsz = todo; } /* Write the control byte at the front of the packet*/ - *first_byte = 1 | ((user_pktsz) << 2); + *first_byte = 1 | ((user_pktsz) << 2); /* Copy data for packet */ memcpy (first_byte + data_offset, current_position, user_pktsz); @@ -1479,7 +1482,7 @@ static int ftdi_write (struct usb_serial_port *port, usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, buffer); /* fill the buffer and send it */ - usb_fill_bulk_urb(urb, port->serial->dev, + usb_fill_bulk_urb(urb, port->serial->dev, usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress), buffer, transfer_size, ftdi_write_bulk_callback, port); @@ -1520,7 +1523,7 @@ static void ftdi_write_bulk_callback (struct urb *urb) kfree (urb->transfer_buffer); dbg("%s - port %d", __FUNCTION__, port->number); - + if (urb->status) { dbg("nonzero write bulk status received: %d", urb->status); return; @@ -1639,19 +1642,20 @@ static void ftdi_read_bulk_callback (struct urb *urb) priv->rx_bytes += countread; spin_unlock_irqrestore(&priv->rx_lock, flags); - ftdi_process_read(port); + ftdi_process_read(&priv->rx_work.work); } /* ftdi_read_bulk_callback */ -static void ftdi_process_read (void *param) +static void ftdi_process_read (struct work_struct *work) { /* ftdi_process_read */ - struct usb_serial_port *port = (struct usb_serial_port*)param; + struct ftdi_private *priv = + container_of(work, struct ftdi_private, rx_work.work); + struct usb_serial_port *port = priv->port; struct urb *urb; struct tty_struct *tty; - struct ftdi_private *priv; char error_flag; - unsigned char *data; + unsigned char *data; int i; int result; @@ -1759,7 +1763,7 @@ static void ftdi_process_read (void *param) } if (length > 0) { for (i = 2; i < length+2; i++) { - /* Note that the error flag is duplicated for + /* Note that the error flag is duplicated for every character received since we don't know which character it applied to */ tty_insert_flip_char(tty, data[packet_offset+i], error_flag); @@ -1773,7 +1777,7 @@ static void ftdi_process_read (void *param) This doesn't work well since the application receives a never ending stream of bad data - even though new data hasn't been sent. Therefore I (bill) have taken this out. - However - this might make sense for framing errors and so on + However - this might make sense for framing errors and so on so I am leaving the code in for now. */ else { @@ -1827,7 +1831,7 @@ static void ftdi_process_read (void *param) /* if the port is closed stop trying to read */ if (port->open_count > 0){ /* Continue trying to always read */ - usb_fill_bulk_urb(port->read_urb, port->serial->dev, + usb_fill_bulk_urb(port->read_urb, port->serial->dev, usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress), port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length, ftdi_read_bulk_callback, port); @@ -1844,9 +1848,9 @@ static void ftdi_process_read (void *param) static void ftdi_break_ctl( struct usb_serial_port *port, int break_state ) { struct ftdi_private *priv = usb_get_serial_port_data(port); - __u16 urb_value = 0; + __u16 urb_value = 0; char buf[1]; - + /* break_state = -1 to turn on break, and 0 to turn off break */ /* see drivers/char/tty_io.c to see it used */ /* last_set_data_urb_value NEVER has the break bit set in it */ @@ -1854,20 +1858,20 @@ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state ) if (break_state) { urb_value = priv->last_set_data_urb_value | FTDI_SIO_SET_BREAK; } else { - urb_value = priv->last_set_data_urb_value; + urb_value = priv->last_set_data_urb_value; } - + if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0), - FTDI_SIO_SET_DATA_REQUEST, + FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, urb_value , priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state); - } + } dbg("%s break state is %d - urb is %d", __FUNCTION__,break_state, urb_value); - + } @@ -1876,19 +1880,19 @@ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state ) * WARNING: set_termios calls this with old_termios in kernel space */ -static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void ftdi_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { /* ftdi_termios */ struct usb_device *dev = port->serial->dev; unsigned int cflag = port->tty->termios->c_cflag; struct ftdi_private *priv = usb_get_serial_port_data(port); __u16 urb_value; /* will hold the new flags */ char buf[1]; /* Perhaps I should dynamically alloc this? */ - + // Added for xon/xoff support unsigned int iflag = port->tty->termios->c_iflag; unsigned char vstop; unsigned char vstart; - + dbg("%s", __FUNCTION__); /* Force baud rate if this device requires it, unless it is set to B0. */ @@ -1906,20 +1910,20 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ cflag = port->tty->termios->c_cflag; - /* FIXME -For this cut I don't care if the line is really changing or - not - so just do the change regardless - should be able to + /* FIXME -For this cut I don't care if the line is really changing or + not - so just do the change regardless - should be able to compare old_termios and tty->termios */ - /* NOTE These routines can get interrupted by - ftdi_sio_read_bulk_callback - need to examine what this + /* NOTE These routines can get interrupted by + ftdi_sio_read_bulk_callback - need to examine what this means - don't see any problems yet */ - + /* Set number of data bits, parity, stop bits */ - + urb_value = 0; urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 : FTDI_SIO_SET_DATA_STOP_BITS_1); - urb_value |= (cflag & PARENB ? - (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : + urb_value |= (cflag & PARENB ? + (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD : FTDI_SIO_SET_DATA_PARITY_EVEN) : FTDI_SIO_SET_DATA_PARITY_NONE); if (cflag & CSIZE) { @@ -1936,25 +1940,25 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ /* This is needed by the break command since it uses the same command - but is * or'ed with this value */ priv->last_set_data_urb_value = urb_value; - + if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_DATA_REQUEST, + FTDI_SIO_SET_DATA_REQUEST, FTDI_SIO_SET_DATA_REQUEST_TYPE, urb_value , priv->interface, buf, 0, WDR_SHORT_TIMEOUT) < 0) { err("%s FAILED to set databits/stopbits/parity", __FUNCTION__); - } + } /* Now do the baudrate */ if ((cflag & CBAUD) == B0 ) { /* Disable flow control */ if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, priv->interface, + 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("%s error from disable flowcontrol urb", __FUNCTION__); - } + } /* Drop RTS and DTR */ clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); } else { @@ -1972,16 +1976,16 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ /* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */ if (cflag & CRTSCTS) { dbg("%s Setting to CRTSCTS flow control", __FUNCTION__); - if (usb_control_msg(dev, + if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, 0 , (FTDI_SIO_RTS_CTS_HS | priv->interface), buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to set to rts/cts flow control"); - } - - } else { + } + + } else { /* * Xon/Xoff code * @@ -2011,16 +2015,16 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_ /* else clause to only run if cfag ! CRTSCTS and iflag ! XOFF */ /* CHECKME Assuming XON/XOFF handled by tty stack - not by device */ dbg("%s Turning off hardware flow control", __FUNCTION__); - if (usb_control_msg(dev, + if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - FTDI_SIO_SET_FLOW_CTRL_REQUEST, + FTDI_SIO_SET_FLOW_CTRL_REQUEST, FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE, - 0, priv->interface, + 0, priv->interface, buf, 0, WDR_TIMEOUT) < 0) { err("urb failed to clear flow control"); - } + } } - + } return; } /* ftdi_termios */ @@ -2036,11 +2040,11 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) switch (priv->chip_type) { case SIO: /* Request the status from the device */ - if ((ret = usb_control_msg(port->serial->dev, + if ((ret = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), - FTDI_SIO_GET_MODEM_STATUS_REQUEST, + FTDI_SIO_GET_MODEM_STATUS_REQUEST, FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, - 0, 0, + 0, 0, buf, 1, WDR_TIMEOUT)) < 0 ) { err("%s Could not get modem status of device - err: %d", __FUNCTION__, ret); @@ -2052,11 +2056,11 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) case FT2232C: /* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same format as the data returned from the in point */ - if ((ret = usb_control_msg(port->serial->dev, + if ((ret = usb_control_msg(port->serial->dev, usb_rcvctrlpipe(port->serial->dev, 0), - FTDI_SIO_GET_MODEM_STATUS_REQUEST, + FTDI_SIO_GET_MODEM_STATUS_REQUEST, FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE, - 0, priv->interface, + 0, priv->interface, buf, 2, WDR_TIMEOUT)) < 0 ) { err("%s Could not get modem status of device - err: %d", __FUNCTION__, ret); @@ -2067,12 +2071,12 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file) return -EFAULT; break; } - + return (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) | (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) | (buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) | (buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) | - priv->last_dtr_rts; + priv->last_dtr_rts; } static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear) @@ -2138,11 +2142,11 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne break; default: break; - + } - /* This is not necessarily an error - turns out the higher layers will do + /* This is not necessarily an error - turns out the higher layers will do * some ioctls itself (see comment above) */ dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __FUNCTION__, cmd); @@ -2178,7 +2182,7 @@ static void ftdi_unthrottle (struct usb_serial_port *port) spin_unlock_irqrestore(&priv->rx_lock, flags); if (actually_throttled) - schedule_work(&priv->rx_work); + schedule_delayed_work(&priv->rx_work, 0); } static int __init ftdi_init (void) @@ -2199,7 +2203,7 @@ static int __init ftdi_init (void) if (retval) goto failed_sio_register; retval = usb_register(&ftdi_driver); - if (retval) + if (retval) goto failed_usb_register; info(DRIVER_VERSION ":" DRIVER_DESC); diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index f0edb87d2dd5..bae117d359af 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -55,6 +55,9 @@ /* iPlus device */ #define FTDI_IPLUS_PID 0xD070 /* Product Id */ +/* DMX4ALL DMX Interfaces */ +#define FTDI_DMX4ALL 0xC850 + /* www.crystalfontz.com devices - thanx for providing free devices for evaluation ! */ /* they use the ftdi chipset for the USB interface and the vendor id is the same */ #define FTDI_XF_632_PID 0xFC08 /* 632: 16x2 Character Display */ @@ -175,9 +178,15 @@ #define FTDI_ASK_RDR400_PID 0xC991 /* ASK RDR 400 series card reader */ /* + * FTDI USB UART chips used in construction projects from the + * Elektor Electronics magazine (http://elektor-electronics.co.uk) + */ +#define ELEKTOR_VID 0x0C7D +#define ELEKTOR_FT323R_PID 0x0005 /* RFID-Reader, issue 09-2006 */ + +/* * DSS-20 Sync Station for Sony Ericsson P800 */ - #define FTDI_DSS20_PID 0xFC82 /* diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index 4543152a9966..6530d391ebed 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -1523,12 +1523,11 @@ static int garmin_attach (struct usb_serial *serial) dbg("%s", __FUNCTION__); - garmin_data_p = kmalloc (sizeof(struct garmin_data), GFP_KERNEL); + garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL); if (garmin_data_p == NULL) { dev_err(&port->dev, "%s - Out of memory\n", __FUNCTION__); return -ENOMEM; } - memset (garmin_data_p, 0, sizeof(struct garmin_data)); init_timer(&garmin_data_p->timer); spin_lock_init(&garmin_data_p->lock); INIT_LIST_HEAD(&garmin_data_p->pktlist); diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 91bd3014ef1e..f623d58370a4 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -229,7 +229,7 @@ static int edge_write_room (struct usb_serial_port *port); static int edge_chars_in_buffer (struct usb_serial_port *port); static void edge_throttle (struct usb_serial_port *port); static void edge_unthrottle (struct usb_serial_port *port); -static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg); static void edge_break (struct usb_serial_port *port, int break_state); static int edge_tiocmget (struct usb_serial_port *port, struct file *file); @@ -257,7 +257,7 @@ static void handle_new_lsr (struct edgeport_port *edge_port, __u8 lsrData, __u8 static int send_iosp_ext_cmd (struct edgeport_port *edge_port, __u8 command, __u8 param); static int calc_baud_rate_divisor (int baud_rate, int *divisor); static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate); -static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios); +static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios); static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue); static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer, int writeLength); static void send_more_port_data (struct edgeport_serial *edge_serial, struct edgeport_port *edge_port); @@ -1038,9 +1038,7 @@ static void edge_close (struct usb_serial_port *port, struct file * filp) edge_port->open = FALSE; edge_port->openPending = FALSE; - if (edge_port->write_urb) { - usb_kill_urb(edge_port->write_urb); - } + usb_kill_urb(edge_port->write_urb); if (edge_port->write_urb) { /* if this urb had a transfer buffer already (old transfer) free it */ @@ -1433,7 +1431,7 @@ static void edge_unthrottle (struct usb_serial_port *port) * SerialSetTermios * this function is called by the tty driver when it wants to change the termios structure *****************************************************************************/ -static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); struct tty_struct *tty = port->tty; @@ -2414,7 +2412,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r #ifndef CMSPAR #define CMSPAR 0 #endif -static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios) +static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios) { struct tty_struct *tty; int baud; diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index ee0c921e1520..2da2684e0809 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -238,7 +238,7 @@ static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned c static void stop_read(struct edgeport_port *edge_port); static int restart_read(struct edgeport_port *edge_port); -static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static void edge_send(struct usb_serial_port *port); /* circular buffer */ @@ -2361,7 +2361,7 @@ static int restart_read(struct edgeport_port *edge_port) return status; } -static void change_port_settings (struct edgeport_port *edge_port, struct termios *old_termios) +static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios) { struct ump_uart_config *config; struct tty_struct *tty; @@ -2512,7 +2512,7 @@ static void change_port_settings (struct edgeport_port *edge_port, struct termio return; } -static void edge_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void edge_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { struct edgeport_port *edge_port = usb_get_serial_port_data(port); struct tty_struct *tty = port->tty; diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 6238aff1e772..d72cf8bc7f76 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -320,6 +320,7 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(0x0B05, 0x9200) }, /* ASUS USB Sync */ { USB_DEVICE(0x0B05, 0x9202) }, /* ASUS USB Sync */ { USB_DEVICE(0x0BB4, 0x00CE) }, /* HTC USB Sync */ + { USB_DEVICE(0x0BB4, 0x00CF) }, /* HTC USB Modem */ { USB_DEVICE(0x0BB4, 0x0A01) }, /* PocketPC USB Sync */ { USB_DEVICE(0x0BB4, 0x0A02) }, /* PocketPC USB Sync */ { USB_DEVICE(0x0BB4, 0x0A03) }, /* PocketPC USB Sync */ diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index 2a4bb66691ad..d3b9a351cef8 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -206,10 +206,9 @@ static int ipw_open(struct usb_serial_port *port, struct file *filp) dbg("%s", __FUNCTION__); - buf_flow_init = kmalloc(16, GFP_KERNEL); + buf_flow_init = kmemdup(buf_flow_static, 16, GFP_KERNEL); if (!buf_flow_init) return -ENOMEM; - memcpy(buf_flow_init, buf_flow_static, 16); if (port->tty) port->tty->low_latency = 1; diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 331bf81556fc..8fdf486e3465 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -107,7 +107,7 @@ static void ir_close (struct usb_serial_port *port, struct file *filep); static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int count); static void ir_write_bulk_callback (struct urb *urb); static void ir_read_bulk_callback (struct urb *urb); -static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static u8 ir_baud = 0; static u8 ir_xbof = 0; @@ -497,7 +497,7 @@ static void ir_read_bulk_callback (struct urb *urb) return; } -static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void ir_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { unsigned char *transfer_buffer; unsigned int cflag; diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 53be824eb1bf..9d2fdfd6865f 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -264,7 +264,7 @@ static void keyspan_break_ctl (struct usb_serial_port *port, int break_state) static void keyspan_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { int baud_rate, device_port; struct keyspan_port_private *p_priv; @@ -2306,22 +2306,16 @@ static void keyspan_shutdown (struct usb_serial *serial) } /* Now free them */ - if (s_priv->instat_urb) - usb_free_urb(s_priv->instat_urb); - if (s_priv->glocont_urb) - usb_free_urb(s_priv->glocont_urb); + usb_free_urb(s_priv->instat_urb); + usb_free_urb(s_priv->glocont_urb); for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; p_priv = usb_get_serial_port_data(port); - if (p_priv->inack_urb) - usb_free_urb(p_priv->inack_urb); - if (p_priv->outcont_urb) - usb_free_urb(p_priv->outcont_urb); + usb_free_urb(p_priv->inack_urb); + usb_free_urb(p_priv->outcont_urb); for (j = 0; j < 2; j++) { - if (p_priv->in_urbs[j]) - usb_free_urb(p_priv->in_urbs[j]); - if (p_priv->out_urbs[j]) - usb_free_urb(p_priv->out_urbs[j]); + usb_free_urb(p_priv->in_urbs[j]); + usb_free_urb(p_priv->out_urbs[j]); } } diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index 7472ed6bf626..6413d73c139c 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -59,7 +59,7 @@ static int keyspan_ioctl (struct usb_serial_port *port, unsigned int cmd, unsigned long arg); static void keyspan_set_termios (struct usb_serial_port *port, - struct termios *old); + struct ktermios *old); static void keyspan_break_ctl (struct usb_serial_port *port, int break_state); static int keyspan_tiocmget (struct usb_serial_port *port, diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 909005107ea2..126b9703bbaf 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -120,6 +120,8 @@ struct keyspan_pda_private { int tx_throttled; struct work_struct wakeup_work; struct work_struct unthrottle_work; + struct usb_serial *serial; + struct usb_serial_port *port; }; @@ -175,9 +177,11 @@ static struct usb_device_id id_table_fake_xircom [] = { }; #endif -static void keyspan_pda_wakeup_write( struct usb_serial_port *port ) +static void keyspan_pda_wakeup_write(struct work_struct *work) { - + struct keyspan_pda_private *priv = + container_of(work, struct keyspan_pda_private, wakeup_work); + struct usb_serial_port *port = priv->port; struct tty_struct *tty = port->tty; /* wake up port processes */ @@ -187,8 +191,11 @@ static void keyspan_pda_wakeup_write( struct usb_serial_port *port ) tty_wakeup(tty); } -static void keyspan_pda_request_unthrottle( struct usb_serial *serial ) +static void keyspan_pda_request_unthrottle(struct work_struct *work) { + struct keyspan_pda_private *priv = + container_of(work, struct keyspan_pda_private, unthrottle_work); + struct usb_serial *serial = priv->serial; int result; dbg(" request_unthrottle"); @@ -358,7 +365,7 @@ static void keyspan_pda_break_ctl (struct usb_serial_port *port, int break_state static void keyspan_pda_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct usb_serial *serial = port->serial; unsigned int cflag = port->tty->termios->c_cflag; @@ -765,11 +772,10 @@ static int keyspan_pda_startup (struct usb_serial *serial) return (1); /* error */ usb_set_serial_port_data(serial->port[0], priv); init_waitqueue_head(&serial->port[0]->write_wait); - INIT_WORK(&priv->wakeup_work, (void *)keyspan_pda_wakeup_write, - (void *)(serial->port[0])); - INIT_WORK(&priv->unthrottle_work, - (void *)keyspan_pda_request_unthrottle, - (void *)(serial)); + INIT_WORK(&priv->wakeup_work, keyspan_pda_wakeup_write); + INIT_WORK(&priv->unthrottle_work, keyspan_pda_request_unthrottle); + priv->serial = serial; + priv->port = serial->port[0]; return (0); } diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 17e205699c2b..73d755df4840 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -86,7 +86,7 @@ static int klsi_105_write_room (struct usb_serial_port *port); static void klsi_105_read_bulk_callback (struct urb *urb); static void klsi_105_set_termios (struct usb_serial_port *port, - struct termios * old); + struct ktermios *old); static int klsi_105_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, @@ -164,7 +164,7 @@ struct klsi_105_port_settings { #define URB_TRANSFER_BUFFER_SIZE 64 struct klsi_105_private { struct klsi_105_port_settings cfg; - struct termios termios; + struct ktermios termios; unsigned long line_state; /* modem line settings */ /* write pool */ struct urb * write_urb_pool[NUM_URBS]; @@ -688,7 +688,7 @@ static void klsi_105_read_bulk_callback (struct urb *urb) static void klsi_105_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct klsi_105_private *priv = usb_get_serial_port_data(port); unsigned int iflag = port->tty->termios->c_iflag; diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index ff03331e0bcf..e284d6c0fd35 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -136,7 +136,7 @@ struct kobil_private { int cur_pos; // index of the next char to send in buf __u16 device_type; int line_state; - struct termios internal_termios; + struct ktermios internal_termios; }; @@ -185,13 +185,11 @@ static int kobil_startup (struct usb_serial *serial) for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { endpoint = &altsetting->endpoint[i]; - if (((endpoint->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) && - ((endpoint->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { + if (usb_endpoint_is_int_out(&endpoint->desc)) { dbg("%s Found interrupt out endpoint. Address: %d", __FUNCTION__, endpoint->desc.bEndpointAddress); priv->write_int_endpoint_address = endpoint->desc.bEndpointAddress; } - if (((endpoint->desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && - ((endpoint->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) { + if (usb_endpoint_is_int_in(&endpoint->desc)) { dbg("%s Found interrupt in endpoint. Address: %d", __FUNCTION__, endpoint->desc.bEndpointAddress); priv->read_int_endpoint_address = endpoint->desc.bEndpointAddress; } @@ -355,8 +353,7 @@ static void kobil_close (struct usb_serial_port *port, struct file *filp) usb_free_urb( port->write_urb ); port->write_urb = NULL; } - if (port->interrupt_in_urb) - usb_kill_urb(port->interrupt_in_urb); + usb_kill_urb(port->interrupt_in_urb); } @@ -627,11 +624,11 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file, switch (cmd) { case TCGETS: // 0x5401 - if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct termios))) { + if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) { dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); return -EFAULT; } - if (kernel_termios_to_user_termios((struct termios __user *)arg, + if (kernel_termios_to_user_termios((struct ktermios __user *)arg, &priv->internal_termios)) return -EFAULT; return 0; @@ -641,12 +638,12 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file, dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number); return -ENOTTY; } - if (!access_ok(VERIFY_READ, user_arg, sizeof(struct termios))) { + if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) { dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number); return -EFAULT; } if (user_termios_to_kernel_termios(&priv->internal_termios, - (struct termios __user *)arg)) + (struct ktermios __user *)arg)) return -EFAULT; settings = kzalloc(50, GFP_KERNEL); diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index b7582cc496dc..38b1d17e06ef 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -98,7 +98,7 @@ static void mct_u232_close (struct usb_serial_port *port, struct file *filp); static void mct_u232_read_int_callback (struct urb *urb); static void mct_u232_set_termios (struct usb_serial_port *port, - struct termios * old); + struct ktermios * old); static int mct_u232_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, @@ -358,10 +358,8 @@ static int mct_u232_startup (struct usb_serial *serial) /* Puh, that's dirty */ port = serial->port[0]; rport = serial->port[1]; - if (port->read_urb) { - /* No unlinking, it wasn't submitted yet. */ - usb_free_urb(port->read_urb); - } + /* No unlinking, it wasn't submitted yet. */ + usb_free_urb(port->read_urb); port->read_urb = rport->interrupt_in_urb; rport->interrupt_in_urb = NULL; port->read_urb->context = port; @@ -558,7 +556,7 @@ exit: } /* mct_u232_read_int_callback */ static void mct_u232_set_termios (struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct mct_u232_private *priv = usb_get_serial_port_data(port); diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c new file mode 100644 index 000000000000..e55f4ed81d7b --- /dev/null +++ b/drivers/usb/serial/mos7720.c @@ -0,0 +1,1683 @@ +/* + * mos7720.c + * Controls the Moschip 7720 usb to dual port serial convertor + * + * Copyright 2006 Moschip Semiconductor Tech. Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * Developed by: + * VijayaKumar.G.N. <vijaykumar@aspirecom.net> + * AjayKumar <ajay@aspirecom.net> + * Gurudeva.N. <gurudev@aspirecom.net> + * + * Cleaned up from the original by: + * Greg Kroah-Hartman <gregkh@suse.de> + * + * Originally based on drivers/usb/serial/io_edgeport.c which is: + * Copyright (C) 2000 Inside Out Networks, All rights reserved. + * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com> + */ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/serial.h> +#include <linux/serial_reg.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include <asm/uaccess.h> + + +/* + * Version Information + */ +#define DRIVER_VERSION "1.0.0.4F" +#define DRIVER_AUTHOR "Aspire Communications pvt Ltd." +#define DRIVER_DESC "Moschip USB Serial Driver" + +/* default urb timeout */ +#define MOS_WDR_TIMEOUT (HZ * 5) + +#define MOS_PORT1 0x0200 +#define MOS_PORT2 0x0300 +#define MOS_VENREG 0x0000 +#define MOS_MAX_PORT 0x02 +#define MOS_WRITE 0x0E +#define MOS_READ 0x0D + +/* Interrupt Rotinue Defines */ +#define SERIAL_IIR_RLS 0x06 +#define SERIAL_IIR_RDA 0x04 +#define SERIAL_IIR_CTI 0x0c +#define SERIAL_IIR_THR 0x02 +#define SERIAL_IIR_MS 0x00 + +#define NUM_URBS 16 /* URB Count */ +#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */ + +/* This structure holds all of the local port information */ +struct moschip_port +{ + __u8 shadowLCR; /* last LCR value received */ + __u8 shadowMCR; /* last MCR value received */ + __u8 shadowMSR; /* last MSR value received */ + char open; + struct async_icount icount; + struct usb_serial_port *port; /* loop back to the owner */ + struct urb *write_urb_pool[NUM_URBS]; +}; + +/* This structure holds all of the individual serial device information */ +struct moschip_serial +{ + int interrupt_started; +}; + +static int debug; + +#define USB_VENDOR_ID_MOSCHIP 0x9710 +#define MOSCHIP_DEVICE_ID_7720 0x7720 +#define MOSCHIP_DEVICE_ID_7715 0x7715 + +static struct usb_device_id moschip_port_id_table [] = { + { USB_DEVICE(USB_VENDOR_ID_MOSCHIP,MOSCHIP_DEVICE_ID_7720) }, + { } /* terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, moschip_port_id_table); + + +/* + * mos7720_interrupt_callback + * this is the callback function for when we have received data on the + * interrupt endpoint. + */ +static void mos7720_interrupt_callback(struct urb *urb) +{ + int result; + int length; + __u32 *data; + unsigned int status; + __u8 sp1; + __u8 sp2; + __u8 st; + + dbg("%s"," : Entering\n"); + + if (!urb) { + dbg("%s","Invalid Pointer !!!!:\n"); + return; + } + + switch (urb->status) { + case 0: + /* success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", __FUNCTION__, + urb->status); + return; + default: + dbg("%s - nonzero urb status received: %d", __FUNCTION__, + urb->status); + goto exit; + } + + length = urb->actual_length; + data = urb->transfer_buffer; + + /* Moschip get 4 bytes + * Byte 1 IIR Port 1 (port.number is 0) + * Byte 2 IIR Port 2 (port.number is 1) + * Byte 3 -------------- + * Byte 4 FIFO status for both */ + if (length && length > 4) { + dbg("Wrong data !!!"); + return; + } + + status = *data; + + sp1 = (status & 0xff000000)>>24; + sp2 = (status & 0x00ff0000)>>16; + st = status & 0x000000ff; + + if ((sp1 & 0x01) || (sp2 & 0x01)) { + /* No Interrupt Pending in both the ports */ + dbg("No Interrupt !!!"); + } else { + switch (sp1 & 0x0f) { + case SERIAL_IIR_RLS: + dbg("Serial Port 1: Receiver status error or address " + "bit detected in 9-bit mode\n"); + break; + case SERIAL_IIR_CTI: + dbg("Serial Port 1: Receiver time out"); + break; + case SERIAL_IIR_MS: + dbg("Serial Port 1: Modem status change"); + break; + } + + switch (sp2 & 0x0f) { + case SERIAL_IIR_RLS: + dbg("Serial Port 2: Receiver status error or address " + "bit detected in 9-bit mode"); + break; + case SERIAL_IIR_CTI: + dbg("Serial Port 2: Receiver time out"); + break; + case SERIAL_IIR_MS: + dbg("Serial Port 2: Modem status change"); + break; + } + } + +exit: + result = usb_submit_urb(urb, GFP_ATOMIC); + if (result) + dev_err(&urb->dev->dev, + "%s - Error %d submitting control urb\n", + __FUNCTION__, result); + return; +} + +/* + * mos7720_bulk_in_callback + * this is the callback function for when we have received data on the + * bulk in endpoint. + */ +static void mos7720_bulk_in_callback(struct urb *urb) +{ + int status; + unsigned char *data ; + struct usb_serial_port *port; + struct moschip_port *mos7720_port; + struct tty_struct *tty; + + if (urb->status) { + dbg("nonzero read bulk status received: %d",urb->status); + return; + } + + mos7720_port = urb->context; + if (!mos7720_port) { + dbg("%s","NULL mos7720_port pointer \n"); + return ; + } + + port = mos7720_port->port; + + dbg("Entering...%s", __FUNCTION__); + + data = urb->transfer_buffer; + + tty = port->tty; + if (tty && urb->actual_length) { + tty_buffer_request_room(tty, urb->actual_length); + tty_insert_flip_string(tty, data, urb->actual_length); + tty_flip_buffer_push(tty); + } + + if (!port->read_urb) { + dbg("URB KILLED !!!"); + return; + } + + if (port->read_urb->status != -EINPROGRESS) { + port->read_urb->dev = port->serial->dev; + + status = usb_submit_urb(port->read_urb, GFP_ATOMIC); + if (status) + dbg("usb_submit_urb(read bulk) failed, status = %d", + status); + } +} + +/* + * mos7720_bulk_out_data_callback + * this is the callback function for when we have finished sending serial + * data on the bulk out endpoint. + */ +static void mos7720_bulk_out_data_callback(struct urb *urb) +{ + struct moschip_port *mos7720_port; + struct tty_struct *tty; + + if (urb->status) { + dbg("nonzero write bulk status received:%d", urb->status); + return; + } + + mos7720_port = urb->context; + if (!mos7720_port) { + dbg("NULL mos7720_port pointer"); + return ; + } + + dbg("Entering ........."); + + tty = mos7720_port->port->tty; + + if (tty && mos7720_port->open) { + /* let the tty driver wakeup if it has a special * + * write_wakeup function */ + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + + /* tell the tty driver that something has changed */ + wake_up_interruptible(&tty->write_wait); + } + + /* schedule_work(&mos7720_port->port->work); */ +} + +/* + * send_mos_cmd + * this function will be used for sending command to device + */ +static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value, + __u16 index, void *data) +{ + int status; + unsigned int pipe; + u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); + __u8 requesttype; + __u16 size = 0x0000; + + if (value < MOS_MAX_PORT) { + if (product == MOSCHIP_DEVICE_ID_7715) { + value = value*0x100+0x100; + } else { + value = value*0x100+0x200; + } + } else { + value = 0x0000; + if ((product == MOSCHIP_DEVICE_ID_7715) && + (index != 0x08)) { + dbg("serial->product== MOSCHIP_DEVICE_ID_7715"); + //index = 0x01 ; + } + } + + if (request == MOS_WRITE) { + request = (__u8)MOS_WRITE; + requesttype = (__u8)0x40; + value = value + (__u16)*((unsigned char *)data); + data = NULL; + pipe = usb_sndctrlpipe(serial->dev, 0); + } else { + request = (__u8)MOS_READ; + requesttype = (__u8)0xC0; + size = 0x01; + pipe = usb_rcvctrlpipe(serial->dev,0); + } + + status = usb_control_msg(serial->dev, pipe, request, requesttype, + value, index, data, size, MOS_WDR_TIMEOUT); + + if (status < 0) + dbg("Command Write failed Value %x index %x\n",value,index); + + return status; +} + +static int mos7720_open(struct usb_serial_port *port, struct file * filp) +{ + struct usb_serial *serial; + struct usb_serial_port *port0; + struct urb *urb; + struct moschip_serial *mos7720_serial; + struct moschip_port *mos7720_port; + int response; + int port_number; + char data; + int j; + + serial = port->serial; + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) + return -ENODEV; + + port0 = serial->port[0]; + + mos7720_serial = usb_get_serial_data(serial); + + if (mos7720_serial == NULL || port0 == NULL) + return -ENODEV; + + usb_clear_halt(serial->dev, port->write_urb->pipe); + usb_clear_halt(serial->dev, port->read_urb->pipe); + + /* Initialising the write urb pool */ + for (j = 0; j < NUM_URBS; ++j) { + urb = usb_alloc_urb(0,GFP_ATOMIC); + mos7720_port->write_urb_pool[j] = urb; + + if (urb == NULL) { + err("No more urbs???"); + continue; + } + + urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, + GFP_KERNEL); + if (!urb->transfer_buffer) { + err("%s-out of memory for urb buffers.", __FUNCTION__); + continue; + } + } + + /* Initialize MCS7720 -- Write Init values to corresponding Registers + * + * Register Index + * 1 : IER + * 2 : FCR + * 3 : LCR + * 4 : MCR + * + * 0x08 : SP1/2 Control Reg + */ + port_number = port->number - port->serial->minor; + send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data); + dbg("SS::%p LSR:%x\n",mos7720_port, data); + + dbg("Check:Sending Command .........."); + + data = 0x02; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x01, &data); + data = 0x02; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x02, &data); + + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); + + data = 0xCF; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); + data = 0x03; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); + data = 0x0b; + mos7720_port->shadowMCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + data = 0x0b; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + + data = 0x00; + send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); + +/* data = 0x00; + send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, port_number + 1, &data); + data = 0x03; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data); + data = 0x00; + send_mos_cmd(port->serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data); +*/ + data = 0x00; + send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); + + data = data | (port->number - port->serial->minor + 1); + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); + + data = 0x83; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); + data = 0x0c; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data); + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + data = 0x03; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); + data = 0x0c; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + data = 0x0c; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + +//Matrix + + /* force low_latency on so that our tty_push actually forces * + * the data through,otherwise it is scheduled, and with * + * high data rates (like with OHCI) data can get lost. */ + + if (port->tty) + port->tty->low_latency = 1; + + /* see if we've set up our endpoint info yet * + * (can't set it up in mos7720_startup as the * + * structures were not set up at that time.) */ + if (!mos7720_serial->interrupt_started) { + dbg("Interrupt buffer NULL !!!"); + + /* not set up yet, so do it now */ + mos7720_serial->interrupt_started = 1; + + dbg("To Submit URB !!!"); + + /* set up our interrupt urb */ + usb_fill_int_urb(port0->interrupt_in_urb, serial->dev, + usb_rcvintpipe(serial->dev, + port->interrupt_in_endpointAddress), + port0->interrupt_in_buffer, + port0->interrupt_in_urb->transfer_buffer_length, + mos7720_interrupt_callback, mos7720_port, + port0->interrupt_in_urb->interval); + + /* start interrupt read for this mos7720 this interrupt * + * will continue as long as the mos7720 is connected */ + dbg("Submit URB over !!!"); + response = usb_submit_urb(port0->interrupt_in_urb, GFP_KERNEL); + if (response) + dev_err(&port->dev, + "%s - Error %d submitting control urb", + __FUNCTION__, response); + } + + /* set up our bulk in urb */ + usb_fill_bulk_urb(port->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, + port->bulk_in_endpointAddress), + port->bulk_in_buffer, + port->read_urb->transfer_buffer_length, + mos7720_bulk_in_callback, mos7720_port); + response = usb_submit_urb(port->read_urb, GFP_KERNEL); + if (response) + dev_err(&port->dev, + "%s - Error %d submitting read urb", __FUNCTION__, response); + + /* initialize our icount structure */ + memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount)); + + /* initialize our port settings */ + mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */ + + /* send a open port command */ + mos7720_port->open = 1; + + return 0; +} + +/* + * mos7720_chars_in_buffer + * this function is called by the tty driver when it wants to know how many + * bytes of data we currently have outstanding in the port (data that has + * been written, but hasn't made it out the port yet) + * If successful, we return the number of bytes left to be written in the + * system, + * Otherwise we return a negative error number. + */ +static int mos7720_chars_in_buffer(struct usb_serial_port *port) +{ + int i; + int chars = 0; + struct moschip_port *mos7720_port; + + dbg("%s:entering ...........", __FUNCTION__); + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) { + dbg("%s:leaving ...........", __FUNCTION__); + return -ENODEV; + } + + for (i = 0; i < NUM_URBS; ++i) { + if (mos7720_port->write_urb_pool[i]->status == -EINPROGRESS) + chars += URB_TRANSFER_BUFFER_SIZE; + } + dbg("%s - returns %d", __FUNCTION__, chars); + return chars; +} + +static void mos7720_close(struct usb_serial_port *port, struct file *filp) +{ + struct usb_serial *serial; + struct moschip_port *mos7720_port; + char data; + int j; + + dbg("mos7720_close:entering..."); + + serial = port->serial; + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) + return; + + for (j = 0; j < NUM_URBS; ++j) + usb_kill_urb(mos7720_port->write_urb_pool[j]); + + /* Freeing Write URBs */ + for (j = 0; j < NUM_URBS; ++j) { + if (mos7720_port->write_urb_pool[j]) { + kfree(mos7720_port->write_urb_pool[j]->transfer_buffer); + usb_free_urb(mos7720_port->write_urb_pool[j]); + } + } + + /* While closing port, shutdown all bulk read, write * + * and interrupt read if they exists */ + if (serial->dev) { + dbg("Shutdown bulk write"); + usb_kill_urb(port->write_urb); + dbg("Shutdown bulk read"); + usb_kill_urb(port->read_urb); + } + + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, + 0x04, &data); + + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, + 0x01, &data); + + mos7720_port->open = 0; + + dbg("Leaving %s", __FUNCTION__); +} + +static void mos7720_break(struct usb_serial_port *port, int break_state) +{ + unsigned char data; + struct usb_serial *serial; + struct moschip_port *mos7720_port; + + dbg("Entering %s", __FUNCTION__); + + serial = port->serial; + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) + return; + + if (break_state == -1) + data = mos7720_port->shadowLCR | UART_LCR_SBC; + else + data = mos7720_port->shadowLCR & ~UART_LCR_SBC; + + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor, + 0x03, &data); + + return; +} + +/* + * mos7720_write_room + * this function is called by the tty driver when it wants to know how many + * bytes of data we can accept for a specific port. + * If successful, we return the amount of room that we have for this port + * Otherwise we return a negative error number. + */ +static int mos7720_write_room(struct usb_serial_port *port) +{ + struct moschip_port *mos7720_port; + int room = 0; + int i; + + dbg("%s:entering ...........", __FUNCTION__); + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) { + dbg("%s:leaving ...........", __FUNCTION__); + return -ENODEV; + } + + for (i = 0; i < NUM_URBS; ++i) { + if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) + room += URB_TRANSFER_BUFFER_SIZE; + } + + dbg("%s - returns %d", __FUNCTION__, room); + return room; +} + +static int mos7720_write(struct usb_serial_port *port, + const unsigned char *data, int count) +{ + int status; + int i; + int bytes_sent = 0; + int transfer_size; + + struct moschip_port *mos7720_port; + struct usb_serial *serial; + struct urb *urb; + const unsigned char *current_position = data; + + dbg("%s:entering ...........", __FUNCTION__); + + serial = port->serial; + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) { + dbg("mos7720_port is NULL"); + return -ENODEV; + } + + /* try to find a free urb in the list */ + urb = NULL; + + for (i = 0; i < NUM_URBS; ++i) { + if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) { + urb = mos7720_port->write_urb_pool[i]; + dbg("URB:%d",i); + break; + } + } + + if (urb == NULL) { + dbg("%s - no more free urbs", __FUNCTION__); + goto exit; + } + + if (urb->transfer_buffer == NULL) { + urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE, + GFP_KERNEL); + if (urb->transfer_buffer == NULL) { + err("%s no more kernel memory...", __FUNCTION__); + goto exit; + } + } + transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE); + + memcpy(urb->transfer_buffer, current_position, transfer_size); + usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, + urb->transfer_buffer); + + /* fill urb with data and submit */ + usb_fill_bulk_urb(urb, serial->dev, + usb_sndbulkpipe(serial->dev, + port->bulk_out_endpointAddress), + urb->transfer_buffer, transfer_size, + mos7720_bulk_out_data_callback, mos7720_port); + + /* send it down the pipe */ + status = usb_submit_urb(urb,GFP_ATOMIC); + if (status) { + err("%s - usb_submit_urb(write bulk) failed with status = %d", + __FUNCTION__, status); + bytes_sent = status; + goto exit; + } + bytes_sent = transfer_size; + +exit: + return bytes_sent; +} + +static void mos7720_throttle(struct usb_serial_port *port) +{ + struct moschip_port *mos7720_port; + struct tty_struct *tty; + int status; + + dbg("%s- port %d\n", __FUNCTION__, port->number); + + mos7720_port = usb_get_serial_port_data(port); + + if (mos7720_port == NULL) + return; + + if (!mos7720_port->open) { + dbg("port not opened"); + return; + } + + dbg("%s: Entering ..........", __FUNCTION__); + + tty = port->tty; + if (!tty) { + dbg("%s - no tty available", __FUNCTION__); + return; + } + + /* if we are implementing XON/XOFF, send the stop character */ + if (I_IXOFF(tty)) { + unsigned char stop_char = STOP_CHAR(tty); + status = mos7720_write(port, &stop_char, 1); + if (status <= 0) + return; + } + + /* if we are implementing RTS/CTS, toggle that line */ + if (tty->termios->c_cflag & CRTSCTS) { + mos7720_port->shadowMCR &= ~UART_MCR_RTS; + status = send_mos_cmd(port->serial, MOS_WRITE, + port->number - port->serial->minor, + UART_MCR, &mos7720_port->shadowMCR); + if (status != 0) + return; + } +} + +static void mos7720_unthrottle(struct usb_serial_port *port) +{ + struct tty_struct *tty; + int status; + struct moschip_port *mos7720_port = usb_get_serial_port_data(port); + + if (mos7720_port == NULL) + return; + + if (!mos7720_port->open) { + dbg("%s - port not opened", __FUNCTION__); + return; + } + + dbg("%s: Entering ..........", __FUNCTION__); + + tty = port->tty; + if (!tty) { + dbg("%s - no tty available", __FUNCTION__); + return; + } + + /* if we are implementing XON/XOFF, send the start character */ + if (I_IXOFF(tty)) { + unsigned char start_char = START_CHAR(tty); + status = mos7720_write(port, &start_char, 1); + if (status <= 0) + return; + } + + /* if we are implementing RTS/CTS, toggle that line */ + if (tty->termios->c_cflag & CRTSCTS) { + mos7720_port->shadowMCR |= UART_MCR_RTS; + status = send_mos_cmd(port->serial, MOS_WRITE, + port->number - port->serial->minor, + UART_MCR, &mos7720_port->shadowMCR); + if (status != 0) + return; + } +} + +static int set_higher_rates(struct moschip_port *mos7720_port, + unsigned int baud) +{ + unsigned char data; + struct usb_serial_port *port; + struct usb_serial *serial; + int port_number; + + if (mos7720_port == NULL) + return -EINVAL; + + port = mos7720_port->port; + serial = port->serial; + + /*********************************************** + * Init Sequence for higher rates + ***********************************************/ + dbg("Sending Setting Commands .........."); + port_number = port->number - port->serial->minor; + + data = 0x000; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + data = 0x000; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data); + data = 0x0CF; + send_mos_cmd(serial, MOS_WRITE, port->number, 0x02, &data); + data = 0x00b; + mos7720_port->shadowMCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + data = 0x00b; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + + data = 0x000; + send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); + data = 0x000; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); + + + /*********************************************** + * Set for higher rates * + ***********************************************/ + + data = baud * 0x10; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1,&data); + + data = 0x003; + send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data); + data = 0x003; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data); + + data = 0x02b; + mos7720_port->shadowMCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + data = 0x02b; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + + /*********************************************** + * Set DLL/DLM + ***********************************************/ + + data = mos7720_port->shadowLCR | UART_LCR_DLAB; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); + + data = 0x001; /* DLL */ + send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data); + data = 0x000; /* DLM */ + send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data); + + data = mos7720_port->shadowLCR & ~UART_LCR_DLAB; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data); + + return 0; +} + +/* baud rate information */ +struct divisor_table_entry +{ + __u32 baudrate; + __u16 divisor; +}; + +/* Define table of divisors for moschip 7720 hardware * + * These assume a 3.6864MHz crystal, the standard /16, and * + * MCR.7 = 0. */ +static struct divisor_table_entry divisor_table[] = { + { 50, 2304}, + { 110, 1047}, /* 2094.545455 => 230450 => .0217 % over */ + { 134, 857}, /* 1713.011152 => 230398.5 => .00065% under */ + { 150, 768}, + { 300, 384}, + { 600, 192}, + { 1200, 96}, + { 1800, 64}, + { 2400, 48}, + { 4800, 24}, + { 7200, 16}, + { 9600, 12}, + { 19200, 6}, + { 38400, 3}, + { 57600, 2}, + { 115200, 1}, +}; + +/***************************************************************************** + * calc_baud_rate_divisor + * this function calculates the proper baud rate divisor for the specified + * baud rate. + *****************************************************************************/ +static int calc_baud_rate_divisor(int baudrate, int *divisor) +{ + int i; + __u16 custom; + __u16 round1; + __u16 round; + + + dbg("%s - %d", __FUNCTION__, baudrate); + + for (i = 0; i < ARRAY_SIZE(divisor_table); i++) { + if (divisor_table[i].baudrate == baudrate) { + *divisor = divisor_table[i].divisor; + return 0; + } + } + + /* After trying for all the standard baud rates * + * Try calculating the divisor for this baud rate */ + if (baudrate > 75 && baudrate < 230400) { + /* get the divisor */ + custom = (__u16)(230400L / baudrate); + + /* Check for round off */ + round1 = (__u16)(2304000L / baudrate); + round = (__u16)(round1 - (custom * 10)); + if (round > 4) + custom++; + *divisor = custom; + + dbg("Baud %d = %d",baudrate, custom); + return 0; + } + + dbg("Baud calculation Failed..."); + return -EINVAL; +} + +/* + * send_cmd_write_baud_rate + * this function sends the proper command to change the baud rate of the + * specified port. + */ +static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port, + int baudrate) +{ + struct usb_serial_port *port; + struct usb_serial *serial; + int divisor; + int status; + unsigned char data; + unsigned char number; + + if (mos7720_port == NULL) + return -1; + + port = mos7720_port->port; + serial = port->serial; + + dbg("%s: Entering ..........", __FUNCTION__); + + number = port->number - port->serial->minor; + dbg("%s - port = %d, baud = %d", __FUNCTION__, port->number, baudrate); + + /* Calculate the Divisor */ + status = calc_baud_rate_divisor(baudrate, &divisor); + if (status) { + err("%s - bad baud rate", __FUNCTION__); + return status; + } + + /* Enable access to divisor latch */ + data = mos7720_port->shadowLCR | UART_LCR_DLAB; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, number, UART_LCR, &data); + + /* Write the divisor */ + data = ((unsigned char)(divisor & 0xff)); + send_mos_cmd(serial, MOS_WRITE, number, 0x00, &data); + + data = ((unsigned char)((divisor & 0xff00) >> 8)); + send_mos_cmd(serial, MOS_WRITE, number, 0x01, &data); + + /* Disable access to divisor latch */ + data = mos7720_port->shadowLCR & ~UART_LCR_DLAB; + mos7720_port->shadowLCR = data; + send_mos_cmd(serial, MOS_WRITE, number, 0x03, &data); + + return status; +} + +/* + * change_port_settings + * This routine is called to set the UART on the device to match + * the specified new settings. + */ +static void change_port_settings(struct moschip_port *mos7720_port, + struct ktermios *old_termios) +{ + struct usb_serial_port *port; + struct usb_serial *serial; + struct tty_struct *tty; + int baud; + unsigned cflag; + unsigned iflag; + __u8 mask = 0xff; + __u8 lData; + __u8 lParity; + __u8 lStop; + int status; + int port_number; + char data; + + if (mos7720_port == NULL) + return ; + + port = mos7720_port->port; + serial = port->serial; + port_number = port->number - port->serial->minor; + + dbg("%s - port %d", __FUNCTION__, port->number); + + if (!mos7720_port->open) { + dbg("%s - port not opened", __FUNCTION__); + return; + } + + tty = mos7720_port->port->tty; + + if ((!tty) || (!tty->termios)) { + dbg("%s - no tty structures", __FUNCTION__); + return; + } + + dbg("%s: Entering ..........", __FUNCTION__); + + lData = UART_LCR_WLEN8; + lStop = 0x00; /* 1 stop bit */ + lParity = 0x00; /* No parity */ + + cflag = tty->termios->c_cflag; + iflag = tty->termios->c_iflag; + + /* Change the number of bits */ + switch (cflag & CSIZE) { + case CS5: + lData = UART_LCR_WLEN5; + mask = 0x1f; + break; + + case CS6: + lData = UART_LCR_WLEN6; + mask = 0x3f; + break; + + case CS7: + lData = UART_LCR_WLEN7; + mask = 0x7f; + break; + default: + case CS8: + lData = UART_LCR_WLEN8; + break; + } + + /* Change the Parity bit */ + if (cflag & PARENB) { + if (cflag & PARODD) { + lParity = UART_LCR_PARITY; + dbg("%s - parity = odd", __FUNCTION__); + } else { + lParity = (UART_LCR_EPAR | UART_LCR_PARITY); + dbg("%s - parity = even", __FUNCTION__); + } + + } else { + dbg("%s - parity = none", __FUNCTION__); + } + + if (cflag & CMSPAR) + lParity = lParity | 0x20; + + /* Change the Stop bit */ + if (cflag & CSTOPB) { + lStop = UART_LCR_STOP; + dbg("%s - stop bits = 2", __FUNCTION__); + } else { + lStop = 0x00; + dbg("%s - stop bits = 1", __FUNCTION__); + } + +#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */ +#define LCR_STOP_MASK 0x04 /* Mask for stop bits field */ +#define LCR_PAR_MASK 0x38 /* Mask for parity field */ + + /* Update the LCR with the correct value */ + mos7720_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK); + mos7720_port->shadowLCR |= (lData | lParity | lStop); + + + /* Disable Interrupts */ + data = 0x00; + send_mos_cmd(serial,MOS_WRITE,port->number - port->serial->minor, UART_IER, &data); + + data = 0x00; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data); + + data = 0xcf; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data); + + /* Send the updated LCR value to the mos7720 */ + data = mos7720_port->shadowLCR; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_LCR, &data); + + data = 0x00b; + mos7720_port->shadowMCR = data; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + data = 0x00b; + send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data); + + /* set up the MCR register and send it to the mos7720 */ + mos7720_port->shadowMCR = UART_MCR_OUT2; + if (cflag & CBAUD) + mos7720_port->shadowMCR |= (UART_MCR_DTR | UART_MCR_RTS); + + if (cflag & CRTSCTS) { + mos7720_port->shadowMCR |= (UART_MCR_XONANY); + + /* To set hardware flow control to the specified * + * serial port, in SP1/2_CONTROL_REG */ + if (port->number) { + data = 0x001; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, + 0x08, &data); + } else { + data = 0x002; + send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, + 0x08, &data); + } + } else { + mos7720_port->shadowMCR &= ~(UART_MCR_XONANY); + } + + data = mos7720_port->shadowMCR; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_MCR, &data); + + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(tty); + if (!baud) { + /* pick a default, any default... */ + dbg("Picked default baud..."); + baud = 9600; + } + + if (baud >= 230400) { + set_higher_rates(mos7720_port, baud); + /* Enable Interrupts */ + data = 0x0c; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data); + return; + } + + dbg("%s - baud rate = %d", __FUNCTION__, baud); + status = send_cmd_write_baud_rate(mos7720_port, baud); + + /* Enable Interrupts */ + data = 0x0c; + send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data); + + if (port->read_urb->status != -EINPROGRESS) { + port->read_urb->dev = serial->dev; + + status = usb_submit_urb(port->read_urb, GFP_ATOMIC); + if (status) + dbg("usb_submit_urb(read bulk) failed, status = %d", + status); + } + return; +} + +/* + * mos7720_set_termios + * this function is called by the tty driver when it wants to change the + * termios structure. + */ +static void mos7720_set_termios(struct usb_serial_port *port, + struct ktermios *old_termios) +{ + int status; + unsigned int cflag; + struct usb_serial *serial; + struct moschip_port *mos7720_port; + struct tty_struct *tty; + + serial = port->serial; + + mos7720_port = usb_get_serial_port_data(port); + + if (mos7720_port == NULL) + return; + + tty = port->tty; + + if (!port->tty || !port->tty->termios) { + dbg("%s - no tty or termios", __FUNCTION__); + return; + } + + if (!mos7720_port->open) { + dbg("%s - port not opened", __FUNCTION__); + return; + } + + dbg("%s\n","setting termios - ASPIRE"); + + cflag = tty->termios->c_cflag; + + if (!cflag) { + printk("%s %s\n",__FUNCTION__,"cflag is NULL"); + return; + } + + /* check that they really want us to change something */ + if (old_termios) { + if ((cflag == old_termios->c_cflag) && + (RELEVANT_IFLAG(tty->termios->c_iflag) == + RELEVANT_IFLAG(old_termios->c_iflag))) { + dbg("Nothing to change"); + return; + } + } + + dbg("%s - clfag %08x iflag %08x", __FUNCTION__, + tty->termios->c_cflag, + RELEVANT_IFLAG(tty->termios->c_iflag)); + + if (old_termios) + dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__, + old_termios->c_cflag, + RELEVANT_IFLAG(old_termios->c_iflag)); + + dbg("%s - port %d", __FUNCTION__, port->number); + + /* change the port settings to the new ones specified */ + change_port_settings(mos7720_port, old_termios); + + if(!port->read_urb) { + dbg("%s","URB KILLED !!!!!\n"); + return; + } + + if(port->read_urb->status != -EINPROGRESS) { + port->read_urb->dev = serial->dev; + status = usb_submit_urb(port->read_urb, GFP_ATOMIC); + if (status) + dbg("usb_submit_urb(read bulk) failed, status = %d", + status); + } + return; +} + +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows an RS485 driver to be written in user space. + */ +static int get_lsr_info(struct moschip_port *mos7720_port, + unsigned int __user *value) +{ + int count; + unsigned int result = 0; + + count = mos7720_chars_in_buffer(mos7720_port->port); + if (count == 0) { + dbg("%s -- Empty", __FUNCTION__); + result = TIOCSER_TEMT; + } + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + +/* + * get_number_bytes_avail - get number of bytes available + * + * Purpose: Let user call ioctl to get the count of number of bytes available. + */ +static int get_number_bytes_avail(struct moschip_port *mos7720_port, + unsigned int __user *value) +{ + unsigned int result = 0; + struct tty_struct *tty = mos7720_port->port->tty; + + if (!tty) + return -ENOIOCTLCMD; + + result = tty->read_cnt; + + dbg("%s(%d) = %d", __FUNCTION__, mos7720_port->port->number, result); + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + + return -ENOIOCTLCMD; +} + +static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd, + unsigned int __user *value) +{ + unsigned int mcr ; + unsigned int arg; + unsigned char data; + + struct usb_serial_port *port; + + if (mos7720_port == NULL) + return -1; + + port = (struct usb_serial_port*)mos7720_port->port; + mcr = mos7720_port->shadowMCR; + + if (copy_from_user(&arg, value, sizeof(int))) + return -EFAULT; + + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (arg & TIOCM_DTR) + mcr |= UART_MCR_RTS; + if (arg & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + break; + + case TIOCMBIC: + if (arg & TIOCM_RTS) + mcr &= ~UART_MCR_RTS; + if (arg & TIOCM_DTR) + mcr &= ~UART_MCR_RTS; + if (arg & TIOCM_LOOP) + mcr &= ~UART_MCR_LOOP; + break; + + case TIOCMSET: + /* turn off the RTS and DTR and LOOPBACK + * and then only turn on what was asked to */ + mcr &= ~(UART_MCR_RTS | UART_MCR_DTR | UART_MCR_LOOP); + mcr |= ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0); + mcr |= ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0); + mcr |= ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0); + break; + } + + mos7720_port->shadowMCR = mcr; + + data = mos7720_port->shadowMCR; + send_mos_cmd(port->serial, MOS_WRITE, + port->number - port->serial->minor, UART_MCR, &data); + + return 0; +} + +static int get_modem_info(struct moschip_port *mos7720_port, + unsigned int __user *value) +{ + unsigned int result = 0; + unsigned int msr = mos7720_port->shadowMSR; + unsigned int mcr = mos7720_port->shadowMCR; + + result = ((mcr & UART_MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */ + | ((mcr & UART_MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */ + | ((msr & UART_MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */ + | ((msr & UART_MSR_DCD) ? TIOCM_CAR: 0) /* 0x040 */ + | ((msr & UART_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */ + | ((msr & UART_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */ + + + dbg("%s -- %x", __FUNCTION__, result); + + if (copy_to_user(value, &result, sizeof(int))) + return -EFAULT; + return 0; +} + +static int get_serial_info(struct moschip_port *mos7720_port, + struct serial_struct __user *retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + + tmp.type = PORT_16550A; + tmp.line = mos7720_port->port->serial->minor; + tmp.port = mos7720_port->port->number; + tmp.irq = 0; + tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; + tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE; + tmp.baud_base = 9600; + tmp.close_delay = 5*HZ; + tmp.closing_wait = 30*HZ; + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int mos7720_ioctl(struct usb_serial_port *port, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct moschip_port *mos7720_port; + struct async_icount cnow; + struct async_icount cprev; + struct serial_icounter_struct icount; + + mos7720_port = usb_get_serial_port_data(port); + if (mos7720_port == NULL) + return -ENODEV; + + dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd); + + switch (cmd) { + case TIOCINQ: + /* return number of bytes available */ + dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number); + return get_number_bytes_avail(mos7720_port, + (unsigned int __user *)arg); + break; + + case TIOCSERGETLSR: + dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number); + return get_lsr_info(mos7720_port, (unsigned int __user *)arg); + return 0; + + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__, + port->number); + return set_modem_info(mos7720_port, cmd, + (unsigned int __user *)arg); + + case TIOCMGET: + dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number); + return get_modem_info(mos7720_port, + (unsigned int __user *)arg); + + case TIOCGSERIAL: + dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number); + return get_serial_info(mos7720_port, + (struct serial_struct __user *)arg); + + case TIOCSSERIAL: + dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number); + break; + + case TIOCMIWAIT: + dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number); + cprev = mos7720_port->icount; + while (1) { + if (signal_pending(current)) + return -ERESTARTSYS; + cnow = mos7720_port->icount; + if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && + cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) + return -EIO; /* no change => error */ + if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { + return 0; + } + cprev = cnow; + } + /* NOTREACHED */ + break; + + case TIOCGICOUNT: + cnow = mos7720_port->icount; + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + + dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__, + port->number, icount.rx, icount.tx ); + if (copy_to_user((void __user *)arg, &icount, sizeof(icount))) + return -EFAULT; + return 0; + } + + return -ENOIOCTLCMD; +} + +static int mos7720_startup(struct usb_serial *serial) +{ + struct moschip_serial *mos7720_serial; + struct moschip_port *mos7720_port; + struct usb_device *dev; + int i; + char data; + + dbg("%s: Entering ..........", __FUNCTION__); + + if (!serial) { + dbg("Invalid Handler"); + return -ENODEV; + } + + dev = serial->dev; + + /* create our private serial structure */ + mos7720_serial = kzalloc(sizeof(struct moschip_serial), GFP_KERNEL); + if (mos7720_serial == NULL) { + err("%s - Out of memory", __FUNCTION__); + return -ENOMEM; + } + + usb_set_serial_data(serial, mos7720_serial); + + /* we set up the pointers to the endpoints in the mos7720_open * + * function, as the structures aren't created yet. */ + + /* set up port private structures */ + for (i = 0; i < serial->num_ports; ++i) { + mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); + if (mos7720_port == NULL) { + err("%s - Out of memory", __FUNCTION__); + usb_set_serial_data(serial, NULL); + kfree(mos7720_serial); + return -ENOMEM; + } + + /* Initialize all port interrupt end point to port 0 int + * endpoint. Our device has only one interrupt endpoint + * comman to all ports */ + serial->port[i]->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress; + + mos7720_port->port = serial->port[i]; + usb_set_serial_port_data(serial->port[i], mos7720_port); + + dbg("port number is %d", serial->port[i]->number); + dbg("serial number is %d", serial->minor); + } + + + /* setting configuration feature to one */ + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + (__u8)0x03, 0x00,0x01,0x00, NULL, 0x00, 5*HZ); + + send_mos_cmd(serial,MOS_READ,0x00, UART_LSR, &data); // LSR For Port 1 + dbg("LSR:%x",data); + + send_mos_cmd(serial,MOS_READ,0x01, UART_LSR, &data); // LSR For Port 2 + dbg("LSR:%x",data); + + return 0; +} + +static void mos7720_shutdown(struct usb_serial *serial) +{ + int i; + + /* free private structure allocated for serial port */ + for (i=0; i < serial->num_ports; ++i) { + kfree(usb_get_serial_port_data(serial->port[i])); + usb_set_serial_port_data(serial->port[i], NULL); + } + + /* free private structure allocated for serial device */ + kfree(usb_get_serial_data(serial)); + usb_set_serial_data(serial, NULL); +} + +static struct usb_serial_driver moschip7720_2port_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "moschip7720", + }, + .description = "Moschip 2 port adapter", + .id_table = moschip_port_id_table, + .num_interrupt_in = 1, + .num_bulk_in = 2, + .num_bulk_out = 2, + .num_ports = 2, + .open = mos7720_open, + .close = mos7720_close, + .throttle = mos7720_throttle, + .unthrottle = mos7720_unthrottle, + .attach = mos7720_startup, + .shutdown = mos7720_shutdown, + .ioctl = mos7720_ioctl, + .set_termios = mos7720_set_termios, + .write = mos7720_write, + .write_room = mos7720_write_room, + .chars_in_buffer = mos7720_chars_in_buffer, + .break_ctl = mos7720_break, + .read_bulk_callback = mos7720_bulk_in_callback, +}; + +static struct usb_driver usb_driver = { + .name = "moschip7720", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = moschip_port_id_table, +}; + +static int __init moschip7720_init(void) +{ + int retval; + + dbg("%s: Entering ..........", __FUNCTION__); + + /* Register with the usb serial */ + retval = usb_serial_register(&moschip7720_2port_driver); + if (retval) + goto failed_port_device_register; + + info(DRIVER_DESC " " DRIVER_VERSION); + + /* Register with the usb */ + retval = usb_register(&usb_driver); + if (retval) + goto failed_usb_register; + + return 0; + +failed_usb_register: + usb_serial_deregister(&moschip7720_2port_driver); + +failed_port_device_register: + return retval; +} + +static void __exit moschip7720_exit(void) +{ + usb_deregister(&usb_driver); + usb_serial_deregister(&moschip7720_2port_driver); +} + +module_init(moschip7720_init); +module_exit(moschip7720_exit); + +/* Module information */ +MODULE_AUTHOR( DRIVER_AUTHOR ); +MODULE_DESCRIPTION( DRIVER_DESC ); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index 021be39fe16e..8cc728a49e41 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -826,7 +826,7 @@ static int mos7840_open(struct usb_serial_port *port, struct file *filp) /* Initialising the write urb pool */ for (j = 0; j < NUM_URBS; ++j) { - urb = usb_alloc_urb(0, SLAB_ATOMIC); + urb = usb_alloc_urb(0, GFP_ATOMIC); mos7840_port->write_urb_pool[j] = urb; if (urb == NULL) { @@ -1931,7 +1931,7 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, *****************************************************************************/ static void mos7840_change_port_settings(struct moschip_port *mos7840_port, - struct termios *old_termios) + struct ktermios *old_termios) { struct tty_struct *tty; int baud; @@ -2118,7 +2118,7 @@ static void mos7840_change_port_settings(struct moschip_port *mos7840_port, *****************************************************************************/ static void mos7840_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { int status; unsigned int cflag; @@ -2413,11 +2413,12 @@ static int mos7840_ioctl(struct usb_serial_port *port, struct file *file, } mos7840_port = mos7840_get_port_private(port); - tty = mos7840_port->port->tty; if (mos7840_port == NULL) return -1; + tty = mos7840_port->port->tty; + dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd); switch (cmd) { @@ -2595,12 +2596,11 @@ static int mos7840_startup(struct usb_serial *serial) /* set up port private structures */ for (i = 0; i < serial->num_ports; ++i) { - mos7840_port = kmalloc(sizeof(struct moschip_port), GFP_KERNEL); + mos7840_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL); if (mos7840_port == NULL) { err("%s - Out of memory", __FUNCTION__); return -ENOMEM; } - memset(mos7840_port, 0, sizeof(struct moschip_port)); /* Initialize all port interrupt end point to port 0 int endpoint * * Our device has only one interrupt end point comman to all port */ @@ -2786,7 +2786,7 @@ static int mos7840_startup(struct usb_serial *serial) i + 1, status); } - mos7840_port->control_urb = usb_alloc_urb(0, SLAB_ATOMIC); + mos7840_port->control_urb = usb_alloc_urb(0, GFP_ATOMIC); mos7840_port->ctrl_buf = kmalloc(16, GFP_KERNEL); } diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index 0610409a6568..054abee81652 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c @@ -95,8 +95,7 @@ static void navman_close(struct usb_serial_port *port, struct file *filp) { dbg("%s - port %d", __FUNCTION__, port->number); - if (port->interrupt_in_urb) - usb_kill_urb(port->interrupt_in_urb); + usb_kill_urb(port->interrupt_in_urb); } static int navman_write(struct usb_serial_port *port, diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 130afbbd3fca..0ae4098718c3 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -59,7 +59,7 @@ static int option_chars_in_buffer(struct usb_serial_port *port); static int option_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg); static void option_set_termios(struct usb_serial_port *port, - struct termios *old); + struct ktermios *old); static void option_break_ctl(struct usb_serial_port *port, int break_state); static int option_tiocmget(struct usb_serial_port *port, struct file *file); static int option_tiocmset(struct usb_serial_port *port, struct file *file, @@ -230,7 +230,7 @@ static void option_break_ctl(struct usb_serial_port *port, int break_state) } static void option_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { dbg("%s", __FUNCTION__); diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index bc800c8787a8..d124d780e42e 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -455,7 +455,7 @@ static int pl2303_chars_in_buffer(struct usb_serial_port *port) } static void pl2303_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct usb_serial *serial = port->serial; struct pl2303_private *priv = usb_get_serial_port_data(port); @@ -687,7 +687,7 @@ static void pl2303_close(struct usb_serial_port *port, struct file *filp) static int pl2303_open(struct usb_serial_port *port, struct file *filp) { - struct termios tmp_termios; + struct ktermios tmp_termios; struct usb_serial *serial = port->serial; struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned char *buf; diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index d29638daa987..6d8e91e00ecf 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -1,75 +1,713 @@ /* - * Sierra Wireless CDMA Wireless Serial USB driver - * - * Current Copy modified by: Kevin Lloyd <linux@sierrawireless.com> - * Original Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de> - * - * 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. - */ + USB Driver for Sierra Wireless + + Copyright (C) 2006 Kevin Lloyd <linux@sierrawireless.com> + + IMPORTANT DISCLAIMER: This driver is not commercially supported by + Sierra Wireless. Use at your own risk. + + This driver is free software; you can redistribute it and/or modify + it under the terms of Version 2 of the GNU General Public License as + published by the Free Software Foundation. + + Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de> + Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org> + + History: +*/ + +#define DRIVER_VERSION "v.1.0.5" +#define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>" +#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems" #include <linux/kernel.h> -#include <linux/init.h> +#include <linux/jiffies.h> +#include <linux/errno.h> #include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/module.h> #include <linux/usb.h> #include <linux/usb/serial.h> + static struct usb_device_id id_table [] = { { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ + { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ + { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ - /* Following devices are supported in the airprime.c driver */ - /* { USB_DEVICE(0x1199, 0x0112) }, */ /* Sierra Wireless AirCard 580 */ - /* { USB_DEVICE(0x0F3D, 0x0112) }, */ /* AirPrime/Sierra PC 5220 */ + + { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ + { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */ { } }; MODULE_DEVICE_TABLE(usb, id_table); +static struct usb_device_id id_table_1port [] = { + { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */ + { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */ + { } +}; + +static struct usb_device_id id_table_3port [] = { + { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */ + { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */ + { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */ + { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */ + { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */ + { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */ + { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */ + { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */ + { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */ + { } +}; + static struct usb_driver sierra_driver = { - .name = "sierra_wireless", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, + .name = "sierra", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + + +static int debug; + +/* per port private data */ +#define N_IN_URB 4 +#define N_OUT_URB 1 +#define IN_BUFLEN 4096 +#define OUT_BUFLEN 128 + +struct sierra_port_private { + /* Input endpoints and buffer for this port */ + struct urb *in_urbs[N_IN_URB]; + char in_buffer[N_IN_URB][IN_BUFLEN]; + /* Output endpoints and buffer for this port */ + struct urb *out_urbs[N_OUT_URB]; + char out_buffer[N_OUT_URB][OUT_BUFLEN]; + + /* Settings for the port */ + int rts_state; /* Handshaking pins (outputs) */ + int dtr_state; + int cts_state; /* Handshaking pins (inputs) */ + int dsr_state; + int dcd_state; + int ri_state; + + unsigned long tx_start_time[N_OUT_URB]; +}; + +static int sierra_send_setup(struct usb_serial_port *port) +{ + struct usb_serial *serial = port->serial; + struct sierra_port_private *portdata; + + dbg("%s", __FUNCTION__); + + portdata = usb_get_serial_port_data(port); + + if (port->tty) { + int val = 0; + if (portdata->dtr_state) + val |= 0x01; + if (portdata->rts_state) + val |= 0x02; + + return usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT); + } + + return 0; +} + +static void sierra_rx_throttle(struct usb_serial_port *port) +{ + dbg("%s", __FUNCTION__); +} + +static void sierra_rx_unthrottle(struct usb_serial_port *port) +{ + dbg("%s", __FUNCTION__); +} + +static void sierra_break_ctl(struct usb_serial_port *port, int break_state) +{ + /* Unfortunately, I don't know how to send a break */ + dbg("%s", __FUNCTION__); +} + +static void sierra_set_termios(struct usb_serial_port *port, + struct ktermios *old_termios) +{ + dbg("%s", __FUNCTION__); + + sierra_send_setup(port); +} + +static int sierra_tiocmget(struct usb_serial_port *port, struct file *file) +{ + unsigned int value; + struct sierra_port_private *portdata; + + portdata = usb_get_serial_port_data(port); + + value = ((portdata->rts_state) ? TIOCM_RTS : 0) | + ((portdata->dtr_state) ? TIOCM_DTR : 0) | + ((portdata->cts_state) ? TIOCM_CTS : 0) | + ((portdata->dsr_state) ? TIOCM_DSR : 0) | + ((portdata->dcd_state) ? TIOCM_CAR : 0) | + ((portdata->ri_state) ? TIOCM_RNG : 0); + + return value; +} + +static int sierra_tiocmset(struct usb_serial_port *port, struct file *file, + unsigned int set, unsigned int clear) +{ + struct sierra_port_private *portdata; + + portdata = usb_get_serial_port_data(port); + + if (set & TIOCM_RTS) + portdata->rts_state = 1; + if (set & TIOCM_DTR) + portdata->dtr_state = 1; + + if (clear & TIOCM_RTS) + portdata->rts_state = 0; + if (clear & TIOCM_DTR) + portdata->dtr_state = 0; + return sierra_send_setup(port); +} + +static int sierra_ioctl(struct usb_serial_port *port, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return -ENOIOCTLCMD; +} + +/* Write */ +static int sierra_write(struct usb_serial_port *port, + const unsigned char *buf, int count) +{ + struct sierra_port_private *portdata; + int i; + int left, todo; + struct urb *this_urb = NULL; /* spurious */ + int err; + + portdata = usb_get_serial_port_data(port); + + dbg("%s: write (%d chars)", __FUNCTION__, count); + + i = 0; + left = count; + for (i=0; left > 0 && i < N_OUT_URB; i++) { + todo = left; + if (todo > OUT_BUFLEN) + todo = OUT_BUFLEN; + + this_urb = portdata->out_urbs[i]; + if (this_urb->status == -EINPROGRESS) { + if (time_before(jiffies, + portdata->tx_start_time[i] + 10 * HZ)) + continue; + usb_unlink_urb(this_urb); + continue; + } + if (this_urb->status != 0) + dbg("usb_write %p failed (err=%d)", + this_urb, this_urb->status); + + dbg("%s: endpoint %d buf %d", __FUNCTION__, + usb_pipeendpoint(this_urb->pipe), i); + + /* send the data */ + memcpy (this_urb->transfer_buffer, buf, todo); + this_urb->transfer_buffer_length = todo; + + this_urb->dev = port->serial->dev; + err = usb_submit_urb(this_urb, GFP_ATOMIC); + if (err) { + dbg("usb_submit_urb %p (write bulk) failed " + "(%d, has %d)", this_urb, + err, this_urb->status); + continue; + } + portdata->tx_start_time[i] = jiffies; + buf += todo; + left -= todo; + } + + count -= left; + dbg("%s: wrote (did %d)", __FUNCTION__, count); + return count; +} + +static void sierra_indat_callback(struct urb *urb) +{ + int err; + int endpoint; + struct usb_serial_port *port; + struct tty_struct *tty; + unsigned char *data = urb->transfer_buffer; + + dbg("%s: %p", __FUNCTION__, urb); + + endpoint = usb_pipeendpoint(urb->pipe); + port = (struct usb_serial_port *) urb->context; + + if (urb->status) { + dbg("%s: nonzero status: %d on endpoint %02x.", + __FUNCTION__, urb->status, endpoint); + } else { + tty = port->tty; + if (urb->actual_length) { + tty_buffer_request_room(tty, urb->actual_length); + tty_insert_flip_string(tty, data, urb->actual_length); + tty_flip_buffer_push(tty); + } else { + dbg("%s: empty read urb received", __FUNCTION__); + } + + /* Resubmit urb so we continue receiving */ + if (port->open_count && urb->status != -ESHUTDOWN) { + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) + printk(KERN_ERR "%s: resubmit read urb failed. " + "(%d)", __FUNCTION__, err); + } + } + return; +} + +static void sierra_outdat_callback(struct urb *urb) +{ + struct usb_serial_port *port; + + dbg("%s", __FUNCTION__); + + port = (struct usb_serial_port *) urb->context; + + usb_serial_port_softint(port); +} + +static void sierra_instat_callback(struct urb *urb) +{ + int err; + struct usb_serial_port *port = (struct usb_serial_port *) urb->context; + struct sierra_port_private *portdata = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; + + dbg("%s", __FUNCTION__); + dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata); + + if (urb->status == 0) { + struct usb_ctrlrequest *req_pkt = + (struct usb_ctrlrequest *)urb->transfer_buffer; + + if (!req_pkt) { + dbg("%s: NULL req_pkt\n", __FUNCTION__); + return; + } + if ((req_pkt->bRequestType == 0xA1) && + (req_pkt->bRequest == 0x20)) { + int old_dcd_state; + unsigned char signals = *((unsigned char *) + urb->transfer_buffer + + sizeof(struct usb_ctrlrequest)); + + dbg("%s: signal x%x", __FUNCTION__, signals); + + old_dcd_state = portdata->dcd_state; + portdata->cts_state = 1; + portdata->dcd_state = ((signals & 0x01) ? 1 : 0); + portdata->dsr_state = ((signals & 0x02) ? 1 : 0); + portdata->ri_state = ((signals & 0x08) ? 1 : 0); + + if (port->tty && !C_CLOCAL(port->tty) && + old_dcd_state && !portdata->dcd_state) + tty_hangup(port->tty); + } else { + dbg("%s: type %x req %x", __FUNCTION__, + req_pkt->bRequestType,req_pkt->bRequest); + } + } else + dbg("%s: error %d", __FUNCTION__, urb->status); + + /* Resubmit urb so we continue receiving IRQ data */ + if (urb->status != -ESHUTDOWN) { + urb->dev = serial->dev; + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) + dbg("%s: resubmit intr urb failed. (%d)", + __FUNCTION__, err); + } +} + +static int sierra_write_room(struct usb_serial_port *port) +{ + struct sierra_port_private *portdata; + int i; + int data_len = 0; + struct urb *this_urb; + + portdata = usb_get_serial_port_data(port); + + for (i=0; i < N_OUT_URB; i++) { + this_urb = portdata->out_urbs[i]; + if (this_urb && this_urb->status != -EINPROGRESS) + data_len += OUT_BUFLEN; + } + + dbg("%s: %d", __FUNCTION__, data_len); + return data_len; +} + +static int sierra_chars_in_buffer(struct usb_serial_port *port) +{ + struct sierra_port_private *portdata; + int i; + int data_len = 0; + struct urb *this_urb; + + portdata = usb_get_serial_port_data(port); + + for (i=0; i < N_OUT_URB; i++) { + this_urb = portdata->out_urbs[i]; + if (this_urb && this_urb->status == -EINPROGRESS) + data_len += this_urb->transfer_buffer_length; + } + dbg("%s: %d", __FUNCTION__, data_len); + return data_len; +} + +static int sierra_open(struct usb_serial_port *port, struct file *filp) +{ + struct sierra_port_private *portdata; + struct usb_serial *serial = port->serial; + int i, err; + struct urb *urb; + + portdata = usb_get_serial_port_data(port); + + dbg("%s", __FUNCTION__); + + /* Set some sane defaults */ + portdata->rts_state = 1; + portdata->dtr_state = 1; + + /* Reset low level data toggle and start reading from endpoints */ + for (i = 0; i < N_IN_URB; i++) { + urb = portdata->in_urbs[i]; + if (! urb) + continue; + if (urb->dev != serial->dev) { + dbg("%s: dev %p != %p", __FUNCTION__, + urb->dev, serial->dev); + continue; + } + + /* + * make sure endpoint data toggle is synchronized with the + * device + */ + usb_clear_halt(urb->dev, urb->pipe); + + err = usb_submit_urb(urb, GFP_KERNEL); + if (err) { + dbg("%s: submit urb %d failed (%d) %d", + __FUNCTION__, i, err, + urb->transfer_buffer_length); + } + } + + /* Reset low level data toggle on out endpoints */ + for (i = 0; i < N_OUT_URB; i++) { + urb = portdata->out_urbs[i]; + if (! urb) + continue; + urb->dev = serial->dev; + /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), + usb_pipeout(urb->pipe), 0); */ + } + + port->tty->low_latency = 1; + + sierra_send_setup(port); + + return (0); +} + +static inline void stop_urb(struct urb *urb) +{ + if (urb && urb->status == -EINPROGRESS) + usb_kill_urb(urb); +} + +static void sierra_close(struct usb_serial_port *port, struct file *filp) +{ + int i; + struct usb_serial *serial = port->serial; + struct sierra_port_private *portdata; + + dbg("%s", __FUNCTION__); + portdata = usb_get_serial_port_data(port); + + portdata->rts_state = 0; + portdata->dtr_state = 0; + + if (serial->dev) { + sierra_send_setup(port); + + /* Stop reading/writing urbs */ + for (i = 0; i < N_IN_URB; i++) + stop_urb(portdata->in_urbs[i]); + for (i = 0; i < N_OUT_URB; i++) + stop_urb(portdata->out_urbs[i]); + } + port->tty = NULL; +} + +/* Helper functions used by sierra_setup_urbs */ +static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint, + int dir, void *ctx, char *buf, int len, + usb_complete_t callback) +{ + struct urb *urb; + + if (endpoint == -1) + return NULL; /* endpoint not needed */ + + urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */ + if (urb == NULL) { + dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint); + return NULL; + } + + /* Fill URB using supplied data. */ + usb_fill_bulk_urb(urb, serial->dev, + usb_sndbulkpipe(serial->dev, endpoint) | dir, + buf, len, callback, ctx); + + return urb; +} + +/* Setup urbs */ +static void sierra_setup_urbs(struct usb_serial *serial) +{ + int i,j; + struct usb_serial_port *port; + struct sierra_port_private *portdata; + + dbg("%s", __FUNCTION__); + + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); + + /* Do indat endpoints first */ + for (j = 0; j < N_IN_URB; ++j) { + portdata->in_urbs[j] = sierra_setup_urb (serial, + port->bulk_in_endpointAddress, USB_DIR_IN, port, + portdata->in_buffer[j], IN_BUFLEN, sierra_indat_callback); + } + + /* outdat endpoints */ + for (j = 0; j < N_OUT_URB; ++j) { + portdata->out_urbs[j] = sierra_setup_urb (serial, + port->bulk_out_endpointAddress, USB_DIR_OUT, port, + portdata->out_buffer[j], OUT_BUFLEN, sierra_outdat_callback); + } + } +} + +static int sierra_startup(struct usb_serial *serial) +{ + int i, err; + struct usb_serial_port *port; + struct sierra_port_private *portdata; + + dbg("%s", __FUNCTION__); + + /* Now setup per port private data */ + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + portdata = kzalloc(sizeof(*portdata), GFP_KERNEL); + if (!portdata) { + dbg("%s: kmalloc for sierra_port_private (%d) failed!.", + __FUNCTION__, i); + return (1); + } + + usb_set_serial_port_data(port, portdata); + + if (! port->interrupt_in_urb) + continue; + err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); + if (err) + dbg("%s: submit irq_in urb failed %d", + __FUNCTION__, err); + } + + sierra_setup_urbs(serial); + + return (0); +} + +static void sierra_shutdown(struct usb_serial *serial) +{ + int i, j; + struct usb_serial_port *port; + struct sierra_port_private *portdata; + + dbg("%s", __FUNCTION__); + + /* Stop reading/writing urbs */ + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); + for (j = 0; j < N_IN_URB; j++) + stop_urb(portdata->in_urbs[j]); + for (j = 0; j < N_OUT_URB; j++) + stop_urb(portdata->out_urbs[j]); + } + + /* Now free them */ + for (i = 0; i < serial->num_ports; ++i) { + port = serial->port[i]; + portdata = usb_get_serial_port_data(port); + + for (j = 0; j < N_IN_URB; j++) { + if (portdata->in_urbs[j]) { + usb_free_urb(portdata->in_urbs[j]); + portdata->in_urbs[j] = NULL; + } + } + for (j = 0; j < N_OUT_URB; j++) { + if (portdata->out_urbs[j]) { + usb_free_urb(portdata->out_urbs[j]); + portdata->out_urbs[j] = NULL; + } + } + } + + /* Now free per port private data */ + for (i = 0; i < serial->num_ports; i++) { + port = serial->port[i]; + kfree(usb_get_serial_port_data(port)); + } +} + +static struct usb_serial_driver sierra_1port_device = { + .driver = { + .owner = THIS_MODULE, + .name = "sierra1", + }, + .description = "Sierra USB modem (1 port)", + .id_table = id_table_1port, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = 1, + .num_bulk_out = 1, + .num_ports = 1, + .open = sierra_open, + .close = sierra_close, + .write = sierra_write, + .write_room = sierra_write_room, + .chars_in_buffer = sierra_chars_in_buffer, + .throttle = sierra_rx_throttle, + .unthrottle = sierra_rx_unthrottle, + .ioctl = sierra_ioctl, + .set_termios = sierra_set_termios, + .break_ctl = sierra_break_ctl, + .tiocmget = sierra_tiocmget, + .tiocmset = sierra_tiocmset, + .attach = sierra_startup, + .shutdown = sierra_shutdown, + .read_int_callback = sierra_instat_callback, }; -static struct usb_serial_driver sierra_device = { +static struct usb_serial_driver sierra_3port_device = { .driver = { - .owner = THIS_MODULE, - .name = "Sierra_Wireless", + .owner = THIS_MODULE, + .name = "sierra3", }, - .id_table = id_table, - .num_interrupt_in = NUM_DONT_CARE, - .num_bulk_in = NUM_DONT_CARE, - .num_bulk_out = NUM_DONT_CARE, - .num_ports = 3, + .description = "Sierra USB modem (3 port)", + .id_table = id_table_3port, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = 3, + .num_bulk_out = 3, + .num_ports = 3, + .open = sierra_open, + .close = sierra_close, + .write = sierra_write, + .write_room = sierra_write_room, + .chars_in_buffer = sierra_chars_in_buffer, + .throttle = sierra_rx_throttle, + .unthrottle = sierra_rx_unthrottle, + .ioctl = sierra_ioctl, + .set_termios = sierra_set_termios, + .break_ctl = sierra_break_ctl, + .tiocmget = sierra_tiocmget, + .tiocmset = sierra_tiocmset, + .attach = sierra_startup, + .shutdown = sierra_shutdown, + .read_int_callback = sierra_instat_callback, }; +/* Functions used by new usb-serial code. */ static int __init sierra_init(void) { int retval; - - retval = usb_serial_register(&sierra_device); + retval = usb_serial_register(&sierra_1port_device); + if (retval) + goto failed_1port_device_register; + retval = usb_serial_register(&sierra_3port_device); if (retval) - return retval; + goto failed_3port_device_register; + + retval = usb_register(&sierra_driver); if (retval) - usb_serial_deregister(&sierra_device); + goto failed_driver_register; + + info(DRIVER_DESC ": " DRIVER_VERSION); + + return 0; + +failed_driver_register: + usb_serial_deregister(&sierra_3port_device); +failed_3port_device_register: + usb_serial_deregister(&sierra_1port_device); +failed_1port_device_register: return retval; } static void __exit sierra_exit(void) { - usb_deregister(&sierra_driver); - usb_serial_deregister(&sierra_device); + usb_deregister (&sierra_driver); + usb_serial_deregister(&sierra_1port_device); + usb_serial_deregister(&sierra_3port_device); } module_init(sierra_init); module_exit(sierra_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); + +#ifdef CONFIG_USB_DEBUG +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug messages"); +#endif + diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index 07400c0c8a8c..f42eb9ea6405 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -161,7 +161,7 @@ static void ti_throttle(struct usb_serial_port *port); static void ti_unthrottle(struct usb_serial_port *port); static int ti_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg); static void ti_set_termios(struct usb_serial_port *port, - struct termios *old_termios); + struct ktermios *old_termios); static int ti_tiocmget(struct usb_serial_port *port, struct file *file); static int ti_tiocmset(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); @@ -228,6 +228,7 @@ static int product_5052_count; /* null entry */ static struct usb_device_id ti_id_table_3410[1+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, }; static struct usb_device_id ti_id_table_5052[4+TI_EXTRA_VID_PID_COUNT+1] = { @@ -239,6 +240,7 @@ static struct usb_device_id ti_id_table_5052[4+TI_EXTRA_VID_PID_COUNT+1] = { static struct usb_device_id ti_id_table_combined[] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5052_BOOT_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5152_BOOT_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_5052_EEPROM_PRODUCT_ID) }, @@ -459,13 +461,12 @@ static int ti_startup(struct usb_serial *serial) /* set up port structures */ for (i = 0; i < serial->num_ports; ++i) { - tport = kmalloc(sizeof(struct ti_port), GFP_KERNEL); + tport = kzalloc(sizeof(struct ti_port), GFP_KERNEL); if (tport == NULL) { dev_err(&dev->dev, "%s - out of memory\n", __FUNCTION__); status = -ENOMEM; goto free_tports; } - memset(tport, 0, sizeof(struct ti_port)); spin_lock_init(&tport->tp_lock); tport->tp_uart_base_addr = (i == 0 ? TI_UART1_BASE_ADDR : TI_UART2_BASE_ADDR); tport->tp_flags = low_latency ? ASYNC_LOW_LATENCY : 0; @@ -880,7 +881,7 @@ static int ti_ioctl(struct usb_serial_port *port, struct file *file, static void ti_set_termios(struct usb_serial_port *port, - struct termios *old_termios) + struct ktermios *old_termios) { struct ti_port *tport = usb_get_serial_port_data(port); struct tty_struct *tty = port->tty; diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h index 02c1aeb9e1b8..b5541bf991ba 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.h +++ b/drivers/usb/serial/ti_usb_3410_5052.h @@ -28,6 +28,7 @@ /* Vendor and product ids */ #define TI_VENDOR_ID 0x0451 #define TI_3410_PRODUCT_ID 0x3410 +#define TI_3410_EZ430_ID 0xF430 /* TI ez430 development tool */ #define TI_5052_BOOT_PRODUCT_ID 0x5052 /* no EEPROM, no firmware */ #define TI_5152_BOOT_PRODUCT_ID 0x5152 /* no EEPROM, no firmware */ #define TI_5052_EEPROM_PRODUCT_ID 0x505A /* EEPROM, no firmware */ diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 8006e51c34bb..716f6806cc89 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -397,7 +397,7 @@ exit: return retval; } -static void serial_set_termios (struct tty_struct *tty, struct termios * old) +static void serial_set_termios (struct tty_struct *tty, struct ktermios * old) { struct usb_serial_port *port = tty->driver_data; @@ -533,9 +533,10 @@ void usb_serial_port_softint(struct usb_serial_port *port) schedule_work(&port->work); } -static void usb_serial_port_work(void *private) +static void usb_serial_port_work(struct work_struct *work) { - struct usb_serial_port *port = private; + struct usb_serial_port *port = + container_of(work, struct usb_serial_port, work); struct tty_struct *tty; dbg("%s - port %d", __FUNCTION__, port->number); @@ -799,7 +800,7 @@ int usb_serial_probe(struct usb_interface *interface, port->serial = serial; spin_lock_init(&port->lock); mutex_init(&port->mutex); - INIT_WORK(&port->work, usb_serial_port_work, port); + INIT_WORK(&port->work, usb_serial_port_work); serial->port[i] = port; } @@ -952,32 +953,28 @@ probe_error: port = serial->port[i]; if (!port) continue; - if (port->read_urb) - usb_free_urb (port->read_urb); + usb_free_urb(port->read_urb); kfree(port->bulk_in_buffer); } for (i = 0; i < num_bulk_out; ++i) { port = serial->port[i]; if (!port) continue; - if (port->write_urb) - usb_free_urb (port->write_urb); + usb_free_urb(port->write_urb); kfree(port->bulk_out_buffer); } for (i = 0; i < num_interrupt_in; ++i) { port = serial->port[i]; if (!port) continue; - if (port->interrupt_in_urb) - usb_free_urb (port->interrupt_in_urb); + usb_free_urb(port->interrupt_in_urb); kfree(port->interrupt_in_buffer); } for (i = 0; i < num_interrupt_out; ++i) { port = serial->port[i]; if (!port) continue; - if (port->interrupt_out_urb) - usb_free_urb (port->interrupt_out_urb); + usb_free_urb(port->interrupt_out_urb); kfree(port->interrupt_out_buffer); } diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c new file mode 100644 index 000000000000..257a5e436873 --- /dev/null +++ b/drivers/usb/serial/usb_debug.c @@ -0,0 +1,65 @@ +/* + * USB Debug cable driver + * + * Copyright (C) 2006 Greg Kroah-Hartman <greg@kroah.com> + * + * 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/kernel.h> +#include <linux/init.h> +#include <linux/tty.h> +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> + +static struct usb_device_id id_table [] = { + { USB_DEVICE(0x0525, 0x127a) }, + { }, +}; +MODULE_DEVICE_TABLE(usb, id_table); + +static struct usb_driver debug_driver = { + .name = "debug", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, + .no_dynamic_id = 1, +}; + +static struct usb_serial_driver debug_device = { + .driver = { + .owner = THIS_MODULE, + .name = "debug", + }, + .id_table = id_table, + .num_interrupt_in = NUM_DONT_CARE, + .num_bulk_in = NUM_DONT_CARE, + .num_bulk_out = NUM_DONT_CARE, + .num_ports = 1, +}; + +static int __init debug_init(void) +{ + int retval; + + retval = usb_serial_register(&debug_device); + if (retval) + return retval; + retval = usb_register(&debug_driver); + if (retval) + usb_serial_deregister(&debug_device); + return retval; +} + +static void __exit debug_exit(void) +{ + usb_deregister(&debug_driver); + usb_serial_deregister(&debug_device); +} + +module_init(debug_init); +module_exit(debug_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index befe2e11a041..b09f06096056 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -46,7 +46,7 @@ static int visor_probe (struct usb_serial *serial, const struct usb_device_id static int visor_calc_num_ports(struct usb_serial *serial); static void visor_shutdown (struct usb_serial *serial); static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); -static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios); +static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios); static void visor_write_bulk_callback (struct urb *urb); static void visor_read_bulk_callback (struct urb *urb); static void visor_read_int_callback (struct urb *urb); @@ -348,8 +348,7 @@ static void visor_close (struct usb_serial_port *port, struct file * filp) /* shutdown our urbs */ usb_kill_urb(port->read_urb); - if (port->interrupt_in_urb) - usb_kill_urb(port->interrupt_in_urb); + usb_kill_urb(port->interrupt_in_urb); /* Try to send shutdown message, if the device is gone, this will just fail. */ transfer_buffer = kmalloc (0x12, GFP_KERNEL); @@ -917,7 +916,7 @@ static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsign /* This function is all nice and good, but we don't change anything based on it :) */ -static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void visor_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { unsigned int cflag; diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 4d1cd7aeccd3..dc45e58e2b8c 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -145,7 +145,7 @@ static void whiteheat_close (struct usb_serial_port *port, struct file *filp); static int whiteheat_write (struct usb_serial_port *port, const unsigned char *buf, int count); static int whiteheat_write_room (struct usb_serial_port *port); static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg); -static void whiteheat_set_termios (struct usb_serial_port *port, struct termios * old); +static void whiteheat_set_termios (struct usb_serial_port *port, struct ktermios * old); static int whiteheat_tiocmget (struct usb_serial_port *port, struct file *file); static int whiteheat_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear); static void whiteheat_break_ctl (struct usb_serial_port *port, int break_state); @@ -227,6 +227,7 @@ struct whiteheat_private { struct list_head rx_urbs_submitted; struct list_head rx_urb_q; struct work_struct rx_work; + struct usb_serial_port *port; struct list_head tx_urbs_free; struct list_head tx_urbs_submitted; }; @@ -241,7 +242,7 @@ static void command_port_read_callback(struct urb *urb); static int start_port_read(struct usb_serial_port *port); static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb, struct list_head *head); static struct list_head *list_first(struct list_head *head); -static void rx_data_softint(void *private); +static void rx_data_softint(struct work_struct *work); static int firm_send_command(struct usb_serial_port *port, __u8 command, __u8 *data, __u8 datasize); static int firm_open(struct usb_serial_port *port); @@ -424,7 +425,8 @@ static int whiteheat_attach (struct usb_serial *serial) spin_lock_init(&info->lock); info->flags = 0; info->mcr = 0; - INIT_WORK(&info->rx_work, rx_data_softint, port); + INIT_WORK(&info->rx_work, rx_data_softint); + info->port = port; INIT_LIST_HEAD(&info->rx_urbs_free); INIT_LIST_HEAD(&info->rx_urbs_submitted); @@ -595,7 +597,7 @@ static void whiteheat_shutdown (struct usb_serial *serial) static int whiteheat_open (struct usb_serial_port *port, struct file *filp) { int retval = 0; - struct termios old_term; + struct ktermios old_term; dbg("%s - port %d", __FUNCTION__, port->number); @@ -868,7 +870,7 @@ static int whiteheat_ioctl (struct usb_serial_port *port, struct file * file, un } -static void whiteheat_set_termios (struct usb_serial_port *port, struct termios *old_termios) +static void whiteheat_set_termios (struct usb_serial_port *port, struct ktermios *old_termios) { dbg("%s -port %d", __FUNCTION__, port->number); @@ -949,7 +951,7 @@ static void whiteheat_unthrottle (struct usb_serial_port *port) spin_unlock_irqrestore(&info->lock, flags); if (actually_throttled) - rx_data_softint(port); + rx_data_softint(&info->rx_work); return; } @@ -1400,10 +1402,11 @@ static struct list_head *list_first(struct list_head *head) } -static void rx_data_softint(void *private) +static void rx_data_softint(struct work_struct *work) { - struct usb_serial_port *port = (struct usb_serial_port *)private; - struct whiteheat_private *info = usb_get_serial_port_data(port); + struct whiteheat_private *info = + container_of(work, struct whiteheat_private, rx_work); + struct usb_serial_port *port = info->port; struct tty_struct *tty = port->tty; struct whiteheat_urb_wrap *wrap; struct urb *urb; diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c index 3baf448e300d..e565d3d2ab29 100644 --- a/drivers/usb/storage/onetouch.c +++ b/drivers/usb/storage/onetouch.c @@ -76,7 +76,7 @@ static void usb_onetouch_irq(struct urb *urb) input_sync(dev); resubmit: - status = usb_submit_urb (urb, SLAB_ATOMIC); + status = usb_submit_urb (urb, GFP_ATOMIC); if (status) err ("can't resubmit intr, %s-%s/input0, status %d", onetouch->udev->bus->bus_name, @@ -142,10 +142,7 @@ int onetouch_connect_input(struct us_data *ss) return -ENODEV; endpoint = &interface->endpoint[2].desc; - if (!(endpoint->bEndpointAddress & USB_DIR_IN)) - return -ENODEV; - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - != USB_ENDPOINT_XFER_INT) + if (!usb_endpoint_is_int_in(endpoint)) return -ENODEV; pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress); @@ -157,7 +154,7 @@ int onetouch_connect_input(struct us_data *ss) goto fail1; onetouch->data = usb_buffer_alloc(udev, ONETOUCH_PKT_LEN, - SLAB_ATOMIC, &onetouch->data_dma); + GFP_ATOMIC, &onetouch->data_dma); if (!onetouch->data) goto fail1; diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 47644b5b6155..323293a3e61f 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -427,7 +427,7 @@ static int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, US_DEBUGP("%s: xfer %u bytes, %d entries\n", __FUNCTION__, length, num_sg); result = usb_sg_init(&us->current_sg, us->pusb_dev, pipe, 0, - sg, num_sg, length, SLAB_NOIO); + sg, num_sg, length, GFP_NOIO); if (result) { US_DEBUGP("usb_sg_init returned %d\n", result); return USB_STOR_XFER_ERROR; diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index c9a8d50106d1..db8b26012c75 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -55,7 +55,8 @@ UNUSUAL_DEV( 0x03eb, 0x2002, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE), -UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0100, +/* modified by Tobias Lorenz <tobias.lorenz@gmx.net> */ +UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0200, "Mitsumi", "USB FDD", US_SC_DEVICE, US_PR_DEVICE, NULL, @@ -182,6 +183,20 @@ UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), +/* Reported by Bardur Arantsson <bardur@scientician.net> */ +UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370, + "Nokia", + "6131", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64 ), + +/* Reported by Alex Corcoles <alex@corcoles.net> */ +UNUSUAL_DEV( 0x0421, 0x0495, 0x0370, 0x0370, + "Nokia", + "6234", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64 ), + /* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */ UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210, "SMSC", @@ -1221,7 +1236,7 @@ UNUSUAL_DEV( 0x0e21, 0x0520, 0x0100, 0x0100, "Cowon Systems", "iAUDIO M5", US_SC_DEVICE, US_PR_BULK, NULL, - 0 ), + US_FL_NEED_OVERRIDE ), /* Submitted by Antoine Mairesse <antoine.mairesse@free.fr> */ UNUSUAL_DEV( 0x0ed1, 0x6660, 0x0100, 0x0300, @@ -1294,13 +1309,25 @@ UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000, /* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu> * Tested on hardware version 1.10. * Entry is needed only for the initializer function override. + * Devices with bcd > 110 seem to not need it while those + * with bcd < 110 appear to need it. */ -UNUSUAL_DEV( 0x1019, 0x0c55, 0x0110, 0x0110, +UNUSUAL_DEV( 0x1019, 0x0c55, 0x0000, 0x0110, "Desknote", "UCR-61S2B", US_SC_DEVICE, US_PR_DEVICE, usb_stor_ucr61s2b_init, 0 ), +/* Reported by Jaco Kroon <jaco@kroon.co.za> + * The usb-storage module found on the Digitech GNX4 (and supposedly other + * devices) misbehaves and causes a bunch of invalid I/O errors. + */ +UNUSUAL_DEV( 0x1210, 0x0003, 0x0100, 0x0100, + "Digitech HMG", + "DigiTech Mass Storage", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_IGNORE_RESIDUE ), + /* Reported by Vilius Bilinkevicius <vilisas AT xxx DOT lt) */ UNUSUAL_DEV( 0x132b, 0x000b, 0x0001, 0x0001, "Minolta", diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index b8d6031b0975..70644506651f 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -49,7 +49,7 @@ #include <linux/sched.h> #include <linux/errno.h> -#include <linux/suspend.h> +#include <linux/freezer.h> #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> @@ -740,18 +740,16 @@ static int get_pipes(struct us_data *us) ep = &altsetting->endpoint[i].desc; /* Is it a BULK endpoint? */ - if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_BULK) { + if (usb_endpoint_xfer_bulk(ep)) { /* BULK in or out? */ - if (ep->bEndpointAddress & USB_DIR_IN) + if (usb_endpoint_dir_in(ep)) ep_in = ep; else ep_out = ep; } /* Is it an interrupt endpoint? */ - else if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_INT) { + else if (usb_endpoint_xfer_int(ep)) { ep_int = ep; } } |