Archived
14
0
Fork 0
This repository has been archived on 2022-02-17. You can view files and clone it, but cannot push or open issues or pull requests.
linux-2.6/drivers/staging/bcm/InterfaceInit.c
Kevin McKinney 41c7b7c0fa Staging: bcm: Fix information leak in ioctl: IOCTL_BCM_REGISTER_READ_PRIVATE, IOCTL_BCM_EEPROM_REGISTER_READ
This patch fixes an information leak in ioctl
IOCTL_BCM_REGISTER_READ_PRIVATE and
IOCTL_BCM_EEPROM_REGISTER_READ when determining
the number of bytes to copy to user space.  Function,
usb_control_msg, returns the correct number of
bytes from the hardware.  Instead of using
this value, we were using a value derived from
user space. In this case, this value could be more
than the hardware allocated.  Therefore, this
patch copies the proper number of bytes from
the hardware, and uses this value as the maximum
number of bytes for user space.

Signed-off-by: Kevin McKinney <klmckinney1@gmail.com>
Reviewed-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
2011-11-26 17:11:58 -08:00

696 lines
23 KiB
C

#include "headers.h"
static struct usb_device_id InterfaceUsbtable[] = {
{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3B) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_T3L) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_T3, BCM_USB_PRODUCT_ID_SM250) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) },
{ USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_TU25) },
{ }
};
MODULE_DEVICE_TABLE(usb, InterfaceUsbtable);
static int debug = -1;
module_param(debug, uint, 0600);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
static const u32 default_msg =
NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK
| NETIF_MSG_TIMER | NETIF_MSG_TX_ERR | NETIF_MSG_RX_ERR
| NETIF_MSG_IFUP | NETIF_MSG_IFDOWN;
static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER Adapter);
static void InterfaceAdapterFree(PS_INTERFACE_ADAPTER psIntfAdapter)
{
int i = 0;
/* Wake up the wait_queue... */
if (psIntfAdapter->psAdapter->LEDInfo.led_thread_running & BCM_LED_THREAD_RUNNING_ACTIVELY) {
psIntfAdapter->psAdapter->DriverState = DRIVER_HALT;
wake_up(&psIntfAdapter->psAdapter->LEDInfo.notify_led_event);
}
reset_card_proc(psIntfAdapter->psAdapter);
/*
* worst case time taken by the RDM/WRM will be 5 sec. will check after every 100 ms
* to accertain the device is not being accessed. After this No RDM/WRM should be made.
*/
while (psIntfAdapter->psAdapter->DeviceAccess) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"Device is being accessed.\n");
msleep(100);
}
/* Free interrupt URB */
/* psIntfAdapter->psAdapter->device_removed = TRUE; */
usb_free_urb(psIntfAdapter->psInterruptUrb);
/* Free transmit URBs */
for (i = 0; i < MAXIMUM_USB_TCB; i++) {
if (psIntfAdapter->asUsbTcb[i].urb != NULL) {
usb_free_urb(psIntfAdapter->asUsbTcb[i].urb);
psIntfAdapter->asUsbTcb[i].urb = NULL;
}
}
/* Free receive URB and buffers */
for (i = 0; i < MAXIMUM_USB_RCB; i++) {
if (psIntfAdapter->asUsbRcb[i].urb != NULL) {
kfree(psIntfAdapter->asUsbRcb[i].urb->transfer_buffer);
usb_free_urb(psIntfAdapter->asUsbRcb[i].urb);
psIntfAdapter->asUsbRcb[i].urb = NULL;
}
}
AdapterFree(psIntfAdapter->psAdapter);
}
static void ConfigureEndPointTypesThroughEEPROM(PMINI_ADAPTER Adapter)
{
unsigned long ulReg = 0;
int bytes;
/* Program EP2 MAX_PKT_SIZE */
ulReg = ntohl(EP2_MPS_REG);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x128, 4, TRUE);
ulReg = ntohl(EP2_MPS);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x12C, 4, TRUE);
ulReg = ntohl(EP2_CFG_REG);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x132, 4, TRUE);
if (((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter))->bHighSpeedDevice == TRUE) {
ulReg = ntohl(EP2_CFG_INT);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE);
} else {
/* USE BULK EP as TX in FS mode. */
ulReg = ntohl(EP2_CFG_BULK);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x136, 4, TRUE);
}
/* Program EP4 MAX_PKT_SIZE. */
ulReg = ntohl(EP4_MPS_REG);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x13C, 4, TRUE);
ulReg = ntohl(EP4_MPS);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x140, 4, TRUE);
/* Program TX EP as interrupt(Alternate Setting) */
bytes = rdmalt(Adapter, 0x0F0110F8, (u32 *)&ulReg, sizeof(u32));
if (bytes < 0) {
BCM_DEBUG_PRINT(Adapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"reading of Tx EP failed\n");
return;
}
ulReg |= 0x6;
ulReg = ntohl(ulReg);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1CC, 4, TRUE);
ulReg = ntohl(EP4_CFG_REG);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C8, 4, TRUE);
/* Program ISOCHRONOUS EP size to zero. */
ulReg = ntohl(ISO_MPS_REG);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D2, 4, TRUE);
ulReg = ntohl(ISO_MPS);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1D6, 4, TRUE);
/*
* Update EEPROM Version.
* Read 4 bytes from 508 and modify 511 and 510.
*/
ReadBeceemEEPROM(Adapter, 0x1FC, (PUINT)&ulReg);
ulReg &= 0x0101FFFF;
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1FC, 4, TRUE);
/* Update length field if required. Also make the string NULL terminated. */
ReadBeceemEEPROM(Adapter, 0xA8, (PUINT)&ulReg);
if ((ulReg&0x00FF0000)>>16 > 0x30) {
ulReg = (ulReg&0xFF00FFFF)|(0x30<<16);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0xA8, 4, TRUE);
}
ReadBeceemEEPROM(Adapter, 0x148, (PUINT)&ulReg);
if ((ulReg&0x00FF0000)>>16 > 0x30) {
ulReg = (ulReg&0xFF00FFFF)|(0x30<<16);
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x148, 4, TRUE);
}
ulReg = 0;
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x122, 4, TRUE);
ulReg = 0;
BeceemEEPROMBulkWrite(Adapter, (PUCHAR)&ulReg, 0x1C2, 4, TRUE);
}
static int usbbcm_device_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
int retval;
PMINI_ADAPTER psAdapter;
PS_INTERFACE_ADAPTER psIntfAdapter;
struct net_device *ndev;
/* Reserve one extra queue for the bit-bucket */
ndev = alloc_etherdev_mq(sizeof(MINI_ADAPTER), NO_OF_QUEUES+1);
if (ndev == NULL) {
dev_err(&udev->dev, DRV_NAME ": no memory for device\n");
return -ENOMEM;
}
SET_NETDEV_DEV(ndev, &intf->dev);
psAdapter = netdev_priv(ndev);
psAdapter->dev = ndev;
psAdapter->msg_enable = netif_msg_init(debug, default_msg);
/* Init default driver debug state */
psAdapter->stDebugState.debug_level = DBG_LVL_CURR;
psAdapter->stDebugState.type = DBG_TYPE_INITEXIT;
/*
* Technically, one can start using BCM_DEBUG_PRINT after this point.
* However, realize that by default the Type/Subtype bitmaps are all zero now;
* so no prints will actually appear until the TestApp turns on debug paths via
* the ioctl(); so practically speaking, in early init, no logging happens.
*
* A solution (used below): we explicitly set the bitmaps to 1 for Type=DBG_TYPE_INITEXIT
* and ALL subtype's of the same. Now all bcm debug statements get logged, enabling debug
* during early init.
* Further, we turn this OFF once init_module() completes.
*/
psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0xff;
BCM_SHOW_DEBUG_BITMAP(psAdapter);
retval = InitAdapter(psAdapter);
if (retval) {
dev_err(&udev->dev, DRV_NAME ": InitAdapter Failed\n");
AdapterFree(psAdapter);
return retval;
}
/* Allocate interface adapter structure */
psIntfAdapter = kzalloc(sizeof(S_INTERFACE_ADAPTER), GFP_KERNEL);
if (psIntfAdapter == NULL) {
dev_err(&udev->dev, DRV_NAME ": no memory for Interface adapter\n");
AdapterFree(psAdapter);
return -ENOMEM;
}
psAdapter->pvInterfaceAdapter = psIntfAdapter;
psIntfAdapter->psAdapter = psAdapter;
/* Store usb interface in Interface Adapter */
psIntfAdapter->interface = intf;
usb_set_intfdata(intf, psIntfAdapter);
BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"psIntfAdapter 0x%p\n", psIntfAdapter);
retval = InterfaceAdapterInit(psIntfAdapter);
if (retval) {
/* If the Firmware/Cfg File is not present
* then return success, let the application
* download the files.
*/
if (-ENOENT == retval) {
BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"File Not Found. Use app to download.\n");
return STATUS_SUCCESS;
}
BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"InterfaceAdapterInit failed.\n");
usb_set_intfdata(intf, NULL);
udev = interface_to_usbdev(intf);
usb_put_dev(udev);
InterfaceAdapterFree(psIntfAdapter);
return retval;
}
if (psAdapter->chip_id > T3) {
uint32_t uiNackZeroLengthInt = 4;
retval = wrmalt(psAdapter, DISABLE_USB_ZERO_LEN_INT, &uiNackZeroLengthInt, sizeof(uiNackZeroLengthInt));
if (retval)
return retval;
}
/* Check whether the USB-Device Supports remote Wake-Up */
if (USB_CONFIG_ATT_WAKEUP & udev->actconfig->desc.bmAttributes) {
/* If Suspend then only support dynamic suspend */
if (psAdapter->bDoSuspend) {
#ifdef CONFIG_PM
pm_runtime_set_autosuspend_delay(&udev->dev, 0);
intf->needs_remote_wakeup = 1;
usb_enable_autosuspend(udev);
device_init_wakeup(&intf->dev, 1);
INIT_WORK(&psIntfAdapter->usbSuspendWork, putUsbSuspend);
BCM_DEBUG_PRINT(psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"Enabling USB Auto-Suspend\n");
#endif
} else {
intf->needs_remote_wakeup = 0;
usb_disable_autosuspend(udev);
}
}
psAdapter->stDebugState.subtype[DBG_TYPE_INITEXIT] = 0x0;
return retval;
}
static void usbbcm_disconnect(struct usb_interface *intf)
{
PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
PMINI_ADAPTER psAdapter;
struct usb_device *udev = interface_to_usbdev(intf);
if (psIntfAdapter == NULL)
return;
psAdapter = psIntfAdapter->psAdapter;
netif_device_detach(psAdapter->dev);
if (psAdapter->bDoSuspend)
intf->needs_remote_wakeup = 0;
psAdapter->device_removed = TRUE ;
usb_set_intfdata(intf, NULL);
InterfaceAdapterFree(psIntfAdapter);
usb_put_dev(udev);
}
static int AllocUsbCb(PS_INTERFACE_ADAPTER psIntfAdapter)
{
int i = 0;
for (i = 0; i < MAXIMUM_USB_TCB; i++) {
psIntfAdapter->asUsbTcb[i].urb = usb_alloc_urb(0, GFP_KERNEL);
if (psIntfAdapter->asUsbTcb[i].urb == NULL) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
"Can't allocate Tx urb for index %d\n", i);
return -ENOMEM;
}
}
for (i = 0; i < MAXIMUM_USB_RCB; i++) {
psIntfAdapter->asUsbRcb[i].urb = usb_alloc_urb(0, GFP_KERNEL);
if (psIntfAdapter->asUsbRcb[i].urb == NULL) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
"Can't allocate Rx urb for index %d\n", i);
return -ENOMEM;
}
psIntfAdapter->asUsbRcb[i].urb->transfer_buffer = kmalloc(MAX_DATA_BUFFER_SIZE, GFP_KERNEL);
if (psIntfAdapter->asUsbRcb[i].urb->transfer_buffer == NULL) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
"Can't allocate Rx buffer for index %d\n", i);
return -ENOMEM;
}
psIntfAdapter->asUsbRcb[i].urb->transfer_buffer_length = MAX_DATA_BUFFER_SIZE;
}
return 0;
}
static int device_run(PS_INTERFACE_ADAPTER psIntfAdapter)
{
int value = 0;
UINT status = STATUS_SUCCESS;
status = InitCardAndDownloadFirmware(psIntfAdapter->psAdapter);
if (status != STATUS_SUCCESS) {
pr_err(DRV_NAME "InitCardAndDownloadFirmware failed.\n");
return status;
}
if (TRUE == psIntfAdapter->psAdapter->fw_download_done) {
if (StartInterruptUrb(psIntfAdapter)) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"Cannot send interrupt in URB\n");
}
/*
* now register the cntrl interface.
* after downloading the f/w waiting for 5 sec to get the mailbox interrupt.
*/
psIntfAdapter->psAdapter->waiting_to_fw_download_done = FALSE;
value = wait_event_timeout(psIntfAdapter->psAdapter->ioctl_fw_dnld_wait_queue,
psIntfAdapter->psAdapter->waiting_to_fw_download_done, 5*HZ);
if (value == 0)
pr_err(DRV_NAME ": Timeout waiting for mailbox interrupt.\n");
if (register_control_device_interface(psIntfAdapter->psAdapter) < 0) {
pr_err(DRV_NAME ": Register Control Device failed.\n");
return -EIO;
}
}
return 0;
}
static inline int bcm_usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
{
return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
}
static inline int bcm_usb_endpoint_type(const struct usb_endpoint_descriptor *epd)
{
return epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
}
static inline int bcm_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
{
return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);
}
static inline int bcm_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
{
return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
}
static inline int bcm_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_BULK);
}
static inline int bcm_usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_CONTROL);
}
static inline int bcm_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_INT);
}
static inline int bcm_usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd)
{
return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
USB_ENDPOINT_XFER_ISOC);
}
static inline int bcm_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
{
return bcm_usb_endpoint_xfer_bulk(epd) && bcm_usb_endpoint_dir_in(epd);
}
static inline int bcm_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
{
return bcm_usb_endpoint_xfer_bulk(epd) && bcm_usb_endpoint_dir_out(epd);
}
static inline int bcm_usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
{
return bcm_usb_endpoint_xfer_int(epd) && bcm_usb_endpoint_dir_in(epd);
}
static inline int bcm_usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd)
{
return bcm_usb_endpoint_xfer_int(epd) && bcm_usb_endpoint_dir_out(epd);
}
static inline int bcm_usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd)
{
return bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_in(epd);
}
static inline int bcm_usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd)
{
return bcm_usb_endpoint_xfer_isoc(epd) && bcm_usb_endpoint_dir_out(epd);
}
static int InterfaceAdapterInit(PS_INTERFACE_ADAPTER psIntfAdapter)
{
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
size_t buffer_size;
unsigned long value;
int retval = 0;
int usedIntOutForBulkTransfer = 0 ;
BOOLEAN bBcm16 = FALSE;
UINT uiData = 0;
int bytes;
/* Store the usb dev into interface adapter */
psIntfAdapter->udev = usb_get_dev(interface_to_usbdev(psIntfAdapter->interface));
psIntfAdapter->bHighSpeedDevice = (psIntfAdapter->udev->speed == USB_SPEED_HIGH);
psIntfAdapter->psAdapter->interface_rdm = BcmRDM;
psIntfAdapter->psAdapter->interface_wrm = BcmWRM;
bytes = rdmalt(psIntfAdapter->psAdapter, CHIP_ID_REG,
(u32 *)&(psIntfAdapter->psAdapter->chip_id), sizeof(u32));
if (bytes < 0) {
retval = bytes;
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0, "CHIP ID Read Failed\n");
return retval;
}
if (0xbece3200 == (psIntfAdapter->psAdapter->chip_id & ~(0xF0)))
psIntfAdapter->psAdapter->chip_id &= ~0xF0;
dev_info(&psIntfAdapter->udev->dev, "RDM Chip ID 0x%lx\n",
psIntfAdapter->psAdapter->chip_id);
iface_desc = psIntfAdapter->interface->cur_altsetting;
if (psIntfAdapter->psAdapter->chip_id == T3B) {
/* T3B device will have EEPROM, check if EEPROM is proper and BCM16 can be done or not. */
BeceemEEPROMBulkRead(psIntfAdapter->psAdapter, &uiData, 0x0, 4);
if (uiData == BECM)
bBcm16 = TRUE;
dev_info(&psIntfAdapter->udev->dev, "number of alternate setting %d\n",
psIntfAdapter->interface->num_altsetting);
if (bBcm16 == TRUE) {
/* selecting alternate setting one as a default setting for High Speed modem. */
if (psIntfAdapter->bHighSpeedDevice)
retval = usb_set_interface(psIntfAdapter->udev, DEFAULT_SETTING_0, ALTERNATE_SETTING_1);
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"BCM16 is applicable on this dongle\n");
if (retval || (psIntfAdapter->bHighSpeedDevice == FALSE)) {
usedIntOutForBulkTransfer = EP2 ;
endpoint = &iface_desc->endpoint[EP2].desc;
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"Interface altsetting failed or modem is configured to Full Speed, hence will work on default setting 0\n");
/*
* If Modem is high speed device EP2 should be INT OUT End point
* If Mode is FS then EP2 should be bulk end point
*/
if (((psIntfAdapter->bHighSpeedDevice == TRUE) && (bcm_usb_endpoint_is_int_out(endpoint) == FALSE))
|| ((psIntfAdapter->bHighSpeedDevice == FALSE) && (bcm_usb_endpoint_is_bulk_out(endpoint) == FALSE))) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"Configuring the EEPROM\n");
/* change the EP2, EP4 to INT OUT end point */
ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter);
/*
* It resets the device and if any thing gets changed
* in USB descriptor it will show fail and re-enumerate
* the device
*/
retval = usb_reset_device(psIntfAdapter->udev);
if (retval) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"reset failed. Re-enumerating the device.\n");
return retval ;
}
}
if ((psIntfAdapter->bHighSpeedDevice == FALSE) && bcm_usb_endpoint_is_bulk_out(endpoint)) {
/* Once BULK is selected in FS mode. Revert it back to INT. Else USB_IF will fail. */
UINT _uiData = ntohl(EP2_CFG_INT);
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"Reverting Bulk to INT as it is in Full Speed mode.\n");
BeceemEEPROMBulkWrite(psIntfAdapter->psAdapter, (PUCHAR)&_uiData, 0x136, 4, TRUE);
}
} else {
usedIntOutForBulkTransfer = EP4 ;
endpoint = &iface_desc->endpoint[EP4].desc;
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"Choosing AltSetting as a default setting.\n");
if (bcm_usb_endpoint_is_int_out(endpoint) == FALSE) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"Dongle does not have BCM16 Fix.\n");
/* change the EP2, EP4 to INT OUT end point and use EP4 in altsetting */
ConfigureEndPointTypesThroughEEPROM(psIntfAdapter->psAdapter);
/*
* It resets the device and if any thing gets changed in
* USB descriptor it will show fail and re-enumerate the
* device
*/
retval = usb_reset_device(psIntfAdapter->udev);
if (retval) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"reset failed. Re-enumerating the device.\n");
return retval;
}
}
}
}
}
iface_desc = psIntfAdapter->interface->cur_altsetting;
for (value = 0; value < iface_desc->desc.bNumEndpoints; ++value) {
endpoint = &iface_desc->endpoint[value].desc;
if (!psIntfAdapter->sBulkIn.bulk_in_endpointAddr && bcm_usb_endpoint_is_bulk_in(endpoint)) {
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
psIntfAdapter->sBulkIn.bulk_in_size = buffer_size;
psIntfAdapter->sBulkIn.bulk_in_endpointAddr = endpoint->bEndpointAddress;
psIntfAdapter->sBulkIn.bulk_in_pipe =
usb_rcvbulkpipe(psIntfAdapter->udev,
psIntfAdapter->sBulkIn.bulk_in_endpointAddr);
}
if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr && bcm_usb_endpoint_is_bulk_out(endpoint)) {
psIntfAdapter->sBulkOut.bulk_out_endpointAddr = endpoint->bEndpointAddress;
psIntfAdapter->sBulkOut.bulk_out_pipe =
usb_sndbulkpipe(psIntfAdapter->udev,
psIntfAdapter->sBulkOut.bulk_out_endpointAddr);
}
if (!psIntfAdapter->sIntrIn.int_in_endpointAddr && bcm_usb_endpoint_is_int_in(endpoint)) {
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
psIntfAdapter->sIntrIn.int_in_size = buffer_size;
psIntfAdapter->sIntrIn.int_in_endpointAddr = endpoint->bEndpointAddress;
psIntfAdapter->sIntrIn.int_in_interval = endpoint->bInterval;
psIntfAdapter->sIntrIn.int_in_buffer =
kmalloc(buffer_size, GFP_KERNEL);
if (!psIntfAdapter->sIntrIn.int_in_buffer) {
dev_err(&psIntfAdapter->udev->dev,
"could not allocate interrupt_in_buffer\n");
return -EINVAL;
}
}
if (!psIntfAdapter->sIntrOut.int_out_endpointAddr && bcm_usb_endpoint_is_int_out(endpoint)) {
if (!psIntfAdapter->sBulkOut.bulk_out_endpointAddr &&
(psIntfAdapter->psAdapter->chip_id == T3B) && (value == usedIntOutForBulkTransfer)) {
/* use first intout end point as a bulk out end point */
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
psIntfAdapter->sBulkOut.bulk_out_size = buffer_size;
psIntfAdapter->sBulkOut.bulk_out_endpointAddr = endpoint->bEndpointAddress;
psIntfAdapter->sBulkOut.bulk_out_pipe = usb_sndintpipe(psIntfAdapter->udev,
psIntfAdapter->sBulkOut.bulk_out_endpointAddr);
psIntfAdapter->sBulkOut.int_out_interval = endpoint->bInterval;
} else if (value == EP6) {
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
psIntfAdapter->sIntrOut.int_out_size = buffer_size;
psIntfAdapter->sIntrOut.int_out_endpointAddr = endpoint->bEndpointAddress;
psIntfAdapter->sIntrOut.int_out_interval = endpoint->bInterval;
psIntfAdapter->sIntrOut.int_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
if (!psIntfAdapter->sIntrOut.int_out_buffer) {
dev_err(&psIntfAdapter->udev->dev,
"could not allocate interrupt_out_buffer\n");
return -EINVAL;
}
}
}
}
usb_set_intfdata(psIntfAdapter->interface, psIntfAdapter);
psIntfAdapter->psAdapter->bcm_file_download = InterfaceFileDownload;
psIntfAdapter->psAdapter->bcm_file_readback_from_chip =
InterfaceFileReadbackFromChip;
psIntfAdapter->psAdapter->interface_transmit = InterfaceTransmitPacket;
retval = CreateInterruptUrb(psIntfAdapter);
if (retval) {
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_PRINTK, 0, 0,
"Cannot create interrupt urb\n");
return retval;
}
retval = AllocUsbCb(psIntfAdapter);
if (retval)
return retval;
return device_run(psIntfAdapter);
}
static int InterfaceSuspend(struct usb_interface *intf, pm_message_t message)
{
PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
psIntfAdapter->bSuspended = TRUE;
if (TRUE == psIntfAdapter->bPreparingForBusSuspend) {
psIntfAdapter->bPreparingForBusSuspend = FALSE;
if (psIntfAdapter->psAdapter->LinkStatus == LINKUP_DONE) {
psIntfAdapter->psAdapter->IdleMode = TRUE ;
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"Host Entered in PMU Idle Mode.\n");
} else {
psIntfAdapter->psAdapter->bShutStatus = TRUE;
BCM_DEBUG_PRINT(psIntfAdapter->psAdapter, DBG_TYPE_INITEXIT, DRV_ENTRY, DBG_LVL_ALL,
"Host Entered in PMU Shutdown Mode.\n");
}
}
psIntfAdapter->psAdapter->bPreparingForLowPowerMode = FALSE;
/* Signaling the control pkt path */
wake_up(&psIntfAdapter->psAdapter->lowpower_mode_wait_queue);
return 0;
}
static int InterfaceResume(struct usb_interface *intf)
{
PS_INTERFACE_ADAPTER psIntfAdapter = usb_get_intfdata(intf);
mdelay(100);
psIntfAdapter->bSuspended = FALSE;
StartInterruptUrb(psIntfAdapter);
InterfaceRx(psIntfAdapter);
return 0;
}
static struct usb_driver usbbcm_driver = {
.name = "usbbcm",
.probe = usbbcm_device_probe,
.disconnect = usbbcm_disconnect,
.suspend = InterfaceSuspend,
.resume = InterfaceResume,
.id_table = InterfaceUsbtable,
.supports_autosuspend = 1,
};
struct class *bcm_class;
static __init int bcm_init(void)
{
printk(KERN_INFO "%s: %s, %s\n", DRV_NAME, DRV_DESCRIPTION, DRV_VERSION);
printk(KERN_INFO "%s\n", DRV_COPYRIGHT);
bcm_class = class_create(THIS_MODULE, DRV_NAME);
if (IS_ERR(bcm_class)) {
printk(KERN_ERR DRV_NAME ": could not create class\n");
return PTR_ERR(bcm_class);
}
return usb_register(&usbbcm_driver);
}
static __exit void bcm_exit(void)
{
usb_deregister(&usbbcm_driver);
class_destroy(bcm_class);
}
module_init(bcm_init);
module_exit(bcm_exit);
MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_VERSION(DRV_VERSION);
MODULE_LICENSE("GPL");