Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6

This commit is contained in:
Linus Torvalds 2005-06-27 15:13:26 -07:00
commit d3b8a1a849
80 changed files with 8610 additions and 3866 deletions

View File

@ -288,8 +288,8 @@ static void usb_release(struct device *dev)
static struct resource udc_resources[] = {
/* order is significant! */
{ /* registers */
.start = IO_ADDRESS(UDC_BASE),
.end = IO_ADDRESS(UDC_BASE + 0xff),
.start = UDC_BASE,
.end = UDC_BASE + 0xff,
.flags = IORESOURCE_MEM,
}, { /* general IRQ */
.start = IH2_BASE + 20,
@ -355,8 +355,8 @@ static struct platform_device ohci_device = {
static struct resource otg_resources[] = {
/* order is significant! */
{
.start = IO_ADDRESS(OTG_BASE),
.end = IO_ADDRESS(OTG_BASE + 0xff),
.start = OTG_BASE,
.end = OTG_BASE + 0xff,
.flags = IORESOURCE_MEM,
}, {
.start = IH2_BASE + 8,

View File

@ -9,6 +9,7 @@ obj-$(CONFIG_USB) += core/
obj-$(CONFIG_USB_MON) += mon/
obj-$(CONFIG_USB_EHCI_HCD) += host/
obj-$(CONFIG_USB_ISP116X_HCD) += host/
obj-$(CONFIG_USB_OHCI_HCD) += host/
obj-$(CONFIG_USB_UHCI_HCD) += host/
obj-$(CONFIG_USB_SL811_HCD) += host/

View File

@ -1,30 +1,60 @@
#
# USB ATM driver configuration
# USB/ATM DSL configuration
#
comment "USB ATM/DSL drivers"
menu "USB DSL modem support"
depends on USB
config USB_ATM
tristate "Generic USB ATM/DSL core I/O support"
tristate "USB DSL modem support"
depends on USB && ATM
select CRC32
default n
help
This provides a library which is used for packet I/O by USB DSL
modems, such as the SpeedTouch driver below.
Say Y here if you want to connect a USB Digital Subscriber Line (DSL)
modem to your computer's USB port. You will then need to choose your
modem from the list below.
To compile this driver as a module, choose M here: the
module will be called usb_atm.
module will be called usbatm.
config USB_SPEEDTOUCH
tristate "Alcatel Speedtouch USB support"
depends on USB && ATM
select USB_ATM
tristate "Speedtouch USB support"
depends on USB_ATM
select FW_LOADER
help
Say Y here if you have an Alcatel SpeedTouch USB or SpeedTouch 330
Say Y here if you have an SpeedTouch USB or SpeedTouch 330
modem. In order to use your modem you will need to install the
two parts of the firmware, extracted by the user space tools; see
<http://www.linux-usb.org/SpeedTouch/> for details.
To compile this driver as a module, choose M here: the
module will be called speedtch.
config USB_CXACRU
tristate "Conexant AccessRunner USB support"
depends on USB_ATM
select FW_LOADER
help
Say Y here if you have an ADSL USB modem based on the Conexant
AccessRunner chipset. In order to use your modem you will need to
install the firmware, extracted by the user space tools; see
<http://accessrunner.sourceforge.net/> for details.
To compile this driver as a module, choose M here: the
module will be called cxacru.
config USB_XUSBATM
tristate "Other USB DSL modem support"
depends on USB_ATM
help
Say Y here if you have a DSL USB modem not explicitly supported by
another USB DSL drivers. In order to use your modem you will need to
pass the vendor ID, product ID, and endpoint numbers for transmission
and reception as module parameters. You may need to initialize the
the modem using a user space utility (a firmware loader for example).
To compile this driver as a module, choose M here: the
module will be called xusbatm.
endmenu

View File

@ -1,7 +1,8 @@
#
# Makefile for the rest of the USB drivers
# (the ones that don't fit into any other categories)
# Makefile for USB ATM/xDSL drivers
#
obj-$(CONFIG_USB_ATM) += usb_atm.o
obj-$(CONFIG_USB_CXACRU) += cxacru.o
obj-$(CONFIG_USB_SPEEDTOUCH) += speedtch.o
obj-$(CONFIG_USB_ATM) += usbatm.o
obj-$(CONFIG_USB_XUSBATM) += xusbatm.o

878
drivers/usb/atm/cxacru.c Normal file
View File

@ -0,0 +1,878 @@
/******************************************************************************
* cxacru.c - driver for USB ADSL modems based on
* Conexant AccessRunner chipset
*
* Copyright (C) 2004 David Woodhouse, Duncan Sands, Roman Kagan
* Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru)
*
* 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.
*
******************************************************************************/
/*
* Credit is due for Josep Comas, who created the original patch to speedtch.c
* to support the different padding used by the AccessRunner (now generalized
* into usbatm), and the userspace firmware loading utility.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/device.h> /* FIXME: linux/firmware.h should include it itself */
#include <linux/firmware.h>
#include "usbatm.h"
#define DRIVER_AUTHOR "Roman Kagan, David Woodhouse, Duncan Sands"
#define DRIVER_VERSION "0.2"
#define DRIVER_DESC "Conexant AccessRunner ADSL USB modem driver"
static const char cxacru_driver_name[] = "cxacru";
#define CXACRU_EP_CMD 0x01 /* Bulk/interrupt in/out */
#define CXACRU_EP_DATA 0x02 /* Bulk in/out */
#define CMD_PACKET_SIZE 64 /* Should be maxpacket(ep)? */
/* Addresses */
#define PLLFCLK_ADDR 0x00350068
#define PLLBCLK_ADDR 0x0035006c
#define SDRAMEN_ADDR 0x00350010
#define FW_ADDR 0x00801000
#define BR_ADDR 0x00180600
#define SIG_ADDR 0x00180500
#define BR_STACK_ADDR 0x00187f10
/* Values */
#define SDRAM_ENA 0x1
#define CMD_TIMEOUT 2000 /* msecs */
#define POLL_INTERVAL 5000 /* msecs */
/* commands for interaction with the modem through the control channel before
* firmware is loaded */
enum cxacru_fw_request {
FW_CMD_ERR,
FW_GET_VER,
FW_READ_MEM,
FW_WRITE_MEM,
FW_RMW_MEM,
FW_CHECKSUM_MEM,
FW_GOTO_MEM,
};
/* commands for interaction with the modem through the control channel once
* firmware is loaded */
enum cxacru_cm_request {
CM_REQUEST_UNDEFINED = 0x80,
CM_REQUEST_TEST,
CM_REQUEST_CHIP_GET_MAC_ADDRESS,
CM_REQUEST_CHIP_GET_DP_VERSIONS,
CM_REQUEST_CHIP_ADSL_LINE_START,
CM_REQUEST_CHIP_ADSL_LINE_STOP,
CM_REQUEST_CHIP_ADSL_LINE_GET_STATUS,
CM_REQUEST_CHIP_ADSL_LINE_GET_SPEED,
CM_REQUEST_CARD_INFO_GET,
CM_REQUEST_CARD_DATA_GET,
CM_REQUEST_CARD_DATA_SET,
CM_REQUEST_COMMAND_HW_IO,
CM_REQUEST_INTERFACE_HW_IO,
CM_REQUEST_CARD_SERIAL_DATA_PATH_GET,
CM_REQUEST_CARD_SERIAL_DATA_PATH_SET,
CM_REQUEST_CARD_CONTROLLER_VERSION_GET,
CM_REQUEST_CARD_GET_STATUS,
CM_REQUEST_CARD_GET_MAC_ADDRESS,
CM_REQUEST_CARD_GET_DATA_LINK_STATUS,
CM_REQUEST_MAX,
};
/* reply codes to the commands above */
enum cxacru_cm_status {
CM_STATUS_UNDEFINED,
CM_STATUS_SUCCESS,
CM_STATUS_ERROR,
CM_STATUS_UNSUPPORTED,
CM_STATUS_UNIMPLEMENTED,
CM_STATUS_PARAMETER_ERROR,
CM_STATUS_DBG_LOOPBACK,
CM_STATUS_MAX,
};
/* indices into CARD_INFO_GET return array */
enum cxacru_info_idx {
CXINF_DOWNSTREAM_RATE,
CXINF_UPSTREAM_RATE,
CXINF_LINK_STATUS,
CXINF_LINE_STATUS,
CXINF_MAC_ADDRESS_HIGH,
CXINF_MAC_ADDRESS_LOW,
CXINF_UPSTREAM_SNR_MARGIN,
CXINF_DOWNSTREAM_SNR_MARGIN,
CXINF_UPSTREAM_ATTENUATION,
CXINF_DOWNSTREAM_ATTENUATION,
CXINF_TRANSMITTER_POWER,
CXINF_UPSTREAM_BITS_PER_FRAME,
CXINF_DOWNSTREAM_BITS_PER_FRAME,
CXINF_STARTUP_ATTEMPTS,
CXINF_UPSTREAM_CRC_ERRORS,
CXINF_DOWNSTREAM_CRC_ERRORS,
CXINF_UPSTREAM_FEC_ERRORS,
CXINF_DOWNSTREAM_FEC_ERRORS,
CXINF_UPSTREAM_HEC_ERRORS,
CXINF_DOWNSTREAM_HEC_ERRORS,
CXINF_LINE_STARTABLE,
CXINF_MODULATION,
CXINF_ADSL_HEADEND,
CXINF_ADSL_HEADEND_ENVIRONMENT,
CXINF_CONTROLLER_VERSION,
/* dunno what the missing two mean */
CXINF_MAX = 0x1c,
};
struct cxacru_modem_type {
u32 pll_f_clk;
u32 pll_b_clk;
int boot_rom_patch;
};
struct cxacru_data {
struct usbatm_data *usbatm;
const struct cxacru_modem_type *modem_type;
int line_status;
struct work_struct poll_work;
/* contol handles */
struct semaphore cm_serialize;
u8 *rcv_buf;
u8 *snd_buf;
struct urb *rcv_urb;
struct urb *snd_urb;
struct completion rcv_done;
struct completion snd_done;
};
/* the following three functions are stolen from drivers/usb/core/message.c */
static void cxacru_blocking_completion(struct urb *urb, struct pt_regs *regs)
{
complete((struct completion *)urb->context);
}
static void cxacru_timeout_kill(unsigned long data)
{
usb_unlink_urb((struct urb *) data);
}
static int cxacru_start_wait_urb(struct urb *urb, struct completion *done,
int* actual_length)
{
struct timer_list timer;
int status;
init_timer(&timer);
timer.expires = jiffies + msecs_to_jiffies(CMD_TIMEOUT);
timer.data = (unsigned long) urb;
timer.function = cxacru_timeout_kill;
add_timer(&timer);
wait_for_completion(done);
status = urb->status;
if (status == -ECONNRESET)
status = -ETIMEDOUT;
del_timer_sync(&timer);
if (actual_length)
*actual_length = urb->actual_length;
return status;
}
static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
u8 *wdata, int wsize, u8 *rdata, int rsize)
{
int ret, actlen;
int offb, offd;
const int stride = CMD_PACKET_SIZE - 4;
u8 *wbuf = instance->snd_buf;
u8 *rbuf = instance->rcv_buf;
int wbuflen = ((wsize - 1) / stride + 1) * CMD_PACKET_SIZE;
int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE;
if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) {
dbg("too big transfer requested");
ret = -ENOMEM;
goto fail;
}
down(&instance->cm_serialize);
/* submit reading urb before the writing one */
init_completion(&instance->rcv_done);
ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL);
if (ret < 0) {
dbg("submitting read urb for cm %#x failed", cm);
ret = ret;
goto fail;
}
memset(wbuf, 0, wbuflen);
/* handle wsize == 0 */
wbuf[0] = cm;
for (offb = offd = 0; offd < wsize; offd += stride, offb += CMD_PACKET_SIZE) {
wbuf[offb] = cm;
memcpy(wbuf + offb + 4, wdata + offd, min_t(int, stride, wsize - offd));
}
instance->snd_urb->transfer_buffer_length = wbuflen;
init_completion(&instance->snd_done);
ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL);
if (ret < 0) {
dbg("submitting write urb for cm %#x failed", cm);
ret = ret;
goto fail;
}
ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL);
if (ret < 0) {
dbg("sending cm %#x failed", cm);
ret = ret;
goto fail;
}
ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen);
if (ret < 0) {
dbg("receiving cm %#x failed", cm);
ret = ret;
goto fail;
}
if (actlen % CMD_PACKET_SIZE || !actlen) {
dbg("response is not a positive multiple of %d: %#x",
CMD_PACKET_SIZE, actlen);
ret = -EIO;
goto fail;
}
/* check the return status and copy the data to the output buffer, if needed */
for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) {
if (rbuf[offb] != cm) {
dbg("wrong cm %#x in response", rbuf[offb]);
ret = -EIO;
goto fail;
}
if (rbuf[offb + 1] != CM_STATUS_SUCCESS) {
dbg("response failed: %#x", rbuf[offb + 1]);
ret = -EIO;
goto fail;
}
if (offd >= rsize)
break;
memcpy(rdata + offd, rbuf + offb + 4, min_t(int, stride, rsize - offd));
offd += stride;
}
ret = offd;
dbg("cm %#x", cm);
fail:
up(&instance->cm_serialize);
return ret;
}
static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_request cm,
u32 *data, int size)
{
int ret, len;
u32 *buf;
int offb, offd;
const int stride = CMD_PACKET_SIZE / (4 * 2) - 1;
int buflen = ((size - 1) / stride + 1 + size * 2) * 4;
buf = kmalloc(buflen, GFP_KERNEL);
if (!buf)
return -ENOMEM;
ret = cxacru_cm(instance, cm, NULL, 0, (u8 *) buf, buflen);
if (ret < 0)
goto cleanup;
/* len > 0 && len % 4 == 0 guaranteed by cxacru_cm() */
len = ret / 4;
for (offb = 0; offb < len; ) {
int l = le32_to_cpu(buf[offb++]);
if (l > stride || l > (len - offb) / 2) {
dbg("wrong data length %#x in response", l);
ret = -EIO;
goto cleanup;
}
while (l--) {
offd = le32_to_cpu(buf[offb++]);
if (offd >= size) {
dbg("wrong index %#x in response", offd);
ret = -EIO;
goto cleanup;
}
data[offd] = le32_to_cpu(buf[offb++]);
}
}
ret = 0;
cleanup:
kfree(buf);
return ret;
}
static int cxacru_card_status(struct cxacru_data *instance)
{
int ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0);
if (ret < 0) { /* firmware not loaded */
dbg("cxacru_adsl_start: CARD_GET_STATUS returned %d", ret);
return ret;
}
return 0;
}
static void cxacru_poll_status(struct cxacru_data *instance);
static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
struct atm_dev *atm_dev)
{
struct cxacru_data *instance = usbatm_instance->driver_data;
struct device *dev = &usbatm_instance->usb_intf->dev;
/*
struct atm_dev *atm_dev = usbatm_instance->atm_dev;
*/
int ret;
dbg("cxacru_atm_start");
/* Read MAC address */
ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_MAC_ADDRESS, NULL, 0,
atm_dev->esi, sizeof(atm_dev->esi));
if (ret < 0) {
dev_err(dev, "cxacru_atm_start: CARD_GET_MAC_ADDRESS returned %d\n", ret);
return ret;
}
/* start ADSL */
ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0);
if (ret < 0) {
dev_err(dev, "cxacru_atm_start: CHIP_ADSL_LINE_START returned %d\n", ret);
return ret;
}
/* Start status polling */
cxacru_poll_status(instance);
return 0;
}
static void cxacru_poll_status(struct cxacru_data *instance)
{
u32 buf[CXINF_MAX] = {};
struct device *dev = &instance->usbatm->usb_intf->dev;
struct atm_dev *atm_dev = instance->usbatm->atm_dev;
int ret;
ret = cxacru_cm_get_array(instance, CM_REQUEST_CARD_INFO_GET, buf, CXINF_MAX);
if (ret < 0) {
dev_warn(dev, "poll status: error %d\n", ret);
goto reschedule;
}
if (instance->line_status == buf[CXINF_LINE_STATUS])
goto reschedule;
instance->line_status = buf[CXINF_LINE_STATUS];
switch (instance->line_status) {
case 0:
atm_dev->signal = ATM_PHY_SIG_LOST;
dev_info(dev, "ADSL line: down\n");
break;
case 1:
atm_dev->signal = ATM_PHY_SIG_LOST;
dev_info(dev, "ADSL line: attemtping to activate\n");
break;
case 2:
atm_dev->signal = ATM_PHY_SIG_LOST;
dev_info(dev, "ADSL line: training\n");
break;
case 3:
atm_dev->signal = ATM_PHY_SIG_LOST;
dev_info(dev, "ADSL line: channel analysis\n");
break;
case 4:
atm_dev->signal = ATM_PHY_SIG_LOST;
dev_info(dev, "ADSL line: exchange\n");
break;
case 5:
atm_dev->link_rate = buf[CXINF_DOWNSTREAM_RATE] * 1000 / 424;
atm_dev->signal = ATM_PHY_SIG_FOUND;
dev_info(dev, "ADSL line: up (%d Kib/s down | %d Kib/s up)\n",
buf[CXINF_DOWNSTREAM_RATE], buf[CXINF_UPSTREAM_RATE]);
break;
case 6:
atm_dev->signal = ATM_PHY_SIG_LOST;
dev_info(dev, "ADSL line: waiting\n");
break;
case 7:
atm_dev->signal = ATM_PHY_SIG_LOST;
dev_info(dev, "ADSL line: initializing\n");
break;
default:
atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
dev_info(dev, "Unknown line state %02x\n", instance->line_status);
break;
}
reschedule:
schedule_delayed_work(&instance->poll_work, msecs_to_jiffies(POLL_INTERVAL));
}
static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw,
u8 code1, u8 code2, u32 addr, u8 *data, int size)
{
int ret;
u8 *buf;
int offd, offb;
const int stride = CMD_PACKET_SIZE - 8;
buf = (u8 *) __get_free_page(GFP_KERNEL);
if (!buf)
return -ENOMEM;
offb = offd = 0;
do {
int l = min_t(int, stride, size - offd);
buf[offb++] = fw;
buf[offb++] = l;
buf[offb++] = code1;
buf[offb++] = code2;
*((u32 *) (buf + offb)) = cpu_to_le32(addr);
offb += 4;
addr += l;
if(l)
memcpy(buf + offb, data + offd, l);
if (l < stride)
memset(buf + offb + l, 0, stride - l);
offb += stride;
offd += stride;
if ((offb >= PAGE_SIZE) || (offd >= size)) {
ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD),
buf, offb, NULL, CMD_TIMEOUT);
if (ret < 0) {
dbg("sending fw %#x failed", fw);
goto cleanup;
}
offb = 0;
}
} while(offd < size);
dbg("sent fw %#x", fw);
ret = 0;
cleanup:
free_page((unsigned long) buf);
return ret;
}
static void cxacru_upload_firmware(struct cxacru_data *instance,
const struct firmware *fw,
const struct firmware *bp,
const struct firmware *cf)
{
int ret;
int off;
struct usb_device *usb_dev = instance->usbatm->usb_dev;
struct device *dev = &instance->usbatm->usb_intf->dev;
u16 signature[] = { usb_dev->descriptor.idVendor, usb_dev->descriptor.idProduct };
u32 val;
dbg("cxacru_upload_firmware");
/* FirmwarePllFClkValue */
val = cpu_to_le32(instance->modem_type->pll_f_clk);
ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLFCLK_ADDR, (u8 *) &val, 4);
if (ret) {
dev_err(dev, "FirmwarePllFClkValue failed: %d\n", ret);
return;
}
/* FirmwarePllBClkValue */
val = cpu_to_le32(instance->modem_type->pll_b_clk);
ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLBCLK_ADDR, (u8 *) &val, 4);
if (ret) {
dev_err(dev, "FirmwarePllBClkValue failed: %d\n", ret);
return;
}
/* Enable SDRAM */
val = cpu_to_le32(SDRAM_ENA);
ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SDRAMEN_ADDR, (u8 *) &val, 4);
if (ret) {
dev_err(dev, "Enable SDRAM failed: %d\n", ret);
return;
}
/* Firmware */
ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, FW_ADDR, fw->data, fw->size);
if (ret) {
dev_err(dev, "Firmware upload failed: %d\n", ret);
return;
}
/* Boot ROM patch */
if (instance->modem_type->boot_rom_patch) {
ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_ADDR, bp->data, bp->size);
if (ret) {
dev_err(dev, "Boot ROM patching failed: %d\n", ret);
return;
}
}
/* Signature */
ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SIG_ADDR, (u8 *) signature, 4);
if (ret) {
dev_err(dev, "Signature storing failed: %d\n", ret);
return;
}
if (instance->modem_type->boot_rom_patch) {
val = cpu_to_le32(BR_ADDR);
ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_STACK_ADDR, (u8 *) &val, 4);
}
else {
ret = cxacru_fw(usb_dev, FW_GOTO_MEM, 0x0, 0x0, FW_ADDR, NULL, 0);
}
if (ret) {
dev_err(dev, "Passing control to firmware failed: %d\n", ret);
return;
}
/* Delay to allow firmware to start up. */
msleep_interruptible(1000);
usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD));
usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_CMD));
usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_DATA));
usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_DATA));
ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0);
if (ret < 0) {
dev_err(dev, "modem failed to initialize: %d\n", ret);
return;
}
/* Load config data (le32), doing one packet at a time */
if (cf)
for (off = 0; off < cf->size / 4; ) {
u32 buf[CMD_PACKET_SIZE / 4 - 1];
int i, len = min_t(int, cf->size / 4 - off, CMD_PACKET_SIZE / 4 / 2 - 1);
buf[0] = cpu_to_le32(len);
for (i = 0; i < len; i++, off++) {
buf[i * 2 + 1] = cpu_to_le32(off);
memcpy(buf + i * 2 + 2, cf->data + off * 4, 4);
}
ret = cxacru_cm(instance, CM_REQUEST_CARD_DATA_SET,
(u8 *) buf, len, NULL, 0);
if (ret < 0) {
dev_err(dev, "load config data failed: %d\n", ret);
return;
}
}
msleep_interruptible(4000);
}
static int cxacru_find_firmware(struct cxacru_data *instance,
char* phase, const struct firmware **fw_p)
{
struct device *dev = &instance->usbatm->usb_intf->dev;
char buf[16];
sprintf(buf, "cxacru-%s.bin", phase);
dbg("cxacru_find_firmware: looking for %s", buf);
if (request_firmware(fw_p, buf, dev)) {
dev_dbg(dev, "no stage %s firmware found\n", phase);
return -ENOENT;
}
dev_info(dev, "found firmware %s\n", buf);
return 0;
}
static int cxacru_heavy_init(struct usbatm_data *usbatm_instance,
struct usb_interface *usb_intf)
{
struct device *dev = &usbatm_instance->usb_intf->dev;
const struct firmware *fw, *bp, *cf;
struct cxacru_data *instance = usbatm_instance->driver_data;
int ret = cxacru_find_firmware(instance, "fw", &fw);
if (ret) {
dev_warn(dev, "firmware (cxacru-fw.bin) unavailable (hotplug misconfiguration?)\n");
return ret;
}
if (instance->modem_type->boot_rom_patch) {
ret = cxacru_find_firmware(instance, "bp", &bp);
if (ret) {
dev_warn(dev, "boot ROM patch (cxacru-bp.bin) unavailable (hotplug misconfiguration?)\n");
release_firmware(fw);
return ret;
}
}
if (cxacru_find_firmware(instance, "cf", &cf)) /* optional */
cf = NULL;
cxacru_upload_firmware(instance, fw, bp, cf);
if (cf)
release_firmware(cf);
if (instance->modem_type->boot_rom_patch)
release_firmware(bp);
release_firmware(fw);
ret = cxacru_card_status(instance);
if (ret)
dbg("modem initialisation failed");
else
dbg("done setting up the modem");
return ret;
}
static int cxacru_bind(struct usbatm_data *usbatm_instance,
struct usb_interface *intf, const struct usb_device_id *id,
int *need_heavy_init)
{
struct cxacru_data *instance;
struct usb_device *usb_dev = interface_to_usbdev(intf);
int ret;
/* instance init */
instance = kmalloc(sizeof(*instance), GFP_KERNEL);
if (!instance) {
dbg("cxacru_bind: no memory for instance data");
return -ENOMEM;
}
memset(instance, 0, sizeof(*instance));
instance->usbatm = usbatm_instance;
instance->modem_type = (struct cxacru_modem_type *) id->driver_info;
instance->rcv_buf = (u8 *) __get_free_page(GFP_KERNEL);
if (!instance->rcv_buf) {
dbg("cxacru_bind: no memory for rcv_buf");
ret = -ENOMEM;
goto fail;
}
instance->snd_buf = (u8 *) __get_free_page(GFP_KERNEL);
if (!instance->snd_buf) {
dbg("cxacru_bind: no memory for snd_buf");
ret = -ENOMEM;
goto fail;
}
instance->rcv_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!instance->rcv_urb) {
dbg("cxacru_bind: no memory for rcv_urb");
ret = -ENOMEM;
goto fail;
}
instance->snd_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!instance->snd_urb) {
dbg("cxacru_bind: no memory for snd_urb");
ret = -ENOMEM;
goto fail;
}
usb_fill_int_urb(instance->rcv_urb,
usb_dev, usb_rcvintpipe(usb_dev, CXACRU_EP_CMD),
instance->rcv_buf, PAGE_SIZE,
cxacru_blocking_completion, &instance->rcv_done, 1);
instance->rcv_urb->transfer_flags |= URB_ASYNC_UNLINK;
usb_fill_int_urb(instance->snd_urb,
usb_dev, usb_sndintpipe(usb_dev, CXACRU_EP_CMD),
instance->snd_buf, PAGE_SIZE,
cxacru_blocking_completion, &instance->snd_done, 4);
instance->snd_urb->transfer_flags |= URB_ASYNC_UNLINK;
init_MUTEX(&instance->cm_serialize);
INIT_WORK(&instance->poll_work, (void *)cxacru_poll_status, instance);
usbatm_instance->driver_data = instance;
*need_heavy_init = cxacru_card_status(instance);
return 0;
fail:
free_page((unsigned long) instance->snd_buf);
free_page((unsigned long) instance->rcv_buf);
usb_free_urb(instance->snd_urb);
usb_free_urb(instance->rcv_urb);
kfree(instance);
return ret;
}
static void cxacru_unbind(struct usbatm_data *usbatm_instance,
struct usb_interface *intf)
{
struct cxacru_data *instance = usbatm_instance->driver_data;
dbg("cxacru_unbind entered");
if (!instance) {
dbg("cxacru_unbind: NULL instance!");
return;
}
while (!cancel_delayed_work(&instance->poll_work))
flush_scheduled_work();
usb_kill_urb(instance->snd_urb);
usb_kill_urb(instance->rcv_urb);
usb_free_urb(instance->snd_urb);
usb_free_urb(instance->rcv_urb);
free_page((unsigned long) instance->snd_buf);
free_page((unsigned long) instance->rcv_buf);
kfree(instance);
usbatm_instance->driver_data = NULL;
}
static const struct cxacru_modem_type cxacru_cafe = {
.pll_f_clk = 0x02d874df,
.pll_b_clk = 0x0196a51a,
.boot_rom_patch = 1,
};
static const struct cxacru_modem_type cxacru_cb00 = {
.pll_f_clk = 0x5,
.pll_b_clk = 0x3,
.boot_rom_patch = 0,
};
static const struct usb_device_id cxacru_usb_ids[] = {
{ /* V = Conexant P = ADSL modem (Euphrates project) */
USB_DEVICE(0x0572, 0xcafe), .driver_info = (unsigned long) &cxacru_cafe
},
{ /* V = Conexant P = ADSL modem (Hasbani project) */
USB_DEVICE(0x0572, 0xcb00), .driver_info = (unsigned long) &cxacru_cb00
},
{ /* V = Conexant P = ADSL modem */
USB_DEVICE(0x0572, 0xcb01), .driver_info = (unsigned long) &cxacru_cb00
},
{ /* V = Conexant P = ADSL modem */
USB_DEVICE(0x0572, 0xcb06), .driver_info = (unsigned long) &cxacru_cb00
},
{ /* V = Olitec P = ADSL modem version 2 */
USB_DEVICE(0x08e3, 0x0100), .driver_info = (unsigned long) &cxacru_cafe
},
{ /* V = Olitec P = ADSL modem version 3 */
USB_DEVICE(0x08e3, 0x0102), .driver_info = (unsigned long) &cxacru_cb00
},
{ /* V = Trust/Amigo Technology Co. P = AMX-CA86U */
USB_DEVICE(0x0eb0, 0x3457), .driver_info = (unsigned long) &cxacru_cafe
},
{ /* V = Zoom P = 5510 */
USB_DEVICE(0x1803, 0x5510), .driver_info = (unsigned long) &cxacru_cb00
},
{ /* V = Draytek P = Vigor 318 */
USB_DEVICE(0x0675, 0x0200), .driver_info = (unsigned long) &cxacru_cb00
},
{ /* V = Zyxel P = 630-C1 aka OMNI ADSL USB (Annex A) */
USB_DEVICE(0x0586, 0x330a), .driver_info = (unsigned long) &cxacru_cb00
},
{ /* V = Zyxel P = 630-C3 aka OMNI ADSL USB (Annex B) */
USB_DEVICE(0x0586, 0x330b), .driver_info = (unsigned long) &cxacru_cb00
},
{ /* V = Aethra P = Starmodem UM1020 */
USB_DEVICE(0x0659, 0x0020), .driver_info = (unsigned long) &cxacru_cb00
},
{ /* V = Aztech Systems P = ? AKA Pirelli AUA-010 */
USB_DEVICE(0x0509, 0x0812), .driver_info = (unsigned long) &cxacru_cb00
},
{ /* V = Netopia P = Cayman 3341(Annex A)/3351(Annex B) */
USB_DEVICE(0x100d, 0xcb01), .driver_info = (unsigned long) &cxacru_cb00
},
{ /* V = Netopia P = Cayman 3342(Annex A)/3352(Annex B) */
USB_DEVICE(0x100d, 0x3342), .driver_info = (unsigned long) &cxacru_cb00
},
{}
};
MODULE_DEVICE_TABLE(usb, cxacru_usb_ids);
static struct usbatm_driver cxacru_driver = {
.owner = THIS_MODULE,
.driver_name = cxacru_driver_name,
.bind = cxacru_bind,
.heavy_init = cxacru_heavy_init,
.unbind = cxacru_unbind,
.atm_start = cxacru_atm_start,
.in = CXACRU_EP_DATA,
.out = CXACRU_EP_DATA,
.rx_padding = 3,
.tx_padding = 11,
};
static int cxacru_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
return usbatm_usb_probe(intf, id, &cxacru_driver);
}
static struct usb_driver cxacru_usb_driver = {
.owner = THIS_MODULE,
.name = cxacru_driver_name,
.probe = cxacru_usb_probe,
.disconnect = usbatm_usb_disconnect,
.id_table = cxacru_usb_ids
};
static int __init cxacru_init(void)
{
return usb_register(&cxacru_usb_driver);
}
static void __exit cxacru_cleanup(void)
{
usb_deregister(&cxacru_usb_driver);
}
module_init(cxacru_init);
module_exit(cxacru_cleanup);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_VERSION(DRIVER_VERSION);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,176 +0,0 @@
/******************************************************************************
* usb_atm.h - Generic USB xDSL driver core
*
* Copyright (C) 2001, Alcatel
* Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas
* Copyright (C) 2004, David Woodhouse
*
* 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/config.h>
#include <linux/list.h>
#include <linux/kref.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <asm/semaphore.h>
/*
#define DEBUG
#define VERBOSE_DEBUG
*/
#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG)
# define DEBUG
#endif
#include <linux/usb.h>
#ifdef DEBUG
#define UDSL_ASSERT(x) BUG_ON(!(x))
#else
#define UDSL_ASSERT(x) do { if (!(x)) warn("failed assertion '" #x "' at line %d", __LINE__); } while(0)
#endif
#define UDSL_MAX_RCV_URBS 4
#define UDSL_MAX_SND_URBS 4
#define UDSL_MAX_RCV_BUFS 8
#define UDSL_MAX_SND_BUFS 8
#define UDSL_MAX_RCV_BUF_SIZE 1024 /* ATM cells */
#define UDSL_MAX_SND_BUF_SIZE 1024 /* ATM cells */
#define UDSL_DEFAULT_RCV_URBS 2
#define UDSL_DEFAULT_SND_URBS 2
#define UDSL_DEFAULT_RCV_BUFS 4
#define UDSL_DEFAULT_SND_BUFS 4
#define UDSL_DEFAULT_RCV_BUF_SIZE 64 /* ATM cells */
#define UDSL_DEFAULT_SND_BUF_SIZE 64 /* ATM cells */
#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
#define UDSL_NUM_CELLS(x) (((x) + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD)
/* receive */
struct udsl_receive_buffer {
struct list_head list;
unsigned char *base;
unsigned int filled_cells;
};
struct udsl_receiver {
struct list_head list;
struct udsl_receive_buffer *buffer;
struct urb *urb;
struct udsl_instance_data *instance;
};
struct udsl_vcc_data {
/* vpi/vci lookup */
struct list_head list;
short vpi;
int vci;
struct atm_vcc *vcc;
/* raw cell reassembly */
struct sk_buff *sarb;
};
/* send */
struct udsl_send_buffer {
struct list_head list;
unsigned char *base;
unsigned char *free_start;
unsigned int free_cells;
};
struct udsl_sender {
struct list_head list;
struct udsl_send_buffer *buffer;
struct urb *urb;
struct udsl_instance_data *instance;
};
struct udsl_control {
struct atm_skb_data atm_data;
unsigned int num_cells;
unsigned int num_entire;
unsigned int pdu_padding;
unsigned char aal5_trailer[ATM_AAL5_TRAILER];
};
#define UDSL_SKB(x) ((struct udsl_control *)(x)->cb)
/* main driver data */
enum udsl_status {
UDSL_NO_FIRMWARE,
UDSL_LOADING_FIRMWARE,
UDSL_LOADED_FIRMWARE
};
struct udsl_instance_data {
struct kref refcount;
struct semaphore serialize;
/* USB device part */
struct usb_device *usb_dev;
char description[64];
int data_endpoint;
int snd_padding;
int rcv_padding;
const char *driver_name;
/* ATM device part */
struct atm_dev *atm_dev;
struct list_head vcc_list;
/* firmware */
int (*firmware_wait) (struct udsl_instance_data *);
enum udsl_status status;
wait_queue_head_t firmware_waiters;
/* receive */
struct udsl_receiver receivers[UDSL_MAX_RCV_URBS];
struct udsl_receive_buffer receive_buffers[UDSL_MAX_RCV_BUFS];
spinlock_t receive_lock;
struct list_head spare_receivers;
struct list_head filled_receive_buffers;
struct tasklet_struct receive_tasklet;
struct list_head spare_receive_buffers;
/* send */
struct udsl_sender senders[UDSL_MAX_SND_URBS];
struct udsl_send_buffer send_buffers[UDSL_MAX_SND_BUFS];
struct sk_buff_head sndqueue;
spinlock_t send_lock;
struct list_head spare_senders;
struct list_head spare_send_buffers;
struct tasklet_struct send_tasklet;
struct sk_buff *current_skb; /* being emptied */
struct udsl_send_buffer *current_buffer; /* being filled */
struct list_head filled_send_buffers;
};
extern int udsl_instance_setup(struct usb_device *dev,
struct udsl_instance_data *instance);
extern void udsl_instance_disconnect(struct udsl_instance_data *instance);
extern void udsl_get_instance(struct udsl_instance_data *instance);
extern void udsl_put_instance(struct udsl_instance_data *instance);

1230
drivers/usb/atm/usbatm.c Normal file

File diff suppressed because it is too large Load Diff

184
drivers/usb/atm/usbatm.h Normal file
View File

