mirror of https://gitee.com/openkylin/linux.git
Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
This commit is contained in:
commit
d3b8a1a849
|
@ -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,
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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);
|
File diff suppressed because it is too large
Load Diff
|
@ -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_ */
|
|
@ -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");
|
|
@ -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 @@ static int acm_probe (struct usb_interface *intf,
|
|||
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 @@ static int acm_probe (struct usb_interface *intf,
|
|||
}
|
||||
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 @@ static int acm_probe (struct usb_interface *intf,
|
|||
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 @@ static int acm_probe (struct usb_interface *intf,
|
|||
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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -519,119 +519,120 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
|
|||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
@ -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 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
|| !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 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
* 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 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
*/
|
||||
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 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|
|||
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 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
|
|||
|
||||
#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 @@ eth_bind (struct usb_gadget *gadget)
|
|||
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 @@ eth_bind (struct usb_gadget *gadget)
|
|||
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 @@ eth_bind (struct usb_gadget *gadget)
|
|||
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 @@ eth_bind (struct usb_gadget *gadget)
|
|||
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 @@ eth_bind (struct usb_gadget *gadget)
|
|||
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 @@ eth_bind (struct usb_gadget *gadget)
|
|||
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 @@ eth_bind (struct usb_gadget *gadget)
|
|||
/* 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 @@ eth_bind (struct usb_gadget *gadget)
|
|||
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,
|
||||
|
|
|
@ -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, "
|
||||
|
|
|
@ -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(®s->bRequestType);
|
||||
ctrl.bRequest = readl(®s->bRequest);
|
||||
ctrl.wValue = (readl(®s->wValueH) << 8) | readl(®s->wValueL);
|
||||
ctrl.wIndex = (readl(®s->wIndexH) << 8) | readl(®s->wIndexL);
|
||||
ctrl.wLength = (readl(®s->wLengthH) << 8) | readl(®s->wLengthL);
|
||||
ctrl.wValue = cpu_to_le16((readl(®s->wValueH) << 8)
|
||||
| readl(®s->wValueL));
|
||||
ctrl.wIndex = cpu_to_le16((readl(®s->wIndexH) << 8)
|
||||
| readl(®s->wIndexL));
|
||||
ctrl.wLength = cpu_to_le16((readl(®s->wLengthH) << 8)
|
||||
| readl(®s->wLengthL));
|
||||
writel(0, ®s->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 @@ static void ep0_setup(struct goku_udc *dev)
|
|||
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 @@ static void ep0_setup(struct goku_udc *dev)
|
|||
#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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
|
|||
*/
|
||||
}
|
||||
|
||||
#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
|
||||
|
|
|
@ -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 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
|
|||
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 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
|
|||
*/
|
||||
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 @@ static int __init omap_udc_probe(struct device *dev)
|
|||
|
||||
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");
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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 @@ static int __init pxa2xx_udc_probe(struct device *_dev)
|
|||
|
||||
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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 @@ static int ehci_start (struct usb_hcd *hcd)
|
|||
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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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) */
|
|
@ -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 @@ static int ohci_run (struct ohci_hcd *ohci)
|
|||
|
||||
// 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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) ?
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
***********************************************************************/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
};
|
Loading…
Reference in New Issue