ConfigDescriptor.c 9.26 KB
 Dean Camera committed May 08, 2010 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 /* LUFA Library Copyright (C) Dean Camera, 2010. dean [at] fourwalledcubicle [dot] com www.fourwalledcubicle.com */ /* Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) Permission to use, copy, modify, distribute, and sell this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that the copyright notice and this permission notice and warranty disclaimer appear in supporting documentation, and that the name of the author not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. The author disclaim all warranties with regard to this software, including all implied warranties of merchantability and fitness. In no event shall the author be liable for any special, indirect or consequential damages or any damages whatsoever resulting from loss of use, data or profits, whether in an action of contract, negligence or other tortious action, arising out of or in connection with the use or performance of this software. */ /** \file * * USB Device Configuration Descriptor processing routines, to determine the correct pipe configurations * needed to communication with an attached USB device. Descriptors are special computer-readable structures * which the host requests upon device enumeration, to determine the device's capabilities and functions. */ #include "ConfigDescriptor.h" /** Reads and processes an attached device's descriptors, to determine compatibility and pipe configurations. This * routine will read in the entire configuration descriptor, and configure the hosts pipes to correctly communicate * with compatible devices. * * This routine searches for a RNDIS interface descriptor containing bulk data IN and OUT endpoints, and an interrupt event endpoint. * * \return An error code from the \ref RNDISHost_GetConfigDescriptorDataCodes_t enum. */ uint8_t ProcessConfigurationDescriptor(void) { uint8_t ConfigDescriptorData[512]; void* CurrConfigLocation = ConfigDescriptorData; uint16_t CurrConfigBytesRem;  Dean Camera committed Sep 30, 2010 53   Dean Camera committed Oct 01, 2010 54 55 56 57  USB_Descriptor_Interface_t* RNDISControlInterface = NULL; USB_Descriptor_Endpoint_t* DataINEndpoint = NULL; USB_Descriptor_Endpoint_t* DataOUTEndpoint = NULL; USB_Descriptor_Endpoint_t* NotificationEndpoint = NULL;  Dean Camera committed May 08, 2010 58 59 60 61 62 63 64 65 66 67 68 69 70 71  /* Retrieve the entire configuration descriptor into the allocated buffer */ switch (USB_Host_GetDeviceConfigDescriptor(1, &CurrConfigBytesRem, ConfigDescriptorData, sizeof(ConfigDescriptorData))) { case HOST_GETCONFIG_Successful: break; case HOST_GETCONFIG_InvalidData: return InvalidConfigDataReturned; case HOST_GETCONFIG_BuffOverflow: return DescriptorTooLarge; default: return ControlError; }  Dean Camera committed Sep 30, 2010 72  while (!(DataINEndpoint) || !(DataOUTEndpoint) || !(NotificationEndpoint))  Dean Camera committed May 08, 2010 73  {  Dean Camera committed Oct 01, 2010 74 75 76  /* See if we've found a likely compatible interface, and if there is an endpoint within that interface */ if (!(RNDISControlInterface) || USB_GetNextDescriptorComp(&CurrConfigBytesRem, &CurrConfigLocation,  Dean Camera committed May 08, 2010 77 78  DComp_NextCDCDataInterfaceEndpoint) != DESCRIPTOR_SEARCH_COMP_Found) {  Dean Camera committed Sep 30, 2010 79 80  /* Check if we have already found the control interface's notification endpoint or not */ if (NotificationEndpoint)  Dean Camera committed May 08, 2010 81  {  Dean Camera committed Sep 30, 2010 82 83 84  /* Get the next RNDIS data interface from the configuration descriptor */ if (USB_GetNextDescriptorComp(&CurrConfigBytesRem, &CurrConfigLocation, DComp_NextCDCDataInterface) != DESCRIPTOR_SEARCH_COMP_Found)  Dean Camera committed May 08, 2010 85 86  { /* Descriptor not found, error out */  Dean Camera committed Sep 30, 2010 87 88 89 90 91 92  return NoCompatibleInterfaceFound; } /* Clear any found endpoints */ DataINEndpoint = NULL; DataOUTEndpoint = NULL;  Dean Camera committed May 08, 2010 93 94 95  } else {  Dean Camera committed Sep 30, 2010 96  /* Get the next RNDIS control interface from the configuration descriptor */  Dean Camera committed May 08, 2010 97  if (USB_GetNextDescriptorComp(&CurrConfigBytesRem, &CurrConfigLocation,  Dean Camera committed Sep 30, 2010 98  DComp_NextCDCControlInterface) != DESCRIPTOR_SEARCH_COMP_Found)  Dean Camera committed May 08, 2010 99 100  { /* Descriptor not found, error out */  Dean Camera committed Sep 30, 2010 101  return NoCompatibleInterfaceFound;  Dean Camera committed May 08, 2010 102 103  }  Dean Camera committed Oct 01, 2010 104 105 106  /* Save the interface in case we need to refer back to it later */ RNDISControlInterface = DESCRIPTOR_PCAST(CurrConfigLocation, USB_Descriptor_Interface_t);  Dean Camera committed Sep 30, 2010 107 108  /* Clear any found endpoints */ NotificationEndpoint = NULL;  Dean Camera committed May 08, 2010 109  }  Dean Camera committed Sep 30, 2010 110 111 112  /* Skip the remainder of the loop as we have not found an endpoint yet */ continue;  Dean Camera committed May 08, 2010 113 114  }  Dean Camera committed Sep 30, 2010 115  /* Retrieve the endpoint address from the endpoint descriptor */  Dean Camera committed May 08, 2010 116 117  USB_Descriptor_Endpoint_t* EndpointData = DESCRIPTOR_PCAST(CurrConfigLocation, USB_Descriptor_Endpoint_t);  Dean Camera committed Sep 30, 2010 118 119  /* If the endpoint is a IN type endpoint */ if (EndpointData->EndpointAddress & ENDPOINT_DESCRIPTOR_DIR_IN)  Dean Camera committed May 08, 2010 120  {  Dean Camera committed Sep 30, 2010 121 122 123 124 125  /* Check if the found endpoint is a interrupt or bulk type descriptor */ if ((EndpointData->Attributes & EP_TYPE_MASK) == EP_TYPE_INTERRUPT) NotificationEndpoint = EndpointData; else DataINEndpoint = EndpointData;  Dean Camera committed May 08, 2010 126 127 128  } else {  Dean Camera committed Sep 30, 2010 129  DataOUTEndpoint = EndpointData;  Dean Camera committed May 08, 2010 130 131  } }  Dean Camera committed Sep 30, 2010 132 133 134 135 136 137 138 139 140 141 142 143 144  /* Configure the RNDIS data IN pipe */ Pipe_ConfigurePipe(RNDIS_DATA_IN_PIPE, EP_TYPE_BULK, PIPE_TOKEN_IN, DataINEndpoint->EndpointAddress, DataINEndpoint->EndpointSize, PIPE_BANK_SINGLE); /* Configure the RNDIS data OUT pipe */ Pipe_ConfigurePipe(RNDIS_DATA_OUT_PIPE, EP_TYPE_BULK, PIPE_TOKEN_OUT, DataOUTEndpoint->EndpointAddress, DataOUTEndpoint->EndpointSize, PIPE_BANK_SINGLE); /* Configure the RNDIS notification pipe */ Pipe_ConfigurePipe(RNDIS_NOTIFICATION_PIPE, EP_TYPE_INTERRUPT, PIPE_TOKEN_IN, NotificationEndpoint->EndpointAddress, NotificationEndpoint->EndpointSize, PIPE_BANK_SINGLE); Pipe_SetInterruptPeriod(NotificationEndpoint->PollingIntervalMS);  Dean Camera committed May 08, 2010 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224  /* Valid data found, return success */ return SuccessfulConfigRead; } /** Descriptor comparator function. This comparator function is can be called while processing an attached USB device's * configuration descriptor, to search for a specific sub descriptor. It can also be used to abort the configuration * descriptor processing if an incompatible descriptor configuration is found. * * This comparator searches for the next Interface descriptor of the correct CDC control Class, Subclass and Protocol values. * * \return A value from the DSEARCH_Return_ErrorCodes_t enum */ uint8_t DComp_NextCDCControlInterface(void* CurrentDescriptor) { if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) { /* Check the CDC descriptor class, subclass and protocol, break out if correct control interface found */ if ((DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Class == CDC_CONTROL_CLASS) && (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).SubClass == CDC_CONTROL_SUBCLASS) && (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Protocol == CDC_CONTROL_PROTOCOL)) { return DESCRIPTOR_SEARCH_Found; } } return DESCRIPTOR_SEARCH_NotFound; } /** Descriptor comparator function. This comparator function is can be called while processing an attached USB device's * configuration descriptor, to search for a specific sub descriptor. It can also be used to abort the configuration * descriptor processing if an incompatible descriptor configuration is found. * * This comparator searches for the next Interface descriptor of the correct CDC data Class, Subclass and Protocol values. * * \return A value from the DSEARCH_Return_ErrorCodes_t enum */ uint8_t DComp_NextCDCDataInterface(void* CurrentDescriptor) { if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) { /* Check the CDC descriptor class, subclass and protocol, break out if correct data interface found */ if ((DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Class == CDC_DATA_CLASS) && (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).SubClass == CDC_DATA_SUBCLASS) && (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Interface_t).Protocol == CDC_DATA_PROTOCOL)) { return DESCRIPTOR_SEARCH_Found; } } return DESCRIPTOR_SEARCH_NotFound; } /** Descriptor comparator function. This comparator function is can be called while processing an attached USB device's * configuration descriptor, to search for a specific sub descriptor. It can also be used to abort the configuration * descriptor processing if an incompatible descriptor configuration is found. * * This comparator searches for the next bulk IN or OUT endpoint, or interrupt IN endpoint within the current interface, * aborting the search if another interface descriptor is found before the required endpoint (so that it may be compared * using a different comparator to determine if it is another CDC class interface). * * \return A value from the DSEARCH_Return_ErrorCodes_t enum */ uint8_t DComp_NextCDCDataInterfaceEndpoint(void* CurrentDescriptor) { if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint) { uint8_t EndpointType = (DESCRIPTOR_CAST(CurrentDescriptor, USB_Descriptor_Endpoint_t).Attributes & EP_TYPE_MASK); if ((EndpointType == EP_TYPE_BULK) || (EndpointType == EP_TYPE_INTERRUPT)) return DESCRIPTOR_SEARCH_Found; } else if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Interface) { return DESCRIPTOR_SEARCH_Fail; } return DESCRIPTOR_SEARCH_NotFound; }