@ -0,0 +1,184 @@
/******************************************************************************
* usbatm.h - Generic USB xDSL driver core
*
* Copyright (C) 2001, Alcatel
* Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas
* Copyright (C) 2004, David Woodhouse
*
* 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.
*
******************************************************************************/
#ifndef _USBATM_H_
#define _USBATM_H_
#include <linux/config.h>
/*
#define DEBUG
#define VERBOSE_DEBUG
*/
#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG)
# define DEBUG
#endif
#include <asm/semaphore.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <linux/completion.h>
#include <linux/device.h>
#include <linux/kref.h>
#include <linux/list.h>
#include <linux/stringify.h>
#include <linux/usb.h>
#ifdef DEBUG
#define UDSL_ASSERT(x) BUG_ON(!(x))
#else
#define UDSL_ASSERT(x) do { if (!(x)) warn("failed assertion '%s' at line %d", __stringify(x), __LINE__); } while(0)
#endif
#define usb_err(instance, format, arg...) \
dev_err(&(instance)->usb_intf->dev , format , ## arg)
#define usb_info(instance, format, arg...) \
dev_info(&(instance)->usb_intf->dev , format , ## arg)
#define usb_warn(instance, format, arg...) \
dev_warn(&(instance)->usb_intf->dev , format , ## arg)
#define usb_dbg(instance, format, arg...) \
dev_dbg(&(instance)->usb_intf->dev , format , ## arg)
/* FIXME: move to dev_* once ATM is driver model aware */
#define atm_printk(level, instance, format, arg...) \
printk(level "ATM dev %d: " format , \
(instance)->atm_dev->number , ## arg)
#define atm_err(instance, format, arg...) \
atm_printk(KERN_ERR, instance , format , ## arg)
#define atm_info(instance, format, arg...) \
atm_printk(KERN_INFO, instance , format , ## arg)
#define atm_warn(instance, format, arg...) \
atm_printk(KERN_WARNING, instance , format , ## arg)
#ifdef DEBUG
#define atm_dbg(instance, format, arg...) \
atm_printk(KERN_DEBUG, instance , format , ## arg)
#else
#define atm_dbg(instance, format, arg...) \
do {} while (0)
#endif
/* mini driver */
struct usbatm_data;
/*
* Assuming all methods exist and succeed, they are called in this order:
*
* bind, heavy_init, atm_start, ..., atm_stop, unbind
*/
struct usbatm_driver {
struct module *owner;
const char *driver_name;
/*
* init device ... can sleep, or cause probe() failure. Drivers with a heavy_init
* method can avoid having it called by setting need_heavy_init to zero.
*/
int (*bind) (struct usbatm_data *, struct usb_interface *,
const struct usb_device_id *id, int *need_heavy_init);
/* additional device initialization that is too slow to be done in probe() */
int (*heavy_init) (struct usbatm_data *, struct usb_interface *);
/* cleanup device ... can sleep, but can't fail */
void (*unbind) (struct usbatm_data *, struct usb_interface *);
/* init ATM device ... can sleep, or cause ATM initialization failure */
int (*atm_start) (struct usbatm_data *, struct atm_dev *);
/* cleanup ATM device ... can sleep, but can't fail */
void (*atm_stop) (struct usbatm_data *, struct atm_dev *);
int in; /* rx endpoint */
int out; /* tx endpoint */
unsigned rx_padding;
unsigned tx_padding;
};
extern int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
struct usbatm_driver *driver);
extern void usbatm_usb_disconnect(struct usb_interface *intf);
struct usbatm_channel {
int endpoint; /* usb pipe */
unsigned int stride; /* ATM cell size + padding */
unsigned int buf_size; /* urb buffer size */
spinlock_t lock;
struct list_head list;
struct tasklet_struct tasklet;
struct timer_list delay;
struct usbatm_data *usbatm;
};
/* main driver data */
struct usbatm_data {
/******************
* public fields *
******************/
/* mini driver */
struct usbatm_driver *driver;
void *driver_data;
char driver_name[16];
/* USB device */
struct usb_device *usb_dev;
struct usb_interface *usb_intf;
char description[64];
/* ATM device */
struct atm_dev *atm_dev;
/********************************
* private fields - do not use *
********************************/
struct kref refcount;
struct semaphore serialize;
/* heavy init */
int thread_pid;
struct completion thread_started;
struct completion thread_exited;
/* ATM device */
struct list_head vcc_list;
struct usbatm_channel rx_channel;
struct usbatm_channel tx_channel;
struct sk_buff_head sndqueue;
struct sk_buff *current_skb; /* being emptied */
struct urb *urbs[0];
};
#endif /* _USBATM_H_ */

196
drivers/usb/atm/xusbatm.c Normal file
View File

@ -0,0 +1,196 @@
/******************************************************************************
* xusbatm.c - dumb usbatm-based driver for modems initialized in userspace
*
* Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru)
*
* 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/module.h>
#include <linux/netdevice.h> /* FIXME: required by linux/etherdevice.h */
#include <linux/etherdevice.h> /* for random_ether_addr() */
#include "usbatm.h"
#define XUSBATM_DRIVERS_MAX 8
#define XUSBATM_PARM(name, type, parmtype, desc) \
static type name[XUSBATM_DRIVERS_MAX]; \
static int num_##name; \
module_param_array(name, parmtype, &num_##name, 0444); \
MODULE_PARM_DESC(name, desc)
XUSBATM_PARM(vendor, unsigned short, ushort, "USB device vendor");
XUSBATM_PARM(product, unsigned short, ushort, "USB device product");
XUSBATM_PARM(rx_endpoint, unsigned char, byte, "rx endpoint number");
XUSBATM_PARM(tx_endpoint, unsigned char, byte, "tx endpoint number");
XUSBATM_PARM(rx_padding, unsigned char, byte, "rx padding (default 0)");
XUSBATM_PARM(tx_padding, unsigned char, byte, "tx padding (default 0)");
static const char xusbatm_driver_name[] = "xusbatm";
static struct usbatm_driver xusbatm_drivers[XUSBATM_DRIVERS_MAX];
static struct usb_device_id xusbatm_usb_ids[XUSBATM_DRIVERS_MAX + 1];
static struct usb_driver xusbatm_usb_driver;
static int usb_intf_has_ep(const struct usb_interface *intf, u8 ep)
{
int i, j;
for (i = 0; i < intf->num_altsetting; i++) {
struct usb_host_interface *alt = intf->altsetting;
for (j = 0; j < alt->desc.bNumEndpoints; j++)
if ((alt->endpoint[i].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) == ep)
return 1;
}
return 0;
}
static int xusbatm_bind(struct usbatm_data *usbatm_instance,
struct usb_interface *intf, const struct usb_device_id *id,
int *need_heavy_init)
{
struct usb_device *usb_dev = interface_to_usbdev(intf);
int drv_ix = id - xusbatm_usb_ids;
int rx_ep_present = usb_intf_has_ep(intf, rx_endpoint[drv_ix]);
int tx_ep_present = usb_intf_has_ep(intf, tx_endpoint[drv_ix]);
u8 searched_ep = rx_ep_present ? tx_endpoint[drv_ix] : rx_endpoint[drv_ix];
int i, ret;
usb_dbg(usbatm_instance, "%s: binding driver %d: vendor %#x product %#x"
" rx: ep %#x padd %d tx: ep %#x padd %d\n",
__func__, drv_ix, vendor[drv_ix], product[drv_ix],
rx_endpoint[drv_ix], rx_padding[drv_ix],
tx_endpoint[drv_ix], tx_padding[drv_ix]);
if (!rx_ep_present && !tx_ep_present) {
usb_dbg(usbatm_instance, "%s: intf #%d has neither rx (%#x) nor tx (%#x) endpoint\n",
__func__, intf->altsetting->desc.bInterfaceNumber,
rx_endpoint[drv_ix], tx_endpoint[drv_ix]);
return -ENODEV;
}
if (rx_ep_present && tx_ep_present)
return 0;
for(i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *cur_if = usb_dev->actconfig->interface[i];
if (cur_if != intf && usb_intf_has_ep(cur_if, searched_ep)) {
ret = usb_driver_claim_interface(&xusbatm_usb_driver,
cur_if, usbatm_instance);
if (!ret)
usb_err(usbatm_instance, "%s: failed to claim interface #%d (%d)\n",
__func__, cur_if->altsetting->desc.bInterfaceNumber, ret);
return ret;
}
}
usb_err(usbatm_instance, "%s: no interface has endpoint %#x\n",
__func__, searched_ep);
return -ENODEV;
}
static void xusbatm_unbind(struct usbatm_data *usbatm_instance,
struct usb_interface *intf)
{
struct usb_device *usb_dev = interface_to_usbdev(intf);
int i;
usb_dbg(usbatm_instance, "%s entered\n", __func__);
for(i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++) {
struct usb_interface *cur_if = usb_dev->actconfig->interface[i];
usb_set_intfdata(cur_if, NULL);
usb_driver_release_interface(&xusbatm_usb_driver, cur_if);
}
}
static int xusbatm_atm_start(struct usbatm_data *usbatm_instance,
struct atm_dev *atm_dev)
{
atm_dbg(usbatm_instance, "%s entered\n", __func__);
/* use random MAC as we've no way to get it from the device */
random_ether_addr(atm_dev->esi);
return 0;
}
static int xusbatm_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return usbatm_usb_probe(intf, id,
xusbatm_drivers + (id - xusbatm_usb_ids));
}
static struct usb_driver xusbatm_usb_driver = {
.owner = THIS_MODULE,
.name = xusbatm_driver_name,
.probe = xusbatm_usb_probe,
.disconnect = usbatm_usb_disconnect,
.id_table = xusbatm_usb_ids
};
static int __init xusbatm_init(void)
{
int i;
dbg("xusbatm_init");
if (!num_vendor ||
num_vendor != num_product ||
num_vendor != num_rx_endpoint ||
num_vendor != num_tx_endpoint) {
warn("malformed module parameters");
return -EINVAL;
}
for (i = 0; i < num_vendor; i++) {
xusbatm_usb_ids[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
xusbatm_usb_ids[i].idVendor = vendor[i];
xusbatm_usb_ids[i].idProduct = product[i];
xusbatm_drivers[i].owner = THIS_MODULE;
xusbatm_drivers[i].driver_name = xusbatm_driver_name;
xusbatm_drivers[i].bind = xusbatm_bind;
xusbatm_drivers[i].unbind = xusbatm_unbind;
xusbatm_drivers[i].atm_start = xusbatm_atm_start;
xusbatm_drivers[i].in = rx_endpoint[i];
xusbatm_drivers[i].out = tx_endpoint[i];
xusbatm_drivers[i].rx_padding = rx_padding[i];
xusbatm_drivers[i].tx_padding = tx_padding[i];
}
return usb_register(&xusbatm_usb_driver);
}
module_init(xusbatm_init);
static void __exit xusbatm_exit(void)
{
dbg("xusbatm_exit entered");
usb_deregister(&xusbatm_usb_driver);
}
module_exit(xusbatm_exit);
MODULE_AUTHOR("Roman Kagan, Duncan Sands");
MODULE_DESCRIPTION("Driver for USB ADSL modems initialized in userspace");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");

View File

@ -105,6 +105,111 @@ static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int
#define acm_send_break(acm, ms) \
acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
/*
* Write buffer management.
* All of these assume proper locks taken by the caller.
*/
static int acm_wb_alloc(struct acm *acm)
{
int i, wbn;
struct acm_wb *wb;
wbn = acm->write_current;
i = 0;
for (;;) {
wb = &acm->wb[wbn];
if (!wb->use) {
wb->use = 1;
return wbn;
}
wbn = (wbn + 1) % ACM_NWB;
if (++i >= ACM_NWB)
return -1;
}
}
static void acm_wb_free(struct acm *acm, int wbn)
{
acm->wb[wbn].use = 0;
}
static int acm_wb_is_avail(struct acm *acm)
{
int i, n;
n = 0;
for (i = 0; i < ACM_NWB; i++) {
if (!acm->wb[i].use)
n++;
}
return n;
}
static inline int acm_wb_is_used(struct acm *acm, int wbn)
{
return acm->wb[wbn].use;
}
/*
* Finish write.
*/
static void acm_write_done(struct acm *acm)
{
unsigned long flags;
int wbn;
spin_lock_irqsave(&acm->write_lock, flags);
acm->write_ready = 1;
wbn = acm->write_current;
acm_wb_free(acm, wbn);
acm->write_current = (wbn + 1) % ACM_NWB;
spin_unlock_irqrestore(&acm->write_lock, flags);
}
/*
* Poke write.
*/
static int acm_write_start(struct acm *acm)
{
unsigned long flags;
int wbn;
struct acm_wb *wb;
int rc;
spin_lock_irqsave(&acm->write_lock, flags);
if (!acm->dev) {
spin_unlock_irqrestore(&acm->write_lock, flags);
return -ENODEV;
}
if (!acm->write_ready) {
spin_unlock_irqrestore(&acm->write_lock, flags);
return 0; /* A white lie */
}
wbn = acm->write_current;
if (!acm_wb_is_used(acm, wbn)) {
spin_unlock_irqrestore(&acm->write_lock, flags);
return 0;
}
wb = &acm->wb[wbn];
acm->write_ready = 0;
spin_unlock_irqrestore(&acm->write_lock, flags);
acm->writeurb->transfer_buffer = wb->buf;
acm->writeurb->transfer_dma = wb->dmah;
acm->writeurb->transfer_buffer_length = wb->len;
acm->writeurb->dev = acm->dev;
if ((rc = usb_submit_urb(acm->writeurb, GFP_ATOMIC)) < 0) {
dbg("usb_submit_urb(write bulk) failed: %d", rc);
acm_write_done(acm);
}
return rc;
}
/*
* Interrupt handlers for various ACM device responses
*/
@ -237,17 +342,13 @@ static void acm_rx_tasklet(unsigned long _acm)
static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
{
struct acm *acm = (struct acm *)urb->context;
dbg("Entering acm_write_bulk with status %d\n", urb->status);
if (!ACM_READY(acm))
goto out;
if (urb->status)
dbg("nonzero write bulk status received: %d", urb->status);
schedule_work(&acm->work);
out:
acm->ready_for_write = 1;
acm_write_done(acm);
acm_write_start(acm);
if (ACM_READY(acm))
schedule_work(&acm->work);
}
static void acm_softint(void *private)
@ -351,32 +452,33 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
{
struct acm *acm = tty->driver_data;
int stat;
unsigned long flags;
int wbn;
struct acm_wb *wb;
dbg("Entering acm_tty_write to write %d bytes,\n", count);
if (!ACM_READY(acm))
return -EINVAL;
if (!acm->ready_for_write)
return 0;
if (!count)
return 0;
count = (count > acm->writesize) ? acm->writesize : count;
dbg("Get %d bytes...", count);
memcpy(acm->write_buffer, buf, count);
dbg(" Successfully copied.\n");
acm->writeurb->transfer_buffer_length = count;
acm->writeurb->dev = acm->dev;
acm->ready_for_write = 0;
stat = usb_submit_urb(acm->writeurb, GFP_ATOMIC);
if (stat < 0) {
dbg("usb_submit_urb(write bulk) failed");
acm->ready_for_write = 1;
return stat;
spin_lock_irqsave(&acm->write_lock, flags);
if ((wbn = acm_wb_alloc(acm)) < 0) {
spin_unlock_irqrestore(&acm->write_lock, flags);
acm_write_start(acm);
return 0;
}
wb = &acm->wb[wbn];
count = (count > acm->writesize) ? acm->writesize : count;
dbg("Get %d bytes...", count);
memcpy(wb->buf, buf, count);
wb->len = count;
spin_unlock_irqrestore(&acm->write_lock, flags);
if ((stat = acm_write_start(acm)) < 0)
return stat;
return count;
}
@ -385,7 +487,11 @@ static int acm_tty_write_room(struct tty_struct *tty)
struct acm *acm = tty->driver_data;
if (!ACM_READY(acm))
return -EINVAL;
return !acm->ready_for_write ? 0 : acm->writesize;
/*
* Do not let the line discipline to know that we have a reserve,
* or it might get too enthusiastic.
*/
return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0;
}
static int acm_tty_chars_in_buffer(struct tty_struct *tty)
@ -393,7 +499,10 @@ static int acm_tty_chars_in_buffer(struct tty_struct *tty)
struct acm *acm = tty->driver_data;
if (!ACM_READY(acm))
return -EINVAL;
return !acm->ready_for_write ? acm->writeurb->transfer_buffer_length : 0;
/*
* This is inaccurate (overcounts), but it works.
*/
return (ACM_NWB - acm_wb_is_avail(acm)) * acm->writesize;
}
static void acm_tty_throttle(struct tty_struct *tty)
@ -526,6 +635,39 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_
* USB probe and disconnect routines.
*/
/* Little helper: write buffers free */
static void acm_write_buffers_free(struct acm *acm)
{
int i;
struct acm_wb *wb;
for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah);
}
}
/* Little helper: write buffers allocate */
static int acm_write_buffers_alloc(struct acm *acm)
{
int i;
struct acm_wb *wb;
for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
&wb->dmah);
if (!wb->buf) {
while (i != 0) {
--i;
--wb;
usb_buffer_free(acm->dev, acm->writesize,
wb->buf, wb->dmah);
}
return -ENOMEM;
}
}
return 0;
}
static int acm_probe (struct usb_interface *intf,
const struct usb_device_id *id)
{
@ -700,7 +842,8 @@ skip_normal_probe:
acm->bh.data = (unsigned long) acm;
INIT_WORK(&acm->work, acm_softint, acm);
spin_lock_init(&acm->throttle_lock);
acm->ready_for_write = 1;
spin_lock_init(&acm->write_lock);
acm->write_ready = 1;
buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
if (!buf) {
@ -716,12 +859,10 @@ skip_normal_probe:
}
acm->read_buffer = buf;
buf = usb_buffer_alloc(usb_dev, acm->writesize, GFP_KERNEL, &acm->write_dma);
if (!buf) {
if (acm_write_buffers_alloc(acm) < 0) {
dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
goto alloc_fail4;
}
acm->write_buffer = buf;
acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->ctrlurb) {
@ -750,9 +891,9 @@ skip_normal_probe:
acm->readurb->transfer_dma = acm->read_dma;
usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
acm->write_buffer, acm->writesize, acm_write_bulk, acm);
NULL, acm->writesize, acm_write_bulk, acm);
acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;
acm->writeurb->transfer_dma = acm->write_dma;
/* acm->writeurb->transfer_dma = 0; */
dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
@ -775,7 +916,7 @@ alloc_fail7:
alloc_fail6:
usb_free_urb(acm->ctrlurb);
alloc_fail5:
usb_buffer_free(usb_dev, acm->writesize, acm->write_buffer, acm->write_dma);
acm_write_buffers_free(acm);
alloc_fail4:
usb_buffer_free(usb_dev, readsize, acm->read_buffer, acm->read_dma);
alloc_fail3:
@ -806,7 +947,7 @@ static void acm_disconnect(struct usb_interface *intf)
flush_scheduled_work(); /* wait for acm_softint */
usb_buffer_free(usb_dev, acm->writesize, acm->write_buffer, acm->write_dma);
acm_write_buffers_free(acm);
usb_buffer_free(usb_dev, acm->readsize, acm->read_buffer, acm->read_dma);
usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);

View File

@ -51,14 +51,34 @@
* Internal driver structures.
*/
/*
* The only reason to have several buffers is to accomodate assumptions
* in line disciplines. They ask for empty space amount, receive our URB size,
* and proceed to issue several 1-character writes, assuming they will fit.
* The very first write takes a complete URB. Fortunately, this only happens
* when processing onlcr, so we only need 2 buffers.
*/
#define ACM_NWB 2
struct acm_wb {
unsigned char *buf;
dma_addr_t dmah;
int len;
int use;
};
struct acm {
struct usb_device *dev; /* the corresponding usb device */
struct usb_interface *control; /* control interface */
struct usb_interface *data; /* data interface */
struct tty_struct *tty; /* the corresponding tty */
struct urb *ctrlurb, *readurb, *writeurb; /* urbs */
u8 *ctrl_buffer, *read_buffer, *write_buffer; /* buffers of urbs */
dma_addr_t ctrl_dma, read_dma, write_dma; /* dma handles of buffers */
u8 *ctrl_buffer, *read_buffer; /* buffers of urbs */
dma_addr_t ctrl_dma, read_dma; /* dma handles of buffers */
struct acm_wb wb[ACM_NWB];
int write_current; /* current write buffer */
int write_used; /* number of non-empty write buffers */
int write_ready; /* write urb is not running */
spinlock_t write_lock;
struct usb_cdc_line_coding line; /* bits, stop, parity */
struct work_struct work; /* work queue entry for line discipline waking up */
struct tasklet_struct bh; /* rx processing */
@ -71,7 +91,6 @@ struct acm {
unsigned int minor; /* acm minor number */
unsigned char throttle; /* throttled by tty layer */
unsigned char clocal; /* termios CLOCAL */
unsigned char ready_for_write; /* write urb can be used */
unsigned char resubmit_to_unthrottle; /* throtteling has disabled the read urb */
unsigned int ctrl_caps; /* control capabilities from the class specific header */
};

View File

@ -379,6 +379,8 @@ static int usblp_open(struct inode *inode, struct file *file)
usblp->writeurb->transfer_buffer_length = 0;
usblp->wcomplete = 1; /* we begin writeable */
usblp->rcomplete = 0;
usblp->writeurb->status = 0;
usblp->readurb->status = 0;
if (usblp->bidir) {
usblp->readcount = 0;
@ -751,6 +753,7 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
schedule();
} else {
set_current_state(TASK_RUNNING);
down(&usblp->sem);
break;
}
down (&usblp->sem);

View File

@ -784,16 +784,16 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)
for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
if (usb_interface_claimed(actconfig->interface[i])) {
dev_warn (&ps->dev->dev,
"usbfs: interface %d claimed "
"usbfs: interface %d claimed by %s "
"while '%s' sets config #%d\n",
actconfig->interface[i]
->cur_altsetting
->desc.bInterfaceNumber,
actconfig->interface[i]
->dev.driver->name,
current->comm, u);
#if 0 /* FIXME: enable in 2.6.10 or so */
status = -EBUSY;
break;
#endif
}
}
}

View File

@ -519,119 +519,120 @@ error:
/*-------------------------------------------------------------------------*/
/*
* Root Hub interrupt transfers are synthesized with a timer.
* Completions are called in_interrupt() but not in_irq().
* Root Hub interrupt transfers are polled using a timer if the
* driver requests it; otherwise the driver is responsible for
* calling usb_hcd_poll_rh_status() when an event occurs.
*
* Note: some root hubs (including common UHCI based designs) can't
* correctly issue port change IRQs. They're the ones that _need_ a
* timer; most other root hubs don't. Some systems could save a
* lot of battery power by eliminating these root hub timer IRQs.
* Completions are called in_interrupt(), but they may or may not
* be in_irq().
*/
static void rh_report_status (unsigned long ptr);
static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb)
{
int len = 1 + (urb->dev->maxchild / 8);
/* rh_timer protected by hcd_data_lock */
if (hcd->rh_timer.data || urb->transfer_buffer_length < len) {
dev_dbg (hcd->self.controller,
"not queuing rh status urb, stat %d\n",
urb->status);
return -EINVAL;
}
init_timer (&hcd->rh_timer);
hcd->rh_timer.function = rh_report_status;
hcd->rh_timer.data = (unsigned long) urb;
/* USB 2.0 spec says 256msec; this is close enough */
hcd->rh_timer.expires = jiffies + HZ/4;
add_timer (&hcd->rh_timer);
urb->hcpriv = hcd; /* nonzero to indicate it's queued */
return 0;
}
/* timer callback */
static void rh_report_status (unsigned long ptr)
void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
{
struct urb *urb;
struct usb_hcd *hcd;
int length = 0;
int length;
unsigned long flags;
char buffer[4]; /* Any root hubs with > 31 ports? */
urb = (struct urb *) ptr;
local_irq_save (flags);
spin_lock (&urb->lock);
/* do nothing if the urb's been unlinked */
if (!urb->dev
|| urb->status != -EINPROGRESS
|| (hcd = urb->dev->bus->hcpriv) == NULL) {
spin_unlock (&urb->lock);
local_irq_restore (flags);
if (!hcd->uses_new_polling && !hcd->status_urb)
return;
}
/* complete the status urb, or retrigger the timer */
spin_lock (&hcd_data_lock);
if (urb->dev->state == USB_STATE_CONFIGURED) {
length = hcd->driver->hub_status_data (
hcd, urb->transfer_buffer);
if (length > 0) {
hcd->rh_timer.data = 0;
urb->actual_length = length;
urb->status = 0;
urb->hcpriv = NULL;
length = hcd->driver->hub_status_data(hcd, buffer);
if (length > 0) {
/* try to complete the status urb */
local_irq_save (flags);
spin_lock(&hcd_root_hub_lock);
urb = hcd->status_urb;
if (urb) {
spin_lock(&urb->lock);
if (urb->status == -EINPROGRESS) {
hcd->poll_pending = 0;
hcd->status_urb = NULL;
urb->status = 0;
urb->hcpriv = NULL;
urb->actual_length = length;
memcpy(urb->transfer_buffer, buffer, length);
} else /* urb has been unlinked */
length = 0;
spin_unlock(&urb->lock);
} else
mod_timer (&hcd->rh_timer, jiffies + HZ/4);
}
spin_unlock (&hcd_data_lock);
spin_unlock (&urb->lock);
length = 0;
spin_unlock(&hcd_root_hub_lock);
/* local irqs are always blocked in completions */
if (length > 0)
usb_hcd_giveback_urb (hcd, urb, NULL);
local_irq_restore (flags);
/* local irqs are always blocked in completions */
if (length > 0)
usb_hcd_giveback_urb (hcd, urb, NULL);
else
hcd->poll_pending = 1;
local_irq_restore (flags);
}
/* The USB 2.0 spec says 256 ms. This is close enough and won't
* exceed that limit if HZ is 100. */
if (hcd->uses_new_polling ? hcd->poll_rh :
(length == 0 && hcd->status_urb != NULL))
mod_timer (&hcd->rh_timer, jiffies + msecs_to_jiffies(250));
}
EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status);
/* timer callback */
static void rh_timer_func (unsigned long _hcd)
{
usb_hcd_poll_rh_status((struct usb_hcd *) _hcd);
}
/*-------------------------------------------------------------------------*/
static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
{
int retval;
unsigned long flags;
int len = 1 + (urb->dev->maxchild / 8);
spin_lock_irqsave (&hcd_root_hub_lock, flags);
if (urb->status != -EINPROGRESS) /* already unlinked */
retval = urb->status;
else if (hcd->status_urb || urb->transfer_buffer_length < len) {
dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
retval = -EINVAL;
} else {
hcd->status_urb = urb;
urb->hcpriv = hcd; /* indicate it's queued */
if (!hcd->uses_new_polling)
mod_timer (&hcd->rh_timer, jiffies +
msecs_to_jiffies(250));
/* If a status change has already occurred, report it ASAP */
else if (hcd->poll_pending)
mod_timer (&hcd->rh_timer, jiffies);
retval = 0;
}
spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
return retval;
}
static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
{
if (usb_pipeint (urb->pipe)) {
int retval;
unsigned long flags;
spin_lock_irqsave (&hcd_data_lock, flags);
retval = rh_status_urb (hcd, urb);
spin_unlock_irqrestore (&hcd_data_lock, flags);
return retval;
}
if (usb_pipeint (urb->pipe))
return rh_queue_status (hcd, urb);
if (usb_pipecontrol (urb->pipe))
return rh_call_control (hcd, urb);
else
return -EINVAL;
return -EINVAL;
}
/*-------------------------------------------------------------------------*/
/* Asynchronous unlinks of root-hub control URBs are legal, but they
* don't do anything. Status URB unlinks must be made in process context
* with interrupts enabled.
*/
static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
{
unsigned long flags;
if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
if (in_interrupt())
return 0; /* nothing to do */
/* note: always a synchronous unlink */
if ((unsigned long) urb == hcd->rh_timer.data) {
del_timer_sync (&hcd->rh_timer);
hcd->rh_timer.data = 0;
local_irq_save (flags);
urb->hcpriv = NULL;
usb_hcd_giveback_urb (hcd, urb, NULL);
local_irq_restore (flags);
} else if (usb_pipeendpoint(urb->pipe) == 0) {
spin_lock_irq(&urb->lock); /* from usb_kill_urb */
++urb->reject;
spin_unlock_irq(&urb->lock);
@ -642,8 +643,22 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
spin_lock_irq(&urb->lock);
--urb->reject;
spin_unlock_irq(&urb->lock);
} else
return -EINVAL;
} else { /* Status URB */
if (!hcd->uses_new_polling)
del_timer_sync (&hcd->rh_timer);
local_irq_disable ();
spin_lock (&hcd_root_hub_lock);
if (urb == hcd->status_urb) {
hcd->status_urb = NULL;
urb->hcpriv = NULL;
} else
urb = NULL; /* wasn't fully queued */
spin_unlock (&hcd_root_hub_lock);
if (urb)
usb_hcd_giveback_urb (hcd, urb, NULL);
local_irq_enable ();
}
return 0;
}
@ -817,30 +832,22 @@ static void usb_deregister_bus (struct usb_bus *bus)
}
/**
* usb_hcd_register_root_hub - called by HCD to register its root hub
* register_root_hub - called by usb_add_hcd() to register a root hub
* @usb_dev: the usb root hub device to be registered.
* @hcd: host controller for this root hub
*
* The USB host controller calls this function to register the root hub
* properly with the USB subsystem. It sets up the device properly in
* the device tree and stores the root_hub pointer in the bus structure,
* then calls usb_new_device() to register the usb device. It also
* assigns the root hub's USB address (always 1).
* This function registers the root hub with the USB subsystem. It sets up
* the device properly in the device tree and stores the root_hub pointer
* in the bus structure, then calls usb_new_device() to register the usb
* device. It also assigns the root hub's USB address (always 1).
*/
int usb_hcd_register_root_hub (struct usb_device *usb_dev, struct usb_hcd *hcd)
static int register_root_hub (struct usb_device *usb_dev,
struct usb_hcd *hcd)
{
struct device *parent_dev = hcd->self.controller;
const int devnum = 1;
int retval;
/* hcd->driver->start() reported can_wakeup, probably with
* assistance from board's boot firmware.
* NOTE: normal devices won't enable wakeup by default.
*/
if (hcd->can_wakeup)
dev_dbg (parent_dev, "supports USB remote wakeup\n");
hcd->remote_wakeup = hcd->can_wakeup;
usb_dev->devnum = devnum;
usb_dev->bus->devnum_next = devnum + 1;
memset (&usb_dev->bus->devmap.devicemap, 0,
@ -883,7 +890,16 @@ int usb_hcd_register_root_hub (struct usb_device *usb_dev, struct usb_hcd *hcd)
return retval;
}
EXPORT_SYMBOL_GPL(usb_hcd_register_root_hub);
void usb_enable_root_hub_irq (struct usb_bus *bus)
{
struct usb_hcd *hcd;
hcd = container_of (bus, struct usb_hcd, self);
if (hcd->driver->hub_irq_enable && !hcd->poll_rh &&
hcd->state != HC_STATE_HALT)
hcd->driver->hub_irq_enable (hcd);
}
/*-------------------------------------------------------------------------*/
@ -1348,7 +1364,8 @@ hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep)
hcd = udev->bus->hcpriv;
WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT);
WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT &&
udev->state != USB_STATE_NOTATTACHED);
local_irq_disable ();
@ -1612,6 +1629,8 @@ void usb_hc_died (struct usb_hcd *hcd)
spin_lock_irqsave (&hcd_root_hub_lock, flags);
if (hcd->rh_registered) {
hcd->poll_rh = 0;
del_timer(&hcd->rh_timer);
/* make khubd clean up old urbs and devices */
usb_set_device_state (hcd->self.root_hub,
@ -1665,6 +1684,8 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
hcd->self.bus_name = bus_name;
init_timer(&hcd->rh_timer);
hcd->rh_timer.function = rh_timer_func;
hcd->rh_timer.data = (unsigned long) hcd;
hcd->driver = driver;
hcd->product_desc = (driver->product_desc) ? driver->product_desc :
@ -1694,7 +1715,8 @@ EXPORT_SYMBOL (usb_put_hcd);
int usb_add_hcd(struct usb_hcd *hcd,
unsigned int irqnum, unsigned long irqflags)
{
int retval;
int retval;
struct usb_device *rhdev;
dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
@ -1710,7 +1732,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
}
if ((retval = usb_register_bus(&hcd->self)) < 0)
goto err1;
goto err_register_bus;
if (hcd->driver->irq) {
char buf[8], *bufp = buf;
@ -1727,7 +1749,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
hcd->irq_descr, hcd)) != 0) {
dev_err(hcd->self.controller,
"request interrupt %s failed\n", bufp);
goto err2;
goto err_request_irq;
}
hcd->irq = irqnum;
dev_info(hcd->self.controller, "irq %s, %s 0x%08llx\n", bufp,
@ -1743,19 +1765,55 @@ int usb_add_hcd(struct usb_hcd *hcd,
(unsigned long long)hcd->rsrc_start);
}
/* Allocate the root hub before calling hcd->driver->start(),
* but don't register it until afterward so that the hardware
* is running.
*/
if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
dev_err(hcd->self.controller, "unable to allocate root hub\n");
retval = -ENOMEM;
goto err_allocate_root_hub;
}
rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
USB_SPEED_FULL;
/* Although in principle hcd->driver->start() might need to use rhdev,
* none of the current drivers do.
*/
if ((retval = hcd->driver->start(hcd)) < 0) {
dev_err(hcd->self.controller, "startup error %d\n", retval);
goto err3;
goto err_hcd_driver_start;
}
/* hcd->driver->start() reported can_wakeup, probably with
* assistance from board's boot firmware.
* NOTE: normal devices won't enable wakeup by default.
*/
if (hcd->can_wakeup)
dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
hcd->remote_wakeup = hcd->can_wakeup;
if ((retval = register_root_hub(rhdev, hcd)) != 0)
goto err_register_root_hub;
if (hcd->uses_new_polling && hcd->poll_rh)
usb_hcd_poll_rh_status(hcd);
return retval;
err3:
err_register_root_hub:
hcd->driver->stop(hcd);
err_hcd_driver_start:
usb_put_dev(rhdev);
err_allocate_root_hub:
if (hcd->irq >= 0)
free_irq(irqnum, hcd);
err2:
err_request_irq:
usb_deregister_bus(&hcd->self);
err1:
err_register_bus:
hcd_buffer_destroy(hcd);
return retval;
}
@ -1782,6 +1840,9 @@ void usb_remove_hcd(struct usb_hcd *hcd)
spin_unlock_irq (&hcd_root_hub_lock);
usb_disconnect(&hcd->self.root_hub);
hcd->poll_rh = 0;
del_timer_sync(&hcd->rh_timer);
hcd->driver->stop(hcd);
hcd->state = HC_STATE_HALT;

View File

