/**************************************************************************** NAME usbFileName DESCRIPTION Get file name from USB root RETURNS void */ static void usbFileName(usb_file_info* root, usb_file_name_info* result) { Source source = StreamFileSource(root->index); usb_file_name* file = (usb_file_name*)SourceMap(source); result->size = 0; if(file) { memmove(result->name, file->name, USB_NAME_SIZE); for(result->size = 0; result->size < USB_NAME_SIZE; result->size++) if(file->name[result->size] == ' ') break; *(result->name + result->size) = '.'; result->size++; memmove(result->name + result->size, file->ext, USB_EXT_SIZE); result->size += USB_EXT_SIZE; SourceClose(source); } #ifdef DEBUG_USB { uint8 count; USB_DEBUG(("USB: File Name ")); for(count = 0; count < result->size; count++) USB_DEBUG(("%c", result->name[count])); USB_DEBUG(("\n")); } #endif }
/**************************************************************************** NAME usbAudioRoute DESCRIPTION Connect USB audio stream RETURNS void */ void usbAudioRoute(void) { AudioPluginFeatures features; Sink sink; Source source; uint16 sampleFreq; UsbDeviceClassGetValue(USB_DEVICE_CLASS_GET_VALUE_AUDIO_SOURCE, (uint16*)(&source)); /* Note: UsbDeviceClassGetValue uses uint16 which limits max value of sample frequency to 64k (uint 16 has range 0->65536) */ UsbDeviceClassGetValue(USB_DEVICE_CLASS_GET_VALUE_SAMPLE_FREQ, &sampleFreq); sink = StreamSinkFromSource(source); /* determine additional features applicable for this audio plugin */ features.stereo = (AUDIO_PLUGIN_FORCE_STEREO || theSink.features.stereo); features.use_i2s_output = theSink.features.UseI2SOutputCapability; USB_DEBUG(("USB: Audio ")); /* Check Audio configured (sink will be NULL if VM USB not enabled) */ if(USB_CLASS_ENABLED(USB_DEVICE_CLASS_AUDIO) && sink) { USB_DEBUG(("Configured ")); if(usbAudioIsAttached()) { USB_DEBUG(("Attached\n")); if(theSink.routed_audio != sink) { Task plugin; AUDIO_MODE_T mode; uint16 volume = usbGetVolume(&mode); const usb_plugin_info* plugin_info = usbAudioGetPluginInfo(&plugin, theSink.usb.config.plugin_type, theSink.usb.config.plugin_index); theSink.routed_audio = sink; UsbDeviceClassGetValue(USB_DEVICE_CLASS_GET_VALUE_AUDIO_SINK, (uint16*)(&theSink.cvc_params.usb_params.usb_sink)); /* Make sure we're using correct parameters for USB */ theSink.a2dp_link_data->a2dp_audio_connect_params.mode_params = &theSink.a2dp_link_data->a2dp_audio_mode_params; USB_DEBUG(("USB: Connect 0x%X 0x%X", (uint16)sink, (uint16)(theSink.cvc_params.usb_params.usb_sink))); #ifdef ENABLE_SUBWOOFER /* set the sub woofer link type prior to passing to audio connect */ theSink.a2dp_link_data->a2dp_audio_connect_params.sub_woofer_type = AUDIO_SUB_WOOFER_NONE; theSink.a2dp_link_data->a2dp_audio_connect_params.sub_sink = NULL; /* bits inverted in dsp plugin */ sinkAudioSetEnhancement(MUSIC_CONFIG_SUB_WOOFER_BYPASS,TRUE); #else /* no subwoofer support, set the sub woofer bypass bit in music config message sent o dsp */ sinkAudioSetEnhancement(MUSIC_CONFIG_SUB_WOOFER_BYPASS,FALSE); #endif /* use a2dp connect parameters */ /* sample frequency is not fixed so read this from usb library */ if(plugin_info->plugin_type == usb_plugin_stereo) AudioConnect(plugin, sink, AUDIO_SINK_USB, theSink.codec_task, volume, sampleFreq, features, mode, 0, powerManagerGetLBIPM(), &theSink.a2dp_link_data->a2dp_audio_connect_params, &theSink.task); /* all other plugins use cvc connect parameters */ else AudioConnect(plugin, sink, AUDIO_SINK_USB, theSink.codec_task, volume, sampleFreq, features, mode, 0, powerManagerGetLBIPM(), &theSink.cvc_params, &theSink.task); } } } USB_DEBUG(("\n")); }
STATIC VOID UsbDisconnectDriver ( IN USB_INTERFACE *UsbIf ) /*++ Routine Description: Disconnect the USB interface with its driver. Arguments: UsbIf - The interface to disconnect driver from Returns: None --*/ { EFI_TPL OldTpl; // // Release the hub if it's a hub controller, otherwise // disconnect the driver if it is managed by other drivers. // if (UsbIf->IsHub) { UsbIf->HubApi->Release (UsbIf); } else if (UsbIf->IsManaged) { // // This function is called in both UsbIoControlTransfer and // the timer callback in hub enumeration. So, at least it is // called at EFI_TPL_CALLBACK. Some driver sitting on USB has // twisted TPL used. It should be no problem for us to connect // or disconnect at CALLBACK. // OldTpl = UsbGetCurrentTpl (); USB_DEBUG (("UsbDisconnectDriver: old TPL is %d\n", OldTpl)); gBS->RestoreTPL (EFI_TPL_CALLBACK); gBS->DisconnectController (UsbIf->Handle, NULL, NULL); UsbIf->IsManaged = FALSE; USB_DEBUG (("UsbDisconnectDriver: TPL after disconnect is %d\n", UsbGetCurrentTpl())); ASSERT (UsbGetCurrentTpl () == EFI_TPL_CALLBACK); gBS->RaiseTPL (OldTpl); } }
EFI_STATUS UsbSelectSetting ( IN USB_INTERFACE_DESC *IfDesc, IN UINT8 Alternate ) /*++ Routine Description: Select an alternate setting for the interface. Each interface can have several mutually exclusive settings. Only one setting is active. It will also reset its endpoints' toggle to zero. Arguments: IfDesc - The interface descriptor to set Alternate - The alternate setting number to locate Returns: EFI_NOT_FOUND - There is no setting with this alternate index EFI_SUCCESS - The interface is set to Alternate setting. --*/ { USB_INTERFACE_SETTING *Setting; UINT8 Index; // // Locate the active alternate setting // Setting = NULL; for (Index = 0; Index < IfDesc->NumOfSetting; Index++) { Setting = IfDesc->Settings[Index]; if (Setting->Desc.AlternateSetting == Alternate) { break; } } if (Index == IfDesc->NumOfSetting) { return EFI_NOT_FOUND; } IfDesc->ActiveIndex = Index; USB_DEBUG (("UsbSelectSetting: setting %d selected for interface %d\n", Alternate, Setting->Desc.InterfaceNumber)); // // Reset the endpoint toggle to zero // for (Index = 0; Index < Setting->Desc.NumEndpoints; Index++) { Setting->Endpoints[Index]->Toggle = 0; } return EFI_SUCCESS; }
/** * \brief Sets the address of a new device */ usb_error_t usb_req_set_address(struct usb_device *dev, uint16_t addr) { USB_DEBUG_TR_ENTER; struct usb_device_request req; usb_error_t err = USB_ERR_INVAL; req.bRequest = USB_REQUEST_SET_ADDRESS; req.wValue = addr; req.wIndex = 0; req.wLength = 0; req.bType.recipient = USB_REQUEST_RECIPIENT_DEVICE; req.bType.type = USB_REQUEST_TYPE_STANDARD; req.bType.direction = USB_REQUEST_WRITE; if (dev->controller->hcdi_bus_fn->set_address != NULL) { USB_DEBUG("set_address function set.\n"); err = (dev->controller->hcdi_bus_fn->set_address)(dev, addr); } if (err != USB_ERR_INVAL) { return (err); } return (usb_exec_request(dev, 0, &req, NULL, NULL)); }
/**************************************************************************** NAME usbSetLowPowerMode DESCRIPTION If delay is non zero queue a message to reset into low powered mode. If delay is zero do nothing. RETURNS void */ static void usbSetLowPowerMode(uint8 delay) { /* Only queue low power mode if not enumerated and attached to normal host/hub */ if(!theSink.usb.enumerated && delay && (UsbAttachedStatus() == HOST_OR_HUB)) { USB_DEBUG(("USB: Queue low power in %d sec\n", delay)); MessageSendLater(&theSink.task, EventUsbLowPowerMode, 0, D_SEC(delay)); } }
/**************************************************************************** NAME usbAudioSinkMatch DESCRIPTION Compare sink to the USB audio sink RETURNS TRUE if sink matches USB audio sink, otherwise FALSE */ bool usbAudioSinkMatch(Sink sink) { Source usb_source = NULL; UsbDeviceClassGetValue(USB_DEVICE_CLASS_GET_VALUE_AUDIO_SOURCE, (uint16*)&usb_source); USB_DEBUG(("USB: usbAudioSinkMatch sink %x = %x, enabled = %x\n", (uint16)sink , (uint16)StreamSinkFromSource(usb_source), USB_CLASS_ENABLED(USB_DEVICE_CLASS_AUDIO) )); return (USB_CLASS_ENABLED(USB_DEVICE_CLASS_AUDIO) && sink && (sink == StreamSinkFromSource(usb_source))); }
/**************************************************************************** NAME usbGetAudioSink DESCRIPTION check USB state and return sink if available RETURNS sink if available, otherwise 0 */ Sink usbGetAudioSink(void) { Source usb_source = NULL; Sink sink = NULL; UsbDeviceClassGetValue(USB_DEVICE_CLASS_GET_VALUE_AUDIO_SOURCE, (uint16*)&usb_source); /* if the usb lead is attached and the speaker is active, try to obtain the audio sink */ if((usbAudioIsAttached())&&(theSink.usb.spkr_active)) { /* attempt to obtain USB audio sink */ sink = StreamSinkFromSource(usb_source); USB_DEBUG(("USB: usbGetAudioSink sink %x, enabled = %x\n", (uint16)sink , USB_CLASS_ENABLED(USB_DEVICE_CLASS_AUDIO) )); } /* USB not attached */ else USB_DEBUG(("USB: usbGetAudioSink sink %x, enabled = %x, speaker active = %x\n", (uint16)sink , USB_CLASS_ENABLED(USB_DEVICE_CLASS_AUDIO), theSink.usb.spkr_active )); return sink; }
/** * \brief this function allocates the resources for a number of usb transfers * * \param device the device we want to allocate the transfers * \param ifaces array of interfaces * \param usb_xfers pointer to an array of usb_xfer * \param setups setup parameter array * \para setup_count the number of setups we have to do * \ */ usb_error_t usb_transfer_setup(struct usb_device *device, const uint8_t iface, struct usb_xfer **ret_xfer, const struct usb_xfer_config *setup) { USB_DEBUG_TR_ENTER; struct usb_xfer_setup_params params; memset(¶ms, 0, sizeof(params)); params.device = device; params.speed = device->speed; params.hc_max_packet_count = 1; params.err = USB_ERR_OK; params.type = setup->usb_type; params.size[0] = 0; params.buf = NULL; params.xfer_setup = setup; struct usb_endpoint *ep = usb_endpoint_lookup(device, iface, setup); if ((ep == NULL) || (ep->pipe_fn == NULL)) { USB_DEBUG_XFER("WARNING: No associated pipe!\n"); USB_DEBUG_TR_RETURN; return (USB_ERR_NO_PIPE); } struct usb_xfer *xfer = malloc(sizeof(struct usb_xfer)); memset(xfer, 0, sizeof(*xfer)); xfer->xfer_id = device->xfer_id++; xfer->device_xfers_next = device->xfers; device->xfers = xfer; xfer->xfer_done_cb = setup->xfer_done_cb; xfer->type = setup->usb_type; xfer->device_address = device->device_address; xfer->host_controller = device->controller; xfer->device = device; xfer->endpoint = ep; params.curr_xfer = xfer; params.pipe_fn = xfer->endpoint->pipe_fn; (device->controller->hcdi_bus_fn->xfer_setup)(¶ms); if (params.err != USB_ERR_OK) { USB_DEBUG( "ERROR: hcdi_xfer_setup failed: %s\n", usb_get_error_string(params.err)); return (params.err); } xfer->endpoint->ref_allocation++; assert(xfer->endpoint->ref_allocation); *ret_xfer = xfer; USB_DEBUG_TR_RETURN; return (USB_ERR_OK); }
EFI_STATUS UsbRemoveDevice ( IN USB_DEVICE *Device ) /*++ Routine Description: Remove the device and all its children from the bus. Arguments: Device - The device to remove Returns: EFI_SUCCESS - The device is removed --*/ { USB_BUS *Bus; USB_DEVICE *Child; EFI_STATUS Status; UINT8 Index; Bus = Device->Bus; // // Remove all the devices on its downstream ports. Search from devices[1]. // Devices[0] is the root hub. // for (Index = 1; Index < USB_MAX_DEVICES; Index++) { Child = Bus->Devices[Index]; if ((Child == NULL) || (Child->ParentAddr != Device->Address)) { continue; } Status = UsbRemoveDevice (Child); if (EFI_ERROR (Status)) { USB_ERROR (("UsbRemoveDevice: failed to remove child, ignore error\n")); Bus->Devices[Index] = NULL; } } UsbRemoveConfig (Device); USB_DEBUG (("UsbRemoveDevice: device %d removed\n", Device->Address)); Bus->Devices[Device->Address] = NULL; UsbFreeDevice (Device); return EFI_SUCCESS; }
/**************************************************************************** NAME usbSetBootMode DESCRIPTION Set the boot mode to default or low power RETURNS void */ void usbSetBootMode(uint8 bootmode) { /* Don't change anything if battery charging disabled */ if(!USB_CLASS_ENABLED(USB_DEVICE_CLASS_TYPE_BATTERY_CHARGING)) return; if(BootGetMode() != bootmode) { USB_DEBUG(("USB: Set Mode %d\n", bootmode)); BootSetMode(bootmode); } }
/**************************************************************************** NAME usbAudioDisconnect DESCRIPTION Disconnect USB audio stream RETURNS void */ void usbAudioDisconnect(void) { if(usbAudioSinkMatch(theSink.routed_audio)) { USB_DEBUG(("USB: Disconnect 0x%X\n", (uint16)theSink.routed_audio)); AudioDisconnect(); theSink.routed_audio = 0; /* If speaker is in use then pause */ if(theSink.usb.spkr_active) UsbDeviceClassSendEvent(USB_DEVICE_CLASS_EVENT_HID_CONSUMER_TRANSPORT_PAUSE); } }
/** * \brief initiates the execution of an existing USB transfer * * \param tid the ID of the transfer to start * * \return USB_ERR_OK on sucess * USB_ERR_XX on failure */ usb_error_t usb_transfer_start(usb_xfer_id_t tid) { struct usb_xfer_state *st = usb_xfer_get_state(tid); if (st == NULL) { USB_DEBUG("inavlid transfer id"); return (USB_ERR_INVAL); } uint32_t ret_error = 0; usb_manager.vtbl.transfer_start(&usb_manager, tid, &ret_error); if (((usb_error_t) ret_error) != USB_ERR_OK) { return ((usb_error_t) ret_error); } return (USB_ERR_OK); }
/**************************************************************************** NAME usbInit DESCRIPTION Initialisation done once the main loop is up and running. Determines USB attach status etc. RETURNS void */ void usbInit(void) { USB_DEBUG(("USB: Init\n")); /* Abort if no device classes supported */ if(!theSink.usb.config.device_class) return; /* If battery charging enabled set the charge current */ usbUpdateChargeCurrent(); #ifdef ENABLE_USB_AUDIO /* Pass NULL USB mic Sink until the plugin handles USB mic */ theSink.a2dp_link_data->a2dp_audio_connect_params.usb_params = NULL; #endif /* Schedule reset to low power mode if attached */ usbSetLowPowerMode(theSink.usb.config.attach_timeout); /* Check for audio */ theSink.usb.ready = TRUE; audioHandleRouting(audio_source_none); PioSetPio(theSink.conf1->PIOIO.pio_outputs.PowerOnPIO, pio_drive, TRUE); }
void usb_rx_transfer_start_call(struct usb_manager_binding *bind, uint32_t tid) { USB_DEBUG_IDC("usb_rx_transfer_start_call()\n"); struct usb_tstart_state *st = malloc(sizeof(struct usb_tstart_state)); if (st == NULL) { debug_printf("WARNING: Cannot reply, out of memory!\n"); } st->bind = bind; struct usb_device *dev = (struct usb_device *) (bind->st); assert(dev != NULL); struct usb_xfer *xfer = dev->xfers; while (xfer) { if (xfer->xfer_id == tid) { break; } xfer = xfer->device_xfers_next; } if (xfer == NULL) { USB_DEBUG("no xfer!\n"); st->error = USB_ERR_BAD_CONTEXT; usb_tx_transfer_start_response(st); } usb_transfer_start(xfer); st->error = xfer->error; usb_tx_transfer_start_response(st); }
/**************************************************************************** NAME usbGetVolume DESCRIPTION Extract USB volume setting from USB lib levels RETURNS Volume to pass to csr_usb_audio_plugin */ static uint16 usbGetVolume(AUDIO_MODE_T* mode) { uint16 result; bool mic_muted; bool spk_muted = FALSE; /* Get vol settings from USB lib */ usb_device_class_audio_levels levels; UsbDeviceClassGetValue(USB_DEVICE_CLASS_GET_VALUE_AUDIO_LEVELS, (uint16*)&levels); /* limit check volume levels returned */ if((levels.out_l_vol < 0)||(levels.out_l_vol > VOLUME_A2DP_MAX_LEVEL)) levels.out_l_vol = VOLUME_A2DP_MAX_LEVEL; if((levels.out_r_vol < 0)||(levels.out_r_vol > VOLUME_A2DP_MAX_LEVEL)) levels.out_r_vol = VOLUME_A2DP_MAX_LEVEL; USB_DEBUG(("USB: Gain L %X R %X\n", levels.out_l_vol, levels.out_r_vol)); USB_DEBUG(("USB: Mute M %X S %X\n", levels.in_mute, levels.out_mute)); if(theSink.usb.config.plugin_type == usb_plugin_stereo) { /* Use A2DP gain mappings */ uint8 l_vol = theSink.conf1->gVolMaps[ levels.out_l_vol ].A2dpGain; uint8 r_vol = theSink.conf1->gVolMaps[ levels.out_r_vol ].A2dpGain; /* Convert A2DP gain setting to mute/gain */ spk_muted = (r_vol == 0 && l_vol == 0); if(r_vol > 0) r_vol --; if(l_vol > 0) l_vol --; /* Pack result */ result = ((l_vol << 8) | r_vol); displayUpdateVolume((levels.out_l_vol + levels.out_r_vol + 1) / 2); #ifdef ENABLE_SUBWOOFER updateSwatVolume((levels.out_l_vol + levels.out_r_vol + 1) / 2); #endif } else { /* Use HFP gain mappings */ result = theSink.conf1->gVolMaps[ levels.out_l_vol ].VolGain; displayUpdateVolume(levels.out_l_vol); #ifdef ENABLE_SUBWOOFER updateSwatVolume(levels.out_l_vol); #endif } /* Mute if muted by host or not supported */ mic_muted = levels.in_mute || !USB_CLASS_ENABLED(USB_DEVICE_CLASS_TYPE_AUDIO_MICROPHONE); spk_muted = spk_muted || levels.out_mute || !USB_CLASS_ENABLED(USB_DEVICE_CLASS_TYPE_AUDIO_SPEAKER); if(mode) { if(mic_muted && spk_muted) *mode = AUDIO_MODE_MUTE_BOTH; else if(mic_muted) *mode = AUDIO_MODE_MUTE_MIC; else if(spk_muted) *mode = AUDIO_MODE_MUTE_SPEAKER; else *mode = AUDIO_MODE_CONNECTED; } return result; }
/**************************************************************************** NAME usbSendHidEvent DESCRIPTION Send HID event over USB RETURNS void */ void usbSendHidEvent(usb_device_class_event event) { USB_DEBUG(("USB: HID Event 0x%X\n", event)); if(USB_CLASS_ENABLED(USB_DEVICE_CLASS_TYPE_HID_CONSUMER_TRANSPORT_CONTROL)) UsbDeviceClassSendEvent(event); }
/**************************************************************************** NAME usbGetChargeCurrent DESCRIPTION Get USB charger limits RETURNS void */ sink_charge_current* usbGetChargeCurrent(void) { /* USB charging not enabled - no limits */ if(!USB_CLASS_ENABLED(USB_DEVICE_CLASS_TYPE_BATTERY_CHARGING)) return NULL; USB_DEBUG(("USB: Status ")); /* Set charge current */ switch(UsbAttachedStatus()) { case HOST_OR_HUB: USB_DEBUG(("Host/Hub ")); if(theSink.usb.suspended) { USB_DEBUG(("Suspended (Battery %s)\n", usbDeadBatteryProvision() ? "Dead" : "Okay")); if(usbDeadBatteryProvision()) return &theSink.usb.config.i_susp_db; else return &theSink.usb.config.i_susp; } else if(powerManagerIsChargerFullCurrent()) { USB_DEBUG(("%sEnumerated (Chg Full)\n", theSink.usb.enumerated ? "" : "Not ")); if(!theSink.usb.enumerated) return &theSink.usb.config.i_att; else return &theSink.usb.config.i_conn; } else { USB_DEBUG(("%sEnumerated (Chg Partial)\n", theSink.usb.enumerated ? "" : "Not ")); if(!theSink.usb.enumerated) return &theSink.usb.config.i_att_trickle; else return &theSink.usb.config.i_conn_trickle; } #ifdef HAVE_FULL_USB_CHARGER_DETECTION case DEDICATED_CHARGER: USB_DEBUG(("Dedicated Charger Port%s\n", theSink.usb.vbus_okay ? "" : " Limited")); if(theSink.usb.vbus_okay) return &theSink.usb.config.i_dchg; else return &theSink.usb.config.i_lim; case HOST_OR_HUB_CHARGER: case CHARGING_PORT: USB_DEBUG(("Charger Port%s\n", theSink.usb.vbus_okay ? "" : " Limited")); if(theSink.usb.vbus_okay) return &theSink.usb.config.i_chg; else return &theSink.usb.config.i_lim; #endif case DETACHED: default: USB_DEBUG(("Detached\n")); if(powerManagerIsChargerConnected()) return &theSink.usb.config.i_disc; else return NULL; } }
/**************************************************************************** NAME usbSetDeadBattery DESCRIPTION Set whether VBAT is below the dead battery threshold RETURNS void */ void usbSetVbatDead(bool dead) { USB_DEBUG(("USB: VBAT %s\n", dead ? "Dead" : "Okay")); theSink.usb.dead_battery = dead; if(!dead) MessageCancelAll(&theSink.task, EventUsbDeadBatteryTimeout); }
/**************************************************************************** NAME usbSetVbusLevel DESCRIPTION Set whether VBUS is above or below threshold RETURNS void */ void usbSetVbusLevel(voltage_reading vbus) { USB_DEBUG(("USB: VBUS %dmV [%d]\n", vbus.voltage, vbus.level)); theSink.usb.vbus_okay = vbus.level; }
/**************************************************************************** NAME usbTimeCriticalInit DESCRIPTION Initialise USB. This function is time critical and must be called from _init. This will fail if either Host Interface is not set to USB or VM control of USB is FALSE in PS. It may also fail if Transport in the project properties is not set to USB VM. RETURNS void */ void usbTimeCriticalInit(void) { #ifdef ENABLE_USB_AUDIO const usb_plugin_info* plugin; #endif usb_device_class_status status; usb_file_info root; usb_file_info file; usb_file_name_info file_name; USB_DEBUG(("USB: Time Critical\n")); /* Default to not configured or suspended */ theSink.usb.ready = FALSE; theSink.usb.enumerated = FALSE; theSink.usb.suspended = FALSE; theSink.usb.vbus_okay = TRUE; theSink.usb.deconfigured = FALSE; /* Check if we booted with dead battery */ usbSetVbatDead(usbDeadBatteryAtBoot()); /* Get USB configuration */ configManagerUsb(); /* Abort if no device classes supported */ if(!theSink.usb.config.device_class) return; usbFileInfo(root_name, sizeof(root_name)-1, &root); usbFileName(&root, &file_name); usbFileInfo(file_name.name, file_name.size, &file); /* If we can't find the help file don't enumerate mass storage */ if(file.index == FILE_NONE || root.index == FILE_NONE) USB_CLASS_DISABLE(USB_DEVICE_CLASS_TYPE_MASS_STORAGE); #ifdef ENABLE_USB_AUDIO plugin = &usb_plugins[theSink.usb.config.plugin_type]; USB_DEBUG(("USB: Audio Plugin %d\n", theSink.usb.config.plugin_index)); UsbDeviceClassConfigure(USB_DEVICE_CLASS_CONFIG_AUDIO_INTERFACE_DESCRIPTORS, 0, 0, (const uint8*)(plugin->usb_descriptors)); #else /* If audio not supported don't enumerate as mic or speaker */ USB_CLASS_DISABLE(USB_DEVICE_CLASS_AUDIO); #endif USB_DEBUG(("USB: Endpoint Setup [0x%04X] - ", theSink.usb.config.device_class)); /* Attempt to enumerate - abort if failed */ status = UsbDeviceClassEnumerate(&theSink.task, theSink.usb.config.device_class); if(status != usb_device_class_status_success) { USB_DEBUG(("Error %X\n", status)); return; } USB_DEBUG(("Success\n")); /* Configure mass storage device */ if(USB_CLASS_ENABLED(USB_DEVICE_CLASS_TYPE_MASS_STORAGE)) { UsbDeviceClassConfigure(USB_DEVICE_CLASS_CONFIG_MASS_STORAGE_FAT_DATA_AREA, file.index, file.size, 0); usbFileInfo(fat_name, sizeof(fat_name)-1, &file); UsbDeviceClassConfigure(USB_DEVICE_CLASS_CONFIG_MASS_STORAGE_FAT_TABLE, file.index, file.size, 0); UsbDeviceClassConfigure(USB_DEVICE_CLASS_CONFIG_MASS_STORAGE_FAT_ROOT_DIR, root.index, root.size, 0); } }
EFI_STATUS UsbSelectConfig ( IN USB_DEVICE *Device, IN UINT8 ConfigValue ) /*++ Routine Description: Select a new configuration for the device. Each device may support several configurations. Arguments: Device - The device to select configuration ConfigValue - The index of the configuration ( != 0) Returns: EFI_NOT_FOUND - There is no configuration with the index EFI_OUT_OF_RESOURCES - Failed to allocate resource EFI_SUCCESS - The configuration is selected. --*/ { USB_DEVICE_DESC *DevDesc; USB_CONFIG_DESC *ConfigDesc; USB_INTERFACE_DESC *IfDesc; USB_INTERFACE *UsbIf; EFI_STATUS Status; UINT8 Index; // // Locate the active config, then set the device's pointer // DevDesc = Device->DevDesc; ConfigDesc = NULL; for (Index = 0; Index < DevDesc->Desc.NumConfigurations; Index++) { ConfigDesc = DevDesc->Configs[Index]; if (ConfigDesc->Desc.ConfigurationValue == ConfigValue) { break; } } if (Index == DevDesc->Desc.NumConfigurations) { return EFI_NOT_FOUND; } Device->ActiveConfig = ConfigDesc; USB_DEBUG (("UsbSelectConfig: config %d selected for device %d\n", ConfigValue, Device->Address)); // // Create interfaces for each USB interface descriptor. // for (Index = 0; Index < ConfigDesc->Desc.NumInterfaces; Index++) { // // First select the default interface setting, and reset // the endpoint toggles to zero for its endpoints. // IfDesc = ConfigDesc->Interfaces[Index]; UsbSelectSetting (IfDesc, IfDesc->Settings[0]->Desc.AlternateSetting); // // Create a USB_INTERFACE and install USB_IO and other protocols // UsbIf = UsbCreateInterface (Device, ConfigDesc->Interfaces[Index]); if (UsbIf == NULL) { return EFI_OUT_OF_RESOURCES; } Device->Interfaces[Index] = UsbIf; // // Connect the device to drivers, if it failed, ignore // the error. Don't let the unsupported interfaces to block // the supported interfaces. // Status = UsbConnectDriver (UsbIf); if (EFI_ERROR (Status)) { USB_ERROR (("UsbSelectConfig: failed to connect driver %r, ignored\n", Status)); } } Device->NumOfInterface = Index; return EFI_SUCCESS; }
STATIC EFI_STATUS UsbConnectDriver ( IN USB_INTERFACE *UsbIf ) /*++ Routine Description: Connect the USB interface with its driver. EFI USB bus will create a USB interface for each seperate interface descriptor. Arguments: UsbIf - The interface to connect driver to Returns: EFI_SUCCESS : Interface is managed by some driver Others : Failed to locate a driver for this interface --*/ { EFI_STATUS Status; EFI_TPL OldTpl; Status = EFI_SUCCESS; // // Hub is maintained by the USB bus driver. Otherwise try to // connect drivers with this interface // if (UsbIsHubInterface (UsbIf)) { USB_DEBUG (("UsbConnectDriver: found a hub device\n")); Status = mUsbHubApi.Init (UsbIf); } else { // // This function is called in both UsbIoControlTransfer and // the timer callback in hub enumeration. So, at least it is // called at EFI_TPL_CALLBACK. Some driver sitting on USB has // twisted TPL used. It should be no problem for us to connect // or disconnect at CALLBACK. // // // Only recursively wanted usb child device // if (UsbBusIsWantedUsbIO (UsbIf->Device->Bus, UsbIf)) { OldTpl = UsbGetCurrentTpl (); USB_DEBUG (("UsbConnectDriver: TPL before connect is %d\n", OldTpl)); gBS->RestoreTPL (EFI_TPL_CALLBACK); Status = gBS->ConnectController (UsbIf->Handle, NULL, NULL, TRUE); UsbIf->IsManaged = (BOOLEAN)!EFI_ERROR (Status); USB_DEBUG (("UsbConnectDriver: TPL after connect is %d\n", UsbGetCurrentTpl())); ASSERT (UsbGetCurrentTpl () == EFI_TPL_CALLBACK); gBS->RaiseTPL (OldTpl); } } return Status; }
/** * \brief starts a USB transfer * * \param xfer the USB transfer to start */ void usb_transfer_start(struct usb_xfer *xfer) { USB_DEBUG_TR_ENTER; if (xfer == NULL) { USB_DEBUG_XFER("NOTICE: No xfer to start...\n"); return; } /* * set the started flag */ xfer->flags_internal.started = 1; /* * if the transfer is already transferring, then we do not * have to do sth. */ if (xfer->flags_internal.transferring) { USB_DEBUG_XFER("NOTICE: already transferring\n"); USB_DEBUG_TR_RETURN; return; } /* struct usb_xfer_queue *queue = &(xfer->host_controller->done_queue); if (queue->current != xfer) { usb_xfer_enqueue(queue, xfer); }*/ /* * submitting the transfer to start the USB hardware for the given * transfer */ if (!xfer->flags_internal.pipe_open) { xfer->flags_internal.pipe_open = 1; (xfer->endpoint->pipe_fn->open)(xfer); } xfer->flags_internal.transferring = 1; xfer->flags_internal.done = 0; /* * check if the transfer is waiting on a queue, and dequeue it */ /* if (xfer->wait_queue) { usb_xfer_dequeue(xfer); }*/ // clear the closed flag xfer->flags_internal.transfer_closed = 0; // clear the DMA delay flag xfer->flags_internal.dma_wait = 0; // transfers are not immediate cancellable xfer->flags_internal.cancellable = 0; /* * update the status fields of the transfer */ xfer->sum_bytes = 0; xfer->actual_bytes = 0; xfer->actual_frames = 0; xfer->error = USB_ERR_OK; if (xfer->device->state < USB_DEVICE_STATE_POWERED) { USB_DEBUG("NOTICE: device is not alive anymore...\n"); usb_xfer_done(xfer, USB_ERR_CANCELLED); return; } if (xfer->num_frames == 0) { if (xfer->flags.pipe_stalled) { USB_DEBUG_XFER("Want to stall w/o transferring...\n"); xfer->flags_internal.cancellable = 1; assert(!"NYI: stalling\n"); /* TODO: usb_command_wrapper(&xfer->endpoint->endpoint_q, xfer); */ return; } USB_DEBUG( "ERROR: invalid number of frames (0) in usb_transfer_start()\n"); usb_xfer_done(xfer, USB_ERR_INVAL); USB_DEBUG_TR_RETURN; return; } for (uint32_t frame = 0; frame < xfer->num_frames; frame++) { xfer->frame_lengths[frame + xfer->max_frame_count] = xfer->frame_lengths[frame]; xfer->sum_bytes += xfer->frame_lengths[frame]; if (xfer->sum_bytes < xfer->frame_lengths[frame]) { USB_DEBUG("WARNING: total length wrapped arroud!\n"); usb_xfer_done(xfer, USB_ERR_INVAL); USB_DEBUG_TR_RETURN; return; } } xfer->flags_internal.short_frames_ok = 0; xfer->flags_internal.short_transfer_ok = 0; if (xfer->flags_internal.ctrl_xfer) { USB_DEBUG_XFER("usb_transfer_start() - is ctrl transfer...\n"); if (usb_transfer_ctrl_start(xfer)) { debug_printf("WARNING: starting usb ctrl transfer failed..\n"); usb_xfer_done(xfer, USB_ERR_STALLED); USB_DEBUG_TR_RETURN; return; } } if ((((xfer)->endpoint_number & 0x80) ? 1 : 0)) { if (xfer->flags.short_frames_ok) { xfer->flags_internal.short_frames_ok = 1; xfer->flags_internal.short_transfer_ok = 1; } else if (xfer->flags.short_xfer_ok) { xfer->flags_internal.short_transfer_ok = 1; if (xfer->flags_internal.ctrl_xfer) { xfer->flags_internal.short_frames_ok = 1; } } } usb_pipe_enter(xfer); USB_DEBUG_TR_RETURN; }
STATIC EFI_STATUS UsbEnumeratePort ( IN USB_INTERFACE *HubIf, IN UINT8 Port ) /*++ Routine Description: Process the events on the port. Arguments: HubIf - The HUB that has the device connected Port - The port index of the hub (started with zero) Returns: EFI_SUCCESS - The device is enumerated (added or removed) EFI_OUT_OF_RESOURCES - Failed to allocate resource for the device Others - Failed to enumerate the device --*/ { USB_HUB_API *HubApi; USB_DEVICE *Child; EFI_USB_PORT_STATUS PortState; EFI_STATUS Status; Child = NULL; HubApi = HubIf->HubApi; // // Host learns of the new device by polling the hub for port changes. // Status = HubApi->GetPortStatus (HubIf, Port, &PortState); if (EFI_ERROR (Status)) { USB_ERROR (("UsbEnumeratePort: failed to get state of port %d\n", Port)); return Status; } if (PortState.PortChangeStatus == 0) { return EFI_SUCCESS; } USB_DEBUG (("UsbEnumeratePort: port %d state - %x, change - %x\n", Port, PortState.PortStatus, PortState.PortChangeStatus)); // // This driver only process two kinds of events now: over current and // connect/disconnect. Other three events are: ENABLE, SUSPEND, RESET. // ENABLE/RESET is used to reset port. SUSPEND isn't supported. // if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_OVERCURRENT)) { if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_OVERCURRENT)) { // // Case1: // Both OverCurrent and OverCurrentChange set, means over current occurs, // which probably is caused by short circuit. It has to wait system hardware // to perform recovery. // USB_DEBUG (("UsbEnumeratePort: Critical Over Current\n", Port)); return EFI_DEVICE_ERROR; } // // Case2: // Only OverCurrentChange set, means system has been recoveried from // over current. As a result, all ports are nearly power-off, so // it's necessary to detach and enumerate all ports again. // USB_DEBUG (("UsbEnumeratePort: 2.0 Device Recovery Over Current\n", Port)); } if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_ENABLE)) { // // Case3: // 1.1 roothub port reg doesn't reflect over-current state, while its counterpart // on 2.0 roothub does. When over-current has influence on 1.1 device, the port // would be disabled, so it's also necessary to detach and enumerate again. // USB_DEBUG (("UsbEnumeratePort: 1.1 Device Recovery Over Current\n", Port)); } if (USB_BIT_IS_SET (PortState.PortChangeStatus, USB_PORT_STAT_C_CONNECTION)) { // // Case4: // Device connected or disconnected normally. // USB_DEBUG (("UsbEnumeratePort: Device Connect/Discount Normally\n", Port)); } // // Following as the above cases, it's safety to remove and create again. // Child = UsbFindChild (HubIf, Port); if (Child != NULL) { USB_DEBUG (("UsbEnumeratePort: device at port %d removed from system\n", Port)); UsbRemoveDevice (Child); } if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_CONNECTION)) { // // Now, new device connected, enumerate and configure the device // USB_DEBUG (("UsbEnumeratePort: new device connected at port %d\n", Port)); Status = UsbEnumerateNewDev (HubIf, Port); } else { USB_DEBUG (("UsbEnumeratePort: device disconnected event on port %d\n", Port)); } HubApi->ClearPortChange (HubIf, Port); return Status; }
STATIC EFI_STATUS UsbEnumerateNewDev ( IN USB_INTERFACE *HubIf, IN UINT8 Port ) /*++ Routine Description: Enumerate and configure the new device on the port of this HUB interface. Arguments: HubIf - The HUB that has the device connected Port - The port index of the hub (started with zero) Returns: EFI_SUCCESS - The device is enumerated (added or removed) EFI_OUT_OF_RESOURCES - Failed to allocate resource for the device Others - Failed to enumerate the device --*/ { USB_BUS *Bus; USB_HUB_API *HubApi; USB_DEVICE *Child; USB_DEVICE *Parent; EFI_USB_PORT_STATUS PortState; UINT8 Address; UINT8 Config; EFI_STATUS Status; Address = USB_MAX_DEVICES; Parent = HubIf->Device; Bus = Parent->Bus; HubApi = HubIf->HubApi; gBS->Stall (USB_WAIT_PORT_STABLE_STALL); // // Hub resets the device for at least 10 milliseconds. // Host learns device speed. If device is of low/full speed // and the hub is a EHCI root hub, ResetPort will release // the device to its companion UHCI and return an error. // Status = HubApi->ResetPort (HubIf, Port); if (EFI_ERROR (Status)) { USB_ERROR (("UsbEnumerateNewDev: failed to reset port %d - %r\n", Port, Status)); return Status; } USB_DEBUG (("UsbEnumerateNewDev: hub port %d is reset\n", Port)); Child = UsbCreateDevice (HubIf, Port); if (Child == NULL) { return EFI_OUT_OF_RESOURCES; } // // OK, now identify the device speed. After reset, hub // fully knows the actual device speed. // Status = HubApi->GetPortStatus (HubIf, Port, &PortState); if (EFI_ERROR (Status)) { USB_ERROR (("UsbEnumerateNewDev: failed to get speed of port %d\n", Port)); goto ON_ERROR; } if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_LOW_SPEED)) { Child->Speed = EFI_USB_SPEED_LOW; } else if (USB_BIT_IS_SET (PortState.PortStatus, USB_PORT_STAT_HIGH_SPEED)) { Child->Speed = EFI_USB_SPEED_HIGH; } else { Child->Speed = EFI_USB_SPEED_FULL; } USB_DEBUG (("UsbEnumerateNewDev: device is of %d speed\n", Child->Speed)); if (Child->Speed != EFI_USB_SPEED_HIGH) { // // If the child isn't a high speed device, it is necessary to // set the transaction translator. Port TT is 1-based. // This is quite simple: // 1. if parent is of high speed, then parent is our translator // 2. otherwise use parent's translator. // if (Parent->Speed == EFI_USB_SPEED_HIGH) { Child->Translator.TranslatorHubAddress = Parent->Address; Child->Translator.TranslatorPortNumber = Port + 1; } else { Child->Translator = Parent->Translator; } USB_DEBUG (("UsbEnumerateNewDev: device uses translator (%d, %d)\n", Child->Translator.TranslatorHubAddress, Child->Translator.TranslatorPortNumber)); } // // After port is reset, hub establishes a signal path between // the device and host (DEFALUT state). Device¡¯s registers are // reset, use default address 0 (host enumerates one device at // a time) , and ready to respond to control transfer at EP 0. // // // Host sends a Get_Descriptor request to learn the max packet // size of default pipe (only part of the device¡¯s descriptor). // Status = UsbGetMaxPacketSize0 (Child); if (EFI_ERROR (Status)) { USB_ERROR (("UsbEnumerateNewDev: failed to get max packet for EP 0 - %r\n", Status)); goto ON_ERROR; } USB_DEBUG (("UsbEnumerateNewDev: max packet size for EP 0 is %d\n", Child->MaxPacket0)); // // Host assigns an address to the device. Device completes the // status stage with default address, then switches to new address. // ADDRESS state. Address zero is reserved for root hub. // for (Address = 1; Address < USB_MAX_DEVICES; Address++) { if (Bus->Devices[Address] == NULL) { break; } } if (Address == USB_MAX_DEVICES) { USB_ERROR (("UsbEnumerateNewDev: address pool is full for port %d\n", Port)); Status = EFI_ACCESS_DENIED; goto ON_ERROR; } Bus->Devices[Address] = Child; Status = UsbSetAddress (Child, Address); Child->Address = Address; if (EFI_ERROR (Status)) { USB_ERROR (("UsbEnumerateNewDev: failed to set device address - %r\n", Status)); goto ON_ERROR; } gBS->Stall (USB_SET_DEVICE_ADDRESS_STALL); USB_DEBUG (("UsbEnumerateNewDev: device is now ADDRESSED at %d\n", Address)); // // Host learns about the device¡¯s abilities by requesting device's // entire descriptions. // Status = UsbBuildDescTable (Child); if (EFI_ERROR (Status)) { USB_ERROR (("UsbEnumerateNewDev: failed to build descriptor table - %r\n", Status)); goto ON_ERROR; } // // Select a default configuration: UEFI must set the configuration // before the driver can connect to the device. // Config = Child->DevDesc->Configs[0]->Desc.ConfigurationValue; Status = UsbSetConfig (Child, Config); if (EFI_ERROR (Status)) { USB_ERROR (("UsbEnumerateNewDev: failed to set configure %d - %r\n", Config, Status)); goto ON_ERROR; } USB_DEBUG (("UsbEnumerateNewDev: device %d is now in CONFIGED state\n", Address)); // // Host assigns and loads a device driver. // Status = UsbSelectConfig (Child, Config); if (EFI_ERROR (Status)) { USB_ERROR (("UsbEnumerateNewDev: failed to create interfaces - %r\n", Status)); goto ON_ERROR; } return EFI_SUCCESS; ON_ERROR: if (Address != USB_MAX_DEVICES) { Bus->Devices[Address] = NULL; } if (Child != NULL) { UsbFreeDevice (Child); } return Status; }
/**************************************************************************** NAME handleUsbMessage DESCRIPTION Handle firmware USB messages RETURNS void */ void handleUsbMessage(Task task, MessageId id, Message message) { USB_DEBUG(("USB: ")); switch (id) { case MESSAGE_USB_ATTACHED: { USB_DEBUG(("MESSAGE_USB_ATTACHED\n")); usbUpdateChargeCurrent(); audioHandleRouting(audio_source_none); usbSetLowPowerMode(theSink.usb.config.attach_timeout); if(theSink.usb.dead_battery) MessageSendLater(&theSink.task, EventUsbDeadBatteryTimeout, 0, D_MIN(45)); break; } case MESSAGE_USB_DETACHED: { USB_DEBUG(("MESSAGE_USB_DETACHED\n")); theSink.usb.enumerated = FALSE; theSink.usb.suspended = FALSE; theSink.usb.deconfigured = FALSE; usbUpdateChargeCurrent(); audioHandleRouting(audio_source_none); MessageCancelAll(&theSink.task, EventUsbLowPowerMode); MessageCancelAll(&theSink.task, EventUsbDeadBatteryTimeout); break; } case MESSAGE_USB_ENUMERATED: { USB_DEBUG(("MESSAGE_USB_ENUMERATED\n")); if(!theSink.usb.enumerated) { theSink.usb.enumerated = TRUE; usbUpdateChargeCurrent(); MessageCancelAll(&theSink.task, EventUsbLowPowerMode); MessageCancelAll(&theSink.task, EventUsbDeadBatteryTimeout); } break; } case MESSAGE_USB_SUSPENDED: { MessageUsbSuspended* ind = (MessageUsbSuspended*)message; USB_DEBUG(("MESSAGE_USB_SUSPENDED - %s\n", (ind->has_suspended ? "Suspend" : "Resume"))); if(ind->has_suspended != theSink.usb.suspended) { theSink.usb.suspended = ind->has_suspended; usbUpdateChargeCurrent(); } break; } case MESSAGE_USB_DECONFIGURED: { USB_DEBUG(("MESSAGE_USB_DECONFIGURED\n")); if(theSink.usb.enumerated) { theSink.usb.enumerated = FALSE; theSink.usb.deconfigured = TRUE; usbUpdateChargeCurrent(); usbSetLowPowerMode(theSink.usb.config.deconfigured_timeout); } break; } case MESSAGE_USB_ALT_INTERFACE: { uint16 interface_id; MessageUsbAltInterface* ind = (MessageUsbAltInterface*)message; USB_DEBUG(("MESSAGE_USB_ALT_INTERFACE %d %d\n", ind->interface, ind->altsetting)); UsbDeviceClassGetValue(USB_DEVICE_CLASS_GET_MIC_INTERFACE_ID, &interface_id); if(interface_id == ind->interface) { theSink.usb.mic_active = (ind->altsetting ? TRUE : FALSE); USB_DEBUG(("USB: Mic ID %d active %d\n", interface_id, theSink.usb.mic_active)); } UsbDeviceClassGetValue(USB_DEVICE_CLASS_GET_SPEAKER_INTERFACE_ID, &interface_id); if(interface_id == ind->interface) { theSink.usb.spkr_active = (ind->altsetting ? TRUE : FALSE); USB_DEBUG(("USB: Speaker ID %d active %d\n", interface_id, theSink.usb.spkr_active)); } #ifdef ENABLE_USB_AUDIO /* check for changes in required audio routing */ USB_DEBUG(("USB: MESSAGE_USB_ALT_INTERFACE checkAudioRouting\n")); MessageCancelFirst(&theSink.task, EventCheckAudioRouting); MessageSendLater(&theSink.task, EventCheckAudioRouting, 0, USB_AUDIO_DISCONNECT_DELAY); #endif break; } case USB_DEVICE_CLASS_MSG_AUDIO_LEVELS_IND: { USB_DEBUG(("USB_DEVICE_CLASS_MSG_AUDIO_LEVELS_IND\n")); usbAudioSetVolume(); break; } default: { USB_DEBUG(("Unhandled USB message 0x%x\n", id)); break; } } }
/** * \brief initializes the OHCI controller hardware */ usb_error_t usb_ohci_init(usb_ohci_hc_t *hc, uintptr_t base) { /* * initialize the mackerel framework */ // TODO: Why does 32-bit expect mackerel_io_t? #ifdef __x86__ ohci_initialize(&ohci_base, (mackerel_io_t)base); #else ohci_initialize(&ohci_base, (mackerel_addr_t)base); #endif hc->ohci_base = &ohci_base; /* * setup the endpoint descriptors */ hc->qh_bulk_last = usb_ohci_init_ed(&hc->qh_bulk_first); hc->qh_ctrl_last = usb_ohci_init_ed(&hc->qh_ctrl_first); hc->qh_isoc_last = usb_ohci_init_ed(NULL); for (uint16_t i = 0; i<USB_OHCI_NO_EP_DESCRIPTORS; i++) { hc->qh_intr_last[i] = usb_ohci_init_ed(NULL); } /** * setup the interrupt transfer type tree */ uint16_t bit = USB_OHCI_NO_EP_DESCRIPTORS / 2; uint16_t current; uint16_t next; while (bit) { current = bit; while (current & bit) { next = (current ^ bit) | (bit / 2); usb_ohci_ed_t *ed_current = hc->qh_intr_last[current]; usb_ohci_ed_t *ed_next = hc->qh_intr_last[next]; ed_current->next = NULL; ed_current->ed_nextED = ed_next->ed_self; current++; } bit >>= 1; } /* * after the last interrupt endpoint the isochronus follows */ usb_ohci_ed_t *intr_ed = hc->qh_intr_last[0]; intr_ed->next = hc->qh_isoc_last; intr_ed->ed_nextED = hc->qh_isoc_last->ed_self; /* * allocate and initiate the HCCA memory region */ hc->hcca = usb_ohci_hcca_alloc(); for (uint16_t i = 0; i < USB_OHCI_NO_IRQS; i++) { hc->hcca->hcca_interrupt_table[i] = hc->qh_intr_last[i | USB_OHCI_NO_EP_DESCRIPTORS / 2]->ed_self; } hc->controller->hcdi_bus_fn = usb_ohci_get_bus_fn(); hc->controller->usb_revision = USB_REV_1_0; /* * initialize the hardware */ if (usb_ohci_init_controller(hc, 0) != USB_ERR_OK) { return USB_ERR_INVAL; } USB_DEBUG("usb_ohci_init() - calling usb_ohci_do_poll\n"); //usb_ohci_do_poll(hc->controller); return USB_ERR_OK; }
void usb_rx_transfer_setup_call(struct usb_manager_binding *bind, uint8_t type, usb_manager_setup_param_t params) { struct usb_tsetup_state *st = malloc(sizeof(struct usb_tsetup_state)); if (st == NULL) { debug_printf("WARNING: Cannot reply, out of memory!\n"); return; } struct usb_xfer_config setup; st->bind = bind; struct usb_xfer *xfer; struct usb_device *dev = (struct usb_device *) bind->st; memcpy(&setup, ¶ms, sizeof(params)); if (dev == NULL) { st->tid = 0; st->error = USB_ERR_BAD_CONTEXT; usb_tx_transfer_setup_response(st); return; } setup.xfer_done_cb = &usb_transfer_complete_notify; switch ((usb_type_t) type) { case USB_TYPE_BULK: USB_DEBUG_IDC("received usb_rx_transfer_setup_call [bulk type]\n"); /* TODO: Handle transfer setup */ setup.usb_type = USB_TYPE_BULK; st->error = USB_ERR_OK; xfer->usb_manager_binding = st->bind; xfer->usb_driver_binding = dev->usb_driver_binding; st->tid = 123; break; case USB_TYPE_CTRL: USB_DEBUG_IDC("received usb_rx_transfer_setup_call [ctrl type]\n"); /* TODO: Handle transfer setup */ setup.usb_type = USB_TYPE_CTRL; st->error = USB_ERR_OK; xfer->usb_manager_binding = st->bind; xfer->usb_driver_binding = dev->usb_driver_binding; st->tid = 234; break; case USB_TYPE_ISOC: USB_DEBUG_IDC("received usb_rx_transfer_setup_call [isoc type]\n"); /* TODO: Handle transfer setup */ setup.usb_type = USB_TYPE_ISOC; st->error = USB_ERR_OK; xfer->usb_manager_binding = st->bind; xfer->usb_driver_binding = dev->usb_driver_binding; st->tid = 345; break; case USB_TYPE_INTR: USB_DEBUG_IDC("received usb_rx_transfer_setup_call [intr type]\n"); /* TODO: Handle transfer setup */ setup.usb_type = USB_TYPE_INTR; st->error = usb_transfer_setup(dev, params.iface, &xfer, &setup); xfer->usb_manager_binding = st->bind; xfer->usb_driver_binding = dev->usb_driver_binding; st->tid = xfer->xfer_id; break; default: USB_DEBUG("received usb_rx_transfer_setup_call [invalid type]\n"); st->error = USB_ERR_INVAL; break; } usb_tx_transfer_setup_response(st); }
/** * \brief initializes the host controller hardware * * \param hc the host controller * \param suspend flag the host controller should be suspended */ static usb_error_t usb_ohci_init_controller(usb_ohci_hc_t *hc, uint8_t suspend) { USB_DEBUG("usb_ohci_init_controller()\n"); char status[512]; ohci_control_pr(status, 512, hc->ohci_base); puts(status); /* * check the ownership of the host controller */ if (ohci_control_ir_rdf(hc->ohci_base)) { assert(!"REQEUST OWER CHANGE. "); } // reset the device ohci_control_hcfs_wrf(hc->ohci_base, 0); /* * TODO: Wait till reset is done */ for(uint32_t i = 0; i < 2000000000; i++); USB_DEBUG("usb_ohci_init_controller(): Device Reset done.\n"); ohci_fm_interval_t ival = ohci_fm_interval_rd(hc->ohci_base); ohci_cmdstatus_hcr_wrf(hc->ohci_base, 1); for (uint16_t i = 0; i < 10; i++) { /* * TODO: Wait 10 us */ for(uint32_t j = 0; j < 2000000000; j++); if (!ohci_cmdstatus_hcr_rdf(hc->ohci_base)) { break; } } if (ohci_cmdstatus_hcr_rdf(hc->ohci_base)) { debug_printf("OHCI host controller reset timeout."); return USB_ERR_IOERROR; } if (suspend) { ohci_control_hcfs_wrf(hc->ohci_base, 3); return USB_ERR_OK; } /* * Setting up register values */ // HCCA pointer ohci_hcca_wr(hc->ohci_base, usb_ohci_hcca_physaddr()); // Control ED head pointer ohci_ctrl_head_wr(hc->ohci_base, hc->qh_ctrl_first->ed_self); // Bulk ED head pointer ohci_bulk_head_wr(hc->ohci_base, hc->qh_bulk_first->ed_self); USB_DEBUG("usb_ohci_init() - reset and enable interrupts\n"); // reset the interrupts ohci_intdisable_rawwr(hc->ohci_base, 0x0); ohci_interrupt_t enabled_intrs = ohci_intenable_rd(hc->ohci_base); enabled_intrs= ohci_interrupt_mie_insert(enabled_intrs, 1); enabled_intrs= ohci_interrupt_wdh_insert(enabled_intrs, 1); enabled_intrs= ohci_interrupt_rd_insert(enabled_intrs, 1); enabled_intrs= ohci_interrupt_ue_insert(enabled_intrs, 1); enabled_intrs= ohci_interrupt_oc_insert(enabled_intrs, 1); enabled_intrs= ohci_interrupt_rhsc_insert(enabled_intrs, 1); ohci_intenable_wr(hc->ohci_base, enabled_intrs); hc->enabled_intrs = enabled_intrs; // setting the desired features ohci_control_t ctrl = ohci_control_rd(hc->ohci_base); ctrl = ohci_control_ie_insert(ctrl, 1); ctrl = ohci_control_ir_insert(ctrl,0); ctrl = ohci_control_cle_insert(ctrl, 1); ctrl = ohci_control_ble_insert(ctrl, 1); ctrl = ohci_control_cbsr_insert(ctrl, 3); ctrl = ohci_control_hcfs_insert(ctrl, 2); ctrl = ohci_control_pe_insert(ctrl, 1); ctrl = ohci_control_rwe_insert(ctrl, 1); ctrl = ohci_control_rwc_insert(ctrl, 1); ohci_control_wr(hc->ohci_base, ctrl); /* * the controller is now OPERATIONAL and running. */ debug_printf("OHCI host controller operational now!\n"); // setting some remaining registers ival = ohci_fm_interval_fit_insert(ival, 0); ival = ohci_fm_interval_fsmps_insert(ival, (ival-210)*6/7); ohci_fm_interval_wr(hc->ohci_base, ival); ohci_period_start_wr(hc->ohci_base, (ival)*9/10); // setting some root hub fields ohci_rh_descra_nocp_wrf(hc->ohci_base, 1); ohci_rh_status_lpsc_wrf(hc->ohci_base, 1); /* * getting the port numbers */ hc->root_hub_num_ports = 0; for (uint8_t i = 0; (i < 10) && (hc->root_hub_num_ports == 0); i++) { /* * TODO: delay */ for(uint32_t j = 0; j < 100000000; j++); hc->root_hub_num_ports = ohci_rh_descra_ndp_rdf(hc->ohci_base); } debug_printf("OHCI CONTROLLER INTIALIZED. Having %"PRIu8" ports\n", hc->root_hub_num_ports ); //char buf[8001]; // ohci_rh_descra_pr(buf, 15999, hc->ohci_base); // printf(buf); //ohci_pr(buf, 5000, hc->ohci_base); //printf(buf); //ohci_cmdstatus_ocr_wrf(hc->ohci_base, 0x1); usb_ohci_root_hub_interrupt(hc); return USB_ERR_OK; }