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 705e11655SAlexander von Gluck IV 8e1e291b0SAlexander von Gluck IV #include "h2generic.h" 9e1e291b0SAlexander von Gluck IV 10a8f90110SAlexander von Gluck IV #include <kernel.h> 119760dcaeSOliver Ruiz Dorantes #include <malloc.h> 129760dcaeSOliver Ruiz Dorantes #include <stdio.h> 139760dcaeSOliver Ruiz Dorantes #include <string.h> 149760dcaeSOliver Ruiz Dorantes 159760dcaeSOliver Ruiz Dorantes #include <KernelExport.h> 169760dcaeSOliver Ruiz Dorantes #include <ByteOrder.h> 179760dcaeSOliver Ruiz Dorantes #include <Drivers.h> 189760dcaeSOliver Ruiz Dorantes 199760dcaeSOliver Ruiz Dorantes #include <btModules.h> 209760dcaeSOliver Ruiz Dorantes 2105e11655SAlexander von Gluck IV #include "snet_buffer.h" 2205e11655SAlexander von Gluck IV #include "h2cfg.h" 2305e11655SAlexander von Gluck IV #include "h2debug.h" 249760dcaeSOliver Ruiz Dorantes #include "h2transactions.h" 259760dcaeSOliver Ruiz Dorantes #include "h2util.h" 269760dcaeSOliver Ruiz Dorantes 271f2fa6cdSAlexander von Gluck IV 289760dcaeSOliver Ruiz Dorantes int32 api_version = B_CUR_DRIVER_API_VERSION; 299760dcaeSOliver Ruiz Dorantes 309760dcaeSOliver Ruiz Dorantes // Modules 310ea1aab2SOliver Tappe static const char* usb_name = B_USB_MODULE_NAME; 320ea1aab2SOliver Tappe static const char* hci_name = BT_HCI_MODULE_NAME; 330ea1aab2SOliver Tappe static const char* btDevices_name = BT_HCI_MODULE_NAME; 349760dcaeSOliver Ruiz Dorantes 359760dcaeSOliver Ruiz Dorantes 369760dcaeSOliver Ruiz Dorantes usb_module_info* usb = NULL; 379760dcaeSOliver Ruiz Dorantes bt_hci_module_info* hci = NULL; // TODO remove / clean 389760dcaeSOliver Ruiz Dorantes struct bt_hci_module_info* btDevices = NULL; 399760dcaeSOliver Ruiz Dorantes struct net_buffer_module_info* nb = NULL; 409760dcaeSOliver Ruiz Dorantes struct bluetooth_core_data_module_info* btCoreData = NULL; 419760dcaeSOliver Ruiz Dorantes 429760dcaeSOliver Ruiz Dorantes // Driver Global data 439760dcaeSOliver Ruiz Dorantes static char* publish_names[MAX_BT_GENERIC_USB_DEVICES]; 449760dcaeSOliver Ruiz Dorantes 459760dcaeSOliver Ruiz Dorantes int32 dev_count = 0; // number of connected devices 469760dcaeSOliver Ruiz Dorantes static bt_usb_dev* bt_usb_devices[MAX_BT_GENERIC_USB_DEVICES]; 479760dcaeSOliver Ruiz Dorantes sem_id dev_table_sem = -1; // sem to synchronize access to device table 489760dcaeSOliver Ruiz Dorantes 499760dcaeSOliver Ruiz Dorantes status_t submit_nbuffer(hci_id hid, net_buffer* nbuf); 509760dcaeSOliver Ruiz Dorantes 519760dcaeSOliver Ruiz Dorantes usb_support_descriptor supported_devices[] = { 529760dcaeSOliver Ruiz Dorantes // Generic Bluetooth USB device 539760dcaeSOliver Ruiz Dorantes // Class, SubClass, and Protocol codes that describe a Bluetooth device 549760dcaeSOliver Ruiz Dorantes { UDCLASS_WIRELESS, UDSUBCLASS_RF, UDPROTO_BLUETOOTH , 0 , 0 }, 559760dcaeSOliver Ruiz Dorantes 569760dcaeSOliver Ruiz Dorantes // Broadcom BCM2035 579760dcaeSOliver Ruiz Dorantes { 0, 0, 0, 0x0a5c, 0x200a }, 589760dcaeSOliver Ruiz Dorantes { 0, 0, 0, 0x0a5c, 0x2009 }, 599760dcaeSOliver Ruiz Dorantes 609760dcaeSOliver Ruiz Dorantes // Devices taken from the linux Driver 619760dcaeSOliver Ruiz Dorantes // AVM BlueFRITZ! USB v2.0 629760dcaeSOliver Ruiz Dorantes { 0, 0, 0, 0x057c, 0x3800 }, 639760dcaeSOliver Ruiz Dorantes // Bluetooth Ultraport Module from IBM 649760dcaeSOliver Ruiz Dorantes { 0, 0, 0, 0x04bf, 0x030a }, 659760dcaeSOliver Ruiz Dorantes // ALPS Modules with non-standard id 669760dcaeSOliver Ruiz Dorantes { 0, 0, 0, 0x044e, 0x3001 }, 679760dcaeSOliver Ruiz Dorantes { 0, 0, 0, 0x044e, 0x3002 }, 689760dcaeSOliver Ruiz Dorantes // Ericsson with non-standard id 699760dcaeSOliver Ruiz Dorantes { 0, 0, 0, 0x0bdb, 0x1002 } 709760dcaeSOliver Ruiz Dorantes }; 719760dcaeSOliver Ruiz Dorantes 729760dcaeSOliver Ruiz Dorantes /* add a device to the list of connected devices */ 739760dcaeSOliver Ruiz Dorantes static bt_usb_dev* 749760dcaeSOliver Ruiz Dorantes spawn_device(usb_device usb_dev) 759760dcaeSOliver Ruiz Dorantes { 761f2fa6cdSAlexander von Gluck IV CALLED(); 771f2fa6cdSAlexander von Gluck IV 789760dcaeSOliver Ruiz Dorantes int32 i; 799760dcaeSOliver Ruiz Dorantes status_t err = B_OK; 809760dcaeSOliver Ruiz Dorantes bt_usb_dev* new_bt_dev = NULL; 819760dcaeSOliver Ruiz Dorantes 829760dcaeSOliver Ruiz Dorantes // 16 usb dongles... 839760dcaeSOliver Ruiz Dorantes if (dev_count >= MAX_BT_GENERIC_USB_DEVICES) { 841f2fa6cdSAlexander von Gluck IV ERROR("%s: Device table full\n", __func__); 859760dcaeSOliver Ruiz Dorantes goto exit; 869760dcaeSOliver Ruiz Dorantes } 879760dcaeSOliver Ruiz Dorantes 889760dcaeSOliver Ruiz Dorantes // try the allocation 899760dcaeSOliver Ruiz Dorantes new_bt_dev = (bt_usb_dev*)malloc(sizeof(bt_usb_dev)); 909760dcaeSOliver Ruiz Dorantes if (new_bt_dev == NULL) { 911f2fa6cdSAlexander von Gluck IV ERROR("%s: Unable to malloc new bt device\n", __func__); 929760dcaeSOliver Ruiz Dorantes goto exit; 939760dcaeSOliver Ruiz Dorantes } 949760dcaeSOliver Ruiz Dorantes memset(new_bt_dev, 0, sizeof(bt_usb_dev)); 959760dcaeSOliver Ruiz Dorantes 969760dcaeSOliver Ruiz Dorantes // We will need this sem for some flow control 979760dcaeSOliver Ruiz Dorantes new_bt_dev->cmd_complete = create_sem(1, 989760dcaeSOliver Ruiz Dorantes BLUETOOTH_DEVICE_DEVFS_NAME "cmd_complete"); 999760dcaeSOliver Ruiz Dorantes if (new_bt_dev->cmd_complete < 0) { 1009760dcaeSOliver Ruiz Dorantes err = new_bt_dev->cmd_complete; 1019760dcaeSOliver Ruiz Dorantes goto bail0; 1029760dcaeSOliver Ruiz Dorantes } 1039760dcaeSOliver Ruiz Dorantes 1049760dcaeSOliver Ruiz Dorantes // and this for something else 1059760dcaeSOliver Ruiz Dorantes new_bt_dev->lock = create_sem(1, BLUETOOTH_DEVICE_DEVFS_NAME "lock"); 1069760dcaeSOliver Ruiz Dorantes if (new_bt_dev->lock < 0) { 1079760dcaeSOliver Ruiz Dorantes err = new_bt_dev->lock; 1089760dcaeSOliver Ruiz Dorantes goto bail1; 1099760dcaeSOliver Ruiz Dorantes } 1109760dcaeSOliver Ruiz Dorantes 1119760dcaeSOliver Ruiz Dorantes // find a free slot and fill out the name 1129760dcaeSOliver Ruiz Dorantes acquire_sem(dev_table_sem); 1139760dcaeSOliver Ruiz Dorantes for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { 1149760dcaeSOliver Ruiz Dorantes if (bt_usb_devices[i] == NULL) { 1159760dcaeSOliver Ruiz Dorantes bt_usb_devices[i] = new_bt_dev; 116f2986394SAlexander von Gluck IV sprintf(new_bt_dev->name, "%s/%" B_PRId32, 117f2986394SAlexander von Gluck IV BLUETOOTH_DEVICE_PATH, i); 1189760dcaeSOliver Ruiz Dorantes new_bt_dev->num = i; 1191f2fa6cdSAlexander von Gluck IV TRACE("%s: added device %p %" B_PRId32 " %s\n", __func__, 1201f2fa6cdSAlexander von Gluck IV bt_usb_devices[i], new_bt_dev->num, new_bt_dev->name); 1219760dcaeSOliver Ruiz Dorantes break; 1229760dcaeSOliver Ruiz Dorantes } 1239760dcaeSOliver Ruiz Dorantes } 1249760dcaeSOliver Ruiz Dorantes release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); 1259760dcaeSOliver Ruiz Dorantes 126446dc38fSLee Mon // In the case we cannot find a free slot 127446dc38fSLee Mon if (i >= MAX_BT_GENERIC_USB_DEVICES) { 1281f2fa6cdSAlexander von Gluck IV ERROR("%s: Device could not be added\n", __func__); 1299760dcaeSOliver Ruiz Dorantes goto bail2; 1309760dcaeSOliver Ruiz Dorantes } 1319760dcaeSOliver Ruiz Dorantes 1329760dcaeSOliver Ruiz Dorantes new_bt_dev->dev = usb_dev; 1339760dcaeSOliver Ruiz Dorantes // TODO: currently only server opens 1349760dcaeSOliver Ruiz Dorantes new_bt_dev->open_count = 0; 1359760dcaeSOliver Ruiz Dorantes 1369760dcaeSOliver Ruiz Dorantes dev_count++; 1379760dcaeSOliver Ruiz Dorantes return new_bt_dev; 1389760dcaeSOliver Ruiz Dorantes 1399760dcaeSOliver Ruiz Dorantes bail2: 1409760dcaeSOliver Ruiz Dorantes delete_sem(new_bt_dev->lock); 1419760dcaeSOliver Ruiz Dorantes bail1: 1429760dcaeSOliver Ruiz Dorantes delete_sem(new_bt_dev->cmd_complete); 1439760dcaeSOliver Ruiz Dorantes bail0: 1449760dcaeSOliver Ruiz Dorantes free(new_bt_dev); 1457cfdd924SMurai Takashi new_bt_dev = NULL; 1469760dcaeSOliver Ruiz Dorantes exit: 1479760dcaeSOliver Ruiz Dorantes return new_bt_dev; 1489760dcaeSOliver Ruiz Dorantes } 1499760dcaeSOliver Ruiz Dorantes 1509760dcaeSOliver Ruiz Dorantes 1519760dcaeSOliver Ruiz Dorantes // remove a device from the list of connected devices 1529760dcaeSOliver Ruiz Dorantes static void 1539760dcaeSOliver Ruiz Dorantes kill_device(bt_usb_dev* bdev) 1549760dcaeSOliver Ruiz Dorantes { 1559760dcaeSOliver Ruiz Dorantes if (bdev != NULL) { 1561f2fa6cdSAlexander von Gluck IV TRACE("%s: (%p)\n", __func__, bdev); 1579760dcaeSOliver Ruiz Dorantes 1589760dcaeSOliver Ruiz Dorantes delete_sem(bdev->lock); 1599760dcaeSOliver Ruiz Dorantes delete_sem(bdev->cmd_complete); 1609760dcaeSOliver Ruiz Dorantes 1619760dcaeSOliver Ruiz Dorantes // mark it free 1629760dcaeSOliver Ruiz Dorantes bt_usb_devices[bdev->num] = NULL; 1639760dcaeSOliver Ruiz Dorantes 1649760dcaeSOliver Ruiz Dorantes free(bdev); 1659760dcaeSOliver Ruiz Dorantes dev_count--; 1669760dcaeSOliver Ruiz Dorantes } 1679760dcaeSOliver Ruiz Dorantes } 1689760dcaeSOliver Ruiz Dorantes 1699760dcaeSOliver Ruiz Dorantes 1709760dcaeSOliver Ruiz Dorantes bt_usb_dev* 1719760dcaeSOliver Ruiz Dorantes fetch_device(bt_usb_dev* dev, hci_id hid) 1729760dcaeSOliver Ruiz Dorantes { 1739760dcaeSOliver Ruiz Dorantes int i; 1749760dcaeSOliver Ruiz Dorantes 1751f2fa6cdSAlexander von Gluck IV // TRACE("%s: (%p) or %d\n", __func__, dev, hid); 1769760dcaeSOliver Ruiz Dorantes 1779760dcaeSOliver Ruiz Dorantes acquire_sem(dev_table_sem); 178f2986394SAlexander von Gluck IV if (dev != NULL) { 1799760dcaeSOliver Ruiz Dorantes for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { 1809760dcaeSOliver Ruiz Dorantes if (bt_usb_devices[i] == dev) { 1819760dcaeSOliver Ruiz Dorantes release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); 1829760dcaeSOliver Ruiz Dorantes return bt_usb_devices[i]; 1839760dcaeSOliver Ruiz Dorantes } 1849760dcaeSOliver Ruiz Dorantes } 185f2986394SAlexander von Gluck IV } else { 1869760dcaeSOliver Ruiz Dorantes for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { 1879760dcaeSOliver Ruiz Dorantes if (bt_usb_devices[i] != NULL && bt_usb_devices[i]->hdev == hid) { 1889760dcaeSOliver Ruiz Dorantes release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); 1899760dcaeSOliver Ruiz Dorantes return bt_usb_devices[i]; 1909760dcaeSOliver Ruiz Dorantes } 1919760dcaeSOliver Ruiz Dorantes } 192f2986394SAlexander von Gluck IV } 1939760dcaeSOliver Ruiz Dorantes 1949760dcaeSOliver Ruiz Dorantes release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); 1959760dcaeSOliver Ruiz Dorantes 1969760dcaeSOliver Ruiz Dorantes return NULL; 1979760dcaeSOliver Ruiz Dorantes } 1989760dcaeSOliver Ruiz Dorantes 1999760dcaeSOliver Ruiz Dorantes 2009760dcaeSOliver Ruiz Dorantes #if 0 2019760dcaeSOliver Ruiz Dorantes #pragma mark - 2029760dcaeSOliver Ruiz Dorantes #endif 2039760dcaeSOliver Ruiz Dorantes 2049760dcaeSOliver Ruiz Dorantes // called by USB Manager when device is added to the USB 2059760dcaeSOliver Ruiz Dorantes static status_t 2069760dcaeSOliver Ruiz Dorantes device_added(usb_device dev, void** cookie) 2079760dcaeSOliver Ruiz Dorantes { 2089760dcaeSOliver Ruiz Dorantes const usb_interface_info* interface; 2099760dcaeSOliver Ruiz Dorantes const usb_device_descriptor* desc; 2109760dcaeSOliver Ruiz Dorantes const usb_configuration_info* config; 2119760dcaeSOliver Ruiz Dorantes const usb_interface_info* uif; 2129760dcaeSOliver Ruiz Dorantes const usb_endpoint_info* ep; 2139760dcaeSOliver Ruiz Dorantes 2149760dcaeSOliver Ruiz Dorantes status_t err = B_ERROR; 2159760dcaeSOliver Ruiz Dorantes bt_usb_dev* new_bt_dev = spawn_device(dev); 2169760dcaeSOliver Ruiz Dorantes int e; 2179760dcaeSOliver Ruiz Dorantes 2181f2fa6cdSAlexander von Gluck IV TRACE("%s: device_added(%p)\n", __func__, new_bt_dev); 2199760dcaeSOliver Ruiz Dorantes 2209760dcaeSOliver Ruiz Dorantes if (new_bt_dev == NULL) { 2211f2fa6cdSAlexander von Gluck IV ERROR("%s: Couldn't allocate device record.\n", __func__); 2229760dcaeSOliver Ruiz Dorantes err = ENOMEM; 2239760dcaeSOliver Ruiz Dorantes goto bail_no_mem; 2249760dcaeSOliver Ruiz Dorantes } 2259760dcaeSOliver Ruiz Dorantes 2269760dcaeSOliver Ruiz Dorantes // we only have 1 configuration number 0 2279760dcaeSOliver Ruiz Dorantes config = usb->get_nth_configuration(dev, 0); 2289760dcaeSOliver Ruiz Dorantes // dump_usb_configuration_info(config); 2299760dcaeSOliver Ruiz Dorantes if (config == NULL) { 2301f2fa6cdSAlexander von Gluck IV ERROR("%s: Couldn't get default USB config.\n", __func__); 2319760dcaeSOliver Ruiz Dorantes err = B_ERROR; 2329760dcaeSOliver Ruiz Dorantes goto bail; 2339760dcaeSOliver Ruiz Dorantes } 2349760dcaeSOliver Ruiz Dorantes 2351f2fa6cdSAlexander von Gluck IV TRACE("%s: found %" B_PRIuSIZE " alt interfaces.\n", __func__, 236f2986394SAlexander von Gluck IV config->interface->alt_count); 2379760dcaeSOliver Ruiz Dorantes 2389760dcaeSOliver Ruiz Dorantes // set first interface 2399760dcaeSOliver Ruiz Dorantes interface = &config->interface->alt[0]; 2409760dcaeSOliver Ruiz Dorantes err = usb->set_alt_interface(new_bt_dev->dev, interface); 2419760dcaeSOliver Ruiz Dorantes 2429760dcaeSOliver Ruiz Dorantes if (err != B_OK) { 2431f2fa6cdSAlexander von Gluck IV ERROR("%s: set_alt_interface() error.\n", __func__); 2449760dcaeSOliver Ruiz Dorantes goto bail; 2459760dcaeSOliver Ruiz Dorantes } 2469760dcaeSOliver Ruiz Dorantes 2479760dcaeSOliver Ruiz Dorantes // call set_configuration() only after calling set_alt_interface() 2489760dcaeSOliver Ruiz Dorantes err = usb->set_configuration(dev, config); 2499760dcaeSOliver Ruiz Dorantes if (err != B_OK) { 2501f2fa6cdSAlexander von Gluck IV ERROR("%s: set_configuration() error.\n", __func__); 2519760dcaeSOliver Ruiz Dorantes goto bail; 2529760dcaeSOliver Ruiz Dorantes } 2539760dcaeSOliver Ruiz Dorantes 2549760dcaeSOliver Ruiz Dorantes // Place to find out whats our concrete device and set up some special 2559760dcaeSOliver Ruiz Dorantes // info to our driver. If this code increases too much reconsider 2569760dcaeSOliver Ruiz Dorantes // this implementation 2579760dcaeSOliver Ruiz Dorantes desc = usb->get_device_descriptor(dev); 2589760dcaeSOliver Ruiz Dorantes if (desc->vendor_id == 0x0a5c 2599760dcaeSOliver Ruiz Dorantes && (desc->product_id == 0x200a 2609760dcaeSOliver Ruiz Dorantes || desc->product_id == 0x2009 2619760dcaeSOliver Ruiz Dorantes || desc->product_id == 0x2035)) { 2629760dcaeSOliver Ruiz Dorantes 2639760dcaeSOliver Ruiz Dorantes new_bt_dev->driver_info = BT_WILL_NEED_A_RESET | BT_SCO_NOT_WORKING; 2649760dcaeSOliver Ruiz Dorantes 2659760dcaeSOliver Ruiz Dorantes } 2669760dcaeSOliver Ruiz Dorantes /* 2679760dcaeSOliver Ruiz Dorantes else if ( desc->vendor_id == YOUR_VENDOR_HERE 2689760dcaeSOliver Ruiz Dorantes && desc->product_id == YOUR_PRODUCT_HERE ) { 2699760dcaeSOliver Ruiz Dorantes YOUR_SPECIAL_FLAGS_HERE 2709760dcaeSOliver Ruiz Dorantes } 2719760dcaeSOliver Ruiz Dorantes */ 2729760dcaeSOliver Ruiz Dorantes 2739760dcaeSOliver Ruiz Dorantes if (new_bt_dev->driver_info & BT_IGNORE_THIS_DEVICE) { 2749760dcaeSOliver Ruiz Dorantes err = ENODEV; 2759760dcaeSOliver Ruiz Dorantes goto bail; 2769760dcaeSOliver Ruiz Dorantes } 2779760dcaeSOliver Ruiz Dorantes 2789760dcaeSOliver Ruiz Dorantes // security check 2799760dcaeSOliver Ruiz Dorantes if (config->interface->active->descr->interface_number > 0) { 2801f2fa6cdSAlexander von Gluck IV ERROR("%s: Strange condition happened %d\n", __func__, 2819760dcaeSOliver Ruiz Dorantes config->interface->active->descr->interface_number); 2829760dcaeSOliver Ruiz Dorantes err = B_ERROR; 2839760dcaeSOliver Ruiz Dorantes goto bail; 2849760dcaeSOliver Ruiz Dorantes } 2859760dcaeSOliver Ruiz Dorantes 2861f2fa6cdSAlexander von Gluck IV TRACE("%s: Found %" B_PRIuSIZE " interfaces. Expected 3\n", __func__, 287f2986394SAlexander von Gluck IV config->interface_count); 288f2986394SAlexander von Gluck IV 2899760dcaeSOliver Ruiz Dorantes // Find endpoints that we need 2909760dcaeSOliver Ruiz Dorantes uif = config->interface->active; 2919760dcaeSOliver Ruiz Dorantes for (e = 0; e < uif->descr->num_endpoints; e++) { 2929760dcaeSOliver Ruiz Dorantes 2939760dcaeSOliver Ruiz Dorantes ep = &uif->endpoint[e]; 2949760dcaeSOliver Ruiz Dorantes switch (ep->descr->attributes & USB_ENDPOINT_ATTR_MASK) { 2959760dcaeSOliver Ruiz Dorantes case USB_ENDPOINT_ATTR_INTERRUPT: 2969760dcaeSOliver Ruiz Dorantes if (ep->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) 2979760dcaeSOliver Ruiz Dorantes { 2989760dcaeSOliver Ruiz Dorantes new_bt_dev->intr_in_ep = ep; 2991f2fa6cdSAlexander von Gluck IV new_bt_dev->max_packet_size_intr_in 3001f2fa6cdSAlexander von Gluck IV = ep->descr->max_packet_size; 3011f2fa6cdSAlexander von Gluck IV TRACE("%s: INT in\n", __func__); 3029760dcaeSOliver Ruiz Dorantes } else { 3031f2fa6cdSAlexander von Gluck IV TRACE("%s: INT out\n", __func__); 3049760dcaeSOliver Ruiz Dorantes } 3059760dcaeSOliver Ruiz Dorantes break; 3069760dcaeSOliver Ruiz Dorantes 3079760dcaeSOliver Ruiz Dorantes case USB_ENDPOINT_ATTR_BULK: 3089760dcaeSOliver Ruiz Dorantes if (ep->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) { 3099760dcaeSOliver Ruiz Dorantes new_bt_dev->bulk_in_ep = ep; 3101f2fa6cdSAlexander von Gluck IV new_bt_dev->max_packet_size_bulk_in 3111f2fa6cdSAlexander von Gluck IV = ep->descr->max_packet_size; 3121f2fa6cdSAlexander von Gluck IV TRACE("%s: BULK int\n", __func__); 3139760dcaeSOliver Ruiz Dorantes } else { 3149760dcaeSOliver Ruiz Dorantes new_bt_dev->bulk_out_ep = ep; 3151f2fa6cdSAlexander von Gluck IV new_bt_dev->max_packet_size_bulk_out 3161f2fa6cdSAlexander von Gluck IV = ep->descr->max_packet_size; 3171f2fa6cdSAlexander von Gluck IV TRACE("%s: BULK out\n", __func__); 3189760dcaeSOliver Ruiz Dorantes } 3199760dcaeSOliver Ruiz Dorantes break; 3209760dcaeSOliver Ruiz Dorantes } 3219760dcaeSOliver Ruiz Dorantes } 3229760dcaeSOliver Ruiz Dorantes 3239760dcaeSOliver Ruiz Dorantes if (!new_bt_dev->bulk_in_ep || !new_bt_dev->bulk_out_ep 3249760dcaeSOliver Ruiz Dorantes || !new_bt_dev->intr_in_ep) { 3251f2fa6cdSAlexander von Gluck IV ERROR("%s: Minimal # endpoints for BT not found\n", __func__); 3269760dcaeSOliver Ruiz Dorantes goto bail; 3279760dcaeSOliver Ruiz Dorantes } 3289760dcaeSOliver Ruiz Dorantes 3299760dcaeSOliver Ruiz Dorantes // Look into the devices suported to understand this 3309760dcaeSOliver Ruiz Dorantes if (new_bt_dev->driver_info & BT_DIGIANSWER) 3319760dcaeSOliver Ruiz Dorantes new_bt_dev->ctrl_req = USB_TYPE_VENDOR; 3329760dcaeSOliver Ruiz Dorantes else 3339760dcaeSOliver Ruiz Dorantes new_bt_dev->ctrl_req = USB_TYPE_CLASS; 3349760dcaeSOliver Ruiz Dorantes 3359760dcaeSOliver Ruiz Dorantes new_bt_dev->connected = true; 3369760dcaeSOliver Ruiz Dorantes 3379760dcaeSOliver Ruiz Dorantes // set the cookie that will be passed to other USB 3389760dcaeSOliver Ruiz Dorantes // hook functions (currently device_removed() is the only other) 3399760dcaeSOliver Ruiz Dorantes *cookie = new_bt_dev; 3401f2fa6cdSAlexander von Gluck IV TRACE("%s: Ok %p\n", __func__, new_bt_dev); 3419760dcaeSOliver Ruiz Dorantes return B_OK; 3429760dcaeSOliver Ruiz Dorantes 3439760dcaeSOliver Ruiz Dorantes bail: 3449760dcaeSOliver Ruiz Dorantes kill_device(new_bt_dev); 3459760dcaeSOliver Ruiz Dorantes bail_no_mem: 3469760dcaeSOliver Ruiz Dorantes *cookie = NULL; 3479760dcaeSOliver Ruiz Dorantes 3489760dcaeSOliver Ruiz Dorantes return err; 3499760dcaeSOliver Ruiz Dorantes } 3509760dcaeSOliver Ruiz Dorantes 3519760dcaeSOliver Ruiz Dorantes 3529760dcaeSOliver Ruiz Dorantes // Called by USB Manager when device is removed from the USB 3539760dcaeSOliver Ruiz Dorantes static status_t 3549760dcaeSOliver Ruiz Dorantes device_removed(void* cookie) 3559760dcaeSOliver Ruiz Dorantes { 3569760dcaeSOliver Ruiz Dorantes bt_usb_dev* bdev = fetch_device((bt_usb_dev*)cookie, 0); 3579760dcaeSOliver Ruiz Dorantes 3581f2fa6cdSAlexander von Gluck IV TRACE("%s: device_removed(%p)\n", __func__, bdev); 3599760dcaeSOliver Ruiz Dorantes 3609760dcaeSOliver Ruiz Dorantes if (bdev == NULL) { 3611f2fa6cdSAlexander von Gluck IV ERROR("%s: Device not present in driver.\n", __func__); 3629760dcaeSOliver Ruiz Dorantes return B_ERROR; 3639760dcaeSOliver Ruiz Dorantes } 3649760dcaeSOliver Ruiz Dorantes 3659760dcaeSOliver Ruiz Dorantes if (!TEST_AND_CLEAR(&bdev->state, RUNNING)) 3661f2fa6cdSAlexander von Gluck IV ERROR("%s: wasnt running?\n", __func__); 3679760dcaeSOliver Ruiz Dorantes 3681f2fa6cdSAlexander von Gluck IV TRACE("%s: Cancelling queues...\n", __func__); 3691f2fa6cdSAlexander von Gluck IV if (bdev->intr_in_ep != NULL) 3709760dcaeSOliver Ruiz Dorantes usb->cancel_queued_transfers(bdev->intr_in_ep->handle); 3711f2fa6cdSAlexander von Gluck IV if (bdev->bulk_in_ep != NULL) 3729760dcaeSOliver Ruiz Dorantes usb->cancel_queued_transfers(bdev->bulk_in_ep->handle); 3731f2fa6cdSAlexander von Gluck IV if (bdev->bulk_out_ep != NULL) 3749760dcaeSOliver Ruiz Dorantes usb->cancel_queued_transfers(bdev->bulk_out_ep->handle); 3759760dcaeSOliver Ruiz Dorantes 3769760dcaeSOliver Ruiz Dorantes bdev->connected = false; 3779760dcaeSOliver Ruiz Dorantes 3789760dcaeSOliver Ruiz Dorantes return B_OK; 3799760dcaeSOliver Ruiz Dorantes } 3809760dcaeSOliver Ruiz Dorantes 3819760dcaeSOliver Ruiz Dorantes 3829760dcaeSOliver Ruiz Dorantes static bt_hci_transport_hooks bluetooth_hooks = { 3839760dcaeSOliver Ruiz Dorantes NULL, 3849760dcaeSOliver Ruiz Dorantes &submit_nbuffer, 3859760dcaeSOliver Ruiz Dorantes &submit_nbuffer, 3869760dcaeSOliver Ruiz Dorantes NULL, 3879760dcaeSOliver Ruiz Dorantes NULL, 3889760dcaeSOliver Ruiz Dorantes H2 3899760dcaeSOliver Ruiz Dorantes }; 3909760dcaeSOliver Ruiz Dorantes 3919760dcaeSOliver Ruiz Dorantes 3929760dcaeSOliver Ruiz Dorantes static usb_notify_hooks notify_hooks = { 3939760dcaeSOliver Ruiz Dorantes &device_added, 3949760dcaeSOliver Ruiz Dorantes &device_removed 3959760dcaeSOliver Ruiz Dorantes }; 3969760dcaeSOliver Ruiz Dorantes 3979760dcaeSOliver Ruiz Dorantes #if 0 3989760dcaeSOliver Ruiz Dorantes #pragma mark - 3999760dcaeSOliver Ruiz Dorantes #endif 4009760dcaeSOliver Ruiz Dorantes 4019760dcaeSOliver Ruiz Dorantes status_t 4029760dcaeSOliver Ruiz Dorantes submit_nbuffer(hci_id hid, net_buffer* nbuf) 4039760dcaeSOliver Ruiz Dorantes { 4049760dcaeSOliver Ruiz Dorantes bt_usb_dev* bdev = NULL; 4059760dcaeSOliver Ruiz Dorantes 4069760dcaeSOliver Ruiz Dorantes bdev = fetch_device(NULL, hid); 4079760dcaeSOliver Ruiz Dorantes 4081f2fa6cdSAlexander von Gluck IV TRACE("%s: index=%" B_PRId32 " nbuf=%p bdev=%p\n", __func__, hid, 4091f2fa6cdSAlexander von Gluck IV nbuf, bdev); 4109760dcaeSOliver Ruiz Dorantes 4119760dcaeSOliver Ruiz Dorantes if (bdev != NULL) { 4129760dcaeSOliver Ruiz Dorantes switch (nbuf->protocol) { 4139760dcaeSOliver Ruiz Dorantes case BT_COMMAND: 4149760dcaeSOliver Ruiz Dorantes // not issued this way 4159760dcaeSOliver Ruiz Dorantes break; 4169760dcaeSOliver Ruiz Dorantes 4179760dcaeSOliver Ruiz Dorantes case BT_ACL: 4189760dcaeSOliver Ruiz Dorantes return submit_tx_acl(bdev, nbuf); 4199760dcaeSOliver Ruiz Dorantes break; 4209760dcaeSOliver Ruiz Dorantes 4219760dcaeSOliver Ruiz Dorantes default: 4229760dcaeSOliver Ruiz Dorantes panic("submit_nbuffer: no protocol"); 4239760dcaeSOliver Ruiz Dorantes break; 4249760dcaeSOliver Ruiz Dorantes 4259760dcaeSOliver Ruiz Dorantes } 4269760dcaeSOliver Ruiz Dorantes } 4279760dcaeSOliver Ruiz Dorantes 4289760dcaeSOliver Ruiz Dorantes return B_ERROR; 4299760dcaeSOliver Ruiz Dorantes 4309760dcaeSOliver Ruiz Dorantes } 4319760dcaeSOliver Ruiz Dorantes 4329760dcaeSOliver Ruiz Dorantes 4339760dcaeSOliver Ruiz Dorantes // implements the POSIX open() 4349760dcaeSOliver Ruiz Dorantes static status_t 4359760dcaeSOliver Ruiz Dorantes device_open(const char* name, uint32 flags, void **cookie) 4369760dcaeSOliver Ruiz Dorantes { 4371f2fa6cdSAlexander von Gluck IV CALLED(); 4381f2fa6cdSAlexander von Gluck IV 4399760dcaeSOliver Ruiz Dorantes status_t err = ENODEV; 4409760dcaeSOliver Ruiz Dorantes bt_usb_dev* bdev = NULL; 4419760dcaeSOliver Ruiz Dorantes hci_id hdev; 4429760dcaeSOliver Ruiz Dorantes int i; 4439760dcaeSOliver Ruiz Dorantes 4449760dcaeSOliver Ruiz Dorantes acquire_sem(dev_table_sem); 4459760dcaeSOliver Ruiz Dorantes for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { 4469760dcaeSOliver Ruiz Dorantes if (bt_usb_devices[i] && !strcmp(name, bt_usb_devices[i]->name)) { 4479760dcaeSOliver Ruiz Dorantes bdev = bt_usb_devices[i]; 4489760dcaeSOliver Ruiz Dorantes break; 4499760dcaeSOliver Ruiz Dorantes } 4509760dcaeSOliver Ruiz Dorantes } 4519760dcaeSOliver Ruiz Dorantes release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); 4529760dcaeSOliver Ruiz Dorantes 4539760dcaeSOliver Ruiz Dorantes if (bdev == NULL) { 4541f2fa6cdSAlexander von Gluck IV ERROR("%s: Device not found in the open list!", __func__); 4559760dcaeSOliver Ruiz Dorantes *cookie = NULL; 4569760dcaeSOliver Ruiz Dorantes return B_ERROR; 4579760dcaeSOliver Ruiz Dorantes } 4589760dcaeSOliver Ruiz Dorantes 4599760dcaeSOliver Ruiz Dorantes // Set RUNNING 4609760dcaeSOliver Ruiz Dorantes if (TEST_AND_SET(&bdev->state, RUNNING)) { 4611f2fa6cdSAlexander von Gluck IV ERROR("%s: dev already running! - reOpened device!\n", __func__); 4629760dcaeSOliver Ruiz Dorantes return B_ERROR; 4639760dcaeSOliver Ruiz Dorantes } 4649760dcaeSOliver Ruiz Dorantes 4659760dcaeSOliver Ruiz Dorantes acquire_sem(bdev->lock); 4669760dcaeSOliver Ruiz Dorantes // TX structures 4679760dcaeSOliver Ruiz Dorantes for (i = 0; i < BT_DRIVER_TXCOVERAGE; i++) { 4689760dcaeSOliver Ruiz Dorantes list_init(&bdev->nbuffersTx[i]); 4699760dcaeSOliver Ruiz Dorantes bdev->nbuffersPendingTx[i] = 0; 4709760dcaeSOliver Ruiz Dorantes } 4719760dcaeSOliver Ruiz Dorantes 4729760dcaeSOliver Ruiz Dorantes // RX structures 4739760dcaeSOliver Ruiz Dorantes bdev->eventRx = NULL; 4749760dcaeSOliver Ruiz Dorantes for (i = 0; i < BT_DRIVER_RXCOVERAGE; i++) { 4759760dcaeSOliver Ruiz Dorantes bdev->nbufferRx[i] = NULL; 4769760dcaeSOliver Ruiz Dorantes } 4779760dcaeSOliver Ruiz Dorantes 4789760dcaeSOliver Ruiz Dorantes // dumping the USB frames 4799760dcaeSOliver Ruiz Dorantes init_room(&bdev->eventRoom); 4809760dcaeSOliver Ruiz Dorantes init_room(&bdev->aclRoom); 4819760dcaeSOliver Ruiz Dorantes // init_room(new_bt_dev->scoRoom); 4829760dcaeSOliver Ruiz Dorantes 4839760dcaeSOliver Ruiz Dorantes list_init(&bdev->snetBufferRecycleTrash); 4849760dcaeSOliver Ruiz Dorantes 4859760dcaeSOliver Ruiz Dorantes // Allocate set and register the HCI device 4869760dcaeSOliver Ruiz Dorantes if (btDevices != NULL) { 4879760dcaeSOliver Ruiz Dorantes bluetooth_device* ndev; 4889760dcaeSOliver Ruiz Dorantes // TODO: Fill the transport descriptor 4899760dcaeSOliver Ruiz Dorantes err = btDevices->RegisterDriver(&bluetooth_hooks, &ndev); 4909760dcaeSOliver Ruiz Dorantes 4919760dcaeSOliver Ruiz Dorantes if (err == B_OK) { 4929760dcaeSOliver Ruiz Dorantes bdev->hdev = hdev = ndev->index; // Get the index 4939760dcaeSOliver Ruiz Dorantes bdev->ndev = ndev; // Get the net_device 4949760dcaeSOliver Ruiz Dorantes 4959760dcaeSOliver Ruiz Dorantes } else { 4969760dcaeSOliver Ruiz Dorantes hdev = bdev->num; // XXX: Lets try to go on 4979760dcaeSOliver Ruiz Dorantes } 4989760dcaeSOliver Ruiz Dorantes } else { 4999760dcaeSOliver Ruiz Dorantes hdev = bdev->num; // XXX: Lets try to go on 5009760dcaeSOliver Ruiz Dorantes } 5019760dcaeSOliver Ruiz Dorantes 5029760dcaeSOliver Ruiz Dorantes bdev->hdev = hdev; 5039760dcaeSOliver Ruiz Dorantes 5049760dcaeSOliver Ruiz Dorantes *cookie = bdev; 5059760dcaeSOliver Ruiz Dorantes release_sem(bdev->lock); 5069760dcaeSOliver Ruiz Dorantes 5079760dcaeSOliver Ruiz Dorantes return B_OK; 5089760dcaeSOliver Ruiz Dorantes 5099760dcaeSOliver Ruiz Dorantes } 5109760dcaeSOliver Ruiz Dorantes 5119760dcaeSOliver Ruiz Dorantes 5129760dcaeSOliver Ruiz Dorantes /* called when a client calls POSIX close() on the driver, but I/O 5139760dcaeSOliver Ruiz Dorantes * requests may still be pending 5149760dcaeSOliver Ruiz Dorantes */ 5159760dcaeSOliver Ruiz Dorantes static status_t 5169760dcaeSOliver Ruiz Dorantes device_close(void* cookie) 5179760dcaeSOliver Ruiz Dorantes { 5181f2fa6cdSAlexander von Gluck IV CALLED(); 5191f2fa6cdSAlexander von Gluck IV 5209760dcaeSOliver Ruiz Dorantes int32 i; 5219760dcaeSOliver Ruiz Dorantes void* item; 5229760dcaeSOliver Ruiz Dorantes bt_usb_dev* bdev = (bt_usb_dev*)cookie; 5239760dcaeSOliver Ruiz Dorantes 5249760dcaeSOliver Ruiz Dorantes if (bdev == NULL) 5259760dcaeSOliver Ruiz Dorantes panic("bad cookie"); 5269760dcaeSOliver Ruiz Dorantes 5279760dcaeSOliver Ruiz Dorantes // Clean queues 5289760dcaeSOliver Ruiz Dorantes 5299760dcaeSOliver Ruiz Dorantes if (bdev->connected == true) { 5301f2fa6cdSAlexander von Gluck IV TRACE("%s: Cancelling queues...\n", __func__); 5311f2fa6cdSAlexander von Gluck IV 5321f2fa6cdSAlexander von Gluck IV if (bdev->intr_in_ep != NULL) 5339760dcaeSOliver Ruiz Dorantes usb->cancel_queued_transfers(bdev->intr_in_ep->handle); 5349760dcaeSOliver Ruiz Dorantes 5351f2fa6cdSAlexander von Gluck IV if (bdev->bulk_in_ep!=NULL) 5369760dcaeSOliver Ruiz Dorantes usb->cancel_queued_transfers(bdev->bulk_in_ep->handle); 5379760dcaeSOliver Ruiz Dorantes 5381f2fa6cdSAlexander von Gluck IV if (bdev->bulk_out_ep!=NULL) 5399760dcaeSOliver Ruiz Dorantes usb->cancel_queued_transfers(bdev->bulk_out_ep->handle); 5409760dcaeSOliver Ruiz Dorantes } 5419760dcaeSOliver Ruiz Dorantes 5429760dcaeSOliver Ruiz Dorantes // TX 5439760dcaeSOliver Ruiz Dorantes for (i = 0; i < BT_DRIVER_TXCOVERAGE; i++) { 544f2986394SAlexander von Gluck IV if (i == BT_COMMAND) { 545f2986394SAlexander von Gluck IV while ((item = list_remove_head_item(&bdev->nbuffersTx[i])) != NULL) 5469760dcaeSOliver Ruiz Dorantes snb_free((snet_buffer*)item); 547f2986394SAlexander von Gluck IV } else { 548f2986394SAlexander von Gluck IV while ((item = list_remove_head_item(&bdev->nbuffersTx[i])) != NULL) 5499760dcaeSOliver Ruiz Dorantes nb_destroy((net_buffer*)item); 5509760dcaeSOliver Ruiz Dorantes } 5519760dcaeSOliver Ruiz Dorantes } 5529760dcaeSOliver Ruiz Dorantes // RX 5539760dcaeSOliver Ruiz Dorantes for (i = 0; i < BT_DRIVER_RXCOVERAGE; i++) { 5549760dcaeSOliver Ruiz Dorantes nb_destroy(bdev->nbufferRx[i]); 5559760dcaeSOliver Ruiz Dorantes } 5569760dcaeSOliver Ruiz Dorantes snb_free(bdev->eventRx); 5579760dcaeSOliver Ruiz Dorantes 5589760dcaeSOliver Ruiz Dorantes purge_room(&bdev->eventRoom); 5599760dcaeSOliver Ruiz Dorantes purge_room(&bdev->aclRoom); 5609760dcaeSOliver Ruiz Dorantes 5619760dcaeSOliver Ruiz Dorantes // Device no longer in our Stack 5629760dcaeSOliver Ruiz Dorantes if (btDevices != NULL) 5639760dcaeSOliver Ruiz Dorantes btDevices->UnregisterDriver(bdev->hdev); 5649760dcaeSOliver Ruiz Dorantes 5659760dcaeSOliver Ruiz Dorantes // unSet RUNNING 5669760dcaeSOliver Ruiz Dorantes if (TEST_AND_CLEAR(&bdev->state, RUNNING)) { 5671f2fa6cdSAlexander von Gluck IV ERROR("%s: %s not running?\n", __func__, bdev->name); 5689760dcaeSOliver Ruiz Dorantes return B_ERROR; 5699760dcaeSOliver Ruiz Dorantes } 5709760dcaeSOliver Ruiz Dorantes 5719760dcaeSOliver Ruiz Dorantes return B_OK; 5729760dcaeSOliver Ruiz Dorantes } 5739760dcaeSOliver Ruiz Dorantes 5749760dcaeSOliver Ruiz Dorantes 5759760dcaeSOliver Ruiz Dorantes // Called after device_close(), when all pending I / O requests have returned 5769760dcaeSOliver Ruiz Dorantes static status_t 5779760dcaeSOliver Ruiz Dorantes device_free(void* cookie) 5789760dcaeSOliver Ruiz Dorantes { 5791f2fa6cdSAlexander von Gluck IV CALLED(); 5801f2fa6cdSAlexander von Gluck IV 5819760dcaeSOliver Ruiz Dorantes status_t err = B_OK; 5829760dcaeSOliver Ruiz Dorantes bt_usb_dev* bdev = (bt_usb_dev*)cookie; 5839760dcaeSOliver Ruiz Dorantes 5841f2fa6cdSAlexander von Gluck IV if (!bdev->connected) 5859760dcaeSOliver Ruiz Dorantes kill_device(bdev); 5869760dcaeSOliver Ruiz Dorantes 5879760dcaeSOliver Ruiz Dorantes return err; 5889760dcaeSOliver Ruiz Dorantes } 5899760dcaeSOliver Ruiz Dorantes 5909760dcaeSOliver Ruiz Dorantes 5919760dcaeSOliver Ruiz Dorantes // implements the POSIX ioctl() 5929760dcaeSOliver Ruiz Dorantes static status_t 593*1e4109cdSAugustin Cavalier device_control(void* cookie, uint32 msg, void* params, size_t size) 5949760dcaeSOliver Ruiz Dorantes { 5959760dcaeSOliver Ruiz Dorantes status_t err = B_ERROR; 5969760dcaeSOliver Ruiz Dorantes bt_usb_dev* bdev = (bt_usb_dev*)cookie; 5979760dcaeSOliver Ruiz Dorantes snet_buffer* snbuf; 5989760dcaeSOliver Ruiz Dorantes #if BT_DRIVER_SUPPORTS_ACL // ACL 5999760dcaeSOliver Ruiz Dorantes int32 i; 6009760dcaeSOliver Ruiz Dorantes #endif 6019760dcaeSOliver Ruiz Dorantes 6029760dcaeSOliver Ruiz Dorantes TOUCH(size); 6031f2fa6cdSAlexander von Gluck IV TRACE("%s: ioctl() opcode %" B_PRId32 " size %" B_PRIuSIZE ".\n", __func__, 6041f2fa6cdSAlexander von Gluck IV msg, size); 6059760dcaeSOliver Ruiz Dorantes 6069760dcaeSOliver Ruiz Dorantes if (bdev == NULL) { 6071f2fa6cdSAlexander von Gluck IV TRACE("%s: Bad cookie\n", __func__); 6089760dcaeSOliver Ruiz Dorantes return B_BAD_VALUE; 6099760dcaeSOliver Ruiz Dorantes } 6109760dcaeSOliver Ruiz Dorantes 611*1e4109cdSAugustin Cavalier if (params == NULL || !IS_USER_ADDRESS(params)) { 6121f2fa6cdSAlexander von Gluck IV TRACE("%s: Invalid pointer control\n", __func__); 6139760dcaeSOliver Ruiz Dorantes return B_BAD_VALUE; 6149760dcaeSOliver Ruiz Dorantes } 6159760dcaeSOliver Ruiz Dorantes 6169760dcaeSOliver Ruiz Dorantes acquire_sem(bdev->lock); 6179760dcaeSOliver Ruiz Dorantes 6189760dcaeSOliver Ruiz Dorantes switch (msg) { 619*1e4109cdSAugustin Cavalier case ISSUE_BT_COMMAND: { 6209760dcaeSOliver Ruiz Dorantes if (size == 0) { 6211f2fa6cdSAlexander von Gluck IV TRACE("%s: Invalid size control\n", __func__); 6229760dcaeSOliver Ruiz Dorantes err = B_BAD_VALUE; 6239760dcaeSOliver Ruiz Dorantes break; 6249760dcaeSOliver Ruiz Dorantes } 6259760dcaeSOliver Ruiz Dorantes 626*1e4109cdSAugustin Cavalier void* _params = alloca(size); 627*1e4109cdSAugustin Cavalier if (user_memcpy(_params, params, size) != B_OK) 628*1e4109cdSAugustin Cavalier return B_BAD_ADDRESS; 629*1e4109cdSAugustin Cavalier 6309760dcaeSOliver Ruiz Dorantes // TODO: Reuse from some TXcompleted queue 6319760dcaeSOliver Ruiz Dorantes // snbuf = snb_create(size); 6329760dcaeSOliver Ruiz Dorantes snbuf = snb_fetch(&bdev->snetBufferRecycleTrash, size); 633*1e4109cdSAugustin Cavalier snb_put(snbuf, _params, size); 6349760dcaeSOliver Ruiz Dorantes 6359760dcaeSOliver Ruiz Dorantes err = submit_tx_command(bdev, snbuf); 6361f2fa6cdSAlexander von Gluck IV TRACE("%s: command launched\n", __func__); 6379760dcaeSOliver Ruiz Dorantes break; 638*1e4109cdSAugustin Cavalier } 6399760dcaeSOliver Ruiz Dorantes 6409760dcaeSOliver Ruiz Dorantes case BT_UP: 6419760dcaeSOliver Ruiz Dorantes // EVENTS 6429760dcaeSOliver Ruiz Dorantes err = submit_rx_event(bdev); 6439760dcaeSOliver Ruiz Dorantes if (err != B_OK) { 644a12bde1cSAdrien Destugues bdev->state = CLEAR_BIT(bdev->state, ANCILLYANT); 6451f2fa6cdSAlexander von Gluck IV ERROR("%s: Queuing failed device stops running\n", __func__); 6469760dcaeSOliver Ruiz Dorantes break; 6479760dcaeSOliver Ruiz Dorantes } 6489760dcaeSOliver Ruiz Dorantes 6499760dcaeSOliver Ruiz Dorantes #if BT_DRIVER_SUPPORTS_ACL // ACL 6509760dcaeSOliver Ruiz Dorantes for (i = 0; i < MAX_ACL_IN_WINDOW; i++) { 6519760dcaeSOliver Ruiz Dorantes err = submit_rx_acl(bdev); 6529760dcaeSOliver Ruiz Dorantes if (err != B_OK && i == 0) { 653a12bde1cSAdrien Destugues bdev->state = CLEAR_BIT(bdev->state, ANCILLYANT); 654a12bde1cSAdrien Destugues // Set the flaq in the HCI world 6551f2fa6cdSAlexander von Gluck IV ERROR("%s: Queuing failed device stops running\n", 6561f2fa6cdSAlexander von Gluck IV __func__); 6579760dcaeSOliver Ruiz Dorantes break; 6589760dcaeSOliver Ruiz Dorantes } 6599760dcaeSOliver Ruiz Dorantes } 6609760dcaeSOliver Ruiz Dorantes #endif 6619760dcaeSOliver Ruiz Dorantes 662a12bde1cSAdrien Destugues bdev->state = SET_BIT(bdev->state, RUNNING); 6639760dcaeSOliver Ruiz Dorantes 6649760dcaeSOliver Ruiz Dorantes #if BT_DRIVER_SUPPORTS_SCO 6659760dcaeSOliver Ruiz Dorantes // TODO: SCO / eSCO 6669760dcaeSOliver Ruiz Dorantes #endif 6671f2fa6cdSAlexander von Gluck IV 6681f2fa6cdSAlexander von Gluck IV ERROR("%s: Device online\n", __func__); 6699760dcaeSOliver Ruiz Dorantes break; 6709760dcaeSOliver Ruiz Dorantes 6719760dcaeSOliver Ruiz Dorantes case GET_STATS: 672*1e4109cdSAugustin Cavalier err = user_memcpy(params, &bdev->stat, sizeof(bt_hci_statistics)); 6739760dcaeSOliver Ruiz Dorantes break; 6749760dcaeSOliver Ruiz Dorantes 6759760dcaeSOliver Ruiz Dorantes case GET_HCI_ID: 676*1e4109cdSAugustin Cavalier err = user_memcpy(params, &bdev->hdev, sizeof(hci_id)); 6779760dcaeSOliver Ruiz Dorantes break; 6789760dcaeSOliver Ruiz Dorantes 6799760dcaeSOliver Ruiz Dorantes 6809760dcaeSOliver Ruiz Dorantes default: 6811f2fa6cdSAlexander von Gluck IV ERROR("%s: Invalid opcode.\n", __func__); 6829760dcaeSOliver Ruiz Dorantes err = B_DEV_INVALID_IOCTL; 6839760dcaeSOliver Ruiz Dorantes break; 6849760dcaeSOliver Ruiz Dorantes } 6859760dcaeSOliver Ruiz Dorantes 6869760dcaeSOliver Ruiz Dorantes release_sem(bdev->lock); 6879760dcaeSOliver Ruiz Dorantes return err; 6889760dcaeSOliver Ruiz Dorantes } 6899760dcaeSOliver Ruiz Dorantes 6909760dcaeSOliver Ruiz Dorantes 6919760dcaeSOliver Ruiz Dorantes // implements the POSIX read() 6929760dcaeSOliver Ruiz Dorantes static status_t 6939760dcaeSOliver Ruiz Dorantes device_read(void* cookie, off_t pos, void* buffer, size_t* count) 6949760dcaeSOliver Ruiz Dorantes { 6951f2fa6cdSAlexander von Gluck IV TRACE("%s: Reading... count = %" B_PRIuSIZE "\n", __func__, *count); 6969760dcaeSOliver Ruiz Dorantes 6979760dcaeSOliver Ruiz Dorantes *count = 0; 6989760dcaeSOliver Ruiz Dorantes return B_OK; 6999760dcaeSOliver Ruiz Dorantes } 7009760dcaeSOliver Ruiz Dorantes 7019760dcaeSOliver Ruiz Dorantes 7029760dcaeSOliver Ruiz Dorantes // implements the POSIX write() 7039760dcaeSOliver Ruiz Dorantes static status_t 7049760dcaeSOliver Ruiz Dorantes device_write(void* cookie, off_t pos, const void* buffer, size_t* count) 7059760dcaeSOliver Ruiz Dorantes { 7061f2fa6cdSAlexander von Gluck IV CALLED(); 7079760dcaeSOliver Ruiz Dorantes 7089760dcaeSOliver Ruiz Dorantes return B_ERROR; 7099760dcaeSOliver Ruiz Dorantes } 7109760dcaeSOliver Ruiz Dorantes 7119760dcaeSOliver Ruiz Dorantes 7129760dcaeSOliver Ruiz Dorantes #if 0 7139760dcaeSOliver Ruiz Dorantes #pragma mark - 7149760dcaeSOliver Ruiz Dorantes #endif 7159760dcaeSOliver Ruiz Dorantes 7169760dcaeSOliver Ruiz Dorantes 7179760dcaeSOliver Ruiz Dorantes static int 7189760dcaeSOliver Ruiz Dorantes dump_driver(int argc, char** argv) 7199760dcaeSOliver Ruiz Dorantes { 7209760dcaeSOliver Ruiz Dorantes int i; 7219760dcaeSOliver Ruiz Dorantes snet_buffer* item = NULL; 7229760dcaeSOliver Ruiz Dorantes 7239760dcaeSOliver Ruiz Dorantes for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { 7249760dcaeSOliver Ruiz Dorantes 7259760dcaeSOliver Ruiz Dorantes if (bt_usb_devices[i] != NULL) { 7269760dcaeSOliver Ruiz Dorantes kprintf("%s : \n", bt_usb_devices[i]->name); 7279760dcaeSOliver Ruiz Dorantes kprintf("\taclroom = %d\teventroom = %d\tcommand & events =%d\n", 7289760dcaeSOliver Ruiz Dorantes snb_packets(&bt_usb_devices[i]->eventRoom), 7299760dcaeSOliver Ruiz Dorantes snb_packets(&bt_usb_devices[i]->aclRoom), 7309760dcaeSOliver Ruiz Dorantes snb_packets(&bt_usb_devices[i]->snetBufferRecycleTrash)); 7319760dcaeSOliver Ruiz Dorantes 7329760dcaeSOliver Ruiz Dorantes while ((item = (snet_buffer*)list_get_next_item( 7339760dcaeSOliver Ruiz Dorantes &bt_usb_devices[i]->snetBufferRecycleTrash, item)) != NULL) 7349760dcaeSOliver Ruiz Dorantes snb_dump(item); 7359760dcaeSOliver Ruiz Dorantes } 7369760dcaeSOliver Ruiz Dorantes } 7379760dcaeSOliver Ruiz Dorantes 7389760dcaeSOliver Ruiz Dorantes return 0; 7399760dcaeSOliver Ruiz Dorantes } 7409760dcaeSOliver Ruiz Dorantes 7419760dcaeSOliver Ruiz Dorantes 7429760dcaeSOliver Ruiz Dorantes // called each time the driver is loaded by the kernel 7439760dcaeSOliver Ruiz Dorantes status_t 7449760dcaeSOliver Ruiz Dorantes init_driver(void) 7459760dcaeSOliver Ruiz Dorantes { 7461f2fa6cdSAlexander von Gluck IV CALLED(); 7479760dcaeSOliver Ruiz Dorantes int j; 7489760dcaeSOliver Ruiz Dorantes 749f2986394SAlexander von Gluck IV if (get_module(BT_CORE_DATA_MODULE_NAME, 750f2986394SAlexander von Gluck IV (module_info**)&btCoreData) != B_OK) { 7511f2fa6cdSAlexander von Gluck IV ERROR("%s: cannot get module '%s'\n", __func__, 7521f2fa6cdSAlexander von Gluck IV BT_CORE_DATA_MODULE_NAME); 7539760dcaeSOliver Ruiz Dorantes return B_ERROR; 7541f2fa6cdSAlexander von Gluck IV } 7559760dcaeSOliver Ruiz Dorantes 7569760dcaeSOliver Ruiz Dorantes // BT devices MODULE INITS 7579760dcaeSOliver Ruiz Dorantes if (get_module(btDevices_name, (module_info**)&btDevices) != B_OK) { 7581f2fa6cdSAlexander von Gluck IV ERROR("%s: cannot get module '%s'\n", __func__, btDevices_name); 7599760dcaeSOliver Ruiz Dorantes goto err_release3; 7601f2fa6cdSAlexander von Gluck IV } 7619760dcaeSOliver Ruiz Dorantes 7629760dcaeSOliver Ruiz Dorantes // HCI MODULE INITS 7639760dcaeSOliver Ruiz Dorantes if (get_module(hci_name, (module_info**)&hci) != B_OK) { 7641f2fa6cdSAlexander von Gluck IV ERROR("%s: cannot get module '%s'\n", __func__, hci_name); 7659760dcaeSOliver Ruiz Dorantes #ifndef BT_SURVIVE_WITHOUT_HCI 7669760dcaeSOliver Ruiz Dorantes goto err_release2; 7679760dcaeSOliver Ruiz Dorantes #endif 7689760dcaeSOliver Ruiz Dorantes } 7699760dcaeSOliver Ruiz Dorantes 7709760dcaeSOliver Ruiz Dorantes // USB MODULE INITS 7719760dcaeSOliver Ruiz Dorantes if (get_module(usb_name, (module_info**)&usb) != B_OK) { 7721f2fa6cdSAlexander von Gluck IV ERROR("%s: cannot get module '%s'\n", __func__, usb_name); 7739760dcaeSOliver Ruiz Dorantes goto err_release1; 7749760dcaeSOliver Ruiz Dorantes } 7759760dcaeSOliver Ruiz Dorantes 7769760dcaeSOliver Ruiz Dorantes if (get_module(NET_BUFFER_MODULE_NAME, (module_info**)&nb) != B_OK) { 7771f2fa6cdSAlexander von Gluck IV ERROR("%s: cannot get module '%s'\n", __func__, 7781f2fa6cdSAlexander von Gluck IV NET_BUFFER_MODULE_NAME); 7799760dcaeSOliver Ruiz Dorantes #ifndef BT_SURVIVE_WITHOUT_NET_BUFFERS 7809760dcaeSOliver Ruiz Dorantes goto err_release; 7819760dcaeSOliver Ruiz Dorantes #endif 7829760dcaeSOliver Ruiz Dorantes } 7839760dcaeSOliver Ruiz Dorantes 7849760dcaeSOliver Ruiz Dorantes // GENERAL INITS 7859760dcaeSOliver Ruiz Dorantes dev_table_sem = create_sem(1, BLUETOOTH_DEVICE_DEVFS_NAME "dev_table_lock"); 7869760dcaeSOliver Ruiz Dorantes if (dev_table_sem < 0) { 7879760dcaeSOliver Ruiz Dorantes goto err; 7889760dcaeSOliver Ruiz Dorantes } 7899760dcaeSOliver Ruiz Dorantes 7909760dcaeSOliver Ruiz Dorantes for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) { 7919760dcaeSOliver Ruiz Dorantes bt_usb_devices[j] = NULL; 7929760dcaeSOliver Ruiz Dorantes } 7939760dcaeSOliver Ruiz Dorantes 7949760dcaeSOliver Ruiz Dorantes // Note: After here device_added and publish devices hooks are called 7959760dcaeSOliver Ruiz Dorantes usb->register_driver(BLUETOOTH_DEVICE_DEVFS_NAME, supported_devices, 1, NULL); 7969760dcaeSOliver Ruiz Dorantes usb->install_notify(BLUETOOTH_DEVICE_DEVFS_NAME, ¬ify_hooks); 7979760dcaeSOliver Ruiz Dorantes 7989760dcaeSOliver Ruiz Dorantes add_debugger_command("bth2generic", &dump_driver, 7999760dcaeSOliver Ruiz Dorantes "Lists H2 Transport device info"); 8009760dcaeSOliver Ruiz Dorantes 8019760dcaeSOliver Ruiz Dorantes return B_OK; 8029760dcaeSOliver Ruiz Dorantes 8039760dcaeSOliver Ruiz Dorantes err: // Releasing 8049760dcaeSOliver Ruiz Dorantes put_module(NET_BUFFER_MODULE_NAME); 8059760dcaeSOliver Ruiz Dorantes err_release: 8069760dcaeSOliver Ruiz Dorantes put_module(usb_name); 8079760dcaeSOliver Ruiz Dorantes err_release1: 8089760dcaeSOliver Ruiz Dorantes put_module(hci_name); 8099760dcaeSOliver Ruiz Dorantes #ifndef BT_SURVIVE_WITHOUT_HCI 8109760dcaeSOliver Ruiz Dorantes err_release2: 8119760dcaeSOliver Ruiz Dorantes #endif 8129760dcaeSOliver Ruiz Dorantes put_module(btDevices_name); 8139760dcaeSOliver Ruiz Dorantes err_release3: 8149760dcaeSOliver Ruiz Dorantes put_module(BT_CORE_DATA_MODULE_NAME); 8159760dcaeSOliver Ruiz Dorantes 8169760dcaeSOliver Ruiz Dorantes return B_ERROR; 8179760dcaeSOliver Ruiz Dorantes } 8189760dcaeSOliver Ruiz Dorantes 8199760dcaeSOliver Ruiz Dorantes 8209760dcaeSOliver Ruiz Dorantes // called just before the kernel unloads the driver 8219760dcaeSOliver Ruiz Dorantes void 8229760dcaeSOliver Ruiz Dorantes uninit_driver(void) 8239760dcaeSOliver Ruiz Dorantes { 8241f2fa6cdSAlexander von Gluck IV CALLED(); 8259760dcaeSOliver Ruiz Dorantes 8261f2fa6cdSAlexander von Gluck IV int32 j; 8279760dcaeSOliver Ruiz Dorantes 8289760dcaeSOliver Ruiz Dorantes for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) { 8299760dcaeSOliver Ruiz Dorantes 8309760dcaeSOliver Ruiz Dorantes if (publish_names[j] != NULL) 8319760dcaeSOliver Ruiz Dorantes free(publish_names[j]); 8329760dcaeSOliver Ruiz Dorantes 8339760dcaeSOliver Ruiz Dorantes if (bt_usb_devices[j] != NULL) { 8349760dcaeSOliver Ruiz Dorantes // if (connected_dev != NULL) { 8359760dcaeSOliver Ruiz Dorantes // debugf("Device %p still exists.\n", connected_dev); 8369760dcaeSOliver Ruiz Dorantes // } 8371f2fa6cdSAlexander von Gluck IV ERROR("%s: %s still present?\n", __func__, bt_usb_devices[j]->name); 8389760dcaeSOliver Ruiz Dorantes kill_device(bt_usb_devices[j]); 8399760dcaeSOliver Ruiz Dorantes } 8409760dcaeSOliver Ruiz Dorantes } 8419760dcaeSOliver Ruiz Dorantes 8429760dcaeSOliver Ruiz Dorantes usb->uninstall_notify(BLUETOOTH_DEVICE_DEVFS_NAME); 8439760dcaeSOliver Ruiz Dorantes 8449760dcaeSOliver Ruiz Dorantes remove_debugger_command("bth2generic", &dump_driver); 8459760dcaeSOliver Ruiz Dorantes 8469760dcaeSOliver Ruiz Dorantes // Releasing modules 8479760dcaeSOliver Ruiz Dorantes put_module(usb_name); 8489760dcaeSOliver Ruiz Dorantes put_module(hci_name); 8499760dcaeSOliver Ruiz Dorantes // TODO: netbuffers 8509760dcaeSOliver Ruiz Dorantes 8519760dcaeSOliver Ruiz Dorantes delete_sem(dev_table_sem); 8529760dcaeSOliver Ruiz Dorantes } 8539760dcaeSOliver Ruiz Dorantes 8549760dcaeSOliver Ruiz Dorantes 8559760dcaeSOliver Ruiz Dorantes const char** 8569760dcaeSOliver Ruiz Dorantes publish_devices(void) 8579760dcaeSOliver Ruiz Dorantes { 8581f2fa6cdSAlexander von Gluck IV CALLED(); 8599760dcaeSOliver Ruiz Dorantes int32 j; 8609760dcaeSOliver Ruiz Dorantes int32 i = 0; 8619760dcaeSOliver Ruiz Dorantes 8629760dcaeSOliver Ruiz Dorantes char* str; 8639760dcaeSOliver Ruiz Dorantes 8649760dcaeSOliver Ruiz Dorantes for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) { 8659760dcaeSOliver Ruiz Dorantes if (publish_names[j]) { 8669760dcaeSOliver Ruiz Dorantes free(publish_names[j]); 8679760dcaeSOliver Ruiz Dorantes publish_names[j] = NULL; 8689760dcaeSOliver Ruiz Dorantes } 8699760dcaeSOliver Ruiz Dorantes } 8709760dcaeSOliver Ruiz Dorantes 8719760dcaeSOliver Ruiz Dorantes acquire_sem(dev_table_sem); 8729760dcaeSOliver Ruiz Dorantes for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) { 8739760dcaeSOliver Ruiz Dorantes if (bt_usb_devices[j] != NULL && bt_usb_devices[j]->connected) { 8749760dcaeSOliver Ruiz Dorantes str = strdup(bt_usb_devices[j]->name); 8759760dcaeSOliver Ruiz Dorantes if (str) { 8769760dcaeSOliver Ruiz Dorantes publish_names[i++] = str; 8771f2fa6cdSAlexander von Gluck IV TRACE("%s: publishing %s\n", __func__, bt_usb_devices[j]->name); 8789760dcaeSOliver Ruiz Dorantes } 8799760dcaeSOliver Ruiz Dorantes } 8809760dcaeSOliver Ruiz Dorantes } 8819760dcaeSOliver Ruiz Dorantes release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); 8829760dcaeSOliver Ruiz Dorantes 8839760dcaeSOliver Ruiz Dorantes publish_names[i] = NULL; 8841f2fa6cdSAlexander von Gluck IV TRACE("%s: published %" B_PRId32 " devices\n", __func__, i); 8859760dcaeSOliver Ruiz Dorantes 8869760dcaeSOliver Ruiz Dorantes // TODO: this method might make better memory use 8879760dcaeSOliver Ruiz Dorantes // dev_names = (char**)malloc(sizeof(char*) * (dev_count + 1)); 8889760dcaeSOliver Ruiz Dorantes // if (dev_names) { 8899760dcaeSOliver Ruiz Dorantes // for (i = 0; i < MAX_NUM_DEVS; i++) { 8909760dcaeSOliver Ruiz Dorantes // if ((dev != NULL) // dev + \n 8919760dcaeSOliver Ruiz Dorantes // && (dev_names[i] = (char*)malloc(strlen(DEVICE_PATH) + 2))) { 8929760dcaeSOliver Ruiz Dorantes // sprintf(dev_names[i], "%s%ld", DEVICE_PATH, dev->num); 8939760dcaeSOliver Ruiz Dorantes // debugf("publishing \"%s\"\n", dev_names[i]); 8949760dcaeSOliver Ruiz Dorantes // } 8959760dcaeSOliver Ruiz Dorantes // } 8969760dcaeSOliver Ruiz Dorantes 8979760dcaeSOliver Ruiz Dorantes return (const char**)publish_names; 8989760dcaeSOliver Ruiz Dorantes } 8999760dcaeSOliver Ruiz Dorantes 9009760dcaeSOliver Ruiz Dorantes 9019760dcaeSOliver Ruiz Dorantes static device_hooks hooks = { 9029760dcaeSOliver Ruiz Dorantes device_open, 9039760dcaeSOliver Ruiz Dorantes device_close, 9049760dcaeSOliver Ruiz Dorantes device_free, 9059760dcaeSOliver Ruiz Dorantes device_control, 9069760dcaeSOliver Ruiz Dorantes device_read, 9079760dcaeSOliver Ruiz Dorantes device_write, 9089760dcaeSOliver Ruiz Dorantes NULL, 9099760dcaeSOliver Ruiz Dorantes NULL, 9109760dcaeSOliver Ruiz Dorantes NULL, 9119760dcaeSOliver Ruiz Dorantes NULL 9129760dcaeSOliver Ruiz Dorantes }; 9139760dcaeSOliver Ruiz Dorantes 9149760dcaeSOliver Ruiz Dorantes 9159760dcaeSOliver Ruiz Dorantes device_hooks* 9169760dcaeSOliver Ruiz Dorantes find_device(const char* name) 9179760dcaeSOliver Ruiz Dorantes { 9181f2fa6cdSAlexander von Gluck IV CALLED(); 9199760dcaeSOliver Ruiz Dorantes 9209760dcaeSOliver Ruiz Dorantes return &hooks; 9219760dcaeSOliver Ruiz Dorantes } 922