| OLD | NEW |
| 1 /* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */ |
| 1 /* | 2 /* |
| 2 * USB descriptor handling functions for libusb | 3 * USB descriptor handling functions for libusbx |
| 3 * Copyright (C) 2007 Daniel Drake <dsd@gentoo.org> | 4 * Copyright © 2007 Daniel Drake <dsd@gentoo.org> |
| 4 * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> | 5 * Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com> |
| 5 * | 6 * |
| 6 * This library is free software; you can redistribute it and/or | 7 * This library is free software; you can redistribute it and/or |
| 7 * modify it under the terms of the GNU Lesser General Public | 8 * modify it under the terms of the GNU Lesser General Public |
| 8 * License as published by the Free Software Foundation; either | 9 * License as published by the Free Software Foundation; either |
| 9 * version 2.1 of the License, or (at your option) any later version. | 10 * version 2.1 of the License, or (at your option) any later version. |
| 10 * | 11 * |
| 11 * This library is distributed in the hope that it will be useful, | 12 * This library is distributed in the hope that it will be useful, |
| 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 14 * Lesser General Public License for more details. | 15 * Lesser General Public License for more details. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 32 #define ENDPOINT_DESC_LENGTH 7 | 33 #define ENDPOINT_DESC_LENGTH 7 |
| 33 #define ENDPOINT_AUDIO_DESC_LENGTH 9 | 34 #define ENDPOINT_AUDIO_DESC_LENGTH 9 |
| 34 | 35 |
| 35 /** @defgroup desc USB descriptors | 36 /** @defgroup desc USB descriptors |
| 36 * This page details how to examine the various standard USB descriptors | 37 * This page details how to examine the various standard USB descriptors |
| 37 * for detected devices | 38 * for detected devices |
| 38 */ | 39 */ |
| 39 | 40 |
| 40 /* set host_endian if the w values are already in host endian format, | 41 /* set host_endian if the w values are already in host endian format, |
| 41 * as opposed to bus endian. */ | 42 * as opposed to bus endian. */ |
| 42 int usbi_parse_descriptor(unsigned char *source, const char *descriptor, | 43 int usbi_parse_descriptor(const unsigned char *source, const char *descriptor, |
| 43 void *dest, int host_endian) | 44 void *dest, int host_endian) |
| 44 { | 45 { |
| 45 » unsigned char *sp = source, *dp = dest; | 46 » const unsigned char *sp = source; |
| 47 » unsigned char *dp = dest; |
| 46 uint16_t w; | 48 uint16_t w; |
| 47 const char *cp; | 49 const char *cp; |
| 50 uint32_t d; |
| 48 | 51 |
| 49 for (cp = descriptor; *cp; cp++) { | 52 for (cp = descriptor; *cp; cp++) { |
| 50 switch (*cp) { | 53 switch (*cp) { |
| 51 case 'b': /* 8-bit byte */ | 54 case 'b': /* 8-bit byte */ |
| 52 *dp++ = *sp++; | 55 *dp++ = *sp++; |
| 53 break; | 56 break; |
| 54 case 'w': /* 16-bit word, convert from little endi
an to CPU */ | 57 case 'w': /* 16-bit word, convert from little endi
an to CPU */ |
| 55 dp += ((uintptr_t)dp & 1); /* Align to word
boundary */ | 58 dp += ((uintptr_t)dp & 1); /* Align to word
boundary */ |
| 56 | 59 |
| 57 if (host_endian) { | 60 if (host_endian) { |
| 58 memcpy(dp, sp, 2); | 61 memcpy(dp, sp, 2); |
| 59 } else { | 62 } else { |
| 60 w = (sp[1] << 8) | sp[0]; | 63 w = (sp[1] << 8) | sp[0]; |
| 61 *((uint16_t *)dp) = w; | 64 *((uint16_t *)dp) = w; |
| 62 } | 65 } |
| 63 sp += 2; | 66 sp += 2; |
| 64 dp += 2; | 67 dp += 2; |
| 65 break; | 68 break; |
| 69 case 'd': /* 32-bit word, convert from little endi
an to CPU */ |
| 70 dp += ((uintptr_t)dp & 1); /* Align to word
boundary */ |
| 71 |
| 72 if (host_endian) { |
| 73 memcpy(dp, sp, 4); |
| 74 } else { |
| 75 d = (sp[3] << 24) | (sp[2] << 16) | |
| 76 (sp[1] << 8) | sp[0]; |
| 77 *((uint32_t *)dp) = d; |
| 78 } |
| 79 sp += 4; |
| 80 dp += 4; |
| 81 break; |
| 82 case 'u': /* 16 byte UUID */ |
| 83 memcpy(dp, sp, 16); |
| 84 sp += 16; |
| 85 dp += 16; |
| 86 break; |
| 66 } | 87 } |
| 67 } | 88 } |
| 68 | 89 |
| 69 return (int) (sp - source); | 90 return (int) (sp - source); |
| 70 } | 91 } |
| 71 | 92 |
| 72 static void clear_endpoint(struct libusb_endpoint_descriptor *endpoint) | 93 static void clear_endpoint(struct libusb_endpoint_descriptor *endpoint) |
| 73 { | 94 { |
| 74 if (endpoint->extra) | 95 if (endpoint->extra) |
| 75 free((unsigned char *) endpoint->extra); | 96 free((unsigned char *) endpoint->extra); |
| 76 } | 97 } |
| 77 | 98 |
| 78 static int parse_endpoint(struct libusb_context *ctx, | 99 static int parse_endpoint(struct libusb_context *ctx, |
| 79 struct libusb_endpoint_descriptor *endpoint, unsigned char *buffer, | 100 struct libusb_endpoint_descriptor *endpoint, unsigned char *buffer, |
| 80 int size, int host_endian) | 101 int size, int host_endian) |
| 81 { | 102 { |
| 82 struct usb_descriptor_header header; | 103 struct usb_descriptor_header header; |
| 83 unsigned char *extra; | 104 unsigned char *extra; |
| 84 unsigned char *begin; | 105 unsigned char *begin; |
| 85 int parsed = 0; | 106 int parsed = 0; |
| 86 int len; | 107 int len; |
| 87 | 108 |
| 88 » usbi_parse_descriptor(buffer, "bb", &header, 0); | 109 » if (size < DESC_HEADER_LENGTH) { |
| 89 | 110 » » usbi_err(ctx, "short endpoint descriptor read %d/%d", |
| 90 » /* Everything should be fine being passed into here, but we sanity */ | 111 » » » size, DESC_HEADER_LENGTH); |
| 91 » /* check JIC */ | 112 » » return LIBUSB_ERROR_IO; |
| 92 » if (header.bLength > size) { | |
| 93 » » usbi_err(ctx, "ran out of descriptors parsing"); | |
| 94 » » return -1; | |
| 95 } | 113 } |
| 96 | 114 |
| 115 usbi_parse_descriptor(buffer, "bb", &header, 0); |
| 97 if (header.bDescriptorType != LIBUSB_DT_ENDPOINT) { | 116 if (header.bDescriptorType != LIBUSB_DT_ENDPOINT) { |
| 98 usbi_err(ctx, "unexpected descriptor %x (expected %x)", | 117 usbi_err(ctx, "unexpected descriptor %x (expected %x)", |
| 99 header.bDescriptorType, LIBUSB_DT_ENDPOINT); | 118 header.bDescriptorType, LIBUSB_DT_ENDPOINT); |
| 100 return parsed; | 119 return parsed; |
| 101 } | 120 } |
| 102 | 121 » if (header.bLength > size) { |
| 122 » » usbi_warn(ctx, "short endpoint descriptor read %d/%d", |
| 123 » » » size, header.bLength); |
| 124 » » return parsed; |
| 125 » } |
| 103 if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH) | 126 if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH) |
| 104 usbi_parse_descriptor(buffer, "bbbbwbbb", endpoint, host_endian)
; | 127 usbi_parse_descriptor(buffer, "bbbbwbbb", endpoint, host_endian)
; |
| 105 else if (header.bLength >= ENDPOINT_DESC_LENGTH) | 128 else if (header.bLength >= ENDPOINT_DESC_LENGTH) |
| 106 usbi_parse_descriptor(buffer, "bbbbwb", endpoint, host_endian); | 129 usbi_parse_descriptor(buffer, "bbbbwb", endpoint, host_endian); |
| 130 else { |
| 131 usbi_err(ctx, "invalid endpoint bLength (%d)", header.bLength); |
| 132 return LIBUSB_ERROR_IO; |
| 133 } |
| 107 | 134 |
| 108 buffer += header.bLength; | 135 buffer += header.bLength; |
| 109 size -= header.bLength; | 136 size -= header.bLength; |
| 110 parsed += header.bLength; | 137 parsed += header.bLength; |
| 111 | 138 |
| 112 /* Skip over the rest of the Class Specific or Vendor Specific */ | 139 /* Skip over the rest of the Class Specific or Vendor Specific */ |
| 113 /* descriptors */ | 140 /* descriptors */ |
| 114 begin = buffer; | 141 begin = buffer; |
| 115 while (size >= DESC_HEADER_LENGTH) { | 142 while (size >= DESC_HEADER_LENGTH) { |
| 116 usbi_parse_descriptor(buffer, "bb", &header, 0); | 143 usbi_parse_descriptor(buffer, "bb", &header, 0); |
| 117 | 144 » » if (header.bLength < DESC_HEADER_LENGTH) { |
| 118 » » if (header.bLength < 2) { | 145 » » » usbi_err(ctx, "invalid extra ep desc len (%d)", |
| 119 » » » usbi_err(ctx, "invalid descriptor length %d", header.bLe
ngth); | 146 » » » » header.bLength); |
| 120 » » » return -1; | 147 » » » return LIBUSB_ERROR_IO; |
| 148 » » } else if (header.bLength > size) { |
| 149 » » » usbi_warn(ctx, "short extra ep desc read %d/%d", |
| 150 » » » » size, header.bLength); |
| 151 » » » return parsed; |
| 121 } | 152 } |
| 122 | 153 |
| 123 /* If we find another "proper" descriptor then we're done */ | 154 /* If we find another "proper" descriptor then we're done */ |
| 124 if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) || | 155 if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) || |
| 125 (header.bDescriptorType == LIBUSB_DT_INTERFACE)
|| | 156 (header.bDescriptorType == LIBUSB_DT_INTERFACE)
|| |
| 126 (header.bDescriptorType == LIBUSB_DT_CONFIG) || | 157 (header.bDescriptorType == LIBUSB_DT_CONFIG) || |
| 127 (header.bDescriptorType == LIBUSB_DT_DEVICE)) | 158 (header.bDescriptorType == LIBUSB_DT_DEVICE)) |
| 128 break; | 159 break; |
| 129 | 160 |
| 130 usbi_dbg("skipping descriptor %x", header.bDescriptorType); | 161 usbi_dbg("skipping descriptor %x", header.bDescriptorType); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 } | 212 } |
| 182 | 213 |
| 183 static int parse_interface(libusb_context *ctx, | 214 static int parse_interface(libusb_context *ctx, |
| 184 struct libusb_interface *usb_interface, unsigned char *buffer, int size, | 215 struct libusb_interface *usb_interface, unsigned char *buffer, int size, |
| 185 int host_endian) | 216 int host_endian) |
| 186 { | 217 { |
| 187 int i; | 218 int i; |
| 188 int len; | 219 int len; |
| 189 int r; | 220 int r; |
| 190 int parsed = 0; | 221 int parsed = 0; |
| 222 int interface_number = -1; |
| 191 size_t tmp; | 223 size_t tmp; |
| 192 struct usb_descriptor_header header; | 224 struct usb_descriptor_header header; |
| 193 struct libusb_interface_descriptor *ifp; | 225 struct libusb_interface_descriptor *ifp; |
| 194 unsigned char *begin; | 226 unsigned char *begin; |
| 195 | 227 |
| 196 usb_interface->num_altsetting = 0; | 228 usb_interface->num_altsetting = 0; |
| 197 | 229 |
| 198 while (size >= INTERFACE_DESC_LENGTH) { | 230 while (size >= INTERFACE_DESC_LENGTH) { |
| 199 struct libusb_interface_descriptor *altsetting = | 231 struct libusb_interface_descriptor *altsetting = |
| 200 (struct libusb_interface_descriptor *) usb_interface->al
tsetting; | 232 (struct libusb_interface_descriptor *) usb_interface->al
tsetting; |
| 201 » » altsetting = realloc(altsetting, | 233 » » altsetting = usbi_reallocf(altsetting, |
| 202 sizeof(struct libusb_interface_descriptor) * | 234 sizeof(struct libusb_interface_descriptor) * |
| 203 (usb_interface->num_altsetting + 1)); | 235 (usb_interface->num_altsetting + 1)); |
| 204 if (!altsetting) { | 236 if (!altsetting) { |
| 205 r = LIBUSB_ERROR_NO_MEM; | 237 r = LIBUSB_ERROR_NO_MEM; |
| 206 goto err; | 238 goto err; |
| 207 } | 239 } |
| 208 usb_interface->altsetting = altsetting; | 240 usb_interface->altsetting = altsetting; |
| 209 | 241 |
| 210 ifp = altsetting + usb_interface->num_altsetting; | 242 ifp = altsetting + usb_interface->num_altsetting; |
| 243 usbi_parse_descriptor(buffer, "bbbbbbbbb", ifp, 0); |
| 244 if (ifp->bDescriptorType != LIBUSB_DT_INTERFACE) { |
| 245 usbi_err(ctx, "unexpected descriptor %x (expected %x)", |
| 246 ifp->bDescriptorType, LIBUSB_DT_INTERFACE); |
| 247 return parsed; |
| 248 } |
| 249 if (ifp->bLength < INTERFACE_DESC_LENGTH) { |
| 250 usbi_err(ctx, "invalid interface bLength (%d)", |
| 251 ifp->bLength); |
| 252 r = LIBUSB_ERROR_IO; |
| 253 goto err; |
| 254 } |
| 255 if (ifp->bLength > size) { |
| 256 usbi_warn(ctx, "short intf descriptor read %d/%d", |
| 257 size, ifp->bLength); |
| 258 return parsed; |
| 259 } |
| 260 if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { |
| 261 usbi_err(ctx, "too many endpoints (%d)", ifp->bNumEndpoi
nts); |
| 262 r = LIBUSB_ERROR_IO; |
| 263 goto err; |
| 264 } |
| 265 |
| 211 usb_interface->num_altsetting++; | 266 usb_interface->num_altsetting++; |
| 212 usbi_parse_descriptor(buffer, "bbbbbbbbb", ifp, 0); | |
| 213 ifp->extra = NULL; | 267 ifp->extra = NULL; |
| 214 ifp->extra_length = 0; | 268 ifp->extra_length = 0; |
| 215 ifp->endpoint = NULL; | 269 ifp->endpoint = NULL; |
| 216 | 270 |
| 271 if (interface_number == -1) |
| 272 interface_number = ifp->bInterfaceNumber; |
| 273 |
| 217 /* Skip over the interface */ | 274 /* Skip over the interface */ |
| 218 buffer += ifp->bLength; | 275 buffer += ifp->bLength; |
| 219 parsed += ifp->bLength; | 276 parsed += ifp->bLength; |
| 220 size -= ifp->bLength; | 277 size -= ifp->bLength; |
| 221 | 278 |
| 222 begin = buffer; | 279 begin = buffer; |
| 223 | 280 |
| 224 /* Skip over any interface, class or vendor descriptors */ | 281 /* Skip over any interface, class or vendor descriptors */ |
| 225 while (size >= DESC_HEADER_LENGTH) { | 282 while (size >= DESC_HEADER_LENGTH) { |
| 226 usbi_parse_descriptor(buffer, "bb", &header, 0); | 283 usbi_parse_descriptor(buffer, "bb", &header, 0); |
| 227 » » » if (header.bLength < 2) { | 284 » » » if (header.bLength < DESC_HEADER_LENGTH) { |
| 228 » » » » usbi_err(ctx, "invalid descriptor of length %d", | 285 » » » » usbi_err(ctx, |
| 229 » » » » » header.bLength); | 286 » » » » » "invalid extra intf desc len (%d)", |
| 287 » » » » » header.bLength); |
| 230 r = LIBUSB_ERROR_IO; | 288 r = LIBUSB_ERROR_IO; |
| 231 goto err; | 289 goto err; |
| 290 } else if (header.bLength > size) { |
| 291 usbi_warn(ctx, |
| 292 "short extra intf desc read %d/%d", |
| 293 size, header.bLength); |
| 294 return parsed; |
| 232 } | 295 } |
| 233 | 296 |
| 234 /* If we find another "proper" descriptor then we're don
e */ | 297 /* If we find another "proper" descriptor then we're don
e */ |
| 235 if ((header.bDescriptorType == LIBUSB_DT_INTERFACE) || | 298 if ((header.bDescriptorType == LIBUSB_DT_INTERFACE) || |
| 236 (header.bDescriptorType == LIBUSB_DT_END
POINT) || | 299 (header.bDescriptorType == LIBUSB_DT_END
POINT) || |
| 237 (header.bDescriptorType == LIBUSB_DT_CON
FIG) || | 300 (header.bDescriptorType == LIBUSB_DT_CON
FIG) || |
| 238 (header.bDescriptorType == LIBUSB_DT_DEV
ICE)) | 301 (header.bDescriptorType == LIBUSB_DT_DEV
ICE)) |
| 239 break; | 302 break; |
| 240 | 303 |
| 241 buffer += header.bLength; | 304 buffer += header.bLength; |
| 242 parsed += header.bLength; | 305 parsed += header.bLength; |
| 243 size -= header.bLength; | 306 size -= header.bLength; |
| 244 } | 307 } |
| 245 | 308 |
| 246 /* Copy any unknown descriptors into a storage area for */ | 309 /* Copy any unknown descriptors into a storage area for */ |
| 247 /* drivers to later parse */ | 310 /* drivers to later parse */ |
| 248 len = (int)(buffer - begin); | 311 len = (int)(buffer - begin); |
| 249 if (len) { | 312 if (len) { |
| 250 ifp->extra = malloc(len); | 313 ifp->extra = malloc(len); |
| 251 if (!ifp->extra) { | 314 if (!ifp->extra) { |
| 252 r = LIBUSB_ERROR_NO_MEM; | 315 r = LIBUSB_ERROR_NO_MEM; |
| 253 goto err; | 316 goto err; |
| 254 } | 317 } |
| 255 memcpy((unsigned char *) ifp->extra, begin, len); | 318 memcpy((unsigned char *) ifp->extra, begin, len); |
| 256 ifp->extra_length = len; | 319 ifp->extra_length = len; |
| 257 } | 320 } |
| 258 | 321 |
| 259 /* Did we hit an unexpected descriptor? */ | |
| 260 if (size >= DESC_HEADER_LENGTH) { | |
| 261 usbi_parse_descriptor(buffer, "bb", &header, 0); | |
| 262 if ((header.bDescriptorType == LIBUSB_DT_CONFIG) || | |
| 263 (header.bDescriptorType == LIBUSB_DT_DEVICE)) { | |
| 264 return parsed; | |
| 265 } | |
| 266 } | |
| 267 | |
| 268 if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { | |
| 269 usbi_err(ctx, "too many endpoints (%d)", ifp->bNumEndpoi
nts); | |
| 270 r = LIBUSB_ERROR_IO; | |
| 271 goto err; | |
| 272 } | |
| 273 | |
| 274 if (ifp->bNumEndpoints > 0) { | 322 if (ifp->bNumEndpoints > 0) { |
| 275 struct libusb_endpoint_descriptor *endpoint; | 323 struct libusb_endpoint_descriptor *endpoint; |
| 276 tmp = ifp->bNumEndpoints * sizeof(struct libusb_endpoint
_descriptor); | 324 tmp = ifp->bNumEndpoints * sizeof(struct libusb_endpoint
_descriptor); |
| 277 endpoint = malloc(tmp); | 325 endpoint = malloc(tmp); |
| 278 ifp->endpoint = endpoint; | 326 ifp->endpoint = endpoint; |
| 279 if (!endpoint) { | 327 if (!endpoint) { |
| 280 r = LIBUSB_ERROR_NO_MEM; | 328 r = LIBUSB_ERROR_NO_MEM; |
| 281 goto err; | 329 goto err; |
| 282 } | 330 } |
| 283 | 331 |
| 284 memset(endpoint, 0, tmp); | 332 memset(endpoint, 0, tmp); |
| 285 for (i = 0; i < ifp->bNumEndpoints; i++) { | 333 for (i = 0; i < ifp->bNumEndpoints; i++) { |
| 286 usbi_parse_descriptor(buffer, "bb", &header, 0); | |
| 287 | |
| 288 if (header.bLength > size) { | |
| 289 usbi_err(ctx, "ran out of descriptors pa
rsing"); | |
| 290 r = LIBUSB_ERROR_IO; | |
| 291 goto err; | |
| 292 } | |
| 293 | |
| 294 r = parse_endpoint(ctx, endpoint + i, buffer, si
ze, | 334 r = parse_endpoint(ctx, endpoint + i, buffer, si
ze, |
| 295 host_endian); | 335 host_endian); |
| 296 if (r < 0) | 336 if (r < 0) |
| 297 goto err; | 337 goto err; |
| 338 if (r == 0) { |
| 339 ifp->bNumEndpoints = (uint8_t)i; |
| 340 break;; |
| 341 } |
| 298 | 342 |
| 299 buffer += r; | 343 buffer += r; |
| 300 parsed += r; | 344 parsed += r; |
| 301 size -= r; | 345 size -= r; |
| 302 } | 346 } |
| 303 } | 347 } |
| 304 | 348 |
| 305 /* We check to see if it's an alternate to this one */ | 349 /* We check to see if it's an alternate to this one */ |
| 306 ifp = (struct libusb_interface_descriptor *) buffer; | 350 ifp = (struct libusb_interface_descriptor *) buffer; |
| 307 if (size < LIBUSB_DT_INTERFACE_SIZE || | 351 if (size < LIBUSB_DT_INTERFACE_SIZE || |
| 308 ifp->bDescriptorType != LIBUSB_DT_INTERFACE || | 352 ifp->bDescriptorType != LIBUSB_DT_INTERFACE || |
| 309 » » » » !ifp->bAlternateSetting) | 353 » » » » ifp->bInterfaceNumber != interface_number) |
| 310 return parsed; | 354 return parsed; |
| 311 } | 355 } |
| 312 | 356 |
| 313 return parsed; | 357 return parsed; |
| 314 err: | 358 err: |
| 315 clear_interface(usb_interface); | 359 clear_interface(usb_interface); |
| 316 return r; | 360 return r; |
| 317 } | 361 } |
| 318 | 362 |
| 319 static void clear_configuration(struct libusb_config_descriptor *config) | 363 static void clear_configuration(struct libusb_config_descriptor *config) |
| 320 { | 364 { |
| 321 if (config->interface) { | 365 if (config->interface) { |
| 322 int i; | 366 int i; |
| 323 for (i = 0; i < config->bNumInterfaces; i++) | 367 for (i = 0; i < config->bNumInterfaces; i++) |
| 324 clear_interface((struct libusb_interface *) | 368 clear_interface((struct libusb_interface *) |
| 325 config->interface + i); | 369 config->interface + i); |
| 326 free((void *) config->interface); | 370 free((void *) config->interface); |
| 327 } | 371 } |
| 328 if (config->extra) | 372 if (config->extra) |
| 329 free((void *) config->extra); | 373 free((void *) config->extra); |
| 330 } | 374 } |
| 331 | 375 |
| 332 static int parse_configuration(struct libusb_context *ctx, | 376 static int parse_configuration(struct libusb_context *ctx, |
| 333 struct libusb_config_descriptor *config, unsigned char *buffer, | 377 struct libusb_config_descriptor *config, unsigned char *buffer, |
| 334 » int host_endian) | 378 » int size, int host_endian) |
| 335 { | 379 { |
| 336 int i; | 380 int i; |
| 337 int r; | 381 int r; |
| 338 int size; | |
| 339 size_t tmp; | 382 size_t tmp; |
| 340 struct usb_descriptor_header header; | 383 struct usb_descriptor_header header; |
| 341 struct libusb_interface *usb_interface; | 384 struct libusb_interface *usb_interface; |
| 342 | 385 |
| 386 if (size < LIBUSB_DT_CONFIG_SIZE) { |
| 387 usbi_err(ctx, "short config descriptor read %d/%d", |
| 388 size, LIBUSB_DT_CONFIG_SIZE); |
| 389 return LIBUSB_ERROR_IO; |
| 390 } |
| 391 |
| 343 usbi_parse_descriptor(buffer, "bbwbbbbb", config, host_endian); | 392 usbi_parse_descriptor(buffer, "bbwbbbbb", config, host_endian); |
| 344 » size = config->wTotalLength; | 393 » if (config->bDescriptorType != LIBUSB_DT_CONFIG) { |
| 345 | 394 » » usbi_err(ctx, "unexpected descriptor %x (expected %x)", |
| 395 » » » config->bDescriptorType, LIBUSB_DT_CONFIG); |
| 396 » » return LIBUSB_ERROR_IO; |
| 397 » } |
| 398 » if (config->bLength < LIBUSB_DT_CONFIG_SIZE) { |
| 399 » » usbi_err(ctx, "invalid config bLength (%d)", config->bLength); |
| 400 » » return LIBUSB_ERROR_IO; |
| 401 » } |
| 402 » if (config->bLength > size) { |
| 403 » » usbi_err(ctx, "short config descriptor read %d/%d", |
| 404 » » » size, config->bLength); |
| 405 » » return LIBUSB_ERROR_IO; |
| 406 » } |
| 346 if (config->bNumInterfaces > USB_MAXINTERFACES) { | 407 if (config->bNumInterfaces > USB_MAXINTERFACES) { |
| 347 usbi_err(ctx, "too many interfaces (%d)", config->bNumInterfaces
); | 408 usbi_err(ctx, "too many interfaces (%d)", config->bNumInterfaces
); |
| 348 return LIBUSB_ERROR_IO; | 409 return LIBUSB_ERROR_IO; |
| 349 } | 410 } |
| 350 | 411 |
| 351 tmp = config->bNumInterfaces * sizeof(struct libusb_interface); | 412 tmp = config->bNumInterfaces * sizeof(struct libusb_interface); |
| 352 usb_interface = malloc(tmp); | 413 usb_interface = malloc(tmp); |
| 353 config->interface = usb_interface; | 414 config->interface = usb_interface; |
| 354 if (!config->interface) | 415 if (!config->interface) |
| 355 return LIBUSB_ERROR_NO_MEM; | 416 return LIBUSB_ERROR_NO_MEM; |
| 356 | 417 |
| 357 memset(usb_interface, 0, tmp); | 418 memset(usb_interface, 0, tmp); |
| 358 buffer += config->bLength; | 419 buffer += config->bLength; |
| 359 size -= config->bLength; | 420 size -= config->bLength; |
| 360 | 421 |
| 361 config->extra = NULL; | 422 config->extra = NULL; |
| 362 config->extra_length = 0; | 423 config->extra_length = 0; |
| 363 | 424 |
| 364 for (i = 0; i < config->bNumInterfaces; i++) { | 425 for (i = 0; i < config->bNumInterfaces; i++) { |
| 365 int len; | 426 int len; |
| 366 unsigned char *begin; | 427 unsigned char *begin; |
| 367 | 428 |
| 368 /* Skip over the rest of the Class Specific or Vendor */ | 429 /* Skip over the rest of the Class Specific or Vendor */ |
| 369 /* Specific descriptors */ | 430 /* Specific descriptors */ |
| 370 begin = buffer; | 431 begin = buffer; |
| 371 while (size >= DESC_HEADER_LENGTH) { | 432 while (size >= DESC_HEADER_LENGTH) { |
| 372 usbi_parse_descriptor(buffer, "bb", &header, 0); | 433 usbi_parse_descriptor(buffer, "bb", &header, 0); |
| 373 | 434 |
| 374 » » » if ((header.bLength > size) || | 435 » » » if (header.bLength < DESC_HEADER_LENGTH) { |
| 375 » » » » » (header.bLength < DESC_HEADER_LENGTH)) { | 436 » » » » usbi_err(ctx, |
| 376 » » » » usbi_err(ctx, "invalid descriptor length of %d", | 437 » » » » » "invalid extra config desc len (%d)", |
| 377 » » » » » header.bLength); | 438 » » » » » header.bLength); |
| 378 r = LIBUSB_ERROR_IO; | 439 r = LIBUSB_ERROR_IO; |
| 379 goto err; | 440 goto err; |
| 441 } else if (header.bLength > size) { |
| 442 usbi_warn(ctx, |
| 443 "short extra config desc read %d/%d", |
| 444 size, header.bLength); |
| 445 config->bNumInterfaces = (uint8_t)i; |
| 446 return size; |
| 380 } | 447 } |
| 381 | 448 |
| 382 /* If we find another "proper" descriptor then we're don
e */ | 449 /* If we find another "proper" descriptor then we're don
e */ |
| 383 if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) || | 450 if ((header.bDescriptorType == LIBUSB_DT_ENDPOINT) || |
| 384 (header.bDescriptorType == LIBUSB_DT_INT
ERFACE) || | 451 (header.bDescriptorType == LIBUSB_DT_INT
ERFACE) || |
| 385 (header.bDescriptorType == LIBUSB_DT_CON
FIG) || | 452 (header.bDescriptorType == LIBUSB_DT_CON
FIG) || |
| 386 (header.bDescriptorType == LIBUSB_DT_DEV
ICE)) | 453 (header.bDescriptorType == LIBUSB_DT_DEV
ICE)) |
| 387 break; | 454 break; |
| 388 | 455 |
| 389 usbi_dbg("skipping descriptor 0x%x\n", header.bDescripto
rType); | 456 usbi_dbg("skipping descriptor 0x%x\n", header.bDescripto
rType); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 404 } | 471 } |
| 405 | 472 |
| 406 memcpy((unsigned char *) config->extra, begin, l
en); | 473 memcpy((unsigned char *) config->extra, begin, l
en); |
| 407 config->extra_length = len; | 474 config->extra_length = len; |
| 408 } | 475 } |
| 409 } | 476 } |
| 410 | 477 |
| 411 r = parse_interface(ctx, usb_interface + i, buffer, size, host_e
ndian); | 478 r = parse_interface(ctx, usb_interface + i, buffer, size, host_e
ndian); |
| 412 if (r < 0) | 479 if (r < 0) |
| 413 goto err; | 480 goto err; |
| 481 if (r == 0) { |
| 482 config->bNumInterfaces = (uint8_t)i; |
| 483 break; |
| 484 } |
| 414 | 485 |
| 415 buffer += r; | 486 buffer += r; |
| 416 size -= r; | 487 size -= r; |
| 417 } | 488 } |
| 418 | 489 |
| 419 return size; | 490 return size; |
| 420 | 491 |
| 421 err: | 492 err: |
| 422 clear_configuration(config); | 493 clear_configuration(config); |
| 423 return r; | 494 return r; |
| 424 } | 495 } |
| 425 | 496 |
| 497 static int raw_desc_to_config(struct libusb_context *ctx, |
| 498 unsigned char *buf, int size, int host_endian, |
| 499 struct libusb_config_descriptor **config) |
| 500 { |
| 501 struct libusb_config_descriptor *_config = malloc(sizeof(*_config)); |
| 502 int r; |
| 503 |
| 504 if (!_config) |
| 505 return LIBUSB_ERROR_NO_MEM; |
| 506 |
| 507 r = parse_configuration(ctx, _config, buf, size, host_endian); |
| 508 if (r < 0) { |
| 509 usbi_err(ctx, "parse_configuration failed with error %d", r); |
| 510 free(_config); |
| 511 return r; |
| 512 } else if (r > 0) { |
| 513 usbi_warn(ctx, "still %d bytes of descriptor data left", r); |
| 514 } |
| 515 |
| 516 *config = _config; |
| 517 return LIBUSB_SUCCESS; |
| 518 } |
| 519 |
| 520 int usbi_device_cache_descriptor(libusb_device *dev) |
| 521 { |
| 522 int r, host_endian = 0; |
| 523 |
| 524 r = usbi_backend->get_device_descriptor(dev, (unsigned char *) &dev->dev
ice_descriptor, |
| 525 &host_endian); |
| 526 if (r < 0) |
| 527 return r; |
| 528 |
| 529 if (!host_endian) { |
| 530 dev->device_descriptor.bcdUSB = libusb_le16_to_cpu(dev->device_d
escriptor.bcdUSB); |
| 531 dev->device_descriptor.idVendor = libusb_le16_to_cpu(dev->device
_descriptor.idVendor); |
| 532 dev->device_descriptor.idProduct = libusb_le16_to_cpu(dev->devic
e_descriptor.idProduct); |
| 533 dev->device_descriptor.bcdDevice = libusb_le16_to_cpu(dev->devic
e_descriptor.bcdDevice); |
| 534 } |
| 535 |
| 536 return LIBUSB_SUCCESS; |
| 537 } |
| 538 |
| 426 /** \ingroup desc | 539 /** \ingroup desc |
| 427 * Get the USB device descriptor for a given device. | 540 * Get the USB device descriptor for a given device. |
| 428 * | 541 * |
| 429 * This is a non-blocking function; the device descriptor is cached in memory. | 542 * This is a non-blocking function; the device descriptor is cached in memory. |
| 430 * | 543 * |
| 544 * Note since libusbx-1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102, this |
| 545 * function always succeeds. |
| 546 * |
| 431 * \param dev the device | 547 * \param dev the device |
| 432 * \param desc output location for the descriptor data | 548 * \param desc output location for the descriptor data |
| 433 * \returns 0 on success or a LIBUSB_ERROR code on failure | 549 * \returns 0 on success or a LIBUSB_ERROR code on failure |
| 434 */ | 550 */ |
| 435 int API_EXPORTED libusb_get_device_descriptor(libusb_device *dev, | 551 int API_EXPORTED libusb_get_device_descriptor(libusb_device *dev, |
| 436 struct libusb_device_descriptor *desc) | 552 struct libusb_device_descriptor *desc) |
| 437 { | 553 { |
| 438 unsigned char raw_desc[DEVICE_DESC_LENGTH]; | |
| 439 int host_endian = 0; | |
| 440 int r; | |
| 441 | |
| 442 usbi_dbg(""); | 554 usbi_dbg(""); |
| 443 » r = usbi_backend->get_device_descriptor(dev, raw_desc, &host_endian); | 555 » memcpy((unsigned char *) desc, (unsigned char *) &dev->device_descriptor
, |
| 444 » if (r < 0) | 556 » sizeof (dev->device_descriptor)); |
| 445 » » return r; | |
| 446 | |
| 447 » memcpy((unsigned char *) desc, raw_desc, sizeof(raw_desc)); | |
| 448 » if (!host_endian) { | |
| 449 » » desc->bcdUSB = libusb_le16_to_cpu(desc->bcdUSB); | |
| 450 » » desc->idVendor = libusb_le16_to_cpu(desc->idVendor); | |
| 451 » » desc->idProduct = libusb_le16_to_cpu(desc->idProduct); | |
| 452 » » desc->bcdDevice = libusb_le16_to_cpu(desc->bcdDevice); | |
| 453 » } | |
| 454 return 0; | 557 return 0; |
| 455 } | 558 } |
| 456 | 559 |
| 457 /** \ingroup desc | 560 /** \ingroup desc |
| 458 * Get the USB configuration descriptor for the currently active configuration. | 561 * Get the USB configuration descriptor for the currently active configuration. |
| 459 * This is a non-blocking function which does not involve any requests being | 562 * This is a non-blocking function which does not involve any requests being |
| 460 * sent to the device. | 563 * sent to the device. |
| 461 * | 564 * |
| 462 * \param dev a device | 565 * \param dev a device |
| 463 * \param config output location for the USB configuration descriptor. Only | 566 * \param config output location for the USB configuration descriptor. Only |
| 464 * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() | 567 * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() |
| 465 * after use. | 568 * after use. |
| 466 * \returns 0 on success | 569 * \returns 0 on success |
| 467 * \returns LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state | 570 * \returns LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state |
| 468 * \returns another LIBUSB_ERROR code on error | 571 * \returns another LIBUSB_ERROR code on error |
| 469 * \see libusb_get_config_descriptor | 572 * \see libusb_get_config_descriptor |
| 470 */ | 573 */ |
| 471 int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev, | 574 int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev, |
| 472 struct libusb_config_descriptor **config) | 575 struct libusb_config_descriptor **config) |
| 473 { | 576 { |
| 474 » struct libusb_config_descriptor *_config = malloc(sizeof(*_config)); | 577 » struct libusb_config_descriptor _config; |
| 475 » unsigned char tmp[8]; | 578 » unsigned char tmp[LIBUSB_DT_CONFIG_SIZE]; |
| 476 unsigned char *buf = NULL; | 579 unsigned char *buf = NULL; |
| 477 int host_endian = 0; | 580 int host_endian = 0; |
| 478 int r; | 581 int r; |
| 479 | 582 |
| 480 » usbi_dbg(""); | 583 » r = usbi_backend->get_active_config_descriptor(dev, tmp, |
| 481 » if (!_config) | 584 » » LIBUSB_DT_CONFIG_SIZE, &host_endian); |
| 585 » if (r < 0) |
| 586 » » return r; |
| 587 » if (r < LIBUSB_DT_CONFIG_SIZE) { |
| 588 » » usbi_err(dev->ctx, "short config descriptor read %d/%d", |
| 589 » » » r, LIBUSB_DT_CONFIG_SIZE); |
| 590 » » return LIBUSB_ERROR_IO; |
| 591 » } |
| 592 |
| 593 » usbi_parse_descriptor(tmp, "bbw", &_config, host_endian); |
| 594 » buf = malloc(_config.wTotalLength); |
| 595 » if (!buf) |
| 482 return LIBUSB_ERROR_NO_MEM; | 596 return LIBUSB_ERROR_NO_MEM; |
| 483 | 597 |
| 484 r = usbi_backend->get_active_config_descriptor(dev, tmp, sizeof(tmp), | |
| 485 &host_endian); | |
| 486 if (r < 0) | |
| 487 goto err; | |
| 488 | |
| 489 usbi_parse_descriptor(tmp, "bbw", _config, host_endian); | |
| 490 buf = malloc(_config->wTotalLength); | |
| 491 if (!buf) { | |
| 492 r = LIBUSB_ERROR_NO_MEM; | |
| 493 goto err; | |
| 494 } | |
| 495 | |
| 496 r = usbi_backend->get_active_config_descriptor(dev, buf, | 598 r = usbi_backend->get_active_config_descriptor(dev, buf, |
| 497 » » _config->wTotalLength, &host_endian); | 599 » » _config.wTotalLength, &host_endian); |
| 498 » if (r < 0) | 600 » if (r >= 0) |
| 499 » » goto err; | 601 » » r = raw_desc_to_config(dev->ctx, buf, r, host_endian, config); |
| 500 | |
| 501 » r = parse_configuration(dev->ctx, _config, buf, host_endian); | |
| 502 » if (r < 0) { | |
| 503 » » usbi_err(dev->ctx, "parse_configuration failed with error %d", r
); | |
| 504 » » goto err; | |
| 505 » } else if (r > 0) { | |
| 506 » » usbi_warn(dev->ctx, "descriptor data still left"); | |
| 507 » } | |
| 508 | 602 |
| 509 free(buf); | 603 free(buf); |
| 510 *config = _config; | |
| 511 return 0; | |
| 512 | |
| 513 err: | |
| 514 free(_config); | |
| 515 if (buf) | |
| 516 free(buf); | |
| 517 return r; | 604 return r; |
| 518 } | 605 } |
| 519 | 606 |
| 520 /** \ingroup desc | 607 /** \ingroup desc |
| 521 * Get a USB configuration descriptor based on its index. | 608 * Get a USB configuration descriptor based on its index. |
| 522 * This is a non-blocking function which does not involve any requests being | 609 * This is a non-blocking function which does not involve any requests being |
| 523 * sent to the device. | 610 * sent to the device. |
| 524 * | 611 * |
| 525 * \param dev a device | 612 * \param dev a device |
| 526 * \param config_index the index of the configuration you wish to retrieve | 613 * \param config_index the index of the configuration you wish to retrieve |
| 527 * \param config output location for the USB configuration descriptor. Only | 614 * \param config output location for the USB configuration descriptor. Only |
| 528 * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() | 615 * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() |
| 529 * after use. | 616 * after use. |
| 530 * \returns 0 on success | 617 * \returns 0 on success |
| 531 * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist | 618 * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist |
| 532 * \returns another LIBUSB_ERROR code on error | 619 * \returns another LIBUSB_ERROR code on error |
| 533 * \see libusb_get_active_config_descriptor() | 620 * \see libusb_get_active_config_descriptor() |
| 534 * \see libusb_get_config_descriptor_by_value() | 621 * \see libusb_get_config_descriptor_by_value() |
| 535 */ | 622 */ |
| 536 int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev, | 623 int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev, |
| 537 uint8_t config_index, struct libusb_config_descriptor **config) | 624 uint8_t config_index, struct libusb_config_descriptor **config) |
| 538 { | 625 { |
| 539 » struct libusb_config_descriptor *_config; | 626 » struct libusb_config_descriptor _config; |
| 540 » unsigned char tmp[8]; | 627 » unsigned char tmp[LIBUSB_DT_CONFIG_SIZE]; |
| 541 unsigned char *buf = NULL; | 628 unsigned char *buf = NULL; |
| 542 int host_endian = 0; | 629 int host_endian = 0; |
| 543 int r; | 630 int r; |
| 544 | 631 |
| 545 usbi_dbg("index %d", config_index); | 632 usbi_dbg("index %d", config_index); |
| 546 if (config_index >= dev->num_configurations) | 633 if (config_index >= dev->num_configurations) |
| 547 return LIBUSB_ERROR_NOT_FOUND; | 634 return LIBUSB_ERROR_NOT_FOUND; |
| 548 | 635 |
| 549 » _config = malloc(sizeof(*_config)); | 636 » r = usbi_backend->get_config_descriptor(dev, config_index, tmp, |
| 550 » if (!_config) | 637 » » LIBUSB_DT_CONFIG_SIZE, &host_endian); |
| 638 » if (r < 0) |
| 639 » » return r; |
| 640 » if (r < LIBUSB_DT_CONFIG_SIZE) { |
| 641 » » usbi_err(dev->ctx, "short config descriptor read %d/%d", |
| 642 » » » r, LIBUSB_DT_CONFIG_SIZE); |
| 643 » » return LIBUSB_ERROR_IO; |
| 644 » } |
| 645 |
| 646 » usbi_parse_descriptor(tmp, "bbw", &_config, host_endian); |
| 647 » buf = malloc(_config.wTotalLength); |
| 648 » if (!buf) |
| 551 return LIBUSB_ERROR_NO_MEM; | 649 return LIBUSB_ERROR_NO_MEM; |
| 552 | 650 |
| 553 r = usbi_backend->get_config_descriptor(dev, config_index, tmp, | |
| 554 sizeof(tmp), &host_endian); | |
| 555 if (r < 0) | |
| 556 goto err; | |
| 557 | |
| 558 usbi_parse_descriptor(tmp, "bbw", _config, host_endian); | |
| 559 buf = malloc(_config->wTotalLength); | |
| 560 if (!buf) { | |
| 561 r = LIBUSB_ERROR_NO_MEM; | |
| 562 goto err; | |
| 563 } | |
| 564 | |
| 565 host_endian = 0; | |
| 566 r = usbi_backend->get_config_descriptor(dev, config_index, buf, | 651 r = usbi_backend->get_config_descriptor(dev, config_index, buf, |
| 567 » » _config->wTotalLength, &host_endian); | 652 » » _config.wTotalLength, &host_endian); |
| 568 » if (r < 0) | 653 » if (r >= 0) |
| 569 » » goto err; | 654 » » r = raw_desc_to_config(dev->ctx, buf, r, host_endian, config); |
| 570 | |
| 571 » r = parse_configuration(dev->ctx, _config, buf, host_endian); | |
| 572 » if (r < 0) { | |
| 573 » » usbi_err(dev->ctx, "parse_configuration failed with error %d", r
); | |
| 574 » » goto err; | |
| 575 » } else if (r > 0) { | |
| 576 » » usbi_warn(dev->ctx, "descriptor data still left"); | |
| 577 » } | |
| 578 | 655 |
| 579 free(buf); | 656 free(buf); |
| 580 *config = _config; | |
| 581 return 0; | |
| 582 | |
| 583 err: | |
| 584 free(_config); | |
| 585 if (buf) | |
| 586 free(buf); | |
| 587 return r; | 657 return r; |
| 588 } | 658 } |
| 589 | 659 |
| 590 /* iterate through all configurations, returning the index of the configuration | 660 /* iterate through all configurations, returning the index of the configuration |
| 591 * matching a specific bConfigurationValue in the idx output parameter, or -1 | 661 * matching a specific bConfigurationValue in the idx output parameter, or -1 |
| 592 * if the config was not found. | 662 * if the config was not found. |
| 593 * returns 0 or a LIBUSB_ERROR code | 663 * returns 0 or a LIBUSB_ERROR code |
| 594 */ | 664 */ |
| 595 int usbi_get_config_index_by_value(struct libusb_device *dev, | 665 int usbi_get_config_index_by_value(struct libusb_device *dev, |
| 596 uint8_t bConfigurationValue, int *idx) | 666 uint8_t bConfigurationValue, int *idx) |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 628 * after use. | 698 * after use. |
| 629 * \returns 0 on success | 699 * \returns 0 on success |
| 630 * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist | 700 * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist |
| 631 * \returns another LIBUSB_ERROR code on error | 701 * \returns another LIBUSB_ERROR code on error |
| 632 * \see libusb_get_active_config_descriptor() | 702 * \see libusb_get_active_config_descriptor() |
| 633 * \see libusb_get_config_descriptor() | 703 * \see libusb_get_config_descriptor() |
| 634 */ | 704 */ |
| 635 int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev, | 705 int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev, |
| 636 uint8_t bConfigurationValue, struct libusb_config_descriptor **config) | 706 uint8_t bConfigurationValue, struct libusb_config_descriptor **config) |
| 637 { | 707 { |
| 638 » int idx; | 708 » int r, idx, host_endian; |
| 639 » int r = usbi_get_config_index_by_value(dev, bConfigurationValue, &idx); | 709 » unsigned char *buf = NULL; |
| 710 |
| 711 » if (usbi_backend->get_config_descriptor_by_value) { |
| 712 » » r = usbi_backend->get_config_descriptor_by_value(dev, |
| 713 » » » bConfigurationValue, &buf, &host_endian); |
| 714 » » if (r < 0) |
| 715 » » » return r; |
| 716 » » return raw_desc_to_config(dev->ctx, buf, r, host_endian, config)
; |
| 717 » } |
| 718 |
| 719 » r = usbi_get_config_index_by_value(dev, bConfigurationValue, &idx); |
| 640 if (r < 0) | 720 if (r < 0) |
| 641 return r; | 721 return r; |
| 642 else if (idx == -1) | 722 else if (idx == -1) |
| 643 return LIBUSB_ERROR_NOT_FOUND; | 723 return LIBUSB_ERROR_NOT_FOUND; |
| 644 else | 724 else |
| 645 return libusb_get_config_descriptor(dev, (uint8_t) idx, config); | 725 return libusb_get_config_descriptor(dev, (uint8_t) idx, config); |
| 646 } | 726 } |
| 647 | 727 |
| 648 /** \ingroup desc | 728 /** \ingroup desc |
| 649 * Free a configuration descriptor obtained from | 729 * Free a configuration descriptor obtained from |
| 650 * libusb_get_active_config_descriptor() or libusb_get_config_descriptor(). | 730 * libusb_get_active_config_descriptor() or libusb_get_config_descriptor(). |
| 651 * It is safe to call this function with a NULL config parameter, in which | 731 * It is safe to call this function with a NULL config parameter, in which |
| 652 * case the function simply returns. | 732 * case the function simply returns. |
| 653 * | 733 * |
| 654 * \param config the configuration descriptor to free | 734 * \param config the configuration descriptor to free |
| 655 */ | 735 */ |
| 656 void API_EXPORTED libusb_free_config_descriptor( | 736 void API_EXPORTED libusb_free_config_descriptor( |
| 657 struct libusb_config_descriptor *config) | 737 struct libusb_config_descriptor *config) |
| 658 { | 738 { |
| 659 if (!config) | 739 if (!config) |
| 660 return; | 740 return; |
| 661 | 741 |
| 662 clear_configuration(config); | 742 clear_configuration(config); |
| 663 free(config); | 743 free(config); |
| 664 } | 744 } |
| 665 | 745 |
| 666 /** \ingroup desc | 746 /** \ingroup desc |
| 747 * Get an endpoints superspeed endpoint companion descriptor (if any) |
| 748 * |
| 749 * \param ctx the context to operate on, or NULL for the default context |
| 750 * \param endpoint endpoint descriptor from which to get the superspeed |
| 751 * endpoint companion descriptor |
| 752 * \param ep_comp output location for the superspeed endpoint companion |
| 753 * descriptor. Only valid if 0 was returned. Must be freed with |
| 754 * libusb_free_ss_endpoint_companion_descriptor() after use. |
| 755 * \returns 0 on success |
| 756 * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist |
| 757 * \returns another LIBUSB_ERROR code on error |
| 758 */ |
| 759 int API_EXPORTED libusb_get_ss_endpoint_companion_descriptor( |
| 760 struct libusb_context *ctx, |
| 761 const struct libusb_endpoint_descriptor *endpoint, |
| 762 struct libusb_ss_endpoint_companion_descriptor **ep_comp) |
| 763 { |
| 764 struct usb_descriptor_header header; |
| 765 int size = endpoint->extra_length; |
| 766 const unsigned char *buffer = endpoint->extra; |
| 767 |
| 768 *ep_comp = NULL; |
| 769 |
| 770 while (size >= DESC_HEADER_LENGTH) { |
| 771 usbi_parse_descriptor(buffer, "bb", &header, 0); |
| 772 if (header.bLength < 2 || header.bLength > size) { |
| 773 usbi_err(ctx, "invalid descriptor length %d", |
| 774 header.bLength); |
| 775 return LIBUSB_ERROR_IO; |
| 776 } |
| 777 if (header.bDescriptorType != LIBUSB_DT_SS_ENDPOINT_COMPANION) { |
| 778 buffer += header.bLength; |
| 779 size -= header.bLength; |
| 780 continue; |
| 781 } |
| 782 if (header.bLength < LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE) { |
| 783 usbi_err(ctx, "invalid ss-ep-comp-desc length %d", |
| 784 header.bLength); |
| 785 return LIBUSB_ERROR_IO; |
| 786 } |
| 787 *ep_comp = malloc(sizeof(**ep_comp)); |
| 788 if (*ep_comp == NULL) |
| 789 return LIBUSB_ERROR_NO_MEM; |
| 790 usbi_parse_descriptor(buffer, "bbbbw", *ep_comp, 0); |
| 791 return LIBUSB_SUCCESS; |
| 792 } |
| 793 return LIBUSB_ERROR_NOT_FOUND; |
| 794 } |
| 795 |
| 796 /** \ingroup desc |
| 797 * Free a superspeed endpoint companion descriptor obtained from |
| 798 * libusb_get_ss_endpoint_companion_descriptor(). |
| 799 * It is safe to call this function with a NULL ep_comp parameter, in which |
| 800 * case the function simply returns. |
| 801 * |
| 802 * \param ep_comp the superspeed endpoint companion descriptor to free |
| 803 */ |
| 804 void API_EXPORTED libusb_free_ss_endpoint_companion_descriptor( |
| 805 struct libusb_ss_endpoint_companion_descriptor *ep_comp) |
| 806 { |
| 807 free(ep_comp); |
| 808 } |
| 809 |
| 810 static int parse_bos(struct libusb_context *ctx, |
| 811 struct libusb_bos_descriptor **bos, |
| 812 unsigned char *buffer, int size, int host_endian) |
| 813 { |
| 814 struct libusb_bos_descriptor bos_header, *_bos; |
| 815 struct libusb_bos_dev_capability_descriptor dev_cap; |
| 816 int i; |
| 817 |
| 818 if (size < LIBUSB_DT_BOS_SIZE) { |
| 819 usbi_err(ctx, "short bos descriptor read %d/%d", |
| 820 size, LIBUSB_DT_BOS_SIZE); |
| 821 return LIBUSB_ERROR_IO; |
| 822 } |
| 823 |
| 824 usbi_parse_descriptor(buffer, "bbwb", &bos_header, host_endian); |
| 825 if (bos_header.bDescriptorType != LIBUSB_DT_BOS) { |
| 826 usbi_err(ctx, "unexpected descriptor %x (expected %x)", |
| 827 bos_header.bDescriptorType, LIBUSB_DT_BOS); |
| 828 return LIBUSB_ERROR_IO; |
| 829 } |
| 830 if (bos_header.bLength < LIBUSB_DT_BOS_SIZE) { |
| 831 usbi_err(ctx, "invalid bos bLength (%d)", bos_header.bLength); |
| 832 return LIBUSB_ERROR_IO; |
| 833 } |
| 834 if (bos_header.bLength > size) { |
| 835 usbi_err(ctx, "short bos descriptor read %d/%d", |
| 836 size, bos_header.bLength); |
| 837 return LIBUSB_ERROR_IO; |
| 838 } |
| 839 |
| 840 _bos = calloc (1, |
| 841 sizeof(*_bos) + bos_header.bNumDeviceCaps * sizeof(void *)); |
| 842 if (!_bos) |
| 843 return LIBUSB_ERROR_NO_MEM; |
| 844 |
| 845 usbi_parse_descriptor(buffer, "bbwb", _bos, host_endian); |
| 846 buffer += bos_header.bLength; |
| 847 size -= bos_header.bLength; |
| 848 |
| 849 /* Get the device capability descriptors */ |
| 850 for (i = 0; i < bos_header.bNumDeviceCaps; i++) { |
| 851 if (size < LIBUSB_DT_DEVICE_CAPABILITY_SIZE) { |
| 852 usbi_warn(ctx, "short dev-cap descriptor read %d/%d", |
| 853 size, LIBUSB_DT_DEVICE_CAPABILITY_SIZE); |
| 854 break; |
| 855 } |
| 856 usbi_parse_descriptor(buffer, "bbb", &dev_cap, host_endian); |
| 857 if (dev_cap.bDescriptorType != LIBUSB_DT_DEVICE_CAPABILITY) { |
| 858 usbi_warn(ctx, "unexpected descriptor %x (expected %x)", |
| 859 dev_cap.bDescriptorType, LIBUSB_DT_DEVICE_CAPA
BILITY); |
| 860 break; |
| 861 } |
| 862 if (dev_cap.bLength < LIBUSB_DT_DEVICE_CAPABILITY_SIZE) { |
| 863 usbi_err(ctx, "invalid dev-cap bLength (%d)", |
| 864 dev_cap.bLength); |
| 865 libusb_free_bos_descriptor(_bos); |
| 866 return LIBUSB_ERROR_IO; |
| 867 } |
| 868 if (dev_cap.bLength > size) { |
| 869 usbi_warn(ctx, "short dev-cap descriptor read %d/%d", |
| 870 size, dev_cap.bLength); |
| 871 break; |
| 872 } |
| 873 |
| 874 _bos->dev_capability[i] = malloc(dev_cap.bLength); |
| 875 if (!_bos->dev_capability[i]) { |
| 876 libusb_free_bos_descriptor(_bos); |
| 877 return LIBUSB_ERROR_NO_MEM; |
| 878 } |
| 879 memcpy(_bos->dev_capability[i], buffer, dev_cap.bLength); |
| 880 buffer += dev_cap.bLength; |
| 881 size -= dev_cap.bLength; |
| 882 } |
| 883 _bos->bNumDeviceCaps = (uint8_t)i; |
| 884 *bos = _bos; |
| 885 |
| 886 return LIBUSB_SUCCESS; |
| 887 } |
| 888 |
| 889 /** \ingroup desc |
| 890 * Get a Binary Object Store (BOS) descriptor |
| 891 * This is a BLOCKING function, which will send requests to the device. |
| 892 * |
| 893 * \param handle the handle of an open libusb device |
| 894 * \param bos output location for the BOS descriptor. Only valid if 0 was return
ed. |
| 895 * Must be freed with \ref libusb_free_bos_descriptor() after use. |
| 896 * \returns 0 on success |
| 897 * \returns LIBUSB_ERROR_NOT_FOUND if the device doesn't have a BOS descriptor |
| 898 * \returns another LIBUSB_ERROR code on error |
| 899 */ |
| 900 int API_EXPORTED libusb_get_bos_descriptor(libusb_device_handle *handle, |
| 901 struct libusb_bos_descriptor **bos) |
| 902 { |
| 903 struct libusb_bos_descriptor _bos; |
| 904 uint8_t bos_header[LIBUSB_DT_BOS_SIZE] = {0}; |
| 905 unsigned char *bos_data = NULL; |
| 906 const int host_endian = 0; |
| 907 int r; |
| 908 |
| 909 /* Read the BOS. This generates 2 requests on the bus, |
| 910 * one for the header, and one for the full BOS */ |
| 911 r = libusb_get_descriptor(handle, LIBUSB_DT_BOS, 0, bos_header, |
| 912 LIBUSB_DT_BOS_SIZE); |
| 913 if (r < 0) { |
| 914 if (r != LIBUSB_ERROR_PIPE) |
| 915 usbi_err(handle->dev->ctx, "failed to read BOS (%d)", r)
; |
| 916 return r; |
| 917 } |
| 918 if (r < LIBUSB_DT_BOS_SIZE) { |
| 919 usbi_err(handle->dev->ctx, "short BOS read %d/%d", |
| 920 r, LIBUSB_DT_BOS_SIZE); |
| 921 return LIBUSB_ERROR_IO; |
| 922 } |
| 923 |
| 924 usbi_parse_descriptor(bos_header, "bbwb", &_bos, host_endian); |
| 925 usbi_dbg("found BOS descriptor: size %d bytes, %d capabilities", |
| 926 _bos.wTotalLength, _bos.bNumDeviceCaps); |
| 927 bos_data = calloc(_bos.wTotalLength, 1); |
| 928 if (bos_data == NULL) |
| 929 return LIBUSB_ERROR_NO_MEM; |
| 930 |
| 931 r = libusb_get_descriptor(handle, LIBUSB_DT_BOS, 0, bos_data, |
| 932 _bos.wTotalLength); |
| 933 if (r >= 0) |
| 934 r = parse_bos(handle->dev->ctx, bos, bos_data, r, host_endian); |
| 935 else |
| 936 usbi_err(handle->dev->ctx, "failed to read BOS (%d)", r); |
| 937 |
| 938 free(bos_data); |
| 939 return r; |
| 940 } |
| 941 |
| 942 /** \ingroup desc |
| 943 * Free a BOS descriptor obtained from libusb_get_bos_descriptor(). |
| 944 * It is safe to call this function with a NULL bos parameter, in which |
| 945 * case the function simply returns. |
| 946 * |
| 947 * \param bos the BOS descriptor to free |
| 948 */ |
| 949 void API_EXPORTED libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos) |
| 950 { |
| 951 int i; |
| 952 |
| 953 if (!bos) |
| 954 return; |
| 955 |
| 956 for (i = 0; i < bos->bNumDeviceCaps; i++) |
| 957 free(bos->dev_capability[i]); |
| 958 free(bos); |
| 959 } |
| 960 |
| 961 /** \ingroup desc |
| 962 * Get an USB 2.0 Extension descriptor |
| 963 * |
| 964 * \param ctx the context to operate on, or NULL for the default context |
| 965 * \param dev_cap Device Capability descriptor with a bDevCapabilityType of |
| 966 * \ref libusb_capability_type::LIBUSB_BT_USB_2_0_EXTENSION |
| 967 * LIBUSB_BT_USB_2_0_EXTENSION |
| 968 * \param usb_2_0_extension output location for the USB 2.0 Extension |
| 969 * descriptor. Only valid if 0 was returned. Must be freed with |
| 970 * libusb_free_usb_2_0_extension_descriptor() after use. |
| 971 * \returns 0 on success |
| 972 * \returns a LIBUSB_ERROR code on error |
| 973 */ |
| 974 int API_EXPORTED libusb_get_usb_2_0_extension_descriptor( |
| 975 struct libusb_context *ctx, |
| 976 struct libusb_bos_dev_capability_descriptor *dev_cap, |
| 977 struct libusb_usb_2_0_extension_descriptor **usb_2_0_extension) |
| 978 { |
| 979 struct libusb_usb_2_0_extension_descriptor *_usb_2_0_extension; |
| 980 const int host_endian = 0; |
| 981 |
| 982 if (dev_cap->bDevCapabilityType != LIBUSB_BT_USB_2_0_EXTENSION) { |
| 983 usbi_err(ctx, "unexpected bDevCapabilityType %x (expected %x)", |
| 984 dev_cap->bDevCapabilityType, |
| 985 LIBUSB_BT_USB_2_0_EXTENSION); |
| 986 return LIBUSB_ERROR_INVALID_PARAM; |
| 987 } |
| 988 if (dev_cap->bLength < LIBUSB_BT_USB_2_0_EXTENSION_SIZE) { |
| 989 usbi_err(ctx, "short dev-cap descriptor read %d/%d", |
| 990 dev_cap->bLength, LIBUSB_BT_USB_2_0_EXTENSION_SIZE); |
| 991 return LIBUSB_ERROR_IO; |
| 992 } |
| 993 |
| 994 _usb_2_0_extension = malloc(sizeof(*_usb_2_0_extension)); |
| 995 if (!_usb_2_0_extension) |
| 996 return LIBUSB_ERROR_NO_MEM; |
| 997 |
| 998 usbi_parse_descriptor((unsigned char *)dev_cap, "bbbd", |
| 999 _usb_2_0_extension, host_endian); |
| 1000 |
| 1001 *usb_2_0_extension = _usb_2_0_extension; |
| 1002 return LIBUSB_SUCCESS; |
| 1003 } |
| 1004 |
| 1005 /** \ingroup desc |
| 1006 * Free a USB 2.0 Extension descriptor obtained from |
| 1007 * libusb_get_usb_2_0_extension_descriptor(). |
| 1008 * It is safe to call this function with a NULL usb_2_0_extension parameter, |
| 1009 * in which case the function simply returns. |
| 1010 * |
| 1011 * \param usb_2_0_extension the USB 2.0 Extension descriptor to free |
| 1012 */ |
| 1013 void API_EXPORTED libusb_free_usb_2_0_extension_descriptor( |
| 1014 struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension) |
| 1015 { |
| 1016 free(usb_2_0_extension); |
| 1017 } |
| 1018 |
| 1019 /** \ingroup desc |
| 1020 * Get a SuperSpeed USB Device Capability descriptor |
| 1021 * |
| 1022 * \param ctx the context to operate on, or NULL for the default context |
| 1023 * \param dev_cap Device Capability descriptor with a bDevCapabilityType of |
| 1024 * \ref libusb_capability_type::LIBUSB_BT_SS_USB_DEVICE_CAPABILITY |
| 1025 * LIBUSB_BT_SS_USB_DEVICE_CAPABILITY |
| 1026 * \param ss_usb_device_cap output location for the SuperSpeed USB Device |
| 1027 * Capability descriptor. Only valid if 0 was returned. Must be freed with |
| 1028 * libusb_free_ss_usb_device_capability_descriptor() after use. |
| 1029 * \returns 0 on success |
| 1030 * \returns a LIBUSB_ERROR code on error |
| 1031 */ |
| 1032 int API_EXPORTED libusb_get_ss_usb_device_capability_descriptor( |
| 1033 struct libusb_context *ctx, |
| 1034 struct libusb_bos_dev_capability_descriptor *dev_cap, |
| 1035 struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_cap) |
| 1036 { |
| 1037 struct libusb_ss_usb_device_capability_descriptor *_ss_usb_device_cap; |
| 1038 const int host_endian = 0; |
| 1039 |
| 1040 if (dev_cap->bDevCapabilityType != LIBUSB_BT_SS_USB_DEVICE_CAPABILITY) { |
| 1041 usbi_err(ctx, "unexpected bDevCapabilityType %x (expected %x)", |
| 1042 dev_cap->bDevCapabilityType, |
| 1043 LIBUSB_BT_SS_USB_DEVICE_CAPABILITY); |
| 1044 return LIBUSB_ERROR_INVALID_PARAM; |
| 1045 } |
| 1046 if (dev_cap->bLength < LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) { |
| 1047 usbi_err(ctx, "short dev-cap descriptor read %d/%d", |
| 1048 dev_cap->bLength, LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SI
ZE); |
| 1049 return LIBUSB_ERROR_IO; |
| 1050 } |
| 1051 |
| 1052 _ss_usb_device_cap = malloc(sizeof(*_ss_usb_device_cap)); |
| 1053 if (!_ss_usb_device_cap) |
| 1054 return LIBUSB_ERROR_NO_MEM; |
| 1055 |
| 1056 usbi_parse_descriptor((unsigned char *)dev_cap, "bbbbwbbw", |
| 1057 _ss_usb_device_cap, host_endian); |
| 1058 |
| 1059 *ss_usb_device_cap = _ss_usb_device_cap; |
| 1060 return LIBUSB_SUCCESS; |
| 1061 } |
| 1062 |
| 1063 /** \ingroup desc |
| 1064 * Free a SuperSpeed USB Device Capability descriptor obtained from |
| 1065 * libusb_get_ss_usb_device_capability_descriptor(). |
| 1066 * It is safe to call this function with a NULL ss_usb_device_cap |
| 1067 * parameter, in which case the function simply returns. |
| 1068 * |
| 1069 * \param ss_usb_device_cap the USB 2.0 Extension descriptor to free |
| 1070 */ |
| 1071 void API_EXPORTED libusb_free_ss_usb_device_capability_descriptor( |
| 1072 struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_cap) |
| 1073 { |
| 1074 free(ss_usb_device_cap); |
| 1075 } |
| 1076 |
| 1077 /** \ingroup desc |
| 1078 * Get a Container ID descriptor |
| 1079 * |
| 1080 * \param ctx the context to operate on, or NULL for the default context |
| 1081 * \param dev_cap Device Capability descriptor with a bDevCapabilityType of |
| 1082 * \ref libusb_capability_type::LIBUSB_BT_CONTAINER_ID |
| 1083 * LIBUSB_BT_CONTAINER_ID |
| 1084 * \param container_id output location for the Container ID descriptor. |
| 1085 * Only valid if 0 was returned. Must be freed with |
| 1086 * libusb_free_container_id_descriptor() after use. |
| 1087 * \returns 0 on success |
| 1088 * \returns a LIBUSB_ERROR code on error |
| 1089 */ |
| 1090 int API_EXPORTED libusb_get_container_id_descriptor(struct libusb_context *ctx, |
| 1091 struct libusb_bos_dev_capability_descriptor *dev_cap, |
| 1092 struct libusb_container_id_descriptor **container_id) |
| 1093 { |
| 1094 struct libusb_container_id_descriptor *_container_id; |
| 1095 const int host_endian = 0; |
| 1096 |
| 1097 if (dev_cap->bDevCapabilityType != LIBUSB_BT_CONTAINER_ID) { |
| 1098 usbi_err(ctx, "unexpected bDevCapabilityType %x (expected %x)", |
| 1099 dev_cap->bDevCapabilityType, |
| 1100 LIBUSB_BT_CONTAINER_ID); |
| 1101 return LIBUSB_ERROR_INVALID_PARAM; |
| 1102 } |
| 1103 if (dev_cap->bLength < LIBUSB_BT_CONTAINER_ID_SIZE) { |
| 1104 usbi_err(ctx, "short dev-cap descriptor read %d/%d", |
| 1105 dev_cap->bLength, LIBUSB_BT_CONTAINER_ID_SIZE); |
| 1106 return LIBUSB_ERROR_IO; |
| 1107 } |
| 1108 |
| 1109 _container_id = malloc(sizeof(*_container_id)); |
| 1110 if (!_container_id) |
| 1111 return LIBUSB_ERROR_NO_MEM; |
| 1112 |
| 1113 usbi_parse_descriptor((unsigned char *)dev_cap, "bbbbu", |
| 1114 _container_id, host_endian); |
| 1115 |
| 1116 *container_id = _container_id; |
| 1117 return LIBUSB_SUCCESS; |
| 1118 } |
| 1119 |
| 1120 /** \ingroup desc |
| 1121 * Free a Container ID descriptor obtained from |
| 1122 * libusb_get_container_id_descriptor(). |
| 1123 * It is safe to call this function with a NULL container_id parameter, |
| 1124 * in which case the function simply returns. |
| 1125 * |
| 1126 * \param container_id the USB 2.0 Extension descriptor to free |
| 1127 */ |
| 1128 void API_EXPORTED libusb_free_container_id_descriptor( |
| 1129 struct libusb_container_id_descriptor *container_id) |
| 1130 { |
| 1131 free(container_id); |
| 1132 } |
| 1133 |
| 1134 /** \ingroup desc |
| 667 * Retrieve a string descriptor in C style ASCII. | 1135 * Retrieve a string descriptor in C style ASCII. |
| 668 * | 1136 * |
| 669 * Wrapper around libusb_get_string_descriptor(). Uses the first language | 1137 * Wrapper around libusb_get_string_descriptor(). Uses the first language |
| 670 * supported by the device. | 1138 * supported by the device. |
| 671 * | 1139 * |
| 672 * \param dev a device handle | 1140 * \param dev a device handle |
| 673 * \param desc_index the index of the descriptor to retrieve | 1141 * \param desc_index the index of the descriptor to retrieve |
| 674 * \param data output buffer for ASCII string descriptor | 1142 * \param data output buffer for ASCII string descriptor |
| 675 * \param length size of data buffer | 1143 * \param length size of data buffer |
| 676 * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure | 1144 * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 711 if (tbuf[1] != LIBUSB_DT_STRING) | 1179 if (tbuf[1] != LIBUSB_DT_STRING) |
| 712 return LIBUSB_ERROR_IO; | 1180 return LIBUSB_ERROR_IO; |
| 713 | 1181 |
| 714 if (tbuf[0] > r) | 1182 if (tbuf[0] > r) |
| 715 return LIBUSB_ERROR_IO; | 1183 return LIBUSB_ERROR_IO; |
| 716 | 1184 |
| 717 for (di = 0, si = 2; si < tbuf[0]; si += 2) { | 1185 for (di = 0, si = 2; si < tbuf[0]; si += 2) { |
| 718 if (di >= (length - 1)) | 1186 if (di >= (length - 1)) |
| 719 break; | 1187 break; |
| 720 | 1188 |
| 721 » » if (tbuf[si + 1]) /* high byte */ | 1189 » » if ((tbuf[si] & 0x80) || (tbuf[si + 1])) /* non-ASCII */ |
| 722 data[di++] = '?'; | 1190 data[di++] = '?'; |
| 723 else | 1191 else |
| 724 data[di++] = tbuf[si]; | 1192 data[di++] = tbuf[si]; |
| 725 } | 1193 } |
| 726 | 1194 |
| 727 data[di] = 0; | 1195 data[di] = 0; |
| 728 return di; | 1196 return di; |
| 729 } | 1197 } |
| 730 | |
| OLD | NEW |