196da8285SMichael Lotz /* 296da8285SMichael Lotz * Copyright 2003-2006, Haiku Inc. All rights reserved. 396da8285SMichael Lotz * Distributed under the terms of the MIT License. 496da8285SMichael Lotz * 596da8285SMichael Lotz * Authors: 65b0ec61fSMichael Lotz * Michael Lotz <mmlr@mlotz.ch> 796da8285SMichael Lotz * Niels S. Reedijk 896da8285SMichael Lotz */ 91501c2bfSNiels Sascha Reedijk 101501c2bfSNiels Sascha Reedijk #include <util/kernel_cpp.h> 111501c2bfSNiels Sascha Reedijk #include "usb_p.h" 121bad4a4eSMichael Lotz #include <USB_rle.h> 131501c2bfSNiels Sascha Reedijk 14f14fe767SMichael Lotz #define USB_MODULE_NAME "module" 1596da8285SMichael Lotz 16b8c6a851SMichael Lotz Stack *gUSBStack = NULL; 17b8c6a851SMichael Lotz 18b8c6a851SMichael Lotz 19*6eba0636SMichael Lotz static int 20*6eba0636SMichael Lotz debug_get_pipe_for_id(int argc, char **argv) 21*6eba0636SMichael Lotz { 22*6eba0636SMichael Lotz if (gUSBStack == NULL) 23*6eba0636SMichael Lotz return 1; 24*6eba0636SMichael Lotz 25*6eba0636SMichael Lotz if (!is_debug_variable_defined("_usbPipeID")) 26*6eba0636SMichael Lotz return 2; 27*6eba0636SMichael Lotz 28*6eba0636SMichael Lotz uint64 id = get_debug_variable("_usbPipeID", 0); 29*6eba0636SMichael Lotz Object *object = gUSBStack->GetObjectNoLock((usb_id)id); 30*6eba0636SMichael Lotz if (!object || (object->Type() & USB_OBJECT_PIPE) == 0) 31*6eba0636SMichael Lotz return 3; 32*6eba0636SMichael Lotz 33*6eba0636SMichael Lotz set_debug_variable("_usbPipe", (uint64)object); 34*6eba0636SMichael Lotz return 0; 35*6eba0636SMichael Lotz } 36*6eba0636SMichael Lotz 37*6eba0636SMichael Lotz 381501c2bfSNiels Sascha Reedijk static int32 391501c2bfSNiels Sascha Reedijk bus_std_ops(int32 op, ...) 401501c2bfSNiels Sascha Reedijk { 411501c2bfSNiels Sascha Reedijk switch (op) { 4296da8285SMichael Lotz case B_MODULE_INIT: { 43f14fe767SMichael Lotz TRACE_MODULE("init\n"); 445b0ec61fSMichael Lotz if (gUSBStack) 455b0ec61fSMichael Lotz return B_OK; 465b0ec61fSMichael Lotz 4748ab20faSMichael Lotz #ifndef __HAIKU__ 4848ab20faSMichael Lotz // This code is to handle plain R5 (non-BONE) where the same module 4948ab20faSMichael Lotz // gets loaded multiple times (once for each exported module 5048ab20faSMichael Lotz // interface, the USB v2 and v3 API in our case). We don't want to 5148ab20faSMichael Lotz // ever create multiple stacks however, so we "share" the same stack 5248ab20faSMichael Lotz // for both modules by storing it's address in a shared area. 53a94a8358SMichael Lotz void *address = NULL; 54a94a8358SMichael Lotz area_id shared = find_area("shared usb stack"); 55a94a8358SMichael Lotz if (shared >= B_OK && clone_area("usb stack clone", &address, 56a94a8358SMichael Lotz B_ANY_KERNEL_ADDRESS, B_KERNEL_READ_AREA, shared) >= B_OK) { 57a94a8358SMichael Lotz gUSBStack = *((Stack **)address); 58f14fe767SMichael Lotz TRACE_MODULE("found shared stack at %p\n", gUSBStack); 59a94a8358SMichael Lotz return B_OK; 60a94a8358SMichael Lotz } 6148ab20faSMichael Lotz #endif 62a94a8358SMichael Lotz 6396da8285SMichael Lotz #ifdef TRACE_USB 641a2e81b5SNiels Sascha Reedijk set_dprintf_enabled(true); 65facc0035SFrançois Revol #ifndef __HAIKU__ 661a2e81b5SNiels Sascha Reedijk load_driver_symbols("usb"); 67facc0035SFrançois Revol #endif 6802ce23a1SMichael Lotz #endif 69b8c6a851SMichael Lotz Stack *stack = new(std::nothrow) Stack(); 70f14fe767SMichael Lotz TRACE_MODULE("usb_module: stack created %p\n", stack); 71b8c6a851SMichael Lotz if (!stack) 72b8c6a851SMichael Lotz return B_NO_MEMORY; 73b8c6a851SMichael Lotz 7496da8285SMichael Lotz if (stack->InitCheck() != B_OK) { 751a2e81b5SNiels Sascha Reedijk delete stack; 761501c2bfSNiels Sascha Reedijk return ENODEV; 771501c2bfSNiels Sascha Reedijk } 7896da8285SMichael Lotz 79eb6a1cbcSMichael Lotz gUSBStack = stack; 80*6eba0636SMichael Lotz add_debugger_command("get_usb_pipe_for_id", 81*6eba0636SMichael Lotz &debug_get_pipe_for_id, 82*6eba0636SMichael Lotz "Gets the config for a USB pipe"); 8348ab20faSMichael Lotz #ifndef __HAIKU__ 8448ab20faSMichael Lotz // Plain R5 workaround, see comment above. 85a94a8358SMichael Lotz shared = create_area("shared usb stack", &address, 86a94a8358SMichael Lotz B_ANY_KERNEL_ADDRESS, B_PAGE_SIZE, B_NO_LOCK, 87a94a8358SMichael Lotz B_KERNEL_WRITE_AREA); 8848ab20faSMichael Lotz if (shared >= B_OK) 89a94a8358SMichael Lotz *((Stack **)address) = gUSBStack; 9048ab20faSMichael Lotz #endif 911501c2bfSNiels Sascha Reedijk break; 9296da8285SMichael Lotz } 9396da8285SMichael Lotz 941501c2bfSNiels Sascha Reedijk case B_MODULE_UNINIT: 95f14fe767SMichael Lotz TRACE_MODULE("uninit\n"); 96b8c6a851SMichael Lotz delete gUSBStack; 97b8c6a851SMichael Lotz gUSBStack = NULL; 98*6eba0636SMichael Lotz remove_debugger_command("get_usb_pipe_for_id", 99*6eba0636SMichael Lotz &debug_get_pipe_for_id); 1001501c2bfSNiels Sascha Reedijk break; 10196da8285SMichael Lotz 1021501c2bfSNiels Sascha Reedijk default: 1031501c2bfSNiels Sascha Reedijk return EINVAL; 1041501c2bfSNiels Sascha Reedijk } 10596da8285SMichael Lotz 1061501c2bfSNiels Sascha Reedijk return B_OK; 1071501c2bfSNiels Sascha Reedijk } 1081501c2bfSNiels Sascha Reedijk 1091501c2bfSNiels Sascha Reedijk 110b8c6a851SMichael Lotz status_t 111b8c6a851SMichael Lotz register_driver(const char *driverName, 112b8c6a851SMichael Lotz const usb_support_descriptor *descriptors, 113b8c6a851SMichael Lotz size_t count, const char *optionalRepublishDriverName) 114b8c6a851SMichael Lotz { 115b8c6a851SMichael Lotz return gUSBStack->RegisterDriver(driverName, descriptors, count, 116b8c6a851SMichael Lotz optionalRepublishDriverName); 117b8c6a851SMichael Lotz } 118b8c6a851SMichael Lotz 119b8c6a851SMichael Lotz 120b8c6a851SMichael Lotz status_t 121b8c6a851SMichael Lotz install_notify(const char *driverName, const usb_notify_hooks *hooks) 122b8c6a851SMichael Lotz { 123b8c6a851SMichael Lotz return gUSBStack->InstallNotify(driverName, hooks); 124b8c6a851SMichael Lotz } 125b8c6a851SMichael Lotz 126b8c6a851SMichael Lotz 127b8c6a851SMichael Lotz status_t 128b8c6a851SMichael Lotz uninstall_notify(const char *driverName) 129b8c6a851SMichael Lotz { 130b8c6a851SMichael Lotz return gUSBStack->UninstallNotify(driverName); 131b8c6a851SMichael Lotz } 132b8c6a851SMichael Lotz 133b8c6a851SMichael Lotz 134b8c6a851SMichael Lotz const usb_device_descriptor * 1355b0ec61fSMichael Lotz get_device_descriptor(usb_device device) 136b8c6a851SMichael Lotz { 137f14fe767SMichael Lotz TRACE_MODULE("get_device_descriptor(%ld)\n", device); 1385b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(device); 1395b0ec61fSMichael Lotz if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) 140b8c6a851SMichael Lotz return NULL; 141b8c6a851SMichael Lotz 1425b0ec61fSMichael Lotz return ((Device *)object)->DeviceDescriptor(); 143b8c6a851SMichael Lotz } 144b8c6a851SMichael Lotz 145b8c6a851SMichael Lotz 146b8c6a851SMichael Lotz const usb_configuration_info * 1477e1490e0SMichael Lotz get_nth_configuration(usb_device device, uint32 index) 148b8c6a851SMichael Lotz { 149f14fe767SMichael Lotz TRACE_MODULE("get_nth_configuration(%ld, %lu)\n", device, index); 1505b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(device); 1515b0ec61fSMichael Lotz if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) 152b8c6a851SMichael Lotz return NULL; 153b8c6a851SMichael Lotz 1545b0ec61fSMichael Lotz return ((Device *)object)->ConfigurationAt((int32)index); 155b8c6a851SMichael Lotz } 156b8c6a851SMichael Lotz 157b8c6a851SMichael Lotz 158b8c6a851SMichael Lotz const usb_configuration_info * 1595b0ec61fSMichael Lotz get_configuration(usb_device device) 160b8c6a851SMichael Lotz { 161f14fe767SMichael Lotz TRACE_MODULE("get_configuration(%ld)\n", device); 1625b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(device); 1635b0ec61fSMichael Lotz if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) 164b8c6a851SMichael Lotz return NULL; 165b8c6a851SMichael Lotz 1665b0ec61fSMichael Lotz return ((Device *)object)->Configuration(); 167b8c6a851SMichael Lotz } 168b8c6a851SMichael Lotz 169b8c6a851SMichael Lotz 170b8c6a851SMichael Lotz status_t 1715b0ec61fSMichael Lotz set_configuration(usb_device device, 172b8c6a851SMichael Lotz const usb_configuration_info *configuration) 173b8c6a851SMichael Lotz { 174f14fe767SMichael Lotz TRACE_MODULE("set_configuration(%ld, %p)\n", device, configuration); 1755b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(device); 1765b0ec61fSMichael Lotz if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) 17717f83b21SMichael Lotz return B_DEV_INVALID_PIPE; 178b8c6a851SMichael Lotz 1795b0ec61fSMichael Lotz return ((Device *)object)->SetConfiguration(configuration); 180b8c6a851SMichael Lotz } 181b8c6a851SMichael Lotz 182b8c6a851SMichael Lotz 183b8c6a851SMichael Lotz status_t 1845b0ec61fSMichael Lotz set_alt_interface(usb_device device, const usb_interface_info *interface) 185b8c6a851SMichael Lotz { 186f14fe767SMichael Lotz TRACE_MODULE("set_alt_interface(%ld, %p)\n", device, interface); 1875b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(device); 1885b0ec61fSMichael Lotz if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) 18917f83b21SMichael Lotz return B_DEV_INVALID_PIPE; 1905b0ec61fSMichael Lotz 19130cb1cfbSSalvatore Benedetto return ((Device *)object)->SetAltInterface(interface); 192b8c6a851SMichael Lotz } 193b8c6a851SMichael Lotz 194b8c6a851SMichael Lotz 195b8c6a851SMichael Lotz status_t 1965b0ec61fSMichael Lotz set_feature(usb_id handle, uint16 selector) 197b8c6a851SMichael Lotz { 198f14fe767SMichael Lotz TRACE_MODULE("set_feature(%ld, %d)\n", handle, selector); 1995b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(handle); 2008fedfdfcSMichael Lotz if (!object) 20117f83b21SMichael Lotz return B_DEV_INVALID_PIPE; 202b8c6a851SMichael Lotz 2038fedfdfcSMichael Lotz return object->SetFeature(selector); 204b8c6a851SMichael Lotz } 205b8c6a851SMichael Lotz 206b8c6a851SMichael Lotz 207b8c6a851SMichael Lotz status_t 2085b0ec61fSMichael Lotz clear_feature(usb_id handle, uint16 selector) 209b8c6a851SMichael Lotz { 210f14fe767SMichael Lotz TRACE_MODULE("clear_feature(%ld, %d)\n", handle, selector); 2115b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(handle); 2128fedfdfcSMichael Lotz if (!object) 21317f83b21SMichael Lotz return B_DEV_INVALID_PIPE; 214b8c6a851SMichael Lotz 2158fedfdfcSMichael Lotz return object->ClearFeature(selector); 216b8c6a851SMichael Lotz } 217b8c6a851SMichael Lotz 218b8c6a851SMichael Lotz 219b8c6a851SMichael Lotz status_t 2205b0ec61fSMichael Lotz get_status(usb_id handle, uint16 *status) 221b8c6a851SMichael Lotz { 222f14fe767SMichael Lotz TRACE_MODULE("get_status(%ld, %p)\n", handle, status); 2235b0ec61fSMichael Lotz if (!status) 2245b0ec61fSMichael Lotz return B_BAD_VALUE; 2255b0ec61fSMichael Lotz 2265b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(handle); 2278fedfdfcSMichael Lotz if (!object) 22817f83b21SMichael Lotz return B_DEV_INVALID_PIPE; 229b8c6a851SMichael Lotz 2308fedfdfcSMichael Lotz return object->GetStatus(status); 231b8c6a851SMichael Lotz } 232b8c6a851SMichael Lotz 233b8c6a851SMichael Lotz 234b8c6a851SMichael Lotz status_t 2355b0ec61fSMichael Lotz get_descriptor(usb_device device, uint8 type, uint8 index, uint16 languageID, 2365b0ec61fSMichael Lotz void *data, size_t dataLength, size_t *actualLength) 237b8c6a851SMichael Lotz { 238f14fe767SMichael Lotz TRACE_MODULE("get_descriptor(%ld, 0x%02x, 0x%02x, 0x%04x, %p, %ld, %p)\n", 239f14fe767SMichael Lotz device, type, index, languageID, data, dataLength, actualLength); 2405b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(device); 2415b0ec61fSMichael Lotz if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) 24217f83b21SMichael Lotz return B_DEV_INVALID_PIPE; 243b8c6a851SMichael Lotz 2445b0ec61fSMichael Lotz return ((Device *)object)->GetDescriptor(type, index, languageID, 245b8c6a851SMichael Lotz data, dataLength, actualLength); 246b8c6a851SMichael Lotz } 247b8c6a851SMichael Lotz 248b8c6a851SMichael Lotz 249b8c6a851SMichael Lotz status_t 2505b0ec61fSMichael Lotz send_request(usb_device device, uint8 requestType, uint8 request, 2515b0ec61fSMichael Lotz uint16 value, uint16 index, uint16 length, void *data, size_t *actualLength) 252b8c6a851SMichael Lotz { 253f14fe767SMichael Lotz TRACE_MODULE("send_request(%ld, 0x%02x, 0x%02x, 0x%04x, 0x%04x, %d, %p, %p)\n", 254f14fe767SMichael Lotz device, requestType, request, value, index, length, data, actualLength); 2555b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(device); 2565b0ec61fSMichael Lotz if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) 25717f83b21SMichael Lotz return B_DEV_INVALID_PIPE; 258b8c6a851SMichael Lotz 2598fedfdfcSMichael Lotz return ((Device *)object)->DefaultPipe()->SendRequest(requestType, request, 2608fedfdfcSMichael Lotz value, index, length, data, length, actualLength); 261b8c6a851SMichael Lotz } 262b8c6a851SMichael Lotz 263b8c6a851SMichael Lotz 264b8c6a851SMichael Lotz status_t 2655b0ec61fSMichael Lotz queue_request(usb_device device, uint8 requestType, uint8 request, 2665b0ec61fSMichael Lotz uint16 value, uint16 index, uint16 length, void *data, 267b8c6a851SMichael Lotz usb_callback_func callback, void *callbackCookie) 268b8c6a851SMichael Lotz { 269f14fe767SMichael Lotz TRACE_MODULE("queue_request(%ld, 0x%02x, 0x%02x, 0x%04x, 0x%04x, %u, %p, %p, %p)\n", 270f14fe767SMichael Lotz device, requestType, request, value, index, length, data, callback, 271f14fe767SMichael Lotz callbackCookie); 2725b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(device); 2735b0ec61fSMichael Lotz if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) 27417f83b21SMichael Lotz return B_DEV_INVALID_PIPE; 275b8c6a851SMichael Lotz 2768fedfdfcSMichael Lotz return ((Device *)object)->DefaultPipe()->QueueRequest(requestType, 2778fedfdfcSMichael Lotz request, value, index, length, data, length, callback, callbackCookie); 278b8c6a851SMichael Lotz } 279b8c6a851SMichael Lotz 280b8c6a851SMichael Lotz 281b8c6a851SMichael Lotz status_t 2825b0ec61fSMichael Lotz queue_interrupt(usb_pipe pipe, void *data, size_t dataLength, 283b8c6a851SMichael Lotz usb_callback_func callback, void *callbackCookie) 284b8c6a851SMichael Lotz { 285f14fe767SMichael Lotz TRACE_MODULE("queue_interrupt(%ld, %p, %ld, %p, %p)\n", 286f14fe767SMichael Lotz pipe, data, dataLength, callback, callbackCookie); 2875b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(pipe); 2885b0ec61fSMichael Lotz if (!object || (object->Type() & USB_OBJECT_INTERRUPT_PIPE) == 0) 28917f83b21SMichael Lotz return B_DEV_INVALID_PIPE; 290b8c6a851SMichael Lotz 2915b0ec61fSMichael Lotz return ((InterruptPipe *)object)->QueueInterrupt(data, dataLength, callback, 292b8c6a851SMichael Lotz callbackCookie); 293b8c6a851SMichael Lotz } 294b8c6a851SMichael Lotz 295b8c6a851SMichael Lotz 296b8c6a851SMichael Lotz status_t 2975b0ec61fSMichael Lotz queue_bulk(usb_pipe pipe, void *data, size_t dataLength, 298b8c6a851SMichael Lotz usb_callback_func callback, void *callbackCookie) 299b8c6a851SMichael Lotz { 300f14fe767SMichael Lotz TRACE_MODULE("queue_bulk(%ld, %p, %ld, %p, %p)\n", 301f14fe767SMichael Lotz pipe, data, dataLength, callback, callbackCookie); 3025b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(pipe); 3035b0ec61fSMichael Lotz if (!object || (object->Type() & USB_OBJECT_BULK_PIPE) == 0) 30417f83b21SMichael Lotz return B_DEV_INVALID_PIPE; 305b8c6a851SMichael Lotz 3065b0ec61fSMichael Lotz return ((BulkPipe *)object)->QueueBulk(data, dataLength, callback, 307b8c6a851SMichael Lotz callbackCookie); 308b8c6a851SMichael Lotz } 309b8c6a851SMichael Lotz 310b8c6a851SMichael Lotz 311b8c6a851SMichael Lotz status_t 3125b0ec61fSMichael Lotz queue_bulk_v(usb_pipe pipe, iovec *vector, size_t vectorCount, 3135b0ec61fSMichael Lotz usb_callback_func callback, void *callbackCookie) 314b8c6a851SMichael Lotz { 315f14fe767SMichael Lotz TRACE_MODULE("queue_bulk(%ld, %p, %ld, %p, %p)\n", 316f14fe767SMichael Lotz pipe, vector, vectorCount, callback, callbackCookie); 3175b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(pipe); 3185b0ec61fSMichael Lotz if (!object || (object->Type() & USB_OBJECT_BULK_PIPE) == 0) 31917f83b21SMichael Lotz return B_DEV_INVALID_PIPE; 320b8c6a851SMichael Lotz 3211e8c0b36SMichael Lotz return ((BulkPipe *)object)->QueueBulkV(vector, vectorCount, callback, 3221e8c0b36SMichael Lotz callbackCookie); 323b8c6a851SMichael Lotz } 324b8c6a851SMichael Lotz 325b8c6a851SMichael Lotz 326b8c6a851SMichael Lotz status_t 3275b0ec61fSMichael Lotz queue_isochronous(usb_pipe pipe, void *data, size_t dataLength, 3281bad4a4eSMichael Lotz usb_iso_packet_descriptor *packetDesc, uint32 packetCount, 3291bad4a4eSMichael Lotz uint32 *startingFrameNumber, uint32 flags, usb_callback_func callback, 3305b0ec61fSMichael Lotz void *callbackCookie) 3315b0ec61fSMichael Lotz { 332f14fe767SMichael Lotz TRACE_MODULE("queue_isochronous(%ld, %p, %ld, %p, %ld, %p, 0x%08lx, %p, %p)\n", 333f14fe767SMichael Lotz pipe, data, dataLength, packetDesc, packetCount, startingFrameNumber, 334f14fe767SMichael Lotz flags, callback, callbackCookie); 3355b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(pipe); 3365b0ec61fSMichael Lotz if (!object || (object->Type() & USB_OBJECT_ISO_PIPE) == 0) 33717f83b21SMichael Lotz return B_DEV_INVALID_PIPE; 3385b0ec61fSMichael Lotz 3395b0ec61fSMichael Lotz return ((IsochronousPipe *)object)->QueueIsochronous(data, dataLength, 3401bad4a4eSMichael Lotz packetDesc, packetCount, startingFrameNumber, flags, callback, 3411bad4a4eSMichael Lotz callbackCookie); 3425b0ec61fSMichael Lotz } 3435b0ec61fSMichael Lotz 3445b0ec61fSMichael Lotz 3455b0ec61fSMichael Lotz status_t 3465b0ec61fSMichael Lotz set_pipe_policy(usb_pipe pipe, uint8 maxQueuedPackets, 3475b0ec61fSMichael Lotz uint16 maxBufferDurationMS, uint16 sampleSize) 3485b0ec61fSMichael Lotz { 349f14fe767SMichael Lotz TRACE_MODULE("set_pipe_policy(%ld, %d, %d, %d)\n", pipe, maxQueuedPackets, 350f14fe767SMichael Lotz maxBufferDurationMS, sampleSize); 3515b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(pipe); 3525b0ec61fSMichael Lotz if (!object || (object->Type() & USB_OBJECT_ISO_PIPE) == 0) 35317f83b21SMichael Lotz return B_DEV_INVALID_PIPE; 3545b0ec61fSMichael Lotz 35500f6fab9SMichael Lotz return ((IsochronousPipe *)object)->SetPipePolicy(maxQueuedPackets, 35600f6fab9SMichael Lotz maxBufferDurationMS, sampleSize); 3575b0ec61fSMichael Lotz } 3585b0ec61fSMichael Lotz 3595b0ec61fSMichael Lotz 3605b0ec61fSMichael Lotz status_t 3615b0ec61fSMichael Lotz cancel_queued_transfers(usb_pipe pipe) 362b8c6a851SMichael Lotz { 363f14fe767SMichael Lotz TRACE_MODULE("cancel_queued_transfers(%ld)\n", pipe); 3645b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(pipe); 3655b0ec61fSMichael Lotz if (!object || (object->Type() & USB_OBJECT_PIPE) == 0) 36617f83b21SMichael Lotz return B_DEV_INVALID_PIPE; 3675b0ec61fSMichael Lotz 36813508e8bSMichael Lotz return ((Pipe *)object)->CancelQueuedTransfers(false); 369b8c6a851SMichael Lotz } 370b8c6a851SMichael Lotz 371b8c6a851SMichael Lotz 372b8c6a851SMichael Lotz status_t 373b8c6a851SMichael Lotz usb_ioctl(uint32 opcode, void *buffer, size_t bufferSize) 374b8c6a851SMichael Lotz { 375f14fe767SMichael Lotz TRACE_MODULE("usb_ioctl(%lu, %p, %ld)\n", opcode, buffer, bufferSize); 37664f3c065SMichael Lotz 37764f3c065SMichael Lotz switch (opcode) { 37864f3c065SMichael Lotz case 'DNAM': { 3795b0ec61fSMichael Lotz Object *object = gUSBStack->GetObject(*(usb_id *)buffer); 3805b0ec61fSMichael Lotz if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) 3815b0ec61fSMichael Lotz return B_BAD_VALUE; 3825b0ec61fSMichael Lotz 38364f3c065SMichael Lotz uint32 index = 0; 3845b0ec61fSMichael Lotz return ((Device *)object)->BuildDeviceName((char *)buffer, &index, 3855b0ec61fSMichael Lotz bufferSize, NULL); 38664f3c065SMichael Lotz } 38764f3c065SMichael Lotz } 38864f3c065SMichael Lotz 38964f3c065SMichael Lotz return B_DEV_INVALID_IOCTL; 390b8c6a851SMichael Lotz } 391b8c6a851SMichael Lotz 392b8c6a851SMichael Lotz 3937e1490e0SMichael Lotz status_t 3947e1490e0SMichael Lotz get_nth_roothub(uint32 index, usb_device *rootHub) 3957e1490e0SMichael Lotz { 3967e1490e0SMichael Lotz if (!rootHub) 3977e1490e0SMichael Lotz return B_BAD_VALUE; 3987e1490e0SMichael Lotz 3997e1490e0SMichael Lotz BusManager *busManager = gUSBStack->BusManagerAt(index); 4007e1490e0SMichael Lotz if (!busManager) 4017e1490e0SMichael Lotz return B_ENTRY_NOT_FOUND; 4027e1490e0SMichael Lotz 4037e1490e0SMichael Lotz Hub *hub = busManager->GetRootHub(); 4047e1490e0SMichael Lotz if (!hub) 4057e1490e0SMichael Lotz return B_NO_INIT; 4067e1490e0SMichael Lotz 4077e1490e0SMichael Lotz *rootHub = hub->USBID(); 4087e1490e0SMichael Lotz return B_OK; 4097e1490e0SMichael Lotz } 4107e1490e0SMichael Lotz 4117e1490e0SMichael Lotz 4127e1490e0SMichael Lotz status_t 4137e1490e0SMichael Lotz get_nth_child(usb_device _hub, uint8 index, usb_device *childDevice) 4147e1490e0SMichael Lotz { 4157e1490e0SMichael Lotz if (!childDevice) 4167e1490e0SMichael Lotz return B_BAD_VALUE; 4177e1490e0SMichael Lotz 4187e1490e0SMichael Lotz Object *object = gUSBStack->GetObject(_hub); 4197e1490e0SMichael Lotz if (!object || (object->Type() & USB_OBJECT_HUB) == 0) 4207e1490e0SMichael Lotz return B_DEV_INVALID_PIPE; 4217e1490e0SMichael Lotz 4227e1490e0SMichael Lotz Hub *hub = (Hub *)object; 4237e1490e0SMichael Lotz for (uint8 i = 0; i < 8; i++) { 4247e1490e0SMichael Lotz if (hub->ChildAt(i) == NULL) 4257e1490e0SMichael Lotz continue; 4267e1490e0SMichael Lotz 4277e1490e0SMichael Lotz if (index-- > 0) 4287e1490e0SMichael Lotz continue; 4297e1490e0SMichael Lotz 4307e1490e0SMichael Lotz *childDevice = hub->ChildAt(i)->USBID(); 4317e1490e0SMichael Lotz return B_OK; 4327e1490e0SMichael Lotz } 4337e1490e0SMichael Lotz 4347e1490e0SMichael Lotz return B_ENTRY_NOT_FOUND; 4357e1490e0SMichael Lotz } 4367e1490e0SMichael Lotz 4377e1490e0SMichael Lotz 4387e1490e0SMichael Lotz status_t 4397e1490e0SMichael Lotz get_device_parent(usb_device _device, usb_device *parentHub, uint8 *portIndex) 4407e1490e0SMichael Lotz { 4417e1490e0SMichael Lotz if (!parentHub || !portIndex) 4427e1490e0SMichael Lotz return B_BAD_VALUE; 4437e1490e0SMichael Lotz 4447e1490e0SMichael Lotz Object *object = gUSBStack->GetObject(_device); 4457e1490e0SMichael Lotz if (!object || (object->Type() & USB_OBJECT_DEVICE) == 0) 4467e1490e0SMichael Lotz return B_DEV_INVALID_PIPE; 4477e1490e0SMichael Lotz 4487e1490e0SMichael Lotz Object *parent = object->Parent(); 4497e1490e0SMichael Lotz if (!parent || (parent->Type() & USB_OBJECT_HUB) == 0) 4507e1490e0SMichael Lotz return B_ENTRY_NOT_FOUND; 4517e1490e0SMichael Lotz 4527e1490e0SMichael Lotz Hub *hub = (Hub *)parent; 4537e1490e0SMichael Lotz for (uint8 i = 0; i < 8; i++) { 4547e1490e0SMichael Lotz if (hub->ChildAt(i) == object) { 4557e1490e0SMichael Lotz *portIndex = i; 4567e1490e0SMichael Lotz *parentHub = hub->USBID(); 4577e1490e0SMichael Lotz return B_OK; 4587e1490e0SMichael Lotz } 4597e1490e0SMichael Lotz } 4607e1490e0SMichael Lotz 4617e1490e0SMichael Lotz return B_ERROR; 4627e1490e0SMichael Lotz } 4637e1490e0SMichael Lotz 4647e1490e0SMichael Lotz 4657e1490e0SMichael Lotz status_t 4667e1490e0SMichael Lotz reset_port(usb_device _hub, uint8 portIndex) 4677e1490e0SMichael Lotz { 4687e1490e0SMichael Lotz Object *object = gUSBStack->GetObject(_hub); 4697e1490e0SMichael Lotz if (!object || (object->Type() & USB_OBJECT_HUB) == 0) 4707e1490e0SMichael Lotz return B_DEV_INVALID_PIPE; 4717e1490e0SMichael Lotz 4727e1490e0SMichael Lotz Hub *hub = (Hub *)object; 4737e1490e0SMichael Lotz return hub->ResetPort(portIndex); 4747e1490e0SMichael Lotz } 4757e1490e0SMichael Lotz 4767e1490e0SMichael Lotz 4777e1490e0SMichael Lotz status_t 4787e1490e0SMichael Lotz disable_port(usb_device _hub, uint8 portIndex) 4797e1490e0SMichael Lotz { 4807e1490e0SMichael Lotz Object *object = gUSBStack->GetObject(_hub); 4817e1490e0SMichael Lotz if (!object || (object->Type() & USB_OBJECT_HUB) == 0) 4827e1490e0SMichael Lotz return B_DEV_INVALID_PIPE; 4837e1490e0SMichael Lotz 4847e1490e0SMichael Lotz Hub *hub = (Hub *)object; 4857e1490e0SMichael Lotz return hub->DisablePort(portIndex); 4867e1490e0SMichael Lotz } 4877e1490e0SMichael Lotz 4887e1490e0SMichael Lotz 48996da8285SMichael Lotz /* 4905b0ec61fSMichael Lotz This module exports the USB API v3 49196da8285SMichael Lotz */ 4925b0ec61fSMichael Lotz struct usb_module_info gModuleInfoV3 = { 4931501c2bfSNiels Sascha Reedijk // First the bus_manager_info: 4941501c2bfSNiels Sascha Reedijk { 4951501c2bfSNiels Sascha Reedijk { 4965b0ec61fSMichael Lotz "bus_managers/usb/v3", 4971501c2bfSNiels Sascha Reedijk B_KEEP_LOADED, // Keep loaded, even if no driver requires it 4981501c2bfSNiels Sascha Reedijk bus_std_ops 4991501c2bfSNiels Sascha Reedijk }, 5001501c2bfSNiels Sascha Reedijk NULL // the rescan function 5011501c2bfSNiels Sascha Reedijk }, 50296da8285SMichael Lotz 503b8c6a851SMichael Lotz register_driver, // register_driver 504b8c6a851SMichael Lotz install_notify, // install_notify 505b8c6a851SMichael Lotz uninstall_notify, // uninstall_notify 506b8c6a851SMichael Lotz get_device_descriptor, // get_device_descriptor 507b8c6a851SMichael Lotz get_nth_configuration, // get_nth_configuration 508b8c6a851SMichael Lotz get_configuration, // get_configuration 509b8c6a851SMichael Lotz set_configuration, // set_configuration 510b8c6a851SMichael Lotz set_alt_interface, // set_alt_interface 511b8c6a851SMichael Lotz set_feature, // set_feature 512b8c6a851SMichael Lotz clear_feature, // clear_feature 513b8c6a851SMichael Lotz get_status, // get_status 514b8c6a851SMichael Lotz get_descriptor, // get_descriptor 515b8c6a851SMichael Lotz send_request, // send_request 516b8c6a851SMichael Lotz queue_interrupt, // queue_interrupt 517b8c6a851SMichael Lotz queue_bulk, // queue_bulk 5185b0ec61fSMichael Lotz queue_bulk_v, // queue_bulk_v 519b8c6a851SMichael Lotz queue_isochronous, // queue_isochronous 520b8c6a851SMichael Lotz queue_request, // queue_request 521b8c6a851SMichael Lotz set_pipe_policy, // set_pipe_policy 522b8c6a851SMichael Lotz cancel_queued_transfers, // cancel_queued_transfers 5237e1490e0SMichael Lotz usb_ioctl, // usb_ioctl 5247e1490e0SMichael Lotz get_nth_roothub, // get_nth_roothub 5257e1490e0SMichael Lotz get_nth_child, // get_nth_child 5267e1490e0SMichael Lotz get_device_parent, // get_device_parent 5277e1490e0SMichael Lotz reset_port, // reset_port 5287e1490e0SMichael Lotz disable_port // disable_port 5291501c2bfSNiels Sascha Reedijk }; 5301501c2bfSNiels Sascha Reedijk 53196da8285SMichael Lotz 5325b0ec61fSMichael Lotz // 5335b0ec61fSMichael Lotz // #pragma mark - 5345b0ec61fSMichael Lotz // 5355b0ec61fSMichael Lotz 5365b0ec61fSMichael Lotz 5375b0ec61fSMichael Lotz const usb_device_descriptor * 5385b0ec61fSMichael Lotz get_device_descriptor_v2(const void *device) 5395b0ec61fSMichael Lotz { 5405b0ec61fSMichael Lotz return get_device_descriptor((usb_id)device); 5415b0ec61fSMichael Lotz } 5425b0ec61fSMichael Lotz 5435b0ec61fSMichael Lotz 5445b0ec61fSMichael Lotz const usb_configuration_info * 5455b0ec61fSMichael Lotz get_nth_configuration_v2(const void *device, uint index) 5465b0ec61fSMichael Lotz { 5475b0ec61fSMichael Lotz return get_nth_configuration((usb_id)device, index); 5485b0ec61fSMichael Lotz } 5495b0ec61fSMichael Lotz 5505b0ec61fSMichael Lotz 5515b0ec61fSMichael Lotz const usb_configuration_info * 5525b0ec61fSMichael Lotz get_configuration_v2(const void *device) 5535b0ec61fSMichael Lotz { 5545b0ec61fSMichael Lotz return get_configuration((usb_id)device); 5555b0ec61fSMichael Lotz } 5565b0ec61fSMichael Lotz 5575b0ec61fSMichael Lotz 5585b0ec61fSMichael Lotz status_t 5595b0ec61fSMichael Lotz set_configuration_v2(const void *device, 5605b0ec61fSMichael Lotz const usb_configuration_info *configuration) 5615b0ec61fSMichael Lotz { 5625b0ec61fSMichael Lotz return set_configuration((usb_id)device, configuration); 5635b0ec61fSMichael Lotz } 5645b0ec61fSMichael Lotz 5655b0ec61fSMichael Lotz 5665b0ec61fSMichael Lotz status_t 5675b0ec61fSMichael Lotz set_alt_interface_v2(const void *device, const usb_interface_info *interface) 5685b0ec61fSMichael Lotz { 5695b0ec61fSMichael Lotz return set_alt_interface((usb_id)device, interface); 5705b0ec61fSMichael Lotz } 5715b0ec61fSMichael Lotz 5725b0ec61fSMichael Lotz 5735b0ec61fSMichael Lotz status_t 5745b0ec61fSMichael Lotz set_feature_v2(const void *object, uint16 selector) 5755b0ec61fSMichael Lotz { 5765b0ec61fSMichael Lotz return set_feature((usb_id)object, selector); 5775b0ec61fSMichael Lotz } 5785b0ec61fSMichael Lotz 5795b0ec61fSMichael Lotz 5805b0ec61fSMichael Lotz status_t 5815b0ec61fSMichael Lotz clear_feature_v2(const void *object, uint16 selector) 5825b0ec61fSMichael Lotz { 5835b0ec61fSMichael Lotz return clear_feature((usb_id)object, selector); 5845b0ec61fSMichael Lotz } 5855b0ec61fSMichael Lotz 5865b0ec61fSMichael Lotz 5875b0ec61fSMichael Lotz status_t 5885b0ec61fSMichael Lotz get_status_v2(const void *object, uint16 *status) 5895b0ec61fSMichael Lotz { 5905b0ec61fSMichael Lotz return get_status((usb_id)object, status); 5915b0ec61fSMichael Lotz } 5925b0ec61fSMichael Lotz 5935b0ec61fSMichael Lotz 5945b0ec61fSMichael Lotz status_t 5955b0ec61fSMichael Lotz get_descriptor_v2(const void *device, uint8 type, uint8 index, 5965b0ec61fSMichael Lotz uint16 languageID, void *data, size_t dataLength, size_t *actualLength) 5975b0ec61fSMichael Lotz { 5985b0ec61fSMichael Lotz return get_descriptor((usb_id)device, type, index, languageID, data, 5995b0ec61fSMichael Lotz dataLength, actualLength); 6005b0ec61fSMichael Lotz } 6015b0ec61fSMichael Lotz 6025b0ec61fSMichael Lotz 6035b0ec61fSMichael Lotz status_t 6045b0ec61fSMichael Lotz send_request_v2(const void *device, uint8 requestType, uint8 request, 6055b0ec61fSMichael Lotz uint16 value, uint16 index, uint16 length, void *data, 6065b0ec61fSMichael Lotz size_t /*dataLength*/, size_t *actualLength) 6075b0ec61fSMichael Lotz { 6085b0ec61fSMichael Lotz return send_request((usb_id)device, requestType, request, value, index, 6095b0ec61fSMichael Lotz length, data, actualLength); 6105b0ec61fSMichael Lotz } 6115b0ec61fSMichael Lotz 6125b0ec61fSMichael Lotz 6135b0ec61fSMichael Lotz status_t 6145b0ec61fSMichael Lotz queue_request_v2(const void *device, uint8 requestType, uint8 request, 6155b0ec61fSMichael Lotz uint16 value, uint16 index, uint16 length, void *data, 6165b0ec61fSMichael Lotz size_t /*dataLength*/, usb_callback_func callback, void *callbackCookie) 6175b0ec61fSMichael Lotz { 6185b0ec61fSMichael Lotz return queue_request((usb_id)device, requestType, request, value, index, 6195b0ec61fSMichael Lotz length, data, callback, callbackCookie); 6205b0ec61fSMichael Lotz } 6215b0ec61fSMichael Lotz 6225b0ec61fSMichael Lotz 6235b0ec61fSMichael Lotz status_t 6245b0ec61fSMichael Lotz queue_interrupt_v2(const void *pipe, void *data, size_t dataLength, 6255b0ec61fSMichael Lotz usb_callback_func callback, void *callbackCookie) 6265b0ec61fSMichael Lotz { 6275b0ec61fSMichael Lotz return queue_interrupt((usb_id)pipe, data, dataLength, callback, 6285b0ec61fSMichael Lotz callbackCookie); 6295b0ec61fSMichael Lotz } 6305b0ec61fSMichael Lotz 6315b0ec61fSMichael Lotz 6325b0ec61fSMichael Lotz status_t 6335b0ec61fSMichael Lotz queue_bulk_v2(const void *pipe, void *data, size_t dataLength, 6345b0ec61fSMichael Lotz usb_callback_func callback, void *callbackCookie) 6355b0ec61fSMichael Lotz { 6365b0ec61fSMichael Lotz return queue_bulk((usb_id)pipe, data, dataLength, callback, 6375b0ec61fSMichael Lotz callbackCookie); 6385b0ec61fSMichael Lotz } 6395b0ec61fSMichael Lotz 6405b0ec61fSMichael Lotz 6415b0ec61fSMichael Lotz status_t 6425b0ec61fSMichael Lotz queue_isochronous_v2(const void *pipe, void *data, size_t dataLength, 6435b0ec61fSMichael Lotz rlea *rleArray, uint16 bufferDurationMS, usb_callback_func callback, 6445b0ec61fSMichael Lotz void *callbackCookie) 6455b0ec61fSMichael Lotz { 6461bad4a4eSMichael Lotz // ToDo: convert rlea to usb_iso_packet_descriptor 6471bad4a4eSMichael Lotz // ToDo: use a flag to indicate that the callback shall produce a rlea 6481bad4a4eSMichael Lotz usb_iso_packet_descriptor *packetDesc = NULL; 6491bad4a4eSMichael Lotz return queue_isochronous((usb_id)pipe, data, dataLength, packetDesc, 0, 6501bad4a4eSMichael Lotz NULL, 0, callback, callbackCookie); 6515b0ec61fSMichael Lotz } 6525b0ec61fSMichael Lotz 6535b0ec61fSMichael Lotz 6545b0ec61fSMichael Lotz status_t 6555b0ec61fSMichael Lotz set_pipe_policy_v2(const void *pipe, uint8 maxQueuedPackets, 6565b0ec61fSMichael Lotz uint16 maxBufferDurationMS, uint16 sampleSize) 6575b0ec61fSMichael Lotz { 6585b0ec61fSMichael Lotz return set_pipe_policy((usb_id)pipe, maxQueuedPackets, maxBufferDurationMS, 6595b0ec61fSMichael Lotz sampleSize); 6605b0ec61fSMichael Lotz } 6615b0ec61fSMichael Lotz 6625b0ec61fSMichael Lotz 6635b0ec61fSMichael Lotz status_t 6645b0ec61fSMichael Lotz cancel_queued_transfers_v2(const void *pipe) 6655b0ec61fSMichael Lotz { 6665b0ec61fSMichael Lotz return cancel_queued_transfers((usb_id)pipe); 6675b0ec61fSMichael Lotz } 6685b0ec61fSMichael Lotz 6695b0ec61fSMichael Lotz 6705b0ec61fSMichael Lotz struct usb_module_info_v2 { 6715b0ec61fSMichael Lotz bus_manager_info binfo; 6725b0ec61fSMichael Lotz status_t (*register_driver)(const char *, const usb_support_descriptor *, size_t, const char *); 6735b0ec61fSMichael Lotz status_t (*install_notify)(const char *, const usb_notify_hooks *); 6745b0ec61fSMichael Lotz status_t (*uninstall_notify)(const char *); 6755b0ec61fSMichael Lotz const usb_device_descriptor *(*get_device_descriptor)(const void *); 6765b0ec61fSMichael Lotz const usb_configuration_info *(*get_nth_configuration)(const void *, uint); 6775b0ec61fSMichael Lotz const usb_configuration_info *(*get_configuration)(const void *); 6785b0ec61fSMichael Lotz status_t (*set_configuration)(const void *, const usb_configuration_info *); 6795b0ec61fSMichael Lotz status_t (*set_alt_interface)(const void *, const usb_interface_info *); 6805b0ec61fSMichael Lotz status_t (*set_feature)(const void *, uint16); 6815b0ec61fSMichael Lotz status_t (*clear_feature)(const void *, uint16); 6825b0ec61fSMichael Lotz status_t (*get_status)(const void *, uint16 *); 6835b0ec61fSMichael Lotz status_t (*get_descriptor)(const void *, uint8, uint8, uint16, void *, size_t, size_t *); 6845b0ec61fSMichael Lotz status_t (*send_request)(const void *, uint8, uint8, uint16, uint16, uint16, void *, size_t, size_t *); 6855b0ec61fSMichael Lotz status_t (*queue_interrupt)(const void *, void *, size_t, usb_callback_func, void *); 6865b0ec61fSMichael Lotz status_t (*queue_bulk)(const void *, void *, size_t, usb_callback_func, void *); 6875b0ec61fSMichael Lotz status_t (*queue_isochronous)(const void *, void *, size_t, rlea *, uint16, usb_callback_func, void *); 6885b0ec61fSMichael Lotz status_t (*queue_request)(const void *, uint8, uint8, uint16, uint16, uint16, void *, size_t, usb_callback_func, void *); 6895b0ec61fSMichael Lotz status_t (*set_pipe_policy)(const void *, uint8, uint16, uint16); 6905b0ec61fSMichael Lotz status_t (*cancel_queued_transfers)(const void *); 6915b0ec61fSMichael Lotz status_t (*usb_ioctl)(uint32 opcode, void *,size_t); 6925b0ec61fSMichael Lotz }; 6935b0ec61fSMichael Lotz 6945b0ec61fSMichael Lotz 6955b0ec61fSMichael Lotz /* 6965b0ec61fSMichael Lotz This module exports the USB API v2 6975b0ec61fSMichael Lotz */ 6985b0ec61fSMichael Lotz struct usb_module_info_v2 gModuleInfoV2 = { 6995b0ec61fSMichael Lotz // First the bus_manager_info: 7005b0ec61fSMichael Lotz { 7015b0ec61fSMichael Lotz { 7025b0ec61fSMichael Lotz "bus_managers/usb/v2", 7035b0ec61fSMichael Lotz B_KEEP_LOADED, // Keep loaded, even if no driver requires it 7045b0ec61fSMichael Lotz bus_std_ops 7055b0ec61fSMichael Lotz }, 7065b0ec61fSMichael Lotz NULL // the rescan function 7075b0ec61fSMichael Lotz }, 7085b0ec61fSMichael Lotz 7095b0ec61fSMichael Lotz register_driver, // register_driver 7105b0ec61fSMichael Lotz install_notify, // install_notify 7115b0ec61fSMichael Lotz uninstall_notify, // uninstall_notify 7125b0ec61fSMichael Lotz get_device_descriptor_v2, // get_device_descriptor 7135b0ec61fSMichael Lotz get_nth_configuration_v2, // get_nth_configuration 7145b0ec61fSMichael Lotz get_configuration_v2, // get_configuration 7155b0ec61fSMichael Lotz set_configuration_v2, // set_configuration 7165b0ec61fSMichael Lotz set_alt_interface_v2, // set_alt_interface 7175b0ec61fSMichael Lotz set_feature_v2, // set_feature 7185b0ec61fSMichael Lotz clear_feature_v2, // clear_feature 7195b0ec61fSMichael Lotz get_status_v2, // get_status 7205b0ec61fSMichael Lotz get_descriptor_v2, // get_descriptor 7215b0ec61fSMichael Lotz send_request_v2, // send_request 7225b0ec61fSMichael Lotz queue_interrupt_v2, // queue_interrupt 7235b0ec61fSMichael Lotz queue_bulk_v2, // queue_bulk 7245b0ec61fSMichael Lotz queue_isochronous_v2, // queue_isochronous 7255b0ec61fSMichael Lotz queue_request_v2, // queue_request 7265b0ec61fSMichael Lotz set_pipe_policy_v2, // set_pipe_policy 7275b0ec61fSMichael Lotz cancel_queued_transfers_v2, // cancel_queued_transfers 7285b0ec61fSMichael Lotz usb_ioctl // usb_ioctl 7295b0ec61fSMichael Lotz }; 7305b0ec61fSMichael Lotz 7315b0ec61fSMichael Lotz 7325b0ec61fSMichael Lotz // 7335b0ec61fSMichael Lotz // #pragma mark - 7345b0ec61fSMichael Lotz // 7355b0ec61fSMichael Lotz 7365b0ec61fSMichael Lotz 7371501c2bfSNiels Sascha Reedijk module_info *modules[] = { 7385b0ec61fSMichael Lotz (module_info *)&gModuleInfoV2, 7395b0ec61fSMichael Lotz (module_info *)&gModuleInfoV3, 7401501c2bfSNiels Sascha Reedijk NULL 7411501c2bfSNiels Sascha Reedijk }; 742