cy7c67200_300_hcd_rh.c
来自「linux嵌入式课程实践中的一个关于声卡驱动程序 。」· C语言 代码 · 共 1,002 行 · 第 1/2 页
C
1,002 行
*(__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) |= (((get_port_stat_change (hci, port_num) >> 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, (void *) 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; int port_num = -1; cy_priv_t * cy_priv; hci_t * hci;// int i;// cy_dbg("enter rh_int_timer_do\n"); if (urb == NULL) { cy_err("rh_int_timer_do: error, urb = 0x%x", (unsigned long) urb); return;// return ERROR; } cy_priv = urb->dev->bus->hcpriv; if (cy_priv == NULL) { cy_err("rh_int_timer_do: error, cy_priv = 0x%x", (unsigned long) cy_priv); return;// return ERROR; } hci = cy_priv->hci; if (hci == NULL) { cy_err("rh_int_timer_do: error, hci = 0x%x", (unsigned long) hci); return;// return ERROR; } port_num = get_port_num_from_urb(cy_priv, urb); if (port_num == ERROR) { cy_err("rh_int_timer_do: can't find port num\n"); return;// return ERROR; } if(hci->port[port_num].rh.send) { // cy_dbg("rh_int_timer_do: urb->transfer_buffer = 0x%x, urb->transfer_buffer_length = %d\n",// urb->transfer_buffer, urb->transfer_buffer_length); len = rh_send_irq (hci, urb->transfer_buffer, urb->transfer_buffer_length, port_num); 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); } } } // cy_dbg("rh_int_timer_do: exiting, urb = 0x%x, port_num = %d\n", (unsigned long) urb, port_num); /* re-activate the timer */ rh_init_int_timer (urb, port_num);}/*************************************************************************** * 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, int port_num) { cy_priv_t * cy_priv = urb->dev->bus->hcpriv; hci_t * hci = cy_priv->hci; hci->port[port_num].rh.interval = urb->interval; // cy_dbg("rh_init_int_timer: urb = 0x%x, port_num = %d\n", (unsigned long) urb, port_num); if (cy_priv == NULL || hci == NULL) { cy_err("rh_init_int_timer: error! cy_priv = 0x%x, hci = 0x%x\n", cy_priv, hci); } init_timer (&hci->port[port_num].rh.rh_int_timer); hci->port[port_num].rh.rh_int_timer.function = rh_int_timer_do; hci->port[port_num].rh.rh_int_timer.data = (unsigned long) urb; hci->port[port_num].rh.rh_int_timer.expires = jiffies + (HZ * (urb->interval < 30? 30: urb->interval)) / 1000; add_timer (&hci->port[port_num].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 **************************************************************************/int rh_submit_urb (urb_t * urb, int port_num){ struct usb_device * usb_dev = urb->dev; cy_priv_t * cy_priv = usb_dev->bus->hcpriv; hci_t * hci = cy_priv->hci; 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; cy_dbg("enter rh_submit_urb\n"); if (usb_pipeint(pipe)) { hci->port[port_num].rh.urb = urb; hci->port[port_num].rh.send = 1; hci->port[port_num].rh.interval = urb->interval; rh_init_int_timer(urb, port_num); urb->status = cc_to_error (TD_CC_NOERROR); return 0; } bmRType_bReq = cmd->requesttype | (cmd->request << 8); wValue = le16_to_cpu (cmd->value); wIndex = le16_to_cpu (cmd->index); wLength = le16_to_cpu (cmd->length); cy_dbg("rh_submit_urb, req = %d(%x) len=%d", bmRType_bReq, bmRType_bReq, wLength); switch (bmRType_bReq) { /* Request Destination: without flags: Device, RH_INTERFACE: interface, RH_ENDPOINT: endpoint, RH_CLASS means HUB here, RH_OTHER | RH_CLASS almost ever means HUB_PORT here */ case RH_GET_STATUS: *(__u16 *) data_buf = cpu_to_le16 (1); OK (2); case RH_GET_STATUS | RH_INTERFACE: *(__u16 *) data_buf = cpu_to_le16 (0); OK (2); case RH_GET_STATUS | RH_ENDPOINT: *(__u16 *) data_buf = cpu_to_le16 (0); OK (2); case RH_GET_STATUS | RH_CLASS: *(__u32 *) data_buf = cpu_to_le32 (0); OK (4); case RH_GET_STATUS | RH_OTHER | RH_CLASS: *(__u32 *) data_buf = cpu_to_le32 (get_port_stat_change(hci, port_num)); OK (4); case RH_CLEAR_FEATURE | RH_ENDPOINT: switch (wValue) { case (RH_ENDPOINT_STALL): OK (0); } break; case RH_CLEAR_FEATURE | RH_CLASS: switch (wValue) { case RH_C_HUB_LOCAL_POWER: OK(0); case (RH_C_HUB_OVER_CURRENT): /* Over Current Not Implemented */ OK (0); } break; case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: switch (wValue) { case (RH_PORT_ENABLE): clr_port_stat (hci, PORT_ENABLE_STAT, port_num); OK (0); case (RH_PORT_SUSPEND): clr_port_stat (hci, PORT_SUSPEND_STAT, port_num); OK (0); case (RH_PORT_POWER): clr_port_stat (hci, PORT_POWER_STAT, port_num); OK (0); case (RH_C_PORT_CONNECTION): clr_port_change (hci, PORT_CONNECT_STAT, port_num); OK (0); case (RH_C_PORT_ENABLE): clr_port_change (hci, PORT_ENABLE_STAT, port_num); OK (0); case (RH_C_PORT_SUSPEND): clr_port_change (hci, PORT_SUSPEND_STAT, port_num); OK (0); case (RH_C_PORT_OVER_CURRENT): clr_port_change (hci, PORT_OVER_CURRENT_STAT, port_num); OK (0); case (RH_C_PORT_RESET): clr_port_change (hci, PORT_RESET_STAT, port_num); OK (0); } break; case RH_SET_FEATURE | RH_OTHER | RH_CLASS: switch (wValue) { case (RH_PORT_SUSPEND): set_port_stat(hci, PORT_SUSPEND_STAT, port_num); OK (0); case (RH_PORT_RESET): set_port_stat(hci, PORT_RESET_STAT, port_num); // hc_host_usb_reset(cy_priv, port_num ); clr_port_change (hci, PORT_CONNECT_CHANGE | PORT_ENABLE_CHANGE | PORT_SUSPEND_CHANGE | PORT_OVER_CURRENT_CHANGE, port_num); set_port_change(hci, PORT_RESET_CHANGE, port_num); clr_port_stat(hci, PORT_RESET_STAT, port_num); set_port_stat(hci, PORT_ENABLE_STAT, port_num); OK (0); case (RH_PORT_POWER): set_port_stat(hci, PORT_POWER_STAT, port_num); OK (0); case (RH_PORT_ENABLE): set_port_stat(hci, PORT_ENABLE_STAT, port_num); OK (0); } break; case RH_SET_ADDRESS: hci->port[port_num].rh.devnum = wValue; OK(0); case RH_GET_DESCRIPTOR: cy_dbg("rh_submit_urb: RH_GET_DESCRIPTOR, wValue = 0x%x\n", wValue); switch ((wValue & 0xff00) >> 8) { case (0x01): /* device descriptor */ len = min (leni, min (sizeof (root_hub_dev_des[port_num]), wLength)); data_buf = root_hub_dev_des[port_num]; OK(len); case (0x02): /* configuration descriptor */ len = min (leni, min (sizeof (root_hub_config_des[port_num]), wLength)); data_buf = root_hub_config_des[port_num]; OK(len); case (0x03): /* string descriptors */ len = usb_root_hub_string (wValue & 0xff,(int)(long) port_num, "CY7C67200/300", data, wLength); if (len > 0) { data_buf = data; OK (min (leni, len)); } default: status = bmHOST_STATMASK_STALL; } break; case RH_GET_DESCRIPTOR | RH_CLASS: data_buf [0] = 9; // min length; data_buf [1] = 0x29; data_buf [2] = 1; // # of downstream port data_buf [3] = 0; datab [1] = 0; data_buf [5] = 50; // 100 ms for port reset data_buf [7] = 0xfc; // which port is attachable if (data_buf [2] < 7) { data_buf [8] = 0xff; } else { } len = min (leni, min (data_buf [0], wLength)); OK (len); case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1); case RH_SET_CONFIGURATION: OK (0); default: cy_err("unsupported root hub command"); status = bmHOST_STATMASK_STALL; } len = min(len, leni); if (data != data_buf) memcpy (data, data_buf, len); urb->actual_length = len; urb->status = cc_to_error (status); urb->hcpriv = NULL; urb->dev = NULL; if (urb->complete) { urb->complete (urb); } return 0;}/*************************************************************************** * Function Name : rh_unlink_urb * * This function unlinks the URB * * Input: urb = USB request block * * Return: 0 **************************************************************************/int rh_unlink_urb (urb_t * urb, int port_num){ cy_priv_t * cy_priv = urb->dev->bus->hcpriv; hci_t * hci = cy_priv->hci; cy_dbg("enter rh_unlink_urb\n"); if (hci->port[port_num].rh.urb == urb) { hci->port[port_num].rh.send = 0; del_timer (&hci->port[port_num].rh.rh_int_timer); hci->port[port_num].rh.urb = NULL; urb->hcpriv = NULL; usb_dec_dev_use(urb->dev); urb->dev = NULL; if (urb->transfer_flags & USB_ASYNC_UNLINK) { urb->status = -ECONNRESET; if (urb->complete) { urb->complete (urb); } } else urb->status = -ENOENT; } return 0;}/*************************************************************************** * Function Name : rh_connect_rh * * This function connect the virtual root hub to the USB stack * * Input: urb = USB request block * * Return: 0 **************************************************************************/ int rh_connect_rh (cy_priv_t * cy_priv, int port_num) { struct usb_device * usb_dev = NULL; hci_t * hci = cy_priv->hci; hci->port[port_num].rh.devnum = 0; cy_dbg("enter rh_connect_rh, port_num = 0x%x\n", port_num); if (hci == NULL) { cy_err("rh_connect_rh: hci is NULL!\n"); } if (hci->port[port_num].bus == NULL) { cy_err("rh_connect_rh: hci->port[port_num].bus is NULL!\n"); } cy_dbg("rh_connect_rh: hci->port[%d].bus = 0x%x\n", port_num, hci->port[port_num].bus); usb_dev = usb_alloc_dev (NULL, hci->port[port_num].bus); if (!usb_dev) { cy_err("rh_connect_rh: usb_dev == NULL!\n"); return -ENOMEM; } cy_dbg("rh_connect_rh: usb_dev->bus = 0x%x, busnu = 0x%x\n", usb_dev->bus, usb_dev->bus->busnum); if (usb_dev->bus == NULL) { cy_err("rh_connect_rh: usb_dev->bus is 0x%x, " "hci->port[%d].bus = 0x%x, usb_dev = 0x%x\n", usb_dev->bus, port_num, hci->port[port_num].bus, usb_dev); } hci->port[port_num].bus->root_hub = usb_dev; usb_connect (usb_dev); if (usb_new_device (usb_dev) != 0) { usb_free_dev (usb_dev); return -ENODEV; } return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?