19760dcaeSOliver Ruiz Dorantes /* 29760dcaeSOliver Ruiz Dorantes * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com 39760dcaeSOliver Ruiz Dorantes * Copyright 2008 Mika Lindqvist, monni1995_at_gmail.com 49760dcaeSOliver Ruiz Dorantes * All rights reserved. Distributed under the terms of the MIT License. 59760dcaeSOliver Ruiz Dorantes * 69760dcaeSOliver Ruiz Dorantes */ 79760dcaeSOliver Ruiz Dorantes 8*05e11655SAlexander von Gluck IV 9e1e291b0SAlexander von Gluck IV #include "h2generic.h" 10e1e291b0SAlexander von Gluck IV 11a8f90110SAlexander von Gluck IV #include <kernel.h> 129760dcaeSOliver Ruiz Dorantes #include <malloc.h> 139760dcaeSOliver Ruiz Dorantes #include <stdio.h> 149760dcaeSOliver Ruiz Dorantes #include <string.h> 159760dcaeSOliver Ruiz Dorantes 169760dcaeSOliver Ruiz Dorantes #include <KernelExport.h> 179760dcaeSOliver Ruiz Dorantes #include <ByteOrder.h> 189760dcaeSOliver Ruiz Dorantes #include <Drivers.h> 199760dcaeSOliver Ruiz Dorantes 209760dcaeSOliver Ruiz Dorantes #include <btModules.h> 219760dcaeSOliver Ruiz Dorantes 22*05e11655SAlexander von Gluck IV #include "snet_buffer.h" 23*05e11655SAlexander von Gluck IV #include "h2cfg.h" 24*05e11655SAlexander von Gluck IV #include "h2debug.h" 259760dcaeSOliver Ruiz Dorantes #include "h2transactions.h" 269760dcaeSOliver Ruiz Dorantes #include "h2util.h" 279760dcaeSOliver Ruiz Dorantes 281f2fa6cdSAlexander von Gluck IV 299760dcaeSOliver Ruiz Dorantes int32 api_version = B_CUR_DRIVER_API_VERSION; 309760dcaeSOliver Ruiz Dorantes 319760dcaeSOliver Ruiz Dorantes // Modules 320ea1aab2SOliver Tappe static const char* usb_name = B_USB_MODULE_NAME; 330ea1aab2SOliver Tappe static const char* hci_name = BT_HCI_MODULE_NAME; 340ea1aab2SOliver Tappe static const char* btDevices_name = BT_HCI_MODULE_NAME; 359760dcaeSOliver Ruiz Dorantes 369760dcaeSOliver Ruiz Dorantes 379760dcaeSOliver Ruiz Dorantes usb_module_info* usb = NULL; 389760dcaeSOliver Ruiz Dorantes bt_hci_module_info* hci = NULL; // TODO remove / clean 399760dcaeSOliver Ruiz Dorantes struct bt_hci_module_info* btDevices = NULL; 409760dcaeSOliver Ruiz Dorantes struct net_buffer_module_info* nb = NULL; 419760dcaeSOliver Ruiz Dorantes struct bluetooth_core_data_module_info* btCoreData = NULL; 429760dcaeSOliver Ruiz Dorantes 439760dcaeSOliver Ruiz Dorantes // Driver Global data 449760dcaeSOliver Ruiz Dorantes static char* publish_names[MAX_BT_GENERIC_USB_DEVICES]; 459760dcaeSOliver Ruiz Dorantes 469760dcaeSOliver Ruiz Dorantes int32 dev_count = 0; // number of connected devices 479760dcaeSOliver Ruiz Dorantes static bt_usb_dev* bt_usb_devices[MAX_BT_GENERIC_USB_DEVICES]; 489760dcaeSOliver Ruiz Dorantes sem_id dev_table_sem = -1; // sem to synchronize access to device table 499760dcaeSOliver Ruiz Dorantes 509760dcaeSOliver Ruiz Dorantes status_t submit_nbuffer(hci_id hid, net_buffer* nbuf); 519760dcaeSOliver Ruiz Dorantes 529760dcaeSOliver Ruiz Dorantes usb_support_descriptor supported_devices[] = { 539760dcaeSOliver Ruiz Dorantes // Generic Bluetooth USB device 549760dcaeSOliver Ruiz Dorantes // Class, SubClass, and Protocol codes that describe a Bluetooth device 559760dcaeSOliver Ruiz Dorantes { UDCLASS_WIRELESS, UDSUBCLASS_RF, UDPROTO_BLUETOOTH , 0 , 0 }, 569760dcaeSOliver Ruiz Dorantes 579760dcaeSOliver Ruiz Dorantes // Broadcom BCM2035 589760dcaeSOliver Ruiz Dorantes { 0, 0, 0, 0x0a5c, 0x200a }, 599760dcaeSOliver Ruiz Dorantes { 0, 0, 0, 0x0a5c, 0x2009 }, 609760dcaeSOliver Ruiz Dorantes 619760dcaeSOliver Ruiz Dorantes // Devices taken from the linux Driver 629760dcaeSOliver Ruiz Dorantes // AVM BlueFRITZ! USB v2.0 639760dcaeSOliver Ruiz Dorantes { 0, 0, 0, 0x057c, 0x3800 }, 649760dcaeSOliver Ruiz Dorantes // Bluetooth Ultraport Module from IBM 659760dcaeSOliver Ruiz Dorantes { 0, 0, 0, 0x04bf, 0x030a }, 669760dcaeSOliver Ruiz Dorantes // ALPS Modules with non-standard id 679760dcaeSOliver Ruiz Dorantes { 0, 0, 0, 0x044e, 0x3001 }, 689760dcaeSOliver Ruiz Dorantes { 0, 0, 0, 0x044e, 0x3002 }, 699760dcaeSOliver Ruiz Dorantes // Ericsson with non-standard id 709760dcaeSOliver Ruiz Dorantes { 0, 0, 0, 0x0bdb, 0x1002 } 719760dcaeSOliver Ruiz Dorantes }; 729760dcaeSOliver Ruiz Dorantes 739760dcaeSOliver Ruiz Dorantes /* add a device to the list of connected devices */ 749760dcaeSOliver Ruiz Dorantes #ifdef HAIKU_TARGET_PLATFORM_HAIKU 759760dcaeSOliver Ruiz Dorantes static bt_usb_dev* 769760dcaeSOliver Ruiz Dorantes spawn_device(usb_device usb_dev) 779760dcaeSOliver Ruiz Dorantes #else 789760dcaeSOliver Ruiz Dorantes static bt_usb_dev* 799760dcaeSOliver Ruiz Dorantes spawn_device(usb_device* usb_dev) 809760dcaeSOliver Ruiz Dorantes #endif 819760dcaeSOliver Ruiz Dorantes 829760dcaeSOliver Ruiz Dorantes { 831f2fa6cdSAlexander von Gluck IV CALLED(); 841f2fa6cdSAlexander von Gluck IV 859760dcaeSOliver Ruiz Dorantes int32 i; 869760dcaeSOliver Ruiz Dorantes status_t err = B_OK; 879760dcaeSOliver Ruiz Dorantes bt_usb_dev* new_bt_dev = NULL; 889760dcaeSOliver Ruiz Dorantes 899760dcaeSOliver Ruiz Dorantes // 16 usb dongles... 909760dcaeSOliver Ruiz Dorantes if (dev_count >= MAX_BT_GENERIC_USB_DEVICES) { 911f2fa6cdSAlexander von Gluck IV ERROR("%s: Device table full\n", __func__); 929760dcaeSOliver Ruiz Dorantes goto exit; 939760dcaeSOliver Ruiz Dorantes } 949760dcaeSOliver Ruiz Dorantes 959760dcaeSOliver Ruiz Dorantes // try the allocation 969760dcaeSOliver Ruiz Dorantes new_bt_dev = (bt_usb_dev*)malloc(sizeof(bt_usb_dev)); 979760dcaeSOliver Ruiz Dorantes if (new_bt_dev == NULL) { 981f2fa6cdSAlexander von Gluck IV ERROR("%s: Unable to malloc new bt device\n", __func__); 999760dcaeSOliver Ruiz Dorantes goto exit; 1009760dcaeSOliver Ruiz Dorantes } 1019760dcaeSOliver Ruiz Dorantes memset(new_bt_dev, 0, sizeof(bt_usb_dev)); 1029760dcaeSOliver Ruiz Dorantes 1039760dcaeSOliver Ruiz Dorantes // We will need this sem for some flow control 1049760dcaeSOliver Ruiz Dorantes new_bt_dev->cmd_complete = create_sem(1, 1059760dcaeSOliver Ruiz Dorantes BLUETOOTH_DEVICE_DEVFS_NAME "cmd_complete"); 1069760dcaeSOliver Ruiz Dorantes if (new_bt_dev->cmd_complete < 0) { 1079760dcaeSOliver Ruiz Dorantes err = new_bt_dev->cmd_complete; 1089760dcaeSOliver Ruiz Dorantes goto bail0; 1099760dcaeSOliver Ruiz Dorantes } 1109760dcaeSOliver Ruiz Dorantes 1119760dcaeSOliver Ruiz Dorantes // and this for something else 1129760dcaeSOliver Ruiz Dorantes new_bt_dev->lock = create_sem(1, BLUETOOTH_DEVICE_DEVFS_NAME "lock"); 1139760dcaeSOliver Ruiz Dorantes if (new_bt_dev->lock < 0) { 1149760dcaeSOliver Ruiz Dorantes err = new_bt_dev->lock; 1159760dcaeSOliver Ruiz Dorantes goto bail1; 1169760dcaeSOliver Ruiz Dorantes } 1179760dcaeSOliver Ruiz Dorantes 1189760dcaeSOliver Ruiz Dorantes // find a free slot and fill out the name 1199760dcaeSOliver Ruiz Dorantes acquire_sem(dev_table_sem); 1209760dcaeSOliver Ruiz Dorantes for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { 1219760dcaeSOliver Ruiz Dorantes if (bt_usb_devices[i] == NULL) { 1229760dcaeSOliver Ruiz Dorantes bt_usb_devices[i] = new_bt_dev; 123f2986394SAlexander von Gluck IV sprintf(new_bt_dev->name, "%s/%" B_PRId32, 124f2986394SAlexander von Gluck IV BLUETOOTH_DEVICE_PATH, i); 1259760dcaeSOliver Ruiz Dorantes new_bt_dev->num = i; 1261f2fa6cdSAlexander von Gluck IV TRACE("%s: added device %p %" B_PRId32 " %s\n", __func__, 1271f2fa6cdSAlexander von Gluck IV bt_usb_devices[i], new_bt_dev->num, new_bt_dev->name); 1289760dcaeSOliver Ruiz Dorantes break; 1299760dcaeSOliver Ruiz Dorantes } 1309760dcaeSOliver Ruiz Dorantes } 1319760dcaeSOliver Ruiz Dorantes release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); 1329760dcaeSOliver Ruiz Dorantes 1339760dcaeSOliver Ruiz Dorantes // In the case we cannot us 1349760dcaeSOliver Ruiz Dorantes if (bt_usb_devices[i] != new_bt_dev) { 1351f2fa6cdSAlexander von Gluck IV ERROR("%s: Device could not be added\n", __func__); 1369760dcaeSOliver Ruiz Dorantes goto bail2; 1379760dcaeSOliver Ruiz Dorantes } 1389760dcaeSOliver Ruiz Dorantes 1399760dcaeSOliver Ruiz Dorantes new_bt_dev->dev = usb_dev; 1409760dcaeSOliver Ruiz Dorantes // TODO: currently only server opens 1419760dcaeSOliver Ruiz Dorantes new_bt_dev->open_count = 0; 1429760dcaeSOliver Ruiz Dorantes 1439760dcaeSOliver Ruiz Dorantes dev_count++; 1449760dcaeSOliver Ruiz Dorantes return new_bt_dev; 1459760dcaeSOliver Ruiz Dorantes 1469760dcaeSOliver Ruiz Dorantes bail2: 1479760dcaeSOliver Ruiz Dorantes delete_sem(new_bt_dev->lock); 1489760dcaeSOliver Ruiz Dorantes bail1: 1499760dcaeSOliver Ruiz Dorantes delete_sem(new_bt_dev->cmd_complete); 1509760dcaeSOliver Ruiz Dorantes bail0: 1519760dcaeSOliver Ruiz Dorantes free(new_bt_dev); 1529760dcaeSOliver Ruiz Dorantes exit: 1539760dcaeSOliver Ruiz Dorantes return new_bt_dev; 1549760dcaeSOliver Ruiz Dorantes } 1559760dcaeSOliver Ruiz Dorantes 1569760dcaeSOliver Ruiz Dorantes 1579760dcaeSOliver Ruiz Dorantes // remove a device from the list of connected devices 1589760dcaeSOliver Ruiz Dorantes static void 1599760dcaeSOliver Ruiz Dorantes kill_device(bt_usb_dev* bdev) 1609760dcaeSOliver Ruiz Dorantes { 1619760dcaeSOliver Ruiz Dorantes if (bdev != NULL) { 1621f2fa6cdSAlexander von Gluck IV TRACE("%s: (%p)\n", __func__, bdev); 1639760dcaeSOliver Ruiz Dorantes 1649760dcaeSOliver Ruiz Dorantes delete_sem(bdev->lock); 1659760dcaeSOliver Ruiz Dorantes delete_sem(bdev->cmd_complete); 1669760dcaeSOliver Ruiz Dorantes 1679760dcaeSOliver Ruiz Dorantes // mark it free 1689760dcaeSOliver Ruiz Dorantes bt_usb_devices[bdev->num] = NULL; 1699760dcaeSOliver Ruiz Dorantes 1709760dcaeSOliver Ruiz Dorantes free(bdev); 1719760dcaeSOliver Ruiz Dorantes dev_count--; 1729760dcaeSOliver Ruiz Dorantes } 1739760dcaeSOliver Ruiz Dorantes } 1749760dcaeSOliver Ruiz Dorantes 1759760dcaeSOliver Ruiz Dorantes 1769760dcaeSOliver Ruiz Dorantes bt_usb_dev* 1779760dcaeSOliver Ruiz Dorantes fetch_device(bt_usb_dev* dev, hci_id hid) 1789760dcaeSOliver Ruiz Dorantes { 1799760dcaeSOliver Ruiz Dorantes int i; 1809760dcaeSOliver Ruiz Dorantes 1811f2fa6cdSAlexander von Gluck IV // TRACE("%s: (%p) or %d\n", __func__, dev, hid); 1829760dcaeSOliver Ruiz Dorantes 1839760dcaeSOliver Ruiz Dorantes acquire_sem(dev_table_sem); 184f2986394SAlexander von Gluck IV if (dev != NULL) { 1859760dcaeSOliver Ruiz Dorantes for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { 1869760dcaeSOliver Ruiz Dorantes if (bt_usb_devices[i] == dev) { 1879760dcaeSOliver Ruiz Dorantes release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); 1889760dcaeSOliver Ruiz Dorantes return bt_usb_devices[i]; 1899760dcaeSOliver Ruiz Dorantes } 1909760dcaeSOliver Ruiz Dorantes } 191f2986394SAlexander von Gluck IV } else { 1929760dcaeSOliver Ruiz Dorantes for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { 1939760dcaeSOliver Ruiz Dorantes if (bt_usb_devices[i] != NULL && bt_usb_devices[i]->hdev == hid) { 1949760dcaeSOliver Ruiz Dorantes release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); 1959760dcaeSOliver Ruiz Dorantes return bt_usb_devices[i]; 1969760dcaeSOliver Ruiz Dorantes } 1979760dcaeSOliver Ruiz Dorantes } 198f2986394SAlexander von Gluck IV } 1999760dcaeSOliver Ruiz Dorantes 2009760dcaeSOliver Ruiz Dorantes release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); 2019760dcaeSOliver Ruiz Dorantes 2029760dcaeSOliver Ruiz Dorantes return NULL; 2039760dcaeSOliver Ruiz Dorantes } 2049760dcaeSOliver Ruiz Dorantes 2059760dcaeSOliver Ruiz Dorantes 2069760dcaeSOliver Ruiz Dorantes #if 0 2079760dcaeSOliver Ruiz Dorantes #pragma mark - 2089760dcaeSOliver Ruiz Dorantes #endif 2099760dcaeSOliver Ruiz Dorantes 2109760dcaeSOliver Ruiz Dorantes // called by USB Manager when device is added to the USB 2119760dcaeSOliver Ruiz Dorantes #ifdef HAIKU_TARGET_PLATFORM_HAIKU 2129760dcaeSOliver Ruiz Dorantes static status_t 2139760dcaeSOliver Ruiz Dorantes device_added(usb_device dev, void** cookie) 2149760dcaeSOliver Ruiz Dorantes #else 2159760dcaeSOliver Ruiz Dorantes device_added(usb_device* dev, void** cookie) 2169760dcaeSOliver Ruiz Dorantes #endif 2179760dcaeSOliver Ruiz Dorantes { 2189760dcaeSOliver Ruiz Dorantes const usb_interface_info* interface; 2199760dcaeSOliver Ruiz Dorantes const usb_device_descriptor* desc; 2209760dcaeSOliver Ruiz Dorantes const usb_configuration_info* config; 2219760dcaeSOliver Ruiz Dorantes const usb_interface_info* uif; 2229760dcaeSOliver Ruiz Dorantes const usb_endpoint_info* ep; 2239760dcaeSOliver Ruiz Dorantes 2249760dcaeSOliver Ruiz Dorantes status_t err = B_ERROR; 2259760dcaeSOliver Ruiz Dorantes bt_usb_dev* new_bt_dev = spawn_device(dev); 2269760dcaeSOliver Ruiz Dorantes int e; 2279760dcaeSOliver Ruiz Dorantes 2281f2fa6cdSAlexander von Gluck IV TRACE("%s: device_added(%p)\n", __func__, new_bt_dev); 2299760dcaeSOliver Ruiz Dorantes 2309760dcaeSOliver Ruiz Dorantes if (new_bt_dev == NULL) { 2311f2fa6cdSAlexander von Gluck IV ERROR("%s: Couldn't allocate device record.\n", __func__); 2329760dcaeSOliver Ruiz Dorantes err = ENOMEM; 2339760dcaeSOliver Ruiz Dorantes goto bail_no_mem; 2349760dcaeSOliver Ruiz Dorantes } 2359760dcaeSOliver Ruiz Dorantes 2369760dcaeSOliver Ruiz Dorantes // we only have 1 configuration number 0 2379760dcaeSOliver Ruiz Dorantes config = usb->get_nth_configuration(dev, 0); 2389760dcaeSOliver Ruiz Dorantes // dump_usb_configuration_info(config); 2399760dcaeSOliver Ruiz Dorantes if (config == NULL) { 2401f2fa6cdSAlexander von Gluck IV ERROR("%s: Couldn't get default USB config.\n", __func__); 2419760dcaeSOliver Ruiz Dorantes err = B_ERROR; 2429760dcaeSOliver Ruiz Dorantes goto bail; 2439760dcaeSOliver Ruiz Dorantes } 2449760dcaeSOliver Ruiz Dorantes 2451f2fa6cdSAlexander von Gluck IV TRACE("%s: found %" B_PRIuSIZE " alt interfaces.\n", __func__, 246f2986394SAlexander von Gluck IV config->interface->alt_count); 2479760dcaeSOliver Ruiz Dorantes 2489760dcaeSOliver Ruiz Dorantes // set first interface 2499760dcaeSOliver Ruiz Dorantes interface = &config->interface->alt[0]; 2509760dcaeSOliver Ruiz Dorantes err = usb->set_alt_interface(new_bt_dev->dev, interface); 2519760dcaeSOliver Ruiz Dorantes 2529760dcaeSOliver Ruiz Dorantes if (err != B_OK) { 2531f2fa6cdSAlexander von Gluck IV ERROR("%s: set_alt_interface() error.\n", __func__); 2549760dcaeSOliver Ruiz Dorantes goto bail; 2559760dcaeSOliver Ruiz Dorantes } 2569760dcaeSOliver Ruiz Dorantes 2579760dcaeSOliver Ruiz Dorantes // call set_configuration() only after calling set_alt_interface() 2589760dcaeSOliver Ruiz Dorantes err = usb->set_configuration(dev, config); 2599760dcaeSOliver Ruiz Dorantes if (err != B_OK) { 2601f2fa6cdSAlexander von Gluck IV ERROR("%s: set_configuration() error.\n", __func__); 2619760dcaeSOliver Ruiz Dorantes goto bail; 2629760dcaeSOliver Ruiz Dorantes } 2639760dcaeSOliver Ruiz Dorantes 2649760dcaeSOliver Ruiz Dorantes // Place to find out whats our concrete device and set up some special 2659760dcaeSOliver Ruiz Dorantes // info to our driver. If this code increases too much reconsider 2669760dcaeSOliver Ruiz Dorantes // this implementation 2679760dcaeSOliver Ruiz Dorantes desc = usb->get_device_descriptor(dev); 2689760dcaeSOliver Ruiz Dorantes if (desc->vendor_id == 0x0a5c 2699760dcaeSOliver Ruiz Dorantes && (desc->product_id == 0x200a 2709760dcaeSOliver Ruiz Dorantes || desc->product_id == 0x2009 2719760dcaeSOliver Ruiz Dorantes || desc->product_id == 0x2035)) { 2729760dcaeSOliver Ruiz Dorantes 2739760dcaeSOliver Ruiz Dorantes new_bt_dev->driver_info = BT_WILL_NEED_A_RESET | BT_SCO_NOT_WORKING; 2749760dcaeSOliver Ruiz Dorantes 2759760dcaeSOliver Ruiz Dorantes } 2769760dcaeSOliver Ruiz Dorantes /* 2779760dcaeSOliver Ruiz Dorantes else if ( desc->vendor_id == YOUR_VENDOR_HERE 2789760dcaeSOliver Ruiz Dorantes && desc->product_id == YOUR_PRODUCT_HERE ) { 2799760dcaeSOliver Ruiz Dorantes YOUR_SPECIAL_FLAGS_HERE 2809760dcaeSOliver Ruiz Dorantes } 2819760dcaeSOliver Ruiz Dorantes */ 2829760dcaeSOliver Ruiz Dorantes 2839760dcaeSOliver Ruiz Dorantes if (new_bt_dev->driver_info & BT_IGNORE_THIS_DEVICE) { 2849760dcaeSOliver Ruiz Dorantes err = ENODEV; 2859760dcaeSOliver Ruiz Dorantes goto bail; 2869760dcaeSOliver Ruiz Dorantes } 2879760dcaeSOliver Ruiz Dorantes 2889760dcaeSOliver Ruiz Dorantes // security check 2899760dcaeSOliver Ruiz Dorantes if (config->interface->active->descr->interface_number > 0) { 2901f2fa6cdSAlexander von Gluck IV ERROR("%s: Strange condition happened %d\n", __func__, 2919760dcaeSOliver Ruiz Dorantes config->interface->active->descr->interface_number); 2929760dcaeSOliver Ruiz Dorantes err = B_ERROR; 2939760dcaeSOliver Ruiz Dorantes goto bail; 2949760dcaeSOliver Ruiz Dorantes } 2959760dcaeSOliver Ruiz Dorantes 2961f2fa6cdSAlexander von Gluck IV TRACE("%s: Found %" B_PRIuSIZE " interfaces. Expected 3\n", __func__, 297f2986394SAlexander von Gluck IV config->interface_count); 298f2986394SAlexander von Gluck IV 2999760dcaeSOliver Ruiz Dorantes // Find endpoints that we need 3009760dcaeSOliver Ruiz Dorantes uif = config->interface->active; 3019760dcaeSOliver Ruiz Dorantes for (e = 0; e < uif->descr->num_endpoints; e++) { 3029760dcaeSOliver Ruiz Dorantes 3039760dcaeSOliver Ruiz Dorantes ep = &uif->endpoint[e]; 3049760dcaeSOliver Ruiz Dorantes switch (ep->descr->attributes & USB_ENDPOINT_ATTR_MASK) { 3059760dcaeSOliver Ruiz Dorantes case USB_ENDPOINT_ATTR_INTERRUPT: 3069760dcaeSOliver Ruiz Dorantes if (ep->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) 3079760dcaeSOliver Ruiz Dorantes { 3089760dcaeSOliver Ruiz Dorantes new_bt_dev->intr_in_ep = ep; 3091f2fa6cdSAlexander von Gluck IV new_bt_dev->max_packet_size_intr_in 3101f2fa6cdSAlexander von Gluck IV = ep->descr->max_packet_size; 3111f2fa6cdSAlexander von Gluck IV TRACE("%s: INT in\n", __func__); 3129760dcaeSOliver Ruiz Dorantes } else { 3131f2fa6cdSAlexander von Gluck IV TRACE("%s: INT out\n", __func__); 3149760dcaeSOliver Ruiz Dorantes } 3159760dcaeSOliver Ruiz Dorantes break; 3169760dcaeSOliver Ruiz Dorantes 3179760dcaeSOliver Ruiz Dorantes case USB_ENDPOINT_ATTR_BULK: 3189760dcaeSOliver Ruiz Dorantes if (ep->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) { 3199760dcaeSOliver Ruiz Dorantes new_bt_dev->bulk_in_ep = ep; 3201f2fa6cdSAlexander von Gluck IV new_bt_dev->max_packet_size_bulk_in 3211f2fa6cdSAlexander von Gluck IV = ep->descr->max_packet_size; 3221f2fa6cdSAlexander von Gluck IV TRACE("%s: BULK int\n", __func__); 3239760dcaeSOliver Ruiz Dorantes } else { 3249760dcaeSOliver Ruiz Dorantes new_bt_dev->bulk_out_ep = ep; 3251f2fa6cdSAlexander von Gluck IV new_bt_dev->max_packet_size_bulk_out 3261f2fa6cdSAlexander von Gluck IV = ep->descr->max_packet_size; 3271f2fa6cdSAlexander von Gluck IV TRACE("%s: BULK out\n", __func__); 3289760dcaeSOliver Ruiz Dorantes } 3299760dcaeSOliver Ruiz Dorantes break; 3309760dcaeSOliver Ruiz Dorantes } 3319760dcaeSOliver Ruiz Dorantes } 3329760dcaeSOliver Ruiz Dorantes 3339760dcaeSOliver Ruiz Dorantes if (!new_bt_dev->bulk_in_ep || !new_bt_dev->bulk_out_ep 3349760dcaeSOliver Ruiz Dorantes || !new_bt_dev->intr_in_ep) { 3351f2fa6cdSAlexander von Gluck IV ERROR("%s: Minimal # endpoints for BT not found\n", __func__); 3369760dcaeSOliver Ruiz Dorantes goto bail; 3379760dcaeSOliver Ruiz Dorantes } 3389760dcaeSOliver Ruiz Dorantes 3399760dcaeSOliver Ruiz Dorantes // Look into the devices suported to understand this 3409760dcaeSOliver Ruiz Dorantes if (new_bt_dev->driver_info & BT_DIGIANSWER) 3419760dcaeSOliver Ruiz Dorantes new_bt_dev->ctrl_req = USB_TYPE_VENDOR; 3429760dcaeSOliver Ruiz Dorantes else 3439760dcaeSOliver Ruiz Dorantes new_bt_dev->ctrl_req = USB_TYPE_CLASS; 3449760dcaeSOliver Ruiz Dorantes 3459760dcaeSOliver Ruiz Dorantes new_bt_dev->connected = true; 3469760dcaeSOliver Ruiz Dorantes 3479760dcaeSOliver Ruiz Dorantes // set the cookie that will be passed to other USB 3489760dcaeSOliver Ruiz Dorantes // hook functions (currently device_removed() is the only other) 3499760dcaeSOliver Ruiz Dorantes *cookie = new_bt_dev; 3501f2fa6cdSAlexander von Gluck IV TRACE("%s: Ok %p\n", __func__, new_bt_dev); 3519760dcaeSOliver Ruiz Dorantes return B_OK; 3529760dcaeSOliver Ruiz Dorantes 3539760dcaeSOliver Ruiz Dorantes bail: 3549760dcaeSOliver Ruiz Dorantes kill_device(new_bt_dev); 3559760dcaeSOliver Ruiz Dorantes bail_no_mem: 3569760dcaeSOliver Ruiz Dorantes *cookie = NULL; 3579760dcaeSOliver Ruiz Dorantes 3589760dcaeSOliver Ruiz Dorantes return err; 3599760dcaeSOliver Ruiz Dorantes } 3609760dcaeSOliver Ruiz Dorantes 3619760dcaeSOliver Ruiz Dorantes 3629760dcaeSOliver Ruiz Dorantes // Called by USB Manager when device is removed from the USB 3639760dcaeSOliver Ruiz Dorantes static status_t 3649760dcaeSOliver Ruiz Dorantes device_removed(void* cookie) 3659760dcaeSOliver Ruiz Dorantes { 3669760dcaeSOliver Ruiz Dorantes bt_usb_dev* bdev = fetch_device((bt_usb_dev*)cookie, 0); 3679760dcaeSOliver Ruiz Dorantes 3681f2fa6cdSAlexander von Gluck IV TRACE("%s: device_removed(%p)\n", __func__, bdev); 3699760dcaeSOliver Ruiz Dorantes 3709760dcaeSOliver Ruiz Dorantes if (bdev == NULL) { 3711f2fa6cdSAlexander von Gluck IV ERROR("%s: Device not present in driver.\n", __func__); 3729760dcaeSOliver Ruiz Dorantes return B_ERROR; 3739760dcaeSOliver Ruiz Dorantes } 3749760dcaeSOliver Ruiz Dorantes 3759760dcaeSOliver Ruiz Dorantes if (!TEST_AND_CLEAR(&bdev->state, RUNNING)) 3761f2fa6cdSAlexander von Gluck IV ERROR("%s: wasnt running?\n", __func__); 3779760dcaeSOliver Ruiz Dorantes 3781f2fa6cdSAlexander von Gluck IV TRACE("%s: Cancelling queues...\n", __func__); 3791f2fa6cdSAlexander von Gluck IV if (bdev->intr_in_ep != NULL) 3809760dcaeSOliver Ruiz Dorantes usb->cancel_queued_transfers(bdev->intr_in_ep->handle); 3811f2fa6cdSAlexander von Gluck IV if (bdev->bulk_in_ep != NULL) 3829760dcaeSOliver Ruiz Dorantes usb->cancel_queued_transfers(bdev->bulk_in_ep->handle); 3831f2fa6cdSAlexander von Gluck IV if (bdev->bulk_out_ep != NULL) 3849760dcaeSOliver Ruiz Dorantes usb->cancel_queued_transfers(bdev->bulk_out_ep->handle); 3859760dcaeSOliver Ruiz Dorantes 3869760dcaeSOliver Ruiz Dorantes bdev->connected = false; 3879760dcaeSOliver Ruiz Dorantes 3889760dcaeSOliver Ruiz Dorantes return B_OK; 3899760dcaeSOliver Ruiz Dorantes } 3909760dcaeSOliver Ruiz Dorantes 3919760dcaeSOliver Ruiz Dorantes 3929760dcaeSOliver Ruiz Dorantes static bt_hci_transport_hooks bluetooth_hooks = { 3939760dcaeSOliver Ruiz Dorantes NULL, 3949760dcaeSOliver Ruiz Dorantes &submit_nbuffer, 3959760dcaeSOliver Ruiz Dorantes &submit_nbuffer, 3969760dcaeSOliver Ruiz Dorantes NULL, 3979760dcaeSOliver Ruiz Dorantes NULL, 3989760dcaeSOliver Ruiz Dorantes H2 3999760dcaeSOliver Ruiz Dorantes }; 4009760dcaeSOliver Ruiz Dorantes 4019760dcaeSOliver Ruiz Dorantes 4029760dcaeSOliver Ruiz Dorantes static usb_notify_hooks notify_hooks = { 4039760dcaeSOliver Ruiz Dorantes &device_added, 4049760dcaeSOliver Ruiz Dorantes &device_removed 4059760dcaeSOliver Ruiz Dorantes }; 4069760dcaeSOliver Ruiz Dorantes 4079760dcaeSOliver Ruiz Dorantes #if 0 4089760dcaeSOliver Ruiz Dorantes #pragma mark - 4099760dcaeSOliver Ruiz Dorantes #endif 4109760dcaeSOliver Ruiz Dorantes 4119760dcaeSOliver Ruiz Dorantes status_t 4129760dcaeSOliver Ruiz Dorantes submit_nbuffer(hci_id hid, net_buffer* nbuf) 4139760dcaeSOliver Ruiz Dorantes { 4149760dcaeSOliver Ruiz Dorantes bt_usb_dev* bdev = NULL; 4159760dcaeSOliver Ruiz Dorantes 4169760dcaeSOliver Ruiz Dorantes bdev = fetch_device(NULL, hid); 4179760dcaeSOliver Ruiz Dorantes 4181f2fa6cdSAlexander von Gluck IV TRACE("%s: index=%" B_PRId32 " nbuf=%p bdev=%p\n", __func__, hid, 4191f2fa6cdSAlexander von Gluck IV nbuf, bdev); 4209760dcaeSOliver Ruiz Dorantes 4219760dcaeSOliver Ruiz Dorantes if (bdev != NULL) { 4229760dcaeSOliver Ruiz Dorantes switch (nbuf->protocol) { 4239760dcaeSOliver Ruiz Dorantes case BT_COMMAND: 4249760dcaeSOliver Ruiz Dorantes // not issued this way 4259760dcaeSOliver Ruiz Dorantes break; 4269760dcaeSOliver Ruiz Dorantes 4279760dcaeSOliver Ruiz Dorantes case BT_ACL: 4289760dcaeSOliver Ruiz Dorantes return submit_tx_acl(bdev, nbuf); 4299760dcaeSOliver Ruiz Dorantes break; 4309760dcaeSOliver Ruiz Dorantes 4319760dcaeSOliver Ruiz Dorantes default: 4329760dcaeSOliver Ruiz Dorantes panic("submit_nbuffer: no protocol"); 4339760dcaeSOliver Ruiz Dorantes break; 4349760dcaeSOliver Ruiz Dorantes 4359760dcaeSOliver Ruiz Dorantes } 4369760dcaeSOliver Ruiz Dorantes } 4379760dcaeSOliver Ruiz Dorantes 4389760dcaeSOliver Ruiz Dorantes return B_ERROR; 4399760dcaeSOliver Ruiz Dorantes 4409760dcaeSOliver Ruiz Dorantes } 4419760dcaeSOliver Ruiz Dorantes 4429760dcaeSOliver Ruiz Dorantes 4439760dcaeSOliver Ruiz Dorantes // implements the POSIX open() 4449760dcaeSOliver Ruiz Dorantes static status_t 4459760dcaeSOliver Ruiz Dorantes device_open(const char* name, uint32 flags, void **cookie) 4469760dcaeSOliver Ruiz Dorantes { 4471f2fa6cdSAlexander von Gluck IV CALLED(); 4481f2fa6cdSAlexander von Gluck IV 4499760dcaeSOliver Ruiz Dorantes status_t err = ENODEV; 4509760dcaeSOliver Ruiz Dorantes bt_usb_dev* bdev = NULL; 4519760dcaeSOliver Ruiz Dorantes hci_id hdev; 4529760dcaeSOliver Ruiz Dorantes int i; 4539760dcaeSOliver Ruiz Dorantes 4549760dcaeSOliver Ruiz Dorantes acquire_sem(dev_table_sem); 4559760dcaeSOliver Ruiz Dorantes for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { 4569760dcaeSOliver Ruiz Dorantes if (bt_usb_devices[i] && !strcmp(name, bt_usb_devices[i]->name)) { 4579760dcaeSOliver Ruiz Dorantes bdev = bt_usb_devices[i]; 4589760dcaeSOliver Ruiz Dorantes break; 4599760dcaeSOliver Ruiz Dorantes } 4609760dcaeSOliver Ruiz Dorantes } 4619760dcaeSOliver Ruiz Dorantes release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); 4629760dcaeSOliver Ruiz Dorantes 4639760dcaeSOliver Ruiz Dorantes if (bdev == NULL) { 4641f2fa6cdSAlexander von Gluck IV ERROR("%s: Device not found in the open list!", __func__); 4659760dcaeSOliver Ruiz Dorantes *cookie = NULL; 4669760dcaeSOliver Ruiz Dorantes return B_ERROR; 4679760dcaeSOliver Ruiz Dorantes } 4689760dcaeSOliver Ruiz Dorantes 4699760dcaeSOliver Ruiz Dorantes // Set RUNNING 4709760dcaeSOliver Ruiz Dorantes if (TEST_AND_SET(&bdev->state, RUNNING)) { 4711f2fa6cdSAlexander von Gluck IV ERROR("%s: dev already running! - reOpened device!\n", __func__); 4729760dcaeSOliver Ruiz Dorantes return B_ERROR; 4739760dcaeSOliver Ruiz Dorantes } 4749760dcaeSOliver Ruiz Dorantes 4759760dcaeSOliver Ruiz Dorantes acquire_sem(bdev->lock); 4769760dcaeSOliver Ruiz Dorantes // TX structures 4779760dcaeSOliver Ruiz Dorantes for (i = 0; i < BT_DRIVER_TXCOVERAGE; i++) { 4789760dcaeSOliver Ruiz Dorantes list_init(&bdev->nbuffersTx[i]); 4799760dcaeSOliver Ruiz Dorantes bdev->nbuffersPendingTx[i] = 0; 4809760dcaeSOliver Ruiz Dorantes } 4819760dcaeSOliver Ruiz Dorantes 4829760dcaeSOliver Ruiz Dorantes // RX structures 4839760dcaeSOliver Ruiz Dorantes bdev->eventRx = NULL; 4849760dcaeSOliver Ruiz Dorantes for (i = 0; i < BT_DRIVER_RXCOVERAGE; i++) { 4859760dcaeSOliver Ruiz Dorantes bdev->nbufferRx[i] = NULL; 4869760dcaeSOliver Ruiz Dorantes } 4879760dcaeSOliver Ruiz Dorantes 4889760dcaeSOliver Ruiz Dorantes // dumping the USB frames 4899760dcaeSOliver Ruiz Dorantes init_room(&bdev->eventRoom); 4909760dcaeSOliver Ruiz Dorantes init_room(&bdev->aclRoom); 4919760dcaeSOliver Ruiz Dorantes // init_room(new_bt_dev->scoRoom); 4929760dcaeSOliver Ruiz Dorantes 4939760dcaeSOliver Ruiz Dorantes list_init(&bdev->snetBufferRecycleTrash); 4949760dcaeSOliver Ruiz Dorantes 4959760dcaeSOliver Ruiz Dorantes // Allocate set and register the HCI device 4969760dcaeSOliver Ruiz Dorantes if (btDevices != NULL) { 4979760dcaeSOliver Ruiz Dorantes bluetooth_device* ndev; 4989760dcaeSOliver Ruiz Dorantes // TODO: Fill the transport descriptor 4999760dcaeSOliver Ruiz Dorantes err = btDevices->RegisterDriver(&bluetooth_hooks, &ndev); 5009760dcaeSOliver Ruiz Dorantes 5019760dcaeSOliver Ruiz Dorantes if (err == B_OK) { 5029760dcaeSOliver Ruiz Dorantes bdev->hdev = hdev = ndev->index; // Get the index 5039760dcaeSOliver Ruiz Dorantes bdev->ndev = ndev; // Get the net_device 5049760dcaeSOliver Ruiz Dorantes 5059760dcaeSOliver Ruiz Dorantes } else { 5069760dcaeSOliver Ruiz Dorantes hdev = bdev->num; // XXX: Lets try to go on 5079760dcaeSOliver Ruiz Dorantes } 5089760dcaeSOliver Ruiz Dorantes } else { 5099760dcaeSOliver Ruiz Dorantes hdev = bdev->num; // XXX: Lets try to go on 5109760dcaeSOliver Ruiz Dorantes } 5119760dcaeSOliver Ruiz Dorantes 5129760dcaeSOliver Ruiz Dorantes bdev->hdev = hdev; 5139760dcaeSOliver Ruiz Dorantes 5149760dcaeSOliver Ruiz Dorantes *cookie = bdev; 5159760dcaeSOliver Ruiz Dorantes release_sem(bdev->lock); 5169760dcaeSOliver Ruiz Dorantes 5179760dcaeSOliver Ruiz Dorantes return B_OK; 5189760dcaeSOliver Ruiz Dorantes 5199760dcaeSOliver Ruiz Dorantes } 5209760dcaeSOliver Ruiz Dorantes 5219760dcaeSOliver Ruiz Dorantes 5229760dcaeSOliver Ruiz Dorantes /* called when a client calls POSIX close() on the driver, but I/O 5239760dcaeSOliver Ruiz Dorantes * requests may still be pending 5249760dcaeSOliver Ruiz Dorantes */ 5259760dcaeSOliver Ruiz Dorantes static status_t 5269760dcaeSOliver Ruiz Dorantes device_close(void* cookie) 5279760dcaeSOliver Ruiz Dorantes { 5281f2fa6cdSAlexander von Gluck IV CALLED(); 5291f2fa6cdSAlexander von Gluck IV 5309760dcaeSOliver Ruiz Dorantes int32 i; 5319760dcaeSOliver Ruiz Dorantes void* item; 5329760dcaeSOliver Ruiz Dorantes bt_usb_dev* bdev = (bt_usb_dev*)cookie; 5339760dcaeSOliver Ruiz Dorantes 5349760dcaeSOliver Ruiz Dorantes if (bdev == NULL) 5359760dcaeSOliver Ruiz Dorantes panic("bad cookie"); 5369760dcaeSOliver Ruiz Dorantes 5379760dcaeSOliver Ruiz Dorantes // Clean queues 5389760dcaeSOliver Ruiz Dorantes 5399760dcaeSOliver Ruiz Dorantes if (bdev->connected == true) { 5401f2fa6cdSAlexander von Gluck IV TRACE("%s: Cancelling queues...\n", __func__); 5411f2fa6cdSAlexander von Gluck IV 5421f2fa6cdSAlexander von Gluck IV if (bdev->intr_in_ep != NULL) 5439760dcaeSOliver Ruiz Dorantes usb->cancel_queued_transfers(bdev->intr_in_ep->handle); 5449760dcaeSOliver Ruiz Dorantes 5451f2fa6cdSAlexander von Gluck IV if (bdev->bulk_in_ep!=NULL) 5469760dcaeSOliver Ruiz Dorantes usb->cancel_queued_transfers(bdev->bulk_in_ep->handle); 5479760dcaeSOliver Ruiz Dorantes 5481f2fa6cdSAlexander von Gluck IV if (bdev->bulk_out_ep!=NULL) 5499760dcaeSOliver Ruiz Dorantes usb->cancel_queued_transfers(bdev->bulk_out_ep->handle); 5509760dcaeSOliver Ruiz Dorantes } 5519760dcaeSOliver Ruiz Dorantes 5529760dcaeSOliver Ruiz Dorantes // TX 5539760dcaeSOliver Ruiz Dorantes for (i = 0; i < BT_DRIVER_TXCOVERAGE; i++) { 554f2986394SAlexander von Gluck IV if (i == BT_COMMAND) { 555f2986394SAlexander von Gluck IV while ((item = list_remove_head_item(&bdev->nbuffersTx[i])) != NULL) 5569760dcaeSOliver Ruiz Dorantes snb_free((snet_buffer*)item); 557f2986394SAlexander von Gluck IV } else { 558f2986394SAlexander von Gluck IV while ((item = list_remove_head_item(&bdev->nbuffersTx[i])) != NULL) 5599760dcaeSOliver Ruiz Dorantes nb_destroy((net_buffer*)item); 5609760dcaeSOliver Ruiz Dorantes } 5619760dcaeSOliver Ruiz Dorantes } 5629760dcaeSOliver Ruiz Dorantes // RX 5639760dcaeSOliver Ruiz Dorantes for (i = 0; i < BT_DRIVER_RXCOVERAGE; i++) { 5649760dcaeSOliver Ruiz Dorantes nb_destroy(bdev->nbufferRx[i]); 5659760dcaeSOliver Ruiz Dorantes } 5669760dcaeSOliver Ruiz Dorantes snb_free(bdev->eventRx); 5679760dcaeSOliver Ruiz Dorantes 5689760dcaeSOliver Ruiz Dorantes purge_room(&bdev->eventRoom); 5699760dcaeSOliver Ruiz Dorantes purge_room(&bdev->aclRoom); 5709760dcaeSOliver Ruiz Dorantes 5719760dcaeSOliver Ruiz Dorantes // Device no longer in our Stack 5729760dcaeSOliver Ruiz Dorantes if (btDevices != NULL) 5739760dcaeSOliver Ruiz Dorantes btDevices->UnregisterDriver(bdev->hdev); 5749760dcaeSOliver Ruiz Dorantes 5759760dcaeSOliver Ruiz Dorantes // unSet RUNNING 5769760dcaeSOliver Ruiz Dorantes if (TEST_AND_CLEAR(&bdev->state, RUNNING)) { 5771f2fa6cdSAlexander von Gluck IV ERROR("%s: %s not running?\n", __func__, bdev->name); 5789760dcaeSOliver Ruiz Dorantes return B_ERROR; 5799760dcaeSOliver Ruiz Dorantes } 5809760dcaeSOliver Ruiz Dorantes 5819760dcaeSOliver Ruiz Dorantes return B_OK; 5829760dcaeSOliver Ruiz Dorantes } 5839760dcaeSOliver Ruiz Dorantes 5849760dcaeSOliver Ruiz Dorantes 5859760dcaeSOliver Ruiz Dorantes // Called after device_close(), when all pending I / O requests have returned 5869760dcaeSOliver Ruiz Dorantes static status_t 5879760dcaeSOliver Ruiz Dorantes device_free(void* cookie) 5889760dcaeSOliver Ruiz Dorantes { 5891f2fa6cdSAlexander von Gluck IV CALLED(); 5901f2fa6cdSAlexander von Gluck IV 5919760dcaeSOliver Ruiz Dorantes status_t err = B_OK; 5929760dcaeSOliver Ruiz Dorantes bt_usb_dev* bdev = (bt_usb_dev*)cookie; 5939760dcaeSOliver Ruiz Dorantes 5941f2fa6cdSAlexander von Gluck IV if (!bdev->connected) 5959760dcaeSOliver Ruiz Dorantes kill_device(bdev); 5969760dcaeSOliver Ruiz Dorantes 5979760dcaeSOliver Ruiz Dorantes return err; 5989760dcaeSOliver Ruiz Dorantes } 5999760dcaeSOliver Ruiz Dorantes 6009760dcaeSOliver Ruiz Dorantes 6019760dcaeSOliver Ruiz Dorantes // implements the POSIX ioctl() 6029760dcaeSOliver Ruiz Dorantes static status_t 6039760dcaeSOliver Ruiz Dorantes device_control(void* cookie, uint32 msg, void* params, size_t size) 6049760dcaeSOliver Ruiz Dorantes { 6059760dcaeSOliver Ruiz Dorantes status_t err = B_ERROR; 6069760dcaeSOliver Ruiz Dorantes bt_usb_dev* bdev = (bt_usb_dev*)cookie; 6079760dcaeSOliver Ruiz Dorantes snet_buffer* snbuf; 6089760dcaeSOliver Ruiz Dorantes #if BT_DRIVER_SUPPORTS_ACL // ACL 6099760dcaeSOliver Ruiz Dorantes int32 i; 6109760dcaeSOliver Ruiz Dorantes #endif 6119760dcaeSOliver Ruiz Dorantes 6129760dcaeSOliver Ruiz Dorantes TOUCH(size); 6131f2fa6cdSAlexander von Gluck IV TRACE("%s: ioctl() opcode %" B_PRId32 " size %" B_PRIuSIZE ".\n", __func__, 6141f2fa6cdSAlexander von Gluck IV msg, size); 6159760dcaeSOliver Ruiz Dorantes 6169760dcaeSOliver Ruiz Dorantes if (bdev == NULL) { 6171f2fa6cdSAlexander von Gluck IV TRACE("%s: Bad cookie\n", __func__); 6189760dcaeSOliver Ruiz Dorantes return B_BAD_VALUE; 6199760dcaeSOliver Ruiz Dorantes } 6209760dcaeSOliver Ruiz Dorantes 6219760dcaeSOliver Ruiz Dorantes if (params == NULL) { 6221f2fa6cdSAlexander von Gluck IV TRACE("%s: Invalid pointer control\n", __func__); 6239760dcaeSOliver Ruiz Dorantes return B_BAD_VALUE; 6249760dcaeSOliver Ruiz Dorantes } 6259760dcaeSOliver Ruiz Dorantes 6269760dcaeSOliver Ruiz Dorantes acquire_sem(bdev->lock); 6279760dcaeSOliver Ruiz Dorantes 6289760dcaeSOliver Ruiz Dorantes switch (msg) { 6299760dcaeSOliver Ruiz Dorantes case ISSUE_BT_COMMAND: 6309760dcaeSOliver Ruiz Dorantes #ifdef BT_IOCTLS_PASS_SIZE 6319760dcaeSOliver Ruiz Dorantes if (size == 0) { 6321f2fa6cdSAlexander von Gluck IV TRACE("%s: Invalid size control\n", __func__); 6339760dcaeSOliver Ruiz Dorantes err = B_BAD_VALUE; 6349760dcaeSOliver Ruiz Dorantes break; 6359760dcaeSOliver Ruiz Dorantes } 6369760dcaeSOliver Ruiz Dorantes #else 6379760dcaeSOliver Ruiz Dorantes size = (*((size_t*)params)); 6389760dcaeSOliver Ruiz Dorantes (*(size_t**)¶ms)++; 6399760dcaeSOliver Ruiz Dorantes #endif 6409760dcaeSOliver Ruiz Dorantes 6419760dcaeSOliver Ruiz Dorantes // TODO: Reuse from some TXcompleted queue 6429760dcaeSOliver Ruiz Dorantes // snbuf = snb_create(size); 6439760dcaeSOliver Ruiz Dorantes snbuf = snb_fetch(&bdev->snetBufferRecycleTrash, size); 6449760dcaeSOliver Ruiz Dorantes snb_put(snbuf, params, size); 6459760dcaeSOliver Ruiz Dorantes 6469760dcaeSOliver Ruiz Dorantes err = submit_tx_command(bdev, snbuf); 6471f2fa6cdSAlexander von Gluck IV TRACE("%s: command launched\n", __func__); 6489760dcaeSOliver Ruiz Dorantes break; 6499760dcaeSOliver Ruiz Dorantes 6509760dcaeSOliver Ruiz Dorantes case BT_UP: 6519760dcaeSOliver Ruiz Dorantes 6529760dcaeSOliver Ruiz Dorantes // EVENTS 6539760dcaeSOliver Ruiz Dorantes err = submit_rx_event(bdev); 6549760dcaeSOliver Ruiz Dorantes if (err != B_OK) { 655a12bde1cSAdrien Destugues bdev->state = CLEAR_BIT(bdev->state, ANCILLYANT); 6561f2fa6cdSAlexander von Gluck IV ERROR("%s: Queuing failed device stops running\n", __func__); 6579760dcaeSOliver Ruiz Dorantes break; 6589760dcaeSOliver Ruiz Dorantes } 6599760dcaeSOliver Ruiz Dorantes 6609760dcaeSOliver Ruiz Dorantes #if BT_DRIVER_SUPPORTS_ACL // ACL 6619760dcaeSOliver Ruiz Dorantes for (i = 0; i < MAX_ACL_IN_WINDOW; i++) { 6629760dcaeSOliver Ruiz Dorantes err = submit_rx_acl(bdev); 6639760dcaeSOliver Ruiz Dorantes if (err != B_OK && i == 0) { 664a12bde1cSAdrien Destugues bdev->state = CLEAR_BIT(bdev->state, ANCILLYANT); 665a12bde1cSAdrien Destugues // Set the flaq in the HCI world 6661f2fa6cdSAlexander von Gluck IV ERROR("%s: Queuing failed device stops running\n", 6671f2fa6cdSAlexander von Gluck IV __func__); 6689760dcaeSOliver Ruiz Dorantes break; 6699760dcaeSOliver Ruiz Dorantes } 6709760dcaeSOliver Ruiz Dorantes } 6719760dcaeSOliver Ruiz Dorantes #endif 6729760dcaeSOliver Ruiz Dorantes 673a12bde1cSAdrien Destugues bdev->state = SET_BIT(bdev->state, RUNNING); 6749760dcaeSOliver Ruiz Dorantes 6759760dcaeSOliver Ruiz Dorantes #if BT_DRIVER_SUPPORTS_SCO 6769760dcaeSOliver Ruiz Dorantes // TODO: SCO / eSCO 6779760dcaeSOliver Ruiz Dorantes #endif 6781f2fa6cdSAlexander von Gluck IV 6791f2fa6cdSAlexander von Gluck IV ERROR("%s: Device online\n", __func__); 6809760dcaeSOliver Ruiz Dorantes break; 6819760dcaeSOliver Ruiz Dorantes 6829760dcaeSOliver Ruiz Dorantes case GET_STATS: 6839760dcaeSOliver Ruiz Dorantes memcpy(params, &bdev->stat, sizeof(bt_hci_statistics)); 6849760dcaeSOliver Ruiz Dorantes err = B_OK; 6859760dcaeSOliver Ruiz Dorantes break; 6869760dcaeSOliver Ruiz Dorantes 6879760dcaeSOliver Ruiz Dorantes case GET_HCI_ID: 6889760dcaeSOliver Ruiz Dorantes *(hci_id*)params = bdev->hdev; 6899760dcaeSOliver Ruiz Dorantes err = B_OK; 6909760dcaeSOliver Ruiz Dorantes break; 6919760dcaeSOliver Ruiz Dorantes 6929760dcaeSOliver Ruiz Dorantes 6939760dcaeSOliver Ruiz Dorantes default: 6941f2fa6cdSAlexander von Gluck IV ERROR("%s: Invalid opcode.\n", __func__); 6959760dcaeSOliver Ruiz Dorantes err = B_DEV_INVALID_IOCTL; 6969760dcaeSOliver Ruiz Dorantes break; 6979760dcaeSOliver Ruiz Dorantes } 6989760dcaeSOliver Ruiz Dorantes 6999760dcaeSOliver Ruiz Dorantes release_sem(bdev->lock); 7009760dcaeSOliver Ruiz Dorantes return err; 7019760dcaeSOliver Ruiz Dorantes } 7029760dcaeSOliver Ruiz Dorantes 7039760dcaeSOliver Ruiz Dorantes 7049760dcaeSOliver Ruiz Dorantes // implements the POSIX read() 7059760dcaeSOliver Ruiz Dorantes static status_t 7069760dcaeSOliver Ruiz Dorantes device_read(void* cookie, off_t pos, void* buffer, size_t* count) 7079760dcaeSOliver Ruiz Dorantes { 7081f2fa6cdSAlexander von Gluck IV TRACE("%s: Reading... count = %" B_PRIuSIZE "\n", __func__, *count); 7099760dcaeSOliver Ruiz Dorantes 7109760dcaeSOliver Ruiz Dorantes *count = 0; 7119760dcaeSOliver Ruiz Dorantes return B_OK; 7129760dcaeSOliver Ruiz Dorantes } 7139760dcaeSOliver Ruiz Dorantes 7149760dcaeSOliver Ruiz Dorantes 7159760dcaeSOliver Ruiz Dorantes // implements the POSIX write() 7169760dcaeSOliver Ruiz Dorantes static status_t 7179760dcaeSOliver Ruiz Dorantes device_write(void* cookie, off_t pos, const void* buffer, size_t* count) 7189760dcaeSOliver Ruiz Dorantes { 7191f2fa6cdSAlexander von Gluck IV CALLED(); 7209760dcaeSOliver Ruiz Dorantes 7219760dcaeSOliver Ruiz Dorantes return B_ERROR; 7229760dcaeSOliver Ruiz Dorantes } 7239760dcaeSOliver Ruiz Dorantes 7249760dcaeSOliver Ruiz Dorantes 7259760dcaeSOliver Ruiz Dorantes #if 0 7269760dcaeSOliver Ruiz Dorantes #pragma mark - 7279760dcaeSOliver Ruiz Dorantes #endif 7289760dcaeSOliver Ruiz Dorantes 7299760dcaeSOliver Ruiz Dorantes 7309760dcaeSOliver Ruiz Dorantes static int 7319760dcaeSOliver Ruiz Dorantes dump_driver(int argc, char** argv) 7329760dcaeSOliver Ruiz Dorantes { 7339760dcaeSOliver Ruiz Dorantes int i; 7349760dcaeSOliver Ruiz Dorantes snet_buffer* item = NULL; 7359760dcaeSOliver Ruiz Dorantes 7369760dcaeSOliver Ruiz Dorantes for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { 7379760dcaeSOliver Ruiz Dorantes 7389760dcaeSOliver Ruiz Dorantes if (bt_usb_devices[i] != NULL) { 7399760dcaeSOliver Ruiz Dorantes kprintf("%s : \n", bt_usb_devices[i]->name); 7409760dcaeSOliver Ruiz Dorantes kprintf("\taclroom = %d\teventroom = %d\tcommand & events =%d\n", 7419760dcaeSOliver Ruiz Dorantes snb_packets(&bt_usb_devices[i]->eventRoom), 7429760dcaeSOliver Ruiz Dorantes snb_packets(&bt_usb_devices[i]->aclRoom), 7439760dcaeSOliver Ruiz Dorantes snb_packets(&bt_usb_devices[i]->snetBufferRecycleTrash)); 7449760dcaeSOliver Ruiz Dorantes 7459760dcaeSOliver Ruiz Dorantes while ((item = (snet_buffer*)list_get_next_item( 7469760dcaeSOliver Ruiz Dorantes &bt_usb_devices[i]->snetBufferRecycleTrash, item)) != NULL) 7479760dcaeSOliver Ruiz Dorantes snb_dump(item); 7489760dcaeSOliver Ruiz Dorantes } 7499760dcaeSOliver Ruiz Dorantes } 7509760dcaeSOliver Ruiz Dorantes 7519760dcaeSOliver Ruiz Dorantes return 0; 7529760dcaeSOliver Ruiz Dorantes } 7539760dcaeSOliver Ruiz Dorantes 7549760dcaeSOliver Ruiz Dorantes 7559760dcaeSOliver Ruiz Dorantes // called each time the driver is loaded by the kernel 7569760dcaeSOliver Ruiz Dorantes status_t 7579760dcaeSOliver Ruiz Dorantes init_driver(void) 7589760dcaeSOliver Ruiz Dorantes { 7591f2fa6cdSAlexander von Gluck IV CALLED(); 7609760dcaeSOliver Ruiz Dorantes int j; 7619760dcaeSOliver Ruiz Dorantes 762f2986394SAlexander von Gluck IV if (get_module(BT_CORE_DATA_MODULE_NAME, 763f2986394SAlexander von Gluck IV (module_info**)&btCoreData) != B_OK) { 7641f2fa6cdSAlexander von Gluck IV ERROR("%s: cannot get module '%s'\n", __func__, 7651f2fa6cdSAlexander von Gluck IV BT_CORE_DATA_MODULE_NAME); 7669760dcaeSOliver Ruiz Dorantes return B_ERROR; 7671f2fa6cdSAlexander von Gluck IV } 7689760dcaeSOliver Ruiz Dorantes 7699760dcaeSOliver Ruiz Dorantes // BT devices MODULE INITS 7709760dcaeSOliver Ruiz Dorantes if (get_module(btDevices_name, (module_info**)&btDevices) != B_OK) { 7711f2fa6cdSAlexander von Gluck IV ERROR("%s: cannot get module '%s'\n", __func__, btDevices_name); 7729760dcaeSOliver Ruiz Dorantes goto err_release3; 7731f2fa6cdSAlexander von Gluck IV } 7749760dcaeSOliver Ruiz Dorantes 7759760dcaeSOliver Ruiz Dorantes // HCI MODULE INITS 7769760dcaeSOliver Ruiz Dorantes if (get_module(hci_name, (module_info**)&hci) != B_OK) { 7771f2fa6cdSAlexander von Gluck IV ERROR("%s: cannot get module '%s'\n", __func__, hci_name); 7789760dcaeSOliver Ruiz Dorantes #ifndef BT_SURVIVE_WITHOUT_HCI 7799760dcaeSOliver Ruiz Dorantes goto err_release2; 7809760dcaeSOliver Ruiz Dorantes #endif 7819760dcaeSOliver Ruiz Dorantes } 7829760dcaeSOliver Ruiz Dorantes 7839760dcaeSOliver Ruiz Dorantes // USB MODULE INITS 7849760dcaeSOliver Ruiz Dorantes if (get_module(usb_name, (module_info**)&usb) != B_OK) { 7851f2fa6cdSAlexander von Gluck IV ERROR("%s: cannot get module '%s'\n", __func__, usb_name); 7869760dcaeSOliver Ruiz Dorantes goto err_release1; 7879760dcaeSOliver Ruiz Dorantes } 7889760dcaeSOliver Ruiz Dorantes 7899760dcaeSOliver Ruiz Dorantes if (get_module(NET_BUFFER_MODULE_NAME, (module_info**)&nb) != B_OK) { 7901f2fa6cdSAlexander von Gluck IV ERROR("%s: cannot get module '%s'\n", __func__, 7911f2fa6cdSAlexander von Gluck IV NET_BUFFER_MODULE_NAME); 7929760dcaeSOliver Ruiz Dorantes #ifndef BT_SURVIVE_WITHOUT_NET_BUFFERS 7939760dcaeSOliver Ruiz Dorantes goto err_release; 7949760dcaeSOliver Ruiz Dorantes #endif 7959760dcaeSOliver Ruiz Dorantes } 7969760dcaeSOliver Ruiz Dorantes 7979760dcaeSOliver Ruiz Dorantes // GENERAL INITS 7989760dcaeSOliver Ruiz Dorantes dev_table_sem = create_sem(1, BLUETOOTH_DEVICE_DEVFS_NAME "dev_table_lock"); 7999760dcaeSOliver Ruiz Dorantes if (dev_table_sem < 0) { 8009760dcaeSOliver Ruiz Dorantes goto err; 8019760dcaeSOliver Ruiz Dorantes } 8029760dcaeSOliver Ruiz Dorantes 8039760dcaeSOliver Ruiz Dorantes for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) { 8049760dcaeSOliver Ruiz Dorantes bt_usb_devices[j] = NULL; 8059760dcaeSOliver Ruiz Dorantes } 8069760dcaeSOliver Ruiz Dorantes 8079760dcaeSOliver Ruiz Dorantes // Note: After here device_added and publish devices hooks are called 8089760dcaeSOliver Ruiz Dorantes usb->register_driver(BLUETOOTH_DEVICE_DEVFS_NAME, supported_devices, 1, NULL); 8099760dcaeSOliver Ruiz Dorantes usb->install_notify(BLUETOOTH_DEVICE_DEVFS_NAME, ¬ify_hooks); 8109760dcaeSOliver Ruiz Dorantes 8119760dcaeSOliver Ruiz Dorantes add_debugger_command("bth2generic", &dump_driver, 8129760dcaeSOliver Ruiz Dorantes "Lists H2 Transport device info"); 8139760dcaeSOliver Ruiz Dorantes 8149760dcaeSOliver Ruiz Dorantes return B_OK; 8159760dcaeSOliver Ruiz Dorantes 8169760dcaeSOliver Ruiz Dorantes err: // Releasing 8179760dcaeSOliver Ruiz Dorantes put_module(NET_BUFFER_MODULE_NAME); 8189760dcaeSOliver Ruiz Dorantes err_release: 8199760dcaeSOliver Ruiz Dorantes put_module(usb_name); 8209760dcaeSOliver Ruiz Dorantes err_release1: 8219760dcaeSOliver Ruiz Dorantes put_module(hci_name); 8229760dcaeSOliver Ruiz Dorantes #ifndef BT_SURVIVE_WITHOUT_HCI 8239760dcaeSOliver Ruiz Dorantes err_release2: 8249760dcaeSOliver Ruiz Dorantes #endif 8259760dcaeSOliver Ruiz Dorantes put_module(btDevices_name); 8269760dcaeSOliver Ruiz Dorantes err_release3: 8279760dcaeSOliver Ruiz Dorantes put_module(BT_CORE_DATA_MODULE_NAME); 8289760dcaeSOliver Ruiz Dorantes 8299760dcaeSOliver Ruiz Dorantes return B_ERROR; 8309760dcaeSOliver Ruiz Dorantes } 8319760dcaeSOliver Ruiz Dorantes 8329760dcaeSOliver Ruiz Dorantes 8339760dcaeSOliver Ruiz Dorantes // called just before the kernel unloads the driver 8349760dcaeSOliver Ruiz Dorantes void 8359760dcaeSOliver Ruiz Dorantes uninit_driver(void) 8369760dcaeSOliver Ruiz Dorantes { 8371f2fa6cdSAlexander von Gluck IV CALLED(); 8389760dcaeSOliver Ruiz Dorantes 8391f2fa6cdSAlexander von Gluck IV int32 j; 8409760dcaeSOliver Ruiz Dorantes 8419760dcaeSOliver Ruiz Dorantes for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) { 8429760dcaeSOliver Ruiz Dorantes 8439760dcaeSOliver Ruiz Dorantes if (publish_names[j] != NULL) 8449760dcaeSOliver Ruiz Dorantes free(publish_names[j]); 8459760dcaeSOliver Ruiz Dorantes 8469760dcaeSOliver Ruiz Dorantes if (bt_usb_devices[j] != NULL) { 8479760dcaeSOliver Ruiz Dorantes // if (connected_dev != NULL) { 8489760dcaeSOliver Ruiz Dorantes // debugf("Device %p still exists.\n", connected_dev); 8499760dcaeSOliver Ruiz Dorantes // } 8501f2fa6cdSAlexander von Gluck IV ERROR("%s: %s still present?\n", __func__, bt_usb_devices[j]->name); 8519760dcaeSOliver Ruiz Dorantes kill_device(bt_usb_devices[j]); 8529760dcaeSOliver Ruiz Dorantes } 8539760dcaeSOliver Ruiz Dorantes } 8549760dcaeSOliver Ruiz Dorantes 8559760dcaeSOliver Ruiz Dorantes usb->uninstall_notify(BLUETOOTH_DEVICE_DEVFS_NAME); 8569760dcaeSOliver Ruiz Dorantes 8579760dcaeSOliver Ruiz Dorantes remove_debugger_command("bth2generic", &dump_driver); 8589760dcaeSOliver Ruiz Dorantes 8599760dcaeSOliver Ruiz Dorantes // Releasing modules 8609760dcaeSOliver Ruiz Dorantes put_module(usb_name); 8619760dcaeSOliver Ruiz Dorantes put_module(hci_name); 8629760dcaeSOliver Ruiz Dorantes // TODO: netbuffers 8639760dcaeSOliver Ruiz Dorantes 8649760dcaeSOliver Ruiz Dorantes delete_sem(dev_table_sem); 8659760dcaeSOliver Ruiz Dorantes } 8669760dcaeSOliver Ruiz Dorantes 8679760dcaeSOliver Ruiz Dorantes 8689760dcaeSOliver Ruiz Dorantes const char** 8699760dcaeSOliver Ruiz Dorantes publish_devices(void) 8709760dcaeSOliver Ruiz Dorantes { 8711f2fa6cdSAlexander von Gluck IV CALLED(); 8729760dcaeSOliver Ruiz Dorantes int32 j; 8739760dcaeSOliver Ruiz Dorantes int32 i = 0; 8749760dcaeSOliver Ruiz Dorantes 8759760dcaeSOliver Ruiz Dorantes char* str; 8769760dcaeSOliver Ruiz Dorantes 8779760dcaeSOliver Ruiz Dorantes for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) { 8789760dcaeSOliver Ruiz Dorantes if (publish_names[j]) { 8799760dcaeSOliver Ruiz Dorantes free(publish_names[j]); 8809760dcaeSOliver Ruiz Dorantes publish_names[j] = NULL; 8819760dcaeSOliver Ruiz Dorantes } 8829760dcaeSOliver Ruiz Dorantes } 8839760dcaeSOliver Ruiz Dorantes 8849760dcaeSOliver Ruiz Dorantes acquire_sem(dev_table_sem); 8859760dcaeSOliver Ruiz Dorantes for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) { 8869760dcaeSOliver Ruiz Dorantes if (bt_usb_devices[j] != NULL && bt_usb_devices[j]->connected) { 8879760dcaeSOliver Ruiz Dorantes str = strdup(bt_usb_devices[j]->name); 8889760dcaeSOliver Ruiz Dorantes if (str) { 8899760dcaeSOliver Ruiz Dorantes publish_names[i++] = str; 8901f2fa6cdSAlexander von Gluck IV TRACE("%s: publishing %s\n", __func__, bt_usb_devices[j]->name); 8919760dcaeSOliver Ruiz Dorantes } 8929760dcaeSOliver Ruiz Dorantes } 8939760dcaeSOliver Ruiz Dorantes } 8949760dcaeSOliver Ruiz Dorantes release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); 8959760dcaeSOliver Ruiz Dorantes 8969760dcaeSOliver Ruiz Dorantes publish_names[i] = NULL; 8971f2fa6cdSAlexander von Gluck IV TRACE("%s: published %" B_PRId32 " devices\n", __func__, i); 8989760dcaeSOliver Ruiz Dorantes 8999760dcaeSOliver Ruiz Dorantes // TODO: this method might make better memory use 9009760dcaeSOliver Ruiz Dorantes // dev_names = (char**)malloc(sizeof(char*) * (dev_count + 1)); 9019760dcaeSOliver Ruiz Dorantes // if (dev_names) { 9029760dcaeSOliver Ruiz Dorantes // for (i = 0; i < MAX_NUM_DEVS; i++) { 9039760dcaeSOliver Ruiz Dorantes // if ((dev != NULL) // dev + \n 9049760dcaeSOliver Ruiz Dorantes // && (dev_names[i] = (char*)malloc(strlen(DEVICE_PATH) + 2))) { 9059760dcaeSOliver Ruiz Dorantes // sprintf(dev_names[i], "%s%ld", DEVICE_PATH, dev->num); 9069760dcaeSOliver Ruiz Dorantes // debugf("publishing \"%s\"\n", dev_names[i]); 9079760dcaeSOliver Ruiz Dorantes // } 9089760dcaeSOliver Ruiz Dorantes // } 9099760dcaeSOliver Ruiz Dorantes 9109760dcaeSOliver Ruiz Dorantes return (const char**)publish_names; 9119760dcaeSOliver Ruiz Dorantes } 9129760dcaeSOliver Ruiz Dorantes 9139760dcaeSOliver Ruiz Dorantes 9149760dcaeSOliver Ruiz Dorantes static device_hooks hooks = { 9159760dcaeSOliver Ruiz Dorantes device_open, 9169760dcaeSOliver Ruiz Dorantes device_close, 9179760dcaeSOliver Ruiz Dorantes device_free, 9189760dcaeSOliver Ruiz Dorantes device_control, 9199760dcaeSOliver Ruiz Dorantes device_read, 9209760dcaeSOliver Ruiz Dorantes device_write, 9219760dcaeSOliver Ruiz Dorantes NULL, 9229760dcaeSOliver Ruiz Dorantes NULL, 9239760dcaeSOliver Ruiz Dorantes NULL, 9249760dcaeSOliver Ruiz Dorantes NULL 9259760dcaeSOliver Ruiz Dorantes }; 9269760dcaeSOliver Ruiz Dorantes 9279760dcaeSOliver Ruiz Dorantes 9289760dcaeSOliver Ruiz Dorantes device_hooks* 9299760dcaeSOliver Ruiz Dorantes find_device(const char* name) 9309760dcaeSOliver Ruiz Dorantes { 9311f2fa6cdSAlexander von Gluck IV CALLED(); 9329760dcaeSOliver Ruiz Dorantes 9339760dcaeSOliver Ruiz Dorantes return &hooks; 9349760dcaeSOliver Ruiz Dorantes } 935