@ -65,7 +65,8 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
const char *product_desc; /* product/vendor string */
char irq_descr[24]; /* driver + bus # */
struct timer_list rh_timer; /* drives root hub */
struct timer_list rh_timer; /* drives root-hub polling */
struct urb *status_urb; /* the current status urb */
/*
* hardware info/state
@ -76,10 +77,17 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
unsigned remote_wakeup:1;/* sw should use wakeup? */
unsigned rh_registered:1;/* is root hub registered? */
/* The next flag is a stopgap, to be removed when all the HCDs
* support the new root-hub polling mechanism. */
unsigned uses_new_polling:1;
unsigned poll_rh:1; /* poll for rh status? */
unsigned poll_pending:1; /* status has changed? */
int irq; /* irq allocated */
void __iomem *regs; /* device memory/io */
u64 rsrc_start; /* memory/io resource start */
u64 rsrc_len; /* memory/io resource length */
unsigned power_budget; /* in mA, 0 = no limit */
#define HCD_BUFFER_POOLS 4
struct dma_pool *pool [HCD_BUFFER_POOLS];
@ -207,6 +215,8 @@ struct hc_driver {
int (*hub_suspend)(struct usb_hcd *);
int (*hub_resume)(struct usb_hcd *);
int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
void (*hub_irq_enable)(struct usb_hcd *);
/* Needed only if port-change IRQs are level-triggered */
};
extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs);
@ -243,7 +253,9 @@ void hcd_buffer_free (struct usb_bus *bus, size_t size,
/* generic bus glue, needed for host controllers that don't use PCI */
extern irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r);
extern void usb_hc_died (struct usb_hcd *hcd);
extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
/* -------------------------------------------------------------------------- */
@ -341,9 +353,6 @@ extern long usb_calc_bus_time (int speed, int is_input,
extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
extern int usb_hcd_register_root_hub (struct usb_device *usb_dev,
struct usb_hcd *hcd);
extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
extern void usb_set_device_state(struct usb_device *udev,
@ -360,6 +369,8 @@ extern wait_queue_head_t usb_kill_urb_queue;
extern struct usb_bus *usb_bus_get (struct usb_bus *bus);
extern void usb_bus_put (struct usb_bus *bus);
extern void usb_enable_root_hub_irq (struct usb_bus *bus);
extern int usb_find_interface_driver (struct usb_device *dev,
struct usb_interface *interface);

View File

@ -643,15 +643,21 @@ static int hub_configure(struct usb_hub *hub,
message = "can't get hub status";
goto fail;
}
cpu_to_le16s(&hubstatus);
if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
le16_to_cpus(&hubstatus);
if (hdev == hdev->bus->root_hub) {
struct usb_hcd *hcd =
container_of(hdev->bus, struct usb_hcd, self);
hub->power_budget = min(500u, hcd->power_budget) / 2;
} else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
hub->descriptor->bHubContrCurrent);
hub->power_budget = (501 - hub->descriptor->bHubContrCurrent)
/ 2;
}
if (hub->power_budget)
dev_dbg(hub_dev, "%dmA bus power budget for children\n",
hub->power_budget * 2);
}
ret = hub_hub_status(hub, &hubstatus, &hubchange);
@ -1727,7 +1733,7 @@ static int finish_port_resume(struct usb_device *udev)
struct usb_driver *driver;
intf = udev->actconfig->interface[i];
if (intf->dev.power.power_state == PMSG_SUSPEND)
if (intf->dev.power.power_state == PMSG_ON)
continue;
if (!intf->dev.driver) {
/* FIXME maybe force to alt 0 */
@ -2787,6 +2793,11 @@ static void hub_events(void)
hub->activating = 0;
/* If this is a root hub, tell the HCD it's okay to
* re-enable port-change interrupts now. */
if (!hdev->parent)
usb_enable_root_hub_irq(hdev->bus);
loop:
usb_unlock_device(hdev);
usb_put_intf(intf);

View File

@ -224,15 +224,4 @@ struct usb_hub {
struct work_struct leds;
};
/* use this for low-powered root hubs */
static inline void
hub_set_power_budget (struct usb_device *hubdev, unsigned mA)
{
struct usb_hub *hub;
hub = (struct usb_hub *)
usb_get_intfdata (hubdev->actconfig->interface[0]);
hub->power_budget = min(mA,(unsigned)500)/2;
}
#endif /* __LINUX_HUB_H */

View File

@ -53,6 +53,9 @@ config USB_GADGET_DEBUG_FILES
driver on a new board. Enable these files by choosing "Y"
here. If in doubt, or to conserve kernel memory, say "N".
config USB_GADGET_SELECTED
boolean
#
# USB Peripheral Controller Support
#
@ -85,6 +88,7 @@ config USB_NET2280
tristate
depends on USB_GADGET_NET2280
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_PXA2XX
boolean "PXA 25x or IXP 4xx"
@ -105,6 +109,7 @@ config USB_PXA2XX
tristate
depends on USB_GADGET_PXA2XX
default USB_GADGET
select USB_GADGET_SELECTED
# if there's only one gadget driver, using only two bulk endpoints,
# don't waste memory for the other endpoints
@ -134,6 +139,7 @@ config USB_GOKU
tristate
depends on USB_GADGET_GOKU
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_LH7A40X
@ -146,6 +152,7 @@ config USB_LH7A40X
tristate
depends on USB_GADGET_LH7A40X
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_OMAP
@ -167,6 +174,7 @@ config USB_OMAP
tristate
depends on USB_GADGET_OMAP
default USB_GADGET
select USB_GADGET_SELECTED
config USB_OTG
boolean "OTG Support"
@ -207,6 +215,7 @@ config USB_DUMMY_HCD
tristate
depends on USB_GADGET_DUMMY_HCD
default USB_GADGET
select USB_GADGET_SELECTED
# NOTE: Please keep dummy_hcd LAST so that "real hardware" appears
# first and will be selected by default.
@ -226,7 +235,7 @@ config USB_GADGET_DUALSPEED
#
choice
tristate "USB Gadget Drivers"
depends on USB_GADGET
depends on USB_GADGET && USB_GADGET_SELECTED
default USB_ETH
help
A Linux "Gadget Driver" talks to the USB Peripheral Controller

File diff suppressed because it is too large Load Diff

View File

@ -84,18 +84,19 @@
*/
#define DRIVER_DESC "Ethernet Gadget"
#define DRIVER_VERSION "Equinox 2004"
#define DRIVER_VERSION "May Day 2005"
static const char shortname [] = "ether";
static const char driver_desc [] = DRIVER_DESC;
#define RX_EXTRA 20 /* guard against rx overflows */
#ifdef CONFIG_USB_ETH_RNDIS
#include "rndis.h"
#else
#define rndis_init() 0
#define rndis_exit() do{}while(0)
#ifndef CONFIG_USB_ETH_RNDIS
#define rndis_uninit(x) do{}while(0)
#define rndis_deregister(c) do{}while(0)
#define rndis_exit() do{}while(0)
#endif
/* CDC and RNDIS support the same host-chosen outgoing packet filters. */
@ -140,9 +141,6 @@ struct eth_dev {
* It also ASSUMES a self-powered device, without remote wakeup,
* although remote wakeup support would make sense.
*/
static const char *EP_IN_NAME;
static const char *EP_OUT_NAME;
static const char *EP_STATUS_NAME;
/*-------------------------------------------------------------------------*/
@ -312,6 +310,7 @@ static inline int rndis_active(struct eth_dev *dev)
#define FS_BPS (19 * 64 * 1 * 1000 * 8)
#ifdef CONFIG_USB_GADGET_DUALSPEED
#define DEVSPEED USB_SPEED_HIGH
static unsigned qmult = 5;
module_param (qmult, uint, S_IRUGO|S_IWUSR);
@ -330,6 +329,8 @@ static inline int BITRATE(struct usb_gadget *g)
}
#else /* full speed (low speed doesn't do bulk) */
#define DEVSPEED USB_SPEED_FULL
#define qlen(gadget) DEFAULT_QLEN
static inline int BITRATE(struct usb_gadget *g)
@ -395,7 +396,8 @@ static inline int BITRATE(struct usb_gadget *g)
#define STRING_SUBSET 8
#define STRING_RNDIS 9
#define USB_BUFSIZ 256 /* holds our biggest descriptor */
/* holds our biggest descriptor (or RNDIS response) */
#define USB_BUFSIZ 256
/*
* This device advertises one configuration, eth_config, unless RNDIS
@ -538,7 +540,7 @@ static const struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = {
.bDataInterface = 0x01,
};
static struct usb_cdc_acm_descriptor acm_descriptor = {
static const struct usb_cdc_acm_descriptor acm_descriptor = {
.bLength = sizeof acm_descriptor,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_ACM_TYPE,
@ -846,7 +848,7 @@ static const struct usb_descriptor_header *hs_rndis_function [] = {
#else
/* if there's no high speed support, maxpacket doesn't change. */
#define ep_desc(g,hs,fs) fs
#define ep_desc(g,hs,fs) (((void)(g)), (fs))
static inline void __init hs_subset_descriptors(void)
{
@ -946,10 +948,31 @@ config_buf (enum usb_device_speed speed,
static void eth_start (struct eth_dev *dev, int gfp_flags);
static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags);
#ifdef DEV_CONFIG_CDC
static inline int ether_alt_ep_setup (struct eth_dev *dev, struct usb_ep *ep)
static int
set_ether_config (struct eth_dev *dev, int gfp_flags)
{
const struct usb_endpoint_descriptor *d;
int result = 0;
struct usb_gadget *gadget = dev->gadget;
/* status endpoint used for RNDIS and (optionally) CDC */
if (!subset_active(dev) && dev->status_ep) {
dev->status = ep_desc (gadget, &hs_status_desc,
&fs_status_desc);
dev->status_ep->driver_data = dev;
result = usb_ep_enable (dev->status_ep, dev->status);
if (result != 0) {
DEBUG (dev, "enable %s --> %d\n",
dev->status_ep->name, result);
goto done;
}
}
dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
dev->in_ep->driver_data = dev;
dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
dev->out_ep->driver_data = dev;
/* With CDC, the host isn't allowed to use these two data
* endpoints in the default altsetting for the interface.
@ -959,135 +982,33 @@ static inline int ether_alt_ep_setup (struct eth_dev *dev, struct usb_ep *ep)
* a side effect of setting a packet filter. Deactivation is
* from REMOTE_NDIS_HALT_MSG, reset from REMOTE_NDIS_RESET_MSG.
*/
/* one endpoint writes data back IN to the host */
if (strcmp (ep->name, EP_IN_NAME) == 0) {
d = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
ep->driver_data = dev;
dev->in = d;
/* one endpoint just reads OUT packets */
} else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
d = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
ep->driver_data = dev;
dev->out = d;
/* optional status/notification endpoint */
} else if (EP_STATUS_NAME &&
strcmp (ep->name, EP_STATUS_NAME) == 0) {
int result;
d = ep_desc (dev->gadget, &hs_status_desc, &fs_status_desc);
result = usb_ep_enable (ep, d);
if (result < 0)
return result;
ep->driver_data = dev;
dev->status = d;
}
return 0;
}
#endif
#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
static inline int ether_ep_setup (struct eth_dev *dev, struct usb_ep *ep)
{
int result;
const struct usb_endpoint_descriptor *d;
/* CDC subset is simpler: if the device is there,
* it's live with rx and tx endpoints.
*
* Do this as a shortcut for RNDIS too.
*/
/* one endpoint writes data back IN to the host */
if (strcmp (ep->name, EP_IN_NAME) == 0) {
d = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
result = usb_ep_enable (ep, d);
if (result < 0)
return result;
ep->driver_data = dev;
dev->in = d;
/* one endpoint just reads OUT packets */
} else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
d = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
result = usb_ep_enable (ep, d);
if (result < 0)
return result;
ep->driver_data = dev;
dev->out = d;
}
return 0;
}
#endif
static int
set_ether_config (struct eth_dev *dev, int gfp_flags)
{
int result = 0;
struct usb_ep *ep;
struct usb_gadget *gadget = dev->gadget;
gadget_for_each_ep (ep, gadget) {
#ifdef DEV_CONFIG_CDC
if (!dev->rndis && dev->cdc) {
result = ether_alt_ep_setup (dev, ep);
if (result == 0)
continue;
}
#endif
#ifdef CONFIG_USB_ETH_RNDIS
if (dev->rndis && strcmp (ep->name, EP_STATUS_NAME) == 0) {
const struct usb_endpoint_descriptor *d;
d = ep_desc (gadget, &hs_status_desc, &fs_status_desc);
result = usb_ep_enable (ep, d);
if (result == 0) {
ep->driver_data = dev;
dev->status = d;
continue;
}
} else
#endif
{
#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
result = ether_ep_setup (dev, ep);
if (result == 0)
continue;
#endif
if (!cdc_active(dev)) {
result = usb_ep_enable (dev->in_ep, dev->in);
if (result != 0) {
DEBUG(dev, "enable %s --> %d\n",
dev->in_ep->name, result);
goto done;
}
/* stop on error */
ERROR (dev, "can't enable %s, result %d\n", ep->name, result);
break;
result = usb_ep_enable (dev->out_ep, dev->out);
if (result != 0) {
DEBUG (dev, "enable %s --> %d\n",
dev->in_ep->name, result);
goto done;
}
}
if (!result && (!dev->in_ep || !dev->out_ep))
result = -ENODEV;
done:
if (result == 0)
result = alloc_requests (dev, qlen (gadget), gfp_flags);
/* on error, disable any endpoints */
if (result < 0) {
#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
if (dev->status)
if (!subset_active(dev))
(void) usb_ep_disable (dev->status_ep);
#endif
dev->status = NULL;
#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
if (dev->rndis || !dev->cdc) {
if (dev->in)
(void) usb_ep_disable (dev->in_ep);
if (dev->out)
(void) usb_ep_disable (dev->out_ep);
}
#endif
(void) usb_ep_disable (dev->in_ep);
(void) usb_ep_disable (dev->out_ep);
dev->in = NULL;
dev->out = NULL;
} else
@ -1095,8 +1016,7 @@ set_ether_config (struct eth_dev *dev, int gfp_flags)
/* activate non-CDC configs right away
* this isn't strictly according to the RNDIS spec
*/
#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
if (dev->rndis || !dev->cdc) {
if (!cdc_active (dev)) {
netif_carrier_on (dev->net);
if (netif_running (dev->net)) {
spin_unlock (&dev->lock);
@ -1104,7 +1024,6 @@ set_ether_config (struct eth_dev *dev, int gfp_flags)
spin_lock (&dev->lock);
}
}
#endif
if (result == 0)
DEBUG (dev, "qlen %d\n", qlen (gadget));
@ -1124,6 +1043,7 @@ static void eth_reset_config (struct eth_dev *dev)
netif_stop_queue (dev->net);
netif_carrier_off (dev->net);
rndis_uninit(dev->rndis_config);
/* disable endpoints, forcing (synchronous) completion of
* pending i/o. then free the requests.
@ -1150,6 +1070,8 @@ static void eth_reset_config (struct eth_dev *dev)
if (dev->status) {
usb_ep_disable (dev->status_ep);
}
dev->rndis = 0;
dev->cdc_filter = 0;
dev->config = 0;
}
@ -1162,9 +1084,6 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
int result = 0;
struct usb_gadget *gadget = dev->gadget;
if (number == dev->config)
return 0;
if (gadget_is_sa1100 (gadget)
&& dev->config
&& atomic_read (&dev->tx_qlen) != 0) {
@ -1174,12 +1093,8 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
}
eth_reset_config (dev);
/* default: pass all packets, no multicast filtering */
dev->cdc_filter = DEFAULT_FILTER;
switch (number) {
case DEV_CONFIG_VALUE:
dev->rndis = 0;
result = set_ether_config (dev, gfp_flags);
break;
#ifdef CONFIG_USB_ETH_RNDIS
@ -1218,9 +1133,9 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
dev->config = number;
INFO (dev, "%s speed config #%d: %d mA, %s, using %s\n",
speed, number, power, driver_desc,
dev->rndis
rndis_active(dev)
? "RNDIS"
: (dev->cdc
: (cdc_active(dev)
? "CDC Ethernet"
: "CDC Ethernet Subset"));
}
@ -1231,6 +1146,13 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
#ifdef DEV_CONFIG_CDC
/* The interrupt endpoint is used in CDC networking models (Ethernet, ATM)
* only to notify the host about link status changes (which we support) or
* report completion of some encapsulated command (as used in RNDIS). Since
* we want this CDC Ethernet code to be vendor-neutral, we don't use that
* command mechanism; and only one status request is ever queued.
*/
static void eth_status_complete (struct usb_ep *ep, struct usb_request *req)
{
struct usb_cdc_notification *event = req->buf;
@ -1259,7 +1181,7 @@ static void eth_status_complete (struct usb_ep *ep, struct usb_request *req)
} else if (value != -ECONNRESET)
DEBUG (dev, "event %02x --> %d\n",
event->bNotificationType, value);
event->bmRequestType = 0xff;
req->context = NULL;
}
static void issue_start_status (struct eth_dev *dev)
@ -1276,6 +1198,8 @@ static void issue_start_status (struct eth_dev *dev)
* a "cancel the whole queue" primitive since any
* unlink-one primitive has way too many error modes.
* here, we "know" toggle is already clear...
*
* FIXME iff req->context != null just dequeue it
*/
usb_ep_disable (dev->status_ep);
usb_ep_enable (dev->status_ep, dev->status);
@ -1292,6 +1216,8 @@ static void issue_start_status (struct eth_dev *dev)
req->length = sizeof *event;
req->complete = eth_status_complete;
req->context = dev;
value = usb_ep_queue (dev->status_ep, req, GFP_ATOMIC);
if (value < 0)
DEBUG (dev, "status buf queue --> %d\n", value);
@ -1351,9 +1277,9 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
struct eth_dev *dev = get_gadget_data (gadget);
struct usb_request *req = dev->req;
int value = -EOPNOTSUPP;
u16 wIndex = (__force u16) ctrl->wIndex;
u16 wValue = (__force u16) ctrl->wValue;
u16 wLength = (__force u16) ctrl->wLength;
u16 wIndex = le16_to_cpu(ctrl->wIndex);
u16 wValue = le16_to_cpu(ctrl->wValue);
u16 wLength = le16_to_cpu(ctrl->wLength);
/* descriptors just go into the pre-allocated ep0 buffer,
* while config change events may enable network traffic.
@ -1424,7 +1350,7 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|| !dev->config
|| wIndex > 1)
break;
if (!dev->cdc && wIndex != 0)
if (!cdc_active(dev) && wIndex != 0)
break;
spin_lock (&dev->lock);
@ -1456,9 +1382,11 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
/* CDC requires the data transfers not be done from
* the default interface setting ... also, setting
* the non-default interface clears filters etc.
* the non-default interface resets filters etc.
*/
if (wValue == 1) {
if (!cdc_active (dev))
break;
usb_ep_enable (dev->in_ep, dev->in);
usb_ep_enable (dev->out_ep, dev->out);
dev->cdc_filter = DEFAULT_FILTER;
@ -1492,11 +1420,11 @@ done_set_intf:
|| !dev->config
|| wIndex > 1)
break;
if (!(dev->cdc || dev->rndis) && wIndex != 0)
if (!(cdc_active(dev) || rndis_active(dev)) && wIndex != 0)
break;
/* for CDC, iff carrier is on, data interface is active. */
if (dev->rndis || wIndex != 1)
if (rndis_active(dev) || wIndex != 1)
*(u8 *)req->buf = 0;
else
*(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0;
@ -1509,8 +1437,7 @@ done_set_intf:
* wValue = packet filter bitmap
*/
if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
|| !dev->cdc
|| dev->rndis
|| !cdc_active(dev)
|| wLength != 0
|| wIndex > 1)
break;
@ -1534,7 +1461,7 @@ done_set_intf:
*/
case USB_CDC_SEND_ENCAPSULATED_COMMAND:
if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
|| !dev->rndis
|| !rndis_active(dev)
|| wLength > USB_BUFSIZ
|| wValue
|| rndis_control_intf.bInterfaceNumber
@ -1549,7 +1476,7 @@ done_set_intf:
case USB_CDC_GET_ENCAPSULATED_RESPONSE:
if ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE)
== ctrl->bRequestType
&& dev->rndis
&& rndis_active(dev)
// && wLength >= 0x0400
&& !wValue
&& rndis_control_intf.bInterfaceNumber
@ -1688,10 +1615,8 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags)
*/
size = (sizeof (struct ethhdr) + dev->net->mtu + RX_EXTRA);
size += dev->out_ep->maxpacket - 1;
#ifdef CONFIG_USB_ETH_RNDIS
if (dev->rndis)
if (rndis_active(dev))
size += sizeof (struct rndis_packet_msg_type);
#endif
size -= size % dev->out_ep->maxpacket;
if ((skb = alloc_skb (size + NET_IP_ALIGN, gfp_flags)) == 0) {
@ -1735,11 +1660,9 @@ static void rx_complete (struct usb_ep *ep, struct usb_request *req)
/* normal completion */
case 0:
skb_put (skb, req->actual);
#ifdef CONFIG_USB_ETH_RNDIS
/* we know MaxPacketsPerTransfer == 1 here */
if (dev->rndis)
if (rndis_active(dev))
status = rndis_rm_hdr (skb);
#endif
if (status < 0
|| ETH_HLEN > skb->len
|| skb->len > ETH_FRAME_LEN) {
@ -1859,8 +1782,6 @@ static void rx_fill (struct eth_dev *dev, int gfp_flags)
struct usb_request *req;
unsigned long flags;
clear_bit (WORK_RX_MEMORY, &dev->todo);
/* fill unused rxq slots with some skb */
spin_lock_irqsave (&dev->lock, flags);
while (!list_empty (&dev->rx_reqs)) {
@ -1883,11 +1804,9 @@ static void eth_work (void *_dev)
{
struct eth_dev *dev = _dev;
if (test_bit (WORK_RX_MEMORY, &dev->todo)) {
if (test_and_clear_bit (WORK_RX_MEMORY, &dev->todo)) {
if (netif_running (dev->net))
rx_fill (dev, GFP_KERNEL);
else
clear_bit (WORK_RX_MEMORY, &dev->todo);
}
if (dev->todo)
@ -1971,8 +1890,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
* or the hardware can't use skb buffers.
* or there's not enough space for any RNDIS headers we need
*/
#ifdef CONFIG_USB_ETH_RNDIS
if (dev->rndis) {
if (rndis_active(dev)) {
struct sk_buff *skb_rndis;
skb_rndis = skb_realloc_headroom (skb,
@ -1985,7 +1903,6 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
rndis_add_hdr (skb);
length = skb->len;
}
#endif
req->buf = skb->data;
req->context = skb;
req->complete = tx_complete;
@ -2018,9 +1935,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
}
if (retval) {
#ifdef CONFIG_USB_ETH_RNDIS
drop:
#endif
dev->stats.tx_dropped++;
dev_kfree_skb_any (skb);
spin_lock_irqsave (&dev->lock, flags);
@ -2036,27 +1951,31 @@ drop:
#ifdef CONFIG_USB_ETH_RNDIS
static void rndis_send_media_state (struct eth_dev *dev, int connect)
{
if (!dev)
return;
if (connect) {
if (rndis_signal_connect (dev->rndis_config))
return;
} else {
if (rndis_signal_disconnect (dev->rndis_config))
return;
}
}
/* The interrupt endpoint is used in RNDIS to notify the host when messages
* other than data packets are available ... notably the REMOTE_NDIS_*_CMPLT
* messages, but also REMOTE_NDIS_INDICATE_STATUS_MSG and potentially even
* REMOTE_NDIS_KEEPALIVE_MSG.
*
* The RNDIS control queue is processed by GET_ENCAPSULATED_RESPONSE, and
* normally just one notification will be queued.
*/
static struct usb_request *eth_req_alloc (struct usb_ep *, unsigned, unsigned);
static void eth_req_free (struct usb_ep *ep, struct usb_request *req);
static void
rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req)
{
struct eth_dev *dev = ep->driver_data;
if (req->status || req->actual != req->length)
DEBUG ((struct eth_dev *) ep->driver_data,
DEBUG (dev,
"rndis control ack complete --> %d, %d/%d\n",
req->status, req->actual, req->length);
req->context = NULL;
if (req != dev->stat_req)
eth_req_free(ep, req);
}
static int rndis_control_ack (struct net_device *net)
@ -2071,11 +1990,19 @@ static int rndis_control_ack (struct net_device *net)
return -ENODEV;
}
/* in case queue length > 1 */
if (resp->context) {
resp = eth_req_alloc (dev->status_ep, 8, GFP_ATOMIC);
if (!resp)
return -ENOMEM;
}
/* Send RNDIS RESPONSE_AVAILABLE notification;
* USB_CDC_NOTIFY_RESPONSE_AVAILABLE should work too
*/
resp->length = 8;
resp->complete = rndis_control_ack_complete;
resp->context = dev;
*((__le32 *) resp->buf) = __constant_cpu_to_le32 (1);
*((__le32 *) resp->buf + 1) = __constant_cpu_to_le32 (0);
@ -2089,6 +2016,10 @@ static int rndis_control_ack (struct net_device *net)
return 0;
}
#else
#define rndis_control_ack NULL
#endif /* RNDIS */
static void eth_start (struct eth_dev *dev, int gfp_flags)
@ -2101,14 +2032,12 @@ static void eth_start (struct eth_dev *dev, int gfp_flags)
/* and open the tx floodgates */
atomic_set (&dev->tx_qlen, 0);
netif_wake_queue (dev->net);
#ifdef CONFIG_USB_ETH_RNDIS
if (dev->rndis) {
if (rndis_active(dev)) {
rndis_set_param_medium (dev->rndis_config,
NDIS_MEDIUM_802_3,
BITRATE(dev->gadget)/100);
rndis_send_media_state (dev, 1);
(void) rndis_signal_connect (dev->rndis_config);
}
#endif
}
static int eth_open (struct net_device *net)
@ -2149,28 +2078,27 @@ static int eth_stop (struct net_device *net)
}
}
#ifdef CONFIG_USB_ETH_RNDIS
if (dev->rndis) {
if (rndis_active(dev)) {
rndis_set_param_medium (dev->rndis_config,
NDIS_MEDIUM_802_3, 0);
rndis_send_media_state (dev, 0);
(void) rndis_signal_disconnect (dev->rndis_config);
}
#endif
return 0;
}
/*-------------------------------------------------------------------------*/
static struct usb_request *eth_req_alloc (struct usb_ep *ep, unsigned size)
static struct usb_request *
eth_req_alloc (struct usb_ep *ep, unsigned size, unsigned gfp_flags)
{
struct usb_request *req;
req = usb_ep_alloc_request (ep, GFP_KERNEL);
req = usb_ep_alloc_request (ep, gfp_flags);
if (!req)
return NULL;
req->buf = kmalloc (size, GFP_KERNEL);
req->buf = kmalloc (size, gfp_flags);
if (!req->buf) {
usb_ep_free_request (ep, req);
req = NULL;
@ -2192,10 +2120,8 @@ eth_unbind (struct usb_gadget *gadget)
struct eth_dev *dev = get_gadget_data (gadget);
DEBUG (dev, "unbind\n");
#ifdef CONFIG_USB_ETH_RNDIS
rndis_deregister (dev->rndis_config);
rndis_exit ();
#endif
/* we've already been disconnected ... no i/o is active */
if (dev->req) {
@ -2368,13 +2294,11 @@ autoconf_fail:
gadget->name);
return -ENODEV;
}
EP_IN_NAME = in_ep->name;
in_ep->driver_data = in_ep; /* claim */
out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
if (!out_ep)
goto autoconf_fail;
EP_OUT_NAME = out_ep->name;
out_ep->driver_data = out_ep; /* claim */
#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
@ -2384,7 +2308,6 @@ autoconf_fail:
if (cdc || rndis) {
status_ep = usb_ep_autoconfig (gadget, &fs_status_desc);
if (status_ep) {
EP_STATUS_NAME = status_ep->name;
status_ep->driver_data = status_ep; /* claim */
} else if (rndis) {
dev_err (&gadget->dev,
@ -2426,7 +2349,7 @@ autoconf_fail:
hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
if (EP_STATUS_NAME)
if (status_ep)
hs_status_desc.bEndpointAddress =
fs_status_desc.bEndpointAddress;
#endif
@ -2499,20 +2422,23 @@ autoconf_fail:
SET_ETHTOOL_OPS(net, &ops);
/* preallocate control message data and buffer */
dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ);
dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ, GFP_KERNEL);
if (!dev->req)
goto fail;
dev->req->complete = eth_setup_complete;
/* ... and maybe likewise for status transfer */
#ifdef DEV_CONFIG_CDC
if (dev->status_ep) {
dev->stat_req = eth_req_alloc (dev->status_ep,
STATUS_BYTECOUNT);
STATUS_BYTECOUNT, GFP_KERNEL);
if (!dev->stat_req) {
eth_req_free (gadget->ep0, dev->req);
goto fail;
}
dev->stat_req->context = NULL;
}
#endif
/* finish hookup to lower layer ... */
dev->gadget = gadget;
@ -2526,16 +2452,16 @@ autoconf_fail:
netif_stop_queue (dev->net);
netif_carrier_off (dev->net);
// SET_NETDEV_DEV (dev->net, &gadget->dev);
SET_NETDEV_DEV (dev->net, &gadget->dev);
status = register_netdev (dev->net);
if (status < 0)
goto fail1;
INFO (dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
INFO (dev, "using %s, OUT %s IN %s%s%s\n", gadget->name,
EP_OUT_NAME, EP_IN_NAME,
EP_STATUS_NAME ? " STATUS " : "",
EP_STATUS_NAME ? EP_STATUS_NAME : ""
out_ep->name, in_ep->name,
status_ep ? " STATUS " : "",
status_ep ? status_ep->name : ""
);
INFO (dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
net->dev_addr [0], net->dev_addr [1],
@ -2548,7 +2474,6 @@ autoconf_fail:
dev->host_mac [2], dev->host_mac [3],
dev->host_mac [4], dev->host_mac [5]);
#ifdef CONFIG_USB_ETH_RNDIS
if (rndis) {
u32 vendorID = 0;
@ -2565,7 +2490,7 @@ fail0:
/* these set up a lot of the OIDs that RNDIS needs */
rndis_set_host_mac (dev->rndis_config, dev->host_mac);
if (rndis_set_param_dev (dev->rndis_config, dev->net,
&dev->stats))
&dev->stats, &dev->cdc_filter))
goto fail0;
if (rndis_set_param_vendor (dev->rndis_config, vendorID,
manufacturer))
@ -2576,7 +2501,6 @@ fail0:
goto fail0;
INFO (dev, "RNDIS ready\n");
}
#endif
return status;
@ -2610,11 +2534,8 @@ eth_resume (struct usb_gadget *gadget)
/*-------------------------------------------------------------------------*/
static struct usb_gadget_driver eth_driver = {
#ifdef CONFIG_USB_GADGET_DUALSPEED
.speed = USB_SPEED_HIGH,
#else
.speed = USB_SPEED_FULL,
#endif
.speed = DEVSPEED,
.function = (char *) driver_desc,
.bind = eth_bind,
.unbind = eth_unbind,

View File

@ -81,6 +81,10 @@
* removable Default false, boolean for removable media
* luns=N Default N = number of filenames, number of
* LUNs to support
* stall Default determined according to the type of
* USB device controller (usually true),
* boolean to permit the driver to halt
* bulk endpoints
* transport=XXX Default BBB, transport name (CB, CBI, or BBB)
* protocol=YYY Default SCSI, protocol name (RBC, 8020 or
* ATAPI, QIC, UFI, 8070, or SCSI;
@ -91,14 +95,10 @@
* buflen=N Default N=16384, buffer size used (will be
* rounded down to a multiple of
* PAGE_CACHE_SIZE)
* stall Default determined according to the type of
* USB device controller (usually true),
* boolean to permit the driver to halt
* bulk endpoints
*
* If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro",
* "removable", and "luns" options are available; default values are used
* for everything else.
* "removable", "luns", and "stall" options are available; default values
* are used for everything else.
*
* The pathnames of the backing files and the ro settings are available in
* the attribute files "file" and "ro" in the lun<n> subdirectory of the
@ -342,14 +342,15 @@ static struct {
int num_ros;
unsigned int nluns;
int removable;
int can_stall;
char *transport_parm;
char *protocol_parm;
int removable;
unsigned short vendor;
unsigned short product;
unsigned short release;
unsigned int buflen;
int can_stall;
int transport_type;
char *transport_name;
@ -360,11 +361,11 @@ static struct {
.transport_parm = "BBB",
.protocol_parm = "SCSI",
.removable = 0,
.can_stall = 1,
.vendor = DRIVER_VENDOR_ID,
.product = DRIVER_PRODUCT_ID,
.release = 0xffff, // Use controller chip type
.buflen = 16384,
.can_stall = 1,
};
@ -380,6 +381,9 @@ MODULE_PARM_DESC(luns, "number of LUNs");
module_param_named(removable, mod_data.removable, bool, S_IRUGO);
MODULE_PARM_DESC(removable, "true to simulate removable media");
module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
/* In the non-TEST version, only the module parameters listed above
* are available. */
@ -404,9 +408,6 @@ MODULE_PARM_DESC(release, "USB release number");
module_param_named(buflen, mod_data.buflen, uint, S_IRUGO);
MODULE_PARM_DESC(buflen, "I/O buffer size");
module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
#endif /* CONFIG_USB_FILE_STORAGE_TEST */
@ -818,7 +819,7 @@ static void inline put_be32(u8 *buf, u32 val)
buf[0] = val >> 24;
buf[1] = val >> 16;
buf[2] = val >> 8;
buf[3] = val;
buf[3] = val & 0xff;
}
@ -1276,8 +1277,8 @@ static int class_setup_req(struct fsg_dev *fsg,
{
struct usb_request *req = fsg->ep0req;
int value = -EOPNOTSUPP;
u16 w_index = ctrl->wIndex;
u16 w_length = ctrl->wLength;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u16 w_length = le16_to_cpu(ctrl->wLength);
if (!fsg->config)
return value;
@ -1312,7 +1313,7 @@ static int class_setup_req(struct fsg_dev *fsg,
}
VDBG(fsg, "get max LUN\n");
*(u8 *) req->buf = fsg->nluns - 1;
value = min(w_length, (u16) 1);
value = 1;
break;
}
}
@ -1344,7 +1345,7 @@ static int class_setup_req(struct fsg_dev *fsg,
"unknown class-specific control req "
"%02x.%02x v%04x i%04x l%u\n",
ctrl->bRequestType, ctrl->bRequest,
ctrl->wValue, w_index, w_length);
le16_to_cpu(ctrl->wValue), w_index, w_length);
return value;
}
@ -1358,9 +1359,8 @@ static int standard_setup_req(struct fsg_dev *fsg,
{
struct usb_request *req = fsg->ep0req;
int value = -EOPNOTSUPP;
u16 w_index = ctrl->wIndex;
u16 w_value = ctrl->wValue;
u16 w_length = ctrl->wLength;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u16 w_value = le16_to_cpu(ctrl->wValue);
/* Usually this just stores reply data in the pre-allocated ep0 buffer,
* but config change events will also reconfigure hardware. */
@ -1374,7 +1374,7 @@ static int standard_setup_req(struct fsg_dev *fsg,
case USB_DT_DEVICE:
VDBG(fsg, "get device descriptor\n");
value = min(w_length, (u16) sizeof device_desc);
value = sizeof device_desc;
memcpy(req->buf, &device_desc, value);
break;
#ifdef CONFIG_USB_GADGET_DUALSPEED
@ -1382,7 +1382,7 @@ static int standard_setup_req(struct fsg_dev *fsg,
VDBG(fsg, "get device qualifier\n");
if (!fsg->gadget->is_dualspeed)
break;
value = min(w_length, (u16) sizeof dev_qualifier);
value = sizeof dev_qualifier;
memcpy(req->buf, &dev_qualifier, value);
break;
@ -1401,8 +1401,6 @@ static int standard_setup_req(struct fsg_dev *fsg,
req->buf,
w_value >> 8,
w_value & 0xff);
if (value >= 0)
value = min(w_length, (u16) value);
break;
case USB_DT_STRING:
@ -1411,8 +1409,6 @@ static int standard_setup_req(struct fsg_dev *fsg,
/* wIndex == language code */
value = usb_gadget_get_string(&stringtab,
w_value & 0xff, req->buf);
if (value >= 0)
value = min(w_length, (u16) value);
break;
}
break;
@ -1438,7 +1434,7 @@ static int standard_setup_req(struct fsg_dev *fsg,
break;
VDBG(fsg, "get configuration\n");
*(u8 *) req->buf = fsg->config;
value = min(w_length, (u16) 1);
value = 1;
break;
case USB_REQ_SET_INTERFACE:
@ -1466,14 +1462,14 @@ static int standard_setup_req(struct fsg_dev *fsg,
}
VDBG(fsg, "get interface\n");
*(u8 *) req->buf = 0;
value = min(w_length, (u16) 1);
value = 1;
break;
default:
VDBG(fsg,
"unknown control req %02x.%02x v%04x i%04x l%u\n",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
w_value, w_index, le16_to_cpu(ctrl->wLength));
}
return value;
@ -1485,6 +1481,7 @@ static int fsg_setup(struct usb_gadget *gadget,
{
struct fsg_dev *fsg = get_gadget_data(gadget);
int rc;
int w_length = le16_to_cpu(ctrl->wLength);
++fsg->ep0_req_tag; // Record arrival of a new request
fsg->ep0req->context = NULL;
@ -1498,9 +1495,9 @@ static int fsg_setup(struct usb_gadget *gadget,
/* Respond with data/status or defer until later? */
if (rc >= 0 && rc != DELAYED_STATUS) {
rc = min(rc, w_length);
fsg->ep0req->length = rc;
fsg->ep0req->zero = (rc < ctrl->wLength &&
(rc % gadget->ep0->maxpacket) == 0);
fsg->ep0req->zero = rc < w_length;
fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
"ep0-in" : "ep0-out");
rc = ep0_queue(fsg);
@ -2660,7 +2657,7 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
}
}
/* Check that the LUN values are oonsistent */
/* Check that the LUN values are consistent */
if (transport_is_bbb()) {
if (fsg->lun != lun)
DBG(fsg, "using LUN %d from CBW, "

View File

@ -70,7 +70,7 @@ MODULE_LICENSE("GPL");
* seem to behave quite as expected. Used by default.
*
* OUT dma documents design problems handling the common "short packet"
* transfer termination policy; it couldn't enabled by default, even
* transfer termination policy; it couldn't be enabled by default, even
* if the OUT-dma abort problems had a resolution.
*/
static unsigned use_dma = 1;
@ -313,7 +313,7 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req)
#if defined(CONFIG_X86)
#define USE_KMALLOC
#elif defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO)
#elif defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT)
#define USE_KMALLOC
#elif defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
@ -1524,9 +1524,12 @@ static void ep0_setup(struct goku_udc *dev)
/* read SETUP packet and enter DATA stage */
ctrl.bRequestType = readl(&regs->bRequestType);
ctrl.bRequest = readl(&regs->bRequest);
ctrl.wValue = (readl(&regs->wValueH) << 8) | readl(&regs->wValueL);
ctrl.wIndex = (readl(&regs->wIndexH) << 8) | readl(&regs->wIndexL);
ctrl.wLength = (readl(&regs->wLengthH) << 8) | readl(&regs->wLengthL);
ctrl.wValue = cpu_to_le16((readl(&regs->wValueH) << 8)
| readl(&regs->wValueL));
ctrl.wIndex = cpu_to_le16((readl(&regs->wIndexH) << 8)
| readl(&regs->wIndexL));
ctrl.wLength = cpu_to_le16((readl(&regs->wLengthH) << 8)
| readl(&regs->wLengthL));
writel(0, &regs->SetupRecv);
nuke(&dev->ep[0], 0);
@ -1548,18 +1551,20 @@ static void ep0_setup(struct goku_udc *dev)
case USB_REQ_CLEAR_FEATURE:
switch (ctrl.bRequestType) {
case USB_RECIP_ENDPOINT:
tmp = ctrl.wIndex & 0x0f;
tmp = le16_to_cpu(ctrl.wIndex) & 0x0f;
/* active endpoint */
if (tmp > 3 || (!dev->ep[tmp].desc && tmp != 0))
goto stall;
if (ctrl.wIndex & USB_DIR_IN) {
if (ctrl.wIndex & __constant_cpu_to_le16(
USB_DIR_IN)) {
if (!dev->ep[tmp].is_in)
goto stall;
} else {
if (dev->ep[tmp].is_in)
goto stall;
}
if (ctrl.wValue != USB_ENDPOINT_HALT)
if (ctrl.wValue != __constant_cpu_to_le16(
USB_ENDPOINT_HALT))
goto stall;
if (tmp)
goku_clear_halt(&dev->ep[tmp]);
@ -1571,7 +1576,7 @@ succeed:
return;
case USB_RECIP_DEVICE:
/* device remote wakeup: always clear */
if (ctrl.wValue != 1)
if (ctrl.wValue != __constant_cpu_to_le16(1))
goto stall;
VDBG(dev, "clear dev remote wakeup\n");
goto succeed;
@ -1589,14 +1594,15 @@ succeed:
#ifdef USB_TRACE
VDBG(dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",
ctrl.bRequestType, ctrl.bRequest,
ctrl.wValue, ctrl.wIndex, ctrl.wLength);
le16_to_cpu(ctrl.wValue), le16_to_cpu(ctrl.wIndex),
le16_to_cpu(ctrl.wLength));
#endif
/* hw wants to know when we're configured (or not) */
dev->req_config = (ctrl.bRequest == USB_REQ_SET_CONFIGURATION
&& ctrl.bRequestType == USB_RECIP_DEVICE);
if (unlikely(dev->req_config))
dev->configured = (ctrl.wValue != 0);
dev->configured = (ctrl.wValue != __constant_cpu_to_le16(0));
/* delegate everything to the gadget driver.
* it may respond after this irq handler returns.

View File

@ -417,8 +417,8 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
goto free1;
value = ep_io (data, kbuf, len);
VDEBUG (data->dev, "%s read %d OUT, status %d\n",
data->name, len, value);
VDEBUG (data->dev, "%s read %zu OUT, status %d\n",
data->name, len, (int) value);
if (value >= 0 && copy_to_user (buf, kbuf, value))
value = -EFAULT;
@ -465,8 +465,8 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
}
value = ep_io (data, kbuf, len);
VDEBUG (data->dev, "%s write %d IN, status %d\n",
data->name, len, value);
VDEBUG (data->dev, "%s write %zu IN, status %d\n",
data->name, len, (int) value);
free1:
up (&data->lock);
kfree (kbuf);
@ -1318,8 +1318,8 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
struct usb_request *req = dev->req;
int value = -EOPNOTSUPP;
struct usb_gadgetfs_event *event;
u16 w_value = ctrl->wValue;
u16 w_length = ctrl->wLength;
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
spin_lock (&dev->lock);
dev->setup_abort = 0;

View File

@ -47,17 +47,17 @@ struct NDIS_PM_WAKE_UP_CAPABILITIES {
#define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004
struct NDIS_PNP_CAPABILITIES {
u32 Flags;
__le32 Flags;
struct NDIS_PM_WAKE_UP_CAPABILITIES WakeUpCapabilities;
};
struct NDIS_PM_PACKET_PATTERN {
u32 Priority;
u32 Reserved;
u32 MaskSize;
u32 PatternOffset;
u32 PatternSize;
u32 PatternFlags;
__le32 Priority;
__le32 Reserved;
__le32 MaskSize;
__le32 PatternOffset;
__le32 PatternSize;
__le32 PatternFlags;
};

View File

@ -448,7 +448,7 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req)
#elif defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
#define USE_KMALLOC
#elif defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO)
#elif defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT)
#define USE_KMALLOC
/* FIXME there are other cases, including an x86-64 one ... */
@ -1113,7 +1113,7 @@ static void restart_dma (struct net2280_ep *ep)
if (ep->in_fifo_validate)
dmactl |= (1 << DMA_FIFO_VALIDATE);
list_for_each_entry (entry, &ep->queue, queue) {
u32 dmacount;
__le32 dmacount;
if (entry == req)
continue;
@ -1238,7 +1238,7 @@ static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req)
&ep->dma->dmadesc);
if (req->td->dmacount & dma_done_ie)
writel (readl (&ep->dma->dmacount)
| dma_done_ie,
| le32_to_cpu(dma_done_ie),
&ep->dma->dmacount);
} else {
struct net2280_request *prev;
@ -1779,6 +1779,9 @@ static void set_fifo_mode (struct net2280 *dev, int mode)
list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list);
}
/* just declare this in any driver that really need it */
extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
/**
* net2280_set_fifo_mode - change allocation of fifo buffers
* @gadget: access to the net2280 device that will be updated
@ -2382,9 +2385,9 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
cpu_to_le32s (&u.raw [0]);
cpu_to_le32s (&u.raw [1]);
le16_to_cpus (&u.r.wValue);
le16_to_cpus (&u.r.wIndex);
le16_to_cpus (&u.r.wLength);
#define w_value le16_to_cpup (&u.r.wValue)
#define w_index le16_to_cpup (&u.r.wIndex)
#define w_length le16_to_cpup (&u.r.wLength)
/* ack the irq */
writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0);
@ -2413,25 +2416,25 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
switch (u.r.bRequest) {
case USB_REQ_GET_STATUS: {
struct net2280_ep *e;
u16 status;
__le32 status;
/* hw handles device and interface status */
if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT))
goto delegate;
if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0
|| u.r.wLength > 2)
if ((e = get_ep_by_addr (dev, w_index)) == 0
|| w_length > 2)
goto do_stall;
if (readl (&e->regs->ep_rsp)
& (1 << SET_ENDPOINT_HALT))
status = __constant_cpu_to_le16 (1);
status = __constant_cpu_to_le32 (1);
else
status = __constant_cpu_to_le16 (0);
status = __constant_cpu_to_le32 (0);
/* don't bother with a request object! */
writel (0, &dev->epregs [0].ep_irqenb);
set_fifo_bytecount (ep, u.r.wLength);
writel (status, &dev->epregs [0].ep_data);
set_fifo_bytecount (ep, w_length);
writel ((__force u32)status, &dev->epregs [0].ep_data);
allow_status (ep);
VDEBUG (dev, "%s stat %02x\n", ep->ep.name, status);
goto next_endpoints;
@ -2443,10 +2446,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
/* hw handles device features */
if (u.r.bRequestType != USB_RECIP_ENDPOINT)
goto delegate;
if (u.r.wValue != USB_ENDPOINT_HALT
|| u.r.wLength != 0)
if (w_value != USB_ENDPOINT_HALT
|| w_length != 0)
goto do_stall;
if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0)
if ((e = get_ep_by_addr (dev, w_index)) == 0)
goto do_stall;
clear_halt (e);
allow_status (ep);
@ -2460,10 +2463,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
/* hw handles device features */
if (u.r.bRequestType != USB_RECIP_ENDPOINT)
goto delegate;
if (u.r.wValue != USB_ENDPOINT_HALT
|| u.r.wLength != 0)
if (w_value != USB_ENDPOINT_HALT
|| w_length != 0)
goto do_stall;
if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0)
if ((e = get_ep_by_addr (dev, w_index)) == 0)
goto do_stall;
set_halt (e);
allow_status (ep);
@ -2473,10 +2476,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
break;
default:
delegate:
VDEBUG (dev, "setup %02x.%02x v%04x i%04x "
VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x"
"ep_cfg %08x\n",
u.r.bRequestType, u.r.bRequest,
u.r.wValue, u.r.wIndex,
w_value, w_index, w_length,
readl (&ep->regs->ep_cfg));
spin_unlock (&dev->lock);
tmp = dev->driver->setup (&dev->gadget, &u.r);
@ -2497,6 +2500,10 @@ do_stall:
*/
}
#undef w_value
#undef w_index
#undef w_length
next_endpoints:
/* endpoint data irq ? */
scratch = stat & 0x7f;
@ -2653,7 +2660,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
restart_dma (ep);
else if (ep->is_in && use_dma_chaining) {
struct net2280_request *req;
u32 dmacount;
__le32 dmacount;
/* the descriptor at the head of the chain
* may still have VALID_BIT clear; that's

View File

@ -52,7 +52,6 @@
#include <asm/mach-types.h>
#include <asm/arch/dma.h>
#include <asm/arch/mux.h>
#include <asm/arch/usb.h>
#include "omap_udc.h"
@ -167,7 +166,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
maxp = le16_to_cpu (desc->wMaxPacketSize);
if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
&& maxp != ep->maxpacket)
|| desc->wMaxPacketSize > ep->maxpacket
|| le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket
|| !desc->wMaxPacketSize) {
DBG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name);
return -ERANGE;
@ -214,7 +213,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
ep->has_dma = 0;
ep->lch = -1;
use_ep(ep, UDC_EP_SEL);
UDC_CTRL_REG = UDC_RESET_EP;
UDC_CTRL_REG = udc->clr_halt;
ep->ackwait = 0;
deselect_ep();
@ -253,7 +252,7 @@ static int omap_ep_disable(struct usb_ep *_ep)
}
spin_lock_irqsave(&ep->udc->lock, flags);
ep->desc = 0;
ep->desc = NULL;
nuke (ep, -ESHUTDOWN);
ep->ep.maxpacket = ep->maxpacket;
ep->has_dma = 0;
@ -388,8 +387,8 @@ done(struct omap_ep *ep, struct omap_req *req, int status)
/*-------------------------------------------------------------------------*/
#define FIFO_FULL (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL)
#define FIFO_UNWRITABLE (UDC_EP_HALTED | FIFO_FULL)
#define UDC_FIFO_FULL (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL)
#define UDC_FIFO_UNWRITABLE (UDC_EP_HALTED | UDC_FIFO_FULL)
#define FIFO_EMPTY (UDC_NON_ISO_FIFO_EMPTY | UDC_ISO_FIFO_EMPTY)
#define FIFO_UNREADABLE (UDC_EP_HALTED | FIFO_EMPTY)
@ -433,7 +432,7 @@ static int write_fifo(struct omap_ep *ep, struct omap_req *req)
/* PIO-IN isn't double buffered except for iso */
ep_stat = UDC_STAT_FLG_REG;
if (ep_stat & FIFO_UNWRITABLE)
if (ep_stat & UDC_FIFO_UNWRITABLE)
return 0;
count = ep->ep.maxpacket;
@ -504,7 +503,7 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
if (ep_stat & UDC_EP_HALTED)
break;
if (ep_stat & FIFO_FULL)
if (ep_stat & UDC_FIFO_FULL)
avail = ep->ep.maxpacket;
else {
avail = UDC_RXFSTAT_REG;
@ -538,6 +537,32 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
/*-------------------------------------------------------------------------*/
static inline dma_addr_t dma_csac(unsigned lch)
{
dma_addr_t csac;
/* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
* read before the DMA controller finished disabling the channel.
*/
csac = omap_readw(OMAP_DMA_CSAC(lch));
if (csac == 0)
csac = omap_readw(OMAP_DMA_CSAC(lch));
return csac;
}
static inline dma_addr_t dma_cdac(unsigned lch)
{
dma_addr_t cdac;
/* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
* read before the DMA controller finished disabling the channel.
*/
cdac = omap_readw(OMAP_DMA_CDAC(lch));
if (cdac == 0)
cdac = omap_readw(OMAP_DMA_CDAC(lch));
return cdac;
}
static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
{
dma_addr_t end;
@ -548,7 +573,7 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
if (cpu_is_omap15xx())
return 0;
end = omap_readw(OMAP_DMA_CSAC(ep->lch));
end = dma_csac(ep->lch);
if (end == ep->dma_counter)
return 0;
@ -559,14 +584,14 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
}
#define DMA_DEST_LAST(x) (cpu_is_omap15xx() \
? OMAP_DMA_CSAC(x) /* really: CPC */ \
: OMAP_DMA_CDAC(x))
? omap_readw(OMAP_DMA_CSAC(x)) /* really: CPC */ \
: dma_cdac(x))
static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start)
{
dma_addr_t end;
end = omap_readw(DMA_DEST_LAST(ep->lch));
end = DMA_DEST_LAST(ep->lch);
if (end == ep->dma_counter)
return 0;
@ -593,7 +618,7 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
: OMAP_DMA_SYNC_ELEMENT;
/* measure length in either bytes or packets */
if ((cpu_is_omap16xx() && length <= (UDC_TXN_TSC + 1))
if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC)
|| (cpu_is_omap15xx() && length < ep->maxpacket)) {
txdma_ctrl = UDC_TXN_EOT | length;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
@ -602,15 +627,15 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
length = min(length / ep->maxpacket,
(unsigned) UDC_TXN_TSC + 1);
txdma_ctrl = length;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
ep->ep.maxpacket, length, sync_mode);
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
ep->ep.maxpacket >> 1, length, sync_mode);
length *= ep->maxpacket;
}
omap_set_dma_src_params(ep->lch, OMAP_DMA_PORT_EMIFF,
OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
omap_start_dma(ep->lch);
ep->dma_counter = omap_readw(OMAP_DMA_CSAC(ep->lch));
ep->dma_counter = dma_csac(ep->lch);
UDC_DMA_IRQ_EN_REG |= UDC_TX_DONE_IE(ep->dma_channel);
UDC_TXDMA_REG(ep->dma_channel) = UDC_TXN_START | txdma_ctrl;
req->dma_bytes = length;
@ -650,12 +675,12 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
packets = (req->req.length - req->req.actual) / ep->ep.maxpacket;
packets = min(packets, (unsigned)UDC_RXN_TC + 1);
req->dma_bytes = packets * ep->ep.maxpacket;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
ep->ep.maxpacket, packets,
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
ep->ep.maxpacket >> 1, packets,
OMAP_DMA_SYNC_ELEMENT);
omap_set_dma_dest_params(ep->lch, OMAP_DMA_PORT_EMIFF,
OMAP_DMA_AMODE_POST_INC, req->req.dma + req->req.actual);
ep->dma_counter = omap_readw(DMA_DEST_LAST(ep->lch));
ep->dma_counter = DMA_DEST_LAST(ep->lch);
UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1);
UDC_DMA_IRQ_EN_REG |= UDC_RX_EOT_IE(ep->dma_channel);
@ -763,7 +788,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
reg = UDC_TXDMA_CFG_REG;
else
reg = UDC_RXDMA_CFG_REG;
reg |= 1 << 12; /* "pulse" activated */
reg |= UDC_DMA_REQ; /* "pulse" activated */
ep->dma_channel = 0;
ep->lch = -1;
@ -787,6 +812,11 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
ep->ep.name, dma_error, ep, &ep->lch);
if (status == 0) {
UDC_TXDMA_CFG_REG = reg;
/* EMIFF */
omap_set_dma_src_burst_mode(ep->lch,
OMAP_DMA_DATA_BURST_4);
omap_set_dma_src_data_pack(ep->lch, 1);
/* TIPB */
omap_set_dma_dest_params(ep->lch,
OMAP_DMA_PORT_TIPB,
OMAP_DMA_AMODE_CONSTANT,
@ -797,10 +827,15 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
ep->ep.name, dma_error, ep, &ep->lch);
if (status == 0) {
UDC_RXDMA_CFG_REG = reg;
/* TIPB */
omap_set_dma_src_params(ep->lch,
OMAP_DMA_PORT_TIPB,
OMAP_DMA_AMODE_CONSTANT,
(unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG));
/* EMIFF */
omap_set_dma_dest_burst_mode(ep->lch,
OMAP_DMA_DATA_BURST_4);
omap_set_dma_dest_data_pack(ep->lch, 1);
}
}
if (status)
@ -856,7 +891,7 @@ static void dma_channel_release(struct omap_ep *ep)
if (!list_empty(&ep->queue))
req = container_of(ep->queue.next, struct omap_req, queue);
else
req = 0;
req = NULL;
active = ((1 << 7) & omap_readl(OMAP_DMA_CCR(ep->lch))) != 0;
@ -865,9 +900,13 @@ static void dma_channel_release(struct omap_ep *ep)
(ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r',
ep->dma_channel - 1, req);
/* NOTE: re-setting RX_REQ/TX_REQ because of a chip bug (before
* OMAP 1710 ES2.0) where reading the DMA_CFG can clear them.
*/
/* wait till current packet DMA finishes, and fifo empties */
if (ep->bEndpointAddress & USB_DIR_IN) {
UDC_TXDMA_CFG_REG &= ~mask;
UDC_TXDMA_CFG_REG = (UDC_TXDMA_CFG_REG & ~mask) | UDC_DMA_REQ;
if (req) {
finish_in_dma(ep, req, -ECONNRESET);
@ -880,7 +919,7 @@ static void dma_channel_release(struct omap_ep *ep)
while (UDC_TXDMA_CFG_REG & mask)
udelay(10);
} else {
UDC_RXDMA_CFG_REG &= ~mask;
UDC_RXDMA_CFG_REG = (UDC_RXDMA_CFG_REG & ~mask) | UDC_DMA_REQ;
/* dma empties the fifo */
while (UDC_RXDMA_CFG_REG & mask)
@ -997,18 +1036,19 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
UDC_IRQ_EN_REG = irq_en;
}
/* STATUS is reverse direction */
UDC_EP_NUM_REG = is_in
? UDC_EP_SEL
: (UDC_EP_SEL|UDC_EP_DIR);
/* STATUS for zero length DATA stages is
* always an IN ... even for IN transfers,
* a wierd case which seem to stall OMAP.
*/
UDC_EP_NUM_REG = (UDC_EP_SEL|UDC_EP_DIR);
UDC_CTRL_REG = UDC_CLR_EP;
UDC_CTRL_REG = UDC_SET_FIFO_EN;
UDC_EP_NUM_REG = udc->ep0_in ? 0 : UDC_EP_DIR;
UDC_EP_NUM_REG = UDC_EP_DIR;
/* cleanup */
udc->ep0_pending = 0;
done(ep, req, 0);
req = 0;
req = NULL;
/* non-empty DATA stage */
} else if (is_in) {
@ -1029,7 +1069,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
(is_in ? next_in_dma : next_out_dma)(ep, req);
else if (req) {
if ((is_in ? write_fifo : read_fifo)(ep, req) == 1)
req = 0;
req = NULL;
deselect_ep();
if (!is_in) {
UDC_CTRL_REG = UDC_SET_FIFO_EN;
@ -1041,7 +1081,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
irq_wait:
/* irq handler advances the queue */
if (req != 0)
if (req != NULL)
list_add_tail(&req->queue, &ep->queue);
spin_unlock_irqrestore(&udc->lock, flags);
@ -1140,7 +1180,7 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value)
dma_channel_claim(ep, channel);
} else {
use_ep(ep, 0);
UDC_CTRL_REG = UDC_RESET_EP;
UDC_CTRL_REG = ep->udc->clr_halt;
ep->ackwait = 0;
if (!(ep->bEndpointAddress & USB_DIR_IN)) {
UDC_CTRL_REG = UDC_SET_FIFO_EN;
@ -1238,6 +1278,8 @@ static int can_pullup(struct omap_udc *udc)
static void pullup_enable(struct omap_udc *udc)
{
udc->gadget.dev.parent->power.power_state = PMSG_ON;
udc->gadget.dev.power.power_state = PMSG_ON;
UDC_SYSCON1_REG |= UDC_PULLUP_EN;
#ifndef CONFIG_USB_OTG
if (!cpu_is_omap15xx())
@ -1382,7 +1424,7 @@ static void update_otg(struct omap_udc *udc)
static void ep0_irq(struct omap_udc *udc, u16 irq_src)
{
struct omap_ep *ep0 = &udc->ep[0];
struct omap_req *req = 0;
struct omap_req *req = NULL;
ep0->irqs++;
@ -1438,7 +1480,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
if (req)
done(ep0, req, 0);
}
req = 0;
req = NULL;
} else if (stat & UDC_STALL) {
UDC_CTRL_REG = UDC_CLR_HALT;
UDC_EP_NUM_REG = UDC_EP_DIR;
@ -1511,9 +1553,10 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
u.word[3] = UDC_DATA_REG;
UDC_EP_NUM_REG = 0;
} while (UDC_IRQ_SRC_REG & UDC_SETUP);
le16_to_cpus (&u.r.wValue);
le16_to_cpus (&u.r.wIndex);
le16_to_cpus (&u.r.wLength);
#define w_value le16_to_cpup (&u.r.wValue)
#define w_index le16_to_cpup (&u.r.wIndex)
#define w_length le16_to_cpup (&u.r.wLength)
/* Delegate almost all control requests to the gadget driver,
* except for a handful of ch9 status/feature requests that
@ -1529,11 +1572,11 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
/* udc needs to know when ep != 0 is valid */
if (u.r.bRequestType != USB_RECIP_DEVICE)
goto delegate;
if (u.r.wLength != 0)
if (w_length != 0)
goto do_stall;
udc->ep0_set_config = 1;
udc->ep0_reset_config = (u.r.wValue == 0);
VDBG("set config %d\n", u.r.wValue);
udc->ep0_reset_config = (w_value == 0);
VDBG("set config %d\n", w_value);
/* update udc NOW since gadget driver may start
* queueing requests immediately; clear config
@ -1549,23 +1592,28 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
/* clear endpoint halt */
if (u.r.bRequestType != USB_RECIP_ENDPOINT)
goto delegate;
if (u.r.wValue != USB_ENDPOINT_HALT
|| u.r.wLength != 0)
if (w_value != USB_ENDPOINT_HALT
|| w_length != 0)
goto do_stall;
ep = &udc->ep[u.r.wIndex & 0xf];
ep = &udc->ep[w_index & 0xf];
if (ep != ep0) {
if (u.r.wIndex & USB_DIR_IN)
if (w_index & USB_DIR_IN)
ep += 16;
if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
|| !ep->desc)
goto do_stall;
use_ep(ep, 0);
UDC_CTRL_REG = UDC_RESET_EP;
UDC_CTRL_REG = udc->clr_halt;
ep->ackwait = 0;
if (!(ep->bEndpointAddress & USB_DIR_IN)) {
UDC_CTRL_REG = UDC_SET_FIFO_EN;
ep->ackwait = 1 + ep->double_buf;
}
/* NOTE: assumes the host behaves sanely,
* only clearing real halts. Else we may
* need to kill pending transfers and then
* restart the queue... very messy for DMA!
*/
}
VDBG("%s halt cleared by host\n", ep->name);
goto ep0out_status_stage;
@ -1573,11 +1621,11 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
/* set endpoint halt */
if (u.r.bRequestType != USB_RECIP_ENDPOINT)
goto delegate;
if (u.r.wValue != USB_ENDPOINT_HALT
|| u.r.wLength != 0)
if (w_value != USB_ENDPOINT_HALT
|| w_length != 0)
goto do_stall;
ep = &udc->ep[u.r.wIndex & 0xf];
if (u.r.wIndex & USB_DIR_IN)
ep = &udc->ep[w_index & 0xf];
if (w_index & USB_DIR_IN)
ep += 16;
if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
|| ep == ep0 || !ep->desc)
@ -1615,13 +1663,13 @@ ep0out_status_stage:
UDC_CTRL_REG = UDC_SET_FIFO_EN;
UDC_EP_NUM_REG = UDC_EP_DIR;
status = 0;
VDBG("GET_STATUS, interface %d\n", u.r.wIndex);
VDBG("GET_STATUS, interface %d\n", w_index);
/* next, status stage */
break;
default:
delegate:
/* activate the ep0out fifo right away */
if (!udc->ep0_in && u.r.wLength) {
if (!udc->ep0_in && w_length) {
UDC_EP_NUM_REG = 0;
UDC_CTRL_REG = UDC_SET_FIFO_EN;
}
@ -1632,7 +1680,11 @@ delegate:
*/
VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n",
u.r.bRequestType, u.r.bRequest,
u.r.wValue, u.r.wIndex, u.r.wLength);
w_value, w_index, w_length);
#undef w_value
#undef w_index
#undef w_length
/* The gadget driver may return an error here,
* causing an immediate protocol stall.
@ -2013,7 +2065,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
udc->softconnect = 1;
/* hook up the driver */
driver->driver.bus = 0;
driver->driver.bus = NULL;
udc->driver = driver;
udc->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc->lock, flags);
@ -2021,8 +2073,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
status = driver->bind (&udc->gadget);
if (status) {
DBG("bind to %s --> %d\n", driver->driver.name, status);
udc->gadget.dev.driver = 0;
udc->driver = 0;
udc->gadget.dev.driver = NULL;
udc->driver = NULL;
goto done;
}
DBG("bound to driver %s\n", driver->driver.name);
@ -2035,8 +2087,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
if (status < 0) {
ERR("can't bind to transceiver\n");
driver->unbind (&udc->gadget);
udc->gadget.dev.driver = 0;
udc->driver = 0;
udc->gadget.dev.driver = NULL;
udc->driver = NULL;
goto done;
}
} else {
@ -2071,7 +2123,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
omap_vbus_session(&udc->gadget, 0);
if (udc->transceiver)
(void) otg_set_peripheral(udc->transceiver, 0);
(void) otg_set_peripheral(udc->transceiver, NULL);
else
pullup_disable(udc);
@ -2080,9 +2132,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
spin_unlock_irqrestore(&udc->lock, flags);
driver->unbind(&udc->gadget);
udc->gadget.dev.driver = 0;
udc->driver = 0;
udc->gadget.dev.driver = NULL;
udc->driver = NULL;
DBG("unregistered driver '%s'\n", driver->driver.name);
return status;
@ -2178,14 +2229,14 @@ static int proc_otg_show(struct seq_file *s)
tmp = OTG_REV_REG;
trans = USB_TRANSCEIVER_CTRL_REG;
seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %03x\n",
seq_printf(s, "\nOTG rev %d.%d, transceiver_ctrl %05x\n",
tmp >> 4, tmp & 0xf, trans);
tmp = OTG_SYSCON_1_REG;
seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s,"
FOURBITS "\n", tmp,
trx_mode(USB2_TRX_MODE(tmp), trans & CONF_USB2_UNI_R),
trx_mode(USB1_TRX_MODE(tmp), trans & CONF_USB1_UNI_R),
(USB0_TRX_MODE(tmp) == 0)
(USB0_TRX_MODE(tmp) == 0 && !cpu_is_omap1710())
? "internal"
: trx_mode(USB0_TRX_MODE(tmp), 1),
(tmp & OTG_IDLE_EN) ? " !otg" : "",
@ -2235,6 +2286,7 @@ static int proc_otg_show(struct seq_file *s)
seq_printf(s, "otg_outctrl %04x" "\n", tmp);
tmp = OTG_TEST_REG;
seq_printf(s, "otg_test %04x" "\n", tmp);
return 0;
}
static int proc_udc_show(struct seq_file *s, void *_)
@ -2378,7 +2430,7 @@ static int proc_udc_show(struct seq_file *s, void *_)
static int proc_udc_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_udc_show, 0);
return single_open(file, proc_udc_show, NULL);
}
static struct file_operations proc_ops = {
@ -2399,7 +2451,7 @@ static void create_proc_file(void)
static void remove_proc_file(void)
{
remove_proc_entry(proc_filename, 0);
remove_proc_entry(proc_filename, NULL);
}
#else
@ -2414,6 +2466,10 @@ static inline void remove_proc_file(void) {}
/* Before this controller can enumerate, we need to pick an endpoint
* configuration, or "fifo_mode" That involves allocating 2KB of packet
* buffer space among the endpoints we'll be operating.
*
* NOTE: as of OMAP 1710 ES2.0, writing a new endpoint config when
* UDC_SYSCON_1_REG.CFG_LOCK is set can now work. We won't use that
* capability yet though.
*/
static unsigned __init
omap_ep_setup(char *name, u8 addr, u8 type,
@ -2505,7 +2561,7 @@ static void omap_udc_release(struct device *dev)
{
complete(udc->done);
kfree (udc);
udc = 0;
udc = NULL;
}
static int __init
@ -2577,23 +2633,33 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
case 1:
OMAP_BULK_EP("ep1in", USB_DIR_IN | 1);
OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2);
OMAP_INT_EP("ep9in", USB_DIR_IN | 9, 16);
OMAP_BULK_EP("ep3in", USB_DIR_IN | 3);
OMAP_BULK_EP("ep4out", USB_DIR_OUT | 4);
OMAP_INT_EP("ep10in", USB_DIR_IN | 10, 16);
OMAP_BULK_EP("ep5in", USB_DIR_IN | 5);
OMAP_BULK_EP("ep5out", USB_DIR_OUT | 5);
OMAP_INT_EP("ep11in", USB_DIR_IN | 11, 16);
OMAP_BULK_EP("ep6in", USB_DIR_IN | 6);
OMAP_BULK_EP("ep6out", USB_DIR_OUT | 6);
OMAP_INT_EP("ep12in", USB_DIR_IN | 12, 16);
OMAP_BULK_EP("ep7in", USB_DIR_IN | 7);
OMAP_BULK_EP("ep7out", USB_DIR_OUT | 7);
OMAP_INT_EP("ep13in", USB_DIR_IN | 13, 16);
OMAP_INT_EP("ep13out", USB_DIR_OUT | 13, 16);
OMAP_BULK_EP("ep8in", USB_DIR_IN | 8);
OMAP_BULK_EP("ep8out", USB_DIR_OUT | 8);
OMAP_INT_EP("ep14in", USB_DIR_IN | 14, 16);
OMAP_INT_EP("ep14out", USB_DIR_OUT | 14, 16);
OMAP_BULK_EP("ep15in", USB_DIR_IN | 15);
OMAP_BULK_EP("ep15out", USB_DIR_OUT | 15);
OMAP_INT_EP("ep9in", USB_DIR_IN | 9, 16);
OMAP_INT_EP("ep10out", USB_DIR_IN | 10, 16);
OMAP_INT_EP("ep11in", USB_DIR_IN | 9, 16);
OMAP_INT_EP("ep12out", USB_DIR_IN | 10, 16);
break;
#ifdef USE_ISO
@ -2640,8 +2706,8 @@ static int __init omap_udc_probe(struct device *dev)
struct platform_device *odev = to_platform_device(dev);
int status = -ENODEV;
int hmc;
struct otg_transceiver *xceiv = 0;
const char *type = 0;
struct otg_transceiver *xceiv = NULL;
const char *type = NULL;
struct omap_usb_config *config = dev->platform_data;
/* NOTE: "knows" the order of the resources! */
@ -2676,54 +2742,78 @@ static int __init omap_udc_probe(struct device *dev)
FUNC_MUX_CTRL_0_REG = tmp;
}
} else {
/* The transceiver may package some GPIO logic or handle
* loopback and/or transceiverless setup; if we find one,
* use it. Except for OTG, we don't _need_ to talk to one;
* but not having one probably means no VBUS detection.
*/
xceiv = otg_get_transceiver();
if (xceiv)
type = xceiv->label;
else if (config->otg) {
DBG("OTG requires external transceiver!\n");
goto cleanup0;
}
hmc = HMC_1610;
switch (hmc) {
case 0: /* POWERUP DEFAULT == 0 */
case 4:
case 12:
case 20:
if (!cpu_is_omap1710()) {
type = "integrated";
break;
}
/* FALL THROUGH */
case 3:
case 11:
case 16:
case 19:
case 25:
xceiv = otg_get_transceiver();
if (!xceiv) {
DBG("external transceiver not registered!\n");
if (config->otg)
goto cleanup0;
type = "(unknown external)";
} else
type = xceiv->label;
break;
case 0: /* POWERUP DEFAULT == 0 */
case 4:
case 12:
case 20:
type = "INTEGRATED";
type = "unknown";
}
break;
case 21: /* internal loopback */
type = "(loopback)";
type = "loopback";
break;
case 14: /* transceiverless */
type = "(none)";
if (cpu_is_omap1710())
goto bad_on_1710;
/* FALL THROUGH */
case 13:
case 15:
type = "no";
break;
default:
bad_on_1710:
ERR("unrecognized UDC HMC mode %d\n", hmc);
return -ENODEV;
goto cleanup0;
}
}
INFO("hmc mode %d, transceiver %s\n", hmc, type);
INFO("hmc mode %d, %s transceiver\n", hmc, type);
/* a "gadget" abstracts/virtualizes the controller */
status = omap_udc_setup(odev, xceiv);
if (status) {
goto cleanup0;
}
xceiv = 0;
xceiv = NULL;
// "udc" is now valid
pullup_disable(udc);
#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
udc->gadget.is_otg = (config->otg != 0);
#endif
/* starting with omap1710 es2.0, clear toggle is a separate bit */
if (UDC_REV_REG >= 0x61)
udc->clr_halt = UDC_RESET_EP | UDC_CLRDATA_TOGGLE;
else
udc->clr_halt = UDC_RESET_EP;
/* USB general purpose IRQ: ep0, state changes, dma, etc */
status = request_irq(odev->resource[1].start, omap_udc_irq,
SA_SAMPLE_RANDOM, driver_name, udc);
@ -2765,7 +2855,7 @@ cleanup2:
cleanup1:
kfree (udc);
udc = 0;
udc = NULL;
cleanup0:
if (xceiv)
@ -2788,7 +2878,7 @@ static int __exit omap_udc_remove(struct device *dev)
pullup_disable(udc);
if (udc->transceiver) {
put_device(udc->transceiver->dev);
udc->transceiver = 0;
udc->transceiver = NULL;
}
UDC_SYSCON1_REG = 0;
@ -2809,13 +2899,32 @@ static int __exit omap_udc_remove(struct device *dev)
return 0;
}
static int omap_udc_suspend(struct device *dev, pm_message_t state, u32 level)
/* suspend/resume/wakeup from sysfs (echo > power/state) or when the
* system is forced into deep sleep
*
* REVISIT we should probably reject suspend requests when there's a host
* session active, rather than disconnecting, at least on boards that can
* report VBUS irqs (UDC_DEVSTAT_REG.UDC_ATT). And in any case, we need to
* make host resumes and VBUS detection trigger OMAP wakeup events; that
* may involve talking to an external transceiver (e.g. isp1301).
*/
static int omap_udc_suspend(struct device *dev, pm_message_t message, u32 level)
{
if (level != 0)
return 0;
u32 devstat;
if (level != SUSPEND_POWER_DOWN)
return 0;
devstat = UDC_DEVSTAT_REG;
/* we're requesting 48 MHz clock if the pullup is enabled
* (== we're attached to the host) and we're not suspended,
* which would prevent entry to deep sleep...
*/
if ((devstat & UDC_ATT) != 0 && (devstat & UDC_SUS) == 0) {
WARN("session active; suspend requires disconnect\n");
omap_pullup(&udc->gadget, 0);
}
DBG("suspend, state %d\n", state);
omap_pullup(&udc->gadget, 0);
udc->gadget.dev.power.power_state = PMSG_SUSPEND;
udc->gadget.dev.parent->power.power_state = PMSG_SUSPEND;
return 0;
@ -2823,7 +2932,7 @@ static int omap_udc_suspend(struct device *dev, pm_message_t state, u32 level)
static int omap_udc_resume(struct device *dev, u32 level)
{
if (level != 0)
if (level != RESUME_POWER_ON)
return 0;
DBG("resume + wakeup/SRP\n");

View File

@ -20,6 +20,7 @@
#define UDC_CTRL_REG UDC_REG(0x0C) /* Endpoint control */
# define UDC_CLR_HALT (1 << 7)
# define UDC_SET_HALT (1 << 6)
# define UDC_CLRDATA_TOGGLE (1 << 3)
# define UDC_SET_FIFO_EN (1 << 2)
# define UDC_CLR_EP (1 << 1)
# define UDC_RESET_EP (1 << 0)
@ -99,6 +100,7 @@
/* DMA configuration registers: up to three channels in each direction. */
#define UDC_RXDMA_CFG_REG UDC_REG(0x40) /* 3 eps for RX DMA */
# define UDC_DMA_REQ (1 << 12)
#define UDC_TXDMA_CFG_REG UDC_REG(0x44) /* 3 eps for TX DMA */
#define UDC_DATA_DMA_REG UDC_REG(0x48) /* rx/tx fifo addr */
@ -162,6 +164,7 @@ struct omap_udc {
spinlock_t lock;
struct omap_ep ep[32];
u16 devstat;
u16 clr_halt;
struct otg_transceiver *transceiver;
struct list_head iso;
unsigned softconnect:1;
@ -171,7 +174,6 @@ struct omap_udc {
unsigned ep0_set_config:1;
unsigned ep0_reset_config:1;
unsigned ep0_setup:1;
struct completion *done;
};

View File

@ -1,6 +1,6 @@
/*
* linux/drivers/usb/gadget/pxa2xx_udc.c
* Intel PXA2xx and IXP4xx on-chip full speed USB device controllers
* Intel PXA25x and IXP4xx on-chip full speed USB device controllers
*
* Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker)
* Copyright (C) 2003 Robert Schwebel, Pengutronix
@ -63,7 +63,7 @@
/*
* This driver handles the USB Device Controller (UDC) in Intel's PXA 2xx
* This driver handles the USB Device Controller (UDC) in Intel's PXA 25x
* series processors. The UDC for the IXP 4xx series is very similar.
* There are fifteen endpoints, in addition to ep0.
*
@ -79,8 +79,8 @@
* pxa250 a0/a1 b0/b1/b2 sure act like they're still there.
*/
#define DRIVER_VERSION "14-Dec-2003"
#define DRIVER_DESC "PXA 2xx USB Device Controller driver"
#define DRIVER_VERSION "4-May-2005"
#define DRIVER_DESC "PXA 25x USB Device Controller driver"
static const char driver_name [] = "pxa2xx_udc";
@ -290,6 +290,7 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
static int pxa2xx_ep_disable (struct usb_ep *_ep)
{
struct pxa2xx_ep *ep;
unsigned long flags;
ep = container_of (_ep, struct pxa2xx_ep, ep);
if (!_ep || !ep->desc) {
@ -297,6 +298,8 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep)
_ep ? ep->ep.name : NULL);
return -EINVAL;
}
local_irq_save(flags);
nuke (ep, -ESHUTDOWN);
#ifdef USE_DMA
@ -313,6 +316,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep)
ep->desc = NULL;
ep->stopped = 1;
local_irq_restore(flags);
DBG(DBG_VERBOSE, "%s disabled\n", _ep->name);
return 0;
}
@ -971,10 +975,10 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
kick_dma(ep, req);
#endif
/* can the FIFO can satisfy the request immediately? */
} else if ((ep->bEndpointAddress & USB_DIR_IN) != 0
&& (*ep->reg_udccs & UDCCS_BI_TFS) != 0
&& write_fifo(ep, req)) {
req = NULL;
} else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0
&& write_fifo(ep, req))
req = NULL;
} else if ((*ep->reg_udccs & UDCCS_BO_RFS) != 0
&& read_fifo(ep, req)) {
req = NULL;
@ -1290,7 +1294,7 @@ udc_proc_read(char *page, char **start, off_t off, int count,
"%s version: %s\nGadget driver: %s\nHost %s\n\n",
driver_name, DRIVER_VERSION SIZE_STR DMASTR,
dev->driver ? dev->driver->driver.name : "(none)",
is_usb_connected() ? "full speed" : "disconnected");
is_vbus_present() ? "full speed" : "disconnected");
size -= t;
next += t;
@ -1339,7 +1343,7 @@ udc_proc_read(char *page, char **start, off_t off, int count,
next += t;
}
if (!is_usb_connected() || !dev->driver)
if (!is_vbus_present() || !dev->driver)
goto done;
t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
@ -1454,7 +1458,7 @@ static void udc_disable(struct pxa2xx_udc *dev)
UFNRH = UFNRH_SIM;
/* if hardware supports it, disconnect from usb */
make_usb_disappear();
pullup_off();
udc_clear_mask_UDCCR(UDCCR_UDE);
@ -1567,7 +1571,7 @@ static void udc_enable (struct pxa2xx_udc *dev)
UICR0 &= ~UICR0_IM0;
/* if hardware supports it, pullup D+ and wait for reset */
let_usb_appear();
pullup_on();
}
@ -2052,10 +2056,10 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r)
if (unlikely(udccr & UDCCR_SUSIR)) {
udc_ack_int_UDCCR(UDCCR_SUSIR);
handled = 1;
DBG(DBG_VERBOSE, "USB suspend%s\n", is_usb_connected()
DBG(DBG_VERBOSE, "USB suspend%s\n", is_vbus_present()
? "" : "+disconnect");
if (!is_usb_connected())
if (!is_vbus_present())
stop_activity(dev, dev->driver);
else if (dev->gadget.speed != USB_SPEED_UNKNOWN
&& dev->driver
@ -2073,7 +2077,7 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r)
if (dev->gadget.speed != USB_SPEED_UNKNOWN
&& dev->driver
&& dev->driver->resume
&& is_usb_connected())
&& is_vbus_present())
dev->driver->resume(&dev->gadget);
}
@ -2509,7 +2513,7 @@ static int __init pxa2xx_udc_probe(struct device *_dev)
udc_disable(dev);
udc_reinit(dev);
dev->vbus = is_usb_connected();
dev->vbus = is_vbus_present();
/* irq setup after old hardware state is cleaned up */
retval = request_irq(IRQ_USB, pxa2xx_udc_irq,
@ -2555,6 +2559,12 @@ lubbock_fail0:
return 0;
}
static void pxa2xx_udc_shutdown(struct device *_dev)
{
pullup_off();
}
static int __exit pxa2xx_udc_remove(struct device *_dev)
{
struct pxa2xx_udc *dev = dev_get_drvdata(_dev);
@ -2624,6 +2634,7 @@ static struct device_driver udc_driver = {
.name = "pxa2xx-udc",
.bus = &platform_bus_type,
.probe = pxa2xx_udc_probe,
.shutdown = pxa2xx_udc_shutdown,
.remove = __exit_p(pxa2xx_udc_remove),
.suspend = pxa2xx_udc_suspend,
.resume = pxa2xx_udc_resume,

View File

@ -177,23 +177,23 @@ struct pxa2xx_udc {
static struct pxa2xx_udc *the_controller;
/* one GPIO should be used to detect host disconnect */
static inline int is_usb_connected(void)
/* one GPIO should be used to detect VBUS from the host */
static inline int is_vbus_present(void)
{
if (!the_controller->mach->udc_is_connected)
return 1;
return the_controller->mach->udc_is_connected();
}
/* one GPIO should force the host to see this device (or not) */
static inline void make_usb_disappear(void)
/* one GPIO should control a D+ pullup, so host sees this device (or not) */
static inline void pullup_off(void)
{
if (!the_controller->mach->udc_command)
return;
the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
}
static inline void let_usb_appear(void)
static inline void pullup_on(void)
{
if (!the_controller->mach->udc_command)
return;

View File

@ -41,6 +41,7 @@
#undef RNDIS_PM
#undef RNDIS_WAKEUP
#undef VERBOSE
#include "rndis.h"
@ -60,7 +61,7 @@
} while (0)
static int rndis_debug = 0;
module_param (rndis_debug, bool, 0);
module_param (rndis_debug, int, 0);
MODULE_PARM_DESC (rndis_debug, "enable debugging");
#else
@ -78,22 +79,103 @@ static rndis_params rndis_per_dev_params [RNDIS_MAX_CONFIGS];
static const __le32 rndis_driver_version = __constant_cpu_to_le32 (1);
/* Function Prototypes */
static int rndis_init_response (int configNr, rndis_init_msg_type *buf);
static int rndis_query_response (int configNr, rndis_query_msg_type *buf);
static int rndis_set_response (int configNr, rndis_set_msg_type *buf);
static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf);
static int rndis_keepalive_response (int configNr,
rndis_keepalive_msg_type *buf);
static rndis_resp_t *rndis_add_response (int configNr, u32 length);
/* supported OIDs */
static const u32 oid_supported_list [] =
{
/* the general stuff */
OID_GEN_SUPPORTED_LIST,
OID_GEN_HARDWARE_STATUS,
OID_GEN_MEDIA_SUPPORTED,
OID_GEN_MEDIA_IN_USE,
OID_GEN_MAXIMUM_FRAME_SIZE,
OID_GEN_LINK_SPEED,
OID_GEN_TRANSMIT_BLOCK_SIZE,
OID_GEN_RECEIVE_BLOCK_SIZE,
OID_GEN_VENDOR_ID,
OID_GEN_VENDOR_DESCRIPTION,
OID_GEN_VENDOR_DRIVER_VERSION,
OID_GEN_CURRENT_PACKET_FILTER,
OID_GEN_MAXIMUM_TOTAL_SIZE,
OID_GEN_MEDIA_CONNECT_STATUS,
OID_GEN_PHYSICAL_MEDIUM,
#if 0
OID_GEN_RNDIS_CONFIG_PARAMETER,
#endif
/* the statistical stuff */
OID_GEN_XMIT_OK,
OID_GEN_RCV_OK,
OID_GEN_XMIT_ERROR,
OID_GEN_RCV_ERROR,
OID_GEN_RCV_NO_BUFFER,
#ifdef RNDIS_OPTIONAL_STATS
OID_GEN_DIRECTED_BYTES_XMIT,
OID_GEN_DIRECTED_FRAMES_XMIT,
OID_GEN_MULTICAST_BYTES_XMIT,
OID_GEN_MULTICAST_FRAMES_XMIT,
OID_GEN_BROADCAST_BYTES_XMIT,
OID_GEN_BROADCAST_FRAMES_XMIT,
OID_GEN_DIRECTED_BYTES_RCV,
OID_GEN_DIRECTED_FRAMES_RCV,
OID_GEN_MULTICAST_BYTES_RCV,
OID_GEN_MULTICAST_FRAMES_RCV,
OID_GEN_BROADCAST_BYTES_RCV,
OID_GEN_BROADCAST_FRAMES_RCV,
OID_GEN_RCV_CRC_ERROR,
OID_GEN_TRANSMIT_QUEUE_LENGTH,
#endif /* RNDIS_OPTIONAL_STATS */
/* mandatory 802.3 */
/* the general stuff */
OID_802_3_PERMANENT_ADDRESS,
OID_802_3_CURRENT_ADDRESS,
OID_802_3_MULTICAST_LIST,
OID_802_3_MAC_OPTIONS,
OID_802_3_MAXIMUM_LIST_SIZE,
/* the statistical stuff */
OID_802_3_RCV_ERROR_ALIGNMENT,
OID_802_3_XMIT_ONE_COLLISION,
OID_802_3_XMIT_MORE_COLLISIONS,
#ifdef RNDIS_OPTIONAL_STATS
OID_802_3_XMIT_DEFERRED,
OID_802_3_XMIT_MAX_COLLISIONS,
OID_802_3_RCV_OVERRUN,
OID_802_3_XMIT_UNDERRUN,
OID_802_3_XMIT_HEARTBEAT_FAILURE,
OID_802_3_XMIT_TIMES_CRS_LOST,
OID_802_3_XMIT_LATE_COLLISIONS,
#endif /* RNDIS_OPTIONAL_STATS */
#ifdef RNDIS_PM
/* PM and wakeup are mandatory for USB: */
/* power management */
OID_PNP_CAPABILITIES,
OID_PNP_QUERY_POWER,
OID_PNP_SET_POWER,
#ifdef RNDIS_WAKEUP
/* wake up host */
OID_PNP_ENABLE_WAKE_UP,
OID_PNP_ADD_WAKE_UP_PATTERN,
OID_PNP_REMOVE_WAKE_UP_PATTERN,
#endif /* RNDIS_WAKEUP */
#endif /* RNDIS_PM */
};
/* NDIS Functions */
static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
static int
gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
rndis_resp_t *r)
{
int retval = -ENOTSUPP;
u32 length = 0;
__le32 *tmp;
u32 length = 4; /* usually */
__le32 *outbuf;
int i, count;
rndis_query_cmplt_type *resp;
@ -101,7 +183,22 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
resp = (rndis_query_cmplt_type *) r->buf;
if (!resp) return -ENOMEM;
if (buf_len && rndis_debug > 1) {
DEBUG("query OID %08x value, len %d:\n", OID, buf_len);
for (i = 0; i < buf_len; i += 16) {
DEBUG ("%03d: %08x %08x %08x %08x\n", i,
le32_to_cpup((__le32 *)&buf[i]),
le32_to_cpup((__le32 *)&buf[i + 4]),
le32_to_cpup((__le32 *)&buf[i + 8]),
le32_to_cpup((__le32 *)&buf[i + 12]));
}
}
/* response goes here, right after the header */
outbuf = (__le32 *) &resp[1];
resp->InformationBufferOffset = __constant_cpu_to_le32 (16);
switch (OID) {
/* general oids (table 4-1) */
@ -111,42 +208,36 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__);
length = sizeof (oid_supported_list);
count = length / sizeof (u32);
tmp = (__le32 *) ((u8 *)resp + 24);
for (i = 0; i < count; i++)
tmp[i] = cpu_to_le32 (oid_supported_list[i]);
outbuf[i] = cpu_to_le32 (oid_supported_list[i]);
retval = 0;
break;
/* mandatory */
case OID_GEN_HARDWARE_STATUS:
DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__);
length = 4;
/* Bogus question!
* Hardware must be ready to receive high level protocols.
* BTW:
* reddite ergo quae sunt Caesaris Caesari
* et quae sunt Dei Deo!
*/
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
/* mandatory */
case OID_GEN_MEDIA_SUPPORTED:
DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
length = 4;
*((__le32 *) resp + 6) = cpu_to_le32 (
rndis_per_dev_params [configNr].medium);
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
retval = 0;
break;
/* mandatory */
case OID_GEN_MEDIA_IN_USE:
DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
length = 4;
/* one medium, one transport... (maybe you do it better) */
*((__le32 *) resp + 6) = cpu_to_le32 (
rndis_per_dev_params [configNr].medium);
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
retval = 0;
break;
@ -154,25 +245,21 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
case OID_GEN_MAXIMUM_FRAME_SIZE:
DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
length = 4;
*((__le32 *) resp + 6) = cpu_to_le32 (
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
/* mandatory */
case OID_GEN_LINK_SPEED:
// DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
length = 4;
if (rndis_debug > 1)
DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].media_state
== NDIS_MEDIA_STATE_DISCONNECTED)
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
== NDIS_MEDIA_STATE_DISCONNECTED)
*outbuf = __constant_cpu_to_le32 (0);
else
*((__le32 *) resp + 6) = cpu_to_le32 (
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].speed);
retval = 0;
break;
@ -181,8 +268,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
case OID_GEN_TRANSMIT_BLOCK_SIZE:
DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
length = 4;
*((__le32 *) resp + 6) = cpu_to_le32 (
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
retval = 0;
}
@ -192,8 +278,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
case OID_GEN_RECEIVE_BLOCK_SIZE:
DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
length = 4;
*((__le32 *) resp + 6) = cpu_to_le32 (
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
retval = 0;
}
@ -202,8 +287,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
/* mandatory */
case OID_GEN_VENDOR_ID:
DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
length = 4;
*((__le32 *) resp + 6) = cpu_to_le32 (
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].vendorID);
retval = 0;
break;
@ -212,51 +296,44 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
case OID_GEN_VENDOR_DESCRIPTION:
DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__);
length = strlen (rndis_per_dev_params [configNr].vendorDescr);
memcpy ((u8 *) resp + 24,
memcpy (outbuf,
rndis_per_dev_params [configNr].vendorDescr, length);
retval = 0;
break;
case OID_GEN_VENDOR_DRIVER_VERSION:
DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
length = 4;
/* Created as LE */
*((__le32 *) resp + 6) = rndis_driver_version;
*outbuf = rndis_driver_version;
retval = 0;
break;
/* mandatory */
case OID_GEN_CURRENT_PACKET_FILTER:
DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
length = 4;
*((__le32 *) resp + 6) = cpu_to_le32 (
rndis_per_dev_params[configNr].filter);
*outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter);
retval = 0;
break;
/* mandatory */
case OID_GEN_MAXIMUM_TOTAL_SIZE:
DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__);
length = 4;
*((__le32 *) resp + 6) = __constant_cpu_to_le32(
RNDIS_MAX_TOTAL_SIZE);
*outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
retval = 0;
break;
/* mandatory */
case OID_GEN_MEDIA_CONNECT_STATUS:
DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
length = 4;
*((__le32 *) resp + 6) = cpu_to_le32 (
rndis_per_dev_params [configNr]
if (rndis_debug > 1)
DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.media_state);
retval = 0;
break;
case OID_GEN_PHYSICAL_MEDIUM:
DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
length = 4;
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
@ -266,8 +343,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
*/
case OID_GEN_MAC_OPTIONS: /* from WinME */
DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
length = 4;
*((__le32 *) resp + 6) = __constant_cpu_to_le32(
*outbuf = __constant_cpu_to_le32(
NDIS_MAC_OPTION_RECEIVE_SERIALIZED
| NDIS_MAC_OPTION_FULL_DUPLEX);
retval = 0;
@ -277,62 +353,49 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
/* mandatory */
case OID_GEN_XMIT_OK:
DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
if (rndis_debug > 1)
DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
length = 4;
*((__le32 *) resp + 6) = cpu_to_le32 (
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].stats->tx_packets -
rndis_per_dev_params [configNr].stats->tx_errors -
rndis_per_dev_params [configNr].stats->tx_dropped);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
/* mandatory */
case OID_GEN_RCV_OK:
DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
if (rndis_debug > 1)
DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
length = 4;
*((__le32 *) resp + 6) = cpu_to_le32 (
*outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].stats->rx_packets -
rndis_per_dev_params [configNr].stats->rx_errors -
rndis_per_dev_params [configNr].stats->rx_dropped);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
/* mandatory */
case OID_GEN_XMIT_ERROR:
DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
if (rndis_debug > 1)
DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
length = 4;
*((__le32 *) resp + 6) = cpu_to_le32 (
rndis_per_dev_params [configNr]
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_errors);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
/* mandatory */
case OID_GEN_RCV_ERROR:
DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
if (rndis_debug > 1)
DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*((__le32 *) resp + 6) = cpu_to_le32 (
rndis_per_dev_params [configNr]
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_errors);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
@ -340,13 +403,9 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
case OID_GEN_RCV_NO_BUFFER:
DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*((__le32 *) resp + 6) = cpu_to_le32 (
rndis_per_dev_params [configNr]
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_dropped);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
@ -359,8 +418,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
* divided by weight of Alpha Centauri
*/
if (rndis_per_dev_params [configNr].stats) {
length = 4;
*((__le32 *) resp + 6) = cpu_to_le32 (
*outbuf = cpu_to_le32 (
(rndis_per_dev_params [configNr]
.stats->tx_packets -
rndis_per_dev_params [configNr]
@ -369,9 +427,6 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
.stats->tx_dropped)
* 123);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
@ -379,8 +434,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__);
/* dito */
if (rndis_per_dev_params [configNr].stats) {
length = 4;
*((__le32 *) resp + 6) = cpu_to_le32 (
*outbuf = cpu_to_le32 (
(rndis_per_dev_params [configNr]
.stats->tx_packets -
rndis_per_dev_params [configNr]
@ -389,144 +443,105 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
.stats->tx_dropped)
/ 123);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
case OID_GEN_MULTICAST_BYTES_XMIT:
DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*((__le32 *) resp + 6) = cpu_to_le32 (
rndis_per_dev_params [configNr]
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast*1234);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
case OID_GEN_MULTICAST_FRAMES_XMIT:
DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*((__le32 *) resp + 6) = cpu_to_le32 (
rndis_per_dev_params [configNr]
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
case OID_GEN_BROADCAST_BYTES_XMIT:
DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*((__le32 *) resp + 6) = cpu_to_le32 (
rndis_per_dev_params [configNr]
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_packets/42*255);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
case OID_GEN_BROADCAST_FRAMES_XMIT:
DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*((__le32 *) resp + 6) = cpu_to_le32 (
rndis_per_dev_params [configNr]
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_packets/42);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
case OID_GEN_DIRECTED_BYTES_RCV:
DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
case OID_GEN_DIRECTED_FRAMES_RCV:
DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
case OID_GEN_MULTICAST_BYTES_RCV:
DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*((__le32 *) resp + 6) = cpu_to_le32 (
rndis_per_dev_params [configNr]
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast * 1111);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
case OID_GEN_MULTICAST_FRAMES_RCV:
DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*((__le32 *) resp + 6) = cpu_to_le32 (
rndis_per_dev_params [configNr]
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
case OID_GEN_BROADCAST_BYTES_RCV:
DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*((__le32 *) resp + 6) = cpu_to_le32 (
rndis_per_dev_params [configNr]
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_packets/42*255);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
case OID_GEN_BROADCAST_FRAMES_RCV:
DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*((__le32 *) resp + 6) = cpu_to_le32 (
rndis_per_dev_params [configNr]
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_packets/42);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
case OID_GEN_RCV_CRC_ERROR:
DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
*((__le32 *) resp + 6) = cpu_to_le32 (
rndis_per_dev_params [configNr]
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_crc_errors);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
case OID_GEN_TRANSMIT_QUEUE_LENGTH:
DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
#endif /* RNDIS_OPTIONAL_STATS */
@ -538,13 +553,10 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
length = ETH_ALEN;
memcpy ((u8 *) resp + 24,
memcpy (outbuf,
rndis_per_dev_params [configNr].host_mac,
length);
retval = 0;
} else {
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
retval = 0;
}
break;
@ -553,7 +565,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
length = ETH_ALEN;
memcpy ((u8 *) resp + 24,
memcpy (outbuf,
rndis_per_dev_params [configNr].host_mac,
length);
retval = 0;
@ -563,18 +575,16 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
/* mandatory */
case OID_802_3_MULTICAST_LIST:
DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
length = 4;
/* Multicast base address only */
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0xE0000000);
*outbuf = __constant_cpu_to_le32 (0xE0000000);
retval = 0;
break;
/* mandatory */
case OID_802_3_MAXIMUM_LIST_SIZE:
DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
length = 4;
/* Multicast base address only */
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (1);
*outbuf = __constant_cpu_to_le32 (1);
retval = 0;
break;
@ -587,11 +597,8 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
/* mandatory */
case OID_802_3_RCV_ERROR_ALIGNMENT:
DEBUG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats)
{
length = 4;
*((__le32 *) resp + 6) = cpu_to_le32 (
rndis_per_dev_params [configNr]
if (rndis_per_dev_params [configNr].stats) {
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_frame_errors);
retval = 0;
}
@ -600,16 +607,14 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
/* mandatory */
case OID_802_3_XMIT_ONE_COLLISION:
DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
length = 4;
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
/* mandatory */
case OID_802_3_XMIT_MORE_COLLISIONS:
DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
length = 4;
*((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
*outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
@ -655,27 +660,18 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
case OID_PNP_CAPABILITIES:
DEBUG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__);
/* just PM, and remote wakeup on link status change
* (not magic packet or pattern match)
*/
/* for now, no wakeup capabilities */
length = sizeof (struct NDIS_PNP_CAPABILITIES);
memset (resp, 0, length);
{
struct NDIS_PNP_CAPABILITIES *caps = (void *) resp;
caps->Flags = NDIS_DEVICE_WAKE_UP_ENABLE;
caps->WakeUpCapabilities.MinLinkChangeWakeUp
= NdisDeviceStateD3;
/* FIXME then use usb_gadget_wakeup(), and
* set USB_CONFIG_ATT_WAKEUP in config desc
*/
}
memset(outbuf, 0, length);
retval = 0;
break;
case OID_PNP_QUERY_POWER:
DEBUG("%s: OID_PNP_QUERY_POWER\n", __FUNCTION__);
/* sure, handle any power state that maps to USB suspend */
DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__,
le32_to_cpup((__le32 *) buf) - 1);
/* only suspend is a real power state, and
* it can't be entered by OID_PNP_SET_POWER...
*/
length = 0;
retval = 0;
break;
#endif
@ -684,11 +680,12 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
printk (KERN_WARNING "%s: query unknown OID 0x%08X\n",
__FUNCTION__, OID);
}
if (retval < 0)
length = 0;
resp->InformationBufferOffset = __constant_cpu_to_le32 (16);
resp->InformationBufferLength = cpu_to_le32 (length);
resp->MessageLength = cpu_to_le32 (24 + length);
r->length = 24 + length;
r->length = length + sizeof *resp;
resp->MessageLength = cpu_to_le32 (r->length);
return retval;
}
@ -705,45 +702,40 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
if (!resp)
return -ENOMEM;
DEBUG("set OID %08x value, len %d:\n", OID, buf_len);
for (i = 0; i < buf_len; i += 16) {
DEBUG ("%03d: "
" %02x %02x %02x %02x"
" %02x %02x %02x %02x"
" %02x %02x %02x %02x"
" %02x %02x %02x %02x"
"\n",
i,
buf[i], buf [i+1],
buf[i+2], buf[i+3],
buf[i+4], buf [i+5],
buf[i+6], buf[i+7],
buf[i+8], buf [i+9],
buf[i+10], buf[i+11],
buf[i+12], buf [i+13],
buf[i+14], buf[i+15]);
if (buf_len && rndis_debug > 1) {
DEBUG("set OID %08x value, len %d:\n", OID, buf_len);
for (i = 0; i < buf_len; i += 16) {
DEBUG ("%03d: %08x %08x %08x %08x\n", i,
le32_to_cpup((__le32 *)&buf[i]),
le32_to_cpup((__le32 *)&buf[i + 4]),
le32_to_cpup((__le32 *)&buf[i + 8]),
le32_to_cpup((__le32 *)&buf[i + 12]));
}
}
params = &rndis_per_dev_params [configNr];
switch (OID) {
case OID_GEN_CURRENT_PACKET_FILTER:
params = &rndis_per_dev_params [configNr];
retval = 0;
/* FIXME use these NDIS_PACKET_TYPE_* bitflags to
* set the cdc_filter; it's not RNDIS-specific
/* these NDIS_PACKET_TYPE_* bitflags are shared with
* cdc_filter; it's not RNDIS-specific
* NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
* PROMISCUOUS, DIRECTED,
* MULTICAST, ALL_MULTICAST, BROADCAST
*/
params->filter = le32_to_cpup((__le32 *)buf);
*params->filter = (u16) le32_to_cpup((__le32 *)buf);
DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
__FUNCTION__, params->filter);
__FUNCTION__, *params->filter);
/* this call has a significant side effect: it's
* what makes the packet flow start and stop, like
* activating the CDC Ethernet altsetting.
*/
if (params->filter) {
#ifdef RNDIS_PM
update_linkstate:
#endif
retval = 0;
if (*params->filter) {
params->state = RNDIS_DATA_INITIALIZED;
netif_carrier_on(params->dev);
if (netif_running(params->dev))
@ -776,21 +768,34 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
#ifdef RNDIS_PM
case OID_PNP_SET_POWER:
DEBUG ("OID_PNP_SET_POWER\n");
/* sure, handle any power state that maps to USB suspend */
retval = 0;
/* The only real power state is USB suspend, and RNDIS requests
* can't enter it; this one isn't really about power. After
* resuming, Windows forces a reset, and then SET_POWER D0.
* FIXME ... then things go batty; Windows wedges itself.
*/
i = le32_to_cpup((__force __le32 *)buf);
DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1);
switch (i) {
case NdisDeviceStateD0:
*params->filter = params->saved_filter;
goto update_linkstate;
case NdisDeviceStateD3:
case NdisDeviceStateD2:
case NdisDeviceStateD1:
params->saved_filter = *params->filter;
retval = 0;
break;
}
break;
case OID_PNP_ENABLE_WAKE_UP:
/* always-connected ... */
DEBUG ("OID_PNP_ENABLE_WAKE_UP\n");
retval = 0;
break;
// no PM resume patterns supported (specified where?)
// so OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN always fails
#ifdef RNDIS_WAKEUP
// no wakeup support advertised, so wakeup OIDs always fail:
// - OID_PNP_ENABLE_WAKE_UP
// - OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN
#endif
#endif /* RNDIS_PM */
default:
printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n",
__FUNCTION__, OID, buf_len);
@ -811,13 +816,10 @@ static int rndis_init_response (int configNr, rndis_init_msg_type *buf)
if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
r = rndis_add_response (configNr, sizeof (rndis_init_cmplt_type));
if (!r) return -ENOMEM;
if (!r)
return -ENOMEM;
resp = (rndis_init_cmplt_type *) r->buf;
if (!resp) return -ENOMEM;
resp->MessageType = __constant_cpu_to_le32 (
REMOTE_NDIS_INITIALIZE_CMPLT);
resp->MessageLength = __constant_cpu_to_le32 (52);
@ -857,20 +859,22 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf)
* oid_supported_list is the largest answer
*/
r = rndis_add_response (configNr, sizeof (oid_supported_list));
if (!r) return -ENOMEM;
if (!r)
return -ENOMEM;
resp = (rndis_query_cmplt_type *) r->buf;
if (!resp) return -ENOMEM;
resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_QUERY_CMPLT);
resp->MessageLength = __constant_cpu_to_le32 (24);
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID), r)) {
if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID),
le32_to_cpu(buf->InformationBufferOffset)
+ 8 + (u8 *) buf,
le32_to_cpu(buf->InformationBufferLength),
r)) {
/* OID not supported */
resp->Status = __constant_cpu_to_le32 (
RNDIS_STATUS_NOT_SUPPORTED);
resp->MessageLength = __constant_cpu_to_le32 (sizeof *resp);
resp->InformationBufferLength = __constant_cpu_to_le32 (0);
resp->InformationBufferOffset = __constant_cpu_to_le32 (0);
} else
@ -889,10 +893,9 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
rndis_resp_t *r;
r = rndis_add_response (configNr, sizeof (rndis_set_cmplt_type));
if (!r) return -ENOMEM;
if (!r)
return -ENOMEM;
resp = (rndis_set_cmplt_type *) r->buf;
if (!resp) return -ENOMEM;
BufLength = le32_to_cpu (buf->InformationBufferLength);
BufOffset = le32_to_cpu (buf->InformationBufferOffset);
@ -930,10 +933,9 @@ static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf)
rndis_resp_t *r;
r = rndis_add_response (configNr, sizeof (rndis_reset_cmplt_type));
if (!r) return -ENOMEM;
if (!r)
return -ENOMEM;
resp = (rndis_reset_cmplt_type *) r->buf;
if (!resp) return -ENOMEM;
resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_RESET_CMPLT);
resp->MessageLength = __constant_cpu_to_le32 (16);
@ -957,8 +959,9 @@ static int rndis_keepalive_response (int configNr,
/* host "should" check only in RNDIS_DATA_INITIALIZED state */
r = rndis_add_response (configNr, sizeof (rndis_keepalive_cmplt_type));
if (!r)
return -ENOMEM;
resp = (rndis_keepalive_cmplt_type *) r->buf;
if (!resp) return -ENOMEM;
resp->MessageType = __constant_cpu_to_le32 (
REMOTE_NDIS_KEEPALIVE_CMPLT);
@ -987,10 +990,9 @@ static int rndis_indicate_status_msg (int configNr, u32 status)
r = rndis_add_response (configNr,
sizeof (rndis_indicate_status_msg_type));
if (!r) return -ENOMEM;
if (!r)
return -ENOMEM;
resp = (rndis_indicate_status_msg_type *) r->buf;
if (!resp) return -ENOMEM;
resp->MessageType = __constant_cpu_to_le32 (
REMOTE_NDIS_INDICATE_STATUS_MSG);
@ -1021,6 +1023,21 @@ int rndis_signal_disconnect (int configNr)
RNDIS_STATUS_MEDIA_DISCONNECT);
}
void rndis_uninit (int configNr)
{
u8 *buf;
u32 length;
if (configNr >= RNDIS_MAX_CONFIGS)
return;
rndis_per_dev_params [configNr].used = 0;
rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED;
/* drain the response queue */
while ((buf = rndis_get_next_response(configNr, &length)))
rndis_free_response(configNr, buf);
}
void rndis_set_host_mac (int configNr, const u8 *addr)
{
rndis_per_dev_params [configNr].host_mac = addr;
@ -1046,9 +1063,13 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
return -ENOTSUPP;
params = &rndis_per_dev_params [configNr];
/* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for
* rx/tx statistics and link status, in addition to KEEPALIVE traffic
* and normal HC level polling to see if there's any IN traffic.
*/
/* For USB: responses may take up to 10 seconds */
switch (MsgType)
{
switch (MsgType) {
case REMOTE_NDIS_INITIALIZE_MSG:
DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n",
__FUNCTION__ );
@ -1082,10 +1103,9 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
case REMOTE_NDIS_KEEPALIVE_MSG:
/* For USB: host does this every 5 seconds */
#ifdef VERBOSE
DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n",
__FUNCTION__ );
#endif
if (rndis_debug > 1)
DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n",
__FUNCTION__ );
return rndis_keepalive_response (configNr,
(rndis_keepalive_msg_type *)
buf);
@ -1152,7 +1172,8 @@ void rndis_deregister (int configNr)
}
int rndis_set_param_dev (u8 configNr, struct net_device *dev,
struct net_device_stats *stats)
struct net_device_stats *stats,
u16 *cdc_filter)
{
DEBUG("%s:\n", __FUNCTION__ );
if (!dev || !stats) return -1;
@ -1160,6 +1181,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev,
rndis_per_dev_params [configNr].dev = dev;
rndis_per_dev_params [configNr].stats = stats;
rndis_per_dev_params [configNr].filter = cdc_filter;
return 0;
}
@ -1178,7 +1200,7 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr)
int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed)
{
DEBUG("%s:\n", __FUNCTION__ );
DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed);
if (configNr >= RNDIS_MAX_CONFIGS) return -1;
rndis_per_dev_params [configNr].medium = medium;
@ -1242,6 +1264,7 @@ static rndis_resp_t *rndis_add_response (int configNr, u32 length)
{
rndis_resp_t *r;
/* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */
r = kmalloc (sizeof (rndis_resp_t) + length, GFP_ATOMIC);
if (!r) return NULL;

View File

@ -69,90 +69,6 @@
#define OID_PNP_ENABLE_WAKE_UP 0xFD010106
/* supported OIDs */
static const u32 oid_supported_list [] =
{
/* the general stuff */
OID_GEN_SUPPORTED_LIST,
OID_GEN_HARDWARE_STATUS,
OID_GEN_MEDIA_SUPPORTED,
OID_GEN_MEDIA_IN_USE,
OID_GEN_MAXIMUM_FRAME_SIZE,
OID_GEN_LINK_SPEED,
OID_GEN_TRANSMIT_BLOCK_SIZE,
OID_GEN_RECEIVE_BLOCK_SIZE,
OID_GEN_VENDOR_ID,
OID_GEN_VENDOR_DESCRIPTION,
OID_GEN_VENDOR_DRIVER_VERSION,
OID_GEN_CURRENT_PACKET_FILTER,
OID_GEN_MAXIMUM_TOTAL_SIZE,
OID_GEN_MEDIA_CONNECT_STATUS,
OID_GEN_PHYSICAL_MEDIUM,
#if 0
OID_GEN_RNDIS_CONFIG_PARAMETER,
#endif
/* the statistical stuff */
OID_GEN_XMIT_OK,
OID_GEN_RCV_OK,
OID_GEN_XMIT_ERROR,
OID_GEN_RCV_ERROR,
OID_GEN_RCV_NO_BUFFER,
#ifdef RNDIS_OPTIONAL_STATS
OID_GEN_DIRECTED_BYTES_XMIT,
OID_GEN_DIRECTED_FRAMES_XMIT,
OID_GEN_MULTICAST_BYTES_XMIT,
OID_GEN_MULTICAST_FRAMES_XMIT,
OID_GEN_BROADCAST_BYTES_XMIT,
OID_GEN_BROADCAST_FRAMES_XMIT,
OID_GEN_DIRECTED_BYTES_RCV,
OID_GEN_DIRECTED_FRAMES_RCV,
OID_GEN_MULTICAST_BYTES_RCV,
OID_GEN_MULTICAST_FRAMES_RCV,
OID_GEN_BROADCAST_BYTES_RCV,
OID_GEN_BROADCAST_FRAMES_RCV,
OID_GEN_RCV_CRC_ERROR,
OID_GEN_TRANSMIT_QUEUE_LENGTH,
#endif /* RNDIS_OPTIONAL_STATS */
/* mandatory 802.3 */
/* the general stuff */
OID_802_3_PERMANENT_ADDRESS,
OID_802_3_CURRENT_ADDRESS,
OID_802_3_MULTICAST_LIST,
OID_802_3_MAC_OPTIONS,
OID_802_3_MAXIMUM_LIST_SIZE,
/* the statistical stuff */
OID_802_3_RCV_ERROR_ALIGNMENT,
OID_802_3_XMIT_ONE_COLLISION,
OID_802_3_XMIT_MORE_COLLISIONS,
#ifdef RNDIS_OPTIONAL_STATS
OID_802_3_XMIT_DEFERRED,
OID_802_3_XMIT_MAX_COLLISIONS,
OID_802_3_RCV_OVERRUN,
OID_802_3_XMIT_UNDERRUN,
OID_802_3_XMIT_HEARTBEAT_FAILURE,
OID_802_3_XMIT_TIMES_CRS_LOST,
OID_802_3_XMIT_LATE_COLLISIONS,
#endif /* RNDIS_OPTIONAL_STATS */
#ifdef RNDIS_PM
/* PM and wakeup are mandatory for USB: */
/* power management */
OID_PNP_CAPABILITIES,
OID_PNP_QUERY_POWER,
OID_PNP_SET_POWER,
/* wake up host */
OID_PNP_ENABLE_WAKE_UP,
OID_PNP_ADD_WAKE_UP_PATTERN,
OID_PNP_REMOVE_WAKE_UP_PATTERN,
#endif
};
typedef struct rndis_init_msg_type
{
__le32 MessageType;
@ -309,15 +225,18 @@ typedef struct rndis_resp_t
typedef struct rndis_params
{
u8 confignr;
int used;
u8 used;
u16 saved_filter;
enum rndis_state state;
u32 filter;
u32 medium;
u32 speed;
u32 media_state;
const u8 *host_mac;
u16 *filter;
struct net_device *dev;
struct net_device_stats *stats;
u32 vendorID;
const char *vendorDescr;
int (*ack) (struct net_device *);
@ -329,7 +248,8 @@ int rndis_msg_parser (u8 configNr, u8 *buf);
int rndis_register (int (*rndis_control_ack) (struct net_device *));
void rndis_deregister (int configNr);
int rndis_set_param_dev (u8 configNr, struct net_device *dev,
struct net_device_stats *stats);
struct net_device_stats *stats,
u16 *cdc_filter);
int rndis_set_param_vendor (u8 configNr, u32 vendorID,
const char *vendorDescr);
int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
@ -338,6 +258,7 @@ int rndis_rm_hdr (struct sk_buff *skb);
u8 *rndis_get_next_response (int configNr, u32 *length);
void rndis_free_response (int configNr, u8 *buf);
void rndis_uninit (int configNr);
int rndis_signal_connect (int configNr);
int rndis_signal_disconnect (int configNr);
int rndis_state (int configNr);

View File

@ -300,18 +300,18 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
u8 type, unsigned int index, int is_otg);
static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
int kmalloc_flags);
unsigned kmalloc_flags);
static void gs_free_req(struct usb_ep *ep, struct usb_request *req);
static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len,
int kmalloc_flags);
unsigned kmalloc_flags);
static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req);
static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags);
static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags);
static void gs_free_ports(struct gs_dev *dev);
/* circular buffer */
static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags);
static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags);
static void gs_buf_free(struct gs_buf *gb);
static void gs_buf_clear(struct gs_buf *gb);
static unsigned int gs_buf_data_avail(struct gs_buf *gb);
@ -1607,9 +1607,9 @@ static int gs_setup(struct usb_gadget *gadget,
int ret = -EOPNOTSUPP;
struct gs_dev *dev = get_gadget_data(gadget);
struct usb_request *req = dev->dev_ctrl_req;
u16 wIndex = ctrl->wIndex;
u16 wValue = ctrl->wValue;
u16 wLength = ctrl->wLength;
u16 wIndex = le16_to_cpu(ctrl->wIndex);
u16 wValue = le16_to_cpu(ctrl->wValue);
u16 wLength = le16_to_cpu(ctrl->wLength);
switch (ctrl->bRequestType & USB_TYPE_MASK) {
case USB_TYPE_STANDARD:
@ -1651,9 +1651,9 @@ static int gs_setup_standard(struct usb_gadget *gadget,
int ret = -EOPNOTSUPP;
struct gs_dev *dev = get_gadget_data(gadget);
struct usb_request *req = dev->dev_ctrl_req;
u16 wIndex = ctrl->wIndex;
u16 wValue = ctrl->wValue;
u16 wLength = ctrl->wLength;
u16 wIndex = le16_to_cpu(ctrl->wIndex);
u16 wValue = le16_to_cpu(ctrl->wValue);
u16 wLength = le16_to_cpu(ctrl->wLength);
switch (ctrl->bRequest) {
case USB_REQ_GET_DESCRIPTOR:
@ -1782,9 +1782,9 @@ static int gs_setup_class(struct usb_gadget *gadget,
struct gs_dev *dev = get_gadget_data(gadget);
struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */
struct usb_request *req = dev->dev_ctrl_req;
u16 wIndex = ctrl->wIndex;
u16 wValue = ctrl->wValue;
u16 wLength = ctrl->wLength;
u16 wIndex = le16_to_cpu(ctrl->wIndex);
u16 wValue = le16_to_cpu(ctrl->wValue);
u16 wLength = le16_to_cpu(ctrl->wLength);
switch (ctrl->bRequest) {
case USB_CDC_REQ_SET_LINE_CODING:
@ -2119,7 +2119,8 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
* Allocate a usb_request and its buffer. Returns a pointer to the
* usb_request or NULL if there is an error.
*/
static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, int kmalloc_flags)
static struct usb_request *
gs_alloc_req(struct usb_ep *ep, unsigned int len, unsigned kmalloc_flags)
{
struct usb_request *req;
@ -2159,7 +2160,8 @@ static void gs_free_req(struct usb_ep *ep, struct usb_request *req)
* Allocates a request and its buffer, using the given
* endpoint, buffer len, and kmalloc flags.
*/
static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len, int kmalloc_flags)
static struct gs_req_entry *
gs_alloc_req_entry(struct usb_ep *ep, unsigned len, unsigned kmalloc_flags)
{
struct gs_req_entry *req;
@ -2200,7 +2202,7 @@ static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req)
*
* The device lock is normally held when calling this function.
*/
static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags)
static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags)
{
int i;
struct gs_port *port;
@ -2282,7 +2284,7 @@ static void gs_free_ports(struct gs_dev *dev)
*
* Allocate a circular buffer and all associated memory.
*/
static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags)
static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags)
{
struct gs_buf *gb;

View File

@ -919,9 +919,9 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
struct zero_dev *dev = get_gadget_data (gadget);
struct usb_request *req = dev->req;
int value = -EOPNOTSUPP;
u16 w_index = ctrl->wIndex;
u16 w_value = ctrl->wValue;
u16 w_length = ctrl->wLength;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
/* usually this stores reply data in the pre-allocated ep0 buffer,
* but config change events will reconfigure hardware.

View File

@ -49,6 +49,19 @@ config USB_EHCI_ROOT_HUB_TT
This supports the EHCI implementation from TransDimension Inc.
config USB_ISP116X_HCD
tristate "ISP116X HCD support"
depends on USB
default N
---help---
The ISP1160 and ISP1161 chips are USB host controllers. Enable this
option if your board has this chip. If unsure, say N.
This driver does not support isochronous transfers.
To compile this driver as a module, choose M here: the
module will be called isp116x-hcd.
config USB_OHCI_HCD
tristate "OHCI HCD support"
depends on USB && USB_ARCH_HAS_OHCI

View File

@ -4,6 +4,7 @@
#
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o

View File

@ -254,7 +254,7 @@ dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
}
return scnprintf (buf, len,
"%s%sport %d status %06x%s%s sig=%s %s%s%s%s%s%s%s%s%s",
"%s%sport %d status %06x%s%s sig=%s%s%s%s%s%s%s%s%s%s",
label, label [0] ? " " : "", port, status,
(status & PORT_POWER) ? " POWER" : "",
(status & PORT_OWNER) ? " OWNER" : "",
@ -644,9 +644,11 @@ show_registers (struct class_device *class_dev, char *buf)
if (bus->controller->power.power_state) {
size = scnprintf (next, size,
"bus %s, device %s (driver " DRIVER_VERSION ")\n"
"%s\n"
"SUSPENDED (no register access)\n",
hcd->self.controller->bus->name,
hcd->self.controller->bus_id);
hcd->self.controller->bus_id,
hcd->product_desc);
goto done;
}
@ -654,13 +656,53 @@ show_registers (struct class_device *class_dev, char *buf)
i = HC_VERSION(readl (&ehci->caps->hc_capbase));
temp = scnprintf (next, size,
"bus %s, device %s (driver " DRIVER_VERSION ")\n"
"%s\n"
"EHCI %x.%02x, hcd state %d\n",
hcd->self.controller->bus->name,
hcd->self.controller->bus_id,
hcd->product_desc,
i >> 8, i & 0x0ff, hcd->state);
size -= temp;
next += temp;
#ifdef CONFIG_PCI
/* EHCI 0.96 and later may have "extended capabilities" */
if (hcd->self.controller->bus == &pci_bus_type) {
struct pci_dev *pdev;
u32 offset, cap, cap2;
unsigned count = 256/4;
pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
offset = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
while (offset && count--) {
pci_read_config_dword (pdev, offset, &cap);
switch (cap & 0xff) {
case 1:
temp = scnprintf (next, size,
"ownership %08x%s%s\n", cap,
(cap & (1 << 24)) ? " linux" : "",
(cap & (1 << 16)) ? " firmware" : "");
size -= temp;
next += temp;
offset += 4;
pci_read_config_dword (pdev, offset, &cap2);
temp = scnprintf (next, size,
"SMI sts/enable 0x%08x\n", cap2);
size -= temp;
next += temp;
break;
case 0: /* illegal reserved capability */
cap = 0;
/* FALLTHROUGH */
default: /* unknown */
break;
}
temp = (cap >> 8) & 0xff;
}
}
#endif
// FIXME interpret both types of params
i = readl (&ehci->caps->hcs_params);
temp = scnprintf (next, size, "structural params 0x%08x\n", i);
@ -696,12 +738,19 @@ show_registers (struct class_device *class_dev, char *buf)
size -= temp;
next += temp;
for (i = 0; i < HCS_N_PORTS (ehci->hcs_params); i++) {
temp = dbg_port_buf (scratch, sizeof scratch, label, i + 1,
readl (&ehci->regs->port_status [i]));
for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
temp = dbg_port_buf (scratch, sizeof scratch, label, i,
readl (&ehci->regs->port_status [i - 1]));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
temp = scnprintf (next, size,
" debug control %08x\n",
readl (&ehci->debug->control));
size -= temp;
next += temp;
}
}
if (ehci->reclaim) {

View File

@ -304,30 +304,31 @@ static void ehci_watchdog (unsigned long param)
*/
static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
{
struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
/* always say Linux will own the hardware */
pci_write_config_byte(pdev, where + 3, 1);
/* maybe wait a while for BIOS to respond */
if (cap & (1 << 16)) {
int msec = 5000;
struct pci_dev *pdev =
to_pci_dev(ehci_to_hcd(ehci)->self.controller);
/* request handoff to OS */
cap |= 1 << 24;
pci_write_config_dword(pdev, where, cap);
/* and wait a while for it to happen */
do {
msleep(10);
msec -= 10;
pci_read_config_dword(pdev, where, &cap);
} while ((cap & (1 << 16)) && msec);
if (cap & (1 << 16)) {
ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n",
ehci_err(ehci, "BIOS handoff failed (%d, %08x)\n",
where, cap);
// some BIOS versions seem buggy...
// return 1;
ehci_warn (ehci, "continuing after BIOS bug...\n");
return 0;
}
ehci_dbg (ehci, "BIOS handoff succeeded\n");
/* disable all SMIs, and clear "BIOS owns" flag */
pci_write_config_dword(pdev, where + 4, 0);
pci_write_config_byte(pdev, where + 2, 0);
} else
ehci_dbg(ehci, "BIOS handoff succeeded\n");
}
return 0;
}
@ -492,8 +493,6 @@ static int ehci_start (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 temp;
struct usb_device *udev;
struct usb_bus *bus;
int retval;
u32 hcc_params;
u8 sbrn = 0;
@ -588,8 +587,8 @@ static int ehci_start (struct usb_hcd *hcd)
writel (0, &ehci->regs->segment);
#if 0
// this is deeply broken on almost all architectures
if (!pci_set_dma_mask (to_pci_dev(hcd->self.controller), 0xffffffffffffffffULL))
ehci_info (ehci, "enabled 64bit PCI DMA\n");
if (!dma_set_mask (hcd->self.controller, DMA_64BIT_MASK))
ehci_info (ehci, "enabled 64bit DMA\n");
#endif
}
@ -631,17 +630,6 @@ static int ehci_start (struct usb_hcd *hcd)
/* set async sleep time = 10 us ... ? */
/* wire up the root hub */
bus = hcd_to_bus (hcd);
udev = first ? usb_alloc_dev (NULL, bus, 0) : bus->root_hub;
if (!udev) {
done2:
ehci_mem_cleanup (ehci);
return -ENOMEM;
}
udev->speed = USB_SPEED_HIGH;
udev->state = first ? USB_STATE_ATTACHED : USB_STATE_CONFIGURED;
/*
* Start, enabling full USB 2.0 functionality ... usb 1.1 devices
* are explicitly handed to companion controller(s), so no TT is
@ -664,24 +652,6 @@ done2:
first ? "initialized" : "restarted",
temp >> 8, temp & 0xff, DRIVER_VERSION);
/*
* From here on, khubd concurrently accesses the root
* hub; drivers will be talking to enumerated devices.
* (On restart paths, khubd already knows about the root
* hub and could find work as soon as we wrote FLAG_CF.)
*
* Before this point the HC was idle/ready. After, khubd
* and device drivers may start it running.
*/
if (first && usb_hcd_register_root_hub (udev, hcd) != 0) {
if (hcd->state == HC_STATE_RUNNING)
ehci_quiesce (ehci);
ehci_reset (ehci);
usb_put_dev (udev);
retval = -ENODEV;
goto done2;
}
writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
if (first)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2002 by David Brownell
* Copyright (C) 2001-2004 by David Brownell
*
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001-2002 by David Brownell
* Copyright (C) 2001-2004 by David Brownell
*
* 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

View File

@ -637,9 +637,8 @@ iso_stream_alloc (int mem_flags)
{
struct ehci_iso_stream *stream;
stream = kmalloc(sizeof *stream, mem_flags);
stream = kcalloc(1, sizeof *stream, mem_flags);
if (likely (stream != NULL)) {
memset (stream, 0, sizeof(*stream));
INIT_LIST_HEAD(&stream->td_list);
INIT_LIST_HEAD(&stream->free_list);
stream->next_uframe = -1;
@ -894,7 +893,7 @@ itd_sched_init (
trans |= length << 16;
uframe->transaction = cpu_to_le32 (trans);
/* might need to cross a buffer page within a td */
/* might need to cross a buffer page within a uframe */
uframe->bufp = (buf & ~(u64)0x0fff);
buf += length;
if (unlikely ((uframe->bufp != (buf & ~(u64)0x0fff))))
@ -1194,6 +1193,7 @@ itd_init (struct ehci_iso_stream *stream, struct ehci_itd *itd)
{
int i;
/* it's been recently zeroed */
itd->hw_next = EHCI_LIST_END;
itd->hw_bufp [0] = stream->buf0;
itd->hw_bufp [1] = stream->buf1;
@ -1210,8 +1210,7 @@ itd_patch (
struct ehci_itd *itd,
struct ehci_iso_sched *iso_sched,
unsigned index,
u16 uframe,
int first
u16 uframe
)
{
struct ehci_iso_packet *uf = &iso_sched->packet [index];
@ -1228,7 +1227,7 @@ itd_patch (
itd->hw_bufp_hi [pg] |= cpu_to_le32 ((u32)(uf->bufp >> 32));
/* iso_frame_desc[].offset must be strictly increasing */
if (unlikely (!first && uf->cross)) {
if (unlikely (uf->cross)) {
u64 bufp = uf->bufp + 4096;
itd->pg = ++pg;
itd->hw_bufp [pg] |= cpu_to_le32 (bufp & ~(u32)0);
@ -1257,7 +1256,7 @@ itd_link_urb (
struct ehci_iso_stream *stream
)
{
int packet, first = 1;
int packet;
unsigned next_uframe, uframe, frame;
struct ehci_iso_sched *iso_sched = urb->hcpriv;
struct ehci_itd *itd;
@ -1290,7 +1289,6 @@ itd_link_urb (
list_move_tail (&itd->itd_list, &stream->td_list);
itd->stream = iso_stream_get (stream);
itd->urb = usb_get_urb (urb);
first = 1;
itd_init (stream, itd);
}
@ -1298,8 +1296,7 @@ itd_link_urb (
frame = next_uframe >> 3;
itd->usecs [uframe] = stream->usecs;
itd_patch (itd, iso_sched, packet, uframe, first);
first = 0;
itd_patch (itd, iso_sched, packet, uframe);
next_uframe += stream->interval;
stream->depth += stream->interval;

File diff suppressed because it is too large Load Diff

583
drivers/usb/host/isp116x.h Normal file
View File

@ -0,0 +1,583 @@
/*
* ISP116x register declarations and HCD data structures
*
* Copyright (C) 2005 Olav Kongas <ok@artecdesign.ee>
* Portions:
* Copyright (C) 2004 Lothar Wassmann
* Copyright (C) 2004 Psion Teklogix
* Copyright (C) 2004 David Brownell
*/
/* us of 1ms frame */
#define MAX_LOAD_LIMIT 850
/* Full speed: max # of bytes to transfer for a single urb
at a time must be < 1024 && must be multiple of 64.
832 allows transfering 4kiB within 5 frames. */
#define MAX_TRANSFER_SIZE_FULLSPEED 832
/* Low speed: there is no reason to schedule in very big
chunks; often the requested long transfers are for
string descriptors containing short strings. */
#define MAX_TRANSFER_SIZE_LOWSPEED 64
/* Bytetime (us), a rough indication of how much time it
would take to transfer a byte of useful data over USB */
#define BYTE_TIME_FULLSPEED 1
#define BYTE_TIME_LOWSPEED 20
/* Buffer sizes */
#define ISP116x_BUF_SIZE 4096
#define ISP116x_ITL_BUFSIZE 0
#define ISP116x_ATL_BUFSIZE ((ISP116x_BUF_SIZE) - 2*(ISP116x_ITL_BUFSIZE))
#define ISP116x_WRITE_OFFSET 0x80
/*------------ ISP116x registers/bits ------------*/
#define HCREVISION 0x00
#define HCCONTROL 0x01
#define HCCONTROL_HCFS (3 << 6) /* host controller
functional state */
#define HCCONTROL_USB_RESET (0 << 6)
#define HCCONTROL_USB_RESUME (1 << 6)
#define HCCONTROL_USB_OPER (2 << 6)
#define HCCONTROL_USB_SUSPEND (3 << 6)
#define HCCONTROL_RWC (1 << 9) /* remote wakeup connected */
#define HCCONTROL_RWE (1 << 10) /* remote wakeup enable */
#define HCCMDSTAT 0x02
#define HCCMDSTAT_HCR (1 << 0) /* host controller reset */
#define HCCMDSTAT_SOC (3 << 16) /* scheduling overrun count */
#define HCINTSTAT 0x03
#define HCINT_SO (1 << 0) /* scheduling overrun */
#define HCINT_WDH (1 << 1) /* writeback of done_head */
#define HCINT_SF (1 << 2) /* start frame */
#define HCINT_RD (1 << 3) /* resume detect */
#define HCINT_UE (1 << 4) /* unrecoverable error */
#define HCINT_FNO (1 << 5) /* frame number overflow */
#define HCINT_RHSC (1 << 6) /* root hub status change */
#define HCINT_OC (1 << 30) /* ownership change */
#define HCINT_MIE (1 << 31) /* master interrupt enable */
#define HCINTENB 0x04
#define HCINTDIS 0x05
#define HCFMINTVL 0x0d
#define HCFMREM 0x0e
#define HCFMNUM 0x0f
#define HCLSTHRESH 0x11
#define HCRHDESCA 0x12
#define RH_A_NDP (0x3 << 0) /* # downstream ports */
#define RH_A_PSM (1 << 8) /* power switching mode */
#define RH_A_NPS (1 << 9) /* no power switching */
#define RH_A_DT (1 << 10) /* device type (mbz) */
#define RH_A_OCPM (1 << 11) /* overcurrent protection
mode */
#define RH_A_NOCP (1 << 12) /* no overcurrent protection */
#define RH_A_POTPGT (0xff << 24) /* power on -> power good
time */
#define HCRHDESCB 0x13
#define RH_B_DR (0xffff << 0) /* device removable flags */
#define RH_B_PPCM (0xffff << 16) /* port power control mask */
#define HCRHSTATUS 0x14
#define RH_HS_LPS (1 << 0) /* local power status */
#define RH_HS_OCI (1 << 1) /* over current indicator */
#define RH_HS_DRWE (1 << 15) /* device remote wakeup
enable */
#define RH_HS_LPSC (1 << 16) /* local power status change */
#define RH_HS_OCIC (1 << 17) /* over current indicator
change */
#define RH_HS_CRWE (1 << 31) /* clear remote wakeup
enable */
#define HCRHPORT1 0x15
#define RH_PS_CCS (1 << 0) /* current connect status */
#define RH_PS_PES (1 << 1) /* port enable status */
#define RH_PS_PSS (1 << 2) /* port suspend status */
#define RH_PS_POCI (1 << 3) /* port over current
indicator */
#define RH_PS_PRS (1 << 4) /* port reset status */
#define RH_PS_PPS (1 << 8) /* port power status */
#define RH_PS_LSDA (1 << 9) /* low speed device attached */
#define RH_PS_CSC (1 << 16) /* connect status change */
#define RH_PS_PESC (1 << 17) /* port enable status change */
#define RH_PS_PSSC (1 << 18) /* port suspend status
change */
#define RH_PS_OCIC (1 << 19) /* over current indicator
change */
#define RH_PS_PRSC (1 << 20) /* port reset status change */
#define HCRHPORT_CLRMASK (0x1f << 16)
#define HCRHPORT2 0x16
#define HCHWCFG 0x20
#define HCHWCFG_15KRSEL (1 << 12)
#define HCHWCFG_CLKNOTSTOP (1 << 11)
#define HCHWCFG_ANALOG_OC (1 << 10)
#define HCHWCFG_DACK_MODE (1 << 8)
#define HCHWCFG_EOT_POL (1 << 7)
#define HCHWCFG_DACK_POL (1 << 6)
#define HCHWCFG_DREQ_POL (1 << 5)
#define HCHWCFG_DBWIDTH_MASK (0x03 << 3)
#define HCHWCFG_DBWIDTH(n) (((n) << 3) & HCHWCFG_DBWIDTH_MASK)
#define HCHWCFG_INT_POL (1 << 2)
#define HCHWCFG_INT_TRIGGER (1 << 1)
#define HCHWCFG_INT_ENABLE (1 << 0)
#define HCDMACFG 0x21
#define HCDMACFG_BURST_LEN_MASK (0x03 << 5)
#define HCDMACFG_BURST_LEN(n) (((n) << 5) & HCDMACFG_BURST_LEN_MASK)
#define HCDMACFG_BURST_LEN_1 HCDMACFG_BURST_LEN(0)
#define HCDMACFG_BURST_LEN_4 HCDMACFG_BURST_LEN(1)
#define HCDMACFG_BURST_LEN_8 HCDMACFG_BURST_LEN(2)
#define HCDMACFG_DMA_ENABLE (1 << 4)
#define HCDMACFG_BUF_TYPE_MASK (0x07 << 1)
#define HCDMACFG_CTR_SEL (1 << 2)
#define HCDMACFG_ITLATL_SEL (1 << 1)
#define HCDMACFG_DMA_RW_SELECT (1 << 0)
#define HCXFERCTR 0x22
#define HCuPINT 0x24
#define HCuPINT_SOF (1 << 0)
#define HCuPINT_ATL (1 << 1)
#define HCuPINT_AIIEOT (1 << 2)
#define HCuPINT_OPR (1 << 4)
#define HCuPINT_SUSP (1 << 5)
#define HCuPINT_CLKRDY (1 << 6)
#define HCuPINTENB 0x25
#define HCCHIPID 0x27
#define HCCHIPID_MASK 0xff00
#define HCCHIPID_MAGIC 0x6100
#define HCSCRATCH 0x28
#define HCSWRES 0x29
#define HCSWRES_MAGIC 0x00f6
#define HCITLBUFLEN 0x2a
#define HCATLBUFLEN 0x2b
#define HCBUFSTAT 0x2c
#define HCBUFSTAT_ITL0_FULL (1 << 0)
#define HCBUFSTAT_ITL1_FULL (1 << 1)
#define HCBUFSTAT_ATL_FULL (1 << 2)
#define HCBUFSTAT_ITL0_DONE (1 << 3)
#define HCBUFSTAT_ITL1_DONE (1 << 4)
#define HCBUFSTAT_ATL_DONE (1 << 5)
#define HCRDITL0LEN 0x2d
#define HCRDITL1LEN 0x2e
#define HCITLPORT 0x40
#define HCATLPORT 0x41
/* Philips transfer descriptor */
struct ptd {
u16 count;
#define PTD_COUNT_MSK (0x3ff << 0)
#define PTD_TOGGLE_MSK (1 << 10)
#define PTD_ACTIVE_MSK (1 << 11)
#define PTD_CC_MSK (0xf << 12)
u16 mps;
#define PTD_MPS_MSK (0x3ff << 0)
#define PTD_SPD_MSK (1 << 10)
#define PTD_LAST_MSK (1 << 11)
#define PTD_EP_MSK (0xf << 12)
u16 len;
#define PTD_LEN_MSK (0x3ff << 0)
#define PTD_DIR_MSK (3 << 10)
#define PTD_DIR_SETUP (0)
#define PTD_DIR_OUT (1)
#define PTD_DIR_IN (2)
#define PTD_B5_5_MSK (1 << 13)
u16 faddr;
#define PTD_FA_MSK (0x7f << 0)
#define PTD_FMT_MSK (1 << 7)
} __attribute__ ((packed, aligned(2)));
/* PTD accessor macros. */
#define PTD_GET_COUNT(p) (((p)->count & PTD_COUNT_MSK) >> 0)
#define PTD_COUNT(v) (((v) << 0) & PTD_COUNT_MSK)
#define PTD_GET_TOGGLE(p) (((p)->count & PTD_TOGGLE_MSK) >> 10)
#define PTD_TOGGLE(v) (((v) << 10) & PTD_TOGGLE_MSK)
#define PTD_GET_ACTIVE(p) (((p)->count & PTD_ACTIVE_MSK) >> 11)
#define PTD_ACTIVE(v) (((v) << 11) & PTD_ACTIVE_MSK)
#define PTD_GET_CC(p) (((p)->count & PTD_CC_MSK) >> 12)
#define PTD_CC(v) (((v) << 12) & PTD_CC_MSK)
#define PTD_GET_MPS(p) (((p)->mps & PTD_MPS_MSK) >> 0)
#define PTD_MPS(v) (((v) << 0) & PTD_MPS_MSK)
#define PTD_GET_SPD(p) (((p)->mps & PTD_SPD_MSK) >> 10)
#define PTD_SPD(v) (((v) << 10) & PTD_SPD_MSK)
#define PTD_GET_LAST(p) (((p)->mps & PTD_LAST_MSK) >> 11)
#define PTD_LAST(v) (((v) << 11) & PTD_LAST_MSK)
#define PTD_GET_EP(p) (((p)->mps & PTD_EP_MSK) >> 12)
#define PTD_EP(v) (((v) << 12) & PTD_EP_MSK)
#define PTD_GET_LEN(p) (((p)->len & PTD_LEN_MSK) >> 0)
#define PTD_LEN(v) (((v) << 0) & PTD_LEN_MSK)
#define PTD_GET_DIR(p) (((p)->len & PTD_DIR_MSK) >> 10)
#define PTD_DIR(v) (((v) << 10) & PTD_DIR_MSK)
#define PTD_GET_B5_5(p) (((p)->len & PTD_B5_5_MSK) >> 13)
#define PTD_B5_5(v) (((v) << 13) & PTD_B5_5_MSK)
#define PTD_GET_FA(p) (((p)->faddr & PTD_FA_MSK) >> 0)
#define PTD_FA(v) (((v) << 0) & PTD_FA_MSK)
#define PTD_GET_FMT(p) (((p)->faddr & PTD_FMT_MSK) >> 7)
#define PTD_FMT(v) (((v) << 7) & PTD_FMT_MSK)
/* Hardware transfer status codes -- CC from ptd->count */
#define TD_CC_NOERROR 0x00
#define TD_CC_CRC 0x01
#define TD_CC_BITSTUFFING 0x02
#define TD_CC_DATATOGGLEM 0x03
#define TD_CC_STALL 0x04
#define TD_DEVNOTRESP 0x05
#define TD_PIDCHECKFAIL 0x06
#define TD_UNEXPECTEDPID 0x07
#define TD_DATAOVERRUN 0x08
#define TD_DATAUNDERRUN 0x09
/* 0x0A, 0x0B reserved for hardware */
#define TD_BUFFEROVERRUN 0x0C
#define TD_BUFFERUNDERRUN 0x0D
/* 0x0E, 0x0F reserved for HCD */
#define TD_NOTACCESSED 0x0F
/* map PTD status codes (CC) to errno values */
static const int cc_to_error[16] = {
/* No Error */ 0,
/* CRC Error */ -EILSEQ,
/* Bit Stuff */ -EPROTO,
/* Data Togg */ -EILSEQ,
/* Stall */ -EPIPE,
/* DevNotResp */ -ETIMEDOUT,
/* PIDCheck */ -EPROTO,
/* UnExpPID */ -EPROTO,
/* DataOver */ -EOVERFLOW,
/* DataUnder */ -EREMOTEIO,
/* (for hw) */ -EIO,
/* (for hw) */ -EIO,
/* BufferOver */ -ECOMM,
/* BuffUnder */ -ENOSR,
/* (for HCD) */ -EALREADY,
/* (for HCD) */ -EALREADY
};
/*--------------------------------------------------------------*/
#define LOG2_PERIODIC_SIZE 5 /* arbitrary; this matches OHCI */
#define PERIODIC_SIZE (1 << LOG2_PERIODIC_SIZE)
struct isp116x {
spinlock_t lock;
struct work_struct rh_resume;
void __iomem *addr_reg;
void __iomem *data_reg;
struct isp116x_platform_data *board;
struct proc_dir_entry *pde;
unsigned long stat1, stat2, stat4, stat8, stat16;
/* HC registers */
u32 intenb; /* "OHCI" interrupts */
u16 irqenb; /* uP interrupts */
/* Root hub registers */
u32 rhdesca;
u32 rhdescb;
u32 rhstatus;
u32 rhport[2];
/* async schedule: control, bulk */
struct list_head async;
/* periodic schedule: int */
u16 load[PERIODIC_SIZE];
struct isp116x_ep *periodic[PERIODIC_SIZE];
unsigned periodic_count;
u16 fmindex;
/* Schedule for the current frame */
struct isp116x_ep *atl_active;
int atl_buflen;
int atl_bufshrt;
int atl_last_dir;
atomic_t atl_finishing;
};
static inline struct isp116x *hcd_to_isp116x(struct usb_hcd *hcd)
{
return (struct isp116x *)(hcd->hcd_priv);
}
static inline struct usb_hcd *isp116x_to_hcd(struct isp116x *isp116x)
{
return container_of((void *)isp116x, struct usb_hcd, hcd_priv);
}
struct isp116x_ep {
struct usb_host_endpoint *hep;
struct usb_device *udev;
struct ptd ptd;
u8 maxpacket;
u8 epnum;
u8 nextpid;
u16 error_count;
u16 length; /* of current packet */
unsigned char *data; /* to databuf */
/* queue of active EP's (the ones scheduled for the
current frame) */
struct isp116x_ep *active;
/* periodic schedule */
u16 period;
u16 branch;
u16 load;
struct isp116x_ep *next;
/* async schedule */
struct list_head schedule;
};
/*-------------------------------------------------------------------------*/
#ifdef DEBUG
#define DBG(stuff...) printk(KERN_DEBUG "116x: " stuff)
#else
#define DBG(stuff...) do{}while(0)
#endif
#ifdef VERBOSE
# define VDBG DBG
#else
# define VDBG(stuff...) do{}while(0)
#endif
#define ERR(stuff...) printk(KERN_ERR "116x: " stuff)
#define WARN(stuff...) printk(KERN_WARNING "116x: " stuff)
#define INFO(stuff...) printk(KERN_INFO "116x: " stuff)
/* ------------------------------------------------- */
#if defined(USE_PLATFORM_DELAY)
#if defined(USE_NDELAY)
#error USE_PLATFORM_DELAY and USE_NDELAY simultaneously defined.
#endif
#define isp116x_delay(h,d) (h)->board->delay( \
isp116x_to_hcd(h)->self.controller,d)
#define isp116x_check_platform_delay(h) ((h)->board->delay == NULL)
#elif defined(USE_NDELAY)
#define isp116x_delay(h,d) ndelay(d)
#define isp116x_check_platform_delay(h) 0
#else
#define isp116x_delay(h,d) do{}while(0)
#define isp116x_check_platform_delay(h) 0
#endif
#if defined(DEBUG)
#define IRQ_TEST() BUG_ON(!irqs_disabled())
#else
#define IRQ_TEST() do{}while(0)
#endif
static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg)
{
IRQ_TEST();
writew(reg & 0xff, isp116x->addr_reg);
isp116x_delay(isp116x, 300);
}
static inline void isp116x_write_data16(struct isp116x *isp116x, u16 val)
{
writew(val, isp116x->data_reg);
isp116x_delay(isp116x, 150);
}
static inline void isp116x_raw_write_data16(struct isp116x *isp116x, u16 val)
{
__raw_writew(val, isp116x->data_reg);
isp116x_delay(isp116x, 150);
}
static inline u16 isp116x_read_data16(struct isp116x *isp116x)
{
u16 val;
val = readw(isp116x->data_reg);
isp116x_delay(isp116x, 150);
return val;
}
static inline u16 isp116x_raw_read_data16(struct isp116x *isp116x)
{
u16 val;
val = __raw_readw(isp116x->data_reg);
isp116x_delay(isp116x, 150);
return val;
}
static inline void isp116x_write_data32(struct isp116x *isp116x, u32 val)
{
writew(val & 0xffff, isp116x->data_reg);
isp116x_delay(isp116x, 150);
writew(val >> 16, isp116x->data_reg);
isp116x_delay(isp116x, 150);
}
static inline u32 isp116x_read_data32(struct isp116x *isp116x)
{
u32 val;
val = (u32) readw(isp116x->data_reg);
isp116x_delay(isp116x, 150);
val |= ((u32) readw(isp116x->data_reg)) << 16;
isp116x_delay(isp116x, 150);
return val;
}
/* Let's keep register access functions out of line. Hint:
we wait at least 150 ns at every access.
*/
static u16 isp116x_read_reg16(struct isp116x *isp116x, unsigned reg)
{
isp116x_write_addr(isp116x, reg);
return isp116x_read_data16(isp116x);
}
static u32 isp116x_read_reg32(struct isp116x *isp116x, unsigned reg)
{
isp116x_write_addr(isp116x, reg);
return isp116x_read_data32(isp116x);
}
static void isp116x_write_reg16(struct isp116x *isp116x, unsigned reg,
unsigned val)
{
isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
isp116x_write_data16(isp116x, (u16) (val & 0xffff));
}
static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg,
unsigned val)
{
isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
isp116x_write_data32(isp116x, (u32) val);
}
#define isp116x_show_reg(d,r) { \
if ((r) < 0x20) { \
DBG("%-12s[%02x]: %08x\n", #r, \
r, isp116x_read_reg32(d, r)); \
} else { \
DBG("%-12s[%02x]: %04x\n", #r, \
r, isp116x_read_reg16(d, r)); \
} \
}
static inline void isp116x_show_regs(struct isp116x *isp116x)
{
isp116x_show_reg(isp116x, HCREVISION);
isp116x_show_reg(isp116x, HCCONTROL);
isp116x_show_reg(isp116x, HCCMDSTAT);
isp116x_show_reg(isp116x, HCINTSTAT);
isp116x_show_reg(isp116x, HCINTENB);
isp116x_show_reg(isp116x, HCFMINTVL);
isp116x_show_reg(isp116x, HCFMREM);
isp116x_show_reg(isp116x, HCFMNUM);
isp116x_show_reg(isp116x, HCLSTHRESH);
isp116x_show_reg(isp116x, HCRHDESCA);
isp116x_show_reg(isp116x, HCRHDESCB);
isp116x_show_reg(isp116x, HCRHSTATUS);
isp116x_show_reg(isp116x, HCRHPORT1);
isp116x_show_reg(isp116x, HCRHPORT2);
isp116x_show_reg(isp116x, HCHWCFG);
isp116x_show_reg(isp116x, HCDMACFG);
isp116x_show_reg(isp116x, HCXFERCTR);
isp116x_show_reg(isp116x, HCuPINT);
isp116x_show_reg(isp116x, HCuPINTENB);
isp116x_show_reg(isp116x, HCCHIPID);
isp116x_show_reg(isp116x, HCSCRATCH);
isp116x_show_reg(isp116x, HCITLBUFLEN);
isp116x_show_reg(isp116x, HCATLBUFLEN);
isp116x_show_reg(isp116x, HCBUFSTAT);
isp116x_show_reg(isp116x, HCRDITL0LEN);
isp116x_show_reg(isp116x, HCRDITL1LEN);
}
#if defined(URB_TRACE)
#define PIPETYPE(pipe) ({ char *__s; \
if (usb_pipecontrol(pipe)) __s = "ctrl"; \
else if (usb_pipeint(pipe)) __s = "int"; \
else if (usb_pipebulk(pipe)) __s = "bulk"; \
else __s = "iso"; \
__s;})
#define PIPEDIR(pipe) ({ usb_pipein(pipe) ? "in" : "out"; })
#define URB_NOTSHORT(urb) ({ (urb)->transfer_flags & URB_SHORT_NOT_OK ? \
"short_not_ok" : ""; })
/* print debug info about the URB */
static void urb_dbg(struct urb *urb, char *msg)
{
unsigned int pipe;
if (!urb) {
DBG("%s: zero urb\n", msg);
return;
}
pipe = urb->pipe;
DBG("%s: FA %d ep%d%s %s: len %d/%d %s\n", msg,
usb_pipedevice(pipe), usb_pipeendpoint(pipe),
PIPEDIR(pipe), PIPETYPE(pipe),
urb->transfer_buffer_length, urb->actual_length, URB_NOTSHORT(urb));
}
#else
#define urb_dbg(urb,msg) do{}while(0)
#endif /* ! defined(URB_TRACE) */
#if defined(PTD_TRACE)
#define PTD_DIR_STR(ptd) ({char __c; \
switch(PTD_GET_DIR(ptd)){ \
case 0: __c = 's'; break; \
case 1: __c = 'o'; break; \
default: __c = 'i'; break; \
}; __c;})
/*
Dump PTD info. The code documents the format
perfectly, right :)
*/
static inline void dump_ptd(struct ptd *ptd)
{
printk("td: %x %d%c%d %d,%d,%d %x %x%x%x\n",
PTD_GET_CC(ptd), PTD_GET_FA(ptd),
PTD_DIR_STR(ptd), PTD_GET_EP(ptd),
PTD_GET_COUNT(ptd), PTD_GET_LEN(ptd), PTD_GET_MPS(ptd),
PTD_GET_TOGGLE(ptd), PTD_GET_ACTIVE(ptd),
PTD_GET_SPD(ptd), PTD_GET_LAST(ptd));
}
static inline void dump_ptd_out_data(struct ptd *ptd, u8 * buf)
{
int k;
if (PTD_GET_DIR(ptd) != PTD_DIR_IN && PTD_GET_LEN(ptd)) {
printk("-> ");
for (k = 0; k < PTD_GET_LEN(ptd); ++k)
printk("%02x ", ((u8 *) buf)[k]);
printk("\n");
}
}
static inline void dump_ptd_in_data(struct ptd *ptd, u8 * buf)
{
int k;
if (PTD_GET_DIR(ptd) == PTD_DIR_IN && PTD_GET_COUNT(ptd)) {
printk("<- ");
for (k = 0; k < PTD_GET_COUNT(ptd); ++k)
printk("%02x ", ((u8 *) buf)[k]);
printk("\n");
}
if (PTD_GET_LAST(ptd))
printk("-\n");
}
#else
#define dump_ptd(ptd) do{}while(0)
#define dump_ptd_in_data(ptd,buf) do{}while(0)
#define dump_ptd_out_data(ptd,buf) do{}while(0)
#endif /* ! defined(PTD_TRACE) */

View File

@ -95,12 +95,11 @@
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/interrupt.h> /* for in_interrupt () */
#include <linux/usb.h>
#include <linux/usb_otg.h>
#include "../core/hcd.h"
#include <linux/dma-mapping.h>
#include <linux/dmapool.h> /* needed by ohci-mem.c when no PCI */
#include <linux/dmapool.h>
#include <linux/reboot.h>
#include <asm/io.h>
#include <asm/irq.h>
@ -108,8 +107,9 @@
#include <asm/unaligned.h>
#include <asm/byteorder.h>
#include "../core/hcd.h"
#define DRIVER_VERSION "2004 Nov 08"
#define DRIVER_VERSION "2005 April 22"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
@ -141,6 +141,7 @@ static const char hcd_name [] = "ohci_hcd";
static void ohci_dump (struct ohci_hcd *ohci, int verbose);
static int ohci_init (struct ohci_hcd *ohci);
static void ohci_stop (struct usb_hcd *hcd);
static int ohci_reboot (struct notifier_block *, unsigned long , void *);
#include "ohci-hub.c"
#include "ohci-dbg.c"
@ -420,6 +421,23 @@ static void ohci_usb_reset (struct ohci_hcd *ohci)
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
}
/* reboot notifier forcibly disables IRQs and DMA, helping kexec and
* other cases where the next software may expect clean state from the
* "firmware". this is bus-neutral, unlike shutdown() methods.
*/
static int
ohci_reboot (struct notifier_block *block, unsigned long code, void *null)
{
struct ohci_hcd *ohci;
ohci = container_of (block, struct ohci_hcd, reboot_notifier);
ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
ohci_usb_reset (ohci);
/* flush the writes */
(void) ohci_readl (ohci, &ohci->regs->control);
return 0;
}
/*-------------------------------------------------------------------------*
* HC functions
*-------------------------------------------------------------------------*/
@ -487,13 +505,10 @@ static int ohci_init (struct ohci_hcd *ohci)
/* Start an OHCI controller, set the BUS operational
* resets USB and controller
* enable interrupts
* connect the virtual root hub
*/
static int ohci_run (struct ohci_hcd *ohci)
{
u32 mask, temp;
struct usb_device *udev;
struct usb_bus *bus;
int first = ohci->fminterval == 0;
disable (ohci);
@ -654,37 +669,13 @@ retry:
// POTPGT delay is bits 24-31, in 2 ms units.
mdelay ((temp >> 23) & 0x1fe);
bus = &ohci_to_hcd(ohci)->self;
ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
ohci_dump (ohci, 1);
udev = bus->root_hub;
if (udev) {
return 0;
}
/* connect the virtual root hub */
udev = usb_alloc_dev (NULL, bus, 0);
if (!udev) {
disable (ohci);
ohci->hc_control &= ~OHCI_CTRL_HCFS;
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
return -ENOMEM;
}
if (ohci_to_hcd(ohci)->self.root_hub == NULL)
create_debug_files (ohci);
udev->speed = USB_SPEED_FULL;
if (usb_hcd_register_root_hub (udev, ohci_to_hcd(ohci)) != 0) {
usb_put_dev (udev);
disable (ohci);
ohci->hc_control &= ~OHCI_CTRL_HCFS;
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
return -ENODEV;
}
if (ohci->power_budget)
hub_set_power_budget(udev, ohci->power_budget);
create_debug_files (ohci);
return 0;
}
@ -781,6 +772,7 @@ static void ohci_stop (struct usb_hcd *hcd)
ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
remove_debug_files (ohci);
unregister_reboot_notifier (&ohci->reboot_notifier);
ohci_mem_cleanup (ohci);
if (ohci->hcca) {
dma_free_coherent (hcd->self.controller,

View File

@ -29,6 +29,7 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
spin_lock_init (&ohci->lock);
INIT_LIST_HEAD (&ohci->pending);
INIT_WORK (&ohci->rh_resume, ohci_rh_resume, ohci_to_hcd(ohci));
ohci->reboot_notifier.notifier_call = ohci_reboot;
}
/*-------------------------------------------------------------------------*/

View File

@ -181,7 +181,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
if (config->otg) {
ohci_to_hcd(ohci)->self.otg_port = config->otg;
/* default/minimum OTG power budget: 8 mA */
ohci->power_budget = 8;
ohci_to_hcd(ohci)->power_budget = 8;
}
/* boards can use OTG transceivers in non-OTG modes */
@ -230,7 +230,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
/* TPS2045 switch for internal transceiver (port 1) */
if (machine_is_omap_osk()) {
ohci->power_budget = 250;
ohci_to_hcd(ohci)->power_budget = 250;
rh &= ~RH_A_NOCP;

View File

@ -371,7 +371,6 @@ struct ohci_hcd {
* other external transceivers should be software-transparent
*/
struct otg_transceiver *transceiver;
unsigned power_budget;
/*
* memory management for queue data structures
@ -390,6 +389,7 @@ struct ohci_hcd {
u32 fminterval; /* saved register */
struct work_struct rh_resume;
struct notifier_block reboot_notifier;
unsigned long flags; /* for HC bugs */
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */

View File

@ -1563,29 +1563,15 @@ static int
sl811h_start(struct usb_hcd *hcd)
{
struct sl811 *sl811 = hcd_to_sl811(hcd);
struct usb_device *udev;
/* chip has been reset, VBUS power is off */
udev = usb_alloc_dev(NULL, &hcd->self, 0);
if (!udev)
return -ENOMEM;
udev->speed = USB_SPEED_FULL;
hcd->state = HC_STATE_RUNNING;
if (sl811->board)
if (sl811->board) {
hcd->can_wakeup = sl811->board->can_wakeup;
if (usb_hcd_register_root_hub(udev, hcd) != 0) {
usb_put_dev(udev);
sl811h_stop(hcd);
return -ENODEV;
hcd->power_budget = sl811->board->power * 2;
}
if (sl811->board && sl811->board->power)
hub_set_power_budget(udev, sl811->board->power * 2);
/* enable power and interupts */
port_power(sl811, 1);

View File

@ -237,6 +237,37 @@ static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
return out - buf;
}
static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf, int len)
{
char *out = buf;
char *rh_state;
/* Try to make sure there's enough memory */
if (len < 60)
return 0;
switch (uhci->rh_state) {
case UHCI_RH_RESET:
rh_state = "reset"; break;
case UHCI_RH_SUSPENDED:
rh_state = "suspended"; break;
case UHCI_RH_AUTO_STOPPED:
rh_state = "auto-stopped"; break;
case UHCI_RH_RESUMING:
rh_state = "resuming"; break;
case UHCI_RH_SUSPENDING:
rh_state = "suspending"; break;
case UHCI_RH_RUNNING:
rh_state = "running"; break;
case UHCI_RH_RUNNING_NODEVS:
rh_state = "running, no devs"; break;
default:
rh_state = "?"; break;
}
out += sprintf(out, "Root-hub state: %s\n", rh_state);
return out - buf;
}
static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
{
char *out = buf;
@ -408,6 +439,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
spin_lock_irqsave(&uhci->lock, flags);
out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
out += sprintf(out, "HC status\n");
out += uhci_show_status(uhci, out, len - (out - buf));

File diff suppressed because it is too large Load Diff

View File

@ -41,6 +41,7 @@
#define USBFRNUM 6
#define USBFLBASEADD 8
#define USBSOF 12
#define USBSOF_DEFAULT 64 /* Frame length is exactly 1 ms */
/* USB port status and control registers */
#define USBPORTSC1 16
@ -66,6 +67,8 @@
/* Legacy support register */
#define USBLEGSUP 0xc0
#define USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */
#define USBLEGSUP_RWC 0x8f00 /* the R/WC bits */
#define USBLEGSUP_RO 0x5040 /* R/O and reserved bits */
#define UHCI_NULL_DATA_SIZE 0x7FF /* for UHCI controller TD */
@ -111,7 +114,6 @@ struct uhci_qh {
/* Software fields */
dma_addr_t dma_handle;
struct usb_device *dev;
struct urb_priv *urbp;
struct list_head list; /* P: uhci->frame_list_lock */
@ -203,7 +205,6 @@ struct uhci_td {
/* Software fields */
dma_addr_t dma_handle;
struct usb_device *dev;
struct urb *urb;
struct list_head list; /* P: urb->lock */
@ -314,26 +315,32 @@ static inline int __interval_to_skel(int interval)
}
/*
* Device states for the host controller.
* States for the root hub.
*
* To prevent "bouncing" in the presence of electrical noise,
* we insist on a 1-second "grace" period, before switching to
* the RUNNING or SUSPENDED states, during which the state is
* not allowed to change.
*
* The resume process is divided into substates in order to avoid
* potentially length delays during the timer handler.
*
* States in which the host controller is halted must have values <= 0.
* when there are no devices attached we delay for 1 second in the
* RUNNING_NODEVS state before switching to the AUTO_STOPPED state.
*
* (Note that the AUTO_STOPPED state won't be necessary once the hub
* driver learns to autosuspend.)
*/
enum uhci_state {
UHCI_RESET,
UHCI_RUNNING_GRACE, /* Before RUNNING */
UHCI_RUNNING, /* The normal state */
UHCI_SUSPENDING_GRACE, /* Before SUSPENDED */
UHCI_SUSPENDED = -10, /* When no devices are attached */
UHCI_RESUMING_1,
UHCI_RESUMING_2
enum uhci_rh_state {
/* In the following states the HC must be halted.
* These two must come first */
UHCI_RH_RESET,
UHCI_RH_SUSPENDED,
UHCI_RH_AUTO_STOPPED,
UHCI_RH_RESUMING,
/* In this state the HC changes from running to halted,
* so it can legally appear either way. */
UHCI_RH_SUSPENDING,
/* In the following states it's an error if the HC is halted.
* These two must come last */
UHCI_RH_RUNNING, /* The normal state */
UHCI_RH_RUNNING_NODEVS, /* Running with no devices attached */
};
/*
@ -363,15 +370,16 @@ struct uhci_hcd {
int fsbr; /* Full-speed bandwidth reclamation */
unsigned long fsbrtimeout; /* FSBR delay */
enum uhci_state state; /* FIXME: needs a spinlock */
unsigned long state_end; /* Time of next transition */
enum uhci_rh_state rh_state;
unsigned long auto_stop_time; /* When to AUTO_STOP */
unsigned int frame_number; /* As of last check */
unsigned int is_stopped;
#define UHCI_IS_STOPPED 9999 /* Larger than a frame # */
unsigned int scan_in_progress:1; /* Schedule scan is running */
unsigned int need_rescan:1; /* Redo the schedule scan */
unsigned int resume_detect:1; /* Need a Global Resume */
unsigned int hc_inaccessible:1; /* HC is suspended or dead */
/* Support for port suspend/resume/reset */
unsigned long port_c_suspend; /* Bit-arrays of ports */
@ -451,4 +459,11 @@ struct urb_priv {
* #2 urb->lock
*/
/* Some special IDs */
#define PCI_VENDOR_ID_GENESYS 0x17a0
#define PCI_DEVICE_ID_GL880S_UHCI 0x8083
#define PCI_DEVICE_ID_GL880S_EHCI 0x8084
#endif

View File

@ -33,9 +33,24 @@ static __u8 root_hub_hub_des[] =
/* status change bits: nonzero writes will clear */
#define RWC_BITS (USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC)
static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
/* A port that either is connected or has a changed-bit set will prevent
* us from AUTO_STOPPING.
*/
static int any_ports_active(struct uhci_hcd *uhci)
{
int port;
for (port = 0; port < uhci->rh_numports; ++port) {
if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) &
(USBPORTSC_CCS | RWC_BITS)) ||
test_bit(port, &uhci->port_c_suspend))
return 1;
}
return 0;
}
static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
int port;
*buf = 0;
@ -44,8 +59,6 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
test_bit(port, &uhci->port_c_suspend))
*buf |= (1 << (port + 1));
}
if (*buf && uhci->state == UHCI_SUSPENDED)
uhci->resume_detect = 1;
return !!*buf;
}
@ -115,6 +128,11 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
set_bit(port, &uhci->resuming_ports);
uhci->ports_timeout = jiffies +
msecs_to_jiffies(20);
/* Make sure we see the port again
* after the resuming period is over. */
mod_timer(&uhci_to_hcd(uhci)->rh_timer,
uhci->ports_timeout);
} else if (time_after_eq(jiffies,
uhci->ports_timeout)) {
uhci_finish_suspend(uhci, port, port_addr);
@ -123,6 +141,60 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
}
}
static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned long flags;
int status;
spin_lock_irqsave(&uhci->lock, flags);
if (uhci->hc_inaccessible) {
status = 0;
goto done;
}
uhci_check_ports(uhci);
status = get_hub_status_data(uhci, buf);
switch (uhci->rh_state) {
case UHCI_RH_SUSPENDING:
case UHCI_RH_SUSPENDED:
/* if port change, ask to be resumed */
if (status)
usb_hcd_resume_root_hub(hcd);
break;
case UHCI_RH_AUTO_STOPPED:
/* if port change, auto start */
if (status)
wakeup_rh(uhci);
break;
case UHCI_RH_RUNNING:
/* are any devices attached? */
if (!any_ports_active(uhci)) {
uhci->rh_state = UHCI_RH_RUNNING_NODEVS;
uhci->auto_stop_time = jiffies + HZ;
}
break;
case UHCI_RH_RUNNING_NODEVS:
/* auto-stop if nothing connected for 1 second */
if (any_ports_active(uhci))
uhci->rh_state = UHCI_RH_RUNNING;
else if (time_after_eq(jiffies, uhci->auto_stop_time))
suspend_rh(uhci, UHCI_RH_AUTO_STOPPED);
break;
default:
break;
}
done:
spin_unlock_irqrestore(&uhci->lock, flags);
return status;
}
/* size of returned buffer is part of USB spec */
static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
@ -134,6 +206,9 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wPortChange, wPortStatus;
unsigned long flags;
if (uhci->hc_inaccessible)
return -ETIMEDOUT;
spin_lock_irqsave(&uhci->lock, flags);
switch (typeReq) {

View File

@ -32,6 +32,8 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci);
*/
static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
{
if (uhci->is_stopped)
mod_timer(&uhci->stall_timer, jiffies);
uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC);
}
@ -46,7 +48,7 @@ static inline void uhci_moveto_complete(struct uhci_hcd *uhci,
list_move_tail(&urbp->urb_list, &uhci->complete_list);
}
static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev)
static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci)
{
dma_addr_t dma_handle;
struct uhci_td *td;
@ -61,14 +63,11 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *d
td->buffer = 0;
td->frame = -1;
td->dev = dev;
INIT_LIST_HEAD(&td->list);
INIT_LIST_HEAD(&td->remove_list);
INIT_LIST_HEAD(&td->fl_list);
usb_get_dev(dev);
return td;
}
@ -168,13 +167,10 @@ static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
if (!list_empty(&td->fl_list))
dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
if (td->dev)
usb_put_dev(td->dev);
dma_pool_free(uhci->td_pool, td, td->dma_handle);
}
static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *dev)
static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci)
{
dma_addr_t dma_handle;
struct uhci_qh *qh;
@ -188,14 +184,11 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *d
qh->element = UHCI_PTR_TERM;
qh->link = UHCI_PTR_TERM;
qh->dev = dev;
qh->urbp = NULL;
INIT_LIST_HEAD(&qh->list);
INIT_LIST_HEAD(&qh->remove_list);
usb_get_dev(dev);
return qh;
}
@ -206,9 +199,6 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
if (!list_empty(&qh->remove_list))
dev_warn(uhci_dev(uhci), "qh %p still in remove_list!\n", qh);
if (qh->dev)
usb_put_dev(qh->dev);
dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
}
@ -597,7 +587,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
/*
* Build the TD for the control request setup packet
*/
td = uhci_alloc_td(uhci, urb->dev);
td = uhci_alloc_td(uhci);
if (!td)
return -ENOMEM;
@ -626,7 +616,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
if (pktsze > maxsze)
pktsze = maxsze;
td = uhci_alloc_td(uhci, urb->dev);
td = uhci_alloc_td(uhci);
if (!td)
return -ENOMEM;
@ -644,7 +634,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
/*
* Build the final TD for control status
*/
td = uhci_alloc_td(uhci, urb->dev);
td = uhci_alloc_td(uhci);
if (!td)
return -ENOMEM;
@ -666,7 +656,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
uhci_fill_td(td, status | TD_CTRL_IOC,
destination | uhci_explen(UHCI_NULL_DATA_SIZE), 0);
qh = uhci_alloc_qh(uhci, urb->dev);
qh = uhci_alloc_qh(uhci);
if (!qh)
return -ENOMEM;
@ -865,7 +855,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb
status &= ~TD_CTRL_SPD;
}
td = uhci_alloc_td(uhci, urb->dev);
td = uhci_alloc_td(uhci);
if (!td)
return -ENOMEM;
@ -891,7 +881,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb
*/
if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) &&
!len && urb->transfer_buffer_length) {
td = uhci_alloc_td(uhci, urb->dev);
td = uhci_alloc_td(uhci);
if (!td)
return -ENOMEM;
@ -913,7 +903,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb
* flag setting. */
td->status |= cpu_to_le32(TD_CTRL_IOC);
qh = uhci_alloc_qh(uhci, urb->dev);
qh = uhci_alloc_qh(uhci);
if (!qh)
return -ENOMEM;
@ -1096,7 +1086,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
if (!urb->iso_frame_desc[i].length)
continue;
td = uhci_alloc_td(uhci, urb->dev);
td = uhci_alloc_td(uhci);
if (!td)
return -ENOMEM;
@ -1497,6 +1487,7 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
rescan:
uhci->need_rescan = 0;
uhci_clear_next_interrupt(uhci);
uhci_get_current_frame_number(uhci);
if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age)
@ -1537,3 +1528,26 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
/* Wake up anyone waiting for an URB to complete */
wake_up_all(&uhci->waitqh);
}
static void check_fsbr(struct uhci_hcd *uhci)
{
struct urb_priv *up;
list_for_each_entry(up, &uhci->urb_list, urb_list) {
struct urb *u = up->urb;
spin_lock(&u->lock);
/* Check if the FSBR timed out */
if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
uhci_fsbr_timeout(uhci, u);
spin_unlock(&u->lock);
}
/* Really disable FSBR */
if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
uhci->fsbrtimeout = 0;
uhci->skel_term_qh->link = UHCI_PTR_TERM;
}
}

View File

@ -639,6 +639,7 @@ static void ati_remote_input_init(struct ati_remote *ati_remote)
idev->id.vendor = le16_to_cpu(ati_remote->udev->descriptor.idVendor);
idev->id.product = le16_to_cpu(ati_remote->udev->descriptor.idProduct);
idev->id.version = le16_to_cpu(ati_remote->udev->descriptor.bcdDevice);
idev->dev = &(ati_remote->udev->dev);
}
static int ati_remote_initialize(struct ati_remote *ati_remote)

View File

@ -1375,9 +1375,13 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id
(le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) {
camera_name = "STV0680";
PDEBUG (0, "STV(i): STV0680 camera found.");
} else if ((le16_to_cpu(dev->descriptor.idVendor) == USB_CREATIVEGOMINI_VENDOR_ID) &&
(le16_to_cpu(dev->descriptor.idProduct) == USB_CREATIVEGOMINI_PRODUCT_ID)) {
camera_name = "Creative WebCam Go Mini";
PDEBUG (0, "STV(i): Creative WebCam Go Mini found.");
} else {
PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 values.");
PDEBUG (0, "STV(e): Check that the STV0680 camera is connected to the computer.");
PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 or Creative WebCam Go Mini values.");
PDEBUG (0, "STV(e): Check that the STV0680 or Creative WebCam Go Mini camera is connected to the computer.");
retval = -ENODEV;
goto error;
}

