1 /* 2 * Implementation of commonly used procedures for HCD handling/initialization 3 * If possible, everything OS specific should be here 4 */ 5 6 #include <string.h> /* memset... */ 7 #include <time.h> /* nanosleep */ 8 9 #include <sys/mman.h> /* Physical to virtual memory mapping */ 10 11 #include <ddekit/interrupt.h> /* DDEKit based interrupt handling */ 12 13 #include <minix/clkconf.h> /* clkconf_* */ 14 #include <minix/syslib.h> /* sys_privctl */ 15 16 #include <usb/hcd_common.h> 17 #include <usb/hcd_interface.h> 18 #include <usb/usb_common.h> 19 20 21 /*===========================================================================* 22 * Local prototypes * 23 *===========================================================================*/ 24 static int hcd_fill_configuration(hcd_reg1 *, int, hcd_configuration *, int); 25 static int hcd_fill_interface(hcd_reg1 *, int, hcd_interface *, int); 26 static int hcd_fill_endpoint(hcd_reg1 *, int, hcd_endpoint *); 27 28 29 /*===========================================================================* 30 * hcd_os_interrupt_attach * 31 *===========================================================================*/ 32 int 33 hcd_os_interrupt_attach(int irq, void (*init)(void *), 34 void (*isr)(void *), void *priv) 35 { 36 DEBUG_DUMP; 37 38 if (NULL == ddekit_interrupt_attach(irq, 0, init, isr, priv)) { 39 USB_MSG("Attaching interrupt %d failed", irq); 40 return EXIT_FAILURE; 41 } 42 43 return EXIT_SUCCESS; 44 } 45 46 47 /*===========================================================================* 48 * hcd_os_interrupt_detach * 49 *===========================================================================*/ 50 void 51 hcd_os_interrupt_detach(int irq) 52 { 53 DEBUG_DUMP; 54 ddekit_interrupt_detach(irq); 55 } 56 57 58 /*===========================================================================* 59 * hcd_os_interrupt_enable * 60 *===========================================================================*/ 61 void 62 hcd_os_interrupt_enable(int irq) 63 { 64 DEBUG_DUMP; 65 ddekit_interrupt_enable(irq); 66 } 67 68 69 /*===========================================================================* 70 * hcd_os_interrupt_disable * 71 *===========================================================================*/ 72 void 73 hcd_os_interrupt_disable(int irq) 74 { 75 DEBUG_DUMP; 76 ddekit_interrupt_disable(irq); 77 } 78 79 80 /*===========================================================================* 81 * hcd_os_regs_init * 82 *===========================================================================*/ 83 void * 84 hcd_os_regs_init(hcd_addr phys_addr, unsigned long addr_len) 85 { 86 /* Memory range where we need privileged access */ 87 struct minix_mem_range mr; 88 89 /* NULL unless initialization was fully completed */ 90 void * virt_reg_base; 91 92 DEBUG_DUMP; 93 94 virt_reg_base = NULL; 95 96 /* Must have been set before */ 97 USB_ASSERT(0 != phys_addr, "Invalid base address!"); 98 USB_ASSERT(0 != addr_len, "Invalid base length!"); 99 100 /* Set memory range for peripheral */ 101 mr.mr_base = phys_addr; 102 mr.mr_limit = phys_addr + addr_len; 103 104 /* Try getting access to memory range */ 105 if (EXIT_SUCCESS == sys_privctl(SELF, SYS_PRIV_ADD_MEM, &mr)) { 106 107 /* And map it where we want it */ 108 virt_reg_base = vm_map_phys(SELF, (void *)phys_addr, addr_len); 109 110 /* Check for mapping errors to allow us returning NULL */ 111 if (MAP_FAILED == virt_reg_base) { 112 USB_MSG("Mapping memory with vm_map_phys() failed"); 113 virt_reg_base = NULL; 114 } 115 116 } else 117 USB_MSG("Acquiring memory with sys_privctl() failed"); 118 119 return virt_reg_base; 120 } 121 122 123 /*===========================================================================* 124 * hcd_os_regs_deinit * 125 *===========================================================================*/ 126 int 127 hcd_os_regs_deinit(hcd_addr virt_addr, unsigned long addr_len) 128 { 129 DEBUG_DUMP; 130 131 /* To keep USBD return value convention */ 132 return (0 == vm_unmap_phys(SELF, (void*)virt_addr, addr_len)) ? 133 EXIT_SUCCESS : EXIT_FAILURE; 134 } 135 136 137 /*===========================================================================* 138 * hcd_os_clkconf * 139 *===========================================================================*/ 140 int 141 hcd_os_clkconf(unsigned long clk, unsigned long mask, unsigned long value) 142 { 143 DEBUG_DUMP; 144 145 /* Apparently clkconf_init may be called more than once anyway */ 146 if ((0 == clkconf_init()) && (0 == clkconf_set(clk, mask, value))) 147 return EXIT_SUCCESS; 148 else 149 return EXIT_FAILURE; 150 } 151 152 153 /*===========================================================================* 154 * hcd_os_clkconf_release * 155 *===========================================================================*/ 156 int 157 hcd_os_clkconf_release(void) 158 { 159 DEBUG_DUMP; 160 return clkconf_release(); 161 } 162 163 164 /*===========================================================================* 165 * hcd_os_nanosleep * 166 *===========================================================================*/ 167 void 168 hcd_os_nanosleep(int nanosec) 169 { 170 struct timespec nanotm; 171 172 DEBUG_DUMP; 173 174 if (nanosec >= HCD_NANO) { 175 nanotm.tv_sec = nanosec / HCD_NANO; 176 nanotm.tv_nsec = nanosec % HCD_NANO; 177 } else { 178 nanotm.tv_sec = 0; 179 nanotm.tv_nsec = nanosec; 180 } 181 182 /* TODO: Since it is not likely to be ever interrupted, we do not try 183 * to sleep for a remaining time in case of signal handling */ 184 /* Signal handling will most likely end up with termination anyway */ 185 USB_ASSERT(EXIT_SUCCESS == nanosleep(&nanotm, NULL), 186 "Calling nanosleep() failed"); 187 } 188 189 190 /*===========================================================================* 191 * hcd_init_device * 192 *===========================================================================*/ 193 int 194 hcd_connect_device(hcd_device_state * this_device, hcd_thread_function funct) 195 { 196 DEBUG_DUMP; 197 198 if ((NULL != this_device->lock) || (NULL != this_device->thread)) { 199 USB_MSG("Device data already allocated"); 200 return EXIT_FAILURE; 201 } 202 203 if (NULL == (this_device->lock = ddekit_sem_init(0))) 204 return EXIT_FAILURE; 205 206 if (NULL == (this_device->thread = ddekit_thread_create(funct, 207 this_device, 208 "Device"))) { 209 ddekit_sem_deinit(this_device->lock); 210 return EXIT_FAILURE; 211 } 212 213 /* Allow device thread to work */ 214 ddekit_yield(); 215 216 return EXIT_SUCCESS; 217 } 218 219 /*===========================================================================* 220 * hcd_deinit_device * 221 *===========================================================================*/ 222 void 223 hcd_disconnect_device(hcd_device_state * this_device) 224 { 225 DEBUG_DUMP; 226 227 hcd_tree_cleanup(&(this_device->config_tree)); 228 229 ddekit_thread_terminate(this_device->thread); 230 ddekit_sem_deinit(this_device->lock); 231 232 this_device->thread = NULL; 233 this_device->lock = NULL; 234 } 235 236 237 /*===========================================================================* 238 * hcd_device_wait * 239 *===========================================================================*/ 240 void 241 hcd_device_wait(hcd_device_state * this_device, hcd_event event, hcd_reg1 ep) 242 { 243 hcd_driver_state * drv; 244 245 DEBUG_DUMP; 246 247 drv = (hcd_driver_state *)this_device->driver; 248 249 drv->expected_event = event; 250 drv->expected_endpoint = ep; 251 252 USB_DBG("Waiting for: ev=0x%X, ep=0x%X", (int)event, ep); 253 254 ddekit_sem_down(this_device->lock); 255 } 256 257 258 /*===========================================================================* 259 * hcd_device_continue * 260 *===========================================================================*/ 261 void 262 hcd_device_continue(hcd_device_state * this_device) 263 { 264 hcd_driver_state * drv; 265 266 DEBUG_DUMP; 267 268 drv = (hcd_driver_state *)this_device->driver; 269 270 /* We need to get what was expected... */ 271 USB_ASSERT(drv->current_event == drv->expected_event, 272 "Unexpected event occurred"); 273 274 /* ...including endpoint interrupts */ 275 if (HCD_EVENT_ENDPOINT == drv->current_event) { 276 USB_ASSERT(drv->current_endpoint == drv->expected_endpoint, 277 "Unexpected endpoint interrupt"); 278 } 279 280 ddekit_sem_up(this_device->lock); 281 } 282 283 284 /*===========================================================================* 285 * hcd_buffer_to_tree * 286 *===========================================================================*/ 287 int 288 hcd_buffer_to_tree(hcd_reg1 * buf, int len, hcd_configuration * c) 289 { 290 hcd_interface * i; 291 hcd_endpoint * e; 292 hcd_descriptor * desc; 293 int cfg_num; 294 int if_num; 295 int ep_num; 296 297 DEBUG_DUMP; 298 299 cfg_num = 0; 300 if_num = 0; 301 ep_num = 0; 302 303 i = NULL; 304 e = NULL; 305 306 /* Cleanup initially to NULL pointers before any allocation */ 307 memset(c, 0, sizeof(*c)); 308 309 while (len > (int)sizeof(*desc)) { 310 /* Check descriptor type */ 311 desc = (hcd_descriptor *)buf; 312 313 if (0 == desc->bLength) { 314 USB_MSG("Zero length descriptor"); 315 goto PARSE_ERROR; 316 } 317 318 if (UDESC_CONFIG == desc->bDescriptorType) { 319 if (EXIT_SUCCESS != hcd_fill_configuration(buf, len, 320 c, cfg_num++)) 321 goto PARSE_ERROR; 322 323 if_num = 0; 324 } 325 else if (UDESC_INTERFACE == desc->bDescriptorType) { 326 if (NULL == c->interface) 327 goto PARSE_ERROR; 328 329 i = &(c->interface[if_num]); 330 331 if (EXIT_SUCCESS != hcd_fill_interface(buf, len, 332 i, if_num++)) 333 goto PARSE_ERROR; 334 335 ep_num = 0; 336 } 337 else if (UDESC_ENDPOINT == desc->bDescriptorType) { 338 if (NULL == c->interface) 339 goto PARSE_ERROR; 340 341 if (NULL == i) 342 goto PARSE_ERROR; 343 344 e = &(i->endpoint[ep_num++]); 345 346 if (EXIT_SUCCESS != hcd_fill_endpoint(buf, len, e)) 347 goto PARSE_ERROR; 348 } else 349 USB_DBG("Unhandled descriptor type 0x%02X", 350 desc->bDescriptorType); 351 352 len -= desc->bLength; 353 buf += desc->bLength; 354 } 355 356 if (0 != len) { 357 USB_MSG("After parsing, some descriptor data remains"); 358 goto PARSE_ERROR; 359 } 360 361 return EXIT_SUCCESS; 362 363 PARSE_ERROR: 364 hcd_tree_cleanup(c); 365 return EXIT_FAILURE; 366 } 367 368 369 /*===========================================================================* 370 * hcd_tree_cleanup * 371 *===========================================================================*/ 372 void 373 hcd_tree_cleanup(hcd_configuration * c) 374 { 375 int if_idx; 376 377 DEBUG_DUMP; 378 379 /* Free if anything was allocated */ 380 if (NULL != c->interface) { 381 382 USB_ASSERT(c->num_interfaces > 0, "Interface number error"); 383 384 for (if_idx = 0; if_idx < c->num_interfaces; if_idx++) { 385 if (NULL != c->interface[if_idx].endpoint) { 386 USB_DBG("Freeing ep for interface #%d", if_idx); 387 free(c->interface[if_idx].endpoint); 388 } 389 } 390 391 USB_DBG("Freeing interfaces"); 392 free(c->interface); 393 c->interface = NULL; 394 } 395 } 396 397 398 /*===========================================================================* 399 * hcd_tree_find_ep * 400 *===========================================================================*/ 401 hcd_endpoint * 402 hcd_tree_find_ep(hcd_configuration * c, hcd_reg1 ep) 403 { 404 hcd_interface * i; 405 hcd_endpoint * e; 406 int if_idx; 407 int ep_idx; 408 409 DEBUG_DUMP; 410 411 /* Free if anything was allocated */ 412 USB_ASSERT(NULL != c->interface, "No interfaces available"); 413 USB_ASSERT(c->num_interfaces > 0, "Interface number error"); 414 415 for (if_idx = 0; if_idx < c->num_interfaces; if_idx++) { 416 i = &(c->interface[if_idx]); 417 for (ep_idx = 0; ep_idx < i->num_endpoints; ep_idx++) { 418 e = &(i->endpoint[ep_idx]); 419 if (UE_GET_ADDR(e->descriptor.bEndpointAddress) == ep) 420 return e; 421 } 422 } 423 424 return NULL; 425 } 426 427 428 /*===========================================================================* 429 * hcd_fill_configuration * 430 *===========================================================================*/ 431 static int 432 hcd_fill_configuration(hcd_reg1 * buf, int len, hcd_configuration * c, int num) 433 { 434 hcd_config_descriptor * desc; 435 int interfaces_size; 436 437 DEBUG_DUMP; 438 439 desc = (hcd_config_descriptor *)buf; 440 441 USB_DBG("Configuration #%d", num); 442 443 if (num > 0) { 444 USB_DBG("Only one configuration possible"); 445 return EXIT_SUCCESS; 446 } 447 448 if (UDESC_CONFIG != desc->bDescriptorType) 449 return EXIT_FAILURE; 450 451 if (desc->bLength > len) 452 return EXIT_FAILURE; 453 454 if (sizeof(*desc) != desc->bLength) 455 return EXIT_FAILURE; 456 457 memcpy(&(c->descriptor), buf, sizeof(c->descriptor)); 458 459 c->num_interfaces = c->descriptor.bNumInterface; 460 461 interfaces_size = c->num_interfaces * sizeof(*(c->interface)); 462 463 USB_DBG("Allocating interfaces, %dB", interfaces_size); 464 c->interface = malloc(interfaces_size); 465 466 memset(c->interface, 0, interfaces_size); 467 468 /* Dump configuration in debug mode */ 469 USB_DBG("<<CONFIGURATION>>"); 470 USB_DBG("bLength %02X", desc->bLength); 471 USB_DBG("bDescriptorType %02X", desc->bDescriptorType); 472 USB_DBG("wTotalLength %04X", UGETW(desc->wTotalLength)); 473 USB_DBG("bNumInterface %02X", desc->bNumInterface); 474 USB_DBG("bConfigurationValue %02X", desc->bConfigurationValue); 475 USB_DBG("iConfiguration %02X", desc->iConfiguration); 476 USB_DBG("bmAttributes %02X", desc->bmAttributes); 477 USB_DBG("bMaxPower %02X", desc->bMaxPower); 478 479 return EXIT_SUCCESS; 480 } 481 482 483 /*===========================================================================* 484 * hcd_fill_interface * 485 *===========================================================================*/ 486 static int 487 hcd_fill_interface(hcd_reg1 * buf, int len, hcd_interface * i, int num) 488 { 489 hcd_interface_descriptor * desc; 490 int endpoints_size; 491 492 DEBUG_DUMP; 493 494 desc = (hcd_interface_descriptor *)buf; 495 496 USB_DBG("Interface #%d", num); 497 498 if (UDESC_INTERFACE != desc->bDescriptorType) 499 return EXIT_FAILURE; 500 501 if (desc->bLength > len) 502 return EXIT_FAILURE; 503 504 if (sizeof(*desc) != desc->bLength) 505 return EXIT_FAILURE; 506 507 /* It is mandatory to supply interfaces in correct order */ 508 if (desc->bInterfaceNumber != num) 509 return EXIT_FAILURE; 510 511 memcpy(&(i->descriptor), buf, sizeof(i->descriptor)); 512 513 i->num_endpoints = i->descriptor.bNumEndpoints; 514 515 endpoints_size = i->num_endpoints * sizeof(*(i->endpoint)); 516 517 USB_DBG("Allocating endpoints, %dB", endpoints_size); 518 i->endpoint = malloc(endpoints_size); 519 520 memset(i->endpoint, 0, endpoints_size); 521 522 /* Dump interface in debug mode */ 523 USB_DBG("<<INTERFACE>>"); 524 USB_DBG("bLength %02X", desc->bLength); 525 USB_DBG("bDescriptorType %02X", desc->bDescriptorType); 526 USB_DBG("bInterfaceNumber %02X", desc->bInterfaceNumber); 527 USB_DBG("bAlternateSetting %02X", desc->bAlternateSetting); 528 USB_DBG("bNumEndpoints %02X", desc->bNumEndpoints); 529 USB_DBG("bInterfaceClass %02X", desc->bInterfaceClass); 530 USB_DBG("bInterfaceSubClass %02X", desc->bInterfaceSubClass); 531 USB_DBG("bInterfaceProtocol %02X", desc->bInterfaceProtocol); 532 USB_DBG("iInterface %02X", desc->iInterface); 533 534 return EXIT_SUCCESS; 535 } 536 537 538 /*===========================================================================* 539 * hcd_fill_endpoint * 540 *===========================================================================*/ 541 static int 542 hcd_fill_endpoint(hcd_reg1 * buf, int len, hcd_endpoint * e) 543 { 544 hcd_endpoint_descriptor * desc; 545 546 DEBUG_DUMP; 547 548 desc = (hcd_endpoint_descriptor *)buf; 549 550 USB_DBG("Endpoint #%d", UE_GET_ADDR(desc->bEndpointAddress)); 551 552 if (UDESC_ENDPOINT != desc->bDescriptorType) 553 return EXIT_FAILURE; 554 555 if (desc->bLength > len) 556 return EXIT_FAILURE; 557 558 if (sizeof(*desc) != desc->bLength) 559 return EXIT_FAILURE; 560 561 memcpy(&(e->descriptor), buf, sizeof(e->descriptor)); 562 563 /* Dump endpoint in debug mode */ 564 USB_DBG("<<ENDPOINT>>"); 565 USB_DBG("bLength %02X", desc->bLength); 566 USB_DBG("bDescriptorType %02X", desc->bDescriptorType); 567 USB_DBG("bEndpointAddress %02X", desc->bEndpointAddress); 568 USB_DBG("bmAttributes %02X", desc->bmAttributes); 569 USB_DBG("wMaxPacketSize %04X", UGETW(desc->wMaxPacketSize)); 570 USB_DBG("bInterval %02X", desc->bInterval); 571 572 return EXIT_SUCCESS; 573 } 574