mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (141 commits) USB: mct_u232: fix broken close USB: gadget: amd5536udc.c: fix error path USB: imx21-hcd - fix off by one resource size calculation usb: gadget: fix Kconfig warning usb: r8a66597-udc: Add processing when USB was removed. mxc_udc: add workaround for ENGcm09152 for i.MX35 USB: ftdi_sio: add device ids for ScienceScope USB: musb: AM35x: Workaround for fifo read issue USB: musb: add musb support for AM35x USB: AM35x: Add musb support usb: Fix linker errors with CONFIG_PM=n USB: ohci-sh - use resource_size instead of defining its own resource_len macro USB: isp1362-hcd - use resource_size instead of defining its own resource_len macro USB: isp116x-hcd - use resource_size instead of defining its own resource_len macro USB: xhci: Fix compile error when CONFIG_PM=n USB: accept some invalid ep0-maxpacket values USB: xHCI: PCI power management implementation USB: xHCI: bus power management implementation USB: xHCI: port remote wakeup implementation USB: xHCI: port power management implementation ... Manually fix up (non-data) conflict: the SCSI merge gad renamed the 'hw_sector_size' member to 'physical_block_size', and the USB tree brought a new use of it.
This commit is contained in:
commit
5cc1035062
179 changed files with 9945 additions and 2874 deletions
|
|
@ -59,6 +59,7 @@ config USB_ARCH_HAS_OHCI
|
|||
config USB_ARCH_HAS_EHCI
|
||||
boolean
|
||||
default y if PPC_83xx
|
||||
default y if PPC_MPC512x
|
||||
default y if SOC_AU1200
|
||||
default y if ARCH_IXP4XX
|
||||
default y if ARCH_W90X900
|
||||
|
|
|
|||
|
|
@ -2,12 +2,10 @@
|
|||
# Makefile for USB ATM/xDSL drivers
|
||||
#
|
||||
|
||||
ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
|
||||
|
||||
obj-$(CONFIG_USB_CXACRU) += cxacru.o
|
||||
obj-$(CONFIG_USB_SPEEDTOUCH) += speedtch.o
|
||||
obj-$(CONFIG_USB_UEAGLEATM) += ueagle-atm.o
|
||||
obj-$(CONFIG_USB_ATM) += usbatm.o
|
||||
obj-$(CONFIG_USB_XUSBATM) += xusbatm.o
|
||||
|
||||
ifeq ($(CONFIG_USB_DEBUG),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
# Makefile for Cypress C67X00 USB Controller
|
||||
#
|
||||
|
||||
ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG
|
||||
ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
|
||||
|
||||
obj-$(CONFIG_USB_C67X00_HCD) += c67x00.o
|
||||
obj-$(CONFIG_USB_C67X00_HCD) += c67x00.o
|
||||
|
||||
c67x00-objs := c67x00-drv.o c67x00-ll-hpi.o c67x00-hcd.o c67x00-sched.o
|
||||
c67x00-y := c67x00-drv.o c67x00-ll-hpi.o c67x00-hcd.o c67x00-sched.o
|
||||
|
|
|
|||
|
|
@ -1614,7 +1614,7 @@ static const struct usb_device_id acm_ids[] = {
|
|||
/* Support Lego NXT using pbLua firmware */
|
||||
{ USB_DEVICE(0x0694, 0xff00),
|
||||
.driver_info = NOT_A_MODEM,
|
||||
},
|
||||
},
|
||||
|
||||
/* control interfaces without any protocol set */
|
||||
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
|
||||
|
|
|
|||
|
|
@ -2,20 +2,13 @@
|
|||
# Makefile for USB Core files and filesystem
|
||||
#
|
||||
|
||||
usbcore-objs := usb.o hub.o hcd.o urb.o message.o driver.o \
|
||||
config.o file.o buffer.o sysfs.o endpoint.o \
|
||||
devio.o notify.o generic.o quirks.o devices.o
|
||||
ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
|
||||
|
||||
ifeq ($(CONFIG_PCI),y)
|
||||
usbcore-objs += hcd-pci.o
|
||||
endif
|
||||
usbcore-y := usb.o hub.o hcd.o urb.o message.o driver.o
|
||||
usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o
|
||||
usbcore-y += devio.o notify.o generic.o quirks.o devices.o
|
||||
|
||||
ifeq ($(CONFIG_USB_DEVICEFS),y)
|
||||
usbcore-objs += inode.o
|
||||
endif
|
||||
usbcore-$(CONFIG_PCI) += hcd-pci.o
|
||||
usbcore-$(CONFIG_USB_DEVICEFS) += inode.o
|
||||
|
||||
obj-$(CONFIG_USB) += usbcore.o
|
||||
|
||||
ifeq ($(CONFIG_USB_DEBUG),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
endif
|
||||
obj-$(CONFIG_USB) += usbcore.o
|
||||
|
|
|
|||
|
|
@ -66,8 +66,8 @@
|
|||
#define ALLOW_SERIAL_NUMBER
|
||||
|
||||
static const char *format_topo =
|
||||
/* T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=ddd MxCh=dd */
|
||||
"\nT: Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%3s MxCh=%2d\n";
|
||||
/* T: Bus=dd Lev=dd Prnt=dd Port=dd Cnt=dd Dev#=ddd Spd=dddd MxCh=dd */
|
||||
"\nT: Bus=%2.2d Lev=%2.2d Prnt=%2.2d Port=%2.2d Cnt=%2.2d Dev#=%3d Spd=%-4s MxCh=%2d\n";
|
||||
|
||||
static const char *format_string_manufacturer =
|
||||
/* S: Manufacturer=xxxx */
|
||||
|
|
@ -520,11 +520,14 @@ static ssize_t usb_device_dump(char __user **buffer, size_t *nbytes,
|
|||
speed = "1.5"; break;
|
||||
case USB_SPEED_UNKNOWN: /* usb 1.1 root hub code */
|
||||
case USB_SPEED_FULL:
|
||||
speed = "12 "; break;
|
||||
speed = "12"; break;
|
||||
case USB_SPEED_WIRELESS: /* Wireless has no real fixed speed */
|
||||
case USB_SPEED_HIGH:
|
||||
speed = "480"; break;
|
||||
case USB_SPEED_SUPER:
|
||||
speed = "5000"; break;
|
||||
default:
|
||||
speed = "?? ";
|
||||
speed = "??";
|
||||
}
|
||||
data_end = pages_start + sprintf(pages_start, format_topo,
|
||||
bus->busnum, level, parent_devnum,
|
||||
|
|
|
|||
|
|
@ -1337,7 +1337,7 @@ int usb_resume(struct device *dev, pm_message_t msg)
|
|||
/* Avoid PM error messages for devices disconnected while suspended
|
||||
* as we'll display regular disconnect messages just a bit later.
|
||||
*/
|
||||
if (status == -ENODEV)
|
||||
if (status == -ENODEV || status == -ESHUTDOWN)
|
||||
status = 0;
|
||||
return status;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ int usb_create_ep_devs(struct device *parent,
|
|||
return retval;
|
||||
|
||||
error_register:
|
||||
kfree(ep_dev);
|
||||
put_device(&ep_dev->dev);
|
||||
exit:
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -329,8 +329,10 @@ void usb_hcd_pci_shutdown(struct pci_dev *dev)
|
|||
return;
|
||||
|
||||
if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) &&
|
||||
hcd->driver->shutdown)
|
||||
hcd->driver->shutdown) {
|
||||
hcd->driver->shutdown(hcd);
|
||||
pci_disable_device(dev);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown);
|
||||
|
||||
|
|
|
|||
|
|
@ -1263,10 +1263,8 @@ static void hcd_free_coherent(struct usb_bus *bus, dma_addr_t *dma_handle,
|
|||
*dma_handle = 0;
|
||||
}
|
||||
|
||||
static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
|
||||
void unmap_urb_setup_for_dma(struct usb_hcd *hcd, struct urb *urb)
|
||||
{
|
||||
enum dma_data_direction dir;
|
||||
|
||||
if (urb->transfer_flags & URB_SETUP_MAP_SINGLE)
|
||||
dma_unmap_single(hcd->self.controller,
|
||||
urb->setup_dma,
|
||||
|
|
@ -1279,6 +1277,17 @@ static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
|
|||
sizeof(struct usb_ctrlrequest),
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
/* Make it safe to call this routine more than once */
|
||||
urb->transfer_flags &= ~(URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unmap_urb_setup_for_dma);
|
||||
|
||||
void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
|
||||
{
|
||||
enum dma_data_direction dir;
|
||||
|
||||
unmap_urb_setup_for_dma(hcd, urb);
|
||||
|
||||
dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
|
||||
if (urb->transfer_flags & URB_DMA_MAP_SG)
|
||||
dma_unmap_sg(hcd->self.controller,
|
||||
|
|
@ -1303,10 +1312,10 @@ static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
|
|||
dir);
|
||||
|
||||
/* Make it safe to call this routine more than once */
|
||||
urb->transfer_flags &= ~(URB_SETUP_MAP_SINGLE | URB_SETUP_MAP_LOCAL |
|
||||
URB_DMA_MAP_SG | URB_DMA_MAP_PAGE |
|
||||
urb->transfer_flags &= ~(URB_DMA_MAP_SG | URB_DMA_MAP_PAGE |
|
||||
URB_DMA_MAP_SINGLE | URB_MAP_LOCAL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unmap_urb_for_dma);
|
||||
|
||||
static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
|
||||
gfp_t mem_flags)
|
||||
|
|
|
|||
|
|
@ -758,6 +758,9 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
|||
clear_port_feature(hdev, port1,
|
||||
USB_PORT_FEAT_ENABLE);
|
||||
portstatus &= ~USB_PORT_STAT_ENABLE;
|
||||
} else {
|
||||
/* Pretend that power was lost for USB3 devs */
|
||||
portstatus &= ~USB_PORT_STAT_ENABLE;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2594,16 +2597,14 @@ static int hub_set_address(struct usb_device *udev, int devnum)
|
|||
return 0;
|
||||
if (udev->state != USB_STATE_DEFAULT)
|
||||
return -EINVAL;
|
||||
if (hcd->driver->address_device) {
|
||||
if (hcd->driver->address_device)
|
||||
retval = hcd->driver->address_device(hcd, udev);
|
||||
} else {
|
||||
else
|
||||
retval = usb_control_msg(udev, usb_sndaddr0pipe(),
|
||||
USB_REQ_SET_ADDRESS, 0, devnum, 0,
|
||||
NULL, 0, USB_CTRL_SET_TIMEOUT);
|
||||
if (retval == 0)
|
||||
update_address(udev, devnum);
|
||||
}
|
||||
if (retval == 0) {
|
||||
update_address(udev, devnum);
|
||||
/* Device now using proper address. */
|
||||
usb_set_device_state(udev, USB_STATE_ADDRESS);
|
||||
usb_ep0_reinit(udev);
|
||||
|
|
@ -2860,13 +2861,16 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
|
|||
else
|
||||
i = udev->descriptor.bMaxPacketSize0;
|
||||
if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
|
||||
if (udev->speed != USB_SPEED_FULL ||
|
||||
if (udev->speed == USB_SPEED_LOW ||
|
||||
!(i == 8 || i == 16 || i == 32 || i == 64)) {
|
||||
dev_err(&udev->dev, "ep0 maxpacket = %d\n", i);
|
||||
dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", i);
|
||||
retval = -EMSGSIZE;
|
||||
goto fail;
|
||||
}
|
||||
dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
|
||||
if (udev->speed == USB_SPEED_FULL)
|
||||
dev_dbg(&udev->dev, "ep0 maxpacket = %d\n", i);
|
||||
else
|
||||
dev_warn(&udev->dev, "Using ep0 maxpacket: %d\n", i);
|
||||
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(i);
|
||||
usb_ep0_reinit(udev);
|
||||
}
|
||||
|
|
@ -3097,16 +3101,17 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
|||
udev->speed = USB_SPEED_UNKNOWN;
|
||||
|
||||
/*
|
||||
* xHCI needs to issue an address device command later
|
||||
* in the hub_port_init sequence for SS/HS/FS/LS devices.
|
||||
* Set the address.
|
||||
* Note xHCI needs to issue an address device command later
|
||||
* in the hub_port_init sequence for SS/HS/FS/LS devices,
|
||||
* and xHC will assign an address to the device. But use
|
||||
* kernel assigned address here, to avoid any address conflict
|
||||
* issue.
|
||||
*/
|
||||
if (!(hcd->driver->flags & HCD_USB3)) {
|
||||
/* set the address */
|
||||
choose_address(udev);
|
||||
if (udev->devnum <= 0) {
|
||||
status = -ENOTCONN; /* Don't retry */
|
||||
goto loop;
|
||||
}
|
||||
choose_address(udev);
|
||||
if (udev->devnum <= 0) {
|
||||
status = -ENOTCONN; /* Don't retry */
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/* reset (non-USB 3.0 devices) and get descriptor */
|
||||
|
|
@ -3629,7 +3634,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
|
|||
}
|
||||
|
||||
if (!parent_hdev) {
|
||||
/* this requires hcd-specific logic; see OHCI hc_restart() */
|
||||
/* this requires hcd-specific logic; see ohci_restart() */
|
||||
dev_dbg(&udev->dev, "%s for root hub!\n", __func__);
|
||||
return -EISDIR;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1140,13 +1140,6 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
|
|||
{
|
||||
int i;
|
||||
|
||||
dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__,
|
||||
skip_ep0 ? "non-ep0" : "all");
|
||||
for (i = skip_ep0; i < 16; ++i) {
|
||||
usb_disable_endpoint(dev, i, true);
|
||||
usb_disable_endpoint(dev, i + USB_DIR_IN, true);
|
||||
}
|
||||
|
||||
/* getting rid of interfaces will disconnect
|
||||
* any drivers bound to them (a key side effect)
|
||||
*/
|
||||
|
|
@ -1176,6 +1169,13 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
|
|||
if (dev->state == USB_STATE_CONFIGURED)
|
||||
usb_set_device_state(dev, USB_STATE_ADDRESS);
|
||||
}
|
||||
|
||||
dev_dbg(&dev->dev, "%s nuking %s URBs\n", __func__,
|
||||
skip_ep0 ? "non-ep0" : "all");
|
||||
for (i = skip_ep0; i < 16; ++i) {
|
||||
usb_disable_endpoint(dev, i, true);
|
||||
usb_disable_endpoint(dev, i + USB_DIR_IN, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -401,8 +401,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
|||
};
|
||||
|
||||
/* Check that the pipe's type matches the endpoint's type */
|
||||
if (usb_pipetype(urb->pipe) != pipetypes[xfertype])
|
||||
if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) {
|
||||
dev_err(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
|
||||
usb_pipetype(urb->pipe), pipetypes[xfertype]);
|
||||
return -EPIPE; /* The most suitable error code :-) */
|
||||
}
|
||||
|
||||
/* enforce simple/standard policy */
|
||||
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK |
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@
|
|||
# Makefile for early USB devices
|
||||
#
|
||||
|
||||
obj-$(CONFIG_EARLY_PRINTK_DBGP) += ehci-dbgp.o
|
||||
obj-$(CONFIG_EARLY_PRINTK_DBGP) += ehci-dbgp.o
|
||||
|
|
|
|||
|
|
@ -158,6 +158,7 @@ config USB_GADGET_FSL_USB2
|
|||
boolean "Freescale Highspeed USB DR Peripheral Controller"
|
||||
depends on FSL_SOC || ARCH_MXC
|
||||
select USB_GADGET_DUALSPEED
|
||||
select USB_FSL_MPH_DR_OF
|
||||
help
|
||||
Some of Freescale PowerPC processors have a High Speed
|
||||
Dual-Role(DR) USB controller, which supports device mode.
|
||||
|
|
@ -209,17 +210,6 @@ config USB_OMAP
|
|||
default USB_GADGET
|
||||
select USB_GADGET_SELECTED
|
||||
|
||||
config USB_OTG
|
||||
boolean "OTG Support"
|
||||
depends on USB_GADGET_OMAP && ARCH_OMAP_OTG && USB_OHCI_HCD
|
||||
help
|
||||
The most notable feature of USB OTG is support for a
|
||||
"Dual-Role" device, which can act as either a device
|
||||
or a host. The initial role choice can be changed
|
||||
later, when two dual-role devices talk to each other.
|
||||
|
||||
Select this only if your OMAP board has a Mini-AB connector.
|
||||
|
||||
config USB_GADGET_PXA25X
|
||||
boolean "PXA 25x or IXP 4xx"
|
||||
depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
|
||||
|
|
@ -716,8 +706,8 @@ config USB_FUNCTIONFS
|
|||
depends on EXPERIMENTAL
|
||||
select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS)
|
||||
help
|
||||
The Function Filesystem (FunctioFS) lets one create USB
|
||||
composite functions in user space in the same way as GadgetFS
|
||||
The Function Filesystem (FunctionFS) lets one create USB
|
||||
composite functions in user space in the same way GadgetFS
|
||||
lets one create USB gadgets in user space. This allows creation
|
||||
of composite gadgets such that some of the functions are
|
||||
implemented in kernel space (for instance Ethernet, serial or
|
||||
|
|
@ -733,14 +723,14 @@ config USB_FUNCTIONFS_ETH
|
|||
bool "Include configuration with CDC ECM (Ethernet)"
|
||||
depends on USB_FUNCTIONFS && NET
|
||||
help
|
||||
Include a configuration with CDC ECM funcion (Ethernet) and the
|
||||
Funcion Filesystem.
|
||||
Include a configuration with CDC ECM function (Ethernet) and the
|
||||
Function Filesystem.
|
||||
|
||||
config USB_FUNCTIONFS_RNDIS
|
||||
bool "Include configuration with RNDIS (Ethernet)"
|
||||
depends on USB_FUNCTIONFS && NET
|
||||
help
|
||||
Include a configuration with RNDIS funcion (Ethernet) and the Filesystem.
|
||||
Include a configuration with RNDIS function (Ethernet) and the Filesystem.
|
||||
|
||||
config USB_FUNCTIONFS_GENERIC
|
||||
bool "Include 'pure' configuration"
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
#
|
||||
# USB peripheral controller drivers
|
||||
#
|
||||
ifeq ($(CONFIG_USB_GADGET_DEBUG),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
endif
|
||||
ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
|
||||
|
||||
obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o
|
||||
obj-$(CONFIG_USB_NET2280) += net2280.o
|
||||
|
|
@ -18,10 +16,8 @@ obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o
|
|||
obj-$(CONFIG_USB_AT91) += at91_udc.o
|
||||
obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
|
||||
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
|
||||
fsl_usb2_udc-objs := fsl_udc_core.o
|
||||
ifeq ($(CONFIG_ARCH_MXC),y)
|
||||
fsl_usb2_udc-objs += fsl_mxc_udc.o
|
||||
endif
|
||||
fsl_usb2_udc-y := fsl_udc_core.o
|
||||
fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o
|
||||
obj-$(CONFIG_USB_M66592) += m66592-udc.o
|
||||
obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o
|
||||
obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
|
||||
|
|
@ -32,21 +28,21 @@ obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o
|
|||
#
|
||||
# USB gadget drivers
|
||||
#
|
||||
g_zero-objs := zero.o
|
||||
g_audio-objs := audio.o
|
||||
g_ether-objs := ether.o
|
||||
g_serial-objs := serial.o
|
||||
g_midi-objs := gmidi.o
|
||||
gadgetfs-objs := inode.o
|
||||
g_file_storage-objs := file_storage.o
|
||||
g_mass_storage-objs := mass_storage.o
|
||||
g_printer-objs := printer.o
|
||||
g_cdc-objs := cdc2.o
|
||||
g_multi-objs := multi.o
|
||||
g_hid-objs := hid.o
|
||||
g_dbgp-objs := dbgp.o
|
||||
g_nokia-objs := nokia.o
|
||||
g_webcam-objs := webcam.o
|
||||
g_zero-y := zero.o
|
||||
g_audio-y := audio.o
|
||||
g_ether-y := ether.o
|
||||
g_serial-y := serial.o
|
||||
g_midi-y := gmidi.o
|
||||
gadgetfs-y := inode.o
|
||||
g_file_storage-y := file_storage.o
|
||||
g_mass_storage-y := mass_storage.o
|
||||
g_printer-y := printer.o
|
||||
g_cdc-y := cdc2.o
|
||||
g_multi-y := multi.o
|
||||
g_hid-y := hid.o
|
||||
g_dbgp-y := dbgp.o
|
||||
g_nokia-y := nokia.o
|
||||
g_webcam-y := webcam.o
|
||||
|
||||
obj-$(CONFIG_USB_ZERO) += g_zero.o
|
||||
obj-$(CONFIG_USB_AUDIO) += g_audio.o
|
||||
|
|
@ -64,4 +60,3 @@ obj-$(CONFIG_USB_G_DBGP) += g_dbgp.o
|
|||
obj-$(CONFIG_USB_G_MULTI) += g_multi.o
|
||||
obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o
|
||||
obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o
|
||||
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ static void print_regs(struct udc *dev)
|
|||
DBG(dev, "DMA mode = PPBNDU (packet per buffer "
|
||||
"WITHOUT desc. update)\n");
|
||||
dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBNDU");
|
||||
} else if (use_dma && use_dma_ppb_du && use_dma_ppb_du) {
|
||||
} else if (use_dma && use_dma_ppb && use_dma_ppb_du) {
|
||||
DBG(dev, "DMA mode = PPBDU (packet per buffer "
|
||||
"WITH desc. update)\n");
|
||||
dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBDU");
|
||||
|
|
@ -1954,13 +1954,14 @@ static int setup_ep0(struct udc *dev)
|
|||
}
|
||||
|
||||
/* Called by gadget driver to register itself */
|
||||
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct udc *dev = udc;
|
||||
int retval;
|
||||
u32 tmp;
|
||||
|
||||
if (!driver || !driver->bind || !driver->setup
|
||||
if (!driver || !bind || !driver->setup
|
||||
|| driver->speed != USB_SPEED_HIGH)
|
||||
return -EINVAL;
|
||||
if (!dev)
|
||||
|
|
@ -1972,7 +1973,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
dev->driver = driver;
|
||||
dev->gadget.dev.driver = &driver->driver;
|
||||
|
||||
retval = driver->bind(&dev->gadget);
|
||||
retval = bind(&dev->gadget);
|
||||
|
||||
/* Some gadget drivers use both ep0 directions.
|
||||
* NOTE: to gadget driver, ep0 is just one endpoint...
|
||||
|
|
@ -2000,7 +2001,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_register_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
/* shutdown requests and disconnect from gadget */
|
||||
static void
|
||||
|
|
@ -3382,8 +3383,10 @@ static int udc_probe(struct udc *dev)
|
|||
udc = dev;
|
||||
|
||||
retval = device_register(&dev->gadget.dev);
|
||||
if (retval)
|
||||
if (retval) {
|
||||
put_device(&dev->gadget.dev);
|
||||
goto finished;
|
||||
}
|
||||
|
||||
/* timer init */
|
||||
init_timer(&udc_timer);
|
||||
|
|
|
|||
|
|
@ -1628,7 +1628,8 @@ static void at91_vbus_timer(unsigned long data)
|
|||
schedule_work(&udc->vbus_timer_work);
|
||||
}
|
||||
|
||||
int usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct at91_udc *udc = &controller;
|
||||
int retval;
|
||||
|
|
@ -1636,7 +1637,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
|||
|
||||
if (!driver
|
||||
|| driver->speed < USB_SPEED_FULL
|
||||
|| !driver->bind
|
||||
|| !bind
|
||||
|| !driver->setup) {
|
||||
DBG("bad parameter.\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -1653,9 +1654,9 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
|||
udc->enabled = 1;
|
||||
udc->selfpowered = 1;
|
||||
|
||||
retval = driver->bind(&udc->gadget);
|
||||
retval = bind(&udc->gadget);
|
||||
if (retval) {
|
||||
DBG("driver->bind() returned %d\n", retval);
|
||||
DBG("bind() returned %d\n", retval);
|
||||
udc->driver = NULL;
|
||||
udc->gadget.dev.driver = NULL;
|
||||
dev_set_drvdata(&udc->gadget.dev, NULL);
|
||||
|
|
@ -1671,7 +1672,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
|||
DBG("bound to %s\n", driver->driver.name);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL (usb_gadget_register_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1789,7 +1789,8 @@ out:
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct usba_udc *udc = &the_udc;
|
||||
unsigned long flags;
|
||||
|
|
@ -1812,7 +1813,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
clk_enable(udc->pclk);
|
||||
clk_enable(udc->hclk);
|
||||
|
||||
ret = driver->bind(&udc->gadget);
|
||||
ret = bind(&udc->gadget);
|
||||
if (ret) {
|
||||
DBG(DBG_ERR, "Could not bind to driver %s: error %d\n",
|
||||
driver->driver.name, ret);
|
||||
|
|
@ -1841,7 +1842,7 @@ err_driver_bind:
|
|||
udc->gadget.dev.driver = NULL;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_register_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
{
|
||||
|
|
@ -2014,6 +2015,9 @@ static int __init usba_udc_probe(struct platform_device *pdev)
|
|||
} else {
|
||||
disable_irq(gpio_to_irq(udc->vbus_pin));
|
||||
}
|
||||
} else {
|
||||
/* gpio_request fail so use -EINVAL for gpio_is_valid */
|
||||
ubc->vbus_pin = -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ static const struct usb_descriptor_header *otg_desc[] = {
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __ref audio_do_config(struct usb_configuration *c)
|
||||
static int __init audio_do_config(struct usb_configuration *c)
|
||||
{
|
||||
/* FIXME alloc iConfiguration string, set it in c->strings */
|
||||
|
||||
|
|
@ -105,7 +105,6 @@ static int __ref audio_do_config(struct usb_configuration *c)
|
|||
|
||||
static struct usb_configuration audio_config_driver = {
|
||||
.label = DRIVER_DESC,
|
||||
.bind = audio_do_config,
|
||||
.bConfigurationValue = 1,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
|
|
@ -113,7 +112,7 @@ static struct usb_configuration audio_config_driver = {
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __ref audio_bind(struct usb_composite_dev *cdev)
|
||||
static int __init audio_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
int gcnum;
|
||||
int status;
|
||||
|
|
@ -145,7 +144,7 @@ static int __ref audio_bind(struct usb_composite_dev *cdev)
|
|||
strings_dev[STRING_PRODUCT_IDX].id = status;
|
||||
device_desc.iProduct = status;
|
||||
|
||||
status = usb_add_config(cdev, &audio_config_driver);
|
||||
status = usb_add_config(cdev, &audio_config_driver, audio_do_config);
|
||||
if (status < 0)
|
||||
goto fail;
|
||||
|
||||
|
|
@ -166,13 +165,12 @@ static struct usb_composite_driver audio_driver = {
|
|||
.name = "g_audio",
|
||||
.dev = &device_desc,
|
||||
.strings = audio_strings,
|
||||
.bind = audio_bind,
|
||||
.unbind = __exit_p(audio_unbind),
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
{
|
||||
return usb_composite_register(&audio_driver);
|
||||
return usb_composite_probe(&audio_driver, audio_bind);
|
||||
}
|
||||
module_init(init);
|
||||
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ static u8 hostaddr[ETH_ALEN];
|
|||
/*
|
||||
* We _always_ have both CDC ECM and CDC ACM functions.
|
||||
*/
|
||||
static int __ref cdc_do_config(struct usb_configuration *c)
|
||||
static int __init cdc_do_config(struct usb_configuration *c)
|
||||
{
|
||||
int status;
|
||||
|
||||
|
|
@ -151,7 +151,6 @@ static int __ref cdc_do_config(struct usb_configuration *c)
|
|||
|
||||
static struct usb_configuration cdc_config_driver = {
|
||||
.label = "CDC Composite (ECM + ACM)",
|
||||
.bind = cdc_do_config,
|
||||
.bConfigurationValue = 1,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
|
|
@ -159,7 +158,7 @@ static struct usb_configuration cdc_config_driver = {
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __ref cdc_bind(struct usb_composite_dev *cdev)
|
||||
static int __init cdc_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
int gcnum;
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
|
|
@ -218,7 +217,7 @@ static int __ref cdc_bind(struct usb_composite_dev *cdev)
|
|||
device_desc.iProduct = status;
|
||||
|
||||
/* register our configuration */
|
||||
status = usb_add_config(cdev, &cdc_config_driver);
|
||||
status = usb_add_config(cdev, &cdc_config_driver, cdc_do_config);
|
||||
if (status < 0)
|
||||
goto fail1;
|
||||
|
||||
|
|
@ -245,7 +244,6 @@ static struct usb_composite_driver cdc_driver = {
|
|||
.name = "g_cdc",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.bind = cdc_bind,
|
||||
.unbind = __exit_p(cdc_unbind),
|
||||
};
|
||||
|
||||
|
|
@ -255,7 +253,7 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
static int __init init(void)
|
||||
{
|
||||
return usb_composite_register(&cdc_driver);
|
||||
return usb_composite_probe(&cdc_driver, cdc_bind);
|
||||
}
|
||||
module_init(init);
|
||||
|
||||
|
|
|
|||
|
|
@ -2340,12 +2340,15 @@ static const struct usb_ep_ops usb_ep_ops = {
|
|||
static const struct usb_gadget_ops usb_gadget_ops;
|
||||
|
||||
/**
|
||||
* usb_gadget_register_driver: register a gadget driver
|
||||
* usb_gadget_probe_driver: register a gadget driver
|
||||
* @driver: the driver being registered
|
||||
* @bind: the driver's bind callback
|
||||
*
|
||||
* Check usb_gadget_register_driver() at "usb_gadget.h" for details
|
||||
* Interrupts are enabled here
|
||||
* Check usb_gadget_probe_driver() at <linux/usb/gadget.h> for details.
|
||||
* Interrupts are enabled here.
|
||||
*/
|
||||
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct ci13xxx *udc = _udc;
|
||||
unsigned long i, k, flags;
|
||||
|
|
@ -2354,7 +2357,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
trace("%p", driver);
|
||||
|
||||
if (driver == NULL ||
|
||||
driver->bind == NULL ||
|
||||
bind == NULL ||
|
||||
driver->unbind == NULL ||
|
||||
driver->setup == NULL ||
|
||||
driver->disconnect == NULL ||
|
||||
|
|
@ -2430,7 +2433,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
udc->gadget.dev.driver = &driver->driver;
|
||||
|
||||
spin_unlock_irqrestore(udc->lock, flags);
|
||||
retval = driver->bind(&udc->gadget); /* MAY SLEEP */
|
||||
retval = bind(&udc->gadget); /* MAY SLEEP */
|
||||
spin_lock_irqsave(udc->lock, flags);
|
||||
|
||||
if (retval) {
|
||||
|
|
@ -2447,7 +2450,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
usb_gadget_unregister_driver(driver);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_register_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
/**
|
||||
* usb_gadget_unregister_driver: unregister a gadget driver
|
||||
|
|
@ -2462,7 +2465,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
|||
trace("%p", driver);
|
||||
|
||||
if (driver == NULL ||
|
||||
driver->bind == NULL ||
|
||||
driver->unbind == NULL ||
|
||||
driver->setup == NULL ||
|
||||
driver->disconnect == NULL ||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/utsname.h>
|
||||
|
||||
#include <linux/usb/composite.h>
|
||||
|
||||
|
|
@ -39,6 +40,7 @@
|
|||
#define USB_BUFSIZ 1024
|
||||
|
||||
static struct usb_composite_driver *composite;
|
||||
static int (*composite_gadget_bind)(struct usb_composite_dev *cdev);
|
||||
|
||||
/* Some systems will need runtime overrides for the product identifers
|
||||
* published in the device descriptor, either numbers or strings or both.
|
||||
|
|
@ -69,6 +71,8 @@ static char *iSerialNumber;
|
|||
module_param(iSerialNumber, charp, 0);
|
||||
MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
|
||||
|
||||
static char composite_manufacturer[50];
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
|
|
@ -470,18 +474,20 @@ done:
|
|||
* usb_add_config() - add a configuration to a device.
|
||||
* @cdev: wraps the USB gadget
|
||||
* @config: the configuration, with bConfigurationValue assigned
|
||||
* @bind: the configuration's bind function
|
||||
* Context: single threaded during gadget setup
|
||||
*
|
||||
* One of the main tasks of a composite driver's bind() routine is to
|
||||
* One of the main tasks of a composite @bind() routine is to
|
||||
* add each of the configurations it supports, using this routine.
|
||||
*
|
||||
* This function returns the value of the configuration's bind(), which
|
||||
* This function returns the value of the configuration's @bind(), which
|
||||
* is zero for success else a negative errno value. Binding configurations
|
||||
* assigns global resources including string IDs, and per-configuration
|
||||
* resources such as interface IDs and endpoints.
|
||||
*/
|
||||
int usb_add_config(struct usb_composite_dev *cdev,
|
||||
struct usb_configuration *config)
|
||||
struct usb_configuration *config,
|
||||
int (*bind)(struct usb_configuration *))
|
||||
{
|
||||
int status = -EINVAL;
|
||||
struct usb_configuration *c;
|
||||
|
|
@ -490,7 +496,7 @@ int usb_add_config(struct usb_composite_dev *cdev,
|
|||
config->bConfigurationValue,
|
||||
config->label, config);
|
||||
|
||||
if (!config->bConfigurationValue || !config->bind)
|
||||
if (!config->bConfigurationValue || !bind)
|
||||
goto done;
|
||||
|
||||
/* Prevent duplicate configuration identifiers */
|
||||
|
|
@ -507,7 +513,7 @@ int usb_add_config(struct usb_composite_dev *cdev,
|
|||
INIT_LIST_HEAD(&config->functions);
|
||||
config->next_interface_id = 0;
|
||||
|
||||
status = config->bind(config);
|
||||
status = bind(config);
|
||||
if (status < 0) {
|
||||
list_del(&config->list);
|
||||
config->cdev = NULL;
|
||||
|
|
@ -533,7 +539,7 @@ int usb_add_config(struct usb_composite_dev *cdev,
|
|||
}
|
||||
}
|
||||
|
||||
/* set_alt(), or next config->bind(), sets up
|
||||
/* set_alt(), or next bind(), sets up
|
||||
* ep->driver_data as needed.
|
||||
*/
|
||||
usb_ep_autoconfig_reset(cdev->gadget);
|
||||
|
|
@ -599,6 +605,7 @@ static int get_string(struct usb_composite_dev *cdev,
|
|||
struct usb_configuration *c;
|
||||
struct usb_function *f;
|
||||
int len;
|
||||
const char *str;
|
||||
|
||||
/* Yes, not only is USB's I18N support probably more than most
|
||||
* folk will ever care about ... also, it's all supported here.
|
||||
|
|
@ -638,9 +645,29 @@ static int get_string(struct usb_composite_dev *cdev,
|
|||
return s->bLength;
|
||||
}
|
||||
|
||||
/* Otherwise, look up and return a specified string. String IDs
|
||||
* are device-scoped, so we look up each string table we're told
|
||||
* about. These lookups are infrequent; simpler-is-better here.
|
||||
/* Otherwise, look up and return a specified string. First
|
||||
* check if the string has not been overridden.
|
||||
*/
|
||||
if (cdev->manufacturer_override == id)
|
||||
str = iManufacturer ?: composite->iManufacturer ?:
|
||||
composite_manufacturer;
|
||||
else if (cdev->product_override == id)
|
||||
str = iProduct ?: composite->iProduct;
|
||||
else if (cdev->serial_override == id)
|
||||
str = iSerialNumber;
|
||||
else
|
||||
str = NULL;
|
||||
if (str) {
|
||||
struct usb_gadget_strings strings = {
|
||||
.language = language,
|
||||
.strings = &(struct usb_string) { 0xff, str }
|
||||
};
|
||||
return usb_gadget_get_string(&strings, 0xff, buf);
|
||||
}
|
||||
|
||||
/* String IDs are device-scoped, so we look up each string
|
||||
* table we're told about. These lookups are infrequent;
|
||||
* simpler-is-better here.
|
||||
*/
|
||||
if (composite->strings) {
|
||||
len = lookup_string(composite->strings, buf, language, id);
|
||||
|
|
@ -901,7 +928,8 @@ unknown:
|
|||
*/
|
||||
switch (ctrl->bRequestType & USB_RECIP_MASK) {
|
||||
case USB_RECIP_INTERFACE:
|
||||
f = cdev->config->interface[intf];
|
||||
if (cdev->config)
|
||||
f = cdev->config->interface[intf];
|
||||
break;
|
||||
|
||||
case USB_RECIP_ENDPOINT:
|
||||
|
|
@ -1025,26 +1053,17 @@ composite_unbind(struct usb_gadget *gadget)
|
|||
composite = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
string_override_one(struct usb_gadget_strings *tab, u8 id, const char *s)
|
||||
static u8 override_id(struct usb_composite_dev *cdev, u8 *desc)
|
||||
{
|
||||
struct usb_string *str = tab->strings;
|
||||
|
||||
for (str = tab->strings; str->s; str++) {
|
||||
if (str->id == id) {
|
||||
str->s = s;
|
||||
return;
|
||||
}
|
||||
if (!*desc) {
|
||||
int ret = usb_string_id(cdev);
|
||||
if (unlikely(ret < 0))
|
||||
WARNING(cdev, "failed to override string ID\n");
|
||||
else
|
||||
*desc = ret;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
string_override(struct usb_gadget_strings **tab, u8 id, const char *s)
|
||||
{
|
||||
while (*tab) {
|
||||
string_override_one(*tab, id, s);
|
||||
tab++;
|
||||
}
|
||||
return *desc;
|
||||
}
|
||||
|
||||
static int composite_bind(struct usb_gadget *gadget)
|
||||
|
|
@ -1074,7 +1093,13 @@ static int composite_bind(struct usb_gadget *gadget)
|
|||
cdev->bufsiz = USB_BUFSIZ;
|
||||
cdev->driver = composite;
|
||||
|
||||
usb_gadget_set_selfpowered(gadget);
|
||||
/*
|
||||
* As per USB compliance update, a device that is actively drawing
|
||||
* more than 100mA from USB must report itself as bus-powered in
|
||||
* the GetStatus(DEVICE) call.
|
||||
*/
|
||||
if (CONFIG_USB_GADGET_VBUS_DRAW <= USB_SELF_POWER_VBUS_MAX_DRAW)
|
||||
usb_gadget_set_selfpowered(gadget);
|
||||
|
||||
/* interface and string IDs start at zero via kzalloc.
|
||||
* we force endpoints to start unassigned; few controller
|
||||
|
|
@ -1094,26 +1119,41 @@ static int composite_bind(struct usb_gadget *gadget)
|
|||
* serial number), register function drivers, potentially update
|
||||
* power state and consumption, etc
|
||||
*/
|
||||
status = composite->bind(cdev);
|
||||
status = composite_gadget_bind(cdev);
|
||||
if (status < 0)
|
||||
goto fail;
|
||||
|
||||
cdev->desc = *composite->dev;
|
||||
cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
|
||||
|
||||
/* strings can't be assigned before bind() allocates the
|
||||
* releavnt identifiers
|
||||
*/
|
||||
if (cdev->desc.iManufacturer && iManufacturer)
|
||||
string_override(composite->strings,
|
||||
cdev->desc.iManufacturer, iManufacturer);
|
||||
if (cdev->desc.iProduct && iProduct)
|
||||
string_override(composite->strings,
|
||||
cdev->desc.iProduct, iProduct);
|
||||
if (cdev->desc.iSerialNumber && iSerialNumber)
|
||||
string_override(composite->strings,
|
||||
cdev->desc.iSerialNumber, iSerialNumber);
|
||||
/* stirng overrides */
|
||||
if (iManufacturer || !cdev->desc.iManufacturer) {
|
||||
if (!iManufacturer && !composite->iManufacturer &&
|
||||
!*composite_manufacturer)
|
||||
snprintf(composite_manufacturer,
|
||||
sizeof composite_manufacturer,
|
||||
"%s %s with %s",
|
||||
init_utsname()->sysname,
|
||||
init_utsname()->release,
|
||||
gadget->name);
|
||||
|
||||
cdev->manufacturer_override =
|
||||
override_id(cdev, &cdev->desc.iManufacturer);
|
||||
}
|
||||
|
||||
if (iProduct || (!cdev->desc.iProduct && composite->iProduct))
|
||||
cdev->product_override =
|
||||
override_id(cdev, &cdev->desc.iProduct);
|
||||
|
||||
if (iSerialNumber)
|
||||
cdev->serial_override =
|
||||
override_id(cdev, &cdev->desc.iSerialNumber);
|
||||
|
||||
/* has userspace failed to provide a serial number? */
|
||||
if (composite->needs_serial && !cdev->desc.iSerialNumber)
|
||||
WARNING(cdev, "userspace failed to provide iSerialNumber\n");
|
||||
|
||||
/* finish up */
|
||||
status = device_create_file(&gadget->dev, &dev_attr_suspended);
|
||||
if (status)
|
||||
goto fail;
|
||||
|
|
@ -1177,7 +1217,6 @@ composite_resume(struct usb_gadget *gadget)
|
|||
static struct usb_gadget_driver composite_driver = {
|
||||
.speed = USB_SPEED_HIGH,
|
||||
|
||||
.bind = composite_bind,
|
||||
.unbind = composite_unbind,
|
||||
|
||||
.setup = composite_setup,
|
||||
|
|
@ -1192,8 +1231,12 @@ static struct usb_gadget_driver composite_driver = {
|
|||
};
|
||||
|
||||
/**
|
||||
* usb_composite_register() - register a composite driver
|
||||
* usb_composite_probe() - register a composite driver
|
||||
* @driver: the driver to register
|
||||
* @bind: the callback used to allocate resources that are shared across the
|
||||
* whole device, such as string IDs, and add its configurations using
|
||||
* @usb_add_config(). This may fail by returning a negative errno
|
||||
* value; it should return zero on successful initialization.
|
||||
* Context: single threaded during gadget setup
|
||||
*
|
||||
* This function is used to register drivers using the composite driver
|
||||
|
|
@ -1206,18 +1249,22 @@ static struct usb_gadget_driver composite_driver = {
|
|||
* while it was binding. That would usually be done in order to wait for
|
||||
* some userspace participation.
|
||||
*/
|
||||
int usb_composite_register(struct usb_composite_driver *driver)
|
||||
extern int usb_composite_probe(struct usb_composite_driver *driver,
|
||||
int (*bind)(struct usb_composite_dev *cdev))
|
||||
{
|
||||
if (!driver || !driver->dev || !driver->bind || composite)
|
||||
if (!driver || !driver->dev || !bind || composite)
|
||||
return -EINVAL;
|
||||
|
||||
if (!driver->iProduct)
|
||||
driver->iProduct = driver->name;
|
||||
if (!driver->name)
|
||||
driver->name = "composite";
|
||||
composite_driver.function = (char *) driver->name;
|
||||
composite_driver.driver.name = driver->name;
|
||||
composite = driver;
|
||||
composite_gadget_bind = bind;
|
||||
|
||||
return usb_gadget_register_driver(&composite_driver);
|
||||
return usb_gadget_probe_driver(&composite_driver, composite_bind);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -386,15 +386,13 @@ static int dbgp_setup(struct usb_gadget *gadget,
|
|||
} else
|
||||
goto fail;
|
||||
|
||||
if (len >= 0) {
|
||||
req->length = min(length, len);
|
||||
req->zero = len < req->length;
|
||||
if (data && req->length)
|
||||
memcpy(req->buf, data, req->length);
|
||||
req->length = min(length, len);
|
||||
req->zero = len < req->length;
|
||||
if (data && req->length)
|
||||
memcpy(req->buf, data, req->length);
|
||||
|
||||
req->complete = dbgp_setup_complete;
|
||||
return usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
|
||||
}
|
||||
req->complete = dbgp_setup_complete;
|
||||
return usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
|
||||
|
||||
fail:
|
||||
dev_dbg(&dbgp.gadget->dev,
|
||||
|
|
@ -405,7 +403,6 @@ fail:
|
|||
static struct usb_gadget_driver dbgp_driver = {
|
||||
.function = "dbgp",
|
||||
.speed = USB_SPEED_HIGH,
|
||||
.bind = dbgp_bind,
|
||||
.unbind = dbgp_unbind,
|
||||
.setup = dbgp_setup,
|
||||
.disconnect = dbgp_disconnect,
|
||||
|
|
@ -417,7 +414,7 @@ static struct usb_gadget_driver dbgp_driver = {
|
|||
|
||||
static int __init dbgp_init(void)
|
||||
{
|
||||
return usb_gadget_register_driver(&dbgp_driver);
|
||||
return usb_gadget_probe_driver(&dbgp_driver, dbgp_bind);
|
||||
}
|
||||
|
||||
static void __exit dbgp_exit(void)
|
||||
|
|
|
|||
|
|
@ -748,7 +748,8 @@ static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
|
|||
*/
|
||||
|
||||
int
|
||||
usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
||||
usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct dummy *dum = the_controller;
|
||||
int retval, i;
|
||||
|
|
@ -757,8 +758,7 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
|||
return -EINVAL;
|
||||
if (dum->driver)
|
||||
return -EBUSY;
|
||||
if (!driver->bind || !driver->setup
|
||||
|| driver->speed == USB_SPEED_UNKNOWN)
|
||||
if (!bind || !driver->setup || driver->speed == USB_SPEED_UNKNOWN)
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
|
|
@ -796,7 +796,7 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
|||
dum->gadget.dev.driver = &driver->driver;
|
||||
dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
|
||||
driver->driver.name);
|
||||
retval = driver->bind(&dum->gadget);
|
||||
retval = bind(&dum->gadget);
|
||||
if (retval) {
|
||||
dum->driver = NULL;
|
||||
dum->gadget.dev.driver = NULL;
|
||||
|
|
@ -812,7 +812,7 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
|||
usb_hcd_poll_rh_status (dummy_to_hcd (dum));
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL (usb_gadget_register_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int
|
||||
usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
|
||||
|
|
@ -874,6 +874,8 @@ static int dummy_udc_probe (struct platform_device *pdev)
|
|||
struct dummy *dum = the_controller;
|
||||
int rc;
|
||||
|
||||
usb_get_hcd(dummy_to_hcd(dum));
|
||||
|
||||
dum->gadget.name = gadget_name;
|
||||
dum->gadget.ops = &dummy_ops;
|
||||
dum->gadget.is_dualspeed = 1;
|
||||
|
|
@ -885,10 +887,10 @@ static int dummy_udc_probe (struct platform_device *pdev)
|
|||
dum->gadget.dev.parent = &pdev->dev;
|
||||
dum->gadget.dev.release = dummy_gadget_release;
|
||||
rc = device_register (&dum->gadget.dev);
|
||||
if (rc < 0)
|
||||
if (rc < 0) {
|
||||
put_device(&dum->gadget.dev);
|
||||
return rc;
|
||||
|
||||
usb_get_hcd (dummy_to_hcd (dum));
|
||||
}
|
||||
|
||||
platform_set_drvdata (pdev, dum);
|
||||
rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@ static u8 hostaddr[ETH_ALEN];
|
|||
* the first one present. That's to make Microsoft's drivers happy,
|
||||
* and to follow DOCSIS 1.0 (cable modem standard).
|
||||
*/
|
||||
static int __ref rndis_do_config(struct usb_configuration *c)
|
||||
static int __init rndis_do_config(struct usb_configuration *c)
|
||||
{
|
||||
/* FIXME alloc iConfiguration string, set it in c->strings */
|
||||
|
||||
|
|
@ -251,7 +251,6 @@ static int __ref rndis_do_config(struct usb_configuration *c)
|
|||
|
||||
static struct usb_configuration rndis_config_driver = {
|
||||
.label = "RNDIS",
|
||||
.bind = rndis_do_config,
|
||||
.bConfigurationValue = 2,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
|
|
@ -270,7 +269,7 @@ MODULE_PARM_DESC(use_eem, "use CDC EEM mode");
|
|||
/*
|
||||
* We _always_ have an ECM, CDC Subset, or EEM configuration.
|
||||
*/
|
||||
static int __ref eth_do_config(struct usb_configuration *c)
|
||||
static int __init eth_do_config(struct usb_configuration *c)
|
||||
{
|
||||
/* FIXME alloc iConfiguration string, set it in c->strings */
|
||||
|
||||
|
|
@ -289,7 +288,6 @@ static int __ref eth_do_config(struct usb_configuration *c)
|
|||
|
||||
static struct usb_configuration eth_config_driver = {
|
||||
/* .label = f(hardware) */
|
||||
.bind = eth_do_config,
|
||||
.bConfigurationValue = 1,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
|
|
@ -297,7 +295,7 @@ static struct usb_configuration eth_config_driver = {
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __ref eth_bind(struct usb_composite_dev *cdev)
|
||||
static int __init eth_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
int gcnum;
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
|
|
@ -373,12 +371,13 @@ static int __ref eth_bind(struct usb_composite_dev *cdev)
|
|||
|
||||
/* register our configuration(s); RNDIS first, if it's used */
|
||||
if (has_rndis()) {
|
||||
status = usb_add_config(cdev, &rndis_config_driver);
|
||||
status = usb_add_config(cdev, &rndis_config_driver,
|
||||
rndis_do_config);
|
||||
if (status < 0)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
status = usb_add_config(cdev, ð_config_driver);
|
||||
status = usb_add_config(cdev, ð_config_driver, eth_do_config);
|
||||
if (status < 0)
|
||||
goto fail;
|
||||
|
||||
|
|
@ -402,7 +401,6 @@ static struct usb_composite_driver eth_driver = {
|
|||
.name = "g_ether",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.bind = eth_bind,
|
||||
.unbind = __exit_p(eth_unbind),
|
||||
};
|
||||
|
||||
|
|
@ -412,7 +410,7 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
static int __init init(void)
|
||||
{
|
||||
return usb_composite_register(ð_driver);
|
||||
return usb_composite_probe(ð_driver, eth_bind);
|
||||
}
|
||||
module_init(init);
|
||||
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ acm_iad_descriptor = {
|
|||
.bInterfaceCount = 2, // control + data
|
||||
.bFunctionClass = USB_CLASS_COMM,
|
||||
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
|
||||
.bFunctionProtocol = USB_CDC_PROTO_NONE,
|
||||
.bFunctionProtocol = USB_CDC_ACM_PROTO_AT_V25TER,
|
||||
/* .iFunction = DYNAMIC */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -324,7 +324,7 @@ static void loopback_disable(struct usb_function *f)
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __ref loopback_bind_config(struct usb_configuration *c)
|
||||
static int __init loopback_bind_config(struct usb_configuration *c)
|
||||
{
|
||||
struct f_loopback *loop;
|
||||
int status;
|
||||
|
|
@ -346,10 +346,9 @@ static int __ref loopback_bind_config(struct usb_configuration *c)
|
|||
return status;
|
||||
}
|
||||
|
||||
static struct usb_configuration loopback_driver = {
|
||||
static struct usb_configuration loopback_driver = {
|
||||
.label = "loopback",
|
||||
.strings = loopback_strings,
|
||||
.bind = loopback_bind_config,
|
||||
.bConfigurationValue = 2,
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
|
|
@ -382,5 +381,5 @@ int __init loopback_add(struct usb_composite_dev *cdev, bool autoresume)
|
|||
loopback_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
return usb_add_config(cdev, &loopback_driver);
|
||||
return usb_add_config(cdev, &loopback_driver, loopback_bind_config);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,8 @@
|
|||
* being removable.
|
||||
* ->cdrom Flag specifying that LUN shall be reported as
|
||||
* being a CD-ROM.
|
||||
* ->nofua Flag specifying that FUA flag in SCSI WRITE(10,12)
|
||||
* commands for this LUN shall be ignored.
|
||||
*
|
||||
* lun_name_format A printf-like format for names of the LUN
|
||||
* devices. This determines how the
|
||||
|
|
@ -127,6 +129,8 @@
|
|||
* Default true, boolean for removable media.
|
||||
* cdrom=b[,b...] Default false, boolean for whether to emulate
|
||||
* a CD-ROM drive.
|
||||
* nofua=b[,b...] Default false, booleans for ignore FUA flag
|
||||
* in SCSI WRITE(10,12) commands
|
||||
* luns=N Default N = number of filenames, number of
|
||||
* LUNs to support.
|
||||
* stall Default determined according to the type of
|
||||
|
|
@ -409,6 +413,7 @@ struct fsg_config {
|
|||
char ro;
|
||||
char removable;
|
||||
char cdrom;
|
||||
char nofua;
|
||||
} luns[FSG_MAX_LUNS];
|
||||
|
||||
const char *lun_name_format;
|
||||
|
|
@ -736,7 +741,7 @@ static int do_read(struct fsg_common *common)
|
|||
|
||||
/* Get the starting Logical Block Address and check that it's
|
||||
* not too big */
|
||||
if (common->cmnd[0] == SC_READ_6)
|
||||
if (common->cmnd[0] == READ_6)
|
||||
lba = get_unaligned_be24(&common->cmnd[1]);
|
||||
else {
|
||||
lba = get_unaligned_be32(&common->cmnd[2]);
|
||||
|
|
@ -874,7 +879,7 @@ static int do_write(struct fsg_common *common)
|
|||
|
||||
/* Get the starting Logical Block Address and check that it's
|
||||
* not too big */
|
||||
if (common->cmnd[0] == SC_WRITE_6)
|
||||
if (common->cmnd[0] == WRITE_6)
|
||||
lba = get_unaligned_be24(&common->cmnd[1]);
|
||||
else {
|
||||
lba = get_unaligned_be32(&common->cmnd[2]);
|
||||
|
|
@ -887,7 +892,7 @@ static int do_write(struct fsg_common *common)
|
|||
curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
|
||||
return -EINVAL;
|
||||
}
|
||||
if (common->cmnd[1] & 0x08) { /* FUA */
|
||||
if (!curlun->nofua && (common->cmnd[1] & 0x08)) { /* FUA */
|
||||
spin_lock(&curlun->filp->f_lock);
|
||||
curlun->filp->f_flags |= O_SYNC;
|
||||
spin_unlock(&curlun->filp->f_lock);
|
||||
|
|
@ -1181,7 +1186,7 @@ static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh)
|
|||
return 36;
|
||||
}
|
||||
|
||||
buf[0] = curlun->cdrom ? TYPE_CDROM : TYPE_DISK;
|
||||
buf[0] = curlun->cdrom ? TYPE_ROM : TYPE_DISK;
|
||||
buf[1] = curlun->removable ? 0x80 : 0;
|
||||
buf[2] = 2; /* ANSI SCSI level 2 */
|
||||
buf[3] = 2; /* SCSI-2 INQUIRY data format */
|
||||
|
|
@ -1348,11 +1353,11 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
|
|||
* The only variable value is the WriteProtect bit. We will fill in
|
||||
* the mode data length later. */
|
||||
memset(buf, 0, 8);
|
||||
if (mscmnd == SC_MODE_SENSE_6) {
|
||||
if (mscmnd == MODE_SENSE) {
|
||||
buf[2] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */
|
||||
buf += 4;
|
||||
limit = 255;
|
||||
} else { /* SC_MODE_SENSE_10 */
|
||||
} else { /* MODE_SENSE_10 */
|
||||
buf[3] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */
|
||||
buf += 8;
|
||||
limit = 65535; /* Should really be FSG_BUFLEN */
|
||||
|
|
@ -1392,7 +1397,7 @@ static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh)
|
|||
}
|
||||
|
||||
/* Store the mode data length */
|
||||
if (mscmnd == SC_MODE_SENSE_6)
|
||||
if (mscmnd == MODE_SENSE)
|
||||
buf0[0] = len - 1;
|
||||
else
|
||||
put_unaligned_be16(len - 2, buf0);
|
||||
|
|
@ -1881,7 +1886,7 @@ static int check_command(struct fsg_common *common, int cmnd_size,
|
|||
if (common->lun >= 0 && common->lun < common->nluns) {
|
||||
curlun = &common->luns[common->lun];
|
||||
common->curlun = curlun;
|
||||
if (common->cmnd[0] != SC_REQUEST_SENSE) {
|
||||
if (common->cmnd[0] != REQUEST_SENSE) {
|
||||
curlun->sense_data = SS_NO_SENSE;
|
||||
curlun->sense_data_info = 0;
|
||||
curlun->info_valid = 0;
|
||||
|
|
@ -1893,8 +1898,8 @@ static int check_command(struct fsg_common *common, int cmnd_size,
|
|||
|
||||
/* INQUIRY and REQUEST SENSE commands are explicitly allowed
|
||||
* to use unsupported LUNs; all others may not. */
|
||||
if (common->cmnd[0] != SC_INQUIRY &&
|
||||
common->cmnd[0] != SC_REQUEST_SENSE) {
|
||||
if (common->cmnd[0] != INQUIRY &&
|
||||
common->cmnd[0] != REQUEST_SENSE) {
|
||||
DBG(common, "unsupported LUN %d\n", common->lun);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -1903,8 +1908,8 @@ static int check_command(struct fsg_common *common, int cmnd_size,
|
|||
/* If a unit attention condition exists, only INQUIRY and
|
||||
* REQUEST SENSE commands are allowed; anything else must fail. */
|
||||
if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
|
||||
common->cmnd[0] != SC_INQUIRY &&
|
||||
common->cmnd[0] != SC_REQUEST_SENSE) {
|
||||
common->cmnd[0] != INQUIRY &&
|
||||
common->cmnd[0] != REQUEST_SENSE) {
|
||||
curlun->sense_data = curlun->unit_attention_data;
|
||||
curlun->unit_attention_data = SS_NO_SENSE;
|
||||
return -EINVAL;
|
||||
|
|
@ -1955,7 +1960,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
down_read(&common->filesem); /* We're using the backing file */
|
||||
switch (common->cmnd[0]) {
|
||||
|
||||
case SC_INQUIRY:
|
||||
case INQUIRY:
|
||||
common->data_size_from_cmnd = common->cmnd[4];
|
||||
reply = check_command(common, 6, DATA_DIR_TO_HOST,
|
||||
(1<<4), 0,
|
||||
|
|
@ -1964,7 +1969,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_inquiry(common, bh);
|
||||
break;
|
||||
|
||||
case SC_MODE_SELECT_6:
|
||||
case MODE_SELECT:
|
||||
common->data_size_from_cmnd = common->cmnd[4];
|
||||
reply = check_command(common, 6, DATA_DIR_FROM_HOST,
|
||||
(1<<1) | (1<<4), 0,
|
||||
|
|
@ -1973,7 +1978,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_mode_select(common, bh);
|
||||
break;
|
||||
|
||||
case SC_MODE_SELECT_10:
|
||||
case MODE_SELECT_10:
|
||||
common->data_size_from_cmnd =
|
||||
get_unaligned_be16(&common->cmnd[7]);
|
||||
reply = check_command(common, 10, DATA_DIR_FROM_HOST,
|
||||
|
|
@ -1983,7 +1988,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_mode_select(common, bh);
|
||||
break;
|
||||
|
||||
case SC_MODE_SENSE_6:
|
||||
case MODE_SENSE:
|
||||
common->data_size_from_cmnd = common->cmnd[4];
|
||||
reply = check_command(common, 6, DATA_DIR_TO_HOST,
|
||||
(1<<1) | (1<<2) | (1<<4), 0,
|
||||
|
|
@ -1992,7 +1997,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_mode_sense(common, bh);
|
||||
break;
|
||||
|
||||
case SC_MODE_SENSE_10:
|
||||
case MODE_SENSE_10:
|
||||
common->data_size_from_cmnd =
|
||||
get_unaligned_be16(&common->cmnd[7]);
|
||||
reply = check_command(common, 10, DATA_DIR_TO_HOST,
|
||||
|
|
@ -2002,7 +2007,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_mode_sense(common, bh);
|
||||
break;
|
||||
|
||||
case SC_PREVENT_ALLOW_MEDIUM_REMOVAL:
|
||||
case ALLOW_MEDIUM_REMOVAL:
|
||||
common->data_size_from_cmnd = 0;
|
||||
reply = check_command(common, 6, DATA_DIR_NONE,
|
||||
(1<<4), 0,
|
||||
|
|
@ -2011,7 +2016,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_prevent_allow(common);
|
||||
break;
|
||||
|
||||
case SC_READ_6:
|
||||
case READ_6:
|
||||
i = common->cmnd[4];
|
||||
common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
|
||||
reply = check_command(common, 6, DATA_DIR_TO_HOST,
|
||||
|
|
@ -2021,7 +2026,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_read(common);
|
||||
break;
|
||||
|
||||
case SC_READ_10:
|
||||
case READ_10:
|
||||
common->data_size_from_cmnd =
|
||||
get_unaligned_be16(&common->cmnd[7]) << 9;
|
||||
reply = check_command(common, 10, DATA_DIR_TO_HOST,
|
||||
|
|
@ -2031,7 +2036,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_read(common);
|
||||
break;
|
||||
|
||||
case SC_READ_12:
|
||||
case READ_12:
|
||||
common->data_size_from_cmnd =
|
||||
get_unaligned_be32(&common->cmnd[6]) << 9;
|
||||
reply = check_command(common, 12, DATA_DIR_TO_HOST,
|
||||
|
|
@ -2041,7 +2046,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_read(common);
|
||||
break;
|
||||
|
||||
case SC_READ_CAPACITY:
|
||||
case READ_CAPACITY:
|
||||
common->data_size_from_cmnd = 8;
|
||||
reply = check_command(common, 10, DATA_DIR_TO_HOST,
|
||||
(0xf<<2) | (1<<8), 1,
|
||||
|
|
@ -2050,7 +2055,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_read_capacity(common, bh);
|
||||
break;
|
||||
|
||||
case SC_READ_HEADER:
|
||||
case READ_HEADER:
|
||||
if (!common->curlun || !common->curlun->cdrom)
|
||||
goto unknown_cmnd;
|
||||
common->data_size_from_cmnd =
|
||||
|
|
@ -2062,7 +2067,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_read_header(common, bh);
|
||||
break;
|
||||
|
||||
case SC_READ_TOC:
|
||||
case READ_TOC:
|
||||
if (!common->curlun || !common->curlun->cdrom)
|
||||
goto unknown_cmnd;
|
||||
common->data_size_from_cmnd =
|
||||
|
|
@ -2074,7 +2079,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_read_toc(common, bh);
|
||||
break;
|
||||
|
||||
case SC_READ_FORMAT_CAPACITIES:
|
||||
case READ_FORMAT_CAPACITIES:
|
||||
common->data_size_from_cmnd =
|
||||
get_unaligned_be16(&common->cmnd[7]);
|
||||
reply = check_command(common, 10, DATA_DIR_TO_HOST,
|
||||
|
|
@ -2084,7 +2089,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_read_format_capacities(common, bh);
|
||||
break;
|
||||
|
||||
case SC_REQUEST_SENSE:
|
||||
case REQUEST_SENSE:
|
||||
common->data_size_from_cmnd = common->cmnd[4];
|
||||
reply = check_command(common, 6, DATA_DIR_TO_HOST,
|
||||
(1<<4), 0,
|
||||
|
|
@ -2093,7 +2098,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_request_sense(common, bh);
|
||||
break;
|
||||
|
||||
case SC_START_STOP_UNIT:
|
||||
case START_STOP:
|
||||
common->data_size_from_cmnd = 0;
|
||||
reply = check_command(common, 6, DATA_DIR_NONE,
|
||||
(1<<1) | (1<<4), 0,
|
||||
|
|
@ -2102,7 +2107,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_start_stop(common);
|
||||
break;
|
||||
|
||||
case SC_SYNCHRONIZE_CACHE:
|
||||
case SYNCHRONIZE_CACHE:
|
||||
common->data_size_from_cmnd = 0;
|
||||
reply = check_command(common, 10, DATA_DIR_NONE,
|
||||
(0xf<<2) | (3<<7), 1,
|
||||
|
|
@ -2111,7 +2116,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_synchronize_cache(common);
|
||||
break;
|
||||
|
||||
case SC_TEST_UNIT_READY:
|
||||
case TEST_UNIT_READY:
|
||||
common->data_size_from_cmnd = 0;
|
||||
reply = check_command(common, 6, DATA_DIR_NONE,
|
||||
0, 1,
|
||||
|
|
@ -2120,7 +2125,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
|
||||
/* Although optional, this command is used by MS-Windows. We
|
||||
* support a minimal version: BytChk must be 0. */
|
||||
case SC_VERIFY:
|
||||
case VERIFY:
|
||||
common->data_size_from_cmnd = 0;
|
||||
reply = check_command(common, 10, DATA_DIR_NONE,
|
||||
(1<<1) | (0xf<<2) | (3<<7), 1,
|
||||
|
|
@ -2129,7 +2134,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_verify(common);
|
||||
break;
|
||||
|
||||
case SC_WRITE_6:
|
||||
case WRITE_6:
|
||||
i = common->cmnd[4];
|
||||
common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
|
||||
reply = check_command(common, 6, DATA_DIR_FROM_HOST,
|
||||
|
|
@ -2139,7 +2144,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_write(common);
|
||||
break;
|
||||
|
||||
case SC_WRITE_10:
|
||||
case WRITE_10:
|
||||
common->data_size_from_cmnd =
|
||||
get_unaligned_be16(&common->cmnd[7]) << 9;
|
||||
reply = check_command(common, 10, DATA_DIR_FROM_HOST,
|
||||
|
|
@ -2149,7 +2154,7 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
reply = do_write(common);
|
||||
break;
|
||||
|
||||
case SC_WRITE_12:
|
||||
case WRITE_12:
|
||||
common->data_size_from_cmnd =
|
||||
get_unaligned_be32(&common->cmnd[6]) << 9;
|
||||
reply = check_command(common, 12, DATA_DIR_FROM_HOST,
|
||||
|
|
@ -2163,10 +2168,10 @@ static int do_scsi_command(struct fsg_common *common)
|
|||
* They don't mean much in this setting. It's left as an exercise
|
||||
* for anyone interested to implement RESERVE and RELEASE in terms
|
||||
* of Posix locks. */
|
||||
case SC_FORMAT_UNIT:
|
||||
case SC_RELEASE:
|
||||
case SC_RESERVE:
|
||||
case SC_SEND_DIAGNOSTIC:
|
||||
case FORMAT_UNIT:
|
||||
case RELEASE:
|
||||
case RESERVE:
|
||||
case SEND_DIAGNOSTIC:
|
||||
/* Fall through */
|
||||
|
||||
default:
|
||||
|
|
@ -2662,6 +2667,7 @@ static int fsg_main_thread(void *common_)
|
|||
|
||||
/* Write permission is checked per LUN in store_*() functions. */
|
||||
static DEVICE_ATTR(ro, 0644, fsg_show_ro, fsg_store_ro);
|
||||
static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, fsg_store_nofua);
|
||||
static DEVICE_ATTR(file, 0644, fsg_show_file, fsg_store_file);
|
||||
|
||||
|
||||
|
|
@ -2766,6 +2772,9 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
|
|||
if (rc)
|
||||
goto error_luns;
|
||||
rc = device_create_file(&curlun->dev, &dev_attr_file);
|
||||
if (rc)
|
||||
goto error_luns;
|
||||
rc = device_create_file(&curlun->dev, &dev_attr_nofua);
|
||||
if (rc)
|
||||
goto error_luns;
|
||||
|
||||
|
|
@ -2911,6 +2920,7 @@ static void fsg_common_release(struct kref *ref)
|
|||
|
||||
/* In error recovery common->nluns may be zero. */
|
||||
for (; i; --i, ++lun) {
|
||||
device_remove_file(&lun->dev, &dev_attr_nofua);
|
||||
device_remove_file(&lun->dev, &dev_attr_ro);
|
||||
device_remove_file(&lun->dev, &dev_attr_file);
|
||||
fsg_lun_close(lun);
|
||||
|
|
@ -3069,8 +3079,10 @@ struct fsg_module_parameters {
|
|||
int ro[FSG_MAX_LUNS];
|
||||
int removable[FSG_MAX_LUNS];
|
||||
int cdrom[FSG_MAX_LUNS];
|
||||
int nofua[FSG_MAX_LUNS];
|
||||
|
||||
unsigned int file_count, ro_count, removable_count, cdrom_count;
|
||||
unsigned int nofua_count;
|
||||
unsigned int luns; /* nluns */
|
||||
int stall; /* can_stall */
|
||||
};
|
||||
|
|
@ -3096,6 +3108,8 @@ struct fsg_module_parameters {
|
|||
"true to simulate removable media"); \
|
||||
_FSG_MODULE_PARAM_ARRAY(prefix, params, cdrom, bool, \
|
||||
"true to simulate CD-ROM instead of disk"); \
|
||||
_FSG_MODULE_PARAM_ARRAY(prefix, params, nofua, bool, \
|
||||
"true to ignore SCSI WRITE(10,12) FUA bit"); \
|
||||
_FSG_MODULE_PARAM(prefix, params, luns, uint, \
|
||||
"number of LUNs"); \
|
||||
_FSG_MODULE_PARAM(prefix, params, stall, bool, \
|
||||
|
|
|
|||
|
|
@ -404,7 +404,7 @@ static void sourcesink_disable(struct usb_function *f)
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __ref sourcesink_bind_config(struct usb_configuration *c)
|
||||
static int __init sourcesink_bind_config(struct usb_configuration *c)
|
||||
{
|
||||
struct f_sourcesink *ss;
|
||||
int status;
|
||||
|
|
@ -498,7 +498,6 @@ unknown:
|
|||
static struct usb_configuration sourcesink_driver = {
|
||||
.label = "source/sink",
|
||||
.strings = sourcesink_strings,
|
||||
.bind = sourcesink_bind_config,
|
||||
.setup = sourcesink_setup,
|
||||
.bConfigurationValue = 3,
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
|
|
@ -532,5 +531,5 @@ int __init sourcesink_add(struct usb_composite_dev *cdev, bool autoresume)
|
|||
sourcesink_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
|
||||
}
|
||||
|
||||
return usb_add_config(cdev, &sourcesink_driver);
|
||||
return usb_add_config(cdev, &sourcesink_driver, sourcesink_bind_config);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@
|
|||
* Required if "removable" is not set, names of
|
||||
* the files or block devices used for
|
||||
* backing storage
|
||||
* serial=HHHH... Required serial number (string of hex chars)
|
||||
* ro=b[,b...] Default false, booleans for read-only access
|
||||
* removable Default false, boolean for removable media
|
||||
* luns=N Default N = number of filenames, number of
|
||||
|
|
@ -108,12 +109,11 @@
|
|||
* vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID
|
||||
* product=0xPPPP Default 0xa4a5 (FSG), USB Product ID
|
||||
* release=0xRRRR Override the USB release number (bcdDevice)
|
||||
* serial=HHHH... Override serial number (string of hex chars)
|
||||
* buflen=N Default N=16384, buffer size used (will be
|
||||
* rounded down to a multiple of
|
||||
* PAGE_CACHE_SIZE)
|
||||
*
|
||||
* If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "ro",
|
||||
* If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "serial", "ro",
|
||||
* "removable", "luns", "nofua", "stall", and "cdrom" options are available;
|
||||
* default values are used for everything else.
|
||||
*
|
||||
|
|
@ -273,13 +273,10 @@
|
|||
|
||||
#define DRIVER_DESC "File-backed Storage Gadget"
|
||||
#define DRIVER_NAME "g_file_storage"
|
||||
/* DRIVER_VERSION must be at least 6 characters long, as it is used
|
||||
* to generate a fallback serial number. */
|
||||
#define DRIVER_VERSION "20 November 2008"
|
||||
#define DRIVER_VERSION "1 September 2010"
|
||||
|
||||
static char fsg_string_manufacturer[64];
|
||||
static const char fsg_string_product[] = DRIVER_DESC;
|
||||
static char fsg_string_serial[13];
|
||||
static const char fsg_string_config[] = "Self-powered";
|
||||
static const char fsg_string_interface[] = "Mass Storage";
|
||||
|
||||
|
|
@ -305,6 +302,7 @@ MODULE_LICENSE("Dual BSD/GPL");
|
|||
|
||||
static struct {
|
||||
char *file[FSG_MAX_LUNS];
|
||||
char *serial;
|
||||
int ro[FSG_MAX_LUNS];
|
||||
int nofua[FSG_MAX_LUNS];
|
||||
unsigned int num_filenames;
|
||||
|
|
@ -321,7 +319,6 @@ static struct {
|
|||
unsigned short vendor;
|
||||
unsigned short product;
|
||||
unsigned short release;
|
||||
char *serial;
|
||||
unsigned int buflen;
|
||||
|
||||
int transport_type;
|
||||
|
|
@ -346,6 +343,9 @@ module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames,
|
|||
S_IRUGO);
|
||||
MODULE_PARM_DESC(file, "names of backing files or devices");
|
||||
|
||||
module_param_named(serial, mod_data.serial, charp, S_IRUGO);
|
||||
MODULE_PARM_DESC(serial, "USB serial number");
|
||||
|
||||
module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO);
|
||||
MODULE_PARM_DESC(ro, "true to force read-only");
|
||||
|
||||
|
|
@ -365,9 +365,6 @@ MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
|
|||
module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO);
|
||||
MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk");
|
||||
|
||||
module_param_named(serial, mod_data.serial, charp, S_IRUGO);
|
||||
MODULE_PARM_DESC(serial, "USB serial number");
|
||||
|
||||
/* In the non-TEST version, only the module parameters listed above
|
||||
* are available. */
|
||||
#ifdef CONFIG_USB_FILE_STORAGE_TEST
|
||||
|
|
@ -786,7 +783,7 @@ static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
|||
{
|
||||
struct usb_request *req = fsg->ep0req;
|
||||
static u8 cbi_reset_cmnd[6] = {
|
||||
SC_SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff};
|
||||
SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
/* Error in command transfer? */
|
||||
if (req->status || req->length != req->actual ||
|
||||
|
|
@ -1138,7 +1135,7 @@ static int do_read(struct fsg_dev *fsg)
|
|||
|
||||
/* Get the starting Logical Block Address and check that it's
|
||||
* not too big */
|
||||
if (fsg->cmnd[0] == SC_READ_6)
|
||||
if (fsg->cmnd[0] == READ_6)
|
||||
lba = get_unaligned_be24(&fsg->cmnd[1]);
|
||||
else {
|
||||
lba = get_unaligned_be32(&fsg->cmnd[2]);
|
||||
|
|
@ -1273,7 +1270,7 @@ static int do_write(struct fsg_dev *fsg)
|
|||
|
||||
/* Get the starting Logical Block Address and check that it's
|
||||
* not too big */
|
||||
if (fsg->cmnd[0] == SC_WRITE_6)
|
||||
if (fsg->cmnd[0] == WRITE_6)
|
||||
lba = get_unaligned_be24(&fsg->cmnd[1]);
|
||||
else {
|
||||
lba = get_unaligned_be32(&fsg->cmnd[2]);
|
||||
|
|
@ -1581,7 +1578,7 @@ static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
|||
}
|
||||
|
||||
memset(buf, 0, 8);
|
||||
buf[0] = (mod_data.cdrom ? TYPE_CDROM : TYPE_DISK);
|
||||
buf[0] = (mod_data.cdrom ? TYPE_ROM : TYPE_DISK);
|
||||
if (mod_data.removable)
|
||||
buf[1] = 0x80;
|
||||
buf[2] = 2; // ANSI SCSI level 2
|
||||
|
|
@ -1750,11 +1747,11 @@ static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
|||
* The only variable value is the WriteProtect bit. We will fill in
|
||||
* the mode data length later. */
|
||||
memset(buf, 0, 8);
|
||||
if (mscmnd == SC_MODE_SENSE_6) {
|
||||
if (mscmnd == MODE_SENSE) {
|
||||
buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
|
||||
buf += 4;
|
||||
limit = 255;
|
||||
} else { // SC_MODE_SENSE_10
|
||||
} else { // MODE_SENSE_10
|
||||
buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA
|
||||
buf += 8;
|
||||
limit = 65535; // Should really be mod_data.buflen
|
||||
|
|
@ -1794,7 +1791,7 @@ static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
|
|||
}
|
||||
|
||||
/* Store the mode data length */
|
||||
if (mscmnd == SC_MODE_SENSE_6)
|
||||
if (mscmnd == MODE_SENSE)
|
||||
buf0[0] = len - 1;
|
||||
else
|
||||
put_unaligned_be16(len - 2, buf0);
|
||||
|
|
@ -2319,7 +2316,7 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
|
|||
/* Check the LUN */
|
||||
if (fsg->lun >= 0 && fsg->lun < fsg->nluns) {
|
||||
fsg->curlun = curlun = &fsg->luns[fsg->lun];
|
||||
if (fsg->cmnd[0] != SC_REQUEST_SENSE) {
|
||||
if (fsg->cmnd[0] != REQUEST_SENSE) {
|
||||
curlun->sense_data = SS_NO_SENSE;
|
||||
curlun->sense_data_info = 0;
|
||||
curlun->info_valid = 0;
|
||||
|
|
@ -2330,8 +2327,8 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
|
|||
|
||||
/* INQUIRY and REQUEST SENSE commands are explicitly allowed
|
||||
* to use unsupported LUNs; all others may not. */
|
||||
if (fsg->cmnd[0] != SC_INQUIRY &&
|
||||
fsg->cmnd[0] != SC_REQUEST_SENSE) {
|
||||
if (fsg->cmnd[0] != INQUIRY &&
|
||||
fsg->cmnd[0] != REQUEST_SENSE) {
|
||||
DBG(fsg, "unsupported LUN %d\n", fsg->lun);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -2340,8 +2337,8 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
|
|||
/* If a unit attention condition exists, only INQUIRY and
|
||||
* REQUEST SENSE commands are allowed; anything else must fail. */
|
||||
if (curlun && curlun->unit_attention_data != SS_NO_SENSE &&
|
||||
fsg->cmnd[0] != SC_INQUIRY &&
|
||||
fsg->cmnd[0] != SC_REQUEST_SENSE) {
|
||||
fsg->cmnd[0] != INQUIRY &&
|
||||
fsg->cmnd[0] != REQUEST_SENSE) {
|
||||
curlun->sense_data = curlun->unit_attention_data;
|
||||
curlun->unit_attention_data = SS_NO_SENSE;
|
||||
return -EINVAL;
|
||||
|
|
@ -2391,7 +2388,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
down_read(&fsg->filesem); // We're using the backing file
|
||||
switch (fsg->cmnd[0]) {
|
||||
|
||||
case SC_INQUIRY:
|
||||
case INQUIRY:
|
||||
fsg->data_size_from_cmnd = fsg->cmnd[4];
|
||||
if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
|
||||
(1<<4), 0,
|
||||
|
|
@ -2399,7 +2396,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_inquiry(fsg, bh);
|
||||
break;
|
||||
|
||||
case SC_MODE_SELECT_6:
|
||||
case MODE_SELECT:
|
||||
fsg->data_size_from_cmnd = fsg->cmnd[4];
|
||||
if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
|
||||
(1<<1) | (1<<4), 0,
|
||||
|
|
@ -2407,7 +2404,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_mode_select(fsg, bh);
|
||||
break;
|
||||
|
||||
case SC_MODE_SELECT_10:
|
||||
case MODE_SELECT_10:
|
||||
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
|
||||
if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
|
||||
(1<<1) | (3<<7), 0,
|
||||
|
|
@ -2415,7 +2412,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_mode_select(fsg, bh);
|
||||
break;
|
||||
|
||||
case SC_MODE_SENSE_6:
|
||||
case MODE_SENSE:
|
||||
fsg->data_size_from_cmnd = fsg->cmnd[4];
|
||||
if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
|
||||
(1<<1) | (1<<2) | (1<<4), 0,
|
||||
|
|
@ -2423,7 +2420,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_mode_sense(fsg, bh);
|
||||
break;
|
||||
|
||||
case SC_MODE_SENSE_10:
|
||||
case MODE_SENSE_10:
|
||||
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
|
||||
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
|
||||
(1<<1) | (1<<2) | (3<<7), 0,
|
||||
|
|
@ -2431,7 +2428,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_mode_sense(fsg, bh);
|
||||
break;
|
||||
|
||||
case SC_PREVENT_ALLOW_MEDIUM_REMOVAL:
|
||||
case ALLOW_MEDIUM_REMOVAL:
|
||||
fsg->data_size_from_cmnd = 0;
|
||||
if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
|
||||
(1<<4), 0,
|
||||
|
|
@ -2439,7 +2436,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_prevent_allow(fsg);
|
||||
break;
|
||||
|
||||
case SC_READ_6:
|
||||
case READ_6:
|
||||
i = fsg->cmnd[4];
|
||||
fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
|
||||
if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
|
||||
|
|
@ -2448,7 +2445,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_read(fsg);
|
||||
break;
|
||||
|
||||
case SC_READ_10:
|
||||
case READ_10:
|
||||
fsg->data_size_from_cmnd =
|
||||
get_unaligned_be16(&fsg->cmnd[7]) << 9;
|
||||
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
|
||||
|
|
@ -2457,7 +2454,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_read(fsg);
|
||||
break;
|
||||
|
||||
case SC_READ_12:
|
||||
case READ_12:
|
||||
fsg->data_size_from_cmnd =
|
||||
get_unaligned_be32(&fsg->cmnd[6]) << 9;
|
||||
if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
|
||||
|
|
@ -2466,7 +2463,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_read(fsg);
|
||||
break;
|
||||
|
||||
case SC_READ_CAPACITY:
|
||||
case READ_CAPACITY:
|
||||
fsg->data_size_from_cmnd = 8;
|
||||
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
|
||||
(0xf<<2) | (1<<8), 1,
|
||||
|
|
@ -2474,7 +2471,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_read_capacity(fsg, bh);
|
||||
break;
|
||||
|
||||
case SC_READ_HEADER:
|
||||
case READ_HEADER:
|
||||
if (!mod_data.cdrom)
|
||||
goto unknown_cmnd;
|
||||
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
|
||||
|
|
@ -2484,7 +2481,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_read_header(fsg, bh);
|
||||
break;
|
||||
|
||||
case SC_READ_TOC:
|
||||
case READ_TOC:
|
||||
if (!mod_data.cdrom)
|
||||
goto unknown_cmnd;
|
||||
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
|
||||
|
|
@ -2494,7 +2491,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_read_toc(fsg, bh);
|
||||
break;
|
||||
|
||||
case SC_READ_FORMAT_CAPACITIES:
|
||||
case READ_FORMAT_CAPACITIES:
|
||||
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
|
||||
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
|
||||
(3<<7), 1,
|
||||
|
|
@ -2502,7 +2499,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_read_format_capacities(fsg, bh);
|
||||
break;
|
||||
|
||||
case SC_REQUEST_SENSE:
|
||||
case REQUEST_SENSE:
|
||||
fsg->data_size_from_cmnd = fsg->cmnd[4];
|
||||
if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
|
||||
(1<<4), 0,
|
||||
|
|
@ -2510,7 +2507,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_request_sense(fsg, bh);
|
||||
break;
|
||||
|
||||
case SC_START_STOP_UNIT:
|
||||
case START_STOP:
|
||||
fsg->data_size_from_cmnd = 0;
|
||||
if ((reply = check_command(fsg, 6, DATA_DIR_NONE,
|
||||
(1<<1) | (1<<4), 0,
|
||||
|
|
@ -2518,7 +2515,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_start_stop(fsg);
|
||||
break;
|
||||
|
||||
case SC_SYNCHRONIZE_CACHE:
|
||||
case SYNCHRONIZE_CACHE:
|
||||
fsg->data_size_from_cmnd = 0;
|
||||
if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
|
||||
(0xf<<2) | (3<<7), 1,
|
||||
|
|
@ -2526,7 +2523,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_synchronize_cache(fsg);
|
||||
break;
|
||||
|
||||
case SC_TEST_UNIT_READY:
|
||||
case TEST_UNIT_READY:
|
||||
fsg->data_size_from_cmnd = 0;
|
||||
reply = check_command(fsg, 6, DATA_DIR_NONE,
|
||||
0, 1,
|
||||
|
|
@ -2535,7 +2532,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
|
||||
/* Although optional, this command is used by MS-Windows. We
|
||||
* support a minimal version: BytChk must be 0. */
|
||||
case SC_VERIFY:
|
||||
case VERIFY:
|
||||
fsg->data_size_from_cmnd = 0;
|
||||
if ((reply = check_command(fsg, 10, DATA_DIR_NONE,
|
||||
(1<<1) | (0xf<<2) | (3<<7), 1,
|
||||
|
|
@ -2543,7 +2540,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_verify(fsg);
|
||||
break;
|
||||
|
||||
case SC_WRITE_6:
|
||||
case WRITE_6:
|
||||
i = fsg->cmnd[4];
|
||||
fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
|
||||
if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
|
||||
|
|
@ -2552,7 +2549,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_write(fsg);
|
||||
break;
|
||||
|
||||
case SC_WRITE_10:
|
||||
case WRITE_10:
|
||||
fsg->data_size_from_cmnd =
|
||||
get_unaligned_be16(&fsg->cmnd[7]) << 9;
|
||||
if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
|
||||
|
|
@ -2561,7 +2558,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
reply = do_write(fsg);
|
||||
break;
|
||||
|
||||
case SC_WRITE_12:
|
||||
case WRITE_12:
|
||||
fsg->data_size_from_cmnd =
|
||||
get_unaligned_be32(&fsg->cmnd[6]) << 9;
|
||||
if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
|
||||
|
|
@ -2574,10 +2571,10 @@ static int do_scsi_command(struct fsg_dev *fsg)
|
|||
* They don't mean much in this setting. It's left as an exercise
|
||||
* for anyone interested to implement RESERVE and RELEASE in terms
|
||||
* of Posix locks. */
|
||||
case SC_FORMAT_UNIT:
|
||||
case SC_RELEASE:
|
||||
case SC_RESERVE:
|
||||
case SC_SEND_DIAGNOSTIC:
|
||||
case FORMAT_UNIT:
|
||||
case RELEASE:
|
||||
case RESERVE:
|
||||
case SEND_DIAGNOSTIC:
|
||||
// Fall through
|
||||
|
||||
default:
|
||||
|
|
@ -3178,6 +3175,7 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
|
|||
for (i = 0; i < fsg->nluns; ++i) {
|
||||
curlun = &fsg->luns[i];
|
||||
if (curlun->registered) {
|
||||
device_remove_file(&curlun->dev, &dev_attr_nofua);
|
||||
device_remove_file(&curlun->dev, &dev_attr_ro);
|
||||
device_remove_file(&curlun->dev, &dev_attr_file);
|
||||
fsg_lun_close(curlun);
|
||||
|
|
@ -3213,7 +3211,6 @@ static int __init check_parameters(struct fsg_dev *fsg)
|
|||
{
|
||||
int prot;
|
||||
int gcnum;
|
||||
int i;
|
||||
|
||||
/* Store the default values */
|
||||
mod_data.transport_type = USB_PR_BULK;
|
||||
|
|
@ -3309,45 +3306,29 @@ static int __init check_parameters(struct fsg_dev *fsg)
|
|||
if ((*ch < '0' || *ch > '9') &&
|
||||
(*ch < 'A' || *ch > 'F')) { /* not uppercase hex */
|
||||
WARNING(fsg,
|
||||
"Invalid serial string character: %c; "
|
||||
"Failing back to default\n",
|
||||
"Invalid serial string character: %c\n",
|
||||
*ch);
|
||||
goto fill_serial;
|
||||
goto no_serial;
|
||||
}
|
||||
}
|
||||
if (len > 126 ||
|
||||
(mod_data.transport_type == USB_PR_BULK && len < 12) ||
|
||||
(mod_data.transport_type != USB_PR_BULK && len > 12)) {
|
||||
WARNING(fsg,
|
||||
"Invalid serial string length; "
|
||||
"Failing back to default\n");
|
||||
goto fill_serial;
|
||||
WARNING(fsg, "Invalid serial string length!\n");
|
||||
goto no_serial;
|
||||
}
|
||||
fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial;
|
||||
} else {
|
||||
WARNING(fsg,
|
||||
"Userspace failed to provide serial number; "
|
||||
"Failing back to default\n");
|
||||
fill_serial:
|
||||
/* Serial number not specified or invalid, make our own.
|
||||
* We just encode it from the driver version string,
|
||||
* 12 characters to comply with both CB[I] and BBB spec.
|
||||
* Warning : Two devices running the same kernel will have
|
||||
* the same fallback serial number. */
|
||||
for (i = 0; i < 12; i += 2) {
|
||||
unsigned char c = DRIVER_VERSION[i / 2];
|
||||
|
||||
if (!c)
|
||||
break;
|
||||
sprintf(&fsg_string_serial[i], "%02X", c);
|
||||
}
|
||||
WARNING(fsg, "No serial-number string provided!\n");
|
||||
no_serial:
|
||||
device_desc.iSerialNumber = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int __ref fsg_bind(struct usb_gadget *gadget)
|
||||
static int __init fsg_bind(struct usb_gadget *gadget)
|
||||
{
|
||||
struct fsg_dev *fsg = the_fsg;
|
||||
int rc;
|
||||
|
|
@ -3607,7 +3588,6 @@ static struct usb_gadget_driver fsg_driver = {
|
|||
.speed = USB_SPEED_FULL,
|
||||
#endif
|
||||
.function = (char *) fsg_string_product,
|
||||
.bind = fsg_bind,
|
||||
.unbind = fsg_unbind,
|
||||
.disconnect = fsg_disconnect,
|
||||
.setup = fsg_setup,
|
||||
|
|
@ -3649,7 +3629,7 @@ static int __init fsg_init(void)
|
|||
if ((rc = fsg_alloc()) != 0)
|
||||
return rc;
|
||||
fsg = the_fsg;
|
||||
if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0)
|
||||
if ((rc = usb_gadget_probe_driver(&fsg_driver, fsg_bind)) != 0)
|
||||
kref_put(&fsg->ref, fsg_release);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@
|
|||
static struct clk *mxc_ahb_clk;
|
||||
static struct clk *mxc_usb_clk;
|
||||
|
||||
/* workaround ENGcm09152 for i.MX35 */
|
||||
#define USBPHYCTRL_OTGBASE_OFFSET 0x608
|
||||
#define USBPHYCTRL_EVDO (1 << 23)
|
||||
|
||||
int fsl_udc_clk_init(struct platform_device *pdev)
|
||||
{
|
||||
struct fsl_usb2_platform_data *pdata;
|
||||
|
|
@ -84,6 +88,17 @@ eenahb:
|
|||
void fsl_udc_clk_finalize(struct platform_device *pdev)
|
||||
{
|
||||
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
|
||||
#if defined(CONFIG_ARCH_MX35)
|
||||
unsigned int v;
|
||||
|
||||
/* workaround ENGcm09152 for i.MX35 */
|
||||
if (pdata->workaround & FLS_USB2_WORKAROUND_ENGCM09152) {
|
||||
v = readl(MX35_IO_ADDRESS(MX35_OTG_BASE_ADDR +
|
||||
USBPHYCTRL_OTGBASE_OFFSET));
|
||||
writel(v | USBPHYCTRL_EVDO, MX35_IO_ADDRESS(MX35_OTG_BASE_ADDR +
|
||||
USBPHYCTRL_OTGBASE_OFFSET));
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ULPI transceivers don't need usbpll */
|
||||
if (pdata->phy_mode == FSL_USB2_PHY_ULPI) {
|
||||
|
|
|
|||
|
|
@ -2302,9 +2302,10 @@ static irqreturn_t qe_udc_irq(int irq, void *_udc)
|
|||
}
|
||||
|
||||
/*-------------------------------------------------------------------------
|
||||
Gadget driver register and unregister.
|
||||
Gadget driver probe and unregister.
|
||||
--------------------------------------------------------------------------*/
|
||||
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
int retval;
|
||||
unsigned long flags = 0;
|
||||
|
|
@ -2315,8 +2316,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
|
||||
if (!driver || (driver->speed != USB_SPEED_FULL
|
||||
&& driver->speed != USB_SPEED_HIGH)
|
||||
|| !driver->bind || !driver->disconnect
|
||||
|| !driver->setup)
|
||||
|| !bind || !driver->disconnect || !driver->setup)
|
||||
return -EINVAL;
|
||||
|
||||
if (udc_controller->driver)
|
||||
|
|
@ -2332,7 +2332,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
udc_controller->gadget.speed = (enum usb_device_speed)(driver->speed);
|
||||
spin_unlock_irqrestore(&udc_controller->lock, flags);
|
||||
|
||||
retval = driver->bind(&udc_controller->gadget);
|
||||
retval = bind(&udc_controller->gadget);
|
||||
if (retval) {
|
||||
dev_err(udc_controller->dev, "bind to %s --> %d",
|
||||
driver->driver.name, retval);
|
||||
|
|
@ -2353,7 +2353,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
udc_controller->gadget.name, driver->driver.name);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_register_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1765,7 +1765,8 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
|
|||
* Hook to gadget drivers
|
||||
* Called by initialization code of gadget drivers
|
||||
*----------------------------------------------------------------*/
|
||||
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
int retval = -ENODEV;
|
||||
unsigned long flags = 0;
|
||||
|
|
@ -1775,8 +1776,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
|
||||
if (!driver || (driver->speed != USB_SPEED_FULL
|
||||
&& driver->speed != USB_SPEED_HIGH)
|
||||
|| !driver->bind || !driver->disconnect
|
||||
|| !driver->setup)
|
||||
|| !bind || !driver->disconnect || !driver->setup)
|
||||
return -EINVAL;
|
||||
|
||||
if (udc_controller->driver)
|
||||
|
|
@ -1792,7 +1792,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
spin_unlock_irqrestore(&udc_controller->lock, flags);
|
||||
|
||||
/* bind udc driver to gadget driver */
|
||||
retval = driver->bind(&udc_controller->gadget);
|
||||
retval = bind(&udc_controller->gadget);
|
||||
if (retval) {
|
||||
VDBG("bind to %s --> %d", driver->driver.name, retval);
|
||||
udc_controller->gadget.dev.driver = NULL;
|
||||
|
|
@ -1814,7 +1814,7 @@ out:
|
|||
retval);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_register_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
/* Disconnect from gadget driver */
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
|
|
|
|||
|
|
@ -52,9 +52,8 @@ MODULE_DESCRIPTION(DRIVER_DESC);
|
|||
MODULE_AUTHOR("Michal Nazarewicz");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
static unsigned short gfs_vendor_id = 0x0525; /* XXX NetChip */
|
||||
static unsigned short gfs_product_id = 0xa4ac; /* XXX */
|
||||
#define GFS_VENDOR_ID 0x1d6b /* Linux Foundation */
|
||||
#define GFS_PRODUCT_ID 0x0105 /* FunctionFS Gadget */
|
||||
|
||||
static struct usb_device_descriptor gfs_dev_desc = {
|
||||
.bLength = sizeof gfs_dev_desc,
|
||||
|
|
@ -63,29 +62,16 @@ static struct usb_device_descriptor gfs_dev_desc = {
|
|||
.bcdUSB = cpu_to_le16(0x0200),
|
||||
.bDeviceClass = USB_CLASS_PER_INTERFACE,
|
||||
|
||||
/* Vendor and product id can be overridden by module parameters. */
|
||||
/* .idVendor = cpu_to_le16(gfs_vendor_id), */
|
||||
/* .idProduct = cpu_to_le16(gfs_product_id), */
|
||||
/* .bcdDevice = f(hardware) */
|
||||
/* .iManufacturer = DYNAMIC */
|
||||
/* .iProduct = DYNAMIC */
|
||||
/* NO SERIAL NUMBER */
|
||||
.bNumConfigurations = 1,
|
||||
.idVendor = cpu_to_le16(GFS_VENDOR_ID),
|
||||
.idProduct = cpu_to_le16(GFS_PRODUCT_ID),
|
||||
};
|
||||
|
||||
#define GFS_MODULE_PARAM_DESC(name, field) \
|
||||
MODULE_PARM_DESC(name, "Value of the " #field " field of the device descriptor sent to the host. Takes effect only prior to the user-space driver registering to the FunctionFS.")
|
||||
|
||||
module_param_named(usb_class, gfs_dev_desc.bDeviceClass, byte, 0644);
|
||||
GFS_MODULE_PARAM_DESC(usb_class, bDeviceClass);
|
||||
module_param_named(usb_subclass, gfs_dev_desc.bDeviceSubClass, byte, 0644);
|
||||
GFS_MODULE_PARAM_DESC(usb_subclass, bDeviceSubClass);
|
||||
module_param_named(usb_protocol, gfs_dev_desc.bDeviceProtocol, byte, 0644);
|
||||
GFS_MODULE_PARAM_DESC(usb_protocol, bDeviceProtocol);
|
||||
module_param_named(usb_vendor, gfs_vendor_id, ushort, 0644);
|
||||
GFS_MODULE_PARAM_DESC(usb_vendor, idVendor);
|
||||
module_param_named(usb_product, gfs_product_id, ushort, 0644);
|
||||
GFS_MODULE_PARAM_DESC(usb_product, idProduct);
|
||||
module_param_named(bDeviceClass, gfs_dev_desc.bDeviceClass, byte, 0644);
|
||||
MODULE_PARM_DESC(bDeviceClass, "USB Device class");
|
||||
module_param_named(bDeviceSubClass, gfs_dev_desc.bDeviceSubClass, byte, 0644);
|
||||
MODULE_PARM_DESC(bDeviceSubClass, "USB Device subclass");
|
||||
module_param_named(bDeviceProtocol, gfs_dev_desc.bDeviceProtocol, byte, 0644);
|
||||
MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol");
|
||||
|
||||
|
||||
|
||||
|
|
@ -95,8 +81,10 @@ static const struct usb_descriptor_header *gfs_otg_desc[] = {
|
|||
.bLength = sizeof(struct usb_otg_descriptor),
|
||||
.bDescriptorType = USB_DT_OTG,
|
||||
|
||||
/* REVISIT SRP-only hardware is possible, although
|
||||
* it would not be called "OTG" ... */
|
||||
/*
|
||||
* REVISIT SRP-only hardware is possible, although
|
||||
* it would not be called "OTG" ...
|
||||
*/
|
||||
.bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
|
||||
},
|
||||
|
||||
|
|
@ -105,19 +93,7 @@ static const struct usb_descriptor_header *gfs_otg_desc[] = {
|
|||
|
||||
/* string IDs are assigned dynamically */
|
||||
|
||||
enum {
|
||||
GFS_STRING_MANUFACTURER_IDX,
|
||||
GFS_STRING_PRODUCT_IDX,
|
||||
GFS_STRING_FIRST_CONFIG_IDX,
|
||||
};
|
||||
|
||||
static char gfs_manufacturer[50];
|
||||
static const char gfs_driver_desc[] = DRIVER_DESC;
|
||||
static const char gfs_short_name[] = DRIVER_NAME;
|
||||
|
||||
static struct usb_string gfs_strings[] = {
|
||||
[GFS_STRING_MANUFACTURER_IDX].s = gfs_manufacturer,
|
||||
[GFS_STRING_PRODUCT_IDX].s = gfs_driver_desc,
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_RNDIS
|
||||
{ .s = "FunctionFS + RNDIS" },
|
||||
#endif
|
||||
|
|
@ -168,11 +144,11 @@ static int gfs_unbind(struct usb_composite_dev *cdev);
|
|||
static int gfs_do_config(struct usb_configuration *c);
|
||||
|
||||
static struct usb_composite_driver gfs_driver = {
|
||||
.name = gfs_short_name,
|
||||
.name = DRIVER_NAME,
|
||||
.dev = &gfs_dev_desc,
|
||||
.strings = gfs_dev_strings,
|
||||
.bind = gfs_bind,
|
||||
.unbind = gfs_unbind,
|
||||
.iProduct = DRIVER_DESC,
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -210,7 +186,7 @@ static int functionfs_ready_callback(struct ffs_data *ffs)
|
|||
return -EBUSY;
|
||||
|
||||
gfs_ffs_data = ffs;
|
||||
ret = usb_composite_register(&gfs_driver);
|
||||
ret = usb_composite_probe(&gfs_driver, gfs_bind);
|
||||
if (unlikely(ret < 0))
|
||||
clear_bit(0, &gfs_registered);
|
||||
return ret;
|
||||
|
|
@ -245,20 +221,10 @@ static int gfs_bind(struct usb_composite_dev *cdev)
|
|||
if (unlikely(ret < 0))
|
||||
goto error_quick;
|
||||
|
||||
gfs_dev_desc.idVendor = cpu_to_le16(gfs_vendor_id);
|
||||
gfs_dev_desc.idProduct = cpu_to_le16(gfs_product_id);
|
||||
|
||||
snprintf(gfs_manufacturer, sizeof gfs_manufacturer, "%s %s with %s",
|
||||
init_utsname()->sysname, init_utsname()->release,
|
||||
cdev->gadget->name);
|
||||
|
||||
ret = usb_string_ids_tab(cdev, gfs_strings);
|
||||
if (unlikely(ret < 0))
|
||||
goto error;
|
||||
|
||||
gfs_dev_desc.iManufacturer = gfs_strings[GFS_STRING_MANUFACTURER_IDX].id;
|
||||
gfs_dev_desc.iProduct = gfs_strings[GFS_STRING_PRODUCT_IDX].id;
|
||||
|
||||
ret = functionfs_bind(gfs_ffs_data, cdev);
|
||||
if (unlikely(ret < 0))
|
||||
goto error;
|
||||
|
|
@ -266,14 +232,12 @@ static int gfs_bind(struct usb_composite_dev *cdev)
|
|||
for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) {
|
||||
struct gfs_configuration *c = gfs_configurations + i;
|
||||
|
||||
ret = GFS_STRING_FIRST_CONFIG_IDX + i;
|
||||
c->c.label = gfs_strings[ret].s;
|
||||
c->c.iConfiguration = gfs_strings[ret].id;
|
||||
c->c.bind = gfs_do_config;
|
||||
c->c.label = gfs_strings[i].s;
|
||||
c->c.iConfiguration = gfs_strings[i].id;
|
||||
c->c.bConfigurationValue = 1 + i;
|
||||
c->c.bmAttributes = USB_CONFIG_ATT_SELFPOWER;
|
||||
|
||||
ret = usb_add_config(cdev, &c->c);
|
||||
ret = usb_add_config(cdev, &c->c, gfs_do_config);
|
||||
if (unlikely(ret < 0))
|
||||
goto error_unbind;
|
||||
}
|
||||
|
|
@ -293,13 +257,14 @@ static int gfs_unbind(struct usb_composite_dev *cdev)
|
|||
{
|
||||
ENTER();
|
||||
|
||||
/* We may have been called in an error recovery frem
|
||||
/*
|
||||
* We may have been called in an error recovery from
|
||||
* composite_bind() after gfs_unbind() failure so we need to
|
||||
* check if gfs_ffs_data is not NULL since gfs_bind() handles
|
||||
* all error recovery itself. I'd rather we werent called
|
||||
* from composite on orror recovery, but what you're gonna
|
||||
* do...? */
|
||||
|
||||
* do...?
|
||||
*/
|
||||
if (gfs_ffs_data) {
|
||||
gether_cleanup();
|
||||
functionfs_unbind(gfs_ffs_data);
|
||||
|
|
@ -334,14 +299,16 @@ static int gfs_do_config(struct usb_configuration *c)
|
|||
if (unlikely(ret < 0))
|
||||
return ret;
|
||||
|
||||
/* After previous do_configs there may be some invalid
|
||||
/*
|
||||
* After previous do_configs there may be some invalid
|
||||
* pointers in c->interface array. This happens every time
|
||||
* a user space function with fewer interfaces than a user
|
||||
* space function that was run before the new one is run. The
|
||||
* compasit's set_config() assumes that if there is no more
|
||||
* then MAX_CONFIG_INTERFACES interfaces in a configuration
|
||||
* then there is a NULL pointer after the last interface in
|
||||
* c->interface array. We need to make sure this is true. */
|
||||
* c->interface array. We need to make sure this is true.
|
||||
*/
|
||||
if (c->next_interface_id < ARRAY_SIZE(c->interface))
|
||||
c->interface[c->next_interface_id] = NULL;
|
||||
|
||||
|
|
@ -350,10 +317,12 @@ static int gfs_do_config(struct usb_configuration *c)
|
|||
|
||||
|
||||
#ifdef CONFIG_USB_FUNCTIONFS_ETH
|
||||
|
||||
static int eth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
|
||||
{
|
||||
return can_support_ecm(c->cdev->gadget)
|
||||
? ecm_bind_config(c, ethaddr)
|
||||
: geth_bind_config(c, ethaddr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1157,7 +1157,7 @@ fail:
|
|||
/*
|
||||
* Creates an output endpoint, and initializes output ports.
|
||||
*/
|
||||
static int __ref gmidi_bind(struct usb_gadget *gadget)
|
||||
static int __init gmidi_bind(struct usb_gadget *gadget)
|
||||
{
|
||||
struct gmidi_device *dev;
|
||||
struct usb_ep *in_ep, *out_ep;
|
||||
|
|
@ -1292,7 +1292,6 @@ static void gmidi_resume(struct usb_gadget *gadget)
|
|||
static struct usb_gadget_driver gmidi_driver = {
|
||||
.speed = USB_SPEED_FULL,
|
||||
.function = (char *)longname,
|
||||
.bind = gmidi_bind,
|
||||
.unbind = gmidi_unbind,
|
||||
|
||||
.setup = gmidi_setup,
|
||||
|
|
@ -1309,7 +1308,7 @@ static struct usb_gadget_driver gmidi_driver = {
|
|||
|
||||
static int __init gmidi_init(void)
|
||||
{
|
||||
return usb_gadget_register_driver(&gmidi_driver);
|
||||
return usb_gadget_probe_driver(&gmidi_driver, gmidi_bind);
|
||||
}
|
||||
module_init(gmidi_init);
|
||||
|
||||
|
|
|
|||
|
|
@ -1343,14 +1343,15 @@ static struct goku_udc *the_controller;
|
|||
* disconnect is reported. then a host may connect again, or
|
||||
* the driver might get unbound.
|
||||
*/
|
||||
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct goku_udc *dev = the_controller;
|
||||
int retval;
|
||||
|
||||
if (!driver
|
||||
|| driver->speed < USB_SPEED_FULL
|
||||
|| !driver->bind
|
||||
|| !bind
|
||||
|| !driver->disconnect
|
||||
|| !driver->setup)
|
||||
return -EINVAL;
|
||||
|
|
@ -1363,7 +1364,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
driver->driver.bus = NULL;
|
||||
dev->driver = driver;
|
||||
dev->gadget.dev.driver = &driver->driver;
|
||||
retval = driver->bind(&dev->gadget);
|
||||
retval = bind(&dev->gadget);
|
||||
if (retval) {
|
||||
DBG(dev, "bind to driver %s --> error %d\n",
|
||||
driver->driver.name, retval);
|
||||
|
|
@ -1380,7 +1381,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
DBG(dev, "registered gadget driver '%s'\n", driver->driver.name);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_register_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
static void
|
||||
stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver)
|
||||
|
|
@ -1744,7 +1745,8 @@ static void goku_remove(struct pci_dev *pdev)
|
|||
pci_resource_len (pdev, 0));
|
||||
if (dev->enabled)
|
||||
pci_disable_device(pdev);
|
||||
device_unregister(&dev->gadget.dev);
|
||||
if (dev->registered)
|
||||
device_unregister(&dev->gadget.dev);
|
||||
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
dev->regs = NULL;
|
||||
|
|
@ -1774,7 +1776,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
if (!pdev->irq) {
|
||||
printk(KERN_ERR "Check PCI %s IRQ setup!\n", pci_name(pdev));
|
||||
retval = -ENODEV;
|
||||
goto done;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* alloc, and start init */
|
||||
|
|
@ -1782,7 +1784,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
if (dev == NULL){
|
||||
pr_debug("enomem %s\n", pci_name(pdev));
|
||||
retval = -ENOMEM;
|
||||
goto done;
|
||||
goto err;
|
||||
}
|
||||
|
||||
spin_lock_init(&dev->lock);
|
||||
|
|
@ -1800,7 +1802,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
retval = pci_enable_device(pdev);
|
||||
if (retval < 0) {
|
||||
DBG(dev, "can't enable, %d\n", retval);
|
||||
goto done;
|
||||
goto err;
|
||||
}
|
||||
dev->enabled = 1;
|
||||
|
||||
|
|
@ -1809,7 +1811,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
if (!request_mem_region(resource, len, driver_name)) {
|
||||
DBG(dev, "controller already in use\n");
|
||||
retval = -EBUSY;
|
||||
goto done;
|
||||
goto err;
|
||||
}
|
||||
dev->got_region = 1;
|
||||
|
||||
|
|
@ -1817,7 +1819,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
if (base == NULL) {
|
||||
DBG(dev, "can't map memory\n");
|
||||
retval = -EFAULT;
|
||||
goto done;
|
||||
goto err;
|
||||
}
|
||||
dev->regs = (struct goku_udc_regs __iomem *) base;
|
||||
|
||||
|
|
@ -1833,7 +1835,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
driver_name, dev) != 0) {
|
||||
DBG(dev, "request interrupt %d failed\n", pdev->irq);
|
||||
retval = -EBUSY;
|
||||
goto done;
|
||||
goto err;
|
||||
}
|
||||
dev->got_irq = 1;
|
||||
if (use_dma)
|
||||
|
|
@ -1844,13 +1846,16 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev);
|
||||
#endif
|
||||
|
||||
/* done */
|
||||
the_controller = dev;
|
||||
retval = device_register(&dev->gadget.dev);
|
||||
if (retval == 0)
|
||||
return 0;
|
||||
if (retval) {
|
||||
put_device(&dev->gadget.dev);
|
||||
goto err;
|
||||
}
|
||||
dev->registered = 1;
|
||||
return 0;
|
||||
|
||||
done:
|
||||
err:
|
||||
if (dev)
|
||||
goku_remove (pdev);
|
||||
return retval;
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ static struct usb_gadget_strings *dev_strings[] = {
|
|||
|
||||
/****************************** Configurations ******************************/
|
||||
|
||||
static int __ref do_config(struct usb_configuration *c)
|
||||
static int __init do_config(struct usb_configuration *c)
|
||||
{
|
||||
struct hidg_func_node *e;
|
||||
int func = 0, status = 0;
|
||||
|
|
@ -148,7 +148,6 @@ static int __ref do_config(struct usb_configuration *c)
|
|||
|
||||
static struct usb_configuration config_driver = {
|
||||
.label = "HID Gadget",
|
||||
.bind = do_config,
|
||||
.bConfigurationValue = 1,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
|
|
@ -156,7 +155,7 @@ static struct usb_configuration config_driver = {
|
|||
|
||||
/****************************** Gadget Bind ******************************/
|
||||
|
||||
static int __ref hid_bind(struct usb_composite_dev *cdev)
|
||||
static int __init hid_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
struct list_head *tmp;
|
||||
|
|
@ -201,7 +200,7 @@ static int __ref hid_bind(struct usb_composite_dev *cdev)
|
|||
device_desc.iProduct = status;
|
||||
|
||||
/* register our configuration */
|
||||
status = usb_add_config(cdev, &config_driver);
|
||||
status = usb_add_config(cdev, &config_driver, do_config);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
|
|
@ -256,7 +255,6 @@ static struct usb_composite_driver hidg_driver = {
|
|||
.name = "g_hid",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.bind = hid_bind,
|
||||
.unbind = __exit_p(hid_unbind),
|
||||
};
|
||||
|
||||
|
|
@ -282,7 +280,7 @@ static int __init hidg_init(void)
|
|||
if (status < 0)
|
||||
return status;
|
||||
|
||||
status = usb_composite_register(&hidg_driver);
|
||||
status = usb_composite_probe(&hidg_driver, hid_bind);
|
||||
if (status < 0)
|
||||
platform_driver_unregister(&hidg_plat_driver);
|
||||
|
||||
|
|
|
|||
|
|
@ -1319,14 +1319,15 @@ static struct imx_udc_struct controller = {
|
|||
* USB gadged driver functions
|
||||
*******************************************************************************
|
||||
*/
|
||||
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct imx_udc_struct *imx_usb = &controller;
|
||||
int retval;
|
||||
|
||||
if (!driver
|
||||
|| driver->speed < USB_SPEED_FULL
|
||||
|| !driver->bind
|
||||
|| !bind
|
||||
|| !driver->disconnect
|
||||
|| !driver->setup)
|
||||
return -EINVAL;
|
||||
|
|
@ -1342,7 +1343,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
retval = device_add(&imx_usb->gadget.dev);
|
||||
if (retval)
|
||||
goto fail;
|
||||
retval = driver->bind(&imx_usb->gadget);
|
||||
retval = bind(&imx_usb->gadget);
|
||||
if (retval) {
|
||||
D_ERR(imx_usb->dev, "<%s> bind to driver %s --> error %d\n",
|
||||
__func__, driver->driver.name, retval);
|
||||
|
|
@ -1362,7 +1363,7 @@ fail:
|
|||
imx_usb->gadget.dev.driver = NULL;
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_register_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1774,7 +1774,6 @@ static struct usb_gadget_driver gadgetfs_driver = {
|
|||
.speed = USB_SPEED_FULL,
|
||||
#endif
|
||||
.function = (char *) driver_desc,
|
||||
.bind = gadgetfs_bind,
|
||||
.unbind = gadgetfs_unbind,
|
||||
.setup = gadgetfs_setup,
|
||||
.disconnect = gadgetfs_disconnect,
|
||||
|
|
@ -1797,7 +1796,6 @@ static int gadgetfs_probe (struct usb_gadget *gadget)
|
|||
|
||||
static struct usb_gadget_driver probe_driver = {
|
||||
.speed = USB_SPEED_HIGH,
|
||||
.bind = gadgetfs_probe,
|
||||
.unbind = gadgetfs_nop,
|
||||
.setup = (void *)gadgetfs_nop,
|
||||
.disconnect = gadgetfs_nop,
|
||||
|
|
@ -1907,7 +1905,7 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
|
|||
|
||||
/* triggers gadgetfs_bind(); then we can enumerate. */
|
||||
spin_unlock_irq (&dev->lock);
|
||||
value = usb_gadget_register_driver (&gadgetfs_driver);
|
||||
value = usb_gadget_probe_driver(&gadgetfs_driver, gadgetfs_bind);
|
||||
if (value != 0) {
|
||||
kfree (dev->buf);
|
||||
dev->buf = NULL;
|
||||
|
|
@ -2046,7 +2044,7 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
|
|||
return -ESRCH;
|
||||
|
||||
/* fake probe to determine $CHIP */
|
||||
(void) usb_gadget_register_driver (&probe_driver);
|
||||
(void) usb_gadget_probe_driver(&probe_driver, gadgetfs_probe);
|
||||
if (!CHIP)
|
||||
return -ENODEV;
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -18,11 +18,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/usb/langwell_udc.h>
|
||||
|
||||
#if defined(CONFIG_USB_LANGWELL_OTG)
|
||||
#include <linux/usb/langwell_otg.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
|
|
@ -199,7 +195,9 @@ struct langwell_udc {
|
|||
vbus_active:1,
|
||||
suspended:1,
|
||||
stopped:1,
|
||||
lpm:1; /* LPM capability */
|
||||
lpm:1, /* LPM capability */
|
||||
has_sram:1, /* SRAM caching */
|
||||
got_sram:1;
|
||||
|
||||
/* pci state used to access those endpoints */
|
||||
struct pci_dev *pdev;
|
||||
|
|
@ -224,5 +222,12 @@ struct langwell_udc {
|
|||
|
||||
/* make sure release() is done */
|
||||
struct completion *done;
|
||||
|
||||
/* for private SRAM caching */
|
||||
unsigned int sram_addr;
|
||||
unsigned int sram_size;
|
||||
|
||||
/* device status data for get_status request */
|
||||
u16 dev_status;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -408,7 +408,8 @@ static void udc_enable(struct lh7a40x_udc *dev)
|
|||
/*
|
||||
Register entry point for the peripheral controller driver.
|
||||
*/
|
||||
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct lh7a40x_udc *dev = the_controller;
|
||||
int retval;
|
||||
|
|
@ -417,7 +418,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
|
||||
if (!driver
|
||||
|| driver->speed != USB_SPEED_FULL
|
||||
|| !driver->bind
|
||||
|| !bind
|
||||
|| !driver->disconnect
|
||||
|| !driver->setup)
|
||||
return -EINVAL;
|
||||
|
|
@ -431,7 +432,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
dev->gadget.dev.driver = &driver->driver;
|
||||
|
||||
device_add(&dev->gadget.dev);
|
||||
retval = driver->bind(&dev->gadget);
|
||||
retval = bind(&dev->gadget);
|
||||
if (retval) {
|
||||
printk(KERN_WARNING "%s: bind to driver %s --> error %d\n",
|
||||
dev->gadget.name, driver->driver.name, retval);
|
||||
|
|
@ -453,8 +454,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(usb_gadget_register_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
/*
|
||||
Unregister entry point for the peripheral controller driver.
|
||||
|
|
|
|||
|
|
@ -1454,14 +1454,15 @@ static struct usb_ep_ops m66592_ep_ops = {
|
|||
/*-------------------------------------------------------------------------*/
|
||||
static struct m66592 *the_controller;
|
||||
|
||||
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct m66592 *m66592 = the_controller;
|
||||
int retval;
|
||||
|
||||
if (!driver
|
||||
|| driver->speed != USB_SPEED_HIGH
|
||||
|| !driver->bind
|
||||
|| !bind
|
||||
|| !driver->setup)
|
||||
return -EINVAL;
|
||||
if (!m66592)
|
||||
|
|
@ -1480,7 +1481,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
goto error;
|
||||
}
|
||||
|
||||
retval = driver->bind (&m66592->gadget);
|
||||
retval = bind(&m66592->gadget);
|
||||
if (retval) {
|
||||
pr_err("bind to driver error (%d)\n", retval);
|
||||
device_del(&m66592->gadget.dev);
|
||||
|
|
@ -1505,7 +1506,7 @@ error:
|
|||
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_register_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -75,10 +75,6 @@ static struct usb_device_descriptor msg_device_desc = {
|
|||
/* Vendor and product id can be overridden by module parameters. */
|
||||
.idVendor = cpu_to_le16(FSG_VENDOR_ID),
|
||||
.idProduct = cpu_to_le16(FSG_PRODUCT_ID),
|
||||
/* .bcdDevice = f(hardware) */
|
||||
/* .iManufacturer = DYNAMIC */
|
||||
/* .iProduct = DYNAMIC */
|
||||
/* NO SERIAL NUMBER */
|
||||
.bNumConfigurations = 1,
|
||||
};
|
||||
|
||||
|
|
@ -86,7 +82,8 @@ static struct usb_otg_descriptor otg_descriptor = {
|
|||
.bLength = sizeof otg_descriptor,
|
||||
.bDescriptorType = USB_DT_OTG,
|
||||
|
||||
/* REVISIT SRP-only hardware is possible, although
|
||||
/*
|
||||
* REVISIT SRP-only hardware is possible, although
|
||||
* it would not be called "OTG" ...
|
||||
*/
|
||||
.bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
|
||||
|
|
@ -98,33 +95,6 @@ static const struct usb_descriptor_header *otg_desc[] = {
|
|||
};
|
||||
|
||||
|
||||
/* string IDs are assigned dynamically */
|
||||
|
||||
#define STRING_MANUFACTURER_IDX 0
|
||||
#define STRING_PRODUCT_IDX 1
|
||||
#define STRING_CONFIGURATION_IDX 2
|
||||
|
||||
static char manufacturer[50];
|
||||
|
||||
static struct usb_string strings_dev[] = {
|
||||
[STRING_MANUFACTURER_IDX].s = manufacturer,
|
||||
[STRING_PRODUCT_IDX].s = DRIVER_DESC,
|
||||
[STRING_CONFIGURATION_IDX].s = "Self Powered",
|
||||
{ } /* end of list */
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings stringtab_dev = {
|
||||
.language = 0x0409, /* en-us */
|
||||
.strings = strings_dev,
|
||||
};
|
||||
|
||||
static struct usb_gadget_strings *dev_strings[] = {
|
||||
&stringtab_dev,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/****************************** Configurations ******************************/
|
||||
|
||||
static struct fsg_module_parameters mod_data = {
|
||||
|
|
@ -141,7 +111,7 @@ static int msg_thread_exits(struct fsg_common *common)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __ref msg_do_config(struct usb_configuration *c)
|
||||
static int __init msg_do_config(struct usb_configuration *c)
|
||||
{
|
||||
static const struct fsg_operations ops = {
|
||||
.thread_exits = msg_thread_exits,
|
||||
|
|
@ -171,54 +141,23 @@ static int __ref msg_do_config(struct usb_configuration *c)
|
|||
|
||||
static struct usb_configuration msg_config_driver = {
|
||||
.label = "Linux File-Backed Storage",
|
||||
.bind = msg_do_config,
|
||||
.bConfigurationValue = 1,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
};
|
||||
|
||||
|
||||
|
||||
/****************************** Gadget Bind ******************************/
|
||||
|
||||
|
||||
static int __ref msg_bind(struct usb_composite_dev *cdev)
|
||||
static int __init msg_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
int status;
|
||||
|
||||
/* Allocate string descriptor numbers ... note that string
|
||||
* contents can be overridden by the composite_dev glue.
|
||||
*/
|
||||
|
||||
/* device descriptor strings: manufacturer, product */
|
||||
snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
|
||||
init_utsname()->sysname, init_utsname()->release,
|
||||
gadget->name);
|
||||
status = usb_string_id(cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
strings_dev[STRING_MANUFACTURER_IDX].id = status;
|
||||
msg_device_desc.iManufacturer = status;
|
||||
|
||||
status = usb_string_id(cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
strings_dev[STRING_PRODUCT_IDX].id = status;
|
||||
msg_device_desc.iProduct = status;
|
||||
|
||||
status = usb_string_id(cdev);
|
||||
if (status < 0)
|
||||
return status;
|
||||
strings_dev[STRING_CONFIGURATION_IDX].id = status;
|
||||
msg_config_driver.iConfiguration = status;
|
||||
|
||||
/* register our second configuration */
|
||||
status = usb_add_config(cdev, &msg_config_driver);
|
||||
status = usb_add_config(cdev, &msg_config_driver, msg_do_config);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
dev_info(&gadget->dev, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
|
||||
dev_info(&cdev->gadget->dev,
|
||||
DRIVER_DESC ", version: " DRIVER_VERSION "\n");
|
||||
set_bit(0, &msg_registered);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -226,12 +165,11 @@ static int __ref msg_bind(struct usb_composite_dev *cdev)
|
|||
|
||||
/****************************** Some noise ******************************/
|
||||
|
||||
|
||||
static struct usb_composite_driver msg_driver = {
|
||||
.name = "g_mass_storage",
|
||||
.dev = &msg_device_desc,
|
||||
.strings = dev_strings,
|
||||
.bind = msg_bind,
|
||||
.iProduct = DRIVER_DESC,
|
||||
.needs_serial = 1,
|
||||
};
|
||||
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
|
|
@ -240,7 +178,7 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
static int __init msg_init(void)
|
||||
{
|
||||
return usb_composite_register(&msg_driver);
|
||||
return usb_composite_probe(&msg_driver, msg_bind);
|
||||
}
|
||||
module_init(msg_init);
|
||||
|
||||
|
|
|
|||
|
|
@ -74,8 +74,8 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
/***************************** Device Descriptor ****************************/
|
||||
|
||||
#define MULTI_VENDOR_NUM 0x0525 /* XXX NetChip */
|
||||
#define MULTI_PRODUCT_NUM 0xa4ab /* XXX */
|
||||
#define MULTI_VENDOR_NUM 0x1d6b /* Linux Foundation */
|
||||
#define MULTI_PRODUCT_NUM 0x0104 /* Multifunction Composite Gadget */
|
||||
|
||||
|
||||
enum {
|
||||
|
|
@ -121,8 +121,6 @@ static const struct usb_descriptor_header *otg_desc[] = {
|
|||
|
||||
|
||||
enum {
|
||||
MULTI_STRING_MANUFACTURER_IDX,
|
||||
MULTI_STRING_PRODUCT_IDX,
|
||||
#ifdef CONFIG_USB_G_MULTI_RNDIS
|
||||
MULTI_STRING_RNDIS_CONFIG_IDX,
|
||||
#endif
|
||||
|
|
@ -131,11 +129,7 @@ enum {
|
|||
#endif
|
||||
};
|
||||
|
||||
static char manufacturer[50];
|
||||
|
||||
static struct usb_string strings_dev[] = {
|
||||
[MULTI_STRING_MANUFACTURER_IDX].s = manufacturer,
|
||||
[MULTI_STRING_PRODUCT_IDX].s = DRIVER_DESC,
|
||||
#ifdef CONFIG_USB_G_MULTI_RNDIS
|
||||
[MULTI_STRING_RNDIS_CONFIG_IDX].s = "Multifunction with RNDIS",
|
||||
#endif
|
||||
|
|
@ -170,7 +164,7 @@ static u8 hostaddr[ETH_ALEN];
|
|||
|
||||
#ifdef USB_ETH_RNDIS
|
||||
|
||||
static __ref int rndis_do_config(struct usb_configuration *c)
|
||||
static __init int rndis_do_config(struct usb_configuration *c)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
|
@ -197,7 +191,6 @@ static __ref int rndis_do_config(struct usb_configuration *c)
|
|||
static int rndis_config_register(struct usb_composite_dev *cdev)
|
||||
{
|
||||
static struct usb_configuration config = {
|
||||
.bind = rndis_do_config,
|
||||
.bConfigurationValue = MULTI_RNDIS_CONFIG_NUM,
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
};
|
||||
|
|
@ -205,7 +198,7 @@ static int rndis_config_register(struct usb_composite_dev *cdev)
|
|||
config.label = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].s;
|
||||
config.iConfiguration = strings_dev[MULTI_STRING_RNDIS_CONFIG_IDX].id;
|
||||
|
||||
return usb_add_config(cdev, &config);
|
||||
return usb_add_config(cdev, &config, rndis_do_config);
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
@ -222,7 +215,7 @@ static int rndis_config_register(struct usb_composite_dev *cdev)
|
|||
|
||||
#ifdef CONFIG_USB_G_MULTI_CDC
|
||||
|
||||
static __ref int cdc_do_config(struct usb_configuration *c)
|
||||
static __init int cdc_do_config(struct usb_configuration *c)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
|
@ -249,7 +242,6 @@ static __ref int cdc_do_config(struct usb_configuration *c)
|
|||
static int cdc_config_register(struct usb_composite_dev *cdev)
|
||||
{
|
||||
static struct usb_configuration config = {
|
||||
.bind = cdc_do_config,
|
||||
.bConfigurationValue = MULTI_CDC_CONFIG_NUM,
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
};
|
||||
|
|
@ -257,7 +249,7 @@ static int cdc_config_register(struct usb_composite_dev *cdev)
|
|||
config.label = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].s;
|
||||
config.iConfiguration = strings_dev[MULTI_STRING_CDC_CONFIG_IDX].id;
|
||||
|
||||
return usb_add_config(cdev, &config);
|
||||
return usb_add_config(cdev, &config, cdc_do_config);
|
||||
}
|
||||
|
||||
#else
|
||||
|
|
@ -314,20 +306,11 @@ static int __ref multi_bind(struct usb_composite_dev *cdev)
|
|||
device_desc.bcdDevice = cpu_to_le16(0x0300 | 0x0099);
|
||||
}
|
||||
|
||||
/* allocate string descriptor numbers */
|
||||
snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
|
||||
init_utsname()->sysname, init_utsname()->release,
|
||||
gadget->name);
|
||||
|
||||
/* allocate string IDs */
|
||||
status = usb_string_ids_tab(cdev, strings_dev);
|
||||
if (unlikely(status < 0))
|
||||
goto fail2;
|
||||
|
||||
device_desc.iManufacturer =
|
||||
strings_dev[MULTI_STRING_MANUFACTURER_IDX].id;
|
||||
device_desc.iProduct =
|
||||
strings_dev[MULTI_STRING_PRODUCT_IDX].id;
|
||||
|
||||
/* register configurations */
|
||||
status = rndis_config_register(cdev);
|
||||
if (unlikely(status < 0))
|
||||
|
|
@ -368,14 +351,15 @@ static struct usb_composite_driver multi_driver = {
|
|||
.name = "g_multi",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.bind = multi_bind,
|
||||
.unbind = __exit_p(multi_unbind),
|
||||
.iProduct = DRIVER_DESC,
|
||||
.needs_serial = 1,
|
||||
};
|
||||
|
||||
|
||||
static int __init multi_init(void)
|
||||
{
|
||||
return usb_composite_register(&multi_driver);
|
||||
return usb_composite_probe(&multi_driver, multi_bind);
|
||||
}
|
||||
module_init(multi_init);
|
||||
|
||||
|
|
|
|||
|
|
@ -1929,7 +1929,8 @@ static void ep0_start (struct net2280 *dev)
|
|||
* disconnect is reported. then a host may connect again, or
|
||||
* the driver might get unbound.
|
||||
*/
|
||||
int usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct net2280 *dev = the_controller;
|
||||
int retval;
|
||||
|
|
@ -1941,8 +1942,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
|||
*/
|
||||
if (!driver
|
||||
|| driver->speed != USB_SPEED_HIGH
|
||||
|| !driver->bind
|
||||
|| !driver->setup)
|
||||
|| !bind || !driver->setup)
|
||||
return -EINVAL;
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
|
@ -1957,7 +1957,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
|||
driver->driver.bus = NULL;
|
||||
dev->driver = driver;
|
||||
dev->gadget.dev.driver = &driver->driver;
|
||||
retval = driver->bind (&dev->gadget);
|
||||
retval = bind(&dev->gadget);
|
||||
if (retval) {
|
||||
DEBUG (dev, "bind to driver %s --> %d\n",
|
||||
driver->driver.name, retval);
|
||||
|
|
@ -1993,7 +1993,7 @@ err_unbind:
|
|||
dev->driver = NULL;
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL (usb_gadget_register_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
static void
|
||||
stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)
|
||||
|
|
|
|||
|
|
@ -135,7 +135,6 @@ static int __init nokia_bind_config(struct usb_configuration *c)
|
|||
|
||||
static struct usb_configuration nokia_config_500ma_driver = {
|
||||
.label = "Bus Powered",
|
||||
.bind = nokia_bind_config,
|
||||
.bConfigurationValue = 1,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
.bmAttributes = USB_CONFIG_ATT_ONE,
|
||||
|
|
@ -144,7 +143,6 @@ static struct usb_configuration nokia_config_500ma_driver = {
|
|||
|
||||
static struct usb_configuration nokia_config_100ma_driver = {
|
||||
.label = "Self Powered",
|
||||
.bind = nokia_bind_config,
|
||||
.bConfigurationValue = 2,
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
.bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
|
||||
|
|
@ -206,11 +204,13 @@ static int __init nokia_bind(struct usb_composite_dev *cdev)
|
|||
}
|
||||
|
||||
/* finaly register the configuration */
|
||||
status = usb_add_config(cdev, &nokia_config_500ma_driver);
|
||||
status = usb_add_config(cdev, &nokia_config_500ma_driver,
|
||||
nokia_bind_config);
|
||||
if (status < 0)
|
||||
goto err_usb;
|
||||
|
||||
status = usb_add_config(cdev, &nokia_config_100ma_driver);
|
||||
status = usb_add_config(cdev, &nokia_config_100ma_driver,
|
||||
nokia_bind_config);
|
||||
if (status < 0)
|
||||
goto err_usb;
|
||||
|
||||
|
|
@ -241,13 +241,12 @@ static struct usb_composite_driver nokia_driver = {
|
|||
.name = "g_nokia",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.bind = nokia_bind,
|
||||
.unbind = __exit_p(nokia_unbind),
|
||||
};
|
||||
|
||||
static int __init nokia_init(void)
|
||||
{
|
||||
return usb_composite_register(&nokia_driver);
|
||||
return usb_composite_probe(&nokia_driver, nokia_bind);
|
||||
}
|
||||
module_init(nokia_init);
|
||||
|
||||
|
|
|
|||
|
|
@ -2102,7 +2102,8 @@ static inline int machine_without_vbus_sense(void)
|
|||
);
|
||||
}
|
||||
|
||||
int usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
int status = -ENODEV;
|
||||
struct omap_ep *ep;
|
||||
|
|
@ -2114,8 +2115,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
|||
if (!driver
|
||||
// FIXME if otg, check: driver->is_otg
|
||||
|| driver->speed < USB_SPEED_FULL
|
||||
|| !driver->bind
|
||||
|| !driver->setup)
|
||||
|| !bind || !driver->setup)
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&udc->lock, flags);
|
||||
|
|
@ -2145,7 +2145,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
|
|||
if (udc->dc_clk != NULL)
|
||||
omap_udc_enable_clock(1);
|
||||
|
||||
status = driver->bind (&udc->gadget);
|
||||
status = bind(&udc->gadget);
|
||||
if (status) {
|
||||
DBG("bind to %s --> %d\n", driver->driver.name, status);
|
||||
udc->gadget.dev.driver = NULL;
|
||||
|
|
@ -2186,7 +2186,7 @@ done:
|
|||
omap_udc_enable_clock(0);
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_register_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1348,7 +1348,7 @@ printer_unbind(struct usb_gadget *gadget)
|
|||
set_gadget_data(gadget, NULL);
|
||||
}
|
||||
|
||||
static int __ref
|
||||
static int __init
|
||||
printer_bind(struct usb_gadget *gadget)
|
||||
{
|
||||
struct printer_dev *dev;
|
||||
|
|
@ -1544,7 +1544,6 @@ static struct usb_gadget_driver printer_driver = {
|
|||
.speed = DEVSPEED,
|
||||
|
||||
.function = (char *) driver_desc,
|
||||
.bind = printer_bind,
|
||||
.unbind = printer_unbind,
|
||||
|
||||
.setup = printer_setup,
|
||||
|
|
@ -1580,11 +1579,11 @@ init(void)
|
|||
return status;
|
||||
}
|
||||
|
||||
status = usb_gadget_register_driver(&printer_driver);
|
||||
status = usb_gadget_probe_driver(&printer_driver, printer_bind);
|
||||
if (status) {
|
||||
class_destroy(usb_gadget_class);
|
||||
unregister_chrdev_region(g_printer_devno, 1);
|
||||
DBG(dev, "usb_gadget_register_driver %x\n", status);
|
||||
DBG(dev, "usb_gadget_probe_driver %x\n", status);
|
||||
}
|
||||
|
||||
return status;
|
||||
|
|
|
|||
|
|
@ -1280,14 +1280,15 @@ static void udc_enable (struct pxa25x_udc *dev)
|
|||
* disconnect is reported. then a host may connect again, or
|
||||
* the driver might get unbound.
|
||||
*/
|
||||
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct pxa25x_udc *dev = the_controller;
|
||||
int retval;
|
||||
|
||||
if (!driver
|
||||
|| driver->speed < USB_SPEED_FULL
|
||||
|| !driver->bind
|
||||
|| !bind
|
||||
|| !driver->disconnect
|
||||
|| !driver->setup)
|
||||
return -EINVAL;
|
||||
|
|
@ -1308,7 +1309,7 @@ fail:
|
|||
dev->gadget.dev.driver = NULL;
|
||||
return retval;
|
||||
}
|
||||
retval = driver->bind(&dev->gadget);
|
||||
retval = bind(&dev->gadget);
|
||||
if (retval) {
|
||||
DMSG("bind to driver %s --> error %d\n",
|
||||
driver->driver.name, retval);
|
||||
|
|
@ -1338,7 +1339,7 @@ fail:
|
|||
bind_fail:
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_register_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
static void
|
||||
stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)
|
||||
|
|
|
|||
|
|
@ -1792,8 +1792,9 @@ static void udc_enable(struct pxa_udc *udc)
|
|||
}
|
||||
|
||||
/**
|
||||
* usb_gadget_register_driver - Register gadget driver
|
||||
* usb_gadget_probe_driver - Register gadget driver
|
||||
* @driver: gadget driver
|
||||
* @bind: bind function
|
||||
*
|
||||
* When a driver is successfully registered, it will receive control requests
|
||||
* including set_configuration(), which enables non-control requests. Then
|
||||
|
|
@ -1805,12 +1806,13 @@ static void udc_enable(struct pxa_udc *udc)
|
|||
*
|
||||
* Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise
|
||||
*/
|
||||
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct pxa_udc *udc = the_controller;
|
||||
int retval;
|
||||
|
||||
if (!driver || driver->speed < USB_SPEED_FULL || !driver->bind
|
||||
if (!driver || driver->speed < USB_SPEED_FULL || !bind
|
||||
|| !driver->disconnect || !driver->setup)
|
||||
return -EINVAL;
|
||||
if (!udc)
|
||||
|
|
@ -1828,7 +1830,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
dev_err(udc->dev, "device_add error %d\n", retval);
|
||||
goto add_fail;
|
||||
}
|
||||
retval = driver->bind(&udc->gadget);
|
||||
retval = bind(&udc->gadget);
|
||||
if (retval) {
|
||||
dev_err(udc->dev, "bind to driver %s --> error %d\n",
|
||||
driver->driver.name, retval);
|
||||
|
|
@ -1859,7 +1861,7 @@ add_fail:
|
|||
udc->gadget.dev.driver = NULL;
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_register_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ static const char *r8a66597_ep_name[] = {
|
|||
"ep8", "ep9",
|
||||
};
|
||||
|
||||
static void init_controller(struct r8a66597 *r8a66597);
|
||||
static void disable_controller(struct r8a66597 *r8a66597);
|
||||
static void irq_ep0_write(struct r8a66597_ep *ep, struct r8a66597_request *req);
|
||||
static void irq_packet_write(struct r8a66597_ep *ep,
|
||||
|
|
@ -104,6 +105,8 @@ __acquires(r8a66597->lock)
|
|||
spin_lock(&r8a66597->lock);
|
||||
|
||||
disable_controller(r8a66597);
|
||||
init_controller(r8a66597);
|
||||
r8a66597_bset(r8a66597, VBSE, INTENB0);
|
||||
INIT_LIST_HEAD(&r8a66597->ep[0].queue);
|
||||
}
|
||||
|
||||
|
|
@ -274,7 +277,7 @@ static int pipe_buffer_setting(struct r8a66597 *r8a66597,
|
|||
}
|
||||
|
||||
if (buf_bsize && ((bufnum + 16) >= R8A66597_MAX_BUFNUM)) {
|
||||
pr_err(KERN_ERR "r8a66597 pipe memory is insufficient\n");
|
||||
pr_err("r8a66597 pipe memory is insufficient\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
@ -1405,14 +1408,15 @@ static struct usb_ep_ops r8a66597_ep_ops = {
|
|||
/*-------------------------------------------------------------------------*/
|
||||
static struct r8a66597 *the_controller;
|
||||
|
||||
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct r8a66597 *r8a66597 = the_controller;
|
||||
int retval;
|
||||
|
||||
if (!driver
|
||||
|| driver->speed != USB_SPEED_HIGH
|
||||
|| !driver->bind
|
||||
|| !bind
|
||||
|| !driver->setup)
|
||||
return -EINVAL;
|
||||
if (!r8a66597)
|
||||
|
|
@ -1431,7 +1435,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
goto error;
|
||||
}
|
||||
|
||||
retval = driver->bind(&r8a66597->gadget);
|
||||
retval = bind(&r8a66597->gadget);
|
||||
if (retval) {
|
||||
printk(KERN_ERR "bind to driver error (%d)\n", retval);
|
||||
device_del(&r8a66597->gadget.dev);
|
||||
|
|
@ -1456,7 +1460,7 @@ error:
|
|||
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_register_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
|
|||
int len)
|
||||
{
|
||||
void __iomem *fifoaddr = r8a66597->reg + offset;
|
||||
unsigned int data;
|
||||
unsigned int data = 0;
|
||||
int i;
|
||||
|
||||
if (r8a66597->pdata->on_chip) {
|
||||
|
|
|
|||
|
|
@ -61,17 +61,17 @@ MODULE_PARM_DESC (rndis_debug, "enable debugging");
|
|||
#define RNDIS_MAX_CONFIGS 1
|
||||
|
||||
|
||||
static rndis_params rndis_per_dev_params [RNDIS_MAX_CONFIGS];
|
||||
static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS];
|
||||
|
||||
/* Driver Version */
|
||||
static const __le32 rndis_driver_version = cpu_to_le32 (1);
|
||||
static const __le32 rndis_driver_version = cpu_to_le32(1);
|
||||
|
||||
/* Function Prototypes */
|
||||
static rndis_resp_t *rndis_add_response (int configNr, u32 length);
|
||||
static rndis_resp_t *rndis_add_response(int configNr, u32 length);
|
||||
|
||||
|
||||
/* supported OIDs */
|
||||
static const u32 oid_supported_list [] =
|
||||
static const u32 oid_supported_list[] =
|
||||
{
|
||||
/* the general stuff */
|
||||
OID_GEN_SUPPORTED_LIST,
|
||||
|
|
@ -161,21 +161,20 @@ static const u32 oid_supported_list [] =
|
|||
|
||||
|
||||
/* NDIS Functions */
|
||||
static int
|
||||
gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
|
||||
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 = 4; /* usually */
|
||||
__le32 *outbuf;
|
||||
int i, count;
|
||||
rndis_query_cmplt_type *resp;
|
||||
struct net_device *net;
|
||||
int retval = -ENOTSUPP;
|
||||
u32 length = 4; /* usually */
|
||||
__le32 *outbuf;
|
||||
int i, count;
|
||||
rndis_query_cmplt_type *resp;
|
||||
struct net_device *net;
|
||||
struct rtnl_link_stats64 temp;
|
||||
const struct rtnl_link_stats64 *stats;
|
||||
|
||||
if (!r) return -ENOMEM;
|
||||
resp = (rndis_query_cmplt_type *) r->buf;
|
||||
resp = (rndis_query_cmplt_type *)r->buf;
|
||||
|
||||
if (!resp) return -ENOMEM;
|
||||
|
||||
|
|
@ -191,8 +190,8 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
|
|||
}
|
||||
|
||||
/* response goes here, right after the header */
|
||||
outbuf = (__le32 *) &resp[1];
|
||||
resp->InformationBufferOffset = cpu_to_le32 (16);
|
||||
outbuf = (__le32 *)&resp[1];
|
||||
resp->InformationBufferOffset = cpu_to_le32(16);
|
||||
|
||||
net = rndis_per_dev_params[configNr].dev;
|
||||
stats = dev_get_stats(net, &temp);
|
||||
|
|
@ -204,10 +203,10 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
|
|||
/* mandatory */
|
||||
case OID_GEN_SUPPORTED_LIST:
|
||||
pr_debug("%s: OID_GEN_SUPPORTED_LIST\n", __func__);
|
||||
length = sizeof (oid_supported_list);
|
||||
count = length / sizeof (u32);
|
||||
length = sizeof(oid_supported_list);
|
||||
count = length / sizeof(u32);
|
||||
for (i = 0; i < count; i++)
|
||||
outbuf[i] = cpu_to_le32 (oid_supported_list[i]);
|
||||
outbuf[i] = cpu_to_le32(oid_supported_list[i]);
|
||||
retval = 0;
|
||||
break;
|
||||
|
||||
|
|
@ -220,14 +219,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
|
|||
* reddite ergo quae sunt Caesaris Caesari
|
||||
* et quae sunt Dei Deo!
|
||||
*/
|
||||
*outbuf = cpu_to_le32 (0);
|
||||
*outbuf = cpu_to_le32(0);
|
||||
retval = 0;
|
||||
break;
|
||||
|
||||
/* mandatory */
|
||||
case OID_GEN_MEDIA_SUPPORTED:
|
||||
pr_debug("%s: OID_GEN_MEDIA_SUPPORTED\n", __func__);
|
||||
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
|
||||
*outbuf = cpu_to_le32(rndis_per_dev_params[configNr].medium);
|
||||
retval = 0;
|
||||
break;
|
||||
|
||||
|
|
@ -235,16 +234,16 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
|
|||
case OID_GEN_MEDIA_IN_USE:
|
||||
pr_debug("%s: OID_GEN_MEDIA_IN_USE\n", __func__);
|
||||
/* one medium, one transport... (maybe you do it better) */
|
||||
*outbuf = 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_MAXIMUM_FRAME_SIZE:
|
||||
pr_debug("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__);
|
||||
if (rndis_per_dev_params [configNr].dev) {
|
||||
*outbuf = cpu_to_le32 (
|
||||
rndis_per_dev_params [configNr].dev->mtu);
|
||||
if (rndis_per_dev_params[configNr].dev) {
|
||||
*outbuf = cpu_to_le32(
|
||||
rndis_per_dev_params[configNr].dev->mtu);
|
||||
retval = 0;
|
||||
}
|
||||
break;
|
||||
|
|
@ -253,21 +252,21 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
|
|||
case OID_GEN_LINK_SPEED:
|
||||
if (rndis_debug > 1)
|
||||
pr_debug("%s: OID_GEN_LINK_SPEED\n", __func__);
|
||||
if (rndis_per_dev_params [configNr].media_state
|
||||
if (rndis_per_dev_params[configNr].media_state
|
||||
== NDIS_MEDIA_STATE_DISCONNECTED)
|
||||
*outbuf = cpu_to_le32 (0);
|
||||
*outbuf = cpu_to_le32(0);
|
||||
else
|
||||
*outbuf = cpu_to_le32 (
|
||||
rndis_per_dev_params [configNr].speed);
|
||||
*outbuf = cpu_to_le32(
|
||||
rndis_per_dev_params[configNr].speed);
|
||||
retval = 0;
|
||||
break;
|
||||
|
||||
/* mandatory */
|
||||
case OID_GEN_TRANSMIT_BLOCK_SIZE:
|
||||
pr_debug("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__);
|
||||
if (rndis_per_dev_params [configNr].dev) {
|
||||
*outbuf = cpu_to_le32 (
|
||||
rndis_per_dev_params [configNr].dev->mtu);
|
||||
if (rndis_per_dev_params[configNr].dev) {
|
||||
*outbuf = cpu_to_le32(
|
||||
rndis_per_dev_params[configNr].dev->mtu);
|
||||
retval = 0;
|
||||
}
|
||||
break;
|
||||
|
|
@ -275,9 +274,9 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
|
|||
/* mandatory */
|
||||
case OID_GEN_RECEIVE_BLOCK_SIZE:
|
||||
pr_debug("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__);
|
||||
if (rndis_per_dev_params [configNr].dev) {
|
||||
*outbuf = cpu_to_le32 (
|
||||
rndis_per_dev_params [configNr].dev->mtu);
|
||||
if (rndis_per_dev_params[configNr].dev) {
|
||||
*outbuf = cpu_to_le32(
|
||||
rndis_per_dev_params[configNr].dev->mtu);
|
||||
retval = 0;
|
||||
}
|
||||
break;
|
||||
|
|
@ -285,18 +284,20 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
|
|||
/* mandatory */
|
||||
case OID_GEN_VENDOR_ID:
|
||||
pr_debug("%s: OID_GEN_VENDOR_ID\n", __func__);
|
||||
*outbuf = cpu_to_le32 (
|
||||
rndis_per_dev_params [configNr].vendorID);
|
||||
*outbuf = cpu_to_le32(
|
||||
rndis_per_dev_params[configNr].vendorID);
|
||||
retval = 0;
|
||||
break;
|
||||
|
||||
/* mandatory */
|
||||
case OID_GEN_VENDOR_DESCRIPTION:
|
||||
pr_debug("%s: OID_GEN_VENDOR_DESCRIPTION\n", __func__);
|
||||
if ( rndis_per_dev_params [configNr].vendorDescr ) {
|
||||
length = strlen (rndis_per_dev_params [configNr].vendorDescr);
|
||||
memcpy (outbuf,
|
||||
rndis_per_dev_params [configNr].vendorDescr, length);
|
||||
if (rndis_per_dev_params[configNr].vendorDescr) {
|
||||
length = strlen(rndis_per_dev_params[configNr].
|
||||
vendorDescr);
|
||||
memcpy(outbuf,
|
||||
rndis_per_dev_params[configNr].vendorDescr,
|
||||
length);
|
||||
} else {
|
||||
outbuf[0] = 0;
|
||||
}
|
||||
|
|
@ -313,7 +314,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
|
|||
/* mandatory */
|
||||
case OID_GEN_CURRENT_PACKET_FILTER:
|
||||
pr_debug("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __func__);
|
||||
*outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter);
|
||||
*outbuf = cpu_to_le32(*rndis_per_dev_params[configNr].filter);
|
||||
retval = 0;
|
||||
break;
|
||||
|
||||
|
|
@ -328,14 +329,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
|
|||
case OID_GEN_MEDIA_CONNECT_STATUS:
|
||||
if (rndis_debug > 1)
|
||||
pr_debug("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __func__);
|
||||
*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
|
||||
*outbuf = cpu_to_le32(rndis_per_dev_params[configNr]
|
||||
.media_state);
|
||||
retval = 0;
|
||||
break;
|
||||
|
||||
case OID_GEN_PHYSICAL_MEDIUM:
|
||||
pr_debug("%s: OID_GEN_PHYSICAL_MEDIUM\n", __func__);
|
||||
*outbuf = cpu_to_le32 (0);
|
||||
*outbuf = cpu_to_le32(0);
|
||||
retval = 0;
|
||||
break;
|
||||
|
||||
|
|
@ -409,10 +410,10 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
|
|||
/* mandatory */
|
||||
case OID_802_3_PERMANENT_ADDRESS:
|
||||
pr_debug("%s: OID_802_3_PERMANENT_ADDRESS\n", __func__);
|
||||
if (rndis_per_dev_params [configNr].dev) {
|
||||
if (rndis_per_dev_params[configNr].dev) {
|
||||
length = ETH_ALEN;
|
||||
memcpy (outbuf,
|
||||
rndis_per_dev_params [configNr].host_mac,
|
||||
memcpy(outbuf,
|
||||
rndis_per_dev_params[configNr].host_mac,
|
||||
length);
|
||||
retval = 0;
|
||||
}
|
||||
|
|
@ -421,9 +422,9 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
|
|||
/* mandatory */
|
||||
case OID_802_3_CURRENT_ADDRESS:
|
||||
pr_debug("%s: OID_802_3_CURRENT_ADDRESS\n", __func__);
|
||||
if (rndis_per_dev_params [configNr].dev) {
|
||||
if (rndis_per_dev_params[configNr].dev) {
|
||||
length = ETH_ALEN;
|
||||
memcpy (outbuf,
|
||||
memcpy(outbuf,
|
||||
rndis_per_dev_params [configNr].host_mac,
|
||||
length);
|
||||
retval = 0;
|
||||
|
|
@ -434,7 +435,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
|
|||
case OID_802_3_MULTICAST_LIST:
|
||||
pr_debug("%s: OID_802_3_MULTICAST_LIST\n", __func__);
|
||||
/* Multicast base address only */
|
||||
*outbuf = cpu_to_le32 (0xE0000000);
|
||||
*outbuf = cpu_to_le32(0xE0000000);
|
||||
retval = 0;
|
||||
break;
|
||||
|
||||
|
|
@ -442,7 +443,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
|
|||
case OID_802_3_MAXIMUM_LIST_SIZE:
|
||||
pr_debug("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __func__);
|
||||
/* Multicast base address only */
|
||||
*outbuf = cpu_to_le32 (1);
|
||||
*outbuf = cpu_to_le32(1);
|
||||
retval = 0;
|
||||
break;
|
||||
|
||||
|
|
@ -466,14 +467,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
|
|||
/* mandatory */
|
||||
case OID_802_3_XMIT_ONE_COLLISION:
|
||||
pr_debug("%s: OID_802_3_XMIT_ONE_COLLISION\n", __func__);
|
||||
*outbuf = cpu_to_le32 (0);
|
||||
*outbuf = cpu_to_le32(0);
|
||||
retval = 0;
|
||||
break;
|
||||
|
||||
/* mandatory */
|
||||
case OID_802_3_XMIT_MORE_COLLISIONS:
|
||||
pr_debug("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __func__);
|
||||
*outbuf = cpu_to_le32 (0);
|
||||
*outbuf = cpu_to_le32(0);
|
||||
retval = 0;
|
||||
break;
|
||||
|
||||
|
|
@ -484,22 +485,22 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
|
|||
if (retval < 0)
|
||||
length = 0;
|
||||
|
||||
resp->InformationBufferLength = cpu_to_le32 (length);
|
||||
r->length = length + sizeof *resp;
|
||||
resp->MessageLength = cpu_to_le32 (r->length);
|
||||
resp->InformationBufferLength = cpu_to_le32(length);
|
||||
r->length = length + sizeof(*resp);
|
||||
resp->MessageLength = cpu_to_le32(r->length);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
|
||||
rndis_resp_t *r)
|
||||
static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len,
|
||||
rndis_resp_t *r)
|
||||
{
|
||||
rndis_set_cmplt_type *resp;
|
||||
int i, retval = -ENOTSUPP;
|
||||
struct rndis_params *params;
|
||||
rndis_set_cmplt_type *resp;
|
||||
int i, retval = -ENOTSUPP;
|
||||
struct rndis_params *params;
|
||||
|
||||
if (!r)
|
||||
return -ENOMEM;
|
||||
resp = (rndis_set_cmplt_type *) r->buf;
|
||||
resp = (rndis_set_cmplt_type *)r->buf;
|
||||
if (!resp)
|
||||
return -ENOMEM;
|
||||
|
||||
|
|
@ -514,7 +515,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
|
|||
}
|
||||
}
|
||||
|
||||
params = &rndis_per_dev_params [configNr];
|
||||
params = &rndis_per_dev_params[configNr];
|
||||
switch (OID) {
|
||||
case OID_GEN_CURRENT_PACKET_FILTER:
|
||||
|
||||
|
|
@ -537,11 +538,11 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
|
|||
params->state = RNDIS_DATA_INITIALIZED;
|
||||
netif_carrier_on(params->dev);
|
||||
if (netif_running(params->dev))
|
||||
netif_wake_queue (params->dev);
|
||||
netif_wake_queue(params->dev);
|
||||
} else {
|
||||
params->state = RNDIS_INITIALIZED;
|
||||
netif_carrier_off (params->dev);
|
||||
netif_stop_queue (params->dev);
|
||||
netif_carrier_off(params->dev);
|
||||
netif_stop_queue(params->dev);
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -563,48 +564,47 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
|
|||
* Response Functions
|
||||
*/
|
||||
|
||||
static int rndis_init_response (int configNr, rndis_init_msg_type *buf)
|
||||
static int rndis_init_response(int configNr, rndis_init_msg_type *buf)
|
||||
{
|
||||
rndis_init_cmplt_type *resp;
|
||||
rndis_resp_t *r;
|
||||
struct rndis_params *params = rndis_per_dev_params + configNr;
|
||||
rndis_init_cmplt_type *resp;
|
||||
rndis_resp_t *r;
|
||||
struct rndis_params *params = rndis_per_dev_params + configNr;
|
||||
|
||||
if (!params->dev)
|
||||
return -ENOTSUPP;
|
||||
|
||||
r = rndis_add_response (configNr, sizeof (rndis_init_cmplt_type));
|
||||
r = rndis_add_response(configNr, sizeof(rndis_init_cmplt_type));
|
||||
if (!r)
|
||||
return -ENOMEM;
|
||||
resp = (rndis_init_cmplt_type *) r->buf;
|
||||
resp = (rndis_init_cmplt_type *)r->buf;
|
||||
|
||||
resp->MessageType = cpu_to_le32 (
|
||||
REMOTE_NDIS_INITIALIZE_CMPLT);
|
||||
resp->MessageLength = cpu_to_le32 (52);
|
||||
resp->MessageType = cpu_to_le32(REMOTE_NDIS_INITIALIZE_CMPLT);
|
||||
resp->MessageLength = cpu_to_le32(52);
|
||||
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
|
||||
resp->Status = cpu_to_le32 (RNDIS_STATUS_SUCCESS);
|
||||
resp->MajorVersion = cpu_to_le32 (RNDIS_MAJOR_VERSION);
|
||||
resp->MinorVersion = cpu_to_le32 (RNDIS_MINOR_VERSION);
|
||||
resp->DeviceFlags = cpu_to_le32 (RNDIS_DF_CONNECTIONLESS);
|
||||
resp->Medium = cpu_to_le32 (RNDIS_MEDIUM_802_3);
|
||||
resp->MaxPacketsPerTransfer = cpu_to_le32 (1);
|
||||
resp->MaxTransferSize = cpu_to_le32 (
|
||||
resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
|
||||
resp->MajorVersion = cpu_to_le32(RNDIS_MAJOR_VERSION);
|
||||
resp->MinorVersion = cpu_to_le32(RNDIS_MINOR_VERSION);
|
||||
resp->DeviceFlags = cpu_to_le32(RNDIS_DF_CONNECTIONLESS);
|
||||
resp->Medium = cpu_to_le32(RNDIS_MEDIUM_802_3);
|
||||
resp->MaxPacketsPerTransfer = cpu_to_le32(1);
|
||||
resp->MaxTransferSize = cpu_to_le32(
|
||||
params->dev->mtu
|
||||
+ sizeof (struct ethhdr)
|
||||
+ sizeof (struct rndis_packet_msg_type)
|
||||
+ sizeof(struct ethhdr)
|
||||
+ sizeof(struct rndis_packet_msg_type)
|
||||
+ 22);
|
||||
resp->PacketAlignmentFactor = cpu_to_le32 (0);
|
||||
resp->AFListOffset = cpu_to_le32 (0);
|
||||
resp->AFListSize = cpu_to_le32 (0);
|
||||
resp->PacketAlignmentFactor = cpu_to_le32(0);
|
||||
resp->AFListOffset = cpu_to_le32(0);
|
||||
resp->AFListSize = cpu_to_le32(0);
|
||||
|
||||
params->resp_avail(params->v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rndis_query_response (int configNr, rndis_query_msg_type *buf)
|
||||
static int rndis_query_response(int configNr, rndis_query_msg_type *buf)
|
||||
{
|
||||
rndis_query_cmplt_type *resp;
|
||||
rndis_resp_t *r;
|
||||
struct rndis_params *params = rndis_per_dev_params + configNr;
|
||||
rndis_resp_t *r;
|
||||
struct rndis_params *params = rndis_per_dev_params + configNr;
|
||||
|
||||
/* pr_debug("%s: OID = %08X\n", __func__, cpu_to_le32(buf->OID)); */
|
||||
if (!params->dev)
|
||||
|
|
@ -616,47 +616,46 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf)
|
|||
* rndis_query_cmplt_type followed by data.
|
||||
* oid_supported_list is the largest data reply
|
||||
*/
|
||||
r = rndis_add_response (configNr,
|
||||
sizeof (oid_supported_list) + sizeof(rndis_query_cmplt_type));
|
||||
r = rndis_add_response(configNr,
|
||||
sizeof(oid_supported_list) + sizeof(rndis_query_cmplt_type));
|
||||
if (!r)
|
||||
return -ENOMEM;
|
||||
resp = (rndis_query_cmplt_type *) r->buf;
|
||||
resp = (rndis_query_cmplt_type *)r->buf;
|
||||
|
||||
resp->MessageType = cpu_to_le32 (REMOTE_NDIS_QUERY_CMPLT);
|
||||
resp->MessageType = cpu_to_le32(REMOTE_NDIS_QUERY_CMPLT);
|
||||
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
|
||||
|
||||
if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID),
|
||||
if (gen_ndis_query_resp(configNr, le32_to_cpu(buf->OID),
|
||||
le32_to_cpu(buf->InformationBufferOffset)
|
||||
+ 8 + (u8 *) buf,
|
||||
+ 8 + (u8 *)buf,
|
||||
le32_to_cpu(buf->InformationBufferLength),
|
||||
r)) {
|
||||
/* OID not supported */
|
||||
resp->Status = cpu_to_le32 (
|
||||
RNDIS_STATUS_NOT_SUPPORTED);
|
||||
resp->MessageLength = cpu_to_le32 (sizeof *resp);
|
||||
resp->InformationBufferLength = cpu_to_le32 (0);
|
||||
resp->InformationBufferOffset = cpu_to_le32 (0);
|
||||
resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
|
||||
resp->MessageLength = cpu_to_le32(sizeof *resp);
|
||||
resp->InformationBufferLength = cpu_to_le32(0);
|
||||
resp->InformationBufferOffset = cpu_to_le32(0);
|
||||
} else
|
||||
resp->Status = cpu_to_le32 (RNDIS_STATUS_SUCCESS);
|
||||
resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
|
||||
|
||||
params->resp_avail(params->v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
|
||||
static int rndis_set_response(int configNr, rndis_set_msg_type *buf)
|
||||
{
|
||||
u32 BufLength, BufOffset;
|
||||
rndis_set_cmplt_type *resp;
|
||||
rndis_resp_t *r;
|
||||
struct rndis_params *params = rndis_per_dev_params + configNr;
|
||||
u32 BufLength, BufOffset;
|
||||
rndis_set_cmplt_type *resp;
|
||||
rndis_resp_t *r;
|
||||
struct rndis_params *params = rndis_per_dev_params + configNr;
|
||||
|
||||
r = rndis_add_response (configNr, sizeof (rndis_set_cmplt_type));
|
||||
r = rndis_add_response(configNr, sizeof(rndis_set_cmplt_type));
|
||||
if (!r)
|
||||
return -ENOMEM;
|
||||
resp = (rndis_set_cmplt_type *) r->buf;
|
||||
resp = (rndis_set_cmplt_type *)r->buf;
|
||||
|
||||
BufLength = le32_to_cpu (buf->InformationBufferLength);
|
||||
BufOffset = le32_to_cpu (buf->InformationBufferOffset);
|
||||
BufLength = le32_to_cpu(buf->InformationBufferLength);
|
||||
BufOffset = le32_to_cpu(buf->InformationBufferOffset);
|
||||
|
||||
#ifdef VERBOSE_DEBUG
|
||||
pr_debug("%s: Length: %d\n", __func__, BufLength);
|
||||
|
|
@ -670,59 +669,59 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
|
|||
pr_debug("\n");
|
||||
#endif
|
||||
|
||||
resp->MessageType = cpu_to_le32 (REMOTE_NDIS_SET_CMPLT);
|
||||
resp->MessageLength = cpu_to_le32 (16);
|
||||
resp->MessageType = cpu_to_le32(REMOTE_NDIS_SET_CMPLT);
|
||||
resp->MessageLength = cpu_to_le32(16);
|
||||
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
|
||||
if (gen_ndis_set_resp (configNr, le32_to_cpu (buf->OID),
|
||||
((u8 *) buf) + 8 + BufOffset, BufLength, r))
|
||||
resp->Status = cpu_to_le32 (RNDIS_STATUS_NOT_SUPPORTED);
|
||||
if (gen_ndis_set_resp(configNr, le32_to_cpu(buf->OID),
|
||||
((u8 *)buf) + 8 + BufOffset, BufLength, r))
|
||||
resp->Status = cpu_to_le32(RNDIS_STATUS_NOT_SUPPORTED);
|
||||
else
|
||||
resp->Status = cpu_to_le32 (RNDIS_STATUS_SUCCESS);
|
||||
resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
|
||||
|
||||
params->resp_avail(params->v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf)
|
||||
static int rndis_reset_response(int configNr, rndis_reset_msg_type *buf)
|
||||
{
|
||||
rndis_reset_cmplt_type *resp;
|
||||
rndis_resp_t *r;
|
||||
struct rndis_params *params = rndis_per_dev_params + configNr;
|
||||
rndis_reset_cmplt_type *resp;
|
||||
rndis_resp_t *r;
|
||||
struct rndis_params *params = rndis_per_dev_params + configNr;
|
||||
|
||||
r = rndis_add_response (configNr, sizeof (rndis_reset_cmplt_type));
|
||||
r = rndis_add_response(configNr, sizeof(rndis_reset_cmplt_type));
|
||||
if (!r)
|
||||
return -ENOMEM;
|
||||
resp = (rndis_reset_cmplt_type *) r->buf;
|
||||
resp = (rndis_reset_cmplt_type *)r->buf;
|
||||
|
||||
resp->MessageType = cpu_to_le32 (REMOTE_NDIS_RESET_CMPLT);
|
||||
resp->MessageLength = cpu_to_le32 (16);
|
||||
resp->Status = cpu_to_le32 (RNDIS_STATUS_SUCCESS);
|
||||
resp->MessageType = cpu_to_le32(REMOTE_NDIS_RESET_CMPLT);
|
||||
resp->MessageLength = cpu_to_le32(16);
|
||||
resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
|
||||
/* resent information */
|
||||
resp->AddressingReset = cpu_to_le32 (1);
|
||||
resp->AddressingReset = cpu_to_le32(1);
|
||||
|
||||
params->resp_avail(params->v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rndis_keepalive_response (int configNr,
|
||||
rndis_keepalive_msg_type *buf)
|
||||
static int rndis_keepalive_response(int configNr,
|
||||
rndis_keepalive_msg_type *buf)
|
||||
{
|
||||
rndis_keepalive_cmplt_type *resp;
|
||||
rndis_resp_t *r;
|
||||
struct rndis_params *params = rndis_per_dev_params + configNr;
|
||||
rndis_keepalive_cmplt_type *resp;
|
||||
rndis_resp_t *r;
|
||||
struct rndis_params *params = rndis_per_dev_params + configNr;
|
||||
|
||||
/* host "should" check only in RNDIS_DATA_INITIALIZED state */
|
||||
|
||||
r = rndis_add_response (configNr, sizeof (rndis_keepalive_cmplt_type));
|
||||
r = rndis_add_response(configNr, sizeof(rndis_keepalive_cmplt_type));
|
||||
if (!r)
|
||||
return -ENOMEM;
|
||||
resp = (rndis_keepalive_cmplt_type *) r->buf;
|
||||
resp = (rndis_keepalive_cmplt_type *)r->buf;
|
||||
|
||||
resp->MessageType = cpu_to_le32 (
|
||||
resp->MessageType = cpu_to_le32(
|
||||
REMOTE_NDIS_KEEPALIVE_CMPLT);
|
||||
resp->MessageLength = cpu_to_le32 (16);
|
||||
resp->MessageLength = cpu_to_le32(16);
|
||||
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
|
||||
resp->Status = cpu_to_le32 (RNDIS_STATUS_SUCCESS);
|
||||
resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS);
|
||||
|
||||
params->resp_avail(params->v);
|
||||
return 0;
|
||||
|
|
@ -732,86 +731,85 @@ static int rndis_keepalive_response (int configNr,
|
|||
/*
|
||||
* Device to Host Comunication
|
||||
*/
|
||||
static int rndis_indicate_status_msg (int configNr, u32 status)
|
||||
static int rndis_indicate_status_msg(int configNr, u32 status)
|
||||
{
|
||||
rndis_indicate_status_msg_type *resp;
|
||||
rndis_resp_t *r;
|
||||
struct rndis_params *params = rndis_per_dev_params + configNr;
|
||||
rndis_indicate_status_msg_type *resp;
|
||||
rndis_resp_t *r;
|
||||
struct rndis_params *params = rndis_per_dev_params + configNr;
|
||||
|
||||
if (params->state == RNDIS_UNINITIALIZED)
|
||||
return -ENOTSUPP;
|
||||
|
||||
r = rndis_add_response (configNr,
|
||||
sizeof (rndis_indicate_status_msg_type));
|
||||
r = rndis_add_response(configNr,
|
||||
sizeof(rndis_indicate_status_msg_type));
|
||||
if (!r)
|
||||
return -ENOMEM;
|
||||
resp = (rndis_indicate_status_msg_type *) r->buf;
|
||||
resp = (rndis_indicate_status_msg_type *)r->buf;
|
||||
|
||||
resp->MessageType = cpu_to_le32 (
|
||||
REMOTE_NDIS_INDICATE_STATUS_MSG);
|
||||
resp->MessageLength = cpu_to_le32 (20);
|
||||
resp->Status = cpu_to_le32 (status);
|
||||
resp->StatusBufferLength = cpu_to_le32 (0);
|
||||
resp->StatusBufferOffset = cpu_to_le32 (0);
|
||||
resp->MessageType = cpu_to_le32(REMOTE_NDIS_INDICATE_STATUS_MSG);
|
||||
resp->MessageLength = cpu_to_le32(20);
|
||||
resp->Status = cpu_to_le32(status);
|
||||
resp->StatusBufferLength = cpu_to_le32(0);
|
||||
resp->StatusBufferOffset = cpu_to_le32(0);
|
||||
|
||||
params->resp_avail(params->v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rndis_signal_connect (int configNr)
|
||||
int rndis_signal_connect(int configNr)
|
||||
{
|
||||
rndis_per_dev_params [configNr].media_state
|
||||
rndis_per_dev_params[configNr].media_state
|
||||
= NDIS_MEDIA_STATE_CONNECTED;
|
||||
return rndis_indicate_status_msg (configNr,
|
||||
return rndis_indicate_status_msg(configNr,
|
||||
RNDIS_STATUS_MEDIA_CONNECT);
|
||||
}
|
||||
|
||||
int rndis_signal_disconnect (int configNr)
|
||||
int rndis_signal_disconnect(int configNr)
|
||||
{
|
||||
rndis_per_dev_params [configNr].media_state
|
||||
rndis_per_dev_params[configNr].media_state
|
||||
= NDIS_MEDIA_STATE_DISCONNECTED;
|
||||
return rndis_indicate_status_msg (configNr,
|
||||
return rndis_indicate_status_msg(configNr,
|
||||
RNDIS_STATUS_MEDIA_DISCONNECT);
|
||||
}
|
||||
|
||||
void rndis_uninit (int configNr)
|
||||
void rndis_uninit(int configNr)
|
||||
{
|
||||
u8 *buf;
|
||||
u32 length;
|
||||
|
||||
if (configNr >= RNDIS_MAX_CONFIGS)
|
||||
return;
|
||||
rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED;
|
||||
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)
|
||||
void rndis_set_host_mac(int configNr, const u8 *addr)
|
||||
{
|
||||
rndis_per_dev_params [configNr].host_mac = addr;
|
||||
rndis_per_dev_params[configNr].host_mac = addr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Message Parser
|
||||
*/
|
||||
int rndis_msg_parser (u8 configNr, u8 *buf)
|
||||
int rndis_msg_parser(u8 configNr, u8 *buf)
|
||||
{
|
||||
u32 MsgType, MsgLength;
|
||||
__le32 *tmp;
|
||||
struct rndis_params *params;
|
||||
struct rndis_params *params;
|
||||
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
tmp = (__le32 *) buf;
|
||||
tmp = (__le32 *)buf;
|
||||
MsgType = get_unaligned_le32(tmp++);
|
||||
MsgLength = get_unaligned_le32(tmp++);
|
||||
|
||||
if (configNr >= RNDIS_MAX_CONFIGS)
|
||||
return -ENOTSUPP;
|
||||
params = &rndis_per_dev_params [configNr];
|
||||
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
|
||||
|
|
@ -822,41 +820,41 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
|
|||
switch (MsgType) {
|
||||
case REMOTE_NDIS_INITIALIZE_MSG:
|
||||
pr_debug("%s: REMOTE_NDIS_INITIALIZE_MSG\n",
|
||||
__func__ );
|
||||
__func__);
|
||||
params->state = RNDIS_INITIALIZED;
|
||||
return rndis_init_response (configNr,
|
||||
(rndis_init_msg_type *) buf);
|
||||
return rndis_init_response(configNr,
|
||||
(rndis_init_msg_type *)buf);
|
||||
|
||||
case REMOTE_NDIS_HALT_MSG:
|
||||
pr_debug("%s: REMOTE_NDIS_HALT_MSG\n",
|
||||
__func__ );
|
||||
__func__);
|
||||
params->state = RNDIS_UNINITIALIZED;
|
||||
if (params->dev) {
|
||||
netif_carrier_off (params->dev);
|
||||
netif_stop_queue (params->dev);
|
||||
netif_carrier_off(params->dev);
|
||||
netif_stop_queue(params->dev);
|
||||
}
|
||||
return 0;
|
||||
|
||||
case REMOTE_NDIS_QUERY_MSG:
|
||||
return rndis_query_response (configNr,
|
||||
(rndis_query_msg_type *) buf);
|
||||
return rndis_query_response(configNr,
|
||||
(rndis_query_msg_type *)buf);
|
||||
|
||||
case REMOTE_NDIS_SET_MSG:
|
||||
return rndis_set_response (configNr,
|
||||
(rndis_set_msg_type *) buf);
|
||||
return rndis_set_response(configNr,
|
||||
(rndis_set_msg_type *)buf);
|
||||
|
||||
case REMOTE_NDIS_RESET_MSG:
|
||||
pr_debug("%s: REMOTE_NDIS_RESET_MSG\n",
|
||||
__func__ );
|
||||
return rndis_reset_response (configNr,
|
||||
(rndis_reset_msg_type *) buf);
|
||||
__func__);
|
||||
return rndis_reset_response(configNr,
|
||||
(rndis_reset_msg_type *)buf);
|
||||
|
||||
case REMOTE_NDIS_KEEPALIVE_MSG:
|
||||
/* For USB: host does this every 5 seconds */
|
||||
if (rndis_debug > 1)
|
||||
pr_debug("%s: REMOTE_NDIS_KEEPALIVE_MSG\n",
|
||||
__func__ );
|
||||
return rndis_keepalive_response (configNr,
|
||||
__func__);
|
||||
return rndis_keepalive_response(configNr,
|
||||
(rndis_keepalive_msg_type *)
|
||||
buf);
|
||||
|
||||
|
|
@ -866,7 +864,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
|
|||
* suspending itself.
|
||||
*/
|
||||
pr_warning("%s: unknown RNDIS message 0x%08X len %d\n",
|
||||
__func__ , MsgType, MsgLength);
|
||||
__func__, MsgType, MsgLength);
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < MsgLength; i += 16) {
|
||||
|
|
@ -901,10 +899,10 @@ int rndis_register(void (*resp_avail)(void *v), void *v)
|
|||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
|
||||
if (!rndis_per_dev_params [i].used) {
|
||||
rndis_per_dev_params [i].used = 1;
|
||||
rndis_per_dev_params [i].resp_avail = resp_avail;
|
||||
rndis_per_dev_params [i].v = v;
|
||||
if (!rndis_per_dev_params[i].used) {
|
||||
rndis_per_dev_params[i].used = 1;
|
||||
rndis_per_dev_params[i].resp_avail = resp_avail;
|
||||
rndis_per_dev_params[i].v = v;
|
||||
pr_debug("%s: configNr = %d\n", __func__, i);
|
||||
return i;
|
||||
}
|
||||
|
|
@ -914,12 +912,12 @@ int rndis_register(void (*resp_avail)(void *v), void *v)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
void rndis_deregister (int configNr)
|
||||
void rndis_deregister(int configNr)
|
||||
{
|
||||
pr_debug("%s: \n", __func__);
|
||||
pr_debug("%s:\n", __func__);
|
||||
|
||||
if (configNr >= RNDIS_MAX_CONFIGS) return;
|
||||
rndis_per_dev_params [configNr].used = 0;
|
||||
rndis_per_dev_params[configNr].used = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -931,76 +929,76 @@ int rndis_set_param_dev(u8 configNr, struct net_device *dev, u16 *cdc_filter)
|
|||
return -EINVAL;
|
||||
if (configNr >= RNDIS_MAX_CONFIGS) return -1;
|
||||
|
||||
rndis_per_dev_params [configNr].dev = dev;
|
||||
rndis_per_dev_params [configNr].filter = cdc_filter;
|
||||
rndis_per_dev_params[configNr].dev = dev;
|
||||
rndis_per_dev_params[configNr].filter = cdc_filter;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr)
|
||||
int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr)
|
||||
{
|
||||
pr_debug("%s:\n", __func__);
|
||||
if (!vendorDescr) return -1;
|
||||
if (configNr >= RNDIS_MAX_CONFIGS) return -1;
|
||||
|
||||
rndis_per_dev_params [configNr].vendorID = vendorID;
|
||||
rndis_per_dev_params [configNr].vendorDescr = vendorDescr;
|
||||
rndis_per_dev_params[configNr].vendorID = vendorID;
|
||||
rndis_per_dev_params[configNr].vendorDescr = vendorDescr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed)
|
||||
int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed)
|
||||
{
|
||||
pr_debug("%s: %u %u\n", __func__, medium, speed);
|
||||
if (configNr >= RNDIS_MAX_CONFIGS) return -1;
|
||||
|
||||
rndis_per_dev_params [configNr].medium = medium;
|
||||
rndis_per_dev_params [configNr].speed = speed;
|
||||
rndis_per_dev_params[configNr].medium = medium;
|
||||
rndis_per_dev_params[configNr].speed = speed;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rndis_add_hdr (struct sk_buff *skb)
|
||||
void rndis_add_hdr(struct sk_buff *skb)
|
||||
{
|
||||
struct rndis_packet_msg_type *header;
|
||||
struct rndis_packet_msg_type *header;
|
||||
|
||||
if (!skb)
|
||||
return;
|
||||
header = (void *) skb_push (skb, sizeof *header);
|
||||
memset (header, 0, sizeof *header);
|
||||
header = (void *)skb_push(skb, sizeof(*header));
|
||||
memset(header, 0, sizeof *header);
|
||||
header->MessageType = cpu_to_le32(REMOTE_NDIS_PACKET_MSG);
|
||||
header->MessageLength = cpu_to_le32(skb->len);
|
||||
header->DataOffset = cpu_to_le32 (36);
|
||||
header->DataLength = cpu_to_le32(skb->len - sizeof *header);
|
||||
header->DataOffset = cpu_to_le32(36);
|
||||
header->DataLength = cpu_to_le32(skb->len - sizeof(*header));
|
||||
}
|
||||
|
||||
void rndis_free_response (int configNr, u8 *buf)
|
||||
void rndis_free_response(int configNr, u8 *buf)
|
||||
{
|
||||
rndis_resp_t *r;
|
||||
struct list_head *act, *tmp;
|
||||
rndis_resp_t *r;
|
||||
struct list_head *act, *tmp;
|
||||
|
||||
list_for_each_safe (act, tmp,
|
||||
&(rndis_per_dev_params [configNr].resp_queue))
|
||||
list_for_each_safe(act, tmp,
|
||||
&(rndis_per_dev_params[configNr].resp_queue))
|
||||
{
|
||||
r = list_entry (act, rndis_resp_t, list);
|
||||
r = list_entry(act, rndis_resp_t, list);
|
||||
if (r && r->buf == buf) {
|
||||
list_del (&r->list);
|
||||
kfree (r);
|
||||
list_del(&r->list);
|
||||
kfree(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
u8 *rndis_get_next_response (int configNr, u32 *length)
|
||||
u8 *rndis_get_next_response(int configNr, u32 *length)
|
||||
{
|
||||
rndis_resp_t *r;
|
||||
struct list_head *act, *tmp;
|
||||
rndis_resp_t *r;
|
||||
struct list_head *act, *tmp;
|
||||
|
||||
if (!length) return NULL;
|
||||
|
||||
list_for_each_safe (act, tmp,
|
||||
&(rndis_per_dev_params [configNr].resp_queue))
|
||||
list_for_each_safe(act, tmp,
|
||||
&(rndis_per_dev_params[configNr].resp_queue))
|
||||
{
|
||||
r = list_entry (act, rndis_resp_t, list);
|
||||
r = list_entry(act, rndis_resp_t, list);
|
||||
if (!r->send) {
|
||||
r->send = 1;
|
||||
*length = r->length;
|
||||
|
|
@ -1011,20 +1009,20 @@ u8 *rndis_get_next_response (int configNr, u32 *length)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static rndis_resp_t *rndis_add_response (int configNr, u32 length)
|
||||
static rndis_resp_t *rndis_add_response(int configNr, u32 length)
|
||||
{
|
||||
rndis_resp_t *r;
|
||||
rndis_resp_t *r;
|
||||
|
||||
/* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */
|
||||
r = kmalloc (sizeof (rndis_resp_t) + length, GFP_ATOMIC);
|
||||
/* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */
|
||||
r = kmalloc(sizeof(rndis_resp_t) + length, GFP_ATOMIC);
|
||||
if (!r) return NULL;
|
||||
|
||||
r->buf = (u8 *) (r + 1);
|
||||
r->buf = (u8 *)(r + 1);
|
||||
r->length = length;
|
||||
r->send = 0;
|
||||
|
||||
list_add_tail (&r->list,
|
||||
&(rndis_per_dev_params [configNr].resp_queue));
|
||||
list_add_tail(&r->list,
|
||||
&(rndis_per_dev_params[configNr].resp_queue));
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -1033,7 +1031,7 @@ int rndis_rm_hdr(struct gether *port,
|
|||
struct sk_buff_head *list)
|
||||
{
|
||||
/* tmp points to a struct rndis_packet_msg_type */
|
||||
__le32 *tmp = (void *) skb->data;
|
||||
__le32 *tmp = (void *)skb->data;
|
||||
|
||||
/* MessageType, MessageLength */
|
||||
if (cpu_to_le32(REMOTE_NDIS_PACKET_MSG)
|
||||
|
|
@ -1054,7 +1052,7 @@ int rndis_rm_hdr(struct gether *port,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
|
||||
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
|
||||
|
||||
static int rndis_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
|
|
@ -1087,7 +1085,7 @@ static int rndis_proc_show(struct seq_file *m, void *v)
|
|||
}
|
||||
|
||||
static ssize_t rndis_proc_write(struct file *file, const char __user *buffer,
|
||||
size_t count, loff_t *ppos)
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
rndis_params *p = PDE(file->f_path.dentry->d_inode)->data;
|
||||
u32 speed = 0;
|
||||
|
|
@ -1109,11 +1107,11 @@ static ssize_t rndis_proc_write(struct file *file, const char __user *buffer,
|
|||
case '8':
|
||||
case '9':
|
||||
fl_speed = 1;
|
||||
speed = speed*10 + c - '0';
|
||||
speed = speed * 10 + c - '0';
|
||||
break;
|
||||
case 'C':
|
||||
case 'c':
|
||||
rndis_signal_connect (p->confignr);
|
||||
rndis_signal_connect(p->confignr);
|
||||
break;
|
||||
case 'D':
|
||||
case 'd':
|
||||
|
|
@ -1145,11 +1143,11 @@ static const struct file_operations rndis_proc_fops = {
|
|||
.write = rndis_proc_write,
|
||||
};
|
||||
|
||||
#define NAME_TEMPLATE "driver/rndis-%03d"
|
||||
#define NAME_TEMPLATE "driver/rndis-%03d"
|
||||
|
||||
static struct proc_dir_entry *rndis_connect_state [RNDIS_MAX_CONFIGS];
|
||||
|
||||
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
|
||||
#endif /* CONFIG_USB_GADGET_DEBUG_FILES */
|
||||
|
||||
|
||||
int rndis_init(void)
|
||||
|
|
@ -1160,42 +1158,40 @@ int rndis_init(void)
|
|||
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
|
||||
char name [20];
|
||||
|
||||
sprintf (name, NAME_TEMPLATE, i);
|
||||
if (!(rndis_connect_state [i]
|
||||
= proc_create_data(name, 0660, NULL,
|
||||
sprintf(name, NAME_TEMPLATE, i);
|
||||
rndis_connect_state[i] = proc_create_data(name, 0660, NULL,
|
||||
&rndis_proc_fops,
|
||||
(void *)(rndis_per_dev_params + i))))
|
||||
{
|
||||
pr_debug("%s :remove entries", __func__);
|
||||
(void *)(rndis_per_dev_params + i));
|
||||
if (!rndis_connect_state[i]) {
|
||||
pr_debug("%s: remove entries", __func__);
|
||||
while (i) {
|
||||
sprintf (name, NAME_TEMPLATE, --i);
|
||||
remove_proc_entry (name, NULL);
|
||||
sprintf(name, NAME_TEMPLATE, --i);
|
||||
remove_proc_entry(name, NULL);
|
||||
}
|
||||
pr_debug("\n");
|
||||
return -EIO;
|
||||
}
|
||||
#endif
|
||||
rndis_per_dev_params [i].confignr = i;
|
||||
rndis_per_dev_params [i].used = 0;
|
||||
rndis_per_dev_params [i].state = RNDIS_UNINITIALIZED;
|
||||
rndis_per_dev_params [i].media_state
|
||||
rndis_per_dev_params[i].confignr = i;
|
||||
rndis_per_dev_params[i].used = 0;
|
||||
rndis_per_dev_params[i].state = RNDIS_UNINITIALIZED;
|
||||
rndis_per_dev_params[i].media_state
|
||||
= NDIS_MEDIA_STATE_DISCONNECTED;
|
||||
INIT_LIST_HEAD (&(rndis_per_dev_params [i].resp_queue));
|
||||
INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rndis_exit (void)
|
||||
void rndis_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
|
||||
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
|
||||
u8 i;
|
||||
char name [20];
|
||||
char name[20];
|
||||
|
||||
for (i = 0; i < RNDIS_MAX_CONFIGS; i++) {
|
||||
sprintf (name, NAME_TEMPLATE, i);
|
||||
remove_proc_entry (name, NULL);
|
||||
sprintf(name, NAME_TEMPLATE, i);
|
||||
remove_proc_entry(name, NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2523,7 +2523,8 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct s3c_hsotg *hsotg = our_hsotg;
|
||||
int ret;
|
||||
|
|
@ -2543,7 +2544,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
dev_err(hsotg->dev, "%s: bad speed\n", __func__);
|
||||
}
|
||||
|
||||
if (!driver->bind || !driver->setup) {
|
||||
if (!bind || !driver->setup) {
|
||||
dev_err(hsotg->dev, "%s: missing entry points\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -2562,7 +2563,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
goto err;
|
||||
}
|
||||
|
||||
ret = driver->bind(&hsotg->gadget);
|
||||
ret = bind(&hsotg->gadget);
|
||||
if (ret) {
|
||||
dev_err(hsotg->dev, "failed bind %s\n", driver->driver.name);
|
||||
|
||||
|
|
@ -2687,7 +2688,7 @@ err:
|
|||
hsotg->gadget.dev.driver = NULL;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_register_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1632,15 +1632,15 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev)
|
|||
}
|
||||
|
||||
/*
|
||||
* usb_gadget_register_driver
|
||||
* usb_gadget_probe_driver
|
||||
*/
|
||||
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
||||
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
|
||||
int (*bind)(struct usb_gadget *))
|
||||
{
|
||||
struct s3c2410_udc *udc = the_controller;
|
||||
int retval;
|
||||
|
||||
dprintk(DEBUG_NORMAL, "usb_gadget_register_driver() '%s'\n",
|
||||
driver->driver.name);
|
||||
dprintk(DEBUG_NORMAL, "%s() '%s'\n", __func__, driver->driver.name);
|
||||
|
||||
/* Sanity checks */
|
||||
if (!udc)
|
||||
|
|
@ -1649,10 +1649,9 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
if (udc->driver)
|
||||
return -EBUSY;
|
||||
|
||||
if (!driver->bind || !driver->setup
|
||||
|| driver->speed < USB_SPEED_FULL) {
|
||||
if (!bind || !driver->setup || driver->speed < USB_SPEED_FULL) {
|
||||
printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n",
|
||||
driver->bind, driver->setup, driver->speed);
|
||||
bind, driver->setup, driver->speed);
|
||||
return -EINVAL;
|
||||
}
|
||||
#if defined(MODULE)
|
||||
|
|
@ -1675,7 +1674,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
|
|||
dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n",
|
||||
driver->driver.name);
|
||||
|
||||
if ((retval = driver->bind (&udc->gadget)) != 0) {
|
||||
if ((retval = bind(&udc->gadget)) != 0) {
|
||||
device_del(&udc->gadget.dev);
|
||||
goto register_error;
|
||||
}
|
||||
|
|
@ -1690,6 +1689,7 @@ register_error:
|
|||
udc->gadget.dev.driver = NULL;
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL(usb_gadget_probe_driver);
|
||||
|
||||
/*
|
||||
* usb_gadget_unregister_driver
|
||||
|
|
@ -2049,7 +2049,6 @@ static void __exit udc_exit(void)
|
|||
}
|
||||
|
||||
EXPORT_SYMBOL(usb_gadget_unregister_driver);
|
||||
EXPORT_SYMBOL(usb_gadget_register_driver);
|
||||
|
||||
module_init(udc_init);
|
||||
module_exit(udc_exit);
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __ref serial_bind_config(struct usb_configuration *c)
|
||||
static int __init serial_bind_config(struct usb_configuration *c)
|
||||
{
|
||||
unsigned i;
|
||||
int status = 0;
|
||||
|
|
@ -155,13 +155,12 @@ static int __ref serial_bind_config(struct usb_configuration *c)
|
|||
|
||||
static struct usb_configuration serial_config_driver = {
|
||||
/* .label = f(use_acm) */
|
||||
.bind = serial_bind_config,
|
||||
/* .bConfigurationValue = f(use_acm) */
|
||||
/* .iConfiguration = DYNAMIC */
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
};
|
||||
|
||||
static int __ref gs_bind(struct usb_composite_dev *cdev)
|
||||
static int __init gs_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
int gcnum;
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
|
|
@ -225,7 +224,8 @@ static int __ref gs_bind(struct usb_composite_dev *cdev)
|
|||
}
|
||||
|
||||
/* register our configuration */
|
||||
status = usb_add_config(cdev, &serial_config_driver);
|
||||
status = usb_add_config(cdev, &serial_config_driver,
|
||||
serial_bind_config);
|
||||
if (status < 0)
|
||||
goto fail;
|
||||
|
||||
|
|
@ -242,7 +242,6 @@ static struct usb_composite_driver gserial_driver = {
|
|||
.name = "g_serial",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.bind = gs_bind,
|
||||
};
|
||||
|
||||
static int __init init(void)
|
||||
|
|
@ -271,7 +270,7 @@ static int __init init(void)
|
|||
}
|
||||
strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label;
|
||||
|
||||
return usb_composite_register(&gserial_driver);
|
||||
return usb_composite_probe(&gserial_driver, gs_bind);
|
||||
}
|
||||
module_init(init);
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
* be defined (each of type pointer to char):
|
||||
* - fsg_string_manufacturer -- name of the manufacturer
|
||||
* - fsg_string_product -- name of the product
|
||||
* - fsg_string_serial -- product's serial
|
||||
* - fsg_string_config -- name of the configuration
|
||||
* - fsg_string_interface -- name of the interface
|
||||
* The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS
|
||||
|
|
@ -54,6 +53,8 @@
|
|||
*/
|
||||
|
||||
|
||||
#include <linux/usb/storage.h>
|
||||
#include <scsi/scsi.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
|
||||
|
|
@ -153,23 +154,6 @@
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/* SCSI device types */
|
||||
#define TYPE_DISK 0x00
|
||||
#define TYPE_CDROM 0x05
|
||||
|
||||
/* USB protocol value = the transport method */
|
||||
#define USB_PR_CBI 0x00 /* Control/Bulk/Interrupt */
|
||||
#define USB_PR_CB 0x01 /* Control/Bulk w/o interrupt */
|
||||
#define USB_PR_BULK 0x50 /* Bulk-only */
|
||||
|
||||
/* USB subclass value = the protocol encapsulation */
|
||||
#define USB_SC_RBC 0x01 /* Reduced Block Commands (flash) */
|
||||
#define USB_SC_8020 0x02 /* SFF-8020i, MMC-2, ATAPI (CD-ROM) */
|
||||
#define USB_SC_QIC 0x03 /* QIC-157 (tape) */
|
||||
#define USB_SC_UFI 0x04 /* UFI (floppy) */
|
||||
#define USB_SC_8070 0x05 /* SFF-8070i (removable) */
|
||||
#define USB_SC_SCSI 0x06 /* Transparent SCSI */
|
||||
|
||||
/* Bulk-only data structures */
|
||||
|
||||
/* Command Block Wrapper */
|
||||
|
|
@ -221,33 +205,6 @@ struct interrupt_data {
|
|||
/* Length of a SCSI Command Data Block */
|
||||
#define MAX_COMMAND_SIZE 16
|
||||
|
||||
/* SCSI commands that we recognize */
|
||||
#define SC_FORMAT_UNIT 0x04
|
||||
#define SC_INQUIRY 0x12
|
||||
#define SC_MODE_SELECT_6 0x15
|
||||
#define SC_MODE_SELECT_10 0x55
|
||||
#define SC_MODE_SENSE_6 0x1a
|
||||
#define SC_MODE_SENSE_10 0x5a
|
||||
#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e
|
||||
#define SC_READ_6 0x08
|
||||
#define SC_READ_10 0x28
|
||||
#define SC_READ_12 0xa8
|
||||
#define SC_READ_CAPACITY 0x25
|
||||
#define SC_READ_FORMAT_CAPACITIES 0x23
|
||||
#define SC_READ_HEADER 0x44
|
||||
#define SC_READ_TOC 0x43
|
||||
#define SC_RELEASE 0x17
|
||||
#define SC_REQUEST_SENSE 0x03
|
||||
#define SC_RESERVE 0x16
|
||||
#define SC_SEND_DIAGNOSTIC 0x1d
|
||||
#define SC_START_STOP_UNIT 0x1b
|
||||
#define SC_SYNCHRONIZE_CACHE 0x35
|
||||
#define SC_TEST_UNIT_READY 0x00
|
||||
#define SC_VERIFY 0x2f
|
||||
#define SC_WRITE_6 0x0a
|
||||
#define SC_WRITE_10 0x2a
|
||||
#define SC_WRITE_12 0xaa
|
||||
|
||||
/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */
|
||||
#define SS_NO_SENSE 0
|
||||
#define SS_COMMUNICATION_FAILURE 0x040800
|
||||
|
|
@ -552,7 +509,7 @@ static struct usb_string fsg_strings[] = {
|
|||
#ifndef FSG_NO_DEVICE_STRINGS
|
||||
{FSG_STRING_MANUFACTURER, fsg_string_manufacturer},
|
||||
{FSG_STRING_PRODUCT, fsg_string_product},
|
||||
{FSG_STRING_SERIAL, fsg_string_serial},
|
||||
{FSG_STRING_SERIAL, ""},
|
||||
{FSG_STRING_CONFIG, fsg_string_config},
|
||||
#endif
|
||||
{FSG_STRING_INTERFACE, fsg_string_interface},
|
||||
|
|
|
|||
|
|
@ -308,7 +308,7 @@ static const struct uvc_descriptor_header * const uvc_hs_streaming_cls[] = {
|
|||
* USB configuration
|
||||
*/
|
||||
|
||||
static int __ref
|
||||
static int __init
|
||||
webcam_config_bind(struct usb_configuration *c)
|
||||
{
|
||||
return uvc_bind_config(c, uvc_control_cls, uvc_fs_streaming_cls,
|
||||
|
|
@ -317,7 +317,6 @@ webcam_config_bind(struct usb_configuration *c)
|
|||
|
||||
static struct usb_configuration webcam_config_driver = {
|
||||
.label = webcam_config_label,
|
||||
.bind = webcam_config_bind,
|
||||
.bConfigurationValue = 1,
|
||||
.iConfiguration = 0, /* dynamic */
|
||||
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
|
||||
|
|
@ -330,7 +329,7 @@ webcam_unbind(struct usb_composite_dev *cdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int __ref
|
||||
static int __init
|
||||
webcam_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -354,7 +353,8 @@ webcam_bind(struct usb_composite_dev *cdev)
|
|||
webcam_config_driver.iConfiguration = ret;
|
||||
|
||||
/* Register our configuration. */
|
||||
if ((ret = usb_add_config(cdev, &webcam_config_driver)) < 0)
|
||||
if ((ret = usb_add_config(cdev, &webcam_config_driver,
|
||||
webcam_config_bind)) < 0)
|
||||
goto error;
|
||||
|
||||
INFO(cdev, "Webcam Video Gadget\n");
|
||||
|
|
@ -373,14 +373,13 @@ static struct usb_composite_driver webcam_driver = {
|
|||
.name = "g_webcam",
|
||||
.dev = &webcam_device_descriptor,
|
||||
.strings = webcam_device_strings,
|
||||
.bind = webcam_bind,
|
||||
.unbind = webcam_unbind,
|
||||
};
|
||||
|
||||
static int __init
|
||||
webcam_init(void)
|
||||
{
|
||||
return usb_composite_register(&webcam_driver);
|
||||
return usb_composite_probe(&webcam_driver, webcam_bind);
|
||||
}
|
||||
|
||||
static void __exit
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ static void zero_resume(struct usb_composite_dev *cdev)
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
static int __ref zero_bind(struct usb_composite_dev *cdev)
|
||||
static int __init zero_bind(struct usb_composite_dev *cdev)
|
||||
{
|
||||
int gcnum;
|
||||
struct usb_gadget *gadget = cdev->gadget;
|
||||
|
|
@ -340,7 +340,6 @@ static struct usb_composite_driver zero_driver = {
|
|||
.name = "zero",
|
||||
.dev = &device_desc,
|
||||
.strings = dev_strings,
|
||||
.bind = zero_bind,
|
||||
.unbind = zero_unbind,
|
||||
.suspend = zero_suspend,
|
||||
.resume = zero_resume,
|
||||
|
|
@ -351,7 +350,7 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
static int __init init(void)
|
||||
{
|
||||
return usb_composite_register(&zero_driver);
|
||||
return usb_composite_probe(&zero_driver, zero_bind);
|
||||
}
|
||||
module_init(init);
|
||||
|
||||
|
|
|
|||
|
|
@ -93,12 +93,14 @@ config USB_EHCI_TT_NEWSCHED
|
|||
|
||||
config USB_EHCI_BIG_ENDIAN_MMIO
|
||||
bool
|
||||
depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX)
|
||||
depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || ARCH_IXP4XX || \
|
||||
XPS_USB_HCD_XILINX || PPC_MPC512x)
|
||||
default y
|
||||
|
||||
config USB_EHCI_BIG_ENDIAN_DESC
|
||||
bool
|
||||
depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX)
|
||||
depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \
|
||||
PPC_MPC512x)
|
||||
default y
|
||||
|
||||
config XPS_USB_HCD_XILINX
|
||||
|
|
@ -112,10 +114,14 @@ config XPS_USB_HCD_XILINX
|
|||
support both high speed and full speed devices, or high speed
|
||||
devices only.
|
||||
|
||||
config USB_FSL_MPH_DR_OF
|
||||
tristate
|
||||
|
||||
config USB_EHCI_FSL
|
||||
bool "Support for Freescale on-chip EHCI USB controller"
|
||||
depends on USB_EHCI_HCD && FSL_SOC
|
||||
select USB_EHCI_ROOT_HUB_TT
|
||||
select USB_FSL_MPH_DR_OF
|
||||
---help---
|
||||
Variation of ARC USB block used in some Freescale chips.
|
||||
|
||||
|
|
|
|||
|
|
@ -2,17 +2,17 @@
|
|||
# Makefile for USB Host Controller Drivers
|
||||
#
|
||||
|
||||
ifeq ($(CONFIG_USB_DEBUG),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
endif
|
||||
ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
|
||||
|
||||
isp1760-objs := isp1760-hcd.o isp1760-if.o
|
||||
fhci-objs := fhci-hcd.o fhci-hub.o fhci-q.o fhci-mem.o \
|
||||
fhci-tds.o fhci-sched.o
|
||||
ifeq ($(CONFIG_FHCI_DEBUG),y)
|
||||
fhci-objs += fhci-dbg.o
|
||||
endif
|
||||
xhci-hcd-objs := xhci.o xhci-mem.o xhci-pci.o xhci-ring.o xhci-hub.o xhci-dbg.o
|
||||
isp1760-y := isp1760-hcd.o isp1760-if.o
|
||||
|
||||
fhci-y := fhci-hcd.o fhci-hub.o fhci-q.o
|
||||
fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o
|
||||
|
||||
fhci-$(CONFIG_FHCI_DEBUG) += fhci-dbg.o
|
||||
|
||||
xhci-hcd-y := xhci.o xhci-mem.o xhci-pci.o
|
||||
xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
|
||||
|
||||
obj-$(CONFIG_USB_WHCI_HCD) += whci/
|
||||
|
||||
|
|
@ -33,4 +33,4 @@ obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
|
|||
obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
|
||||
obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
|
||||
obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
|
||||
|
||||
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
|
||||
|
|
|
|||
|
|
@ -116,13 +116,33 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
|
|||
goto err3;
|
||||
}
|
||||
|
||||
/* Enable USB controller */
|
||||
temp = in_be32(hcd->regs + 0x500);
|
||||
out_be32(hcd->regs + 0x500, temp | 0x4);
|
||||
pdata->regs = hcd->regs;
|
||||
|
||||
/* Set to Host mode */
|
||||
temp = in_le32(hcd->regs + 0x1a8);
|
||||
out_le32(hcd->regs + 0x1a8, temp | 0x3);
|
||||
/*
|
||||
* do platform specific init: check the clock, grab/config pins, etc.
|
||||
*/
|
||||
if (pdata->init && pdata->init(pdev)) {
|
||||
retval = -ENODEV;
|
||||
goto err3;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if it is MPC5121 SoC, otherwise set pdata->have_sysif_regs
|
||||
* flag for 83xx or 8536 system interface registers.
|
||||
*/
|
||||
if (pdata->big_endian_mmio)
|
||||
temp = in_be32(hcd->regs + FSL_SOC_USB_ID);
|
||||
else
|
||||
temp = in_le32(hcd->regs + FSL_SOC_USB_ID);
|
||||
|
||||
if ((temp & ID_MSK) != (~((temp & NID_MSK) >> 8) & ID_MSK))
|
||||
pdata->have_sysif_regs = 1;
|
||||
|
||||
/* Enable USB controller, 83xx or 8536 */
|
||||
if (pdata->have_sysif_regs)
|
||||
setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4);
|
||||
|
||||
/* Don't need to set host mode here. It will be done by tdi_reset() */
|
||||
|
||||
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
if (retval != 0)
|
||||
|
|
@ -137,6 +157,8 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
|
|||
usb_put_hcd(hcd);
|
||||
err1:
|
||||
dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval);
|
||||
if (pdata->exit)
|
||||
pdata->exit(pdev);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
@ -154,17 +176,30 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
|
|||
static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
|
||||
/*
|
||||
* do platform specific un-initialization:
|
||||
* release iomux pins, disable clock, etc.
|
||||
*/
|
||||
if (pdata->exit)
|
||||
pdata->exit(pdev);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
}
|
||||
|
||||
static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
|
||||
enum fsl_usb2_phy_modes phy_mode,
|
||||
unsigned int port_offset)
|
||||
static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
|
||||
enum fsl_usb2_phy_modes phy_mode,
|
||||
unsigned int port_offset)
|
||||
{
|
||||
u32 portsc = 0;
|
||||
u32 portsc;
|
||||
|
||||
portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]);
|
||||
portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
|
||||
|
||||
switch (phy_mode) {
|
||||
case FSL_USB2_PHY_ULPI:
|
||||
portsc |= PORT_PTS_ULPI;
|
||||
|
|
@ -184,20 +219,21 @@ static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
|
|||
ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
|
||||
}
|
||||
|
||||
static void mpc83xx_usb_setup(struct usb_hcd *hcd)
|
||||
static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
struct usb_hcd *hcd = ehci_to_hcd(ehci);
|
||||
struct fsl_usb2_platform_data *pdata;
|
||||
void __iomem *non_ehci = hcd->regs;
|
||||
u32 temp;
|
||||
|
||||
pdata =
|
||||
(struct fsl_usb2_platform_data *)hcd->self.controller->
|
||||
platform_data;
|
||||
pdata = hcd->self.controller->platform_data;
|
||||
|
||||
/* Enable PHY interface in the control reg. */
|
||||
temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
|
||||
out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
|
||||
out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
|
||||
if (pdata->have_sysif_regs) {
|
||||
temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
|
||||
out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
|
||||
out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
|
||||
/*
|
||||
|
|
@ -214,7 +250,7 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
|
|||
|
||||
if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
|
||||
(pdata->operating_mode == FSL_USB2_DR_OTG))
|
||||
mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
|
||||
ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
|
||||
|
||||
if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
|
||||
unsigned int chip, rev, svr;
|
||||
|
|
@ -228,27 +264,27 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
|
|||
ehci->has_fsl_port_bug = 1;
|
||||
|
||||
if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
|
||||
mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
|
||||
ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
|
||||
if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
|
||||
mpc83xx_setup_phy(ehci, pdata->phy_mode, 1);
|
||||
ehci_fsl_setup_phy(ehci, pdata->phy_mode, 1);
|
||||
}
|
||||
|
||||
/* put controller in host mode. */
|
||||
ehci_writel(ehci, 0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
|
||||
if (pdata->have_sysif_regs) {
|
||||
#ifdef CONFIG_PPC_85xx
|
||||
out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008);
|
||||
out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080);
|
||||
out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008);
|
||||
out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080);
|
||||
#else
|
||||
out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
|
||||
out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
|
||||
out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
|
||||
out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
|
||||
#endif
|
||||
out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
|
||||
out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
|
||||
}
|
||||
}
|
||||
|
||||
/* called after powerup, by probe or system-pm "wakeup" */
|
||||
static int ehci_fsl_reinit(struct ehci_hcd *ehci)
|
||||
{
|
||||
mpc83xx_usb_setup(ehci_to_hcd(ehci));
|
||||
ehci_fsl_usb_setup(ehci);
|
||||
ehci_port_power(ehci, 0);
|
||||
|
||||
return 0;
|
||||
|
|
@ -259,6 +295,11 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
|
|||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int retval;
|
||||
struct fsl_usb2_platform_data *pdata;
|
||||
|
||||
pdata = hcd->self.controller->platform_data;
|
||||
ehci->big_endian_desc = pdata->big_endian_desc;
|
||||
ehci->big_endian_mmio = pdata->big_endian_mmio;
|
||||
|
||||
/* EHCI registers start at offset 0x100 */
|
||||
ehci->caps = hcd->regs + 0x100;
|
||||
|
|
@ -270,6 +311,8 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
|
|||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
hcd->has_tt = 1;
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
|
@ -279,8 +322,6 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
hcd->has_tt = 1;
|
||||
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
|
@ -372,7 +413,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
|
|||
* generic hardware linkage
|
||||
*/
|
||||
.irq = ehci_irq,
|
||||
.flags = HCD_USB2,
|
||||
.flags = HCD_USB2 | HCD_MEMORY,
|
||||
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (c) 2005 freescale semiconductor
|
||||
/* Copyright (C) 2005-2010 Freescale Semiconductor, Inc.
|
||||
* Copyright (c) 2005 MontaVista Software
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
|
|
@ -19,6 +19,9 @@
|
|||
#define _EHCI_FSL_H
|
||||
|
||||
/* offsets for the non-ehci registers in the FSL SOC USB controller */
|
||||
#define FSL_SOC_USB_ID 0x0
|
||||
#define ID_MSK 0x3f
|
||||
#define NID_MSK 0x3f00
|
||||
#define FSL_SOC_USB_ULPIVP 0x170
|
||||
#define FSL_SOC_USB_PORTSC1 0x184
|
||||
#define PORT_PTS_MSK (3<<30)
|
||||
|
|
@ -27,7 +30,14 @@
|
|||
#define PORT_PTS_SERIAL (3<<30)
|
||||
#define PORT_PTS_PTW (1<<28)
|
||||
#define FSL_SOC_USB_PORTSC2 0x188
|
||||
#define FSL_SOC_USB_USBMODE 0x1a8
|
||||
|
||||
#define FSL_SOC_USB_USBGENCTRL 0x200
|
||||
#define USBGENCTRL_PPP (1 << 3)
|
||||
#define USBGENCTRL_PFP (1 << 2)
|
||||
#define FSL_SOC_USB_ISIPHYCTRL 0x204
|
||||
#define ISIPHYCTRL_PXE (1)
|
||||
#define ISIPHYCTRL_PHYE (1 << 4)
|
||||
|
||||
#define FSL_SOC_USB_SNOOP1 0x400 /* NOTE: big-endian */
|
||||
#define FSL_SOC_USB_SNOOP2 0x404 /* NOTE: big-endian */
|
||||
#define FSL_SOC_USB_AGECNTTHRSH 0x408 /* NOTE: big-endian */
|
||||
|
|
|
|||
|
|
@ -194,6 +194,17 @@ static int handshake (struct ehci_hcd *ehci, void __iomem *ptr,
|
|||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* check TDI/ARC silicon is in host mode */
|
||||
static int tdi_in_host_mode (struct ehci_hcd *ehci)
|
||||
{
|
||||
u32 __iomem *reg_ptr;
|
||||
u32 tmp;
|
||||
|
||||
reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + USBMODE);
|
||||
tmp = ehci_readl(ehci, reg_ptr);
|
||||
return (tmp & 3) == USBMODE_CM_HC;
|
||||
}
|
||||
|
||||
/* force HC to halt state from unknown (EHCI spec section 2.3) */
|
||||
static int ehci_halt (struct ehci_hcd *ehci)
|
||||
{
|
||||
|
|
@ -202,6 +213,10 @@ static int ehci_halt (struct ehci_hcd *ehci)
|
|||
/* disable any irqs left enabled by previous code */
|
||||
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
|
||||
|
||||
if (ehci_is_TDI(ehci) && tdi_in_host_mode(ehci) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((temp & STS_HALT) != 0)
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ static inline void ehci_qtd_init(struct ehci_hcd *ehci, struct ehci_qtd *qtd,
|
|||
{
|
||||
memset (qtd, 0, sizeof *qtd);
|
||||
qtd->qtd_dma = dma;
|
||||
qtd->hw_token = cpu_to_le32 (QTD_STS_HALT);
|
||||
qtd->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
|
||||
qtd->hw_next = EHCI_LIST_END(ehci);
|
||||
qtd->hw_alt_next = EHCI_LIST_END(ehci);
|
||||
INIT_LIST_HEAD (&qtd->qtd_list);
|
||||
|
|
|
|||
|
|
@ -26,9 +26,6 @@
|
|||
#include <mach/mxc_ehci.h>
|
||||
|
||||
#define ULPI_VIEWPORT_OFFSET 0x170
|
||||
#define PORTSC_OFFSET 0x184
|
||||
#define USBMODE_OFFSET 0x1a8
|
||||
#define USBMODE_CM_HOST 3
|
||||
|
||||
struct ehci_mxc_priv {
|
||||
struct clk *usbclk, *ahbclk;
|
||||
|
|
@ -51,6 +48,8 @@ static int ehci_mxc_setup(struct usb_hcd *hcd)
|
|||
/* cache this readonly data; minimize chip reads */
|
||||
ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
|
||||
|
||||
hcd->has_tt = 1;
|
||||
|
||||
retval = ehci_halt(ehci);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
|
@ -60,8 +59,6 @@ static int ehci_mxc_setup(struct usb_hcd *hcd)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
hcd->has_tt = 1;
|
||||
|
||||
ehci->sbrn = 0x20;
|
||||
|
||||
ehci_reset(ehci);
|
||||
|
|
@ -191,12 +188,8 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
|
|||
clk_enable(priv->ahbclk);
|
||||
}
|
||||
|
||||
/* set USBMODE to host mode */
|
||||
temp = readl(hcd->regs + USBMODE_OFFSET);
|
||||
writel(temp | USBMODE_CM_HOST, hcd->regs + USBMODE_OFFSET);
|
||||
|
||||
/* set up the PORTSCx register */
|
||||
writel(pdata->portsc, hcd->regs + PORTSC_OFFSET);
|
||||
ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);
|
||||
mdelay(10);
|
||||
|
||||
/* setup specific usb hw */
|
||||
|
|
|
|||
308
drivers/usb/host/fsl-mph-dr-of.c
Normal file
308
drivers/usb/host/fsl-mph-dr-of.c
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
/*
|
||||
* Setup platform devices needed by the Freescale multi-port host
|
||||
* and/or dual-role USB controller modules based on the description
|
||||
* in flat device tree.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/fsl_devices.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/clk.h>
|
||||
|
||||
struct fsl_usb2_dev_data {
|
||||
char *dr_mode; /* controller mode */
|
||||
char *drivers[3]; /* drivers to instantiate for this mode */
|
||||
enum fsl_usb2_operating_modes op_mode; /* operating mode */
|
||||
};
|
||||
|
||||
struct fsl_usb2_dev_data dr_mode_data[] __devinitdata = {
|
||||
{
|
||||
.dr_mode = "host",
|
||||
.drivers = { "fsl-ehci", NULL, NULL, },
|
||||
.op_mode = FSL_USB2_DR_HOST,
|
||||
},
|
||||
{
|
||||
.dr_mode = "otg",
|
||||
.drivers = { "fsl-usb2-otg", "fsl-ehci", "fsl-usb2-udc", },
|
||||
.op_mode = FSL_USB2_DR_OTG,
|
||||
},
|
||||
{
|
||||
.dr_mode = "peripheral",
|
||||
.drivers = { "fsl-usb2-udc", NULL, NULL, },
|
||||
.op_mode = FSL_USB2_DR_DEVICE,
|
||||
},
|
||||
};
|
||||
|
||||
struct fsl_usb2_dev_data * __devinit get_dr_mode_data(struct device_node *np)
|
||||
{
|
||||
const unsigned char *prop;
|
||||
int i;
|
||||
|
||||
prop = of_get_property(np, "dr_mode", NULL);
|
||||
if (prop) {
|
||||
for (i = 0; i < ARRAY_SIZE(dr_mode_data); i++) {
|
||||
if (!strcmp(prop, dr_mode_data[i].dr_mode))
|
||||
return &dr_mode_data[i];
|
||||
}
|
||||
}
|
||||
pr_warn("%s: Invalid 'dr_mode' property, fallback to host mode\n",
|
||||
np->full_name);
|
||||
return &dr_mode_data[0]; /* mode not specified, use host */
|
||||
}
|
||||
|
||||
static enum fsl_usb2_phy_modes __devinit determine_usb_phy(const char *phy_type)
|
||||
{
|
||||
if (!phy_type)
|
||||
return FSL_USB2_PHY_NONE;
|
||||
if (!strcasecmp(phy_type, "ulpi"))
|
||||
return FSL_USB2_PHY_ULPI;
|
||||
if (!strcasecmp(phy_type, "utmi"))
|
||||
return FSL_USB2_PHY_UTMI;
|
||||
if (!strcasecmp(phy_type, "utmi_wide"))
|
||||
return FSL_USB2_PHY_UTMI_WIDE;
|
||||
if (!strcasecmp(phy_type, "serial"))
|
||||
return FSL_USB2_PHY_SERIAL;
|
||||
|
||||
return FSL_USB2_PHY_NONE;
|
||||
}
|
||||
|
||||
struct platform_device * __devinit fsl_usb2_device_register(
|
||||
struct platform_device *ofdev,
|
||||
struct fsl_usb2_platform_data *pdata,
|
||||
const char *name, int id)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
const struct resource *res = ofdev->resource;
|
||||
unsigned int num = ofdev->num_resources;
|
||||
int retval;
|
||||
|
||||
pdev = platform_device_alloc(name, id);
|
||||
if (!pdev) {
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
pdev->dev.parent = &ofdev->dev;
|
||||
|
||||
pdev->dev.coherent_dma_mask = ofdev->dev.coherent_dma_mask;
|
||||
pdev->dev.dma_mask = &pdev->archdata.dma_mask;
|
||||
*pdev->dev.dma_mask = *ofdev->dev.dma_mask;
|
||||
|
||||
retval = platform_device_add_data(pdev, pdata, sizeof(*pdata));
|
||||
if (retval)
|
||||
goto error;
|
||||
|
||||
if (num) {
|
||||
retval = platform_device_add_resources(pdev, res, num);
|
||||
if (retval)
|
||||
goto error;
|
||||
}
|
||||
|
||||
retval = platform_device_add(pdev);
|
||||
if (retval)
|
||||
goto error;
|
||||
|
||||
return pdev;
|
||||
|
||||
error:
|
||||
platform_device_put(pdev);
|
||||
return ERR_PTR(retval);
|
||||
}
|
||||
|
||||
static const struct of_device_id fsl_usb2_mph_dr_of_match[];
|
||||
|
||||
static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev)
|
||||
{
|
||||
struct device_node *np = ofdev->dev.of_node;
|
||||
struct platform_device *usb_dev;
|
||||
struct fsl_usb2_platform_data data, *pdata;
|
||||
struct fsl_usb2_dev_data *dev_data;
|
||||
const struct of_device_id *match;
|
||||
const unsigned char *prop;
|
||||
static unsigned int idx;
|
||||
int i;
|
||||
|
||||
if (!of_device_is_available(np))
|
||||
return -ENODEV;
|
||||
|
||||
match = of_match_device(fsl_usb2_mph_dr_of_match, &ofdev->dev);
|
||||
if (!match)
|
||||
return -ENODEV;
|
||||
|
||||
pdata = &data;
|
||||
if (match->data)
|
||||
memcpy(pdata, match->data, sizeof(data));
|
||||
else
|
||||
memset(pdata, 0, sizeof(data));
|
||||
|
||||
dev_data = get_dr_mode_data(np);
|
||||
|
||||
if (of_device_is_compatible(np, "fsl-usb2-mph")) {
|
||||
if (of_get_property(np, "port0", NULL))
|
||||
pdata->port_enables |= FSL_USB2_PORT0_ENABLED;
|
||||
|
||||
if (of_get_property(np, "port1", NULL))
|
||||
pdata->port_enables |= FSL_USB2_PORT1_ENABLED;
|
||||
|
||||
pdata->operating_mode = FSL_USB2_MPH_HOST;
|
||||
} else {
|
||||
if (of_get_property(np, "fsl,invert-drvvbus", NULL))
|
||||
pdata->invert_drvvbus = 1;
|
||||
|
||||
if (of_get_property(np, "fsl,invert-pwr-fault", NULL))
|
||||
pdata->invert_pwr_fault = 1;
|
||||
|
||||
/* setup mode selected in the device tree */
|
||||
pdata->operating_mode = dev_data->op_mode;
|
||||
}
|
||||
|
||||
prop = of_get_property(np, "phy_type", NULL);
|
||||
pdata->phy_mode = determine_usb_phy(prop);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(dev_data->drivers); i++) {
|
||||
if (!dev_data->drivers[i])
|
||||
continue;
|
||||
usb_dev = fsl_usb2_device_register(ofdev, pdata,
|
||||
dev_data->drivers[i], idx);
|
||||
if (IS_ERR(usb_dev)) {
|
||||
dev_err(&ofdev->dev, "Can't register usb device\n");
|
||||
return PTR_ERR(usb_dev);
|
||||
}
|
||||
}
|
||||
idx++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit __unregister_subdev(struct device *dev, void *d)
|
||||
{
|
||||
platform_device_unregister(to_platform_device(dev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devexit fsl_usb2_mph_dr_of_remove(struct platform_device *ofdev)
|
||||
{
|
||||
device_for_each_child(&ofdev->dev, NULL, __unregister_subdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PPC_MPC512x
|
||||
|
||||
#define USBGENCTRL 0x200 /* NOTE: big endian */
|
||||
#define GC_WU_INT_CLR (1 << 5) /* Wakeup int clear */
|
||||
#define GC_ULPI_SEL (1 << 4) /* ULPI i/f select (usb0 only)*/
|
||||
#define GC_PPP (1 << 3) /* Inv. Port Power Polarity */
|
||||
#define GC_PFP (1 << 2) /* Inv. Power Fault Polarity */
|
||||
#define GC_WU_ULPI_EN (1 << 1) /* Wakeup on ULPI event */
|
||||
#define GC_WU_IE (1 << 1) /* Wakeup interrupt enable */
|
||||
|
||||
#define ISIPHYCTRL 0x204 /* NOTE: big endian */
|
||||
#define PHYCTRL_PHYE (1 << 4) /* On-chip UTMI PHY enable */
|
||||
#define PHYCTRL_BSENH (1 << 3) /* Bit Stuff Enable High */
|
||||
#define PHYCTRL_BSEN (1 << 2) /* Bit Stuff Enable */
|
||||
#define PHYCTRL_LSFE (1 << 1) /* Line State Filter Enable */
|
||||
#define PHYCTRL_PXE (1 << 0) /* PHY oscillator enable */
|
||||
|
||||
int fsl_usb2_mpc5121_init(struct platform_device *pdev)
|
||||
{
|
||||
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
|
||||
struct clk *clk;
|
||||
char clk_name[10];
|
||||
int base, clk_num;
|
||||
|
||||
base = pdev->resource->start & 0xf000;
|
||||
if (base == 0x3000)
|
||||
clk_num = 1;
|
||||
else if (base == 0x4000)
|
||||
clk_num = 2;
|
||||
else
|
||||
return -ENODEV;
|
||||
|
||||
snprintf(clk_name, sizeof(clk_name), "usb%d_clk", clk_num);
|
||||
clk = clk_get(&pdev->dev, clk_name);
|
||||
if (IS_ERR(clk)) {
|
||||
dev_err(&pdev->dev, "failed to get clk\n");
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
|
||||
clk_enable(clk);
|
||||
pdata->clk = clk;
|
||||
|
||||
if (pdata->phy_mode == FSL_USB2_PHY_UTMI_WIDE) {
|
||||
u32 reg = 0;
|
||||
|
||||
if (pdata->invert_drvvbus)
|
||||
reg |= GC_PPP;
|
||||
|
||||
if (pdata->invert_pwr_fault)
|
||||
reg |= GC_PFP;
|
||||
|
||||
out_be32(pdata->regs + ISIPHYCTRL, PHYCTRL_PHYE | PHYCTRL_PXE);
|
||||
out_be32(pdata->regs + USBGENCTRL, reg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fsl_usb2_mpc5121_exit(struct platform_device *pdev)
|
||||
{
|
||||
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
|
||||
|
||||
pdata->regs = NULL;
|
||||
|
||||
if (pdata->clk) {
|
||||
clk_disable(pdata->clk);
|
||||
clk_put(pdata->clk);
|
||||
}
|
||||
}
|
||||
|
||||
struct fsl_usb2_platform_data fsl_usb2_mpc5121_pd = {
|
||||
.big_endian_desc = 1,
|
||||
.big_endian_mmio = 1,
|
||||
.es = 1,
|
||||
.le_setup_buf = 1,
|
||||
.init = fsl_usb2_mpc5121_init,
|
||||
.exit = fsl_usb2_mpc5121_exit,
|
||||
};
|
||||
#endif /* CONFIG_PPC_MPC512x */
|
||||
|
||||
static const struct of_device_id fsl_usb2_mph_dr_of_match[] = {
|
||||
{ .compatible = "fsl-usb2-mph", },
|
||||
{ .compatible = "fsl-usb2-dr", },
|
||||
#ifdef CONFIG_PPC_MPC512x
|
||||
{ .compatible = "fsl,mpc5121-usb2-dr", .data = &fsl_usb2_mpc5121_pd, },
|
||||
#endif
|
||||
{},
|
||||
};
|
||||
|
||||
static struct platform_driver fsl_usb2_mph_dr_driver = {
|
||||
.driver = {
|
||||
.name = "fsl-usb2-mph-dr",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = fsl_usb2_mph_dr_of_match,
|
||||
},
|
||||
.probe = fsl_usb2_mph_dr_of_probe,
|
||||
.remove = __devexit_p(fsl_usb2_mph_dr_of_remove),
|
||||
};
|
||||
|
||||
static int __init fsl_usb2_mph_dr_init(void)
|
||||
{
|
||||
return platform_driver_register(&fsl_usb2_mph_dr_driver);
|
||||
}
|
||||
module_init(fsl_usb2_mph_dr_init);
|
||||
|
||||
static void __exit fsl_usb2_mph_dr_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&fsl_usb2_mph_dr_driver);
|
||||
}
|
||||
module_exit(fsl_usb2_mph_dr_exit);
|
||||
|
||||
MODULE_DESCRIPTION("FSL MPH DR OF devices driver");
|
||||
MODULE_AUTHOR("Anatolij Gustschin <[email protected]>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -57,6 +57,7 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
#include "imx21-hcd.h"
|
||||
|
||||
|
|
@ -136,9 +137,18 @@ static int imx21_hc_get_frame(struct usb_hcd *hcd)
|
|||
return wrap_frame(readl(imx21->regs + USBH_FRMNUB));
|
||||
}
|
||||
|
||||
static inline bool unsuitable_for_dma(dma_addr_t addr)
|
||||
{
|
||||
return (addr & 3) != 0;
|
||||
}
|
||||
|
||||
#include "imx21-dbg.c"
|
||||
|
||||
static void nonisoc_urb_completed_for_etd(
|
||||
struct imx21 *imx21, struct etd_priv *etd, int status);
|
||||
static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb);
|
||||
static void free_dmem(struct imx21 *imx21, struct etd_priv *etd);
|
||||
|
||||
/* =========================================== */
|
||||
/* ETD management */
|
||||
/* =========================================== */
|
||||
|
|
@ -185,7 +195,8 @@ static void reset_etd(struct imx21 *imx21, int num)
|
|||
etd_writel(imx21, num, i, 0);
|
||||
etd->urb = NULL;
|
||||
etd->ep = NULL;
|
||||
etd->td = NULL;;
|
||||
etd->td = NULL;
|
||||
etd->bounce_buffer = NULL;
|
||||
}
|
||||
|
||||
static void free_etd(struct imx21 *imx21, int num)
|
||||
|
|
@ -221,26 +232,94 @@ static void setup_etd_dword0(struct imx21 *imx21,
|
|||
((u32) maxpacket << DW0_MAXPKTSIZ));
|
||||
}
|
||||
|
||||
static void activate_etd(struct imx21 *imx21,
|
||||
int etd_num, dma_addr_t dma, u8 dir)
|
||||
/**
|
||||
* Copy buffer to data controller data memory.
|
||||
* We cannot use memcpy_toio() because the hardware requires 32bit writes
|
||||
*/
|
||||
static void copy_to_dmem(
|
||||
struct imx21 *imx21, int dmem_offset, void *src, int count)
|
||||
{
|
||||
void __iomem *dmem = imx21->regs + USBOTG_DMEM + dmem_offset;
|
||||
u32 word = 0;
|
||||
u8 *p = src;
|
||||
int byte = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
byte = i % 4;
|
||||
word += (*p++ << (byte * 8));
|
||||
if (byte == 3) {
|
||||
writel(word, dmem);
|
||||
dmem += 4;
|
||||
word = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (count && byte != 3)
|
||||
writel(word, dmem);
|
||||
}
|
||||
|
||||
static void activate_etd(struct imx21 *imx21, int etd_num, u8 dir)
|
||||
{
|
||||
u32 etd_mask = 1 << etd_num;
|
||||
struct etd_priv *etd = &imx21->etd[etd_num];
|
||||
|
||||
if (etd->dma_handle && unsuitable_for_dma(etd->dma_handle)) {
|
||||
/* For non aligned isoc the condition below is always true */
|
||||
if (etd->len <= etd->dmem_size) {
|
||||
/* Fits into data memory, use PIO */
|
||||
if (dir != TD_DIR_IN) {
|
||||
copy_to_dmem(imx21,
|
||||
etd->dmem_offset,
|
||||
etd->cpu_buffer, etd->len);
|
||||
}
|
||||
etd->dma_handle = 0;
|
||||
|
||||
} else {
|
||||
/* Too big for data memory, use bounce buffer */
|
||||
enum dma_data_direction dmadir;
|
||||
|
||||
if (dir == TD_DIR_IN) {
|
||||
dmadir = DMA_FROM_DEVICE;
|
||||
etd->bounce_buffer = kmalloc(etd->len,
|
||||
GFP_ATOMIC);
|
||||
} else {
|
||||
dmadir = DMA_TO_DEVICE;
|
||||
etd->bounce_buffer = kmemdup(etd->cpu_buffer,
|
||||
etd->len,
|
||||
GFP_ATOMIC);
|
||||
}
|
||||
if (!etd->bounce_buffer) {
|
||||
dev_err(imx21->dev, "failed bounce alloc\n");
|
||||
goto err_bounce_alloc;
|
||||
}
|
||||
|
||||
etd->dma_handle =
|
||||
dma_map_single(imx21->dev,
|
||||
etd->bounce_buffer,
|
||||
etd->len,
|
||||
dmadir);
|
||||
if (dma_mapping_error(imx21->dev, etd->dma_handle)) {
|
||||
dev_err(imx21->dev, "failed bounce map\n");
|
||||
goto err_bounce_map;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clear_toggle_bit(imx21, USBH_ETDDONESTAT, etd_mask);
|
||||
set_register_bits(imx21, USBH_ETDDONEEN, etd_mask);
|
||||
clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
|
||||
clear_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask);
|
||||
|
||||
if (dma) {
|
||||
if (etd->dma_handle) {
|
||||
set_register_bits(imx21, USB_ETDDMACHANLCLR, etd_mask);
|
||||
clear_toggle_bit(imx21, USBH_XBUFSTAT, etd_mask);
|
||||
clear_toggle_bit(imx21, USBH_YBUFSTAT, etd_mask);
|
||||
writel(dma, imx21->regs + USB_ETDSMSA(etd_num));
|
||||
writel(etd->dma_handle, imx21->regs + USB_ETDSMSA(etd_num));
|
||||
set_register_bits(imx21, USB_ETDDMAEN, etd_mask);
|
||||
} else {
|
||||
if (dir != TD_DIR_IN) {
|
||||
/* need to set for ZLP */
|
||||
/* need to set for ZLP and PIO */
|
||||
set_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
|
||||
set_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask);
|
||||
}
|
||||
|
|
@ -263,6 +342,14 @@ static void activate_etd(struct imx21 *imx21,
|
|||
|
||||
etd->active_count = 1;
|
||||
writel(etd_mask, imx21->regs + USBH_ETDENSET);
|
||||
return;
|
||||
|
||||
err_bounce_map:
|
||||
kfree(etd->bounce_buffer);
|
||||
|
||||
err_bounce_alloc:
|
||||
free_dmem(imx21, etd);
|
||||
nonisoc_urb_completed_for_etd(imx21, etd, -ENOMEM);
|
||||
}
|
||||
|
||||
/* =========================================== */
|
||||
|
|
@ -323,16 +410,23 @@ static void activate_queued_etd(struct imx21 *imx21,
|
|||
etd_writel(imx21, etd_num, 1,
|
||||
((dmem_offset + maxpacket) << DW1_YBUFSRTAD) | dmem_offset);
|
||||
|
||||
etd->dmem_offset = dmem_offset;
|
||||
urb_priv->active = 1;
|
||||
activate_etd(imx21, etd_num, etd->dma_handle, dir);
|
||||
activate_etd(imx21, etd_num, dir);
|
||||
}
|
||||
|
||||
static void free_dmem(struct imx21 *imx21, int offset)
|
||||
static void free_dmem(struct imx21 *imx21, struct etd_priv *etd)
|
||||
{
|
||||
struct imx21_dmem_area *area;
|
||||
struct etd_priv *etd, *tmp;
|
||||
struct etd_priv *tmp;
|
||||
int found = 0;
|
||||
int offset;
|
||||
|
||||
if (!etd->dmem_size)
|
||||
return;
|
||||
etd->dmem_size = 0;
|
||||
|
||||
offset = etd->dmem_offset;
|
||||
list_for_each_entry(area, &imx21->dmem_list, list) {
|
||||
if (area->offset == offset) {
|
||||
debug_dmem_freed(imx21, area->size);
|
||||
|
|
@ -378,20 +472,23 @@ static void free_epdmem(struct imx21 *imx21, struct usb_host_endpoint *ep)
|
|||
/* =========================================== */
|
||||
/* End handling */
|
||||
/* =========================================== */
|
||||
static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb);
|
||||
|
||||
/* Endpoint now idle - release it's ETD(s) or asssign to queued request */
|
||||
static void ep_idle(struct imx21 *imx21, struct ep_priv *ep_priv)
|
||||
{
|
||||
int etd_num;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_ISO_ETDS; i++) {
|
||||
etd_num = ep_priv->etd[i];
|
||||
int etd_num = ep_priv->etd[i];
|
||||
struct etd_priv *etd;
|
||||
if (etd_num < 0)
|
||||
continue;
|
||||
|
||||
etd = &imx21->etd[etd_num];
|
||||
ep_priv->etd[i] = -1;
|
||||
|
||||
free_dmem(imx21, etd); /* for isoc */
|
||||
|
||||
if (list_empty(&imx21->queue_for_etd)) {
|
||||
free_etd(imx21, etd_num);
|
||||
continue;
|
||||
|
|
@ -437,6 +534,24 @@ __acquires(imx21->lock)
|
|||
ep_idle(imx21, ep_priv);
|
||||
}
|
||||
|
||||
static void nonisoc_urb_completed_for_etd(
|
||||
struct imx21 *imx21, struct etd_priv *etd, int status)
|
||||
{
|
||||
struct usb_host_endpoint *ep = etd->ep;
|
||||
|
||||
urb_done(imx21->hcd, etd->urb, status);
|
||||
etd->urb = NULL;
|
||||
|
||||
if (!list_empty(&ep->urb_list)) {
|
||||
struct urb *urb = list_first_entry(
|
||||
&ep->urb_list, struct urb, urb_list);
|
||||
|
||||
dev_vdbg(imx21->dev, "next URB %p\n", urb);
|
||||
schedule_nonisoc_etd(imx21, urb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* =========================================== */
|
||||
/* ISOC Handling ... */
|
||||
/* =========================================== */
|
||||
|
|
@ -489,6 +604,8 @@ too_late:
|
|||
etd->ep = td->ep;
|
||||
etd->urb = td->urb;
|
||||
etd->len = td->len;
|
||||
etd->dma_handle = td->dma_handle;
|
||||
etd->cpu_buffer = td->cpu_buffer;
|
||||
|
||||
debug_isoc_submitted(imx21, cur_frame, td);
|
||||
|
||||
|
|
@ -502,16 +619,17 @@ too_late:
|
|||
(TD_NOTACCESSED << DW3_COMPCODE0) |
|
||||
(td->len << DW3_PKTLEN0));
|
||||
|
||||
activate_etd(imx21, etd_num, td->data, dir);
|
||||
activate_etd(imx21, etd_num, dir);
|
||||
}
|
||||
}
|
||||
|
||||
static void isoc_etd_done(struct usb_hcd *hcd, struct urb *urb, int etd_num)
|
||||
static void isoc_etd_done(struct usb_hcd *hcd, int etd_num)
|
||||
{
|
||||
struct imx21 *imx21 = hcd_to_imx21(hcd);
|
||||
int etd_mask = 1 << etd_num;
|
||||
struct urb_priv *urb_priv = urb->hcpriv;
|
||||
struct etd_priv *etd = imx21->etd + etd_num;
|
||||
struct urb *urb = etd->urb;
|
||||
struct urb_priv *urb_priv = urb->hcpriv;
|
||||
struct td *td = etd->td;
|
||||
struct usb_host_endpoint *ep = etd->ep;
|
||||
int isoc_index = td->isoc_index;
|
||||
|
|
@ -545,8 +663,13 @@ static void isoc_etd_done(struct usb_hcd *hcd, struct urb *urb, int etd_num)
|
|||
bytes_xfrd, td->len, urb, etd_num, isoc_index);
|
||||
}
|
||||
|
||||
if (dir_in)
|
||||
if (dir_in) {
|
||||
clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
|
||||
if (!etd->dma_handle)
|
||||
memcpy_fromio(etd->cpu_buffer,
|
||||
imx21->regs + USBOTG_DMEM + etd->dmem_offset,
|
||||
bytes_xfrd);
|
||||
}
|
||||
|
||||
urb->actual_length += bytes_xfrd;
|
||||
urb->iso_frame_desc[isoc_index].actual_length = bytes_xfrd;
|
||||
|
|
@ -569,30 +692,43 @@ static struct ep_priv *alloc_isoc_ep(
|
|||
int i;
|
||||
|
||||
ep_priv = kzalloc(sizeof(struct ep_priv), GFP_ATOMIC);
|
||||
if (ep_priv == NULL)
|
||||
if (!ep_priv)
|
||||
return NULL;
|
||||
|
||||
/* Allocate the ETDs */
|
||||
for (i = 0; i < NUM_ISO_ETDS; i++) {
|
||||
ep_priv->etd[i] = alloc_etd(imx21);
|
||||
if (ep_priv->etd[i] < 0) {
|
||||
int j;
|
||||
dev_err(imx21->dev, "isoc: Couldn't allocate etd\n");
|
||||
for (j = 0; j < i; j++)
|
||||
free_etd(imx21, ep_priv->etd[j]);
|
||||
goto alloc_etd_failed;
|
||||
}
|
||||
imx21->etd[ep_priv->etd[i]].ep = ep;
|
||||
}
|
||||
for (i = 0; i < NUM_ISO_ETDS; i++)
|
||||
ep_priv->etd[i] = -1;
|
||||
|
||||
INIT_LIST_HEAD(&ep_priv->td_list);
|
||||
ep_priv->ep = ep;
|
||||
ep->hcpriv = ep_priv;
|
||||
return ep_priv;
|
||||
}
|
||||
|
||||
static int alloc_isoc_etds(struct imx21 *imx21, struct ep_priv *ep_priv)
|
||||
{
|
||||
int i, j;
|
||||
int etd_num;
|
||||
|
||||
/* Allocate the ETDs if required */
|
||||
for (i = 0; i < NUM_ISO_ETDS; i++) {
|
||||
if (ep_priv->etd[i] < 0) {
|
||||
etd_num = alloc_etd(imx21);
|
||||
if (etd_num < 0)
|
||||
goto alloc_etd_failed;
|
||||
|
||||
ep_priv->etd[i] = etd_num;
|
||||
imx21->etd[etd_num].ep = ep_priv->ep;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
alloc_etd_failed:
|
||||
kfree(ep_priv);
|
||||
return NULL;
|
||||
dev_err(imx21->dev, "isoc: Couldn't allocate etd\n");
|
||||
for (j = 0; j < i; j++) {
|
||||
free_etd(imx21, ep_priv->etd[j]);
|
||||
ep_priv->etd[j] = -1;
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int imx21_hc_urb_enqueue_isoc(struct usb_hcd *hcd,
|
||||
|
|
@ -632,6 +768,10 @@ static int imx21_hc_urb_enqueue_isoc(struct usb_hcd *hcd,
|
|||
ep_priv = ep->hcpriv;
|
||||
}
|
||||
|
||||
ret = alloc_isoc_etds(imx21, ep_priv);
|
||||
if (ret)
|
||||
goto alloc_etd_failed;
|
||||
|
||||
ret = usb_hcd_link_urb_to_ep(hcd, urb);
|
||||
if (ret)
|
||||
goto link_failed;
|
||||
|
|
@ -688,12 +828,14 @@ static int imx21_hc_urb_enqueue_isoc(struct usb_hcd *hcd,
|
|||
/* set up transfers */
|
||||
td = urb_priv->isoc_td;
|
||||
for (i = 0; i < urb->number_of_packets; i++, td++) {
|
||||
unsigned int offset = urb->iso_frame_desc[i].offset;
|
||||
td->ep = ep;
|
||||
td->urb = urb;
|
||||
td->len = urb->iso_frame_desc[i].length;
|
||||
td->isoc_index = i;
|
||||
td->frame = wrap_frame(urb->start_frame + urb->interval * i);
|
||||
td->data = urb->transfer_dma + urb->iso_frame_desc[i].offset;
|
||||
td->dma_handle = urb->transfer_dma + offset;
|
||||
td->cpu_buffer = urb->transfer_buffer + offset;
|
||||
list_add_tail(&td->list, &ep_priv->td_list);
|
||||
}
|
||||
|
||||
|
|
@ -711,6 +853,7 @@ alloc_dmem_failed:
|
|||
usb_hcd_unlink_urb_from_ep(hcd, urb);
|
||||
|
||||
link_failed:
|
||||
alloc_etd_failed:
|
||||
alloc_ep_failed:
|
||||
spin_unlock_irqrestore(&imx21->lock, flags);
|
||||
kfree(urb_priv->isoc_td);
|
||||
|
|
@ -734,9 +877,7 @@ static void dequeue_isoc_urb(struct imx21 *imx21,
|
|||
struct etd_priv *etd = imx21->etd + etd_num;
|
||||
|
||||
reset_etd(imx21, etd_num);
|
||||
if (etd->dmem_size)
|
||||
free_dmem(imx21, etd->dmem_offset);
|
||||
etd->dmem_size = 0;
|
||||
free_dmem(imx21, etd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -761,7 +902,6 @@ static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb)
|
|||
int state = urb_priv->state;
|
||||
int etd_num = ep_priv->etd[0];
|
||||
struct etd_priv *etd;
|
||||
int dmem_offset;
|
||||
u32 count;
|
||||
u16 etd_buf_size;
|
||||
u16 maxpacket;
|
||||
|
|
@ -786,13 +926,15 @@ static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb)
|
|||
if (usb_pipecontrol(pipe) && (state != US_CTRL_DATA)) {
|
||||
if (state == US_CTRL_SETUP) {
|
||||
dir = TD_DIR_SETUP;
|
||||
if (unsuitable_for_dma(urb->setup_dma))
|
||||
unmap_urb_setup_for_dma(imx21->hcd, urb);
|
||||
etd->dma_handle = urb->setup_dma;
|
||||
etd->cpu_buffer = urb->setup_packet;
|
||||
bufround = 0;
|
||||
count = 8;
|
||||
datatoggle = TD_TOGGLE_DATA0;
|
||||
} else { /* US_CTRL_ACK */
|
||||
dir = usb_pipeout(pipe) ? TD_DIR_IN : TD_DIR_OUT;
|
||||
etd->dma_handle = urb->transfer_dma;
|
||||
bufround = 0;
|
||||
count = 0;
|
||||
datatoggle = TD_TOGGLE_DATA1;
|
||||
|
|
@ -800,7 +942,11 @@ static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb)
|
|||
} else {
|
||||
dir = usb_pipeout(pipe) ? TD_DIR_OUT : TD_DIR_IN;
|
||||
bufround = (dir == TD_DIR_IN) ? 1 : 0;
|
||||
if (unsuitable_for_dma(urb->transfer_dma))
|
||||
unmap_urb_for_dma(imx21->hcd, urb);
|
||||
|
||||
etd->dma_handle = urb->transfer_dma;
|
||||
etd->cpu_buffer = urb->transfer_buffer;
|
||||
if (usb_pipebulk(pipe) && (state == US_BULK0))
|
||||
count = 0;
|
||||
else
|
||||
|
|
@ -855,8 +1001,8 @@ static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb)
|
|||
|
||||
/* allocate x and y buffer space at once */
|
||||
etd->dmem_size = (count > maxpacket) ? maxpacket * 2 : maxpacket;
|
||||
dmem_offset = alloc_dmem(imx21, etd->dmem_size, urb_priv->ep);
|
||||
if (dmem_offset < 0) {
|
||||
etd->dmem_offset = alloc_dmem(imx21, etd->dmem_size, urb_priv->ep);
|
||||
if (etd->dmem_offset < 0) {
|
||||
/* Setup everything we can in HW and update when we get DMEM */
|
||||
etd_writel(imx21, etd_num, 1, (u32)maxpacket << 16);
|
||||
|
||||
|
|
@ -867,26 +1013,26 @@ static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb)
|
|||
}
|
||||
|
||||
etd_writel(imx21, etd_num, 1,
|
||||
(((u32) dmem_offset + (u32) maxpacket) << DW1_YBUFSRTAD) |
|
||||
(u32) dmem_offset);
|
||||
(((u32) etd->dmem_offset + (u32) maxpacket) << DW1_YBUFSRTAD) |
|
||||
(u32) etd->dmem_offset);
|
||||
|
||||
urb_priv->active = 1;
|
||||
|
||||
/* enable the ETD to kick off transfer */
|
||||
dev_vdbg(imx21->dev, "Activating etd %d for %d bytes %s\n",
|
||||
etd_num, count, dir != TD_DIR_IN ? "out" : "in");
|
||||
activate_etd(imx21, etd_num, etd->dma_handle, dir);
|
||||
activate_etd(imx21, etd_num, dir);
|
||||
|
||||
}
|
||||
|
||||
static void nonisoc_etd_done(struct usb_hcd *hcd, struct urb *urb, int etd_num)
|
||||
static void nonisoc_etd_done(struct usb_hcd *hcd, int etd_num)
|
||||
{
|
||||
struct imx21 *imx21 = hcd_to_imx21(hcd);
|
||||
struct etd_priv *etd = &imx21->etd[etd_num];
|
||||
struct urb *urb = etd->urb;
|
||||
u32 etd_mask = 1 << etd_num;
|
||||
struct urb_priv *urb_priv = urb->hcpriv;
|
||||
int dir;
|
||||
u16 xbufaddr;
|
||||
int cc;
|
||||
u32 bytes_xfrd;
|
||||
int etd_done;
|
||||
|
|
@ -894,7 +1040,6 @@ static void nonisoc_etd_done(struct usb_hcd *hcd, struct urb *urb, int etd_num)
|
|||
disactivate_etd(imx21, etd_num);
|
||||
|
||||
dir = (etd_readl(imx21, etd_num, 0) >> DW0_DIRECT) & 0x3;
|
||||
xbufaddr = etd_readl(imx21, etd_num, 1) & 0xffff;
|
||||
cc = (etd_readl(imx21, etd_num, 2) >> DW2_COMPCODE) & 0xf;
|
||||
bytes_xfrd = etd->len - (etd_readl(imx21, etd_num, 3) & 0x1fffff);
|
||||
|
||||
|
|
@ -906,8 +1051,21 @@ static void nonisoc_etd_done(struct usb_hcd *hcd, struct urb *urb, int etd_num)
|
|||
if (dir == TD_DIR_IN) {
|
||||
clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
|
||||
clear_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask);
|
||||
|
||||
if (etd->bounce_buffer) {
|
||||
memcpy(etd->cpu_buffer, etd->bounce_buffer, bytes_xfrd);
|
||||
dma_unmap_single(imx21->dev,
|
||||
etd->dma_handle, etd->len, DMA_FROM_DEVICE);
|
||||
} else if (!etd->dma_handle && bytes_xfrd) {/* PIO */
|
||||
memcpy_fromio(etd->cpu_buffer,
|
||||
imx21->regs + USBOTG_DMEM + etd->dmem_offset,
|
||||
bytes_xfrd);
|
||||
}
|
||||
}
|
||||
free_dmem(imx21, xbufaddr);
|
||||
|
||||
kfree(etd->bounce_buffer);
|
||||
etd->bounce_buffer = NULL;
|
||||
free_dmem(imx21, etd);
|
||||
|
||||
urb->error_count = 0;
|
||||
if (!(urb->transfer_flags & URB_SHORT_NOT_OK)
|
||||
|
|
@ -964,24 +1122,15 @@ static void nonisoc_etd_done(struct usb_hcd *hcd, struct urb *urb, int etd_num)
|
|||
break;
|
||||
}
|
||||
|
||||
if (!etd_done) {
|
||||
if (etd_done)
|
||||
nonisoc_urb_completed_for_etd(imx21, etd, cc_to_error[cc]);
|
||||
else {
|
||||
dev_vdbg(imx21->dev, "next state=%d\n", urb_priv->state);
|
||||
schedule_nonisoc_etd(imx21, urb);
|
||||
} else {
|
||||
struct usb_host_endpoint *ep = urb->ep;
|
||||
|
||||
urb_done(hcd, urb, cc_to_error[cc]);
|
||||
etd->urb = NULL;
|
||||
|
||||
if (!list_empty(&ep->urb_list)) {
|
||||
urb = list_first_entry(&ep->urb_list,
|
||||
struct urb, urb_list);
|
||||
dev_vdbg(imx21->dev, "next URB %p\n", urb);
|
||||
schedule_nonisoc_etd(imx21, urb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct ep_priv *alloc_ep(void)
|
||||
{
|
||||
int i;
|
||||
|
|
@ -1007,7 +1156,6 @@ static int imx21_hc_urb_enqueue(struct usb_hcd *hcd,
|
|||
struct etd_priv *etd;
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
int new_ep = 0;
|
||||
|
||||
dev_vdbg(imx21->dev,
|
||||
"enqueue urb=%p ep=%p len=%d "
|
||||
|
|
@ -1035,7 +1183,6 @@ static int imx21_hc_urb_enqueue(struct usb_hcd *hcd,
|
|||
}
|
||||
ep->hcpriv = ep_priv;
|
||||
ep_priv->ep = ep;
|
||||
new_ep = 1;
|
||||
}
|
||||
|
||||
ret = usb_hcd_link_urb_to_ep(hcd, urb);
|
||||
|
|
@ -1124,9 +1271,13 @@ static int imx21_hc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
|
|||
} else if (urb_priv->active) {
|
||||
int etd_num = ep_priv->etd[0];
|
||||
if (etd_num != -1) {
|
||||
struct etd_priv *etd = &imx21->etd[etd_num];
|
||||
|
||||
disactivate_etd(imx21, etd_num);
|
||||
free_dmem(imx21, etd_readl(imx21, etd_num, 1) & 0xffff);
|
||||
imx21->etd[etd_num].urb = NULL;
|
||||
free_dmem(imx21, etd);
|
||||
etd->urb = NULL;
|
||||
kfree(etd->bounce_buffer);
|
||||
etd->bounce_buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1226,9 +1377,9 @@ static void process_etds(struct usb_hcd *hcd, struct imx21 *imx21, int sof)
|
|||
}
|
||||
|
||||
if (usb_pipeisoc(etd->urb->pipe))
|
||||
isoc_etd_done(hcd, etd->urb, etd_num);
|
||||
isoc_etd_done(hcd, etd_num);
|
||||
else
|
||||
nonisoc_etd_done(hcd, etd->urb, etd_num);
|
||||
nonisoc_etd_done(hcd, etd_num);
|
||||
}
|
||||
|
||||
/* only enable SOF interrupt if it may be needed for the kludge */
|
||||
|
|
@ -1696,6 +1847,7 @@ static int imx21_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
imx21 = hcd_to_imx21(hcd);
|
||||
imx21->hcd = hcd;
|
||||
imx21->dev = &pdev->dev;
|
||||
imx21->pdata = pdev->dev.platform_data;
|
||||
if (!imx21->pdata)
|
||||
|
|
@ -1754,7 +1906,7 @@ failed_clock_set:
|
|||
failed_clock_get:
|
||||
iounmap(imx21->regs);
|
||||
failed_ioremap:
|
||||
release_mem_region(res->start, res->end - res->start);
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
failed_request_mem:
|
||||
remove_debug_files(imx21);
|
||||
usb_put_hcd(hcd);
|
||||
|
|
|
|||
|
|
@ -250,6 +250,7 @@
|
|||
#define USBCTRL_USB_BYP (1 << 2)
|
||||
#define USBCTRL_HOST1_TXEN_OE (1 << 1)
|
||||
|
||||
#define USBOTG_DMEM 0x1000
|
||||
|
||||
/* Values in TD blocks */
|
||||
#define TD_DIR_SETUP 0
|
||||
|
|
@ -346,8 +347,8 @@ struct td {
|
|||
struct list_head list;
|
||||
struct urb *urb;
|
||||
struct usb_host_endpoint *ep;
|
||||
dma_addr_t data;
|
||||
unsigned long buf_addr;
|
||||
dma_addr_t dma_handle;
|
||||
void *cpu_buffer;
|
||||
int len;
|
||||
int frame;
|
||||
int isoc_index;
|
||||
|
|
@ -360,6 +361,8 @@ struct etd_priv {
|
|||
struct td *td;
|
||||
struct list_head queue;
|
||||
dma_addr_t dma_handle;
|
||||
void *cpu_buffer;
|
||||
void *bounce_buffer;
|
||||
int alloc;
|
||||
int len;
|
||||
int dmem_size;
|
||||
|
|
@ -412,6 +415,7 @@ struct debug_isoc_trace {
|
|||
struct imx21 {
|
||||
spinlock_t lock;
|
||||
struct device *dev;
|
||||
struct usb_hcd *hcd;
|
||||
struct mx21_usbh_platform_data *pdata;
|
||||
struct list_head dmem_list;
|
||||
struct list_head queue_for_etd; /* eps queued due to etd shortage */
|
||||
|
|
|
|||
|
|
@ -1557,8 +1557,6 @@ static int isp116x_remove(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define resource_len(r) (((r)->end - (r)->start) + 1)
|
||||
|
||||
static int __devinit isp116x_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
|
|
@ -1597,7 +1595,7 @@ static int __devinit isp116x_probe(struct platform_device *pdev)
|
|||
ret = -EBUSY;
|
||||
goto err1;
|
||||
}
|
||||
addr_reg = ioremap(addr->start, resource_len(addr));
|
||||
addr_reg = ioremap(addr->start, resource_size(addr));
|
||||
if (addr_reg == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err2;
|
||||
|
|
@ -1606,7 +1604,7 @@ static int __devinit isp116x_probe(struct platform_device *pdev)
|
|||
ret = -EBUSY;
|
||||
goto err3;
|
||||
}
|
||||
data_reg = ioremap(data->start, resource_len(data));
|
||||
data_reg = ioremap(data->start, resource_size(data));
|
||||
if (data_reg == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto err4;
|
||||
|
|
|
|||
|
|
@ -1676,13 +1676,6 @@ static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
switch (wValue) {
|
||||
case USB_PORT_FEAT_SUSPEND:
|
||||
_DBG(0, "USB_PORT_FEAT_SUSPEND\n");
|
||||
#ifdef CONFIG_USB_OTG
|
||||
if (ohci->hcd.self.otg_port == (wIndex + 1) &&
|
||||
ohci->hcd.self.b_hnp_enable) {
|
||||
start_hnp(ohci);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
spin_lock_irqsave(&isp1362_hcd->lock, flags);
|
||||
isp1362_write_reg32(isp1362_hcd, HCRHPORT1 + wIndex, RH_PS_PSS);
|
||||
isp1362_hcd->rhport[wIndex] =
|
||||
|
|
@ -2656,8 +2649,6 @@ static struct hc_driver isp1362_hc_driver = {
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#define resource_len(r) (((r)->end - (r)->start) + 1)
|
||||
|
||||
static int __devexit isp1362_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
|
|
@ -2679,12 +2670,12 @@ static int __devexit isp1362_remove(struct platform_device *pdev)
|
|||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
DBG(0, "%s: release mem_region: %08lx\n", __func__, (long unsigned int)res->start);
|
||||
if (res)
|
||||
release_mem_region(res->start, resource_len(res));
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
DBG(0, "%s: release mem_region: %08lx\n", __func__, (long unsigned int)res->start);
|
||||
if (res)
|
||||
release_mem_region(res->start, resource_len(res));
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
|
||||
DBG(0, "%s: put_hcd\n", __func__);
|
||||
usb_put_hcd(hcd);
|
||||
|
|
@ -2730,21 +2721,21 @@ static int __init isp1362_probe(struct platform_device *pdev)
|
|||
goto err1;
|
||||
}
|
||||
|
||||
if (!request_mem_region(addr->start, resource_len(addr), hcd_name)) {
|
||||
if (!request_mem_region(addr->start, resource_size(addr), hcd_name)) {
|
||||
retval = -EBUSY;
|
||||
goto err1;
|
||||
}
|
||||
addr_reg = ioremap(addr->start, resource_len(addr));
|
||||
addr_reg = ioremap(addr->start, resource_size(addr));
|
||||
if (addr_reg == NULL) {
|
||||
retval = -ENOMEM;
|
||||
goto err2;
|
||||
}
|
||||
|
||||
if (!request_mem_region(data->start, resource_len(data), hcd_name)) {
|
||||
if (!request_mem_region(data->start, resource_size(data), hcd_name)) {
|
||||
retval = -EBUSY;
|
||||
goto err3;
|
||||
}
|
||||
data_reg = ioremap(data->start, resource_len(data));
|
||||
data_reg = ioremap(data->start, resource_size(data));
|
||||
if (data_reg == NULL) {
|
||||
retval = -ENOMEM;
|
||||
goto err4;
|
||||
|
|
@ -2802,13 +2793,13 @@ static int __init isp1362_probe(struct platform_device *pdev)
|
|||
iounmap(data_reg);
|
||||
err4:
|
||||
DBG(0, "%s: Releasing mem region %08lx\n", __func__, (long unsigned int)data->start);
|
||||
release_mem_region(data->start, resource_len(data));
|
||||
release_mem_region(data->start, resource_size(data));
|
||||
err3:
|
||||
DBG(0, "%s: Unmapping addr_reg @ %p\n", __func__, addr_reg);
|
||||
iounmap(addr_reg);
|
||||
err2:
|
||||
DBG(0, "%s: Releasing mem region %08lx\n", __func__, (long unsigned int)addr->start);
|
||||
release_mem_region(addr->start, resource_len(addr));
|
||||
release_mem_region(addr->start, resource_size(addr));
|
||||
err1:
|
||||
pr_err("%s: init error, %d\n", __func__, retval);
|
||||
|
||||
|
|
|
|||
|
|
@ -398,7 +398,14 @@ ohci_shutdown (struct usb_hcd *hcd)
|
|||
|
||||
ohci = hcd_to_ohci (hcd);
|
||||
ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
|
||||
ohci_usb_reset (ohci);
|
||||
ohci->hc_control = ohci_readl(ohci, &ohci->regs->control);
|
||||
|
||||
/* If the SHUTDOWN quirk is set, don't put the controller in RESET */
|
||||
ohci->hc_control &= (ohci->flags & OHCI_QUIRK_SHUTDOWN ?
|
||||
OHCI_CTRL_RWC | OHCI_CTRL_HCFS :
|
||||
OHCI_CTRL_RWC);
|
||||
ohci_writel(ohci, ohci->hc_control, &ohci->regs->control);
|
||||
|
||||
/* flush the writes */
|
||||
(void) ohci_readl (ohci, &ohci->regs->control);
|
||||
}
|
||||
|
|
@ -1270,6 +1277,9 @@ static void __exit ohci_hcd_mod_exit(void)
|
|||
#ifdef PLATFORM_DRIVER
|
||||
platform_driver_unregister(&PLATFORM_DRIVER);
|
||||
#endif
|
||||
#ifdef OMAP3_PLATFORM_DRIVER
|
||||
platform_driver_unregister(&OMAP3_PLATFORM_DRIVER);
|
||||
#endif
|
||||
#ifdef PS3_SYSTEM_BUS_DRIVER
|
||||
ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -201,6 +201,20 @@ static int ohci_quirk_amd700(struct usb_hcd *hcd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* nVidia controllers continue to drive Reset signalling on the bus
|
||||
* even after system shutdown, wasting power. This flag tells the
|
||||
* shutdown routine to leave the controller OPERATIONAL instead of RESET.
|
||||
*/
|
||||
static int ohci_quirk_nvidia_shutdown(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
|
||||
|
||||
ohci->flags |= OHCI_QUIRK_SHUTDOWN;
|
||||
ohci_dbg(ohci, "enabled nVidia shutdown quirk\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The hardware normally enables the A-link power management feature, which
|
||||
* lets the system lower the power consumption in idle states.
|
||||
|
|
@ -332,6 +346,10 @@ static const struct pci_device_id ohci_pci_quirks[] = {
|
|||
PCI_DEVICE(PCI_VENDOR_ID_ATI, 0x4399),
|
||||
.driver_data = (unsigned long)ohci_quirk_amd700,
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID),
|
||||
.driver_data = (unsigned long) ohci_quirk_nvidia_shutdown,
|
||||
},
|
||||
|
||||
/* FIXME for some of the early AMD 760 southbridges, OHCI
|
||||
* won't work at all. blacklist them.
|
||||
|
|
|
|||
|
|
@ -77,7 +77,6 @@ static const struct hc_driver ohci_sh_hc_driver = {
|
|||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
#define resource_len(r) (((r)->end - (r)->start) + 1)
|
||||
static int ohci_hcd_sh_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res = NULL;
|
||||
|
|
@ -109,7 +108,7 @@ static int ohci_hcd_sh_probe(struct platform_device *pdev)
|
|||
|
||||
hcd->regs = (void __iomem *)res->start;
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = resource_len(res);
|
||||
hcd->rsrc_len = resource_size(res);
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
|
||||
if (ret != 0) {
|
||||
err("Failed to add hcd");
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev)
|
|||
|
||||
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
if (retval)
|
||||
goto err4;
|
||||
goto err5;
|
||||
|
||||
/* enable power and unmask interrupts */
|
||||
|
||||
|
|
@ -176,6 +176,8 @@ static int ohci_hcd_sm501_drv_probe(struct platform_device *pdev)
|
|||
sm501_modify_reg(dev->parent, SM501_IRQ_MASK, 1 << 6, 0);
|
||||
|
||||
return 0;
|
||||
err5:
|
||||
iounmap(hcd->regs);
|
||||
err4:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
err3:
|
||||
|
|
|
|||
|
|
@ -403,6 +403,7 @@ struct ohci_hcd {
|
|||
#define OHCI_QUIRK_HUB_POWER 0x100 /* distrust firmware power/oc setup */
|
||||
#define OHCI_QUIRK_AMD_ISO 0x200 /* ISO transfers*/
|
||||
#define OHCI_QUIRK_AMD_PREFETCH 0x400 /* pre-fetch for ISO transfer */
|
||||
#define OHCI_QUIRK_SHUTDOWN 0x800 /* nVidia power bug */
|
||||
// there are also chip quirks/bugs in init logic
|
||||
|
||||
struct work_struct nec_work; /* Worker for NEC quirk */
|
||||
|
|
|
|||
|
|
@ -3696,7 +3696,7 @@ static void oxu_configuration(struct platform_device *pdev, void *base)
|
|||
static int oxu_verify_id(struct platform_device *pdev, void *base)
|
||||
{
|
||||
u32 id;
|
||||
char *bo[] = {
|
||||
static const char * const bo[] = {
|
||||
"reserved",
|
||||
"128-pin LQFP",
|
||||
"84-pin TFBGA",
|
||||
|
|
|
|||
|
|
@ -169,6 +169,7 @@ static int __devinit mmio_resource_enabled(struct pci_dev *pdev, int idx)
|
|||
static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
|
||||
{
|
||||
void __iomem *base;
|
||||
u32 control;
|
||||
|
||||
if (!mmio_resource_enabled(pdev, 0))
|
||||
return;
|
||||
|
|
@ -177,10 +178,14 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
|
|||
if (base == NULL)
|
||||
return;
|
||||
|
||||
control = readl(base + OHCI_CONTROL);
|
||||
|
||||
/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */
|
||||
#ifndef __hppa__
|
||||
{
|
||||
u32 control = readl(base + OHCI_CONTROL);
|
||||
#ifdef __hppa__
|
||||
#define OHCI_CTRL_MASK (OHCI_CTRL_RWC | OHCI_CTRL_IR)
|
||||
#else
|
||||
#define OHCI_CTRL_MASK OHCI_CTRL_RWC
|
||||
|
||||
if (control & OHCI_CTRL_IR) {
|
||||
int wait_time = 500; /* arbitrary; 5 seconds */
|
||||
writel(OHCI_INTR_OC, base + OHCI_INTRENABLE);
|
||||
|
|
@ -194,13 +199,12 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
|
|||
dev_warn(&pdev->dev, "OHCI: BIOS handoff failed"
|
||||
" (BIOS bug?) %08x\n",
|
||||
readl(base + OHCI_CONTROL));
|
||||
|
||||
/* reset controller, preserving RWC */
|
||||
writel(control & OHCI_CTRL_RWC, base + OHCI_CONTROL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* reset controller, preserving RWC (and possibly IR) */
|
||||
writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
|
||||
|
||||
/*
|
||||
* disable interrupts
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
|
|||
int odd = len & 0x0001;
|
||||
|
||||
len = len / 2;
|
||||
ioread16_rep(fifoaddr, buf, len);
|
||||
iowrite16_rep(fifoaddr, buf, len);
|
||||
if (unlikely(odd)) {
|
||||
buf = &buf[len];
|
||||
iowrite8((unsigned char)*buf, fifoaddr);
|
||||
|
|
|
|||
|
|
@ -917,10 +917,13 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
|
|||
unsigned long destination, status;
|
||||
int maxsze = le16_to_cpu(qh->hep->desc.wMaxPacketSize);
|
||||
int len = urb->transfer_buffer_length;
|
||||
dma_addr_t data = urb->transfer_dma;
|
||||
int this_sg_len;
|
||||
dma_addr_t data;
|
||||
__le32 *plink;
|
||||
struct urb_priv *urbp = urb->hcpriv;
|
||||
unsigned int toggle;
|
||||
struct scatterlist *sg;
|
||||
int i;
|
||||
|
||||
if (len < 0)
|
||||
return -EINVAL;
|
||||
|
|
@ -937,12 +940,26 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
|
|||
if (usb_pipein(urb->pipe))
|
||||
status |= TD_CTRL_SPD;
|
||||
|
||||
i = urb->num_sgs;
|
||||
if (len > 0 && i > 0) {
|
||||
sg = urb->sg;
|
||||
data = sg_dma_address(sg);
|
||||
|
||||
/* urb->transfer_buffer_length may be smaller than the
|
||||
* size of the scatterlist (or vice versa)
|
||||
*/
|
||||
this_sg_len = min_t(int, sg_dma_len(sg), len);
|
||||
} else {
|
||||
sg = NULL;
|
||||
data = urb->transfer_dma;
|
||||
this_sg_len = len;
|
||||
}
|
||||
/*
|
||||
* Build the DATA TDs
|
||||
*/
|
||||
plink = NULL;
|
||||
td = qh->dummy_td;
|
||||
do { /* Allow zero length packets */
|
||||
for (;;) { /* Allow zero length packets */
|
||||
int pktsze = maxsze;
|
||||
|
||||
if (len <= pktsze) { /* The last packet */
|
||||
|
|
@ -965,10 +982,18 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
|
|||
plink = &td->link;
|
||||
status |= TD_CTRL_ACTIVE;
|
||||
|
||||
data += pktsze;
|
||||
len -= maxsze;
|
||||
toggle ^= 1;
|
||||
} while (len > 0);
|
||||
data += pktsze;
|
||||
this_sg_len -= pktsze;
|
||||
len -= maxsze;
|
||||
if (this_sg_len <= 0) {
|
||||
if (--i <= 0 || len <= 0)
|
||||
break;
|
||||
sg = sg_next(sg);
|
||||
data = sg_dma_address(sg);
|
||||
this_sg_len = min_t(int, sg_dma_len(sg), len);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* URB_ZERO_PACKET means adding a 0-length packet, if direction
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ obj-$(CONFIG_USB_WHCI_HCD) += whci-hcd.o
|
|||
whci-hcd-y := \
|
||||
asl.o \
|
||||
debug.o \
|
||||
hcd.o \
|
||||
hcd.o \
|
||||
hw.o \
|
||||
init.o \
|
||||
int.o \
|
||||
|
|
|
|||
|
|
@ -24,6 +24,10 @@
|
|||
|
||||
#include "xhci.h"
|
||||
|
||||
#define PORT_WAKE_BITS (PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E)
|
||||
#define PORT_RWC_BITS (PORT_CSC | PORT_PEC | PORT_WRC | PORT_OCC | \
|
||||
PORT_RC | PORT_PLC | PORT_PE)
|
||||
|
||||
static void xhci_hub_descriptor(struct xhci_hcd *xhci,
|
||||
struct usb_hub_descriptor *desc)
|
||||
{
|
||||
|
|
@ -123,12 +127,105 @@ static unsigned int xhci_port_speed(unsigned int port_status)
|
|||
* writing a 0 clears the bit and writing a 1 sets the bit (RWS).
|
||||
* For all other types (RW1S, RW1CS, RW, and RZ), writing a '0' has no effect.
|
||||
*/
|
||||
static u32 xhci_port_state_to_neutral(u32 state)
|
||||
u32 xhci_port_state_to_neutral(u32 state)
|
||||
{
|
||||
/* Save read-only status and port state */
|
||||
return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
|
||||
}
|
||||
|
||||
/*
|
||||
* find slot id based on port number.
|
||||
*/
|
||||
int xhci_find_slot_id_by_port(struct xhci_hcd *xhci, u16 port)
|
||||
{
|
||||
int slot_id;
|
||||
int i;
|
||||
|
||||
slot_id = 0;
|
||||
for (i = 0; i < MAX_HC_SLOTS; i++) {
|
||||
if (!xhci->devs[i])
|
||||
continue;
|
||||
if (xhci->devs[i]->port == port) {
|
||||
slot_id = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return slot_id;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop device
|
||||
* It issues stop endpoint command for EP 0 to 30. And wait the last command
|
||||
* to complete.
|
||||
* suspend will set to 1, if suspend bit need to set in command.
|
||||
*/
|
||||
static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
|
||||
{
|
||||
struct xhci_virt_device *virt_dev;
|
||||
struct xhci_command *cmd;
|
||||
unsigned long flags;
|
||||
int timeleft;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
ret = 0;
|
||||
virt_dev = xhci->devs[slot_id];
|
||||
cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO);
|
||||
if (!cmd) {
|
||||
xhci_dbg(xhci, "Couldn't allocate command structure.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
for (i = LAST_EP_INDEX; i > 0; i--) {
|
||||
if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue)
|
||||
xhci_queue_stop_endpoint(xhci, slot_id, i, suspend);
|
||||
}
|
||||
cmd->command_trb = xhci->cmd_ring->enqueue;
|
||||
list_add_tail(&cmd->cmd_list, &virt_dev->cmd_list);
|
||||
xhci_queue_stop_endpoint(xhci, slot_id, 0, suspend);
|
||||
xhci_ring_cmd_db(xhci);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
|
||||
/* Wait for last stop endpoint command to finish */
|
||||
timeleft = wait_for_completion_interruptible_timeout(
|
||||
cmd->completion,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
if (timeleft <= 0) {
|
||||
xhci_warn(xhci, "%s while waiting for stop endpoint command\n",
|
||||
timeleft == 0 ? "Timeout" : "Signal");
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
/* The timeout might have raced with the event ring handler, so
|
||||
* only delete from the list if the item isn't poisoned.
|
||||
*/
|
||||
if (cmd->cmd_list.next != LIST_POISON1)
|
||||
list_del(&cmd->cmd_list);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
ret = -ETIME;
|
||||
goto command_cleanup;
|
||||
}
|
||||
|
||||
command_cleanup:
|
||||
xhci_free_command(xhci, cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ring device, it rings the all doorbells unconditionally.
|
||||
*/
|
||||
void xhci_ring_device(struct xhci_hcd *xhci, int slot_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < LAST_EP_INDEX + 1; i++)
|
||||
if (xhci->devs[slot_id]->eps[i].ring &&
|
||||
xhci->devs[slot_id]->eps[i].ring->dequeue)
|
||||
xhci_ring_ep_doorbell(xhci, slot_id, i, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex,
|
||||
u32 __iomem *addr, u32 port_status)
|
||||
{
|
||||
|
|
@ -162,6 +259,10 @@ static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
|
|||
status = PORT_PEC;
|
||||
port_change_bit = "enable/disable";
|
||||
break;
|
||||
case USB_PORT_FEAT_C_SUSPEND:
|
||||
status = PORT_PLC;
|
||||
port_change_bit = "suspend/resume";
|
||||
break;
|
||||
default:
|
||||
/* Should never happen */
|
||||
return;
|
||||
|
|
@ -179,9 +280,10 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int ports;
|
||||
unsigned long flags;
|
||||
u32 temp, status;
|
||||
u32 temp, temp1, status;
|
||||
int retval = 0;
|
||||
u32 __iomem *addr;
|
||||
int slot_id;
|
||||
|
||||
ports = HCS_MAX_PORTS(xhci->hcs_params1);
|
||||
|
||||
|
|
@ -211,9 +313,49 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
if ((temp & PORT_OCC))
|
||||
status |= USB_PORT_STAT_C_OVERCURRENT << 16;
|
||||
/*
|
||||
* FIXME ignoring suspend, reset, and USB 2.1/3.0 specific
|
||||
* FIXME ignoring reset and USB 2.1/3.0 specific
|
||||
* changes
|
||||
*/
|
||||
if ((temp & PORT_PLS_MASK) == XDEV_U3
|
||||
&& (temp & PORT_POWER))
|
||||
status |= 1 << USB_PORT_FEAT_SUSPEND;
|
||||
if ((temp & PORT_PLS_MASK) == XDEV_RESUME) {
|
||||
if ((temp & PORT_RESET) || !(temp & PORT_PE))
|
||||
goto error;
|
||||
if (!DEV_SUPERSPEED(temp) && time_after_eq(jiffies,
|
||||
xhci->resume_done[wIndex])) {
|
||||
xhci_dbg(xhci, "Resume USB2 port %d\n",
|
||||
wIndex + 1);
|
||||
xhci->resume_done[wIndex] = 0;
|
||||
temp1 = xhci_port_state_to_neutral(temp);
|
||||
temp1 &= ~PORT_PLS_MASK;
|
||||
temp1 |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp1, addr);
|
||||
|
||||
xhci_dbg(xhci, "set port %d resume\n",
|
||||
wIndex + 1);
|
||||
slot_id = xhci_find_slot_id_by_port(xhci,
|
||||
wIndex + 1);
|
||||
if (!slot_id) {
|
||||
xhci_dbg(xhci, "slot_id is zero\n");
|
||||
goto error;
|
||||
}
|
||||
xhci_ring_device(xhci, slot_id);
|
||||
xhci->port_c_suspend[wIndex >> 5] |=
|
||||
1 << (wIndex & 31);
|
||||
xhci->suspended_ports[wIndex >> 5] &=
|
||||
~(1 << (wIndex & 31));
|
||||
}
|
||||
}
|
||||
if ((temp & PORT_PLS_MASK) == XDEV_U0
|
||||
&& (temp & PORT_POWER)
|
||||
&& (xhci->suspended_ports[wIndex >> 5] &
|
||||
(1 << (wIndex & 31)))) {
|
||||
xhci->suspended_ports[wIndex >> 5] &=
|
||||
~(1 << (wIndex & 31));
|
||||
xhci->port_c_suspend[wIndex >> 5] |=
|
||||
1 << (wIndex & 31);
|
||||
}
|
||||
if (temp & PORT_CONNECT) {
|
||||
status |= USB_PORT_STAT_CONNECTION;
|
||||
status |= xhci_port_speed(temp);
|
||||
|
|
@ -226,6 +368,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
status |= USB_PORT_STAT_RESET;
|
||||
if (temp & PORT_POWER)
|
||||
status |= USB_PORT_STAT_POWER;
|
||||
if (xhci->port_c_suspend[wIndex >> 5] & (1 << (wIndex & 31)))
|
||||
status |= 1 << USB_PORT_FEAT_C_SUSPEND;
|
||||
xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
|
||||
put_unaligned(cpu_to_le32(status), (__le32 *) buf);
|
||||
break;
|
||||
|
|
@ -238,6 +382,42 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
switch (wValue) {
|
||||
case USB_PORT_FEAT_SUSPEND:
|
||||
temp = xhci_readl(xhci, addr);
|
||||
/* In spec software should not attempt to suspend
|
||||
* a port unless the port reports that it is in the
|
||||
* enabled (PED = ‘1’,PLS < ‘3’) state.
|
||||
*/
|
||||
if ((temp & PORT_PE) == 0 || (temp & PORT_RESET)
|
||||
|| (temp & PORT_PLS_MASK) >= XDEV_U3) {
|
||||
xhci_warn(xhci, "USB core suspending device "
|
||||
"not in U0/U1/U2.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
slot_id = xhci_find_slot_id_by_port(xhci, wIndex + 1);
|
||||
if (!slot_id) {
|
||||
xhci_warn(xhci, "slot_id is zero\n");
|
||||
goto error;
|
||||
}
|
||||
/* unlock to execute stop endpoint commands */
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
xhci_stop_device(xhci, slot_id, 1);
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U3;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
msleep(10); /* wait device to enter */
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
temp = xhci_readl(xhci, addr);
|
||||
xhci->suspended_ports[wIndex >> 5] |=
|
||||
1 << (wIndex & (31));
|
||||
break;
|
||||
case USB_PORT_FEAT_POWER:
|
||||
/*
|
||||
* Turn on ports, even if there isn't per-port switching.
|
||||
|
|
@ -271,6 +451,52 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
switch (wValue) {
|
||||
case USB_PORT_FEAT_SUSPEND:
|
||||
temp = xhci_readl(xhci, addr);
|
||||
xhci_dbg(xhci, "clear USB_PORT_FEAT_SUSPEND\n");
|
||||
xhci_dbg(xhci, "PORTSC %04x\n", temp);
|
||||
if (temp & PORT_RESET)
|
||||
goto error;
|
||||
if (temp & XDEV_U3) {
|
||||
if ((temp & PORT_PE) == 0)
|
||||
goto error;
|
||||
if (DEV_SUPERSPEED(temp)) {
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
xhci_readl(xhci, addr);
|
||||
} else {
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_RESUME;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock,
|
||||
flags);
|
||||
msleep(20);
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
}
|
||||
xhci->port_c_suspend[wIndex >> 5] |=
|
||||
1 << (wIndex & 31);
|
||||
}
|
||||
|
||||
slot_id = xhci_find_slot_id_by_port(xhci, wIndex + 1);
|
||||
if (!slot_id) {
|
||||
xhci_dbg(xhci, "slot_id is zero\n");
|
||||
goto error;
|
||||
}
|
||||
xhci_ring_device(xhci, slot_id);
|
||||
break;
|
||||
case USB_PORT_FEAT_C_SUSPEND:
|
||||
xhci->port_c_suspend[wIndex >> 5] &=
|
||||
~(1 << (wIndex & 31));
|
||||
case USB_PORT_FEAT_C_RESET:
|
||||
case USB_PORT_FEAT_C_CONNECTION:
|
||||
case USB_PORT_FEAT_C_OVER_CURRENT:
|
||||
|
|
@ -306,6 +532,7 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
|
|||
{
|
||||
unsigned long flags;
|
||||
u32 temp, status;
|
||||
u32 mask;
|
||||
int i, retval;
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int ports;
|
||||
|
|
@ -318,13 +545,18 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
|
|||
memset(buf, 0, retval);
|
||||
status = 0;
|
||||
|
||||
mask = PORT_CSC | PORT_PEC | PORT_OCC;
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
/* For each port, did anything change? If so, set that bit in buf. */
|
||||
for (i = 0; i < ports; i++) {
|
||||
addr = &xhci->op_regs->port_status_base +
|
||||
NUM_PORT_REGS*i;
|
||||
temp = xhci_readl(xhci, addr);
|
||||
if (temp & (PORT_CSC | PORT_PEC | PORT_OCC)) {
|
||||
if ((temp & mask) != 0 ||
|
||||
(xhci->port_c_suspend[i >> 5] & 1 << (i & 31)) ||
|
||||
(xhci->resume_done[i] && time_after_eq(
|
||||
jiffies, xhci->resume_done[i]))) {
|
||||
buf[(i + 1) / 8] |= 1 << (i + 1) % 8;
|
||||
status = 1;
|
||||
}
|
||||
|
|
@ -332,3 +564,182 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
|
|||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
return status ? retval : 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
int xhci_bus_suspend(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int port;
|
||||
unsigned long flags;
|
||||
|
||||
xhci_dbg(xhci, "suspend root hub\n");
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
if (hcd->self.root_hub->do_remote_wakeup) {
|
||||
port = HCS_MAX_PORTS(xhci->hcs_params1);
|
||||
while (port--) {
|
||||
if (xhci->resume_done[port] != 0) {
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
xhci_dbg(xhci, "suspend failed because "
|
||||
"port %d is resuming\n",
|
||||
port + 1);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
port = HCS_MAX_PORTS(xhci->hcs_params1);
|
||||
xhci->bus_suspended = 0;
|
||||
while (port--) {
|
||||
/* suspend the port if the port is not suspended */
|
||||
u32 __iomem *addr;
|
||||
u32 t1, t2;
|
||||
int slot_id;
|
||||
|
||||
addr = &xhci->op_regs->port_status_base +
|
||||
NUM_PORT_REGS * (port & 0xff);
|
||||
t1 = xhci_readl(xhci, addr);
|
||||
t2 = xhci_port_state_to_neutral(t1);
|
||||
|
||||
if ((t1 & PORT_PE) && !(t1 & PORT_PLS_MASK)) {
|
||||
xhci_dbg(xhci, "port %d not suspended\n", port);
|
||||
slot_id = xhci_find_slot_id_by_port(xhci, port + 1);
|
||||
if (slot_id) {
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
xhci_stop_device(xhci, slot_id, 1);
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
}
|
||||
t2 &= ~PORT_PLS_MASK;
|
||||
t2 |= PORT_LINK_STROBE | XDEV_U3;
|
||||
set_bit(port, &xhci->bus_suspended);
|
||||
}
|
||||
if (hcd->self.root_hub->do_remote_wakeup) {
|
||||
if (t1 & PORT_CONNECT) {
|
||||
t2 |= PORT_WKOC_E | PORT_WKDISC_E;
|
||||
t2 &= ~PORT_WKCONN_E;
|
||||
} else {
|
||||
t2 |= PORT_WKOC_E | PORT_WKCONN_E;
|
||||
t2 &= ~PORT_WKDISC_E;
|
||||
}
|
||||
} else
|
||||
t2 &= ~PORT_WAKE_BITS;
|
||||
|
||||
t1 = xhci_port_state_to_neutral(t1);
|
||||
if (t1 != t2)
|
||||
xhci_writel(xhci, t2, addr);
|
||||
|
||||
if (DEV_HIGHSPEED(t1)) {
|
||||
/* enable remote wake up for USB 2.0 */
|
||||
u32 __iomem *addr;
|
||||
u32 tmp;
|
||||
|
||||
addr = &xhci->op_regs->port_power_base +
|
||||
NUM_PORT_REGS * (port & 0xff);
|
||||
tmp = xhci_readl(xhci, addr);
|
||||
tmp |= PORT_RWE;
|
||||
xhci_writel(xhci, tmp, addr);
|
||||
}
|
||||
}
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
xhci->next_statechange = jiffies + msecs_to_jiffies(10);
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int xhci_bus_resume(struct usb_hcd *hcd)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int port;
|
||||
u32 temp;
|
||||
unsigned long flags;
|
||||
|
||||
xhci_dbg(xhci, "resume root hub\n");
|
||||
|
||||
if (time_before(jiffies, xhci->next_statechange))
|
||||
msleep(5);
|
||||
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
if (!HCD_HW_ACCESSIBLE(hcd)) {
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
return -ESHUTDOWN;
|
||||
}
|
||||
|
||||
/* delay the irqs */
|
||||
temp = xhci_readl(xhci, &xhci->op_regs->command);
|
||||
temp &= ~CMD_EIE;
|
||||
xhci_writel(xhci, temp, &xhci->op_regs->command);
|
||||
|
||||
port = HCS_MAX_PORTS(xhci->hcs_params1);
|
||||
while (port--) {
|
||||
/* Check whether need resume ports. If needed
|
||||
resume port and disable remote wakeup */
|
||||
u32 __iomem *addr;
|
||||
u32 temp;
|
||||
int slot_id;
|
||||
|
||||
addr = &xhci->op_regs->port_status_base +
|
||||
NUM_PORT_REGS * (port & 0xff);
|
||||
temp = xhci_readl(xhci, addr);
|
||||
if (DEV_SUPERSPEED(temp))
|
||||
temp &= ~(PORT_RWC_BITS | PORT_CEC | PORT_WAKE_BITS);
|
||||
else
|
||||
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
|
||||
if (test_bit(port, &xhci->bus_suspended) &&
|
||||
(temp & PORT_PLS_MASK)) {
|
||||
if (DEV_SUPERSPEED(temp)) {
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
} else {
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_RESUME;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
msleep(20);
|
||||
spin_lock_irqsave(&xhci->lock, flags);
|
||||
|
||||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
}
|
||||
slot_id = xhci_find_slot_id_by_port(xhci, port + 1);
|
||||
if (slot_id)
|
||||
xhci_ring_device(xhci, slot_id);
|
||||
} else
|
||||
xhci_writel(xhci, temp, addr);
|
||||
|
||||
if (DEV_HIGHSPEED(temp)) {
|
||||
/* disable remote wake up for USB 2.0 */
|
||||
u32 __iomem *addr;
|
||||
u32 tmp;
|
||||
|
||||
addr = &xhci->op_regs->port_power_base +
|
||||
NUM_PORT_REGS * (port & 0xff);
|
||||
tmp = xhci_readl(xhci, addr);
|
||||
tmp &= ~PORT_RWE;
|
||||
xhci_writel(xhci, tmp, addr);
|
||||
}
|
||||
}
|
||||
|
||||
(void) xhci_readl(xhci, &xhci->op_regs->command);
|
||||
|
||||
xhci->next_statechange = jiffies + msecs_to_jiffies(5);
|
||||
hcd->state = HC_STATE_RUNNING;
|
||||
/* re-enable irqs */
|
||||
temp = xhci_readl(xhci, &xhci->op_regs->command);
|
||||
temp |= CMD_EIE;
|
||||
xhci_writel(xhci, temp, &xhci->op_regs->command);
|
||||
temp = xhci_readl(xhci, &xhci->op_regs->command);
|
||||
|
||||
spin_unlock_irqrestore(&xhci->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
|
|
|||
|
|
@ -778,6 +778,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
|
|||
|
||||
init_completion(&dev->cmd_completion);
|
||||
INIT_LIST_HEAD(&dev->cmd_list);
|
||||
dev->udev = udev;
|
||||
|
||||
/* Point to output device context in dcbaa. */
|
||||
xhci->dcbaa->dev_context_ptrs[slot_id] = dev->out_ctx->dma;
|
||||
|
|
@ -866,6 +867,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
|
|||
top_dev = top_dev->parent)
|
||||
/* Found device below root hub */;
|
||||
slot_ctx->dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum);
|
||||
dev->port = top_dev->portnum;
|
||||
xhci_dbg(xhci, "Set root hub portnum to %d\n", top_dev->portnum);
|
||||
|
||||
/* Is this a LS/FS device under a HS hub? */
|
||||
|
|
@ -1443,6 +1445,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
|
|||
scratchpad_free(xhci);
|
||||
xhci->page_size = 0;
|
||||
xhci->page_shift = 0;
|
||||
xhci->bus_suspended = 0;
|
||||
}
|
||||
|
||||
static int xhci_test_trb_in_td(struct xhci_hcd *xhci,
|
||||
|
|
@ -1801,6 +1804,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
|||
init_completion(&xhci->addr_dev);
|
||||
for (i = 0; i < MAX_HC_SLOTS; ++i)
|
||||
xhci->devs[i] = NULL;
|
||||
for (i = 0; i < MAX_HC_PORTS; ++i)
|
||||
xhci->resume_done[i] = 0;
|
||||
|
||||
if (scratchpad_alloc(xhci, flags))
|
||||
goto fail;
|
||||
|
|
|
|||
|
|
@ -116,6 +116,30 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
|
|||
return xhci_pci_reinit(xhci, pdev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int retval = 0;
|
||||
|
||||
if (hcd->state != HC_STATE_SUSPENDED)
|
||||
return -EINVAL;
|
||||
|
||||
retval = xhci_suspend(xhci);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
|
||||
{
|
||||
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
|
||||
int retval = 0;
|
||||
|
||||
retval = xhci_resume(xhci, hibernated);
|
||||
return retval;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static const struct hc_driver xhci_pci_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "xHCI Host Controller",
|
||||
|
|
@ -132,7 +156,10 @@ static const struct hc_driver xhci_pci_hc_driver = {
|
|||
*/
|
||||
.reset = xhci_pci_setup,
|
||||
.start = xhci_run,
|
||||
/* suspend and resume implemented later */
|
||||
#ifdef CONFIG_PM
|
||||
.pci_suspend = xhci_pci_suspend,
|
||||
.pci_resume = xhci_pci_resume,
|
||||
#endif
|
||||
.stop = xhci_stop,
|
||||
.shutdown = xhci_shutdown,
|
||||
|
||||
|
|
@ -152,7 +179,7 @@ static const struct hc_driver xhci_pci_hc_driver = {
|
|||
.reset_bandwidth = xhci_reset_bandwidth,
|
||||
.address_device = xhci_address_device,
|
||||
.update_hub_device = xhci_update_hub_device,
|
||||
.reset_device = xhci_reset_device,
|
||||
.reset_device = xhci_discover_or_reset_device,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
|
|
@ -162,6 +189,8 @@ static const struct hc_driver xhci_pci_hc_driver = {
|
|||
/* Root hub support */
|
||||
.hub_control = xhci_hub_control,
|
||||
.hub_status_data = xhci_hub_status_data,
|
||||
.bus_suspend = xhci_bus_suspend,
|
||||
.bus_resume = xhci_bus_resume,
|
||||
};
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
|
@ -186,6 +215,11 @@ static struct pci_driver xhci_pci_driver = {
|
|||
/* suspend and resume implemented later */
|
||||
|
||||
.shutdown = usb_hcd_pci_shutdown,
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
.driver = {
|
||||
.pm = &usb_hcd_pci_pm_ops
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
int xhci_register_pci(void)
|
||||
|
|
|
|||
|
|
@ -68,6 +68,10 @@
|
|||
#include <linux/slab.h>
|
||||
#include "xhci.h"
|
||||
|
||||
static int handle_cmd_in_cmd_wait_list(struct xhci_hcd *xhci,
|
||||
struct xhci_virt_device *virt_dev,
|
||||
struct xhci_event_cmd *event);
|
||||
|
||||
/*
|
||||
* Returns zero if the TRB isn't in this segment, otherwise it returns the DMA
|
||||
* address of the TRB.
|
||||
|
|
@ -313,7 +317,7 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci)
|
|||
xhci_readl(xhci, &xhci->dba->doorbell[0]);
|
||||
}
|
||||
|
||||
static void ring_ep_doorbell(struct xhci_hcd *xhci,
|
||||
void xhci_ring_ep_doorbell(struct xhci_hcd *xhci,
|
||||
unsigned int slot_id,
|
||||
unsigned int ep_index,
|
||||
unsigned int stream_id)
|
||||
|
|
@ -353,7 +357,7 @@ static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
|
|||
/* A ring has pending URBs if its TD list is not empty */
|
||||
if (!(ep->ep_state & EP_HAS_STREAMS)) {
|
||||
if (!(list_empty(&ep->ring->td_list)))
|
||||
ring_ep_doorbell(xhci, slot_id, ep_index, 0);
|
||||
xhci_ring_ep_doorbell(xhci, slot_id, ep_index, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -361,7 +365,8 @@ static void ring_doorbell_for_active_rings(struct xhci_hcd *xhci,
|
|||
stream_id++) {
|
||||
struct xhci_stream_info *stream_info = ep->stream_info;
|
||||
if (!list_empty(&stream_info->stream_rings[stream_id]->td_list))
|
||||
ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
|
||||
xhci_ring_ep_doorbell(xhci, slot_id, ep_index,
|
||||
stream_id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -626,10 +631,11 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci,
|
|||
* bit cleared) so that the HW will skip over them.
|
||||
*/
|
||||
static void handle_stopped_endpoint(struct xhci_hcd *xhci,
|
||||
union xhci_trb *trb)
|
||||
union xhci_trb *trb, struct xhci_event_cmd *event)
|
||||
{
|
||||
unsigned int slot_id;
|
||||
unsigned int ep_index;
|
||||
struct xhci_virt_device *virt_dev;
|
||||
struct xhci_ring *ep_ring;
|
||||
struct xhci_virt_ep *ep;
|
||||
struct list_head *entry;
|
||||
|
|
@ -638,6 +644,21 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
|
|||
|
||||
struct xhci_dequeue_state deq_state;
|
||||
|
||||
if (unlikely(TRB_TO_SUSPEND_PORT(
|
||||
xhci->cmd_ring->dequeue->generic.field[3]))) {
|
||||
slot_id = TRB_TO_SLOT_ID(
|
||||
xhci->cmd_ring->dequeue->generic.field[3]);
|
||||
virt_dev = xhci->devs[slot_id];
|
||||
if (virt_dev)
|
||||
handle_cmd_in_cmd_wait_list(xhci, virt_dev,
|
||||
event);
|
||||
else
|
||||
xhci_warn(xhci, "Stop endpoint command "
|
||||
"completion for disabled slot %u\n",
|
||||
slot_id);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&deq_state, 0, sizeof(deq_state));
|
||||
slot_id = TRB_TO_SLOT_ID(trb->generic.field[3]);
|
||||
ep_index = TRB_TO_EP_INDEX(trb->generic.field[3]);
|
||||
|
|
@ -1091,7 +1112,7 @@ bandwidth_change:
|
|||
complete(&xhci->addr_dev);
|
||||
break;
|
||||
case TRB_TYPE(TRB_STOP_RING):
|
||||
handle_stopped_endpoint(xhci, xhci->cmd_ring->dequeue);
|
||||
handle_stopped_endpoint(xhci, xhci->cmd_ring->dequeue, event);
|
||||
break;
|
||||
case TRB_TYPE(TRB_SET_DEQ):
|
||||
handle_set_deq_completion(xhci, event, xhci->cmd_ring->dequeue);
|
||||
|
|
@ -1144,17 +1165,72 @@ static void handle_vendor_event(struct xhci_hcd *xhci,
|
|||
static void handle_port_status(struct xhci_hcd *xhci,
|
||||
union xhci_trb *event)
|
||||
{
|
||||
struct usb_hcd *hcd = xhci_to_hcd(xhci);
|
||||
u32 port_id;
|
||||
u32 temp, temp1;
|
||||
u32 __iomem *addr;
|
||||
int ports;
|
||||
int slot_id;
|
||||
|
||||
/* Port status change events always have a successful completion code */
|
||||
if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) {
|
||||
xhci_warn(xhci, "WARN: xHC returned failed port status event\n");
|
||||
xhci->error_bitmask |= 1 << 8;
|
||||
}
|
||||
/* FIXME: core doesn't care about all port link state changes yet */
|
||||
port_id = GET_PORT_ID(event->generic.field[0]);
|
||||
xhci_dbg(xhci, "Port Status Change Event for port %d\n", port_id);
|
||||
|
||||
ports = HCS_MAX_PORTS(xhci->hcs_params1);
|
||||
if ((port_id <= 0) || (port_id > ports)) {
|
||||
xhci_warn(xhci, "Invalid port id %d\n", port_id);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS * (port_id - 1);
|
||||
temp = xhci_readl(xhci, addr);
|
||||
if ((temp & PORT_CONNECT) && (hcd->state == HC_STATE_SUSPENDED)) {
|
||||
xhci_dbg(xhci, "resume root hub\n");
|
||||
usb_hcd_resume_root_hub(hcd);
|
||||
}
|
||||
|
||||
if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_RESUME) {
|
||||
xhci_dbg(xhci, "port resume event for port %d\n", port_id);
|
||||
|
||||
temp1 = xhci_readl(xhci, &xhci->op_regs->command);
|
||||
if (!(temp1 & CMD_RUN)) {
|
||||
xhci_warn(xhci, "xHC is not running.\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (DEV_SUPERSPEED(temp)) {
|
||||
xhci_dbg(xhci, "resume SS port %d\n", port_id);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp &= ~PORT_PLS_MASK;
|
||||
temp |= PORT_LINK_STROBE | XDEV_U0;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
slot_id = xhci_find_slot_id_by_port(xhci, port_id);
|
||||
if (!slot_id) {
|
||||
xhci_dbg(xhci, "slot_id is zero\n");
|
||||
goto cleanup;
|
||||
}
|
||||
xhci_ring_device(xhci, slot_id);
|
||||
xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
|
||||
/* Clear PORT_PLC */
|
||||
temp = xhci_readl(xhci, addr);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
temp |= PORT_PLC;
|
||||
xhci_writel(xhci, temp, addr);
|
||||
} else {
|
||||
xhci_dbg(xhci, "resume HS port %d\n", port_id);
|
||||
xhci->resume_done[port_id - 1] = jiffies +
|
||||
msecs_to_jiffies(20);
|
||||
mod_timer(&hcd->rh_timer,
|
||||
xhci->resume_done[port_id - 1]);
|
||||
/* Do the rest in GetPortStatus */
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
/* Update event ring dequeue pointer before dropping the lock */
|
||||
inc_deq(xhci, xhci->event_ring, true);
|
||||
|
||||
|
|
@ -2347,7 +2423,7 @@ static void giveback_first_trb(struct xhci_hcd *xhci, int slot_id,
|
|||
*/
|
||||
wmb();
|
||||
start_trb->field[3] |= start_cycle;
|
||||
ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
|
||||
xhci_ring_ep_doorbell(xhci, slot_id, ep_index, stream_id);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2931,7 +3007,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
|
|||
wmb();
|
||||
start_trb->field[3] |= start_cycle;
|
||||
|
||||
ring_ep_doorbell(xhci, slot_id, ep_index, urb->stream_id);
|
||||
xhci_ring_ep_doorbell(xhci, slot_id, ep_index, urb->stream_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -3108,15 +3184,20 @@ int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
|
|||
false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Suspend is set to indicate "Stop Endpoint Command" is being issued to stop
|
||||
* activity on an endpoint that is about to be suspended.
|
||||
*/
|
||||
int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id,
|
||||
unsigned int ep_index)
|
||||
unsigned int ep_index, int suspend)
|
||||
{
|
||||
u32 trb_slot_id = SLOT_ID_FOR_TRB(slot_id);
|
||||
u32 trb_ep_index = EP_ID_FOR_TRB(ep_index);
|
||||
u32 type = TRB_TYPE(TRB_STOP_RING);
|
||||
u32 trb_suspend = SUSPEND_PORT_FOR_TRB(suspend);
|
||||
|
||||
return queue_command(xhci, 0, 0, 0,
|
||||
trb_slot_id | trb_ep_index | type, false);
|
||||
trb_slot_id | trb_ep_index | type | trb_suspend, false);
|
||||
}
|
||||
|
||||
/* Set Transfer Ring Dequeue Pointer command.
|
||||
|
|
|
|||
|
|
@ -551,6 +551,218 @@ void xhci_shutdown(struct usb_hcd *hcd)
|
|||
xhci_readl(xhci, &xhci->op_regs->status));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static void xhci_save_registers(struct xhci_hcd *xhci)
|
||||
{
|
||||
xhci->s3.command = xhci_readl(xhci, &xhci->op_regs->command);
|
||||
xhci->s3.dev_nt = xhci_readl(xhci, &xhci->op_regs->dev_notification);
|
||||
xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
|
||||
xhci->s3.config_reg = xhci_readl(xhci, &xhci->op_regs->config_reg);
|
||||
xhci->s3.irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
|
||||
xhci->s3.irq_control = xhci_readl(xhci, &xhci->ir_set->irq_control);
|
||||
xhci->s3.erst_size = xhci_readl(xhci, &xhci->ir_set->erst_size);
|
||||
xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base);
|
||||
xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
|
||||
}
|
||||
|
||||
static void xhci_restore_registers(struct xhci_hcd *xhci)
|
||||
{
|
||||
xhci_writel(xhci, xhci->s3.command, &xhci->op_regs->command);
|
||||
xhci_writel(xhci, xhci->s3.dev_nt, &xhci->op_regs->dev_notification);
|
||||
xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr);
|
||||
xhci_writel(xhci, xhci->s3.config_reg, &xhci->op_regs->config_reg);
|
||||
xhci_writel(xhci, xhci->s3.irq_pending, &xhci->ir_set->irq_pending);
|
||||
xhci_writel(xhci, xhci->s3.irq_control, &xhci->ir_set->irq_control);
|
||||
xhci_writel(xhci, xhci->s3.erst_size, &xhci->ir_set->erst_size);
|
||||
xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);
|
||||
}
|
||||
|
||||
/*
|
||||
* Stop HC (not bus-specific)
|
||||
*
|
||||
* This is called when the machine transition into S3/S4 mode.
|
||||
*
|
||||
*/
|
||||
int xhci_suspend(struct xhci_hcd *xhci)
|
||||
{
|
||||
int rc = 0;
|
||||
struct usb_hcd *hcd = xhci_to_hcd(xhci);
|
||||
u32 command;
|
||||
|
||||
spin_lock_irq(&xhci->lock);
|
||||
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
/* step 1: stop endpoint */
|
||||
/* skipped assuming that port suspend has done */
|
||||
|
||||
/* step 2: clear Run/Stop bit */
|
||||
command = xhci_readl(xhci, &xhci->op_regs->command);
|
||||
command &= ~CMD_RUN;
|
||||
xhci_writel(xhci, command, &xhci->op_regs->command);
|
||||
if (handshake(xhci, &xhci->op_regs->status,
|
||||
STS_HALT, STS_HALT, 100*100)) {
|
||||
xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n");
|
||||
spin_unlock_irq(&xhci->lock);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
/* step 3: save registers */
|
||||
xhci_save_registers(xhci);
|
||||
|
||||
/* step 4: set CSS flag */
|
||||
command = xhci_readl(xhci, &xhci->op_regs->command);
|
||||
command |= CMD_CSS;
|
||||
xhci_writel(xhci, command, &xhci->op_regs->command);
|
||||
if (handshake(xhci, &xhci->op_regs->status, STS_SAVE, 0, 10*100)) {
|
||||
xhci_warn(xhci, "WARN: xHC CMD_CSS timeout\n");
|
||||
spin_unlock_irq(&xhci->lock);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
/* step 5: remove core well power */
|
||||
xhci_cleanup_msix(xhci);
|
||||
spin_unlock_irq(&xhci->lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* start xHC (not bus-specific)
|
||||
*
|
||||
* This is called when the machine transition from S3/S4 mode.
|
||||
*
|
||||
*/
|
||||
int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
|
||||
{
|
||||
u32 command, temp = 0;
|
||||
struct usb_hcd *hcd = xhci_to_hcd(xhci);
|
||||
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
|
||||
u64 val_64;
|
||||
int old_state, retval;
|
||||
|
||||
old_state = hcd->state;
|
||||
if (time_before(jiffies, xhci->next_statechange))
|
||||
msleep(100);
|
||||
|
||||
spin_lock_irq(&xhci->lock);
|
||||
|
||||
if (!hibernated) {
|
||||
/* step 1: restore register */
|
||||
xhci_restore_registers(xhci);
|
||||
/* step 2: initialize command ring buffer */
|
||||
val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring);
|
||||
val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) |
|
||||
(xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg,
|
||||
xhci->cmd_ring->dequeue) &
|
||||
(u64) ~CMD_RING_RSVD_BITS) |
|
||||
xhci->cmd_ring->cycle_state;
|
||||
xhci_dbg(xhci, "// Setting command ring address to 0x%llx\n",
|
||||
(long unsigned long) val_64);
|
||||
xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring);
|
||||
/* step 3: restore state and start state*/
|
||||
/* step 3: set CRS flag */
|
||||
command = xhci_readl(xhci, &xhci->op_regs->command);
|
||||
command |= CMD_CRS;
|
||||
xhci_writel(xhci, command, &xhci->op_regs->command);
|
||||
if (handshake(xhci, &xhci->op_regs->status,
|
||||
STS_RESTORE, 0, 10*100)) {
|
||||
xhci_dbg(xhci, "WARN: xHC CMD_CSS timeout\n");
|
||||
spin_unlock_irq(&xhci->lock);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
temp = xhci_readl(xhci, &xhci->op_regs->status);
|
||||
}
|
||||
|
||||
/* If restore operation fails, re-initialize the HC during resume */
|
||||
if ((temp & STS_SRE) || hibernated) {
|
||||
usb_root_hub_lost_power(hcd->self.root_hub);
|
||||
|
||||
xhci_dbg(xhci, "Stop HCD\n");
|
||||
xhci_halt(xhci);
|
||||
xhci_reset(xhci);
|
||||
if (hibernated)
|
||||
xhci_cleanup_msix(xhci);
|
||||
spin_unlock_irq(&xhci->lock);
|
||||
|
||||
#ifdef CONFIG_USB_XHCI_HCD_DEBUGGING
|
||||
/* Tell the event ring poll function not to reschedule */
|
||||
xhci->zombie = 1;
|
||||
del_timer_sync(&xhci->event_ring_timer);
|
||||
#endif
|
||||
|
||||
xhci_dbg(xhci, "// Disabling event ring interrupts\n");
|
||||
temp = xhci_readl(xhci, &xhci->op_regs->status);
|
||||
xhci_writel(xhci, temp & ~STS_EINT, &xhci->op_regs->status);
|
||||
temp = xhci_readl(xhci, &xhci->ir_set->irq_pending);
|
||||
xhci_writel(xhci, ER_IRQ_DISABLE(temp),
|
||||
&xhci->ir_set->irq_pending);
|
||||
xhci_print_ir_set(xhci, xhci->ir_set, 0);
|
||||
|
||||
xhci_dbg(xhci, "cleaning up memory\n");
|
||||
xhci_mem_cleanup(xhci);
|
||||
xhci_dbg(xhci, "xhci_stop completed - status = %x\n",
|
||||
xhci_readl(xhci, &xhci->op_regs->status));
|
||||
|
||||
xhci_dbg(xhci, "Initialize the HCD\n");
|
||||
retval = xhci_init(hcd);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
xhci_dbg(xhci, "Start the HCD\n");
|
||||
retval = xhci_run(hcd);
|
||||
if (!retval)
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Re-setup MSI-X */
|
||||
if (hcd->irq)
|
||||
free_irq(hcd->irq, hcd);
|
||||
hcd->irq = -1;
|
||||
|
||||
retval = xhci_setup_msix(xhci);
|
||||
if (retval)
|
||||
/* fall back to msi*/
|
||||
retval = xhci_setup_msi(xhci);
|
||||
|
||||
if (retval) {
|
||||
/* fall back to legacy interrupt*/
|
||||
retval = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED,
|
||||
hcd->irq_descr, hcd);
|
||||
if (retval) {
|
||||
xhci_err(xhci, "request interrupt %d failed\n",
|
||||
pdev->irq);
|
||||
return retval;
|
||||
}
|
||||
hcd->irq = pdev->irq;
|
||||
}
|
||||
|
||||
/* step 4: set Run/Stop bit */
|
||||
command = xhci_readl(xhci, &xhci->op_regs->command);
|
||||
command |= CMD_RUN;
|
||||
xhci_writel(xhci, command, &xhci->op_regs->command);
|
||||
handshake(xhci, &xhci->op_regs->status, STS_HALT,
|
||||
0, 250 * 1000);
|
||||
|
||||
/* step 5: walk topology and initialize portsc,
|
||||
* portpmsc and portli
|
||||
*/
|
||||
/* this is done in bus_resume */
|
||||
|
||||
/* step 6: restart each of the previously
|
||||
* Running endpoints by ringing their doorbells
|
||||
*/
|
||||
|
||||
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
|
||||
if (!hibernated)
|
||||
hcd->state = old_state;
|
||||
else
|
||||
hcd->state = HC_STATE_SUSPENDED;
|
||||
|
||||
spin_unlock_irq(&xhci->lock);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
|
|
@ -607,7 +819,11 @@ unsigned int xhci_last_valid_endpoint(u32 added_ctxs)
|
|||
* returns 0 this is a root hub; returns -EINVAL for NULL pointers.
|
||||
*/
|
||||
int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
|
||||
struct usb_host_endpoint *ep, int check_ep, const char *func) {
|
||||
struct usb_host_endpoint *ep, int check_ep, bool check_virt_dev,
|
||||
const char *func) {
|
||||
struct xhci_hcd *xhci;
|
||||
struct xhci_virt_device *virt_dev;
|
||||
|
||||
if (!hcd || (check_ep && !ep) || !udev) {
|
||||
printk(KERN_DEBUG "xHCI %s called with invalid args\n",
|
||||
func);
|
||||
|
|
@ -618,11 +834,24 @@ int xhci_check_args(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
func);
|
||||
return 0;
|
||||
}
|
||||
if (!udev->slot_id) {
|
||||
printk(KERN_DEBUG "xHCI %s called with unaddressed device\n",
|
||||
func);
|
||||
return -EINVAL;
|
||||
|
||||
if (check_virt_dev) {
|
||||
xhci = hcd_to_xhci(hcd);
|
||||
if (!udev->slot_id || !xhci->devs
|
||||
|| !xhci->devs[udev->slot_id]) {
|
||||
printk(KERN_DEBUG "xHCI %s called with unaddressed "
|
||||
"device\n", func);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
virt_dev = xhci->devs[udev->slot_id];
|
||||
if (virt_dev->udev != udev) {
|
||||
printk(KERN_DEBUG "xHCI %s called with udev and "
|
||||
"virt_dev does not match\n", func);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -704,18 +933,13 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
|
|||
struct urb_priv *urb_priv;
|
||||
int size, i;
|
||||
|
||||
if (!urb || xhci_check_args(hcd, urb->dev, urb->ep, true, __func__) <= 0)
|
||||
if (!urb || xhci_check_args(hcd, urb->dev, urb->ep,
|
||||
true, true, __func__) <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
slot_id = urb->dev->slot_id;
|
||||
ep_index = xhci_get_endpoint_index(&urb->ep->desc);
|
||||
|
||||
if (!xhci->devs || !xhci->devs[slot_id]) {
|
||||
if (!in_interrupt())
|
||||
dev_warn(&urb->dev->dev, "WARN: urb submitted for dev with no Slot ID\n");
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
if (!HCD_HW_ACCESSIBLE(hcd)) {
|
||||
if (!in_interrupt())
|
||||
xhci_dbg(xhci, "urb submitted during PCI suspend\n");
|
||||
|
|
@ -956,7 +1180,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
|
|||
ep->stop_cmd_timer.expires = jiffies +
|
||||
XHCI_STOP_EP_CMD_TIMEOUT * HZ;
|
||||
add_timer(&ep->stop_cmd_timer);
|
||||
xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index);
|
||||
xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index, 0);
|
||||
xhci_ring_cmd_db(xhci);
|
||||
}
|
||||
done:
|
||||
|
|
@ -991,7 +1215,7 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
u32 new_add_flags, new_drop_flags, new_slot_info;
|
||||
int ret;
|
||||
|
||||
ret = xhci_check_args(hcd, udev, ep, 1, __func__);
|
||||
ret = xhci_check_args(hcd, udev, ep, 1, true, __func__);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
xhci = hcd_to_xhci(hcd);
|
||||
|
|
@ -1004,12 +1228,6 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!xhci->devs || !xhci->devs[udev->slot_id]) {
|
||||
xhci_warn(xhci, "xHCI %s called with unaddressed device\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
in_ctx = xhci->devs[udev->slot_id]->in_ctx;
|
||||
out_ctx = xhci->devs[udev->slot_id]->out_ctx;
|
||||
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
|
||||
|
|
@ -1078,7 +1296,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
u32 new_add_flags, new_drop_flags, new_slot_info;
|
||||
int ret = 0;
|
||||
|
||||
ret = xhci_check_args(hcd, udev, ep, 1, __func__);
|
||||
ret = xhci_check_args(hcd, udev, ep, 1, true, __func__);
|
||||
if (ret <= 0) {
|
||||
/* So we won't queue a reset ep command for a root hub */
|
||||
ep->hcpriv = NULL;
|
||||
|
|
@ -1098,12 +1316,6 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (!xhci->devs || !xhci->devs[udev->slot_id]) {
|
||||
xhci_warn(xhci, "xHCI %s called with unaddressed device\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
in_ctx = xhci->devs[udev->slot_id]->in_ctx;
|
||||
out_ctx = xhci->devs[udev->slot_id]->out_ctx;
|
||||
ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
|
||||
|
|
@ -1346,16 +1558,11 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
struct xhci_input_control_ctx *ctrl_ctx;
|
||||
struct xhci_slot_ctx *slot_ctx;
|
||||
|
||||
ret = xhci_check_args(hcd, udev, NULL, 0, __func__);
|
||||
ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
xhci = hcd_to_xhci(hcd);
|
||||
|
||||
if (!udev->slot_id || !xhci->devs || !xhci->devs[udev->slot_id]) {
|
||||
xhci_warn(xhci, "xHCI %s called with unaddressed device\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
|
||||
virt_dev = xhci->devs[udev->slot_id];
|
||||
|
||||
|
|
@ -1405,16 +1612,11 @@ void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
struct xhci_virt_device *virt_dev;
|
||||
int i, ret;
|
||||
|
||||
ret = xhci_check_args(hcd, udev, NULL, 0, __func__);
|
||||
ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__);
|
||||
if (ret <= 0)
|
||||
return;
|
||||
xhci = hcd_to_xhci(hcd);
|
||||
|
||||
if (!xhci->devs || !xhci->devs[udev->slot_id]) {
|
||||
xhci_warn(xhci, "xHCI %s called with unaddressed device\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
xhci_dbg(xhci, "%s called for udev %p\n", __func__, udev);
|
||||
virt_dev = xhci->devs[udev->slot_id];
|
||||
/* Free any rings allocated for added endpoints */
|
||||
|
|
@ -1575,7 +1777,7 @@ static int xhci_check_streams_endpoint(struct xhci_hcd *xhci,
|
|||
|
||||
if (!ep)
|
||||
return -EINVAL;
|
||||
ret = xhci_check_args(xhci_to_hcd(xhci), udev, ep, 1, __func__);
|
||||
ret = xhci_check_args(xhci_to_hcd(xhci), udev, ep, 1, true, __func__);
|
||||
if (ret <= 0)
|
||||
return -EINVAL;
|
||||
if (ep->ss_ep_comp.bmAttributes == 0) {
|
||||
|
|
@ -1953,8 +2155,13 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
|
|||
* Wait for the Reset Device command to finish. Remove all structures
|
||||
* associated with the endpoints that were disabled. Clear the input device
|
||||
* structure? Cache the rings? Reset the control endpoint 0 max packet size?
|
||||
*
|
||||
* If the virt_dev to be reset does not exist or does not match the udev,
|
||||
* it means the device is lost, possibly due to the xHC restore error and
|
||||
* re-initialization during S3/S4. In this case, call xhci_alloc_dev() to
|
||||
* re-allocate the device.
|
||||
*/
|
||||
int xhci_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
|
||||
{
|
||||
int ret, i;
|
||||
unsigned long flags;
|
||||
|
|
@ -1965,16 +2172,35 @@ int xhci_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
int timeleft;
|
||||
int last_freed_endpoint;
|
||||
|
||||
ret = xhci_check_args(hcd, udev, NULL, 0, __func__);
|
||||
ret = xhci_check_args(hcd, udev, NULL, 0, false, __func__);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
xhci = hcd_to_xhci(hcd);
|
||||
slot_id = udev->slot_id;
|
||||
virt_dev = xhci->devs[slot_id];
|
||||
if (!virt_dev) {
|
||||
xhci_dbg(xhci, "%s called with invalid slot ID %u\n",
|
||||
__func__, slot_id);
|
||||
return -EINVAL;
|
||||
xhci_dbg(xhci, "The device to be reset with slot ID %u does "
|
||||
"not exist. Re-allocate the device\n", slot_id);
|
||||
ret = xhci_alloc_dev(hcd, udev);
|
||||
if (ret == 1)
|
||||
return 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (virt_dev->udev != udev) {
|
||||
/* If the virt_dev and the udev does not match, this virt_dev
|
||||
* may belong to another udev.
|
||||
* Re-allocate the device.
|
||||
*/
|
||||
xhci_dbg(xhci, "The device to be reset with slot ID %u does "
|
||||
"not match the udev. Re-allocate the device\n",
|
||||
slot_id);
|
||||
ret = xhci_alloc_dev(hcd, udev);
|
||||
if (ret == 1)
|
||||
return 0;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
xhci_dbg(xhci, "Resetting device with slot ID %u\n", slot_id);
|
||||
|
|
@ -2077,13 +2303,13 @@ void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
struct xhci_virt_device *virt_dev;
|
||||
unsigned long flags;
|
||||
u32 state;
|
||||
int i;
|
||||
int i, ret;
|
||||
|
||||
if (udev->slot_id == 0)
|
||||
ret = xhci_check_args(hcd, udev, NULL, 0, true, __func__);
|
||||
if (ret <= 0)
|
||||
return;
|
||||
|
||||
virt_dev = xhci->devs[udev->slot_id];
|
||||
if (!virt_dev)
|
||||
return;
|
||||
|
||||
/* Stop any wayward timer functions (which may grab the lock) */
|
||||
for (i = 0; i < 31; ++i) {
|
||||
|
|
@ -2191,12 +2417,17 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
|
||||
virt_dev = xhci->devs[udev->slot_id];
|
||||
|
||||
/* If this is a Set Address to an unconfigured device, setup ep 0 */
|
||||
if (!udev->config)
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
|
||||
/*
|
||||
* If this is the first Set Address since device plug-in or
|
||||
* virt_device realloaction after a resume with an xHCI power loss,
|
||||
* then set up the slot context.
|
||||
*/
|
||||
if (!slot_ctx->dev_info)
|
||||
xhci_setup_addressable_virt_dev(xhci, udev);
|
||||
/* Otherwise, update the control endpoint ring enqueue pointer. */
|
||||
else
|
||||
xhci_copy_ep0_dequeue_into_input_ctx(xhci, udev);
|
||||
/* Otherwise, assume the core has the device configured how it wants */
|
||||
xhci_dbg(xhci, "Slot ID %d Input Context:\n", udev->slot_id);
|
||||
xhci_dbg_ctx(xhci, virt_dev->in_ctx, 2);
|
||||
|
||||
|
|
@ -2268,15 +2499,15 @@ int xhci_address_device(struct usb_hcd *hcd, struct usb_device *udev)
|
|||
* address given back to us by the HC.
|
||||
*/
|
||||
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->out_ctx);
|
||||
udev->devnum = (slot_ctx->dev_state & DEV_ADDR_MASK) + 1;
|
||||
/* Use kernel assigned address for devices; store xHC assigned
|
||||
* address locally. */
|
||||
virt_dev->address = (slot_ctx->dev_state & DEV_ADDR_MASK) + 1;
|
||||
/* Zero the input context control for later use */
|
||||
ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
|
||||
ctrl_ctx->add_flags = 0;
|
||||
ctrl_ctx->drop_flags = 0;
|
||||
|
||||
xhci_dbg(xhci, "Device address = %d\n", udev->devnum);
|
||||
/* XXX Meh, not sure if anyone else but choose_address uses this. */
|
||||
set_bit(udev->devnum, udev->bus->devmap.devicemap);
|
||||
xhci_dbg(xhci, "Internal device address = %d\n", virt_dev->address);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ struct xhci_op_regs {
|
|||
/* bits 4:6 are reserved (and should be preserved on writes). */
|
||||
/* light reset (port status stays unchanged) - reset completed when this is 0 */
|
||||
#define CMD_LRESET (1 << 7)
|
||||
/* FIXME: ignoring host controller save/restore state for now. */
|
||||
/* host controller save/restore state. */
|
||||
#define CMD_CSS (1 << 8)
|
||||
#define CMD_CRS (1 << 9)
|
||||
/* Enable Wrap Event - '1' means xHC generates an event when MFINDEX wraps. */
|
||||
|
|
@ -269,6 +269,10 @@ struct xhci_op_regs {
|
|||
* A read gives the current link PM state of the port,
|
||||
* a write with Link State Write Strobe set sets the link state.
|
||||
*/
|
||||
#define PORT_PLS_MASK (0xf << 5)
|
||||
#define XDEV_U0 (0x0 << 5)
|
||||
#define XDEV_U3 (0x3 << 5)
|
||||
#define XDEV_RESUME (0xf << 5)
|
||||
/* true: port has power (see HCC_PPC) */
|
||||
#define PORT_POWER (1 << 9)
|
||||
/* bits 10:13 indicate device speed:
|
||||
|
|
@ -353,6 +357,8 @@ struct xhci_op_regs {
|
|||
#define PORT_U2_TIMEOUT(p) (((p) & 0xff) << 8)
|
||||
/* Bits 24:31 for port testing */
|
||||
|
||||
/* USB2 Protocol PORTSPMSC */
|
||||
#define PORT_RWE (1 << 0x3)
|
||||
|
||||
/**
|
||||
* struct xhci_intr_reg - Interrupt Register Set
|
||||
|
|
@ -510,6 +516,7 @@ struct xhci_slot_ctx {
|
|||
#define MAX_EXIT (0xffff)
|
||||
/* Root hub port number that is needed to access the USB device */
|
||||
#define ROOT_HUB_PORT(p) (((p) & 0xff) << 16)
|
||||
#define DEVINFO_TO_ROOT_HUB_PORT(p) (((p) >> 16) & 0xff)
|
||||
/* Maximum number of ports under a hub device */
|
||||
#define XHCI_MAX_PORTS(p) (((p) & 0xff) << 24)
|
||||
|
||||
|
|
@ -731,6 +738,7 @@ struct xhci_virt_ep {
|
|||
};
|
||||
|
||||
struct xhci_virt_device {
|
||||
struct usb_device *udev;
|
||||
/*
|
||||
* Commands to the hardware are passed an "input context" that
|
||||
* tells the hardware what to change in its data structures.
|
||||
|
|
@ -745,12 +753,15 @@ struct xhci_virt_device {
|
|||
/* Rings saved to ensure old alt settings can be re-instated */
|
||||
struct xhci_ring **ring_cache;
|
||||
int num_rings_cached;
|
||||
/* Store xHC assigned device address */
|
||||
int address;
|
||||
#define XHCI_MAX_RINGS_CACHED 31
|
||||
struct xhci_virt_ep eps[31];
|
||||
struct completion cmd_completion;
|
||||
/* Status of the last command issued for this device */
|
||||
u32 cmd_status;
|
||||
struct list_head cmd_list;
|
||||
u8 port;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -881,6 +892,10 @@ struct xhci_event_cmd {
|
|||
#define TRB_TO_EP_INDEX(p) ((((p) & (0x1f << 16)) >> 16) - 1)
|
||||
#define EP_ID_FOR_TRB(p) ((((p) + 1) & 0x1f) << 16)
|
||||
|
||||
#define SUSPEND_PORT_FOR_TRB(p) (((p) & 1) << 23)
|
||||
#define TRB_TO_SUSPEND_PORT(p) (((p) & (1 << 23)) >> 23)
|
||||
#define LAST_EP_INDEX 30
|
||||
|
||||
/* Set TR Dequeue Pointer command TRB fields */
|
||||
#define TRB_TO_STREAM_ID(p) ((((p) & (0xffff << 16)) >> 16))
|
||||
#define STREAM_ID_FOR_TRB(p) ((((p)) & 0xffff) << 16)
|
||||
|
|
@ -1115,6 +1130,17 @@ struct urb_priv {
|
|||
#define XHCI_STOP_EP_CMD_TIMEOUT 5
|
||||
/* XXX: Make these module parameters */
|
||||
|
||||
struct s3_save {
|
||||
u32 command;
|
||||
u32 dev_nt;
|
||||
u64 dcbaa_ptr;
|
||||
u32 config_reg;
|
||||
u32 irq_pending;
|
||||
u32 irq_control;
|
||||
u32 erst_size;
|
||||
u64 erst_base;
|
||||
u64 erst_dequeue;
|
||||
};
|
||||
|
||||
/* There is one ehci_hci structure per controller */
|
||||
struct xhci_hcd {
|
||||
|
|
@ -1178,6 +1204,12 @@ struct xhci_hcd {
|
|||
#endif
|
||||
/* Host controller watchdog timer structures */
|
||||
unsigned int xhc_state;
|
||||
|
||||
unsigned long bus_suspended;
|
||||
unsigned long next_statechange;
|
||||
|
||||
u32 command;
|
||||
struct s3_save s3;
|
||||
/* Host controller is dying - not responding to commands. "I'm not dead yet!"
|
||||
*
|
||||
* xHC interrupts have been disabled and a watchdog timer will (or has already)
|
||||
|
|
@ -1199,6 +1231,10 @@ struct xhci_hcd {
|
|||
#define XHCI_LINK_TRB_QUIRK (1 << 0)
|
||||
#define XHCI_RESET_EP_QUIRK (1 << 1)
|
||||
#define XHCI_NEC_HOST (1 << 2)
|
||||
u32 port_c_suspend[8]; /* port suspend change*/
|
||||
u32 suspended_ports[8]; /* which ports are
|
||||
suspended */
|
||||
unsigned long resume_done[MAX_HC_PORTS];
|
||||
};
|
||||
|
||||
/* For testing purposes */
|
||||
|
|
@ -1369,6 +1405,15 @@ int xhci_init(struct usb_hcd *hcd);
|
|||
int xhci_run(struct usb_hcd *hcd);
|
||||
void xhci_stop(struct usb_hcd *hcd);
|
||||
void xhci_shutdown(struct usb_hcd *hcd);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
int xhci_suspend(struct xhci_hcd *xhci);
|
||||
int xhci_resume(struct xhci_hcd *xhci, bool hibernated);
|
||||
#else
|
||||
#define xhci_suspend NULL
|
||||
#define xhci_resume NULL
|
||||
#endif
|
||||
|
||||
int xhci_get_frame(struct usb_hcd *hcd);
|
||||
irqreturn_t xhci_irq(struct usb_hcd *hcd);
|
||||
irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd);
|
||||
|
|
@ -1388,7 +1433,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
|
|||
int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
|
||||
int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
|
||||
void xhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
|
||||
int xhci_reset_device(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
|
||||
|
||||
|
|
@ -1406,7 +1451,7 @@ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
|
|||
int xhci_queue_vendor_command(struct xhci_hcd *xhci,
|
||||
u32 field1, u32 field2, u32 field3, u32 field4);
|
||||
int xhci_queue_stop_endpoint(struct xhci_hcd *xhci, int slot_id,
|
||||
unsigned int ep_index);
|
||||
unsigned int ep_index, int suspend);
|
||||
int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
|
||||
int slot_id, unsigned int ep_index);
|
||||
int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, struct urb *urb,
|
||||
|
|
@ -1436,12 +1481,26 @@ void xhci_queue_config_ep_quirk(struct xhci_hcd *xhci,
|
|||
unsigned int slot_id, unsigned int ep_index,
|
||||
struct xhci_dequeue_state *deq_state);
|
||||
void xhci_stop_endpoint_command_watchdog(unsigned long arg);
|
||||
void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id,
|
||||
unsigned int ep_index, unsigned int stream_id);
|
||||
|
||||
/* xHCI roothub code */
|
||||
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex,
|
||||
char *buf, u16 wLength);
|
||||
int xhci_hub_status_data(struct usb_hcd *hcd, char *buf);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
int xhci_bus_suspend(struct usb_hcd *hcd);
|
||||
int xhci_bus_resume(struct usb_hcd *hcd);
|
||||
#else
|
||||
#define xhci_bus_suspend NULL
|
||||
#define xhci_bus_resume NULL
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
u32 xhci_port_state_to_neutral(u32 state);
|
||||
int xhci_find_slot_id_by_port(struct xhci_hcd *xhci, u16 port);
|
||||
void xhci_ring_device(struct xhci_hcd *xhci, int slot_id);
|
||||
|
||||
/* xHCI contexts */
|
||||
struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
|
||||
struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
|
||||
|
|
|
|||
|
|
@ -231,3 +231,16 @@ config USB_ISIGHTFW
|
|||
driver beforehand. Tools for doing so are available at
|
||||
http://bersace03.free.fr
|
||||
|
||||
config USB_YUREX
|
||||
tristate "USB YUREX driver support"
|
||||
depends on USB
|
||||
help
|
||||
Say Y here if you want to connect a YUREX to your computer's
|
||||
USB port. The YUREX is a leg-shakes sensor. See
|
||||
<http://bbu.kayac.com/en/> for further information.
|
||||
This driver supports read/write of leg-shakes counter and
|
||||
fasync for the counter update via a device file /dev/yurex*.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called yurex.
|
||||
|
||||
|
|
|
|||
|
|
@ -3,28 +3,27 @@
|
|||
# (the ones that don't fit into any other categories)
|
||||
#
|
||||
|
||||
obj-$(CONFIG_USB_ADUTUX) += adutux.o
|
||||
obj-$(CONFIG_USB_APPLEDISPLAY) += appledisplay.o
|
||||
obj-$(CONFIG_USB_CYPRESS_CY7C63)+= cypress_cy7c63.o
|
||||
obj-$(CONFIG_USB_CYTHERM) += cytherm.o
|
||||
obj-$(CONFIG_USB_EMI26) += emi26.o
|
||||
obj-$(CONFIG_USB_EMI62) += emi62.o
|
||||
obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o
|
||||
obj-$(CONFIG_USB_IDMOUSE) += idmouse.o
|
||||
obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o
|
||||
obj-$(CONFIG_USB_ISIGHTFW) += isight_firmware.o
|
||||
obj-$(CONFIG_USB_LCD) += usblcd.o
|
||||
obj-$(CONFIG_USB_LD) += ldusb.o
|
||||
obj-$(CONFIG_USB_LED) += usbled.o
|
||||
obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o
|
||||
obj-$(CONFIG_USB_RIO500) += rio500.o
|
||||
obj-$(CONFIG_USB_TEST) += usbtest.o
|
||||
ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
|
||||
|
||||
obj-$(CONFIG_USB_ADUTUX) += adutux.o
|
||||
obj-$(CONFIG_USB_APPLEDISPLAY) += appledisplay.o
|
||||
obj-$(CONFIG_USB_CYPRESS_CY7C63) += cypress_cy7c63.o
|
||||
obj-$(CONFIG_USB_CYTHERM) += cytherm.o
|
||||
obj-$(CONFIG_USB_EMI26) += emi26.o
|
||||
obj-$(CONFIG_USB_EMI62) += emi62.o
|
||||
obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o
|
||||
obj-$(CONFIG_USB_IDMOUSE) += idmouse.o
|
||||
obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o
|
||||
obj-$(CONFIG_USB_ISIGHTFW) += isight_firmware.o
|
||||
obj-$(CONFIG_USB_LCD) += usblcd.o
|
||||
obj-$(CONFIG_USB_LD) += ldusb.o
|
||||
obj-$(CONFIG_USB_LED) += usbled.o
|
||||
obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o
|
||||
obj-$(CONFIG_USB_RIO500) += rio500.o
|
||||
obj-$(CONFIG_USB_TEST) += usbtest.o
|
||||
obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o
|
||||
obj-$(CONFIG_USB_USS720) += uss720.o
|
||||
obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o
|
||||
obj-$(CONFIG_USB_USS720) += uss720.o
|
||||
obj-$(CONFIG_USB_SEVSEG) += usbsevseg.o
|
||||
obj-$(CONFIG_USB_YUREX) += yurex.o
|
||||
|
||||
obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
|
||||
|
||||
ifeq ($(CONFIG_USB_DEBUG),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
endif
|
||||
obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
|
||||
|
|
|
|||
|
|
@ -2769,7 +2769,7 @@ static int ftdi_elan_probe(struct usb_interface *interface,
|
|||
ftdi->sequence_num = ++ftdi_instances;
|
||||
mutex_unlock(&ftdi_module_lock);
|
||||
ftdi_elan_init_kref(ftdi);
|
||||
init_MUTEX(&ftdi->sw_lock);
|
||||
sema_init(&ftdi->sw_lock, 1);
|
||||
ftdi->udev = usb_get_dev(interface_to_usbdev(interface));
|
||||
ftdi->interface = interface;
|
||||
mutex_init(&ftdi->u132_lock);
|
||||
|
|
|
|||
|
|
@ -374,7 +374,7 @@ static ssize_t iowarrior_write(struct file *file,
|
|||
case USB_DEVICE_ID_CODEMERCS_IOWPV2:
|
||||
case USB_DEVICE_ID_CODEMERCS_IOW40:
|
||||
/* IOW24 and IOW40 use a synchronous call */
|
||||
buf = kmalloc(8, GFP_KERNEL); /* 8 bytes are enough for both products */
|
||||
buf = kmalloc(count, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
|
|
|
|||
|
|
@ -4,5 +4,4 @@
|
|||
|
||||
obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga.o
|
||||
|
||||
sisusbvga-objs := sisusb.o sisusb_init.o sisusb_con.o
|
||||
|
||||
sisusbvga-y := sisusb.o sisusb_init.o sisusb_con.o
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
563
drivers/usb/misc/yurex.c
Normal file
563
drivers/usb/misc/yurex.c
Normal file
|
|
@ -0,0 +1,563 @@
|
|||
/*
|
||||
* Driver for Meywa-Denki & KAYAC YUREX
|
||||
*
|
||||
* Copyright (C) 2010 Tomoki Sekiyama (tomoki.sekiyama@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/hid.h>
|
||||
|
||||
#define DRIVER_AUTHOR "Tomoki Sekiyama"
|
||||
#define DRIVER_DESC "Driver for Meywa-Denki & KAYAC YUREX"
|
||||
|
||||
#define YUREX_VENDOR_ID 0x0c45
|
||||
#define YUREX_PRODUCT_ID 0x1010
|
||||
|
||||
#define CMD_ACK '!'
|
||||
#define CMD_ANIMATE 'A'
|
||||
#define CMD_COUNT 'C'
|
||||
#define CMD_LED 'L'
|
||||
#define CMD_READ 'R'
|
||||
#define CMD_SET 'S'
|
||||
#define CMD_VERSION 'V'
|
||||
#define CMD_EOF 0x0d
|
||||
#define CMD_PADDING 0xff
|
||||
|
||||
#define YUREX_BUF_SIZE 8
|
||||
#define YUREX_WRITE_TIMEOUT (HZ*2)
|
||||
|
||||
/* table of devices that work with this driver */
|
||||
static struct usb_device_id yurex_table[] = {
|
||||
{ USB_DEVICE(YUREX_VENDOR_ID, YUREX_PRODUCT_ID) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, yurex_table);
|
||||
|
||||
#ifdef CONFIG_USB_DYNAMIC_MINORS
|
||||
#define YUREX_MINOR_BASE 0
|
||||
#else
|
||||
#define YUREX_MINOR_BASE 192
|
||||
#endif
|
||||
|
||||
/* Structure to hold all of our device specific stuff */
|
||||
struct usb_yurex {
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *interface;
|
||||
__u8 int_in_endpointAddr;
|
||||
struct urb *urb; /* URB for interrupt in */
|
||||
unsigned char *int_buffer; /* buffer for intterupt in */
|
||||
struct urb *cntl_urb; /* URB for control msg */
|
||||
struct usb_ctrlrequest *cntl_req; /* req for control msg */
|
||||
unsigned char *cntl_buffer; /* buffer for control msg */
|
||||
|
||||
struct kref kref;
|
||||
struct mutex io_mutex;
|
||||
struct fasync_struct *async_queue;
|
||||
wait_queue_head_t waitq;
|
||||
|
||||
spinlock_t lock;
|
||||
__s64 bbu; /* BBU from device */
|
||||
};
|
||||
#define to_yurex_dev(d) container_of(d, struct usb_yurex, kref)
|
||||
|
||||
static struct usb_driver yurex_driver;
|
||||
static const struct file_operations yurex_fops;
|
||||
|
||||
|
||||
static void yurex_control_callback(struct urb *urb)
|
||||
{
|
||||
struct usb_yurex *dev = urb->context;
|
||||
int status = urb->status;
|
||||
|
||||
if (status) {
|
||||
err("%s - control failed: %d\n", __func__, status);
|
||||
wake_up_interruptible(&dev->waitq);
|
||||
return;
|
||||
}
|
||||
/* on success, sender woken up by CMD_ACK int in, or timeout */
|
||||
}
|
||||
|
||||
static void yurex_delete(struct kref *kref)
|
||||
{
|
||||
struct usb_yurex *dev = to_yurex_dev(kref);
|
||||
|
||||
dbg("yurex_delete");
|
||||
|
||||
usb_put_dev(dev->udev);
|
||||
if (dev->cntl_urb) {
|
||||
usb_kill_urb(dev->cntl_urb);
|
||||
if (dev->cntl_req)
|
||||
usb_free_coherent(dev->udev, YUREX_BUF_SIZE,
|
||||
dev->cntl_req, dev->cntl_urb->setup_dma);
|
||||
if (dev->cntl_buffer)
|
||||
usb_free_coherent(dev->udev, YUREX_BUF_SIZE,
|
||||
dev->cntl_buffer, dev->cntl_urb->transfer_dma);
|
||||
usb_free_urb(dev->cntl_urb);
|
||||
}
|
||||
if (dev->urb) {
|
||||
usb_kill_urb(dev->urb);
|
||||
if (dev->int_buffer)
|
||||
usb_free_coherent(dev->udev, YUREX_BUF_SIZE,
|
||||
dev->int_buffer, dev->urb->transfer_dma);
|
||||
usb_free_urb(dev->urb);
|
||||
}
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* usb class driver info in order to get a minor number from the usb core,
|
||||
* and to have the device registered with the driver core
|
||||
*/
|
||||
static struct usb_class_driver yurex_class = {
|
||||
.name = "yurex%d",
|
||||
.fops = &yurex_fops,
|
||||
.minor_base = YUREX_MINOR_BASE,
|
||||
};
|
||||
|
||||
static void yurex_interrupt(struct urb *urb)
|
||||
{
|
||||
struct usb_yurex *dev = urb->context;
|
||||
unsigned char *buf = dev->int_buffer;
|
||||
int status = urb->status;
|
||||
unsigned long flags;
|
||||
int retval, i;
|
||||
|
||||
switch (status) {
|
||||
case 0: /*success*/
|
||||
break;
|
||||
case -EOVERFLOW:
|
||||
err("%s - overflow with length %d, actual length is %d",
|
||||
__func__, YUREX_BUF_SIZE, dev->urb->actual_length);
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
case -ESHUTDOWN:
|
||||
case -EILSEQ:
|
||||
/* The device is terminated, clean up */
|
||||
return;
|
||||
default:
|
||||
err("%s - unknown status received: %d", __func__, status);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* handle received message */
|
||||
switch (buf[0]) {
|
||||
case CMD_COUNT:
|
||||
case CMD_READ:
|
||||
if (buf[6] == CMD_EOF) {
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
dev->bbu = 0;
|
||||
for (i = 1; i < 6; i++) {
|
||||
dev->bbu += buf[i];
|
||||
if (i != 5)
|
||||
dev->bbu <<= 8;
|
||||
}
|
||||
dbg("%s count: %lld", __func__, dev->bbu);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
|
||||
}
|
||||
else
|
||||
dbg("data format error - no EOF");
|
||||
break;
|
||||
case CMD_ACK:
|
||||
dbg("%s ack: %c", __func__, buf[1]);
|
||||
wake_up_interruptible(&dev->waitq);
|
||||
break;
|
||||
}
|
||||
|
||||
exit:
|
||||
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
|
||||
if (retval) {
|
||||
err("%s - usb_submit_urb failed: %d",
|
||||
__func__, retval);
|
||||
}
|
||||
}
|
||||
|
||||
static int yurex_probe(struct usb_interface *interface, const struct usb_device_id *id)
|
||||
{
|
||||
struct usb_yurex *dev;
|
||||
struct usb_host_interface *iface_desc;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
int retval = -ENOMEM;
|
||||
int i;
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
/* allocate memory for our device state and initialize it */
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
err("Out of memory");
|
||||
goto error;
|
||||
}
|
||||
kref_init(&dev->kref);
|
||||
mutex_init(&dev->io_mutex);
|
||||
spin_lock_init(&dev->lock);
|
||||
init_waitqueue_head(&dev->waitq);
|
||||
|
||||
dev->udev = usb_get_dev(interface_to_usbdev(interface));
|
||||
dev->interface = interface;
|
||||
|
||||
/* set up the endpoint information */
|
||||
iface_desc = interface->cur_altsetting;
|
||||
for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
|
||||
endpoint = &iface_desc->endpoint[i].desc;
|
||||
|
||||
if (usb_endpoint_is_int_in(endpoint)) {
|
||||
dev->int_in_endpointAddr = endpoint->bEndpointAddress;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!dev->int_in_endpointAddr) {
|
||||
retval = -ENODEV;
|
||||
err("Could not find endpoints");
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
/* allocate control URB */
|
||||
dev->cntl_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!dev->cntl_urb) {
|
||||
err("Could not allocate control URB");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* allocate buffer for control req */
|
||||
dev->cntl_req = usb_alloc_coherent(dev->udev, YUREX_BUF_SIZE,
|
||||
GFP_KERNEL,
|
||||
&dev->cntl_urb->setup_dma);
|
||||
if (!dev->cntl_req) {
|
||||
err("Could not allocate cntl_req");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* allocate buffer for control msg */
|
||||
dev->cntl_buffer = usb_alloc_coherent(dev->udev, YUREX_BUF_SIZE,
|
||||
GFP_KERNEL,
|
||||
&dev->cntl_urb->transfer_dma);
|
||||
if (!dev->cntl_buffer) {
|
||||
err("Could not allocate cntl_buffer");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* configure control URB */
|
||||
dev->cntl_req->bRequestType = USB_DIR_OUT | USB_TYPE_CLASS |
|
||||
USB_RECIP_INTERFACE;
|
||||
dev->cntl_req->bRequest = HID_REQ_SET_REPORT;
|
||||
dev->cntl_req->wValue = cpu_to_le16((HID_OUTPUT_REPORT + 1) << 8);
|
||||
dev->cntl_req->wIndex = cpu_to_le16(iface_desc->desc.bInterfaceNumber);
|
||||
dev->cntl_req->wLength = cpu_to_le16(YUREX_BUF_SIZE);
|
||||
|
||||
usb_fill_control_urb(dev->cntl_urb, dev->udev,
|
||||
usb_sndctrlpipe(dev->udev, 0),
|
||||
(void *)dev->cntl_req, dev->cntl_buffer,
|
||||
YUREX_BUF_SIZE, yurex_control_callback, dev);
|
||||
dev->cntl_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
|
||||
/* allocate interrupt URB */
|
||||
dev->urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!dev->urb) {
|
||||
err("Could not allocate URB");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* allocate buffer for interrupt in */
|
||||
dev->int_buffer = usb_alloc_coherent(dev->udev, YUREX_BUF_SIZE,
|
||||
GFP_KERNEL, &dev->urb->transfer_dma);
|
||||
if (!dev->int_buffer) {
|
||||
err("Could not allocate int_buffer");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* configure interrupt URB */
|
||||
usb_fill_int_urb(dev->urb, dev->udev,
|
||||
usb_rcvintpipe(dev->udev, dev->int_in_endpointAddr),
|
||||
dev->int_buffer, YUREX_BUF_SIZE, yurex_interrupt,
|
||||
dev, 1);
|
||||
dev->cntl_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
if (usb_submit_urb(dev->urb, GFP_KERNEL)) {
|
||||
retval = -EIO;
|
||||
err("Could not submitting URB");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* save our data pointer in this interface device */
|
||||
usb_set_intfdata(interface, dev);
|
||||
|
||||
/* we can register the device now, as it is ready */
|
||||
retval = usb_register_dev(interface, &yurex_class);
|
||||
if (retval) {
|
||||
err("Not able to get a minor for this device.");
|
||||
usb_set_intfdata(interface, NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
dev->bbu = -1;
|
||||
|
||||
dev_info(&interface->dev,
|
||||
"USB YUREX device now attached to Yurex #%d\n",
|
||||
interface->minor);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (dev)
|
||||
/* this frees allocated memory */
|
||||
kref_put(&dev->kref, yurex_delete);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void yurex_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct usb_yurex *dev;
|
||||
int minor = interface->minor;
|
||||
|
||||
dev = usb_get_intfdata(interface);
|
||||
usb_set_intfdata(interface, NULL);
|
||||
|
||||
/* give back our minor */
|
||||
usb_deregister_dev(interface, &yurex_class);
|
||||
|
||||
/* prevent more I/O from starting */
|
||||
mutex_lock(&dev->io_mutex);
|
||||
dev->interface = NULL;
|
||||
mutex_unlock(&dev->io_mutex);
|
||||
|
||||
/* wakeup waiters */
|
||||
kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
|
||||
wake_up_interruptible(&dev->waitq);
|
||||
|
||||
/* decrement our usage count */
|
||||
kref_put(&dev->kref, yurex_delete);
|
||||
|
||||
dev_info(&interface->dev, "USB YUREX #%d now disconnected\n", minor);
|
||||
}
|
||||
|
||||
static struct usb_driver yurex_driver = {
|
||||
.name = "yurex",
|
||||
.probe = yurex_probe,
|
||||
.disconnect = yurex_disconnect,
|
||||
.id_table = yurex_table,
|
||||
};
|
||||
|
||||
|
||||
static int yurex_fasync(int fd, struct file *file, int on)
|
||||
{
|
||||
struct usb_yurex *dev;
|
||||
|
||||
dev = (struct usb_yurex *)file->private_data;
|
||||
return fasync_helper(fd, file, on, &dev->async_queue);
|
||||
}
|
||||
|
||||
static int yurex_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct usb_yurex *dev;
|
||||
struct usb_interface *interface;
|
||||
int subminor;
|
||||
int retval = 0;
|
||||
|
||||
subminor = iminor(inode);
|
||||
|
||||
interface = usb_find_interface(&yurex_driver, subminor);
|
||||
if (!interface) {
|
||||
err("%s - error, can't find device for minor %d",
|
||||
__func__, subminor);
|
||||
retval = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
dev = usb_get_intfdata(interface);
|
||||
if (!dev) {
|
||||
retval = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* increment our usage count for the device */
|
||||
kref_get(&dev->kref);
|
||||
|
||||
/* save our object in the file's private structure */
|
||||
mutex_lock(&dev->io_mutex);
|
||||
file->private_data = dev;
|
||||
mutex_unlock(&dev->io_mutex);
|
||||
|
||||
exit:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int yurex_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct usb_yurex *dev;
|
||||
|
||||
dev = (struct usb_yurex *)file->private_data;
|
||||
if (dev == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
yurex_fasync(-1, file, 0);
|
||||
|
||||
/* decrement the count on our device */
|
||||
kref_put(&dev->kref, yurex_delete);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t yurex_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct usb_yurex *dev;
|
||||
int retval = 0;
|
||||
int bytes_read = 0;
|
||||
char in_buffer[20];
|
||||
unsigned long flags;
|
||||
|
||||
dev = (struct usb_yurex *)file->private_data;
|
||||
|
||||
mutex_lock(&dev->io_mutex);
|
||||
if (!dev->interface) { /* already disconnected */
|
||||
retval = -ENODEV;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
bytes_read = snprintf(in_buffer, 20, "%lld\n", dev->bbu);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
if (*ppos < bytes_read) {
|
||||
if (copy_to_user(buffer, in_buffer + *ppos, bytes_read - *ppos))
|
||||
retval = -EFAULT;
|
||||
else {
|
||||
retval = bytes_read - *ppos;
|
||||
*ppos += bytes_read;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&dev->io_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static ssize_t yurex_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct usb_yurex *dev;
|
||||
int i, set = 0, retval = 0;
|
||||
char buffer[16];
|
||||
char *data = buffer;
|
||||
unsigned long long c, c2 = 0;
|
||||
signed long timeout = 0;
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
count = min(sizeof(buffer), count);
|
||||
dev = (struct usb_yurex *)file->private_data;
|
||||
|
||||
/* verify that we actually have some data to write */
|
||||
if (count == 0)
|
||||
goto error;
|
||||
|
||||
mutex_lock(&dev->io_mutex);
|
||||
if (!dev->interface) { /* alreaday disconnected */
|
||||
mutex_unlock(&dev->io_mutex);
|
||||
retval = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (copy_from_user(buffer, user_buffer, count)) {
|
||||
mutex_unlock(&dev->io_mutex);
|
||||
retval = -EFAULT;
|
||||
goto error;
|
||||
}
|
||||
memset(dev->cntl_buffer, CMD_PADDING, YUREX_BUF_SIZE);
|
||||
|
||||
switch (buffer[0]) {
|
||||
case CMD_ANIMATE:
|
||||
case CMD_LED:
|
||||
dev->cntl_buffer[0] = buffer[0];
|
||||
dev->cntl_buffer[1] = buffer[1];
|
||||
dev->cntl_buffer[2] = CMD_EOF;
|
||||
break;
|
||||
case CMD_READ:
|
||||
case CMD_VERSION:
|
||||
dev->cntl_buffer[0] = buffer[0];
|
||||
dev->cntl_buffer[1] = 0x00;
|
||||
dev->cntl_buffer[2] = CMD_EOF;
|
||||
break;
|
||||
case CMD_SET:
|
||||
data++;
|
||||
/* FALL THROUGH */
|
||||
case '0' ... '9':
|
||||
set = 1;
|
||||
c = c2 = simple_strtoull(data, NULL, 0);
|
||||
dev->cntl_buffer[0] = CMD_SET;
|
||||
for (i = 1; i < 6; i++) {
|
||||
dev->cntl_buffer[i] = (c>>32) & 0xff;
|
||||
c <<= 8;
|
||||
}
|
||||
buffer[6] = CMD_EOF;
|
||||
break;
|
||||
default:
|
||||
mutex_unlock(&dev->io_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* send the data as the control msg */
|
||||
prepare_to_wait(&dev->waitq, &wait, TASK_INTERRUPTIBLE);
|
||||
dbg("%s - submit %c", __func__, dev->cntl_buffer[0]);
|
||||
retval = usb_submit_urb(dev->cntl_urb, GFP_KERNEL);
|
||||
if (retval >= 0)
|
||||
timeout = schedule_timeout(YUREX_WRITE_TIMEOUT);
|
||||
finish_wait(&dev->waitq, &wait);
|
||||
|
||||
mutex_unlock(&dev->io_mutex);
|
||||
|
||||
if (retval < 0) {
|
||||
err("%s - failed to send bulk msg, error %d", __func__, retval);
|
||||
goto error;
|
||||
}
|
||||
if (set && timeout)
|
||||
dev->bbu = c2;
|
||||
return timeout ? count : -EIO;
|
||||
|
||||
error:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static const struct file_operations yurex_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = yurex_read,
|
||||
.write = yurex_write,
|
||||
.open = yurex_open,
|
||||
.release = yurex_release,
|
||||
.fasync = yurex_fasync,
|
||||
};
|
||||
|
||||
|
||||
static int __init usb_yurex_init(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
/* register this driver with the USB subsystem */
|
||||
result = usb_register(&yurex_driver);
|
||||
if (result)
|
||||
err("usb_register failed. Error number %d", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void __exit usb_yurex_exit(void)
|
||||
{
|
||||
/* deregister this driver with the USB subsystem */
|
||||
usb_deregister(&yurex_driver);
|
||||
}
|
||||
|
||||
module_init(usb_yurex_init);
|
||||
module_exit(usb_yurex_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -2,6 +2,6 @@
|
|||
# Makefile for USB monitor
|
||||
#
|
||||
|
||||
usbmon-objs := mon_main.o mon_stat.o mon_text.o mon_bin.o
|
||||
usbmon-y := mon_main.o mon_stat.o mon_text.o mon_bin.o
|
||||
|
||||
obj-$(CONFIG_USB_MON) += usbmon.o
|
||||
|
|
|
|||
|
|
@ -45,6 +45,9 @@ config USB_MUSB_SOC
|
|||
comment "DaVinci 35x and 644x USB support"
|
||||
depends on USB_MUSB_HDRC && ARCH_DAVINCI_DMx
|
||||
|
||||
comment "DA8xx/OMAP-L1x USB support"
|
||||
depends on USB_MUSB_HDRC && ARCH_DAVINCI_DA8XX
|
||||
|
||||
comment "OMAP 243x high speed USB support"
|
||||
depends on USB_MUSB_HDRC && ARCH_OMAP2430
|
||||
|
||||
|
|
@ -57,6 +60,17 @@ comment "OMAP 44xx high speed USB support"
|
|||
comment "Blackfin high speed USB Support"
|
||||
depends on USB_MUSB_HDRC && ((BF54x && !BF544) || (BF52x && !BF522 && !BF523))
|
||||
|
||||
config USB_MUSB_AM35X
|
||||
bool
|
||||
depends on USB_MUSB_HDRC && !ARCH_OMAP2430 && !ARCH_OMAP4
|
||||
select NOP_USB_XCEIV
|
||||
default MACH_OMAP3517EVM
|
||||
help
|
||||
Select this option if your platform is based on AM35x. As
|
||||
AM35x has an updated MUSB with CPPI4.1 DMA so this config
|
||||
is introduced to differentiate musb ip between OMAP3x and
|
||||
AM35x platforms.
|
||||
|
||||
config USB_TUSB6010
|
||||
boolean "TUSB 6010 support"
|
||||
depends on USB_MUSB_HDRC && !USB_MUSB_SOC
|
||||
|
|
@ -144,7 +158,7 @@ config USB_MUSB_HDRC_HCD
|
|||
config MUSB_PIO_ONLY
|
||||
bool 'Disable DMA (always use PIO)'
|
||||
depends on USB_MUSB_HDRC
|
||||
default y if USB_TUSB6010
|
||||
default USB_TUSB6010 || ARCH_DAVINCI_DA8XX || USB_MUSB_AM35X
|
||||
help
|
||||
All data is copied between memory and FIFO by the CPU.
|
||||
DMA controllers are ignored.
|
||||
|
|
|
|||
|
|
@ -2,49 +2,27 @@
|
|||
# for USB OTG silicon based on Mentor Graphics INVENTRA designs
|
||||
#
|
||||
|
||||
musb_hdrc-objs := musb_core.o
|
||||
ccflags-$(CONFIG_USB_MUSB_DEBUG) := -DDEBUG
|
||||
|
||||
obj-$(CONFIG_USB_MUSB_HDRC) += musb_hdrc.o
|
||||
obj-$(CONFIG_USB_MUSB_HDRC) += musb_hdrc.o
|
||||
|
||||
ifeq ($(CONFIG_ARCH_DAVINCI_DMx),y)
|
||||
musb_hdrc-objs += davinci.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_USB_TUSB6010),y)
|
||||
musb_hdrc-objs += tusb6010.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_OMAP2430),y)
|
||||
musb_hdrc-objs += omap2430.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_OMAP3430),y)
|
||||
musb_hdrc-objs += omap2430.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_OMAP4),y)
|
||||
musb_hdrc-objs += omap2430.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BF54x),y)
|
||||
musb_hdrc-objs += blackfin.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_BF52x),y)
|
||||
musb_hdrc-objs += blackfin.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_USB_GADGET_MUSB_HDRC),y)
|
||||
musb_hdrc-objs += musb_gadget_ep0.o musb_gadget.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_USB_MUSB_HDRC_HCD),y)
|
||||
musb_hdrc-objs += musb_virthub.o musb_host.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_DEBUG_FS),y)
|
||||
musb_hdrc-objs += musb_debugfs.o
|
||||
musb_hdrc-y := musb_core.o
|
||||
|
||||
musb_hdrc-$(CONFIG_ARCH_DAVINCI_DMx) += davinci.o
|
||||
musb_hdrc-$(CONFIG_ARCH_DAVINCI_DA8XX) += da8xx.o
|
||||
musb_hdrc-$(CONFIG_USB_TUSB6010) += tusb6010.o
|
||||
musb_hdrc-$(CONFIG_ARCH_OMAP2430) += omap2430.o
|
||||
ifeq ($(CONFIG_USB_MUSB_AM35X),y)
|
||||
musb_hdrc-$(CONFIG_ARCH_OMAP3430) += am35x.o
|
||||
else
|
||||
musb_hdrc-$(CONFIG_ARCH_OMAP3430) += omap2430.o
|
||||
endif
|
||||
musb_hdrc-$(CONFIG_ARCH_OMAP4) += omap2430.o
|
||||
musb_hdrc-$(CONFIG_BF54x) += blackfin.o
|
||||
musb_hdrc-$(CONFIG_BF52x) += blackfin.o
|
||||
musb_hdrc-$(CONFIG_USB_GADGET_MUSB_HDRC) += musb_gadget_ep0.o musb_gadget.o
|
||||
musb_hdrc-$(CONFIG_USB_MUSB_HDRC_HCD) += musb_virthub.o musb_host.o
|
||||
musb_hdrc-$(CONFIG_DEBUG_FS) += musb_debugfs.o
|
||||
|
||||
# the kconfig must guarantee that only one of the
|
||||
# possible I/O schemes will be enabled at a time ...
|
||||
|
|
@ -54,26 +32,17 @@ endif
|
|||
ifneq ($(CONFIG_MUSB_PIO_ONLY),y)
|
||||
|
||||
ifeq ($(CONFIG_USB_INVENTRA_DMA),y)
|
||||
musb_hdrc-objs += musbhsdma.o
|
||||
musb_hdrc-y += musbhsdma.o
|
||||
|
||||
else
|
||||
ifeq ($(CONFIG_USB_TI_CPPI_DMA),y)
|
||||
musb_hdrc-objs += cppi_dma.o
|
||||
musb_hdrc-y += cppi_dma.o
|
||||
|
||||
else
|
||||
ifeq ($(CONFIG_USB_TUSB_OMAP_DMA),y)
|
||||
musb_hdrc-objs += tusb6010_omap.o
|
||||
musb_hdrc-y += tusb6010_omap.o
|
||||
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
################################################################################
|
||||
|
||||
# Debugging
|
||||
|
||||
ifeq ($(CONFIG_USB_MUSB_DEBUG),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
endif
|
||||
|
|
|
|||
524
drivers/usb/musb/am35x.c
Normal file
524
drivers/usb/musb/am35x.c
Normal file
|
|
@ -0,0 +1,524 @@
|
|||
/*
|
||||
* Texas Instruments AM35x "glue layer"
|
||||
*
|
||||
* Copyright (c) 2010, by Texas Instruments
|
||||
*
|
||||
* Based on the DA8xx "glue layer" code.
|
||||
* Copyright (c) 2008-2009, MontaVista Software, Inc. <source@mvista.com>
|
||||
*
|
||||
* This file is part of the Inventra Controller Driver for Linux.
|
||||
*
|
||||
* The Inventra Controller Driver for Linux is free software; you
|
||||
* can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License version 2 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* The Inventra Controller Driver for Linux 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 The Inventra Controller Driver for Linux ; if not,
|
||||
* write to the Free Software Foundation, Inc., 59 Temple Place,
|
||||
* Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <plat/control.h>
|
||||
#include <plat/usb.h>
|
||||
|
||||
#include "musb_core.h"
|
||||
|
||||
/*
|
||||
* AM35x specific definitions
|
||||
*/
|
||||
/* USB 2.0 OTG module registers */
|
||||
#define USB_REVISION_REG 0x00
|
||||
#define USB_CTRL_REG 0x04
|
||||
#define USB_STAT_REG 0x08
|
||||
#define USB_EMULATION_REG 0x0c
|
||||
/* 0x10 Reserved */
|
||||
#define USB_AUTOREQ_REG 0x14
|
||||
#define USB_SRP_FIX_TIME_REG 0x18
|
||||
#define USB_TEARDOWN_REG 0x1c
|
||||
#define EP_INTR_SRC_REG 0x20
|
||||
#define EP_INTR_SRC_SET_REG 0x24
|
||||
#define EP_INTR_SRC_CLEAR_REG 0x28
|
||||
#define EP_INTR_MASK_REG 0x2c
|
||||
#define EP_INTR_MASK_SET_REG 0x30
|
||||
#define EP_INTR_MASK_CLEAR_REG 0x34
|
||||
#define EP_INTR_SRC_MASKED_REG 0x38
|
||||
#define CORE_INTR_SRC_REG 0x40
|
||||
#define CORE_INTR_SRC_SET_REG 0x44
|
||||
#define CORE_INTR_SRC_CLEAR_REG 0x48
|
||||
#define CORE_INTR_MASK_REG 0x4c
|
||||
#define CORE_INTR_MASK_SET_REG 0x50
|
||||
#define CORE_INTR_MASK_CLEAR_REG 0x54
|
||||
#define CORE_INTR_SRC_MASKED_REG 0x58
|
||||
/* 0x5c Reserved */
|
||||
#define USB_END_OF_INTR_REG 0x60
|
||||
|
||||
/* Control register bits */
|
||||
#define AM35X_SOFT_RESET_MASK 1
|
||||
|
||||
/* USB interrupt register bits */
|
||||
#define AM35X_INTR_USB_SHIFT 16
|
||||
#define AM35X_INTR_USB_MASK (0x1ff << AM35X_INTR_USB_SHIFT)
|
||||
#define AM35X_INTR_DRVVBUS 0x100
|
||||
#define AM35X_INTR_RX_SHIFT 16
|
||||
#define AM35X_INTR_TX_SHIFT 0
|
||||
#define AM35X_TX_EP_MASK 0xffff /* EP0 + 15 Tx EPs */
|
||||
#define AM35X_RX_EP_MASK 0xfffe /* 15 Rx EPs */
|
||||
#define AM35X_TX_INTR_MASK (AM35X_TX_EP_MASK << AM35X_INTR_TX_SHIFT)
|
||||
#define AM35X_RX_INTR_MASK (AM35X_RX_EP_MASK << AM35X_INTR_RX_SHIFT)
|
||||
|
||||
#define USB_MENTOR_CORE_OFFSET 0x400
|
||||
|
||||
static inline void phy_on(void)
|
||||
{
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(100);
|
||||
u32 devconf2;
|
||||
|
||||
/*
|
||||
* Start the on-chip PHY and its PLL.
|
||||
*/
|
||||
devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
|
||||
|
||||
devconf2 &= ~(CONF2_RESET | CONF2_PHYPWRDN | CONF2_OTGPWRDN);
|
||||
devconf2 |= CONF2_PHY_PLLON;
|
||||
|
||||
omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
|
||||
|
||||
DBG(1, "Waiting for PHY clock good...\n");
|
||||
while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2)
|
||||
& CONF2_PHYCLKGD)) {
|
||||
cpu_relax();
|
||||
|
||||
if (time_after(jiffies, timeout)) {
|
||||
DBG(1, "musb PHY clock good timed out\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void phy_off(void)
|
||||
{
|
||||
u32 devconf2;
|
||||
|
||||
/*
|
||||
* Power down the on-chip PHY.
|
||||
*/
|
||||
devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
|
||||
|
||||
devconf2 &= ~CONF2_PHY_PLLON;
|
||||
devconf2 |= CONF2_PHYPWRDN | CONF2_OTGPWRDN;
|
||||
omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
|
||||
}
|
||||
|
||||
/*
|
||||
* musb_platform_enable - enable interrupts
|
||||
*/
|
||||
void musb_platform_enable(struct musb *musb)
|
||||
{
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
u32 epmask;
|
||||
|
||||
/* Workaround: setup IRQs through both register sets. */
|
||||
epmask = ((musb->epmask & AM35X_TX_EP_MASK) << AM35X_INTR_TX_SHIFT) |
|
||||
((musb->epmask & AM35X_RX_EP_MASK) << AM35X_INTR_RX_SHIFT);
|
||||
|
||||
musb_writel(reg_base, EP_INTR_MASK_SET_REG, epmask);
|
||||
musb_writel(reg_base, CORE_INTR_MASK_SET_REG, AM35X_INTR_USB_MASK);
|
||||
|
||||
/* Force the DRVVBUS IRQ so we can start polling for ID change. */
|
||||
if (is_otg_enabled(musb))
|
||||
musb_writel(reg_base, CORE_INTR_SRC_SET_REG,
|
||||
AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT);
|
||||
}
|
||||
|
||||
/*
|
||||
* musb_platform_disable - disable HDRC and flush interrupts
|
||||
*/
|
||||
void musb_platform_disable(struct musb *musb)
|
||||
{
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
|
||||
musb_writel(reg_base, CORE_INTR_MASK_CLEAR_REG, AM35X_INTR_USB_MASK);
|
||||
musb_writel(reg_base, EP_INTR_MASK_CLEAR_REG,
|
||||
AM35X_TX_INTR_MASK | AM35X_RX_INTR_MASK);
|
||||
musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
|
||||
musb_writel(reg_base, USB_END_OF_INTR_REG, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USB_MUSB_HDRC_HCD
|
||||
#define portstate(stmt) stmt
|
||||
#else
|
||||
#define portstate(stmt)
|
||||
#endif
|
||||
|
||||
static void am35x_set_vbus(struct musb *musb, int is_on)
|
||||
{
|
||||
WARN_ON(is_on && is_peripheral_active(musb));
|
||||
}
|
||||
|
||||
#define POLL_SECONDS 2
|
||||
|
||||
static struct timer_list otg_workaround;
|
||||
|
||||
static void otg_timer(unsigned long _musb)
|
||||
{
|
||||
struct musb *musb = (void *)_musb;
|
||||
void __iomem *mregs = musb->mregs;
|
||||
u8 devctl;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* We poll because AM35x's won't expose several OTG-critical
|
||||
* status change events (from the transceiver) otherwise.
|
||||
*/
|
||||
devctl = musb_readb(mregs, MUSB_DEVCTL);
|
||||
DBG(7, "Poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
|
||||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
switch (musb->xceiv->state) {
|
||||
case OTG_STATE_A_WAIT_BCON:
|
||||
devctl &= ~MUSB_DEVCTL_SESSION;
|
||||
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
|
||||
|
||||
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
|
||||
if (devctl & MUSB_DEVCTL_BDEVICE) {
|
||||
musb->xceiv->state = OTG_STATE_B_IDLE;
|
||||
MUSB_DEV_MODE(musb);
|
||||
} else {
|
||||
musb->xceiv->state = OTG_STATE_A_IDLE;
|
||||
MUSB_HST_MODE(musb);
|
||||
}
|
||||
break;
|
||||
case OTG_STATE_A_WAIT_VFALL:
|
||||
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
|
||||
musb_writel(musb->ctrl_base, CORE_INTR_SRC_SET_REG,
|
||||
MUSB_INTR_VBUSERROR << AM35X_INTR_USB_SHIFT);
|
||||
break;
|
||||
case OTG_STATE_B_IDLE:
|
||||
if (!is_peripheral_enabled(musb))
|
||||
break;
|
||||
|
||||
devctl = musb_readb(mregs, MUSB_DEVCTL);
|
||||
if (devctl & MUSB_DEVCTL_BDEVICE)
|
||||
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
|
||||
else
|
||||
musb->xceiv->state = OTG_STATE_A_IDLE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
}
|
||||
|
||||
void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
|
||||
{
|
||||
static unsigned long last_timer;
|
||||
|
||||
if (!is_otg_enabled(musb))
|
||||
return;
|
||||
|
||||
if (timeout == 0)
|
||||
timeout = jiffies + msecs_to_jiffies(3);
|
||||
|
||||
/* Never idle if active, or when VBUS timeout is not set as host */
|
||||
if (musb->is_active || (musb->a_wait_bcon == 0 &&
|
||||
musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
|
||||
DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
|
||||
del_timer(&otg_workaround);
|
||||
last_timer = jiffies;
|
||||
return;
|
||||
}
|
||||
|
||||
if (time_after(last_timer, timeout) && timer_pending(&otg_workaround)) {
|
||||
DBG(4, "Longer idle timer already pending, ignoring...\n");
|
||||
return;
|
||||
}
|
||||
last_timer = timeout;
|
||||
|
||||
DBG(4, "%s inactive, starting idle timer for %u ms\n",
|
||||
otg_state_string(musb), jiffies_to_msecs(timeout - jiffies));
|
||||
mod_timer(&otg_workaround, timeout);
|
||||
}
|
||||
|
||||
static irqreturn_t am35x_interrupt(int irq, void *hci)
|
||||
{
|
||||
struct musb *musb = hci;
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
unsigned long flags;
|
||||
irqreturn_t ret = IRQ_NONE;
|
||||
u32 epintr, usbintr, lvl_intr;
|
||||
|
||||
spin_lock_irqsave(&musb->lock, flags);
|
||||
|
||||
/* Get endpoint interrupts */
|
||||
epintr = musb_readl(reg_base, EP_INTR_SRC_MASKED_REG);
|
||||
|
||||
if (epintr) {
|
||||
musb_writel(reg_base, EP_INTR_SRC_CLEAR_REG, epintr);
|
||||
|
||||
musb->int_rx =
|
||||
(epintr & AM35X_RX_INTR_MASK) >> AM35X_INTR_RX_SHIFT;
|
||||
musb->int_tx =
|
||||
(epintr & AM35X_TX_INTR_MASK) >> AM35X_INTR_TX_SHIFT;
|
||||
}
|
||||
|
||||
/* Get usb core interrupts */
|
||||
usbintr = musb_readl(reg_base, CORE_INTR_SRC_MASKED_REG);
|
||||
if (!usbintr && !epintr)
|
||||
goto eoi;
|
||||
|
||||
if (usbintr) {
|
||||
musb_writel(reg_base, CORE_INTR_SRC_CLEAR_REG, usbintr);
|
||||
|
||||
musb->int_usb =
|
||||
(usbintr & AM35X_INTR_USB_MASK) >> AM35X_INTR_USB_SHIFT;
|
||||
}
|
||||
/*
|
||||
* DRVVBUS IRQs are the only proxy we have (a very poor one!) for
|
||||
* AM35x's missing ID change IRQ. We need an ID change IRQ to
|
||||
* switch appropriately between halves of the OTG state machine.
|
||||
* Managing DEVCTL.SESSION per Mentor docs requires that we know its
|
||||
* value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set.
|
||||
* Also, DRVVBUS pulses for SRP (but not at 5V) ...
|
||||
*/
|
||||
if (usbintr & (AM35X_INTR_DRVVBUS << AM35X_INTR_USB_SHIFT)) {
|
||||
int drvvbus = musb_readl(reg_base, USB_STAT_REG);
|
||||
void __iomem *mregs = musb->mregs;
|
||||
u8 devctl = musb_readb(mregs, MUSB_DEVCTL);
|
||||
int err;
|
||||
|
||||
err = is_host_enabled(musb) && (musb->int_usb &
|
||||
MUSB_INTR_VBUSERROR);
|
||||
if (err) {
|
||||
/*
|
||||
* The Mentor core doesn't debounce VBUS as needed
|
||||
* to cope with device connect current spikes. This
|
||||
* means it's not uncommon for bus-powered devices
|
||||
* to get VBUS errors during enumeration.
|
||||
*
|
||||
* This is a workaround, but newer RTL from Mentor
|
||||
* seems to allow a better one: "re"-starting sessions
|
||||
* without waiting for VBUS to stop registering in
|
||||
* devctl.
|
||||
*/
|
||||
musb->int_usb &= ~MUSB_INTR_VBUSERROR;
|
||||
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
|
||||
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
|
||||
WARNING("VBUS error workaround (delay coming)\n");
|
||||
} else if (is_host_enabled(musb) && drvvbus) {
|
||||
MUSB_HST_MODE(musb);
|
||||
musb->xceiv->default_a = 1;
|
||||
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
|
||||
portstate(musb->port1_status |= USB_PORT_STAT_POWER);
|
||||
del_timer(&otg_workaround);
|
||||
} else {
|
||||
musb->is_active = 0;
|
||||
MUSB_DEV_MODE(musb);
|
||||
musb->xceiv->default_a = 0;
|
||||
musb->xceiv->state = OTG_STATE_B_IDLE;
|
||||
portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
|
||||
}
|
||||
|
||||
/* NOTE: this must complete power-on within 100 ms. */
|
||||
DBG(2, "VBUS %s (%s)%s, devctl %02x\n",
|
||||
drvvbus ? "on" : "off",
|
||||
otg_state_string(musb),
|
||||
err ? " ERROR" : "",
|
||||
devctl);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (musb->int_tx || musb->int_rx || musb->int_usb)
|
||||
ret |= musb_interrupt(musb);
|
||||
|
||||
eoi:
|
||||
/* EOI needs to be written for the IRQ to be re-asserted. */
|
||||
if (ret == IRQ_HANDLED || epintr || usbintr) {
|
||||
/* clear level interrupt */
|
||||
lvl_intr = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
|
||||
lvl_intr |= AM35XX_USBOTGSS_INT_CLR;
|
||||
omap_ctrl_writel(lvl_intr, AM35XX_CONTROL_LVL_INTR_CLEAR);
|
||||
/* write EOI */
|
||||
musb_writel(reg_base, USB_END_OF_INTR_REG, 0);
|
||||
}
|
||||
|
||||
/* Poll for ID change */
|
||||
if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE)
|
||||
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
|
||||
|
||||
spin_unlock_irqrestore(&musb->lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
|
||||
{
|
||||
u32 devconf2 = omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2);
|
||||
|
||||
devconf2 &= ~CONF2_OTGMODE;
|
||||
switch (musb_mode) {
|
||||
#ifdef CONFIG_USB_MUSB_HDRC_HCD
|
||||
case MUSB_HOST: /* Force VBUS valid, ID = 0 */
|
||||
devconf2 |= CONF2_FORCE_HOST;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
|
||||
case MUSB_PERIPHERAL: /* Force VBUS valid, ID = 1 */
|
||||
devconf2 |= CONF2_FORCE_DEVICE;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_USB_MUSB_OTG
|
||||
case MUSB_OTG: /* Don't override the VBUS/ID comparators */
|
||||
devconf2 |= CONF2_NO_OVERRIDE;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
DBG(2, "Trying to set unsupported mode %u\n", musb_mode);
|
||||
}
|
||||
|
||||
omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init musb_platform_init(struct musb *musb, void *board_data)
|
||||
{
|
||||
void __iomem *reg_base = musb->ctrl_base;
|
||||
u32 rev, lvl_intr, sw_reset;
|
||||
int status;
|
||||
|
||||
musb->mregs += USB_MENTOR_CORE_OFFSET;
|
||||
|
||||
clk_enable(musb->clock);
|
||||
DBG(2, "musb->clock=%lud\n", clk_get_rate(musb->clock));
|
||||
|
||||
musb->phy_clock = clk_get(musb->controller, "fck");
|
||||
if (IS_ERR(musb->phy_clock)) {
|
||||
status = PTR_ERR(musb->phy_clock);
|
||||
goto exit0;
|
||||
}
|
||||
clk_enable(musb->phy_clock);
|
||||
DBG(2, "musb->phy_clock=%lud\n", clk_get_rate(musb->phy_clock));
|
||||
|
||||
/* Returns zero if e.g. not clocked */
|
||||
rev = musb_readl(reg_base, USB_REVISION_REG);
|
||||
if (!rev) {
|
||||
status = -ENODEV;
|
||||
goto exit1;
|
||||
}
|
||||
|
||||
usb_nop_xceiv_register();
|
||||
musb->xceiv = otg_get_transceiver();
|
||||
if (!musb->xceiv) {
|
||||
status = -ENODEV;
|
||||
goto exit1;
|
||||
}
|
||||
|
||||
if (is_host_enabled(musb))
|
||||
setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
|
||||
|
||||
musb->board_set_vbus = am35x_set_vbus;
|
||||
|
||||
/* Global reset */
|
||||
sw_reset = omap_ctrl_readl(AM35XX_CONTROL_IP_SW_RESET);
|
||||
|
||||
sw_reset |= AM35XX_USBOTGSS_SW_RST;
|
||||
omap_ctrl_writel(sw_reset, AM35XX_CONTROL_IP_SW_RESET);
|
||||
|
||||
sw_reset &= ~AM35XX_USBOTGSS_SW_RST;
|
||||
omap_ctrl_writel(sw_reset, AM35XX_CONTROL_IP_SW_RESET);
|
||||
|
||||
/* Reset the controller */
|
||||
musb_writel(reg_base, USB_CTRL_REG, AM35X_SOFT_RESET_MASK);
|
||||
|
||||
/* Start the on-chip PHY and its PLL. */
|
||||
phy_on();
|
||||
|
||||
msleep(5);
|
||||
|
||||
musb->isr = am35x_interrupt;
|
||||
|
||||
/* clear level interrupt */
|
||||
lvl_intr = omap_ctrl_readl(AM35XX_CONTROL_LVL_INTR_CLEAR);
|
||||
lvl_intr |= AM35XX_USBOTGSS_INT_CLR;
|
||||
omap_ctrl_writel(lvl_intr, AM35XX_CONTROL_LVL_INTR_CLEAR);
|
||||
return 0;
|
||||
exit1:
|
||||
clk_disable(musb->phy_clock);
|
||||
clk_put(musb->phy_clock);
|
||||
exit0:
|
||||
clk_disable(musb->clock);
|
||||
return status;
|
||||
}
|
||||
|
||||
int musb_platform_exit(struct musb *musb)
|
||||
{
|
||||
if (is_host_enabled(musb))
|
||||
del_timer_sync(&otg_workaround);
|
||||
|
||||
phy_off();
|
||||
|
||||
otg_put_transceiver(musb->xceiv);
|
||||
usb_nop_xceiv_unregister();
|
||||
|
||||
clk_disable(musb->clock);
|
||||
|
||||
clk_disable(musb->phy_clock);
|
||||
clk_put(musb->phy_clock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
void musb_platform_save_context(struct musb *musb,
|
||||
struct musb_context_registers *musb_context)
|
||||
{
|
||||
phy_off();
|
||||
}
|
||||
|
||||
void musb_platform_restore_context(struct musb *musb,
|
||||
struct musb_context_registers *musb_context)
|
||||
{
|
||||
phy_on();
|
||||
}
|
||||
#endif
|
||||
|
||||
/* AM35x supports only 32bit read operation */
|
||||
void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
|
||||
{
|
||||
void __iomem *fifo = hw_ep->fifo;
|
||||
u32 val;
|
||||
int i;
|
||||
|
||||
/* Read for 32bit-aligned destination address */
|
||||
if (likely((0x03 & (unsigned long) dst) == 0) && len >= 4) {
|
||||
readsl(fifo, dst, len >> 2);
|
||||
dst += len & ~0x03;
|
||||
len &= 0x03;
|
||||
}
|
||||
/*
|
||||
* Now read the remaining 1 to 3 byte or complete length if
|
||||
* unaligned address.
|
||||
*/
|
||||
if (len > 4) {
|
||||
for (i = 0; i < (len >> 2); i++) {
|
||||
*(u32 *) dst = musb_readl(fifo, 0);
|
||||
dst += 4;
|
||||
}
|
||||
len &= 0x03;
|
||||
}
|
||||
if (len > 0) {
|
||||
val = musb_readl(fifo, 0);
|
||||
memcpy(dst, &val, len);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue