📄 hc_sl811_rh.c
字号:
/*-------------------------------------------------------------------------*/
/*-------------------------------------------------------------------------*
* SL811HS virtual root hub
*
* based on usb-ohci.c by R. Weissgaerber et al.
*-------------------------------------------------------------------------*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*-------------------------------------------------------------------------*/
#ifdef DEBUG
#undef DEBUG
#endif
static __u32 getPortStatusAndChange(hci_t *hci);
static void setPortStatus(hci_t *hci, __u16 bitPos);
static void setPortChange(hci_t *hci, __u16 bitPos);
static void clrPortStatus(hci_t *hci, __u16 bitPos);
static void clrPortChange(hci_t *hci, __u16 bitPos);
static int USBReset(hci_t *hci);
static int cc_to_error (int cc);
/*-------------------------------------------------------------------------*
* Virtual Root Hub
*-------------------------------------------------------------------------*/
/* Device descriptor */
static __u8 root_hub_dev_des[] =
{
0x12, /* __u8 bLength; */
0x01, /* __u8 bDescriptorType; Device */
0x10, /* __u16 bcdUSB; v1.1 */
0x01,
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
0x00, /* __u8 bDeviceSubClass; */
0x00, /* __u8 bDeviceProtocol; */
0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
0x00, /* __u16 idVendor; */
0x00,
0x00, /* __u16 idProduct; */
0x00,
0x00, /* __u16 bcdDevice; */
0x00,
0x00, /* __u8 iManufacturer; */
0x02, /* __u8 iProduct; */
0x01, /* __u8 iSerialNumber; */
0x01 /* __u8 bNumConfigurations; */
};
/* Configuration descriptor */
static __u8 root_hub_config_des[] =
{
0x09, /* __u8 bLength; */
0x02, /* __u8 bDescriptorType; Configuration */
0x19, /* __u16 wTotalLength; */
0x00,
0x01, /* __u8 bNumInterfaces; */
0x01, /* __u8 bConfigurationValue; */
0x00, /* __u8 iConfiguration; */
0x40, /* __u8 bmAttributes;
Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup,
4..0: resvd */
0x00, /* __u8 MaxPower; */
/* interface */
0x09, /* __u8 if_bLength; */
0x04, /* __u8 if_bDescriptorType; Interface */
0x00, /* __u8 if_bInterfaceNumber; */
0x00, /* __u8 if_bAlternateSetting; */
0x01, /* __u8 if_bNumEndpoints; */
0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
0x00, /* __u8 if_bInterfaceSubClass; */
0x00, /* __u8 if_bInterfaceProtocol; */
0x00, /* __u8 if_iInterface; */
/* endpoint */
0x07, /* __u8 ep_bLength; */
0x05, /* __u8 ep_bDescriptorType; Endpoint */
0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
0x03, /* __u8 ep_bmAttributes; Interrupt */
0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
0x00,
0xff /* __u8 ep_bInterval; 255 ms */
};
/* Hub class-specific descriptor is constructed dynamically */
/***************************************************************************
* Function Name : rh_send_irq
*
* This function examine the port change in the virtual root hub.
*
* Note: This function assumes only one port exist in the root hub.
*
* Input: hci = data structure for the host controller
* rh_data = The pointer to port change data
* rh_len = length of the data in bytes
*
* Return: length of data
**************************************************************************/
static int rh_send_irq (hci_t * hci, void * rh_data, int rh_len)
{
int num_ports;
int i;
int ret;
int len;
__u8 data[8];
DBGFUNC ("enter rh_send_irq: \n");
/* Assuming the root hub has one port. This value need to change if
* there are more than one port for the root hub
*/
num_ports = 1;
/* The root hub status is not implemented, it basically has two fields:
* -- Local Power Status
* -- Over Current Indicator
* -- Local Power Change
* -- Over Current Indicator
*
* Right now, It is assume the power is good and no changes
*/
*(__u8 *) data = 0;
ret = *(__u8 *) data;
/* Has the port status change within the root hub: It checks for
* -- Port Connect Status change
* -- Port Enable Change
*/
for ( i = 0; i < num_ports; i++)
{
*(__u8 *) (data + (i + 1) / 8) |= (((getPortStatusAndChange (hci) >> 16)
& (PORT_CONNECT_STAT | PORT_ENABLE_STAT)) ? 1: 0) <<
((i + 1) % 8);
ret += *(__u8 *) (data + (i + 1) / 8);
/* After the port change is read, it should be reset so the next time
* is it doesn't trigger a change again */
}
len = i/8 + 1;
if (ret > 0)
{
memcpy (rh_data, data, min (len, min (rh_len, sizeof(data))));
return len;
}
return 0;
}
/***************************************************************************
* Function Name : rh_int_timer_do
*
* This function is called when the timer expires. It gets the the port
* change data and pass along to the upper protocol.
*
* Note: The virtual root hub interrupt pipe are polled by the timer
* every "interval" ms
*
* Input: ptr = ptr to the urb
*
* Return: none
**************************************************************************/
static void rh_int_timer_do (unsigned long ptr)
{
int len;
urb_t * urb = (urb_t *) ptr;
hci_t * hci = urb->dev->bus->hcpriv;
DBGFUNC ("enter rh_int_timer_do\n");
if(hci->rh.send)
{
len = rh_send_irq (hci, urb->transfer_buffer,
urb->transfer_buffer_length);
if (len > 0)
{
urb->actual_length = len;
if (urb_debug == 2)
urb_print (urb, "RET-t(rh)", usb_pipeout (urb->pipe));
if (urb->complete)
{
urb->complete (urb);
}
}
}
/* re-activate the timer */
rh_init_int_timer (urb);
}
/***************************************************************************
* Function Name : rh_init_int_timer
*
* This function creates a timer that act as interrupt pipe in the
* virtual hub.
*
* Note: The virtual root hub's interrupt pipe are polled by the timer
* every "interval" ms
*
* Input: urb = USB request block
*
* Return: 0
**************************************************************************/
static int rh_init_int_timer (urb_t * urb)
{
hci_t * hci = urb->dev->bus->hcpriv;
hci->rh.interval = urb->interval;
init_timer (&hci->rh.rh_int_timer);
hci->rh.rh_int_timer.function = rh_int_timer_do;
hci->rh.rh_int_timer.data = (unsigned long) urb;
hci->rh.rh_int_timer.expires = jiffies +
(HZ * (urb->interval < 30? 30: urb->interval)) / 1000;
add_timer (&hci->rh.rh_int_timer);
return 0;
}
/*-------------------------------------------------------------------------*/
/* helper macro */
#define OK(x) len = (x); break
/***************************************************************************
* Function Name : rh_submit_urb
*
* This function handles all USB request to the the virtual root hub
*
* Input: urb = USB request block
*
* Return: 0
**************************************************************************/
static int rh_submit_urb (urb_t * urb)
{
struct usb_device * usb_dev = urb->dev;
hci_t * hci = usb_dev->bus->hcpriv;
unsigned int pipe = urb->pipe;
devrequest * cmd = (devrequest *) urb->setup_packet;
void * data = urb->transfer_buffer;
int leni = urb->transfer_buffer_length;
int len = 0;
int status = TD_CC_NOERROR;
__u32 datab[4];
__u8 * data_buf = (__u8 *) datab;
__u16 bmRType_bReq;
__u16 wValue;
__u16 wIndex;
__u16 wLength;
DBGFUNC ("enter rh_submit_urb\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -