static int ohci_s3c2410_hub_status_data (struct usb_hcd *hcd, char *buf) { struct s3c2410_hcd_info *info = to_s3c2410_info(hcd); struct s3c2410_hcd_port *port; int orig; int portno; orig = ohci_hub_status_data (hcd, buf); if (info == NULL) return orig; port = &info->port[0]; /* mark any changed port as changed */ for (portno = 0; portno < 2; port++, portno++) { if (port->oc_changed == 1 && port->flags & S3C_HCDFLG_USED) { dev_dbg(hcd->self.controller, "oc change on port %d\n", portno); if (orig < 1) orig = 1; buf[0] |= 1<<(portno+1); } } return orig; }
static int ohci_s3c2410_hub_control ( struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct s3c2410_hcd_info *info = to_s3c2410_info(hcd); struct usb_hub_descriptor *desc; int ret = -EINVAL; u32 *data = (u32 *)buf; dev_dbg(hcd->self.controller, "s3c2410_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n", hcd, typeReq, wValue, wIndex, buf, wLength); /* if we are only an humble host without any special capabilities * process the request straight away and exit */ if (info == NULL) { ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); goto out; } /* check the request to see if it needs handling */ switch (typeReq) { case SetPortFeature: if (wValue == USB_PORT_FEAT_POWER) { dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n"); s3c2410_usb_set_power(info, wIndex, 1); goto out; } break; case ClearPortFeature: switch (wValue) { case USB_PORT_FEAT_C_OVER_CURRENT: dev_dbg(hcd->self.controller, "ClearPortFeature: C_OVER_CURRENT\n"); if (valid_port(wIndex)) { info->port[wIndex-1].oc_changed = 0; info->port[wIndex-1].oc_status = 0; } goto out; case USB_PORT_FEAT_OVER_CURRENT: dev_dbg(hcd->self.controller, "ClearPortFeature: OVER_CURRENT\n"); if (valid_port(wIndex)) { info->port[wIndex-1].oc_status = 0; } goto out; case USB_PORT_FEAT_POWER: dev_dbg(hcd->self.controller, "ClearPortFeature: POWER\n"); if (valid_port(wIndex)) { s3c2410_usb_set_power(info, wIndex, 0); return 0; } } break; } ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); if (ret) goto out; switch (typeReq) { case GetHubDescriptor: /* update the hub's descriptor */ desc = (struct usb_hub_descriptor *)buf; if (info->power_control == NULL) return ret; dev_dbg(hcd->self.controller, "wHubCharacteristics 0x%04x\n", desc->wHubCharacteristics); /* remove the old configurations for power-switching, and * over-current protection, and insert our new configuration */ desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM); desc->wHubCharacteristics |= cpu_to_le16(0x0001); if (info->enable_oc) { desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM); desc->wHubCharacteristics |= cpu_to_le16(0x0008|0x0001); } dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n", desc->wHubCharacteristics); return ret; case GetPortStatus: /* check port status */ dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex); if (valid_port(wIndex)) { if (info->port[wIndex-1].oc_changed) { *data |= cpu_to_le32(RH_PS_OCIC); } if (info->port[wIndex-1].oc_status) { *data |= cpu_to_le32(RH_PS_POCI); } } } out: return ret; }
static int ohci_s3c2410_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct s3c2410_hcd_info *info = to_s3c2410_info(hcd); struct usb_hub_descriptor *desc; int ret = -EINVAL; u32 *data = (u32 *)buf; dev_dbg(hcd->self.controller, "s3c2410_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n", hcd, typeReq, wValue, wIndex, buf, wLength); /* */ if (info == NULL) { ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); goto out; } /* */ switch (typeReq) { case SetPortFeature: if (wValue == USB_PORT_FEAT_POWER) { dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n"); s3c2410_usb_set_power(info, wIndex, 1); goto out; } break; case ClearPortFeature: switch (wValue) { case USB_PORT_FEAT_C_OVER_CURRENT: dev_dbg(hcd->self.controller, "ClearPortFeature: C_OVER_CURRENT\n"); if (valid_port(wIndex)) { info->port[wIndex-1].oc_changed = 0; info->port[wIndex-1].oc_status = 0; } goto out; case USB_PORT_FEAT_OVER_CURRENT: dev_dbg(hcd->self.controller, "ClearPortFeature: OVER_CURRENT\n"); if (valid_port(wIndex)) info->port[wIndex-1].oc_status = 0; goto out; case USB_PORT_FEAT_POWER: dev_dbg(hcd->self.controller, "ClearPortFeature: POWER\n"); if (valid_port(wIndex)) { s3c2410_usb_set_power(info, wIndex, 0); return 0; } } break; } ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); if (ret) goto out; switch (typeReq) { case GetHubDescriptor: /* */ desc = (struct usb_hub_descriptor *)buf; if (info->power_control == NULL) return ret; dev_dbg(hcd->self.controller, "wHubCharacteristics 0x%04x\n", desc->wHubCharacteristics); /* */ desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM); desc->wHubCharacteristics |= cpu_to_le16(0x0001); if (info->enable_oc) { desc->wHubCharacteristics &= ~cpu_to_le16( HUB_CHAR_OCPM); desc->wHubCharacteristics |= cpu_to_le16( 0x0008 | 0x0001); } dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n", desc->wHubCharacteristics); return ret; case GetPortStatus: /* */ dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex); if (valid_port(wIndex)) { if (info->port[wIndex-1].oc_changed) *data |= cpu_to_le32(RH_PS_OCIC); if (info->port[wIndex-1].oc_status) *data |= cpu_to_le32(RH_PS_POCI); } } out: return ret; }