View File

@ -41,12 +41,17 @@
#define USB_PENCAM_VENDOR_ID 0x0553
#define USB_PENCAM_PRODUCT_ID 0x0202
#define USB_CREATIVEGOMINI_VENDOR_ID 0x041e
#define USB_CREATIVEGOMINI_PRODUCT_ID 0x4007
#define PENCAM_TIMEOUT 1000
/* fmt 4 */
#define STV_VIDEO_PALETTE VIDEO_PALETTE_RGB24
static struct usb_device_id device_table[] = {
{USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
{USB_DEVICE (USB_CREATIVEGOMINI_VENDOR_ID, USB_CREATIVEGOMINI_PRODUCT_ID)},
{}
};
MODULE_DEVICE_TABLE (usb, device_table);

View File

@ -1,4 +1,4 @@
/* Siemens ID Mouse driver v0.5
/* Siemens ID Mouse driver v0.6
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@ -11,6 +11,9 @@
Derived from the USB Skeleton driver 1.1,
Copyright (C) 2003 Greg Kroah-Hartman (greg@kroah.com)
Additional information provided by Martin Reising
<Martin.Reising@natural-computing.de>
*/
#include <linux/config.h>
@ -25,29 +28,44 @@
#include <asm/uaccess.h>
#include <linux/usb.h>
/* image constants */
#define WIDTH 225
#define HEIGHT 288
#define HEADER "P5 225 288 255 "
#define HEIGHT 289
#define HEADER "P5 225 289 255 "
#define IMGSIZE ((WIDTH * HEIGHT) + sizeof(HEADER)-1)
/* Version Information */
#define DRIVER_VERSION "0.5"
/* version information */
#define DRIVER_VERSION "0.6"
#define DRIVER_SHORT "idmouse"
#define DRIVER_AUTHOR "Florian 'Floe' Echtler <echtler@fs.tum.de>"
#define DRIVER_DESC "Siemens ID Mouse FingerTIP Sensor Driver"
/* Siemens ID Mouse */
#define USB_IDMOUSE_VENDOR_ID 0x0681
#define USB_IDMOUSE_PRODUCT_ID 0x0005
/* we still need a minor number */
/* minor number for misc USB devices */
#define USB_IDMOUSE_MINOR_BASE 132
/* vendor and device IDs */
#define ID_SIEMENS 0x0681
#define ID_IDMOUSE 0x0005
#define ID_CHERRY 0x0010
/* device ID table */
static struct usb_device_id idmouse_table[] = {
{USB_DEVICE(USB_IDMOUSE_VENDOR_ID, USB_IDMOUSE_PRODUCT_ID)},
{} /* null entry at the end */
{USB_DEVICE(ID_SIEMENS, ID_IDMOUSE)}, /* Siemens ID Mouse (Professional) */
{USB_DEVICE(ID_SIEMENS, ID_CHERRY )}, /* Cherry FingerTIP ID Board */
{} /* terminating null entry */
};
/* sensor commands */
#define FTIP_RESET 0x20
#define FTIP_ACQUIRE 0x21
#define FTIP_RELEASE 0x22
#define FTIP_BLINK 0x23 /* LSB of value = blink pulse width */
#define FTIP_SCROLL 0x24
#define ftip_command(dev, command, value, index) \
usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), command, \
USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000)
MODULE_DEVICE_TABLE(usb, idmouse_table);
/* structure to hold all of our device specific stuff */
@ -57,7 +75,8 @@ struct usb_idmouse {
struct usb_interface *interface; /* the interface for this device */
unsigned char *bulk_in_buffer; /* the buffer to receive data */
size_t bulk_in_size; /* the size of the receive buffer */
size_t bulk_in_size; /* the maximum bulk packet size */
size_t orig_bi_size; /* same as above, but reported by the device */
__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
int open; /* if the port is open or not */
@ -103,7 +122,7 @@ static struct usb_driver idmouse_driver = {
.id_table = idmouse_table,
};
// prevent races between open() and disconnect()
/* prevent races between open() and disconnect() */
static DECLARE_MUTEX(disconnect_sem);
static int idmouse_create_image(struct usb_idmouse *dev)
@ -112,42 +131,34 @@ static int idmouse_create_image(struct usb_idmouse *dev)
int bulk_read = 0;
int result = 0;
if (dev->bulk_in_size < sizeof(HEADER))
return -ENOMEM;
memcpy(dev->bulk_in_buffer,HEADER,sizeof(HEADER)-1);
memcpy(dev->bulk_in_buffer, HEADER, sizeof(HEADER)-1);
bytes_read += sizeof(HEADER)-1;
/* Dump the setup packets. Yes, they are uncommented, simply
because they were sniffed under Windows using SnoopyPro.
I _guess_ that 0x22 is a kind of reset command and 0x21
means init..
*/
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
0x21, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
/* reset the device and set a fast blink rate */
result = ftip_command(dev, FTIP_RELEASE, 0, 0);
if (result < 0)
return result;
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
0x20, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
goto reset;
result = ftip_command(dev, FTIP_BLINK, 1, 0);
if (result < 0)
return result;
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
if (result < 0)
return result;
goto reset;
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
0x21, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
/* initialize the sensor - sending this command twice */
/* significantly reduces the rate of failed reads */
result = ftip_command(dev, FTIP_ACQUIRE, 0, 0);
if (result < 0)
return result;
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
0x20, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
goto reset;
result = ftip_command(dev, FTIP_ACQUIRE, 0, 0);
if (result < 0)
return result;
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
0x20, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
goto reset;
/* start the readout - sending this command twice */
/* presumably enables the high dynamic range mode */
result = ftip_command(dev, FTIP_RESET, 0, 0);
if (result < 0)
return result;
goto reset;
result = ftip_command(dev, FTIP_RESET, 0, 0);
if (result < 0)
goto reset;
/* loop over a blocking bulk read to get data from the device */
while (bytes_read < IMGSIZE) {
@ -155,22 +166,40 @@ static int idmouse_create_image(struct usb_idmouse *dev)
usb_rcvbulkpipe (dev->udev, dev->bulk_in_endpointAddr),
dev->bulk_in_buffer + bytes_read,
dev->bulk_in_size, &bulk_read, 5000);
if (result < 0)
return result;
if (signal_pending(current))
return -EINTR;
if (result < 0) {
/* Maybe this error was caused by the increased packet size? */
/* Reset to the original value and tell userspace to retry. */
if (dev->bulk_in_size != dev->orig_bi_size) {
dev->bulk_in_size = dev->orig_bi_size;
result = -EAGAIN;
}
break;
}
if (signal_pending(current)) {
result = -EINTR;
break;
}
bytes_read += bulk_read;
}
/* reset the device */
result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
if (result < 0)
return result;
reset:
ftip_command(dev, FTIP_RELEASE, 0, 0);
/* should be IMGSIZE == 64815 */
/* check for valid image */
/* right border should be black (0x00) */
for (bytes_read = sizeof(HEADER)-1 + WIDTH-1; bytes_read < IMGSIZE; bytes_read += WIDTH)
if (dev->bulk_in_buffer[bytes_read] != 0x00)
return -EAGAIN;
/* lower border should be white (0xFF) */
for (bytes_read = IMGSIZE-WIDTH; bytes_read < IMGSIZE-1; bytes_read++)
if (dev->bulk_in_buffer[bytes_read] != 0xFF)
return -EAGAIN;
/* should be IMGSIZE == 65040 */
dbg("read %d bytes fingerprint data", bytes_read);
return 0;
return result;
}
static inline void idmouse_delete(struct usb_idmouse *dev)
@ -282,10 +311,10 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count
dev = (struct usb_idmouse *) file->private_data;
// lock this object
/* lock this object */
down (&dev->sem);
// verify that the device wasn't unplugged
/* verify that the device wasn't unplugged */
if (!dev->present) {
up (&dev->sem);
return -ENODEV;
@ -296,8 +325,7 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count
return 0;
}
if (count > IMGSIZE - *ppos)
count = IMGSIZE - *ppos;
count = min ((loff_t)count, IMGSIZE - (*ppos));
if (copy_to_user (buffer, dev->bulk_in_buffer + *ppos, count)) {
result = -EFAULT;
@ -306,7 +334,7 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count
*ppos += count;
}
// unlock the device
/* unlock the device */
up(&dev->sem);
return result;
}
@ -318,7 +346,6 @@ static int idmouse_probe(struct usb_interface *interface,
struct usb_idmouse *dev = NULL;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
size_t buffer_size;
int result;
/* check if we have gotten the data or the hid interface */
@ -344,11 +371,11 @@ static int idmouse_probe(struct usb_interface *interface,
USB_ENDPOINT_XFER_BULK)) {
/* we found a bulk in endpoint */
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
dev->bulk_in_size = buffer_size;
dev->orig_bi_size = le16_to_cpu(endpoint->wMaxPacketSize);
dev->bulk_in_size = 0x200; /* works _much_ faster */
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
dev->bulk_in_buffer =
kmalloc(IMGSIZE + buffer_size, GFP_KERNEL);
kmalloc(IMGSIZE + dev->bulk_in_size, GFP_KERNEL);
if (!dev->bulk_in_buffer) {
err("Unable to allocate input buffer.");

View File

@ -461,7 +461,7 @@ static int perform_sglist (
static unsigned realworld = 1;
module_param (realworld, uint, 0);
MODULE_PARM_DESC (realworld, "clear to demand stricter ch9 compliance");
MODULE_PARM_DESC (realworld, "clear to demand stricter spec compliance");
static int get_altsetting (struct usbtest_dev *dev)
{
@ -604,9 +604,8 @@ static int ch9_postconfig (struct usbtest_dev *dev)
USB_DIR_IN | USB_RECIP_DEVICE,
0, 0, dev->buf, 1, USB_CTRL_GET_TIMEOUT);
if (retval != 1 || dev->buf [0] != expected) {
dev_dbg (&iface->dev,
"get config --> %d (%d)\n", retval,
expected);
dev_dbg (&iface->dev, "get config --> %d %d (1 %d)\n",
retval, dev->buf[0], expected);
return (retval < 0) ? retval : -EDOM;
}
}
@ -1243,7 +1242,7 @@ static int ctrl_out (struct usbtest_dev *dev,
char *what = "?";
struct usb_device *udev;
if (length > 0xffff || vary >= length)
if (length < 1 || length > 0xffff || vary >= length)
return -EINVAL;
buf = kmalloc(length, SLAB_KERNEL);
@ -1266,6 +1265,11 @@ static int ctrl_out (struct usbtest_dev *dev,
0, 0, buf, len, USB_CTRL_SET_TIMEOUT);
if (retval != len) {
what = "write";
if (retval >= 0) {
INFO(dev, "ctrl_out, wlen %d (expected %d)\n",
retval, len);
retval = -EBADMSG;
}
break;
}
@ -1275,6 +1279,11 @@ static int ctrl_out (struct usbtest_dev *dev,
0, 0, buf, len, USB_CTRL_GET_TIMEOUT);
if (retval != len) {
what = "read";
if (retval >= 0) {
INFO(dev, "ctrl_out, rlen %d (expected %d)\n",
retval, len);
retval = -EBADMSG;
}
break;
}
@ -1293,8 +1302,13 @@ static int ctrl_out (struct usbtest_dev *dev,
}
len += vary;
/* [real world] the "zero bytes IN" case isn't really used.
* hardware can easily trip up in this wierd case, since its
* status stage is IN, not OUT like other ep0in transfers.
*/
if (len > length)
len = 0;
len = realworld ? 1 : 0;
}
if (retval < 0)
@ -1519,6 +1533,11 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
if (down_interruptible (&dev->sem))
return -ERESTARTSYS;
if (intf->dev.power.power_state != PMSG_ON) {
up (&dev->sem);
return -EHOSTUNREACH;
}
/* some devices, like ez-usb default devices, need a non-default
* altsetting to have any active endpoints. some tests change
* altsettings; force a default so most tests don't need to check.
@ -1762,8 +1781,10 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
case 14:
if (!dev->info->ctrl_out)
break;
dev_dbg (&intf->dev, "TEST 14: %d ep0out, 0..%d vary %d\n",
param->iterations, param->length, param->vary);
dev_dbg (&intf->dev, "TEST 14: %d ep0out, %d..%d vary %d\n",
param->iterations,
realworld ? 1 : 0, param->length,
param->vary);
retval = ctrl_out (dev, param->iterations,
param->length, param->vary);
break;
@ -1927,6 +1948,27 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
return 0;
}
static int usbtest_suspend (struct usb_interface *intf, pm_message_t message)
{
struct usbtest_dev *dev = usb_get_intfdata (intf);
down (&dev->sem);
intf->dev.power.power_state = PMSG_SUSPEND;
up (&dev->sem);
return 0;
}
static int usbtest_resume (struct usb_interface *intf)
{
struct usbtest_dev *dev = usb_get_intfdata (intf);
down (&dev->sem);
intf->dev.power.power_state = PMSG_ON;
up (&dev->sem);
return 0;
}
static void usbtest_disconnect (struct usb_interface *intf)
{
struct usbtest_dev *dev = usb_get_intfdata (intf);
@ -2115,6 +2157,8 @@ static struct usb_driver usbtest_driver = {
.probe = usbtest_probe,
.ioctl = usbtest_ioctl,
.disconnect = usbtest_disconnect,
.suspend = usbtest_suspend,
.resume = usbtest_resume,
};
/*-------------------------------------------------------------------------*/

View File

@ -1429,7 +1429,7 @@ static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf)
info->ether = (void *) buf;
if (info->ether->bLength != sizeof *info->ether) {
dev_dbg (&intf->dev, "CDC ether len %u\n",
info->u->bLength);
info->ether->bLength);
goto bad_desc;
}
dev->net->mtu = le16_to_cpup (

View File

@ -1884,12 +1884,53 @@ static void zd1201_disconnect(struct usb_interface *interface)
kfree(zd);
}
#ifdef CONFIG_PM
static int zd1201_suspend(struct usb_interface *interface,
pm_message_t message)
{
struct zd1201 *zd = usb_get_intfdata(interface);
netif_device_detach(zd->dev);
zd->was_enabled = zd->mac_enabled;
if (zd->was_enabled)
return zd1201_disable(zd);
else
return 0;
}
static int zd1201_resume(struct usb_interface *interface)
{
struct zd1201 *zd = usb_get_intfdata(interface);
if (!zd || !zd->dev)
return -ENODEV;
netif_device_attach(zd->dev);
if (zd->was_enabled)
return zd1201_enable(zd);
else
return 0;
}
#else
#define zd1201_suspend NULL
#define zd1201_resume NULL
#endif
static struct usb_driver zd1201_usb = {
.owner = THIS_MODULE,
.name = "zd1201",
.probe = zd1201_probe,
.disconnect = zd1201_disconnect,
.id_table = zd1201_table,
.suspend = zd1201_suspend,
.resume = zd1201_resume,
};
static int __init zd1201_init(void)

View File

@ -46,6 +46,7 @@ struct zd1201 {
char essid[IW_ESSID_MAX_SIZE+1];
int essidlen;
int mac_enabled;
int was_enabled;
int monitor;
int encode_enabled;
int encode_restricted;

View File

@ -213,10 +213,14 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
return (0);
}
if (port->write_urb->status == -EINPROGRESS) {
spin_lock(&port->lock);
if (port->write_urb_busy) {
spin_unlock(&port->lock);
dbg("%s - already writing", __FUNCTION__);
return (0);
return 0;
}
port->write_urb_busy = 1;
spin_unlock(&port->lock);
spin_lock_irqsave(&priv->lock, flags);
@ -224,6 +228,7 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
/* To much data for buffer. Reset buffer. */
priv->wrfilled=0;
spin_unlock_irqrestore(&priv->lock, flags);
port->write_urb_busy = 0;
return (0);
}
@ -268,6 +273,7 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
priv->wrfilled=0;
priv->wrsent=0;
spin_unlock_irqrestore(&priv->lock, flags);
port->write_urb_busy = 0;
return 0;
}
@ -412,7 +418,8 @@ static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs
struct cyberjack_private *priv = usb_get_serial_port_data(port);
dbg("%s - port %d", __FUNCTION__, port->number);
port->write_urb_busy = 0;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;
@ -424,12 +431,6 @@ static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs
if( priv->wrfilled ) {
int length, blksize, result;
if (port->write_urb->status == -EINPROGRESS) {
dbg("%s - already writing", __FUNCTION__);
spin_unlock(&priv->lock);
return;
}
dbg("%s - transmitting data (frame n)", __FUNCTION__);
length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ?

View File

@ -174,10 +174,14 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *
/* only do something if we have a bulk out endpoint */
if (serial->num_bulk_out) {
if (port->write_urb->status == -EINPROGRESS) {
spin_lock(&port->lock);
if (port->write_urb_busy) {
spin_unlock(&port->lock);
dbg("%s - already writing", __FUNCTION__);
return (0);
return 0;
}
port->write_urb_busy = 1;
spin_unlock(&port->lock);
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
@ -195,17 +199,20 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *
usb_serial_generic_write_bulk_callback), port);
/* send the data out the bulk port */
port->write_urb_busy = 1;
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result)
if (result) {
dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
else
/* don't have to grab the lock here, as we will retry if != 0 */
port->write_urb_busy = 0;
} else
result = count;
return result;
}
/* no bulk out, so return 0 bytes written */
return (0);
return 0;
}
int usb_serial_generic_write_room (struct usb_serial_port *port)
@ -214,9 +221,9 @@ int usb_serial_generic_write_room (struct usb_serial_port *port)
int room = 0;
dbg("%s - port %d", __FUNCTION__, port->number);
if (serial->num_bulk_out) {
if (port->write_urb->status != -EINPROGRESS)
if (port->write_urb_busy)
room = port->bulk_out_size;
}
@ -232,7 +239,7 @@ int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port)
dbg("%s - port %d", __FUNCTION__, port->number);
if (serial->num_bulk_out) {
if (port->write_urb->status == -EINPROGRESS)
if (port->write_urb_busy)
chars = port->write_urb->transfer_buffer_length;
}
@ -291,6 +298,7 @@ void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *re
dbg("%s - port %d", __FUNCTION__, port->number);
port->write_urb_busy = 0;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;

View File

@ -818,11 +818,6 @@ static void ipaq_write_gather(struct usb_serial_port *port)
struct ipaq_packet *pkt, *tmp;
struct urb *urb = port->write_urb;
if (urb->status == -EINPROGRESS) {
/* Should never happen */
err("%s - flushing while urb is active !", __FUNCTION__);
return;
}
room = URBDATA_SIZE;
list_for_each_entry_safe(pkt, tmp, &priv->queue, list) {
count = min(room, (int)(pkt->len - pkt->written));

View File

@ -399,16 +399,21 @@ static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int
dbg("%s - write request of 0 bytes", __FUNCTION__);
return 0;
}
/* Racy and broken, FIXME properly! */
if (port->write_urb->status == -EINPROGRESS)
spin_lock(&port->lock);
if (port->write_urb_busy) {
spin_unlock(&port->lock);
dbg("%s - already writing", __FUNCTION__);
return 0;
}
port->write_urb_busy = 1;
spin_unlock(&port->lock);
count = min(count, port->bulk_out_size);
memcpy(port->bulk_out_buffer, buf, count);
dbg("%s count now:%d", __FUNCTION__, count);
usb_fill_bulk_urb(port->write_urb, dev,
usb_sndbulkpipe(dev, port->bulk_out_endpointAddress),
port->write_urb->transfer_buffer,
@ -418,6 +423,7 @@ static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int
ret = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (ret != 0) {
port->write_urb_busy = 0;
dbg("%s - usb_submit_urb(write bulk) failed with error = %d", __FUNCTION__, ret);
return ret;
}

View File

@ -341,10 +341,14 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int
if (count == 0)
return 0;
if (port->write_urb->status == -EINPROGRESS) {
dbg ("%s - already writing", __FUNCTION__);
spin_lock(&port->lock);
if (port->write_urb_busy) {
spin_unlock(&port->lock);
dbg("%s - already writing", __FUNCTION__);
return 0;
}
port->write_urb_busy = 1;
spin_unlock(&port->lock);
transfer_buffer = port->write_urb->transfer_buffer;
transfer_size = min(count, port->bulk_out_size - 1);
@ -374,9 +378,10 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int
port->write_urb->transfer_flags = URB_ZERO_PACKET;
result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
if (result)
if (result) {
port->write_urb_busy = 0;
dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
else
} else
result = transfer_size;
return result;
@ -387,7 +392,8 @@ static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
dbg("%s - port %d", __FUNCTION__, port->number);
port->write_urb_busy = 0;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;

View File

@ -520,9 +520,13 @@ static int keyspan_pda_write(struct usb_serial_port *port,
the TX urb is in-flight (wait until it completes)
the device is full (wait until it says there is room)
*/
if (port->write_urb->status == -EINPROGRESS || priv->tx_throttled ) {
return( 0 );
spin_lock(&port->lock);
if (port->write_urb_busy || priv->tx_throttled) {
spin_unlock(&port->lock);
return 0;
}
port->write_urb_busy = 1;
spin_unlock(&port->lock);
/* At this point the URB is in our control, nobody else can submit it
again (the only sudden transition was the one from EINPROGRESS to
@ -570,7 +574,7 @@ static int keyspan_pda_write(struct usb_serial_port *port,
memcpy (port->write_urb->transfer_buffer, buf, count);
/* send the data out the bulk port */
port->write_urb->transfer_buffer_length = count;
priv->tx_room -= count;
port->write_urb->dev = port->serial->dev;
@ -593,6 +597,8 @@ static int keyspan_pda_write(struct usb_serial_port *port,
rc = count;
exit:
if (rc < 0)
port->write_urb_busy = 0;
return rc;
}
@ -602,6 +608,7 @@ static void keyspan_pda_write_bulk_callback (struct urb *urb, struct pt_regs *re
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct keyspan_pda_private *priv;
port->write_urb_busy = 0;
priv = usb_get_serial_port_data(port);
/* queue up a wakeup at scheduler time */
@ -626,12 +633,12 @@ static int keyspan_pda_write_room (struct usb_serial_port *port)
static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
{
struct keyspan_pda_private *priv;
priv = usb_get_serial_port_data(port);
/* when throttled, return at least WAKEUP_CHARS to tell select() (via
n_tty.c:normal_poll() ) that we're not writeable. */
if( port->write_urb->status == -EINPROGRESS || priv->tx_throttled )
if (port->write_urb_busy || priv->tx_throttled)
return 256;
return 0;
}

View File

@ -254,10 +254,15 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf
dbg("%s - write request of 0 bytes", __FUNCTION__);
return (0);
}
if (wport->write_urb->status == -EINPROGRESS) {
spin_lock(&port->lock);
if (port->write_urb_busy) {
spin_unlock(&port->lock);
dbg("%s - already writing", __FUNCTION__);
return (0);
return 0;
}
port->write_urb_busy = 1;
spin_unlock(&port->lock);
count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
@ -275,9 +280,10 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf
wport->write_urb->dev = serial->dev;
result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);
if (result)
if (result) {
port->write_urb_busy = 0;
err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
else
} else
result = count;
return result;
@ -291,7 +297,7 @@ static int omninet_write_room (struct usb_serial_port *port)
int room = 0; // Default: no room
if (wport->write_urb->status != -EINPROGRESS)
if (wport->write_urb_busy)
room = wport->bulk_out_size - OMNINET_HEADERLEN;
// dbg("omninet_write_room returns %d", room);
@ -306,6 +312,7 @@ static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
// dbg("omninet_write_bulk_callback, port %0x\n", port);
port->write_urb_busy = 0;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;

View File

@ -299,10 +299,14 @@ static int safe_write (struct usb_serial_port *port, const unsigned char *buf, i
dbg ("%s - write request of 0 bytes", __FUNCTION__);
return (0);
}
if (port->write_urb->status == -EINPROGRESS) {
dbg ("%s - already writing", __FUNCTION__);
return (0);
spin_lock(&port->lock);
if (port->write_urb_busy) {
spin_unlock(&port->lock);
dbg("%s - already writing", __FUNCTION__);
return 0;
}
port->write_urb_busy = 1;
spin_unlock(&port->lock);
packet_length = port->bulk_out_size; // get max packetsize
@ -354,6 +358,7 @@ static int safe_write (struct usb_serial_port *port, const unsigned char *buf, i
#endif
port->write_urb->dev = port->serial->dev;
if ((result = usb_submit_urb (port->write_urb, GFP_KERNEL))) {
port->write_urb_busy = 0;
err ("%s - failed submitting write urb, error %d", __FUNCTION__, result);
return 0;
}
@ -368,7 +373,7 @@ static int safe_write_room (struct usb_serial_port *port)
dbg ("%s", __FUNCTION__);
if (port->write_urb->status != -EINPROGRESS)
if (port->write_urb_busy)
room = port->bulk_out_size - (safe ? 2 : 0);
if (room) {

View File

@ -1047,6 +1047,7 @@ int usb_serial_probe(struct usb_interface *interface,
memset(port, 0x00, sizeof(struct usb_serial_port));
port->number = i + serial->minor;
port->serial = serial;
spin_lock_init(&port->lock);
INIT_WORK(&port->work, usb_serial_port_softint, port);
serial->port[i] = port;
}

View File

@ -69,6 +69,7 @@
* usb_serial_port: structure for the specific ports of a device.
* @serial: pointer back to the struct usb_serial owner of this port.
* @tty: pointer to the corresponding tty for this port.
* @lock: spinlock to grab when updating portions of this structure.
* @number: the number of the port (the minor number).
* @interrupt_in_buffer: pointer to the interrupt in buffer for this port.
* @interrupt_in_urb: pointer to the interrupt in struct urb for this port.
@ -98,6 +99,7 @@
struct usb_serial_port {
struct usb_serial * serial;
struct tty_struct * tty;
spinlock_t lock;
unsigned char number;
unsigned char * interrupt_in_buffer;
@ -117,6 +119,7 @@ struct usb_serial_port {
unsigned char * bulk_out_buffer;
int bulk_out_size;
struct urb * write_urb;
int write_urb_busy;
__u8 bulk_out_endpointAddress;
wait_queue_head_t write_wait;

View File

@ -155,6 +155,15 @@ static int slave_configure(struct scsi_device *sdev)
* If this device makes that mistake, tell the sd driver. */
if (us->flags & US_FL_FIX_CAPACITY)
sdev->fix_capacity = 1;
/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
* Hardware Error) when any low-level error occurs,
* recoverable or not. Setting this flag tells the SCSI
* midlayer to retry such commands, which frequently will
* succeed and fix the error. The worst this can lead to
* is an occasional series of retries that will all fail. */
sdev->retry_hwerror = 1;
} else {
/* Non-disk-type devices don't need to blacklist any pages
@ -255,50 +264,23 @@ static int device_reset(struct scsi_cmnd *srb)
/* lock the device pointers and do the reset */
down(&(us->dev_semaphore));
if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
result = FAILED;
US_DEBUGP("No reset during disconnect\n");
} else
result = us->transport_reset(us);
result = us->transport_reset(us);
up(&(us->dev_semaphore));
return result;
return result < 0 ? FAILED : SUCCESS;
}
/* This resets the device's USB port. */
/* It refuses to work if there's more than one interface in
* the device, so that other users are not affected. */
/* Simulate a SCSI bus reset by resetting the device's USB port. */
/* This is always called with scsi_lock(host) held */
static int bus_reset(struct scsi_cmnd *srb)
{
struct us_data *us = host_to_us(srb->device->host);
int result, rc;
int result;
US_DEBUGP("%s called\n", __FUNCTION__);
/* The USB subsystem doesn't handle synchronisation between
* a device's several drivers. Therefore we reset only devices
* with just one interface, which we of course own. */
down(&(us->dev_semaphore));
if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
result = -EIO;
US_DEBUGP("No reset during disconnect\n");
} else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) {
result = -EBUSY;
US_DEBUGP("Refusing to reset a multi-interface device\n");
} else {
rc = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
if (rc < 0) {
US_DEBUGP("unable to lock device for reset: %d\n", rc);
result = rc;
} else {
result = usb_reset_device(us->pusb_dev);
if (rc)
usb_unlock_device(us->pusb_dev);
US_DEBUGP("usb_reset_device returns %d\n", result);
}
}
result = usb_stor_port_reset(us);
up(&(us->dev_semaphore));
/* lock the host for the return */
@ -320,6 +302,14 @@ void usb_stor_report_device_reset(struct us_data *us)
}
}
/* Report a driver-initiated bus reset to the SCSI layer.
* Calling this for a SCSI-initiated reset is unnecessary but harmless.
* The caller must own the SCSI host lock. */
void usb_stor_report_bus_reset(struct us_data *us)
{
scsi_report_bus_reset(us_to_host(us), 0);
}
/***********************************************************************
* /proc/scsi/ functions
***********************************************************************/

View File

@ -42,6 +42,7 @@
#define _SCSIGLUE_H_
extern void usb_stor_report_device_reset(struct us_data *us);
extern void usb_stor_report_bus_reset(struct us_data *us);
extern unsigned char usb_stor_sense_invalidCDB[18];
extern struct scsi_host_template usb_stor_host_template;

View File

@ -266,8 +266,9 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
NULL, 0, 3*HZ);
/* reset the endpoint toggle */
usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
usb_pipeout(pipe), 0);
if (result >= 0)
usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
usb_pipeout(pipe), 0);
US_DEBUGP("%s: result = %d\n", __FUNCTION__, result);
return result;
@ -540,15 +541,15 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
*/
if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
US_DEBUGP("-- command was aborted\n");
goto Handle_Abort;
srb->result = DID_ABORT << 16;
goto Handle_Errors;
}
/* if there is a transport error, reset and don't auto-sense */
if (result == USB_STOR_TRANSPORT_ERROR) {
US_DEBUGP("-- transport indicates error, resetting\n");
us->transport_reset(us);
srb->result = DID_ERROR << 16;
return;
goto Handle_Errors;
}
/* if the transport provided its own sense data, don't auto-sense */
@ -668,7 +669,8 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
US_DEBUGP("-- auto-sense aborted\n");
goto Handle_Abort;
srb->result = DID_ABORT << 16;
goto Handle_Errors;
}
if (temp_result != USB_STOR_TRANSPORT_GOOD) {
US_DEBUGP("-- auto-sense failure\n");
@ -677,9 +679,9 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
* multi-target device, since failure of an
* auto-sense is perfectly valid
*/
if (!(us->flags & US_FL_SCM_MULT_TARG))
us->transport_reset(us);
srb->result = DID_ERROR << 16;
if (!(us->flags & US_FL_SCM_MULT_TARG))
goto Handle_Errors;
return;
}
@ -720,12 +722,28 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
return;
/* abort processing: the bulk-only transport requires a reset
* following an abort */
Handle_Abort:
srb->result = DID_ABORT << 16;
if (us->protocol == US_PR_BULK)
/* Error and abort processing: try to resynchronize with the device
* by issuing a port reset. If that fails, try a class-specific
* device reset. */
Handle_Errors:
/* Let the SCSI layer know we are doing a reset, set the
* RESETTING bit, and clear the ABORTING bit so that the reset
* may proceed. */
scsi_lock(us_to_host(us));
usb_stor_report_bus_reset(us);
set_bit(US_FLIDX_RESETTING, &us->flags);
clear_bit(US_FLIDX_ABORTING, &us->flags);
scsi_unlock(us_to_host(us));
result = usb_stor_port_reset(us);
if (result < 0) {
scsi_lock(us_to_host(us));
usb_stor_report_device_reset(us);
scsi_unlock(us_to_host(us));
us->transport_reset(us);
}
clear_bit(US_FLIDX_RESETTING, &us->flags);
}
/* Stop the current URB transfer */
@ -1124,7 +1142,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
* It's handy that every transport mechanism uses the control endpoint for
* resets.
*
* Basically, we send a reset with a 20-second timeout, so we don't get
* Basically, we send a reset with a 5-second timeout, so we don't get
* jammed attempting to do the reset.
*/
static int usb_stor_reset_common(struct us_data *us,
@ -1133,28 +1151,18 @@ static int usb_stor_reset_common(struct us_data *us,
{
int result;
int result2;
int rc = FAILED;
/* Let the SCSI layer know we are doing a reset, set the
* RESETTING bit, and clear the ABORTING bit so that the reset
* may proceed.
*/
scsi_lock(us_to_host(us));
usb_stor_report_device_reset(us);
set_bit(US_FLIDX_RESETTING, &us->flags);
clear_bit(US_FLIDX_ABORTING, &us->flags);
scsi_unlock(us_to_host(us));
if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
US_DEBUGP("No reset during disconnect\n");
return -EIO;
}
/* A 20-second timeout may seem rather long, but a LaCie
* StudioDrive USB2 device takes 16+ seconds to get going
* following a powerup or USB attach event.
*/
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
request, requesttype, value, index, data, size,
20*HZ);
5*HZ);
if (result < 0) {
US_DEBUGP("Soft reset failed: %d\n", result);
goto Done;
return result;
}
/* Give the device some time to recover from the reset,
@ -1164,7 +1172,7 @@ static int usb_stor_reset_common(struct us_data *us,
HZ*6);
if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
US_DEBUGP("Reset interrupted by disconnect\n");
goto Done;
return -EIO;
}
US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n");
@ -1173,17 +1181,14 @@ static int usb_stor_reset_common(struct us_data *us,
US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n");
result2 = usb_stor_clear_halt(us, us->send_bulk_pipe);
/* return a result code based on the result of the control message */
if (result < 0 || result2 < 0) {
/* return a result code based on the result of the clear-halts */
if (result >= 0)
result = result2;
if (result < 0)
US_DEBUGP("Soft reset failed\n");
goto Done;
}
US_DEBUGP("Soft reset done\n");
rc = SUCCESS;
Done:
clear_bit(US_FLIDX_RESETTING, &us->flags);
return rc;
else
US_DEBUGP("Soft reset done\n");
return result;
}
/* This issues a CB[I] Reset to the device in question
@ -1213,3 +1218,32 @@ int usb_stor_Bulk_reset(struct us_data *us)
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum, NULL, 0);
}
/* Issue a USB port reset to the device. But don't do anything if
* there's more than one interface in the device, so that other users
* are not affected. */
int usb_stor_port_reset(struct us_data *us)
{
int result, rc;
if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
result = -EIO;
US_DEBUGP("No reset during disconnect\n");
} else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) {
result = -EBUSY;
US_DEBUGP("Refusing to reset a multi-interface device\n");
} else {
result = rc =
usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
if (result < 0) {
US_DEBUGP("unable to lock device for reset: %d\n",
result);
} else {
result = usb_reset_device(us->pusb_dev);
if (rc)
usb_unlock_device(us->pusb_dev);
US_DEBUGP("usb_reset_device returns %d\n", result);
}
}
return result;
}

View File

@ -171,4 +171,5 @@ extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
void *buf, unsigned int length, int use_sg, int *residual);
extern int usb_stor_port_reset(struct us_data *us);
#endif

View File

@ -47,6 +47,15 @@
# define HMC_TLLATTACH (1 << 6)
# define OTG_HMC(w) (((w)>>0)&0x3f)
#define OTG_CTRL_REG OTG_REG32(0x0c)
# define OTG_USB2_EN (1 << 29)
# define OTG_USB2_DP (1 << 28)
# define OTG_USB2_DM (1 << 27)
# define OTG_USB1_EN (1 << 26)
# define OTG_USB1_DP (1 << 25)
# define OTG_USB1_DM (1 << 24)
# define OTG_USB0_EN (1 << 23)
# define OTG_USB0_DP (1 << 22)
# define OTG_USB0_DM (1 << 21)
# define OTG_ASESSVLD (1 << 20)
# define OTG_BSESSEND (1 << 19)
# define OTG_BSESSVLD (1 << 18)

View File

@ -6,11 +6,14 @@
*
* - the master/host side Linux-USB kernel driver API;
* - the "usbfs" user space API; and
* - (eventually) a Linux "gadget" slave/device side driver API.
* - the Linux "gadget" slave/device/peripheral side driver API.
*
* USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems
* act either as a USB master/host or as a USB slave/device. That means
* the master and slave side APIs will benefit from working well together.
* the master and slave side APIs benefit from working well together.
*
* There's also "Wireless USB", using low power short range radios for
* peripheral interconnection but otherwise building on the USB framework.
*/
#ifndef __LINUX_USB_CH9_H
@ -68,6 +71,18 @@
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
#define USB_REQ_SET_ENCRYPTION 0x0D /* Wireless USB */
#define USB_REQ_GET_ENCRYPTION 0x0E
#define USB_REQ_SET_HANDSHAKE 0x0F
#define USB_REQ_GET_HANDSHAKE 0x10
#define USB_REQ_SET_CONNECTION 0x11
#define USB_REQ_SET_SECURITY_DATA 0x12
#define USB_REQ_GET_SECURITY_DATA 0x13
#define USB_REQ_SET_WUSB_DATA 0x14
#define USB_REQ_LOOPBACK_DATA_WRITE 0x15
#define USB_REQ_LOOPBACK_DATA_READ 0x16
#define USB_REQ_SET_INTERFACE_DS 0x17
/*
* USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and
* are read as a bit array returned by USB_REQ_GET_STATUS. (So there
@ -75,10 +90,12 @@
*/
#define USB_DEVICE_SELF_POWERED 0 /* (read only) */
#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */
#define USB_DEVICE_TEST_MODE 2 /* (high speed only) */
#define USB_DEVICE_B_HNP_ENABLE 3 /* dev may initiate HNP */
#define USB_DEVICE_A_HNP_SUPPORT 4 /* RH port supports HNP */
#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* other RH port does */
#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */
#define USB_DEVICE_BATTERY 2 /* (wireless) */
#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */
#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless)*/
#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */
#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */
#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */
#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */
@ -135,6 +152,13 @@ struct usb_ctrlrequest {
#define USB_DT_OTG 0x09
#define USB_DT_DEBUG 0x0a
#define USB_DT_INTERFACE_ASSOCIATION 0x0b
/* these are from the Wireless USB spec */
#define USB_DT_SECURITY 0x0c
#define USB_DT_KEY 0x0d
#define USB_DT_ENCRYPTION_TYPE 0x0e
#define USB_DT_BOS 0x0f
#define USB_DT_DEVICE_CAPABILITY 0x10
#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11
/* conventional codes for class-specific descriptors */
#define USB_DT_CS_DEVICE 0x21
@ -192,6 +216,7 @@ struct usb_device_descriptor {
#define USB_CLASS_CSCID 0x0b /* chip+ smart card */
#define USB_CLASS_CONTENT_SEC 0x0d /* content security */
#define USB_CLASS_VIDEO 0x0e
#define USB_CLASS_WIRELESS_CONTROLLER 0xe0
#define USB_CLASS_APP_SPEC 0xfe
#define USB_CLASS_VENDOR_SPEC 0xff
@ -223,6 +248,7 @@ struct usb_config_descriptor {
#define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */
#define USB_CONFIG_ATT_SELFPOWER (1 << 6) /* self powered */
#define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */
#define USB_CONFIG_ATT_BATTERY (1 << 4) /* battery powered */
/*-------------------------------------------------------------------------*/
@ -289,6 +315,7 @@ struct usb_endpoint_descriptor {
#define USB_ENDPOINT_XFER_ISOC 1
#define USB_ENDPOINT_XFER_BULK 2
#define USB_ENDPOINT_XFER_INT 3
#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80
/*-------------------------------------------------------------------------*/
@ -350,6 +377,147 @@ struct usb_interface_assoc_descriptor {
} __attribute__ ((packed));
/*-------------------------------------------------------------------------*/
/* USB_DT_SECURITY: group of wireless security descriptors, including
* encryption types available for setting up a CC/association.
*/
struct usb_security_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wTotalLength;
__u8 bNumEncryptionTypes;
};
/*-------------------------------------------------------------------------*/
/* USB_DT_KEY: used with {GET,SET}_SECURITY_DATA; only public keys
* may be retrieved.
*/
struct usb_key_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 tTKID[3];
__u8 bReserved;
__u8 bKeyData[0];
};
/*-------------------------------------------------------------------------*/
/* USB_DT_ENCRYPTION_TYPE: bundled in DT_SECURITY groups */
struct usb_encryption_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bEncryptionType;
#define USB_ENC_TYPE_UNSECURE 0
#define USB_ENC_TYPE_WIRED 1 /* non-wireless mode */
#define USB_ENC_TYPE_CCM_1 2 /* aes128/cbc session */
#define USB_ENC_TYPE_RSA_1 3 /* rsa3072/sha1 auth */
__u8 bEncryptionValue; /* use in SET_ENCRYPTION */
__u8 bAuthKeyIndex;
};
/*-------------------------------------------------------------------------*/
/* USB_DT_BOS: group of wireless capabilities */
struct usb_bos_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wTotalLength;
__u8 bNumDeviceCaps;
};
/*-------------------------------------------------------------------------*/
/* USB_DT_DEVICE_CAPABILITY: grouped with BOS */
struct usb_dev_cap_header {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDevCapabilityType;
};
#define USB_CAP_TYPE_WIRELESS_USB 1
struct usb_wireless_cap_descriptor { /* Ultra Wide Band */
__u8 bLength;
__u8 bDescriptorType;
__u8 bDevCapabilityType;
__u8 bmAttributes;
#define USB_WIRELESS_P2P_DRD (1 << 1)
#define USB_WIRELESS_BEACON_MASK (3 << 2)
#define USB_WIRELESS_BEACON_SELF (1 << 2)
#define USB_WIRELESS_BEACON_DIRECTED (2 << 2)
#define USB_WIRELESS_BEACON_NONE (3 << 2)
__le16 wPHYRates; /* bit rates, Mbps */
#define USB_WIRELESS_PHY_53 (1 << 0) /* always set */
#define USB_WIRELESS_PHY_80 (1 << 1)
#define USB_WIRELESS_PHY_107 (1 << 2) /* always set */
#define USB_WIRELESS_PHY_160 (1 << 3)
#define USB_WIRELESS_PHY_200 (1 << 4) /* always set */
#define USB_WIRELESS_PHY_320 (1 << 5)
#define USB_WIRELESS_PHY_400 (1 << 6)
#define USB_WIRELESS_PHY_480 (1 << 7)
__u8 bmTFITXPowerInfo; /* TFI power levels */
__u8 bmFFITXPowerInfo; /* FFI power levels */
__le16 bmBandGroup;
__u8 bReserved;
};
/*-------------------------------------------------------------------------*/
/* USB_DT_WIRELESS_ENDPOINT_COMP: companion descriptor associated with
* each endpoint descriptor for a wireless device
*/
struct usb_wireless_ep_comp_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bMaxBurst;
__u8 bMaxSequence;
__le16 wMaxStreamDelay;
__le16 wOverTheAirPacketSize;
__u8 bOverTheAirInterval;
__u8 bmCompAttributes;
#define USB_ENDPOINT_SWITCH_MASK 0x03 /* in bmCompAttributes */
#define USB_ENDPOINT_SWITCH_NO 0
#define USB_ENDPOINT_SWITCH_SWITCH 1
#define USB_ENDPOINT_SWITCH_SCALE 2
};
/*-------------------------------------------------------------------------*/
/* USB_REQ_SET_HANDSHAKE is a four-way handshake used between a wireless
* host and a device for connection set up, mutual authentication, and
* exchanging short lived session keys. The handshake depends on a CC.
*/
struct usb_handshake {
__u8 bMessageNumber;
__u8 bStatus;
__u8 tTKID[3];
__u8 bReserved;
__u8 CDID[16];
__u8 nonce[16];
__u8 MIC[8];
};
/*-------------------------------------------------------------------------*/
/* USB_REQ_SET_CONNECTION modifies or revokes a connection context (CC).
* A CC may also be set up using non-wireless secure channels (including
* wired USB!), and some devices may support CCs with multiple hosts.
*/
struct usb_connection_context {
__u8 CHID[16]; /* persistent host id */
__u8 CDID[16]; /* device id (unique w/in host context) */
__u8 CK[16]; /* connection key */
};
/*-------------------------------------------------------------------------*/
/* USB 2.0 defines three speeds, here's how Linux identifies them */
@ -357,7 +525,8 @@ struct usb_interface_assoc_descriptor {
enum usb_device_speed {
USB_SPEED_UNKNOWN = 0, /* enumerating */
USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */
USB_SPEED_HIGH /* usb 2.0 */
USB_SPEED_HIGH, /* usb 2.0 */
USB_SPEED_VARIABLE, /* wireless (usb 2.5) */
};
enum usb_device_state {

View File

@ -711,7 +711,7 @@ usb_gadget_disconnect (struct usb_gadget *gadget)
* the hardware level driver. Most calls must be handled by
* the gadget driver, including descriptor and configuration
* management. The 16 bit members of the setup data are in
* cpu order. Called in_interrupt; this may not sleep. Driver
* USB byte order. Called in_interrupt; this may not sleep. Driver
* queues a response to ep0, or returns negative to stall.
* @disconnect: Invoked after all transfers have been stopped,
* when the host is disconnected. May be called in_interrupt; this

View File

@ -0,0 +1,47 @@
/*
* Board initialization code should put one of these into dev->platform_data
* and place the isp116x onto platform_bus.
*/
struct isp116x_platform_data {
/* Enable internal resistors on downstream ports */
unsigned sel15Kres:1;
/* Chip's internal clock won't be stopped in suspended state.
Setting/unsetting this bit takes effect only if
'remote_wakeup_enable' below is not set. */
unsigned clknotstop:1;
/* On-chip overcurrent protection */
unsigned oc_enable:1;
/* INT output polarity */
unsigned int_act_high:1;
/* INT edge or level triggered */
unsigned int_edge_triggered:1;
/* WAKEUP pin connected - NOT SUPPORTED */
/* unsigned remote_wakeup_connected:1; */
/* Wakeup by devices on usb bus enabled */
unsigned remote_wakeup_enable:1;
/* Switch or not to switch (keep always powered) */
unsigned no_power_switching:1;
/* Ganged port power switching (0) or individual port
power switching (1) */
unsigned power_switching_mode:1;
/* Given port_power, msec/2 after power on till power good */
u8 potpg;
/* Hardware reset set/clear. If implemented, this function must:
if set == 0, deassert chip's HW reset pin
otherwise, assert chip's HW reset pin */
void (*reset) (struct device * dev, int set);
/* Hardware clock start/stop. If implemented, this function must:
if start == 0, stop the external clock
otherwise, start the external clock
*/
void (*clock) (struct device * dev, int start);
/* Inter-io delay (ns). The chip is picky about access timings; it
expects at least:
150ns delay between consecutive accesses to DATA_REG,
300ns delay between access to ADDR_REG and DATA_REG
OE, WE MUST NOT be changed during these intervals
*/
void (*delay) (struct device * dev, int delay);
};