📄 dm_usb_isp1362.c
字号:
} spin_unlock_irqrestore(&isp1362->lock, flags); return changed;}static void isp1362_hub_descriptor(struct isp1362 *isp1362, struct usb_hub_descriptor *desc){ u32 reg = isp1362->rhdesca; desc->bDescriptorType = 0x29; desc->bDescLength = 9; desc->bHubContrCurrent = 0; desc->bNbrPorts = (u8) (reg & 0x3); /* Power switching, device type, overcurrent. */ desc->wHubCharacteristics = (__force __u16) cpu_to_le16((u16) ((reg >> 8) & 0x1f)); desc->bPwrOn2PwrGood = (u8) ((reg >> 24) & 0xff); /* two bitmaps: ports removable, and legacy PortPwrCtrlMask */ desc->bitmap[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1; desc->bitmap[1] = ~0;}/* Perform reset of a given port. It would be great to just start the reset and let the USB core to clear the reset in due time. However, root hub ports should be reset for at least 50 ms, while our chip stays in reset for about 10 ms. I.e., we must repeatedly reset it ourself here.*/static inline void root_port_reset(struct isp1362 *isp1362, unsigned port){ u32 tmp; unsigned long flags, t; /* Root hub reset should be 50 ms, but some devices want it even longer. */ t = jiffies + msecs_to_jiffies(100); while (time_before(jiffies, t)) { spin_lock_irqsave(&isp1362->lock, flags); /* spin until any current reset finishes */ for (;;) { tmp = isp1362_read_reg32(isp1362, port ? HCRHPORT2 : HCRHPORT1); if (!(tmp & RH_PS_PRS)) break; udelay(500); } /* Don't reset a disconnected port */ if (!(tmp & RH_PS_CCS)) { spin_unlock_irqrestore(&isp1362->lock, flags); break; } /* Reset lasts 10ms (claims datasheet) */ isp1362_write_reg32(isp1362, port ? HCRHPORT2 : HCRHPORT1, (RH_PS_PRS)); spin_unlock_irqrestore(&isp1362->lock, flags); msleep(10); }}/* Adapted from ohci-hub.c */static int isp1362_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength){ struct isp1362 *isp1362 = hcd_to_isp1362(hcd); int ret = 0; unsigned long flags; int ports = isp1362->rhdesca & RH_A_NDP; u32 tmp = 0; switch (typeReq) { case ClearHubFeature: DBG("ClearHubFeature: "); switch (wValue) { case C_HUB_OVER_CURRENT: DBG("C_HUB_OVER_CURRENT\n"); spin_lock_irqsave(&isp1362->lock, flags); isp1362_write_reg32(isp1362, HCRHSTATUS, RH_HS_OCIC); spin_unlock_irqrestore(&isp1362->lock, flags); case C_HUB_LOCAL_POWER: DBG("C_HUB_LOCAL_POWER\n"); break; default: goto error; } break; case SetHubFeature: DBG("SetHubFeature: "); switch (wValue) { case C_HUB_OVER_CURRENT: case C_HUB_LOCAL_POWER: DBG("C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n"); break; default: goto error; } break; case GetHubDescriptor: DBG("GetHubDescriptor\n"); isp1362_hub_descriptor(isp1362, (struct usb_hub_descriptor *)buf); break; case GetHubStatus: DBG("GetHubStatus\n"); *(__le32 *) buf = 0; break; case GetPortStatus: DBG("GetPortStatus\n"); if (!wIndex || wIndex > ports) goto error; tmp = isp1362->rhport[--wIndex]; *(__le32 *) buf = cpu_to_le32(tmp); DBG("GetPortStatus: port[%d] %08x\n", wIndex + 1, tmp); break; case ClearPortFeature: DBG("ClearPortFeature: "); if (!wIndex || wIndex > ports) goto error; wIndex--; switch (wValue) { case USB_PORT_FEAT_ENABLE: DBG("USB_PORT_FEAT_ENABLE\n"); tmp = RH_PS_CCS; break; case USB_PORT_FEAT_C_ENABLE: DBG("USB_PORT_FEAT_C_ENABLE\n"); tmp = RH_PS_PESC; break; case USB_PORT_FEAT_SUSPEND: DBG("USB_PORT_FEAT_SUSPEND\n"); tmp = RH_PS_POCI; break; case USB_PORT_FEAT_C_SUSPEND: DBG("USB_PORT_FEAT_C_SUSPEND\n"); tmp = RH_PS_PSSC; break; case USB_PORT_FEAT_POWER: DBG("USB_PORT_FEAT_POWER\n"); tmp = RH_PS_LSDA; break; case USB_PORT_FEAT_C_CONNECTION: DBG("USB_PORT_FEAT_C_CONNECTION\n"); tmp = RH_PS_CSC; break; case USB_PORT_FEAT_C_OVER_CURRENT: DBG("USB_PORT_FEAT_C_OVER_CURRENT\n"); tmp = RH_PS_OCIC; break; case USB_PORT_FEAT_C_RESET: DBG("USB_PORT_FEAT_C_RESET\n"); tmp = RH_PS_PRSC; break; default: goto error; } spin_lock_irqsave(&isp1362->lock, flags); isp1362_write_reg32(isp1362, wIndex ? HCRHPORT2 : HCRHPORT1, tmp); isp1362->rhport[wIndex] = isp1362_read_reg32(isp1362, wIndex ? HCRHPORT2 : HCRHPORT1); spin_unlock_irqrestore(&isp1362->lock, flags); break; case SetPortFeature: DBG("SetPortFeature: "); if (!wIndex || wIndex > ports) goto error; wIndex--; switch (wValue) { case USB_PORT_FEAT_SUSPEND: DBG("USB_PORT_FEAT_SUSPEND\n"); spin_lock_irqsave(&isp1362->lock, flags); isp1362_write_reg32(isp1362, wIndex ? HCRHPORT2 : HCRHPORT1, RH_PS_PSS); break; case USB_PORT_FEAT_POWER: DBG("USB_PORT_FEAT_POWER\n"); spin_lock_irqsave(&isp1362->lock, flags); isp1362_write_reg32(isp1362, wIndex ? HCRHPORT2 : HCRHPORT1, RH_PS_PPS); break; case USB_PORT_FEAT_RESET: DBG("USB_PORT_FEAT_RESET\n"); root_port_reset(isp1362, wIndex); spin_lock_irqsave(&isp1362->lock, flags); break; default: goto error; } isp1362->rhport[wIndex] = isp1362_read_reg32(isp1362, wIndex ? HCRHPORT2 : HCRHPORT1); spin_unlock_irqrestore(&isp1362->lock, flags); break; default: error: /* "protocol stall" on error */ DBG("PROTOCOL STALL\n"); ret = -EPIPE; } return ret;}#ifdef CONFIG_PMstatic int isp1362_hub_suspend(struct usb_hcd *hcd){ struct isp1362 *isp1362 = hcd_to_isp1362(hcd); unsigned long flags; u32 val; int ret = 0; spin_lock_irqsave(&isp1362->lock, flags); val = isp1362_read_reg32(isp1362, HCCONTROL); switch (val & HCCONTROL_HCFS) { case HCCONTROL_USB_OPER: hcd->state = HC_STATE_QUIESCING; val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE); val |= HCCONTROL_USB_SUSPEND; if (hcd->remote_wakeup) val |= HCCONTROL_RWE; /* Wait for usb transfers to finish */ mdelay(2); isp1362_write_reg32(isp1362, HCCONTROL, val); hcd->state = HC_STATE_SUSPENDED; /* Wait for devices to suspend */ mdelay(5); case HCCONTROL_USB_SUSPEND: break; case HCCONTROL_USB_RESUME: isp1362_write_reg32(isp1362, HCCONTROL, (val & ~HCCONTROL_HCFS) | HCCONTROL_USB_RESET); case HCCONTROL_USB_RESET: ret = -EBUSY; break; default: ret = -EINVAL; } spin_unlock_irqrestore(&isp1362->lock, flags); return ret;}static int isp1362_hub_resume(struct usb_hcd *hcd){ struct isp1362 *isp1362 = hcd_to_isp1362(hcd); u32 val; int ret = -EINPROGRESS; msleep(5); spin_lock_irq(&isp1362->lock); val = isp1362_read_reg32(isp1362, HCCONTROL); switch (val & HCCONTROL_HCFS) { case HCCONTROL_USB_SUSPEND: val &= ~HCCONTROL_HCFS; val |= HCCONTROL_USB_RESUME; isp1362_write_reg32(isp1362, HCCONTROL, val); case HCCONTROL_USB_RESUME: break; case HCCONTROL_USB_OPER: /* Without setting power_state here the SUSPENDED state won't be removed from sysfs/usbN/power.state as a response to remote wakeup. Maybe in the future. */ hcd->self.root_hub->dev.power.power_state = PMSG_ON; ret = 0; break; default: ret = -EBUSY; } if (ret != -EINPROGRESS) { spin_unlock_irq(&isp1362->lock); return ret; } val = isp1362->rhdesca & RH_A_NDP; while (val--) { u32 stat = isp1362_read_reg32(isp1362, val ? HCRHPORT2 : HCRHPORT1); /* force global, not selective, resume */ if (!(stat & RH_PS_PSS)) continue; DBG("%s: Resuming port %d\n", __func__, val); isp1362_write_reg32(isp1362, RH_PS_POCI, val ? HCRHPORT2 : HCRHPORT1); } spin_unlock_irq(&isp1362->lock); hcd->state = HC_STATE_RESUMING; mdelay(20); /* Go operational */ spin_lock_irq(&isp1362->lock); val = isp1362_read_reg32(isp1362, HCCONTROL); isp1362_write_reg32(isp1362, HCCONTROL, (val & ~HCCONTROL_HCFS) | HCCONTROL_USB_OPER); spin_unlock_irq(&isp1362->lock); /* see analogous comment above */ hcd->self.root_hub->dev.power.power_state = PMSG_ON; hcd->state = HC_STATE_RUNNING; return 0;}static void isp1362_rh_resume(void *_hcd){ struct usb_hcd *hcd = _hcd; usb_resume_device(hcd->self.root_hub);}#else#define isp1362_hub_suspend NULL#define isp1362_hub_resume NULLstatic void isp1362_rh_resume(void *_hcd){}#endif/*-----------------------------------------------------------------*/#ifdef STUB_DEBUG_FILEstatic inline void create_debug_file(struct isp1362 *isp1362){}static inline void remove_debug_file(struct isp1362 *isp1362){}#else#include <linux/proc_fs.h>#include <linux/seq_file.h>static void dump_irq(struct seq_file *s, char *label, u16 mask){ seq_printf(s, "%s %04x%s%s%s%s%s%s\n", label, mask, mask & HCuPINT_CLKRDY ? " clkrdy" : "", mask & HCuPINT_SUSP ? " susp" : "", mask & HCuPINT_OPR ? " opr" : "", mask & HCuPINT_AIIEOT ? " eot" : "", mask & HCuPINT_ATL ? " atl" : "", mask & HCuPINT_SOF ? " sof" : "");}static void dump_int(struct seq_file *s, char *label, u32 mask){ seq_printf(s, "%s %08x%s%s%s%s%s%s%s\n", label, mask, mask & HCINT_MIE ? " MIE" : "", mask & HCINT_RHSC ? " rhsc" : "", mask & HCINT_FNO ? " fno" : "", mask & HCINT_UE ? " ue" : "", mask & HCINT_RD ? " rd" : "", mask & HCINT_SF ? " sof" : "", mask & HCINT_SO ? " so" : "");}static int proc_isp1362_show(struct seq_file *s, void *unused){ struct isp1362 *isp1362 = s->private; struct isp1362_ep *ep; struct urb *urb; unsigned i; char *str; seq_printf(s, "%s\n%s version %s\n", isp1362_to_hcd(isp1362)->product_desc, hcd_name, DRIVER_VERSION); if (HC_IS_SUSPENDED(isp1362_to_hcd(isp1362)->state)) { seq_printf(s, "HCD is suspended\n"); return 0; } if (!HC_IS_RUNNING(isp1362_to_hcd(isp1362)->state)) { seq_printf(s, "HCD not running\n"); return 0; } spin_lock_irq(&isp1362->lock); dump_irq(s, "hc_irq_enable", isp1362_read_reg16(isp1362, HCuPINTENB)); dump_irq(s, "hc_irq_status", isp1362_read_reg16(isp1362, HCuPINT)); dump_int(s, "hc_int_enable", isp1362_read_reg32(isp1362, HCINTENB)); dump_int(s, "hc_int_status", isp1362_read_reg32(isp1362, HCINTSTAT)); list_for_each_entry(ep, &isp1362->async, schedule) { switch (ep->nextpid) { case USB_PID_IN: str = "in"; break; case USB_PID_OUT: str = "out"; break; case USB_PID_SETUP: str = "setup"; break; case USB_PID_ACK: str = "status"; break; default: str = "?"; break; }; seq_printf(s, "%p, ep%d%s, maxpacket %d:\n", ep, ep->epnum, str, ep->maxpacket); list_for_each_entry(urb, &ep->hep->urb_list, urb_list) { seq_printf(s, " urb%p, %d/%d\n", urb, urb->actual_length, urb->transfer_buffer_length); } } if (!list_empty(&isp1362->async)) seq_printf(s, "\n"); seq_printf(s, "periodic size= %d\n", PERIODIC_SIZE); for (i = 0; i < PERIODIC_SIZE; i++) { ep = isp1362->periodic[i]; if (!ep) continue; seq_printf(s, "%2d [%3d]:\n", i, isp1362->load[i]); /* DUMB: prints shared entries multiple times */ do { seq_printf(s, " %d/%p (%sdev%d ep%d%s max %d)\n", ep->period, ep, (ep->udev->speed == USB_SPEED_FULL) ? "" : "ls ", ep->udev->devnum, ep->epnum, (ep->epnum == 0) ? "" : ((ep->nextpid == USB_PID_IN) ? "in" : "out"), ep->maxpacket); ep = ep->next; } while (ep); } spin_unlock_irq(&isp1362->lock); seq_printf(s, "\n"); return 0;}static int proc_isp1362_open(struct inode *inode, struct file *file){ return single_open(file, proc_isp1362_show, PDE(inode)->data);}static struct file_operations proc_ops = { .open = proc_isp1362_open, .read = seq_read, .llseek = seq_lseek,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -