xref: /haiku/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2generic.cpp (revision 30e762a797d9e6ef296de60d5f65aacd14359929)
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
616116b3a0SAlexander von Gluck IV 	// MediaTek MT76x0E
626116b3a0SAlexander von Gluck IV 	{ 0, 0, 0, 0x0e8d, 0x763f },
636116b3a0SAlexander von Gluck IV 	// Broadcom SoftSailing reporting vendor specific
646116b3a0SAlexander von Gluck IV 	{ 0, 0, 0, 0x0a5c, 0x21e1 },
656116b3a0SAlexander von Gluck IV 
666116b3a0SAlexander von Gluck IV 	// Apple MacBookPro 7,1
676116b3a0SAlexander von Gluck IV 	{ 0, 0, 0, 0x05ac, 0x8213 },
686116b3a0SAlexander von Gluck IV 	// Apple iMac11,1
696116b3a0SAlexander von Gluck IV 	{ 0, 0, 0, 0x05ac, 0x8215 },
706116b3a0SAlexander von Gluck IV 	// Apple MacBookPro6,2
716116b3a0SAlexander von Gluck IV 	{ 0, 0, 0, 0x05ac, 0x8218 },
726116b3a0SAlexander von Gluck IV 	// Apple MacBookAir3,1, MacBookAir3,2
736116b3a0SAlexander von Gluck IV 	{ 0, 0, 0, 0x05ac, 0x821b },
746116b3a0SAlexander von Gluck IV 	// Apple MacBookAir4,1
756116b3a0SAlexander von Gluck IV 	{ 0, 0, 0, 0x05ac, 0x821f },
766116b3a0SAlexander von Gluck IV 	// Apple MacBookPro8,2
776116b3a0SAlexander von Gluck IV 	{ 0, 0, 0, 0x05ac, 0x821a },
786116b3a0SAlexander von Gluck IV 	// Apple MacMini5,1
796116b3a0SAlexander von Gluck IV 	{ 0, 0, 0, 0x05ac, 0x8281 },
806116b3a0SAlexander von Gluck IV 
819760dcaeSOliver Ruiz Dorantes 	// AVM BlueFRITZ! USB v2.0
829760dcaeSOliver Ruiz Dorantes 	{ 0, 0, 0, 0x057c, 0x3800 },
839760dcaeSOliver Ruiz Dorantes 	// Bluetooth Ultraport Module from IBM
849760dcaeSOliver Ruiz Dorantes 	{ 0, 0, 0, 0x04bf, 0x030a },
859760dcaeSOliver Ruiz Dorantes 	// ALPS Modules with non-standard id
869760dcaeSOliver Ruiz Dorantes 	{ 0, 0, 0, 0x044e, 0x3001 },
879760dcaeSOliver Ruiz Dorantes 	{ 0, 0, 0, 0x044e, 0x3002 },
889760dcaeSOliver Ruiz Dorantes 	// Ericsson with non-standard id
896116b3a0SAlexander von Gluck IV 	{ 0, 0, 0, 0x0bdb, 0x1002 },
906116b3a0SAlexander von Gluck IV 
916116b3a0SAlexander von Gluck IV 	// Canyon CN-BTU1 with HID interfaces
926116b3a0SAlexander von Gluck IV 	{ 0, 0, 0, 0x0c10, 0x0000 },
936116b3a0SAlexander von Gluck IV 
946116b3a0SAlexander von Gluck IV 	// Broadcom BCM20702A0
956116b3a0SAlexander von Gluck IV 	{ 0, 0, 0, 0x413c, 0x8197 },
966116b3a0SAlexander von Gluck IV 
979760dcaeSOliver Ruiz Dorantes };
989760dcaeSOliver Ruiz Dorantes 
999760dcaeSOliver Ruiz Dorantes /* add a device to the list of connected devices */
1009760dcaeSOliver Ruiz Dorantes static bt_usb_dev*
spawn_device(usb_device usb_dev)1019760dcaeSOliver Ruiz Dorantes spawn_device(usb_device usb_dev)
1029760dcaeSOliver Ruiz Dorantes {
1031f2fa6cdSAlexander von Gluck IV 	CALLED();
1041f2fa6cdSAlexander von Gluck IV 
1059760dcaeSOliver Ruiz Dorantes 	int32 i;
1069760dcaeSOliver Ruiz Dorantes 	status_t err = B_OK;
1079760dcaeSOliver Ruiz Dorantes 	bt_usb_dev* new_bt_dev = NULL;
1089760dcaeSOliver Ruiz Dorantes 
1099760dcaeSOliver Ruiz Dorantes 	// 16 usb dongles...
1109760dcaeSOliver Ruiz Dorantes 	if (dev_count >= MAX_BT_GENERIC_USB_DEVICES) {
1111f2fa6cdSAlexander von Gluck IV 		ERROR("%s: Device table full\n", __func__);
1129760dcaeSOliver Ruiz Dorantes 		goto exit;
1139760dcaeSOliver Ruiz Dorantes 	}
1149760dcaeSOliver Ruiz Dorantes 
1159760dcaeSOliver Ruiz Dorantes 	// try the allocation
1169760dcaeSOliver Ruiz Dorantes 	new_bt_dev = (bt_usb_dev*)malloc(sizeof(bt_usb_dev));
1179760dcaeSOliver Ruiz Dorantes 	if (new_bt_dev == NULL) {
1181f2fa6cdSAlexander von Gluck IV 		ERROR("%s: Unable to malloc new bt device\n", __func__);
1199760dcaeSOliver Ruiz Dorantes 		goto exit;
1209760dcaeSOliver Ruiz Dorantes 	}
1219760dcaeSOliver Ruiz Dorantes 	memset(new_bt_dev, 0, sizeof(bt_usb_dev));
1229760dcaeSOliver Ruiz Dorantes 
1239760dcaeSOliver Ruiz Dorantes 	// We will need this sem for some flow control
1249760dcaeSOliver Ruiz Dorantes 	new_bt_dev->cmd_complete = create_sem(1,
1259760dcaeSOliver Ruiz Dorantes 		BLUETOOTH_DEVICE_DEVFS_NAME "cmd_complete");
1269760dcaeSOliver Ruiz Dorantes 	if (new_bt_dev->cmd_complete < 0) {
1279760dcaeSOliver Ruiz Dorantes 		err = new_bt_dev->cmd_complete;
128*30e762a7SPulkoMandy 		ERROR("%s: Unable to create bt device command semaphore: %" B_PRId32 "\n", __func__, err);
1299760dcaeSOliver Ruiz Dorantes 		goto bail0;
1309760dcaeSOliver Ruiz Dorantes 	}
1319760dcaeSOliver Ruiz Dorantes 
1329760dcaeSOliver Ruiz Dorantes 	// and this for something else
1339760dcaeSOliver Ruiz Dorantes 	new_bt_dev->lock = create_sem(1, BLUETOOTH_DEVICE_DEVFS_NAME "lock");
1349760dcaeSOliver Ruiz Dorantes 	if (new_bt_dev->lock < 0) {
1359760dcaeSOliver Ruiz Dorantes 		err = new_bt_dev->lock;
136*30e762a7SPulkoMandy 		ERROR("%s: Unable to create bt device lock semaphore: %" B_PRId32 "\n", __func__, err);
1379760dcaeSOliver Ruiz Dorantes 		goto bail1;
1389760dcaeSOliver Ruiz Dorantes 	}
1399760dcaeSOliver Ruiz Dorantes 
1409760dcaeSOliver Ruiz Dorantes 	// find a free slot and fill out the name
1419760dcaeSOliver Ruiz Dorantes 	acquire_sem(dev_table_sem);
1429760dcaeSOliver Ruiz Dorantes 	for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) {
1439760dcaeSOliver Ruiz Dorantes 		if (bt_usb_devices[i] == NULL) {
1449760dcaeSOliver Ruiz Dorantes 			bt_usb_devices[i] = new_bt_dev;
145f2986394SAlexander von Gluck IV 			sprintf(new_bt_dev->name, "%s/%" B_PRId32,
146f2986394SAlexander von Gluck IV 				BLUETOOTH_DEVICE_PATH, i);
1479760dcaeSOliver Ruiz Dorantes 			new_bt_dev->num = i;
1481f2fa6cdSAlexander von Gluck IV 			TRACE("%s: added device %p %" B_PRId32 " %s\n", __func__,
1491f2fa6cdSAlexander von Gluck IV 				bt_usb_devices[i], new_bt_dev->num, new_bt_dev->name);
1509760dcaeSOliver Ruiz Dorantes 			break;
1519760dcaeSOliver Ruiz Dorantes 		}
1529760dcaeSOliver Ruiz Dorantes 	}
1539760dcaeSOliver Ruiz Dorantes 	release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE);
1549760dcaeSOliver Ruiz Dorantes 
155446dc38fSLee Mon 	// In the case we cannot find a free slot
156446dc38fSLee Mon 	if (i >= MAX_BT_GENERIC_USB_DEVICES) {
1571f2fa6cdSAlexander von Gluck IV 		ERROR("%s: Device could not be added\n", __func__);
1589760dcaeSOliver Ruiz Dorantes 		goto bail2;
1599760dcaeSOliver Ruiz Dorantes 	}
1609760dcaeSOliver Ruiz Dorantes 
1619760dcaeSOliver Ruiz Dorantes 	new_bt_dev->dev = usb_dev;
1629760dcaeSOliver Ruiz Dorantes 	// TODO: currently only server opens
1639760dcaeSOliver Ruiz Dorantes 	new_bt_dev->open_count = 0;
1649760dcaeSOliver Ruiz Dorantes 
1659760dcaeSOliver Ruiz Dorantes 	dev_count++;
1669760dcaeSOliver Ruiz Dorantes 	return new_bt_dev;
1679760dcaeSOliver Ruiz Dorantes 
1689760dcaeSOliver Ruiz Dorantes bail2:
1699760dcaeSOliver Ruiz Dorantes 	delete_sem(new_bt_dev->lock);
1709760dcaeSOliver Ruiz Dorantes bail1:
1719760dcaeSOliver Ruiz Dorantes 	delete_sem(new_bt_dev->cmd_complete);
1729760dcaeSOliver Ruiz Dorantes bail0:
1739760dcaeSOliver Ruiz Dorantes 	free(new_bt_dev);
1747cfdd924SMurai Takashi 	new_bt_dev = NULL;
1759760dcaeSOliver Ruiz Dorantes exit:
1769760dcaeSOliver Ruiz Dorantes 	return new_bt_dev;
1779760dcaeSOliver Ruiz Dorantes }
1789760dcaeSOliver Ruiz Dorantes 
1799760dcaeSOliver Ruiz Dorantes 
1809760dcaeSOliver Ruiz Dorantes // remove a device from the list of connected devices
1819760dcaeSOliver Ruiz Dorantes static void
kill_device(bt_usb_dev * bdev)1829760dcaeSOliver Ruiz Dorantes kill_device(bt_usb_dev* bdev)
1839760dcaeSOliver Ruiz Dorantes {
1849760dcaeSOliver Ruiz Dorantes 	if (bdev != NULL) {
1851f2fa6cdSAlexander von Gluck IV 		TRACE("%s: (%p)\n", __func__, bdev);
1869760dcaeSOliver Ruiz Dorantes 
1879760dcaeSOliver Ruiz Dorantes 		delete_sem(bdev->lock);
1889760dcaeSOliver Ruiz Dorantes 		delete_sem(bdev->cmd_complete);
1899760dcaeSOliver Ruiz Dorantes 
1909760dcaeSOliver Ruiz Dorantes 		// mark it free
1919760dcaeSOliver Ruiz Dorantes 		bt_usb_devices[bdev->num] = NULL;
1929760dcaeSOliver Ruiz Dorantes 
1939760dcaeSOliver Ruiz Dorantes 		free(bdev);
1949760dcaeSOliver Ruiz Dorantes 		dev_count--;
1959760dcaeSOliver Ruiz Dorantes 	}
1969760dcaeSOliver Ruiz Dorantes }
1979760dcaeSOliver Ruiz Dorantes 
1989760dcaeSOliver Ruiz Dorantes 
1999760dcaeSOliver Ruiz Dorantes bt_usb_dev*
fetch_device(bt_usb_dev * dev,hci_id hid)2009760dcaeSOliver Ruiz Dorantes fetch_device(bt_usb_dev* dev, hci_id hid)
2019760dcaeSOliver Ruiz Dorantes {
2029760dcaeSOliver Ruiz Dorantes 	int i;
2039760dcaeSOliver Ruiz Dorantes 
2041f2fa6cdSAlexander von Gluck IV //	TRACE("%s: (%p) or %d\n", __func__, dev, hid);
2059760dcaeSOliver Ruiz Dorantes 
2069760dcaeSOliver Ruiz Dorantes 	acquire_sem(dev_table_sem);
207f2986394SAlexander von Gluck IV 	if (dev != NULL) {
2089760dcaeSOliver Ruiz Dorantes 		for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) {
2099760dcaeSOliver Ruiz Dorantes 			if (bt_usb_devices[i] == dev) {
2109760dcaeSOliver Ruiz Dorantes 				release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE);
2119760dcaeSOliver Ruiz Dorantes 				return bt_usb_devices[i];
2129760dcaeSOliver Ruiz Dorantes 			}
2139760dcaeSOliver Ruiz Dorantes 		}
214f2986394SAlexander von Gluck IV 	} else {
2159760dcaeSOliver Ruiz Dorantes 		for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) {
2169760dcaeSOliver Ruiz Dorantes 			if (bt_usb_devices[i] != NULL && bt_usb_devices[i]->hdev == hid) {
2179760dcaeSOliver Ruiz Dorantes 				release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE);
2189760dcaeSOliver Ruiz Dorantes 				return bt_usb_devices[i];
2199760dcaeSOliver Ruiz Dorantes 			}
2209760dcaeSOliver Ruiz Dorantes 		}
221f2986394SAlexander von Gluck IV 	}
2229760dcaeSOliver Ruiz Dorantes 
2239760dcaeSOliver Ruiz Dorantes 	release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE);
2249760dcaeSOliver Ruiz Dorantes 
2259760dcaeSOliver Ruiz Dorantes 	return NULL;
2269760dcaeSOliver Ruiz Dorantes }
2279760dcaeSOliver Ruiz Dorantes 
2289760dcaeSOliver Ruiz Dorantes 
2299760dcaeSOliver Ruiz Dorantes #if 0
2309760dcaeSOliver Ruiz Dorantes #pragma mark -
2319760dcaeSOliver Ruiz Dorantes #endif
2329760dcaeSOliver Ruiz Dorantes 
2339760dcaeSOliver Ruiz Dorantes // called by USB Manager when device is added to the USB
2349760dcaeSOliver Ruiz Dorantes static status_t
device_added(usb_device dev,void ** cookie)2359760dcaeSOliver Ruiz Dorantes device_added(usb_device dev, void** cookie)
2369760dcaeSOliver Ruiz Dorantes {
2379760dcaeSOliver Ruiz Dorantes 	const usb_interface_info* 		interface;
2389760dcaeSOliver Ruiz Dorantes 	const usb_device_descriptor* 	desc;
2399760dcaeSOliver Ruiz Dorantes 	const usb_configuration_info*	config;
2409760dcaeSOliver Ruiz Dorantes 	const usb_interface_info*		uif;
2419760dcaeSOliver Ruiz Dorantes 	const usb_endpoint_info*		ep;
2429760dcaeSOliver Ruiz Dorantes 
2439760dcaeSOliver Ruiz Dorantes 	status_t 	err = B_ERROR;
2449760dcaeSOliver Ruiz Dorantes 	bt_usb_dev* new_bt_dev = spawn_device(dev);
2459760dcaeSOliver Ruiz Dorantes 	int e;
2469760dcaeSOliver Ruiz Dorantes 
2471f2fa6cdSAlexander von Gluck IV 	TRACE("%s: device_added(%p)\n", __func__, new_bt_dev);
2489760dcaeSOliver Ruiz Dorantes 
2499760dcaeSOliver Ruiz Dorantes 	if (new_bt_dev == NULL) {
2501f2fa6cdSAlexander von Gluck IV 		ERROR("%s: Couldn't allocate device record.\n", __func__);
2519760dcaeSOliver Ruiz Dorantes 		err = ENOMEM;
2529760dcaeSOliver Ruiz Dorantes 		goto bail_no_mem;
2539760dcaeSOliver Ruiz Dorantes 	}
2549760dcaeSOliver Ruiz Dorantes 
2559760dcaeSOliver Ruiz Dorantes 	// we only have 1 configuration number 0
2569760dcaeSOliver Ruiz Dorantes 	config = usb->get_nth_configuration(dev, 0);
2579760dcaeSOliver Ruiz Dorantes 	// dump_usb_configuration_info(config);
2589760dcaeSOliver Ruiz Dorantes 	if (config == NULL) {
2591f2fa6cdSAlexander von Gluck IV 		ERROR("%s: Couldn't get default USB config.\n", __func__);
2609760dcaeSOliver Ruiz Dorantes 		err = B_ERROR;
2619760dcaeSOliver Ruiz Dorantes 		goto bail;
2629760dcaeSOliver Ruiz Dorantes 	}
2639760dcaeSOliver Ruiz Dorantes 
2641f2fa6cdSAlexander von Gluck IV 	TRACE("%s: found %" B_PRIuSIZE " alt interfaces.\n", __func__,
265f2986394SAlexander von Gluck IV 		config->interface->alt_count);
2669760dcaeSOliver Ruiz Dorantes 
2679760dcaeSOliver Ruiz Dorantes 	// set first interface
2689760dcaeSOliver Ruiz Dorantes 	interface = &config->interface->alt[0];
2699760dcaeSOliver Ruiz Dorantes 	err = usb->set_alt_interface(new_bt_dev->dev, interface);
2709760dcaeSOliver Ruiz Dorantes 
2719760dcaeSOliver Ruiz Dorantes 	if (err != B_OK) {
2721f2fa6cdSAlexander von Gluck IV 		ERROR("%s: set_alt_interface() error.\n", __func__);
2739760dcaeSOliver Ruiz Dorantes 		goto bail;
2749760dcaeSOliver Ruiz Dorantes 	}
2759760dcaeSOliver Ruiz Dorantes 
2769760dcaeSOliver Ruiz Dorantes 	// call set_configuration() only after calling set_alt_interface()
2779760dcaeSOliver Ruiz Dorantes 	err = usb->set_configuration(dev, config);
2789760dcaeSOliver Ruiz Dorantes 	if (err != B_OK) {
2791f2fa6cdSAlexander von Gluck IV 		ERROR("%s: set_configuration() error.\n", __func__);
2809760dcaeSOliver Ruiz Dorantes 		goto bail;
2819760dcaeSOliver Ruiz Dorantes 	}
2829760dcaeSOliver Ruiz Dorantes 
2839760dcaeSOliver Ruiz Dorantes 	// Place to find out whats our concrete device and set up some special
2849760dcaeSOliver Ruiz Dorantes 	// info to our driver. If this code increases too much reconsider
2859760dcaeSOliver Ruiz Dorantes 	// this implementation
2869760dcaeSOliver Ruiz Dorantes 	desc = usb->get_device_descriptor(dev);
2879760dcaeSOliver Ruiz Dorantes 	if (desc->vendor_id == 0x0a5c
2889760dcaeSOliver Ruiz Dorantes 		&& (desc->product_id == 0x200a
2899760dcaeSOliver Ruiz Dorantes 			|| desc->product_id == 0x2009
2909760dcaeSOliver Ruiz Dorantes 			|| desc->product_id == 0x2035)) {
2919760dcaeSOliver Ruiz Dorantes 
2929760dcaeSOliver Ruiz Dorantes 		new_bt_dev->driver_info = BT_WILL_NEED_A_RESET | BT_SCO_NOT_WORKING;
2939760dcaeSOliver Ruiz Dorantes 
2949760dcaeSOliver Ruiz Dorantes 	}
2959760dcaeSOliver Ruiz Dorantes 	/*
2969760dcaeSOliver Ruiz Dorantes 	else if ( desc->vendor_id == YOUR_VENDOR_HERE
2979760dcaeSOliver Ruiz Dorantes 		&& desc->product_id == YOUR_PRODUCT_HERE ) {
2989760dcaeSOliver Ruiz Dorantes 		YOUR_SPECIAL_FLAGS_HERE
2999760dcaeSOliver Ruiz Dorantes 	}
3009760dcaeSOliver Ruiz Dorantes 	*/
3019760dcaeSOliver Ruiz Dorantes 
3029760dcaeSOliver Ruiz Dorantes 	if (new_bt_dev->driver_info & BT_IGNORE_THIS_DEVICE) {
3039760dcaeSOliver Ruiz Dorantes 		err = ENODEV;
3049760dcaeSOliver Ruiz Dorantes 		goto bail;
3059760dcaeSOliver Ruiz Dorantes 	}
3069760dcaeSOliver Ruiz Dorantes 
3079760dcaeSOliver Ruiz Dorantes 	// security check
3089760dcaeSOliver Ruiz Dorantes 	if (config->interface->active->descr->interface_number > 0) {
3091f2fa6cdSAlexander von Gluck IV 		ERROR("%s: Strange condition happened %d\n", __func__,
3109760dcaeSOliver Ruiz Dorantes 			config->interface->active->descr->interface_number);
3119760dcaeSOliver Ruiz Dorantes 		err = B_ERROR;
3129760dcaeSOliver Ruiz Dorantes 		goto bail;
3139760dcaeSOliver Ruiz Dorantes 	}
3149760dcaeSOliver Ruiz Dorantes 
3151f2fa6cdSAlexander von Gluck IV 	TRACE("%s: Found %" B_PRIuSIZE " interfaces. Expected 3\n", __func__,
316f2986394SAlexander von Gluck IV 		config->interface_count);
317f2986394SAlexander von Gluck IV 
3189760dcaeSOliver Ruiz Dorantes 	// Find endpoints that we need
3199760dcaeSOliver Ruiz Dorantes 	uif = config->interface->active;
3209760dcaeSOliver Ruiz Dorantes 	for (e = 0; e < uif->descr->num_endpoints; e++) {
3219760dcaeSOliver Ruiz Dorantes 
3229760dcaeSOliver Ruiz Dorantes 		ep = &uif->endpoint[e];
3239760dcaeSOliver Ruiz Dorantes 		switch (ep->descr->attributes & USB_ENDPOINT_ATTR_MASK) {
3249760dcaeSOliver Ruiz Dorantes 			case USB_ENDPOINT_ATTR_INTERRUPT:
3259760dcaeSOliver Ruiz Dorantes 				if (ep->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN)
3269760dcaeSOliver Ruiz Dorantes 				{
3279760dcaeSOliver Ruiz Dorantes 					new_bt_dev->intr_in_ep = ep;
3281f2fa6cdSAlexander von Gluck IV 					new_bt_dev->max_packet_size_intr_in
3291f2fa6cdSAlexander von Gluck IV 						= ep->descr->max_packet_size;
3301f2fa6cdSAlexander von Gluck IV 					TRACE("%s: INT in\n", __func__);
3319760dcaeSOliver Ruiz Dorantes 				} else {
3321f2fa6cdSAlexander von Gluck IV 					TRACE("%s: INT out\n", __func__);
3339760dcaeSOliver Ruiz Dorantes 				}
3349760dcaeSOliver Ruiz Dorantes 			break;
3359760dcaeSOliver Ruiz Dorantes 
3369760dcaeSOliver Ruiz Dorantes 			case USB_ENDPOINT_ATTR_BULK:
3379760dcaeSOliver Ruiz Dorantes 				if (ep->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN)	{
3389760dcaeSOliver Ruiz Dorantes 					new_bt_dev->bulk_in_ep  = ep;
3391f2fa6cdSAlexander von Gluck IV 					new_bt_dev->max_packet_size_bulk_in
3401f2fa6cdSAlexander von Gluck IV 						= ep->descr->max_packet_size;
3411f2fa6cdSAlexander von Gluck IV 					TRACE("%s: BULK int\n", __func__);
3429760dcaeSOliver Ruiz Dorantes 				} else	{
3439760dcaeSOliver Ruiz Dorantes 					new_bt_dev->bulk_out_ep = ep;
3441f2fa6cdSAlexander von Gluck IV 					new_bt_dev->max_packet_size_bulk_out
3451f2fa6cdSAlexander von Gluck IV 						= ep->descr->max_packet_size;
3461f2fa6cdSAlexander von Gluck IV 					TRACE("%s: BULK out\n", __func__);
3479760dcaeSOliver Ruiz Dorantes 				}
3489760dcaeSOliver Ruiz Dorantes 			break;
3499760dcaeSOliver Ruiz Dorantes 		}
3509760dcaeSOliver Ruiz Dorantes 	}
3519760dcaeSOliver Ruiz Dorantes 
3529760dcaeSOliver Ruiz Dorantes 	if (!new_bt_dev->bulk_in_ep || !new_bt_dev->bulk_out_ep
3539760dcaeSOliver Ruiz Dorantes 		|| !new_bt_dev->intr_in_ep) {
3541f2fa6cdSAlexander von Gluck IV 		ERROR("%s: Minimal # endpoints for BT not found\n", __func__);
3559760dcaeSOliver Ruiz Dorantes 		goto bail;
3569760dcaeSOliver Ruiz Dorantes 	}
3579760dcaeSOliver Ruiz Dorantes 
3589760dcaeSOliver Ruiz Dorantes 	// Look into the devices suported to understand this
3599760dcaeSOliver Ruiz Dorantes 	if (new_bt_dev->driver_info & BT_DIGIANSWER)
3609760dcaeSOliver Ruiz Dorantes 		new_bt_dev->ctrl_req = USB_TYPE_VENDOR;
3619760dcaeSOliver Ruiz Dorantes 	else
3629760dcaeSOliver Ruiz Dorantes 		new_bt_dev->ctrl_req = USB_TYPE_CLASS;
3639760dcaeSOliver Ruiz Dorantes 
3649760dcaeSOliver Ruiz Dorantes 	new_bt_dev->connected = true;
3659760dcaeSOliver Ruiz Dorantes 
3669760dcaeSOliver Ruiz Dorantes 	// set the cookie that will be passed to other USB
3679760dcaeSOliver Ruiz Dorantes 	// hook functions (currently device_removed() is the only other)
3689760dcaeSOliver Ruiz Dorantes 	*cookie = new_bt_dev;
3691f2fa6cdSAlexander von Gluck IV 	TRACE("%s: Ok %p\n", __func__, new_bt_dev);
3709760dcaeSOliver Ruiz Dorantes 	return B_OK;
3719760dcaeSOliver Ruiz Dorantes 
3729760dcaeSOliver Ruiz Dorantes bail:
3739760dcaeSOliver Ruiz Dorantes 	kill_device(new_bt_dev);
3749760dcaeSOliver Ruiz Dorantes bail_no_mem:
3759760dcaeSOliver Ruiz Dorantes 	*cookie = NULL;
3769760dcaeSOliver Ruiz Dorantes 
3779760dcaeSOliver Ruiz Dorantes 	return err;
3789760dcaeSOliver Ruiz Dorantes }
3799760dcaeSOliver Ruiz Dorantes 
3809760dcaeSOliver Ruiz Dorantes 
3819760dcaeSOliver Ruiz Dorantes // Called by USB Manager when device is removed from the USB
3829760dcaeSOliver Ruiz Dorantes static status_t
device_removed(void * cookie)3839760dcaeSOliver Ruiz Dorantes device_removed(void* cookie)
3849760dcaeSOliver Ruiz Dorantes {
3859760dcaeSOliver Ruiz Dorantes 	bt_usb_dev* bdev = fetch_device((bt_usb_dev*)cookie, 0);
3869760dcaeSOliver Ruiz Dorantes 
3871f2fa6cdSAlexander von Gluck IV 	TRACE("%s: device_removed(%p)\n", __func__, bdev);
3889760dcaeSOliver Ruiz Dorantes 
3899760dcaeSOliver Ruiz Dorantes 	if (bdev == NULL) {
3901f2fa6cdSAlexander von Gluck IV 		ERROR("%s: Device not present in driver.\n", __func__);
3919760dcaeSOliver Ruiz Dorantes 		return B_ERROR;
3929760dcaeSOliver Ruiz Dorantes 	}
3939760dcaeSOliver Ruiz Dorantes 
3949760dcaeSOliver Ruiz Dorantes 	if (!TEST_AND_CLEAR(&bdev->state, RUNNING))
3951f2fa6cdSAlexander von Gluck IV 		ERROR("%s: wasnt running?\n", __func__);
3969760dcaeSOliver Ruiz Dorantes 
3971f2fa6cdSAlexander von Gluck IV 	TRACE("%s: Cancelling queues...\n", __func__);
3981f2fa6cdSAlexander von Gluck IV 	if (bdev->intr_in_ep != NULL)
3999760dcaeSOliver Ruiz Dorantes 		usb->cancel_queued_transfers(bdev->intr_in_ep->handle);
4001f2fa6cdSAlexander von Gluck IV 	if (bdev->bulk_in_ep != NULL)
4019760dcaeSOliver Ruiz Dorantes 		usb->cancel_queued_transfers(bdev->bulk_in_ep->handle);
4021f2fa6cdSAlexander von Gluck IV 	if (bdev->bulk_out_ep != NULL)
4039760dcaeSOliver Ruiz Dorantes 		usb->cancel_queued_transfers(bdev->bulk_out_ep->handle);
4049760dcaeSOliver Ruiz Dorantes 
4059760dcaeSOliver Ruiz Dorantes 	bdev->connected = false;
4069760dcaeSOliver Ruiz Dorantes 
4079760dcaeSOliver Ruiz Dorantes 	return B_OK;
4089760dcaeSOliver Ruiz Dorantes }
4099760dcaeSOliver Ruiz Dorantes 
4109760dcaeSOliver Ruiz Dorantes 
4119760dcaeSOliver Ruiz Dorantes static bt_hci_transport_hooks bluetooth_hooks = {
4129760dcaeSOliver Ruiz Dorantes 	NULL,
4139760dcaeSOliver Ruiz Dorantes 	&submit_nbuffer,
4149760dcaeSOliver Ruiz Dorantes 	&submit_nbuffer,
4159760dcaeSOliver Ruiz Dorantes 	NULL,
4169760dcaeSOliver Ruiz Dorantes 	NULL,
4179760dcaeSOliver Ruiz Dorantes 	H2
4189760dcaeSOliver Ruiz Dorantes };
4199760dcaeSOliver Ruiz Dorantes 
4209760dcaeSOliver Ruiz Dorantes 
4219760dcaeSOliver Ruiz Dorantes static usb_notify_hooks notify_hooks = {
4229760dcaeSOliver Ruiz Dorantes 	&device_added,
4239760dcaeSOliver Ruiz Dorantes 	&device_removed
4249760dcaeSOliver Ruiz Dorantes };
4259760dcaeSOliver Ruiz Dorantes 
4269760dcaeSOliver Ruiz Dorantes #if 0
4279760dcaeSOliver Ruiz Dorantes #pragma mark -
4289760dcaeSOliver Ruiz Dorantes #endif
4299760dcaeSOliver Ruiz Dorantes 
4309760dcaeSOliver Ruiz Dorantes status_t
submit_nbuffer(hci_id hid,net_buffer * nbuf)4319760dcaeSOliver Ruiz Dorantes submit_nbuffer(hci_id hid, net_buffer* nbuf)
4329760dcaeSOliver Ruiz Dorantes {
4339760dcaeSOliver Ruiz Dorantes 	bt_usb_dev* bdev = NULL;
4349760dcaeSOliver Ruiz Dorantes 
4359760dcaeSOliver Ruiz Dorantes 	bdev = fetch_device(NULL, hid);
4369760dcaeSOliver Ruiz Dorantes 
4371f2fa6cdSAlexander von Gluck IV 	TRACE("%s: index=%" B_PRId32 " nbuf=%p bdev=%p\n", __func__, hid,
4381f2fa6cdSAlexander von Gluck IV 		nbuf, bdev);
4399760dcaeSOliver Ruiz Dorantes 
4409760dcaeSOliver Ruiz Dorantes 	if (bdev != NULL) {
4419760dcaeSOliver Ruiz Dorantes 		switch (nbuf->protocol) {
4429760dcaeSOliver Ruiz Dorantes 			case BT_COMMAND:
4439760dcaeSOliver Ruiz Dorantes 				// not issued this way
4449760dcaeSOliver Ruiz Dorantes 			break;
4459760dcaeSOliver Ruiz Dorantes 
4469760dcaeSOliver Ruiz Dorantes 			case BT_ACL:
4479760dcaeSOliver Ruiz Dorantes 				return submit_tx_acl(bdev, nbuf);
4489760dcaeSOliver Ruiz Dorantes 			break;
4499760dcaeSOliver Ruiz Dorantes 
4509760dcaeSOliver Ruiz Dorantes 			default:
4519760dcaeSOliver Ruiz Dorantes 				panic("submit_nbuffer: no protocol");
4529760dcaeSOliver Ruiz Dorantes 			break;
4539760dcaeSOliver Ruiz Dorantes 
4549760dcaeSOliver Ruiz Dorantes 		}
4559760dcaeSOliver Ruiz Dorantes 	}
4569760dcaeSOliver Ruiz Dorantes 
4579760dcaeSOliver Ruiz Dorantes 	return B_ERROR;
4589760dcaeSOliver Ruiz Dorantes 
4599760dcaeSOliver Ruiz Dorantes }
4609760dcaeSOliver Ruiz Dorantes 
4619760dcaeSOliver Ruiz Dorantes 
4629760dcaeSOliver Ruiz Dorantes // implements the POSIX open()
4639760dcaeSOliver Ruiz Dorantes static status_t
device_open(const char * name,uint32 flags,void ** cookie)4649760dcaeSOliver Ruiz Dorantes device_open(const char* name, uint32 flags, void **cookie)
4659760dcaeSOliver Ruiz Dorantes {
4661f2fa6cdSAlexander von Gluck IV 	CALLED();
4671f2fa6cdSAlexander von Gluck IV 
4689760dcaeSOliver Ruiz Dorantes 	status_t err = ENODEV;
4699760dcaeSOliver Ruiz Dorantes 	bt_usb_dev* bdev = NULL;
4709760dcaeSOliver Ruiz Dorantes 	hci_id hdev;
4719760dcaeSOliver Ruiz Dorantes 	int i;
4729760dcaeSOliver Ruiz Dorantes 
4739760dcaeSOliver Ruiz Dorantes 	acquire_sem(dev_table_sem);
4749760dcaeSOliver Ruiz Dorantes 	for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) {
4759760dcaeSOliver Ruiz Dorantes 		if (bt_usb_devices[i] && !strcmp(name, bt_usb_devices[i]->name)) {
4769760dcaeSOliver Ruiz Dorantes 			bdev = bt_usb_devices[i];
4779760dcaeSOliver Ruiz Dorantes 			break;
4789760dcaeSOliver Ruiz Dorantes 		}
4799760dcaeSOliver Ruiz Dorantes 	}
4809760dcaeSOliver Ruiz Dorantes 	release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE);
4819760dcaeSOliver Ruiz Dorantes 
4829760dcaeSOliver Ruiz Dorantes 	if (bdev == NULL) {
4831f2fa6cdSAlexander von Gluck IV 		ERROR("%s: Device not found in the open list!", __func__);
4849760dcaeSOliver Ruiz Dorantes 		*cookie = NULL;
4859760dcaeSOliver Ruiz Dorantes 		return B_ERROR;
4869760dcaeSOliver Ruiz Dorantes 	}
4879760dcaeSOliver Ruiz Dorantes 
4889760dcaeSOliver Ruiz Dorantes 	// Set RUNNING
4899760dcaeSOliver Ruiz Dorantes 	if (TEST_AND_SET(&bdev->state, RUNNING)) {
4901f2fa6cdSAlexander von Gluck IV 		ERROR("%s: dev already running! - reOpened device!\n", __func__);
4919760dcaeSOliver Ruiz Dorantes 		return B_ERROR;
4929760dcaeSOliver Ruiz Dorantes 	}
4939760dcaeSOliver Ruiz Dorantes 
4949760dcaeSOliver Ruiz Dorantes 	acquire_sem(bdev->lock);
4959760dcaeSOliver Ruiz Dorantes 	// TX structures
4969760dcaeSOliver Ruiz Dorantes 	for (i = 0; i < BT_DRIVER_TXCOVERAGE; i++) {
4979760dcaeSOliver Ruiz Dorantes 		list_init(&bdev->nbuffersTx[i]);
4989760dcaeSOliver Ruiz Dorantes 		bdev->nbuffersPendingTx[i] = 0;
4999760dcaeSOliver Ruiz Dorantes 	}
5009760dcaeSOliver Ruiz Dorantes 
5019760dcaeSOliver Ruiz Dorantes 	// RX structures
5029760dcaeSOliver Ruiz Dorantes 	bdev->eventRx = NULL;
5039760dcaeSOliver Ruiz Dorantes 	for (i = 0; i < BT_DRIVER_RXCOVERAGE; i++) {
5049760dcaeSOliver Ruiz Dorantes 		bdev->nbufferRx[i] = NULL;
5059760dcaeSOliver Ruiz Dorantes 	}
5069760dcaeSOliver Ruiz Dorantes 
5079760dcaeSOliver Ruiz Dorantes 	// dumping the USB frames
5089760dcaeSOliver Ruiz Dorantes 	init_room(&bdev->eventRoom);
5099760dcaeSOliver Ruiz Dorantes 	init_room(&bdev->aclRoom);
5109760dcaeSOliver Ruiz Dorantes 	// init_room(new_bt_dev->scoRoom);
5119760dcaeSOliver Ruiz Dorantes 
5129760dcaeSOliver Ruiz Dorantes 	list_init(&bdev->snetBufferRecycleTrash);
5139760dcaeSOliver Ruiz Dorantes 
5149760dcaeSOliver Ruiz Dorantes 	// Allocate set and register the HCI device
5159760dcaeSOliver Ruiz Dorantes 	if (btDevices != NULL) {
5169760dcaeSOliver Ruiz Dorantes 		bluetooth_device* ndev;
5179760dcaeSOliver Ruiz Dorantes 		// TODO: Fill the transport descriptor
5189760dcaeSOliver Ruiz Dorantes 		err = btDevices->RegisterDriver(&bluetooth_hooks, &ndev);
5199760dcaeSOliver Ruiz Dorantes 
5209760dcaeSOliver Ruiz Dorantes 		if (err == B_OK) {
5219760dcaeSOliver Ruiz Dorantes 			bdev->hdev = hdev = ndev->index; // Get the index
5229760dcaeSOliver Ruiz Dorantes 			bdev->ndev = ndev;  // Get the net_device
5239760dcaeSOliver Ruiz Dorantes 
5249760dcaeSOliver Ruiz Dorantes 		} else {
5259760dcaeSOliver Ruiz Dorantes 			hdev = bdev->num; // XXX: Lets try to go on
5269760dcaeSOliver Ruiz Dorantes 		}
5279760dcaeSOliver Ruiz Dorantes 	} else {
5289760dcaeSOliver Ruiz Dorantes 		hdev = bdev->num; // XXX: Lets try to go on
5299760dcaeSOliver Ruiz Dorantes 	}
5309760dcaeSOliver Ruiz Dorantes 
5319760dcaeSOliver Ruiz Dorantes 	bdev->hdev = hdev;
5329760dcaeSOliver Ruiz Dorantes 
5339760dcaeSOliver Ruiz Dorantes 	*cookie = bdev;
5349760dcaeSOliver Ruiz Dorantes 	release_sem(bdev->lock);
5359760dcaeSOliver Ruiz Dorantes 
5369760dcaeSOliver Ruiz Dorantes 	return B_OK;
5379760dcaeSOliver Ruiz Dorantes 
5389760dcaeSOliver Ruiz Dorantes }
5399760dcaeSOliver Ruiz Dorantes 
5409760dcaeSOliver Ruiz Dorantes 
5419760dcaeSOliver Ruiz Dorantes /* called when a client calls POSIX close() on the driver, but I/O
5429760dcaeSOliver Ruiz Dorantes  * requests may still be pending
5439760dcaeSOliver Ruiz Dorantes  */
5449760dcaeSOliver Ruiz Dorantes static status_t
device_close(void * cookie)5459760dcaeSOliver Ruiz Dorantes device_close(void* cookie)
5469760dcaeSOliver Ruiz Dorantes {
5471f2fa6cdSAlexander von Gluck IV 	CALLED();
5481f2fa6cdSAlexander von Gluck IV 
5499760dcaeSOliver Ruiz Dorantes 	int32 i;
5509760dcaeSOliver Ruiz Dorantes 	void* item;
5519760dcaeSOliver Ruiz Dorantes 	bt_usb_dev* bdev = (bt_usb_dev*)cookie;
5529760dcaeSOliver Ruiz Dorantes 
5539760dcaeSOliver Ruiz Dorantes 	if (bdev == NULL)
5549760dcaeSOliver Ruiz Dorantes 		panic("bad cookie");
5559760dcaeSOliver Ruiz Dorantes 
5569760dcaeSOliver Ruiz Dorantes 	// Clean queues
5579760dcaeSOliver Ruiz Dorantes 
5589760dcaeSOliver Ruiz Dorantes 	if (bdev->connected == true) {
5591f2fa6cdSAlexander von Gluck IV 		TRACE("%s: Cancelling queues...\n", __func__);
5601f2fa6cdSAlexander von Gluck IV 
5611f2fa6cdSAlexander von Gluck IV 		if (bdev->intr_in_ep != NULL)
5629760dcaeSOliver Ruiz Dorantes 			usb->cancel_queued_transfers(bdev->intr_in_ep->handle);
5639760dcaeSOliver Ruiz Dorantes 
5641f2fa6cdSAlexander von Gluck IV 		if (bdev->bulk_in_ep!=NULL)
5659760dcaeSOliver Ruiz Dorantes 			usb->cancel_queued_transfers(bdev->bulk_in_ep->handle);
5669760dcaeSOliver Ruiz Dorantes 
5671f2fa6cdSAlexander von Gluck IV 		if (bdev->bulk_out_ep!=NULL)
5689760dcaeSOliver Ruiz Dorantes 			usb->cancel_queued_transfers(bdev->bulk_out_ep->handle);
5699760dcaeSOliver Ruiz Dorantes 	}
5709760dcaeSOliver Ruiz Dorantes 
5719760dcaeSOliver Ruiz Dorantes 	// TX
5729760dcaeSOliver Ruiz Dorantes 	for (i = 0; i < BT_DRIVER_TXCOVERAGE; i++) {
573f2986394SAlexander von Gluck IV 		if (i == BT_COMMAND) {
574f2986394SAlexander von Gluck IV 			while ((item = list_remove_head_item(&bdev->nbuffersTx[i])) != NULL)
5759760dcaeSOliver Ruiz Dorantes 				snb_free((snet_buffer*)item);
576f2986394SAlexander von Gluck IV 		} else {
577f2986394SAlexander von Gluck IV 			while ((item = list_remove_head_item(&bdev->nbuffersTx[i])) != NULL)
5789760dcaeSOliver Ruiz Dorantes 				nb_destroy((net_buffer*)item);
5799760dcaeSOliver Ruiz Dorantes 		}
5809760dcaeSOliver Ruiz Dorantes 	}
5819760dcaeSOliver Ruiz Dorantes 	// RX
5829760dcaeSOliver Ruiz Dorantes 	for (i = 0; i < BT_DRIVER_RXCOVERAGE; i++) {
5839760dcaeSOliver Ruiz Dorantes 		nb_destroy(bdev->nbufferRx[i]);
5849760dcaeSOliver Ruiz Dorantes 	}
5859760dcaeSOliver Ruiz Dorantes 	snb_free(bdev->eventRx);
5869760dcaeSOliver Ruiz Dorantes 
5879760dcaeSOliver Ruiz Dorantes 	purge_room(&bdev->eventRoom);
5889760dcaeSOliver Ruiz Dorantes 	purge_room(&bdev->aclRoom);
5899760dcaeSOliver Ruiz Dorantes 
5909760dcaeSOliver Ruiz Dorantes 	// Device no longer in our Stack
5919760dcaeSOliver Ruiz Dorantes 	if (btDevices != NULL)
5929760dcaeSOliver Ruiz Dorantes 		btDevices->UnregisterDriver(bdev->hdev);
5939760dcaeSOliver Ruiz Dorantes 
5949760dcaeSOliver Ruiz Dorantes 	// unSet RUNNING
5959760dcaeSOliver Ruiz Dorantes 	if (TEST_AND_CLEAR(&bdev->state, RUNNING)) {
5961f2fa6cdSAlexander von Gluck IV 		ERROR("%s: %s not running?\n", __func__, bdev->name);
5979760dcaeSOliver Ruiz Dorantes 		return B_ERROR;
5989760dcaeSOliver Ruiz Dorantes 	}
5999760dcaeSOliver Ruiz Dorantes 
6009760dcaeSOliver Ruiz Dorantes 	return B_OK;
6019760dcaeSOliver Ruiz Dorantes }
6029760dcaeSOliver Ruiz Dorantes 
6039760dcaeSOliver Ruiz Dorantes 
6049760dcaeSOliver Ruiz Dorantes // Called after device_close(), when all pending I / O requests have returned
6059760dcaeSOliver Ruiz Dorantes static status_t
device_free(void * cookie)6069760dcaeSOliver Ruiz Dorantes device_free(void* cookie)
6079760dcaeSOliver Ruiz Dorantes {
6081f2fa6cdSAlexander von Gluck IV 	CALLED();
6091f2fa6cdSAlexander von Gluck IV 
6109760dcaeSOliver Ruiz Dorantes 	status_t err = B_OK;
6119760dcaeSOliver Ruiz Dorantes 	bt_usb_dev* bdev = (bt_usb_dev*)cookie;
6129760dcaeSOliver Ruiz Dorantes 
6131f2fa6cdSAlexander von Gluck IV 	if (!bdev->connected)
6149760dcaeSOliver Ruiz Dorantes 		kill_device(bdev);
6159760dcaeSOliver Ruiz Dorantes 
6169760dcaeSOliver Ruiz Dorantes 	return err;
6179760dcaeSOliver Ruiz Dorantes }
6189760dcaeSOliver Ruiz Dorantes 
6199760dcaeSOliver Ruiz Dorantes 
6209760dcaeSOliver Ruiz Dorantes // implements the POSIX ioctl()
6219760dcaeSOliver Ruiz Dorantes static status_t
device_control(void * cookie,uint32 msg,void * params,size_t size)6221e4109cdSAugustin Cavalier device_control(void* cookie, uint32 msg, void* params, size_t size)
6239760dcaeSOliver Ruiz Dorantes {
6249760dcaeSOliver Ruiz Dorantes 	status_t 	err = B_ERROR;
6259760dcaeSOliver Ruiz Dorantes 	bt_usb_dev*	bdev = (bt_usb_dev*)cookie;
6269760dcaeSOliver Ruiz Dorantes 	snet_buffer* snbuf;
6279760dcaeSOliver Ruiz Dorantes 	#if BT_DRIVER_SUPPORTS_ACL // ACL
6289760dcaeSOliver Ruiz Dorantes 	int32	i;
6299760dcaeSOliver Ruiz Dorantes 	#endif
6309760dcaeSOliver Ruiz Dorantes 
6319760dcaeSOliver Ruiz Dorantes 	TOUCH(size);
6321f2fa6cdSAlexander von Gluck IV 	TRACE("%s: ioctl() opcode %" B_PRId32 " size %" B_PRIuSIZE ".\n", __func__,
6331f2fa6cdSAlexander von Gluck IV 		msg, size);
6349760dcaeSOliver Ruiz Dorantes 
6359760dcaeSOliver Ruiz Dorantes 	if (bdev == NULL) {
6361f2fa6cdSAlexander von Gluck IV 		TRACE("%s: Bad cookie\n", __func__);
6379760dcaeSOliver Ruiz Dorantes 		return B_BAD_VALUE;
6389760dcaeSOliver Ruiz Dorantes 	}
6399760dcaeSOliver Ruiz Dorantes 
6401e4109cdSAugustin Cavalier 	if (params == NULL || !IS_USER_ADDRESS(params)) {
6411f2fa6cdSAlexander von Gluck IV 		TRACE("%s: Invalid pointer control\n", __func__);
6429760dcaeSOliver Ruiz Dorantes 		return B_BAD_VALUE;
6439760dcaeSOliver Ruiz Dorantes 	}
6449760dcaeSOliver Ruiz Dorantes 
6459760dcaeSOliver Ruiz Dorantes 	acquire_sem(bdev->lock);
6469760dcaeSOliver Ruiz Dorantes 
6479760dcaeSOliver Ruiz Dorantes 	switch (msg) {
6481e4109cdSAugustin Cavalier 		case ISSUE_BT_COMMAND: {
6499760dcaeSOliver Ruiz Dorantes 			if (size == 0) {
6501f2fa6cdSAlexander von Gluck IV 				TRACE("%s: Invalid size control\n", __func__);
6519760dcaeSOliver Ruiz Dorantes 				err = B_BAD_VALUE;
6529760dcaeSOliver Ruiz Dorantes 				break;
6539760dcaeSOliver Ruiz Dorantes 			}
6549760dcaeSOliver Ruiz Dorantes 
6551e4109cdSAugustin Cavalier 			void* _params = alloca(size);
6561e4109cdSAugustin Cavalier 			if (user_memcpy(_params, params, size) != B_OK)
6571e4109cdSAugustin Cavalier 				return B_BAD_ADDRESS;
6581e4109cdSAugustin Cavalier 
6599760dcaeSOliver Ruiz Dorantes 			// TODO: Reuse from some TXcompleted queue
6609760dcaeSOliver Ruiz Dorantes 			// snbuf = snb_create(size);
6619760dcaeSOliver Ruiz Dorantes 			snbuf = snb_fetch(&bdev->snetBufferRecycleTrash, size);
6621e4109cdSAugustin Cavalier 			snb_put(snbuf, _params, size);
6639760dcaeSOliver Ruiz Dorantes 
6649760dcaeSOliver Ruiz Dorantes 			err = submit_tx_command(bdev, snbuf);
6651f2fa6cdSAlexander von Gluck IV 			TRACE("%s: command launched\n", __func__);
6669760dcaeSOliver Ruiz Dorantes 			break;
6671e4109cdSAugustin Cavalier 		}
6689760dcaeSOliver Ruiz Dorantes 
6699760dcaeSOliver Ruiz Dorantes 		case BT_UP:
6709760dcaeSOliver Ruiz Dorantes 			//  EVENTS
6719760dcaeSOliver Ruiz Dorantes 			err = submit_rx_event(bdev);
6729760dcaeSOliver Ruiz Dorantes 			if (err != B_OK) {
673a12bde1cSAdrien Destugues 				bdev->state = CLEAR_BIT(bdev->state, ANCILLYANT);
6741f2fa6cdSAlexander von Gluck IV 				ERROR("%s: Queuing failed device stops running\n", __func__);
6759760dcaeSOliver Ruiz Dorantes 				break;
6769760dcaeSOliver Ruiz Dorantes 			}
6779760dcaeSOliver Ruiz Dorantes 
6789760dcaeSOliver Ruiz Dorantes 			#if BT_DRIVER_SUPPORTS_ACL // ACL
6799760dcaeSOliver Ruiz Dorantes 			for (i = 0; i < MAX_ACL_IN_WINDOW; i++) {
6809760dcaeSOliver Ruiz Dorantes 				err = submit_rx_acl(bdev);
6819760dcaeSOliver Ruiz Dorantes 				if (err != B_OK && i == 0) {
682a12bde1cSAdrien Destugues 					bdev->state = CLEAR_BIT(bdev->state, ANCILLYANT);
683a12bde1cSAdrien Destugues 						// Set the flaq in the HCI world
6841f2fa6cdSAlexander von Gluck IV 					ERROR("%s: Queuing failed device stops running\n",
6851f2fa6cdSAlexander von Gluck IV 						__func__);
6869760dcaeSOliver Ruiz Dorantes 					break;
6879760dcaeSOliver Ruiz Dorantes 				}
6889760dcaeSOliver Ruiz Dorantes 			}
6899760dcaeSOliver Ruiz Dorantes 			#endif
6909760dcaeSOliver Ruiz Dorantes 
691a12bde1cSAdrien Destugues 			bdev->state = SET_BIT(bdev->state, RUNNING);
6929760dcaeSOliver Ruiz Dorantes 
6939760dcaeSOliver Ruiz Dorantes 			#if BT_DRIVER_SUPPORTS_SCO
6949760dcaeSOliver Ruiz Dorantes 				// TODO:  SCO / eSCO
6959760dcaeSOliver Ruiz Dorantes 			#endif
6961f2fa6cdSAlexander von Gluck IV 
6971f2fa6cdSAlexander von Gluck IV 			ERROR("%s: Device online\n", __func__);
6989760dcaeSOliver Ruiz Dorantes 		break;
6999760dcaeSOliver Ruiz Dorantes 
7009760dcaeSOliver Ruiz Dorantes 		case GET_STATS:
7011e4109cdSAugustin Cavalier 			err = user_memcpy(params, &bdev->stat, sizeof(bt_hci_statistics));
7029760dcaeSOliver Ruiz Dorantes 		break;
7039760dcaeSOliver Ruiz Dorantes 
7049760dcaeSOliver Ruiz Dorantes 		case GET_HCI_ID:
7051e4109cdSAugustin Cavalier 			err = user_memcpy(params, &bdev->hdev, sizeof(hci_id));
7069760dcaeSOliver Ruiz Dorantes 		break;
7079760dcaeSOliver Ruiz Dorantes 
7089760dcaeSOliver Ruiz Dorantes 
7099760dcaeSOliver Ruiz Dorantes 	default:
7101f2fa6cdSAlexander von Gluck IV 		ERROR("%s: Invalid opcode.\n", __func__);
7119760dcaeSOliver Ruiz Dorantes 		err = B_DEV_INVALID_IOCTL;
7129760dcaeSOliver Ruiz Dorantes 		break;
7139760dcaeSOliver Ruiz Dorantes 	}
7149760dcaeSOliver Ruiz Dorantes 
7159760dcaeSOliver Ruiz Dorantes 	release_sem(bdev->lock);
7169760dcaeSOliver Ruiz Dorantes 	return err;
7179760dcaeSOliver Ruiz Dorantes }
7189760dcaeSOliver Ruiz Dorantes 
7199760dcaeSOliver Ruiz Dorantes 
7209760dcaeSOliver Ruiz Dorantes // implements the POSIX read()
7219760dcaeSOliver Ruiz Dorantes static status_t
device_read(void * cookie,off_t pos,void * buffer,size_t * count)7229760dcaeSOliver Ruiz Dorantes device_read(void* cookie, off_t pos, void* buffer, size_t* count)
7239760dcaeSOliver Ruiz Dorantes {
7241f2fa6cdSAlexander von Gluck IV 	TRACE("%s: Reading... count = %" B_PRIuSIZE "\n", __func__, *count);
7259760dcaeSOliver Ruiz Dorantes 
7269760dcaeSOliver Ruiz Dorantes 	*count = 0;
7279760dcaeSOliver Ruiz Dorantes 	return B_OK;
7289760dcaeSOliver Ruiz Dorantes }
7299760dcaeSOliver Ruiz Dorantes 
7309760dcaeSOliver Ruiz Dorantes 
7319760dcaeSOliver Ruiz Dorantes // implements the POSIX write()
7329760dcaeSOliver Ruiz Dorantes static status_t
device_write(void * cookie,off_t pos,const void * buffer,size_t * count)7339760dcaeSOliver Ruiz Dorantes device_write(void* cookie, off_t pos, const void* buffer, size_t* count)
7349760dcaeSOliver Ruiz Dorantes {
7351f2fa6cdSAlexander von Gluck IV 	CALLED();
7369760dcaeSOliver Ruiz Dorantes 
7379760dcaeSOliver Ruiz Dorantes 	return B_ERROR;
7389760dcaeSOliver Ruiz Dorantes }
7399760dcaeSOliver Ruiz Dorantes 
7409760dcaeSOliver Ruiz Dorantes 
7419760dcaeSOliver Ruiz Dorantes #if 0
7429760dcaeSOliver Ruiz Dorantes #pragma mark -
7439760dcaeSOliver Ruiz Dorantes #endif
7449760dcaeSOliver Ruiz Dorantes 
7459760dcaeSOliver Ruiz Dorantes 
7469760dcaeSOliver Ruiz Dorantes static int
dump_driver(int argc,char ** argv)7479760dcaeSOliver Ruiz Dorantes dump_driver(int argc, char** argv)
7489760dcaeSOliver Ruiz Dorantes {
7499760dcaeSOliver Ruiz Dorantes 	int i;
7509760dcaeSOliver Ruiz Dorantes 	snet_buffer* item = NULL;
7519760dcaeSOliver Ruiz Dorantes 
7529760dcaeSOliver Ruiz Dorantes 	for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) {
7539760dcaeSOliver Ruiz Dorantes 
7549760dcaeSOliver Ruiz Dorantes 		if (bt_usb_devices[i] != NULL) {
7559760dcaeSOliver Ruiz Dorantes 			kprintf("%s : \n", bt_usb_devices[i]->name);
7569760dcaeSOliver Ruiz Dorantes 			kprintf("\taclroom = %d\teventroom = %d\tcommand & events =%d\n",
7579760dcaeSOliver Ruiz Dorantes 				snb_packets(&bt_usb_devices[i]->eventRoom),
7589760dcaeSOliver Ruiz Dorantes 				snb_packets(&bt_usb_devices[i]->aclRoom),
7599760dcaeSOliver Ruiz Dorantes 				snb_packets(&bt_usb_devices[i]->snetBufferRecycleTrash));
7609760dcaeSOliver Ruiz Dorantes 
7619760dcaeSOliver Ruiz Dorantes 			while ((item = (snet_buffer*)list_get_next_item(
7629760dcaeSOliver Ruiz Dorantes 				&bt_usb_devices[i]->snetBufferRecycleTrash, item)) != NULL)
7639760dcaeSOliver Ruiz Dorantes 				snb_dump(item);
7649760dcaeSOliver Ruiz Dorantes 		}
7659760dcaeSOliver Ruiz Dorantes 	}
7669760dcaeSOliver Ruiz Dorantes 
7679760dcaeSOliver Ruiz Dorantes 	return 0;
7689760dcaeSOliver Ruiz Dorantes }
7699760dcaeSOliver Ruiz Dorantes 
7709760dcaeSOliver Ruiz Dorantes 
7719760dcaeSOliver Ruiz Dorantes // called each time the driver is loaded by the kernel
7729760dcaeSOliver Ruiz Dorantes status_t
init_driver(void)7739760dcaeSOliver Ruiz Dorantes init_driver(void)
7749760dcaeSOliver Ruiz Dorantes {
7751f2fa6cdSAlexander von Gluck IV 	CALLED();
7769760dcaeSOliver Ruiz Dorantes 	int j;
7779760dcaeSOliver Ruiz Dorantes 
778f2986394SAlexander von Gluck IV 	if (get_module(BT_CORE_DATA_MODULE_NAME,
779f2986394SAlexander von Gluck IV 		(module_info**)&btCoreData) != B_OK) {
7801f2fa6cdSAlexander von Gluck IV 		ERROR("%s: cannot get module '%s'\n", __func__,
7811f2fa6cdSAlexander von Gluck IV 			BT_CORE_DATA_MODULE_NAME);
7829760dcaeSOliver Ruiz Dorantes 		return B_ERROR;
7831f2fa6cdSAlexander von Gluck IV 	}
7849760dcaeSOliver Ruiz Dorantes 
7859760dcaeSOliver Ruiz Dorantes 	// BT devices MODULE INITS
7869760dcaeSOliver Ruiz Dorantes 	if (get_module(btDevices_name, (module_info**)&btDevices) != B_OK) {
7871f2fa6cdSAlexander von Gluck IV 		ERROR("%s: cannot get module '%s'\n", __func__, btDevices_name);
7889760dcaeSOliver Ruiz Dorantes 		goto err_release3;
7891f2fa6cdSAlexander von Gluck IV 	}
7909760dcaeSOliver Ruiz Dorantes 
7919760dcaeSOliver Ruiz Dorantes 	// HCI MODULE INITS
7929760dcaeSOliver Ruiz Dorantes 	if (get_module(hci_name, (module_info**)&hci) != B_OK) {
7931f2fa6cdSAlexander von Gluck IV 		ERROR("%s: cannot get module '%s'\n", __func__, hci_name);
7949760dcaeSOliver Ruiz Dorantes #ifndef BT_SURVIVE_WITHOUT_HCI
7959760dcaeSOliver Ruiz Dorantes 		goto err_release2;
7969760dcaeSOliver Ruiz Dorantes #endif
7979760dcaeSOliver Ruiz Dorantes 	}
7989760dcaeSOliver Ruiz Dorantes 
7999760dcaeSOliver Ruiz Dorantes 	// USB MODULE INITS
8009760dcaeSOliver Ruiz Dorantes 	if (get_module(usb_name, (module_info**)&usb) != B_OK) {
8011f2fa6cdSAlexander von Gluck IV 		ERROR("%s: cannot get module '%s'\n", __func__, usb_name);
8029760dcaeSOliver Ruiz Dorantes 		goto err_release1;
8039760dcaeSOliver Ruiz Dorantes 	}
8049760dcaeSOliver Ruiz Dorantes 
8059760dcaeSOliver Ruiz Dorantes 	if (get_module(NET_BUFFER_MODULE_NAME, (module_info**)&nb) != B_OK) {
8061f2fa6cdSAlexander von Gluck IV 		ERROR("%s: cannot get module '%s'\n", __func__,
8071f2fa6cdSAlexander von Gluck IV 			NET_BUFFER_MODULE_NAME);
8089760dcaeSOliver Ruiz Dorantes #ifndef BT_SURVIVE_WITHOUT_NET_BUFFERS
8099760dcaeSOliver Ruiz Dorantes 		goto err_release;
8109760dcaeSOliver Ruiz Dorantes #endif
8119760dcaeSOliver Ruiz Dorantes 	}
8129760dcaeSOliver Ruiz Dorantes 
8139760dcaeSOliver Ruiz Dorantes 	// GENERAL INITS
8149760dcaeSOliver Ruiz Dorantes 	dev_table_sem = create_sem(1, BLUETOOTH_DEVICE_DEVFS_NAME "dev_table_lock");
8159760dcaeSOliver Ruiz Dorantes 	if (dev_table_sem < 0) {
8169760dcaeSOliver Ruiz Dorantes 		goto err;
8179760dcaeSOliver Ruiz Dorantes 	}
8189760dcaeSOliver Ruiz Dorantes 
8199760dcaeSOliver Ruiz Dorantes 	for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) {
8209760dcaeSOliver Ruiz Dorantes 		bt_usb_devices[j] = NULL;
8219760dcaeSOliver Ruiz Dorantes 	}
8229760dcaeSOliver Ruiz Dorantes 
8239760dcaeSOliver Ruiz Dorantes 	// Note: After here device_added and publish devices hooks are called
8249760dcaeSOliver Ruiz Dorantes 	usb->register_driver(BLUETOOTH_DEVICE_DEVFS_NAME, supported_devices, 1, NULL);
8259760dcaeSOliver Ruiz Dorantes 	usb->install_notify(BLUETOOTH_DEVICE_DEVFS_NAME, &notify_hooks);
8269760dcaeSOliver Ruiz Dorantes 
8279760dcaeSOliver Ruiz Dorantes 	add_debugger_command("bth2generic", &dump_driver,
8289760dcaeSOliver Ruiz Dorantes 		"Lists H2 Transport device info");
8299760dcaeSOliver Ruiz Dorantes 
8309760dcaeSOliver Ruiz Dorantes 	return B_OK;
8319760dcaeSOliver Ruiz Dorantes 
8329760dcaeSOliver Ruiz Dorantes err:	// Releasing
8339760dcaeSOliver Ruiz Dorantes 	put_module(NET_BUFFER_MODULE_NAME);
8349760dcaeSOliver Ruiz Dorantes err_release:
8359760dcaeSOliver Ruiz Dorantes 	put_module(usb_name);
8369760dcaeSOliver Ruiz Dorantes err_release1:
8379760dcaeSOliver Ruiz Dorantes 	put_module(hci_name);
8389760dcaeSOliver Ruiz Dorantes #ifndef BT_SURVIVE_WITHOUT_HCI
8399760dcaeSOliver Ruiz Dorantes err_release2:
8409760dcaeSOliver Ruiz Dorantes #endif
8419760dcaeSOliver Ruiz Dorantes 	put_module(btDevices_name);
8429760dcaeSOliver Ruiz Dorantes err_release3:
8439760dcaeSOliver Ruiz Dorantes 	put_module(BT_CORE_DATA_MODULE_NAME);
8449760dcaeSOliver Ruiz Dorantes 
8459760dcaeSOliver Ruiz Dorantes 	return B_ERROR;
8469760dcaeSOliver Ruiz Dorantes }
8479760dcaeSOliver Ruiz Dorantes 
8489760dcaeSOliver Ruiz Dorantes 
8499760dcaeSOliver Ruiz Dorantes // called just before the kernel unloads the driver
8509760dcaeSOliver Ruiz Dorantes void
uninit_driver(void)8519760dcaeSOliver Ruiz Dorantes uninit_driver(void)
8529760dcaeSOliver Ruiz Dorantes {
8531f2fa6cdSAlexander von Gluck IV 	CALLED();
8549760dcaeSOliver Ruiz Dorantes 
8551f2fa6cdSAlexander von Gluck IV 	int32 j;
8569760dcaeSOliver Ruiz Dorantes 
8579760dcaeSOliver Ruiz Dorantes 	for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) {
8589760dcaeSOliver Ruiz Dorantes 
8599760dcaeSOliver Ruiz Dorantes 		if (publish_names[j] != NULL)
8609760dcaeSOliver Ruiz Dorantes 			free(publish_names[j]);
8619760dcaeSOliver Ruiz Dorantes 
8629760dcaeSOliver Ruiz Dorantes 		if (bt_usb_devices[j] != NULL) {
8639760dcaeSOliver Ruiz Dorantes 			//	if (connected_dev != NULL) {
8649760dcaeSOliver Ruiz Dorantes 			//		debugf("Device %p still exists.\n",	connected_dev);
8659760dcaeSOliver Ruiz Dorantes 			//	}
8661f2fa6cdSAlexander von Gluck IV 			ERROR("%s: %s still present?\n", __func__, bt_usb_devices[j]->name);
8679760dcaeSOliver Ruiz Dorantes 			kill_device(bt_usb_devices[j]);
8689760dcaeSOliver Ruiz Dorantes 		}
8699760dcaeSOliver Ruiz Dorantes 	}
8709760dcaeSOliver Ruiz Dorantes 
8719760dcaeSOliver Ruiz Dorantes 	usb->uninstall_notify(BLUETOOTH_DEVICE_DEVFS_NAME);
8729760dcaeSOliver Ruiz Dorantes 
8739760dcaeSOliver Ruiz Dorantes 	remove_debugger_command("bth2generic", &dump_driver);
8749760dcaeSOliver Ruiz Dorantes 
8759760dcaeSOliver Ruiz Dorantes 	// Releasing modules
8769760dcaeSOliver Ruiz Dorantes 	put_module(usb_name);
8779760dcaeSOliver Ruiz Dorantes 	put_module(hci_name);
8789760dcaeSOliver Ruiz Dorantes 	// TODO: netbuffers
8799760dcaeSOliver Ruiz Dorantes 
8809760dcaeSOliver Ruiz Dorantes 	delete_sem(dev_table_sem);
8819760dcaeSOliver Ruiz Dorantes }
8829760dcaeSOliver Ruiz Dorantes 
8839760dcaeSOliver Ruiz Dorantes 
8849760dcaeSOliver Ruiz Dorantes const char**
publish_devices(void)8859760dcaeSOliver Ruiz Dorantes publish_devices(void)
8869760dcaeSOliver Ruiz Dorantes {
8871f2fa6cdSAlexander von Gluck IV 	CALLED();
8889760dcaeSOliver Ruiz Dorantes 	int32 j;
8899760dcaeSOliver Ruiz Dorantes 	int32 i = 0;
8909760dcaeSOliver Ruiz Dorantes 
8919760dcaeSOliver Ruiz Dorantes 	char* str;
8929760dcaeSOliver Ruiz Dorantes 
8939760dcaeSOliver Ruiz Dorantes 	for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) {
8949760dcaeSOliver Ruiz Dorantes 		if (publish_names[j]) {
8959760dcaeSOliver Ruiz Dorantes 			free(publish_names[j]);
8969760dcaeSOliver Ruiz Dorantes 			publish_names[j] = NULL;
8979760dcaeSOliver Ruiz Dorantes 		}
8989760dcaeSOliver Ruiz Dorantes 	}
8999760dcaeSOliver Ruiz Dorantes 
9009760dcaeSOliver Ruiz Dorantes 	acquire_sem(dev_table_sem);
9019760dcaeSOliver Ruiz Dorantes 	for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) {
9029760dcaeSOliver Ruiz Dorantes 		if (bt_usb_devices[j] != NULL && bt_usb_devices[j]->connected) {
9039760dcaeSOliver Ruiz Dorantes 			str = strdup(bt_usb_devices[j]->name);
9049760dcaeSOliver Ruiz Dorantes 			if (str) {
9059760dcaeSOliver Ruiz Dorantes 				publish_names[i++] = str;
9061f2fa6cdSAlexander von Gluck IV 				TRACE("%s: publishing %s\n", __func__, bt_usb_devices[j]->name);
9079760dcaeSOliver Ruiz Dorantes 			}
9089760dcaeSOliver Ruiz Dorantes 		}
9099760dcaeSOliver Ruiz Dorantes 	}
9109760dcaeSOliver Ruiz Dorantes 	release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE);
9119760dcaeSOliver Ruiz Dorantes 
9129760dcaeSOliver Ruiz Dorantes 	publish_names[i] = NULL;
9131f2fa6cdSAlexander von Gluck IV 	TRACE("%s: published %" B_PRId32 " devices\n", __func__, i);
9149760dcaeSOliver Ruiz Dorantes 
9159760dcaeSOliver Ruiz Dorantes 	// TODO: this method might make better memory use
9169760dcaeSOliver Ruiz Dorantes 	// dev_names = (char**)malloc(sizeof(char*) * (dev_count + 1));
9179760dcaeSOliver Ruiz Dorantes 	// if (dev_names) {
9189760dcaeSOliver Ruiz Dorantes 	// for (i = 0; i < MAX_NUM_DEVS; i++) {
9199760dcaeSOliver Ruiz Dorantes 	//	if ((dev != NULL) // dev + \n
9209760dcaeSOliver Ruiz Dorantes 	//	&& (dev_names[i] = (char*)malloc(strlen(DEVICE_PATH) + 2))) {
9219760dcaeSOliver Ruiz Dorantes 	//	sprintf(dev_names[i], "%s%ld", DEVICE_PATH, dev->num);
9229760dcaeSOliver Ruiz Dorantes 	//	debugf("publishing \"%s\"\n", dev_names[i]);
9239760dcaeSOliver Ruiz Dorantes 	//	}
9249760dcaeSOliver Ruiz Dorantes 	// }
9259760dcaeSOliver Ruiz Dorantes 
9269760dcaeSOliver Ruiz Dorantes 	return (const char**)publish_names;
9279760dcaeSOliver Ruiz Dorantes }
9289760dcaeSOliver Ruiz Dorantes 
9299760dcaeSOliver Ruiz Dorantes 
9309760dcaeSOliver Ruiz Dorantes static device_hooks hooks = {
9319760dcaeSOliver Ruiz Dorantes 	device_open,
9329760dcaeSOliver Ruiz Dorantes 	device_close,
9339760dcaeSOliver Ruiz Dorantes 	device_free,
9349760dcaeSOliver Ruiz Dorantes 	device_control,
9359760dcaeSOliver Ruiz Dorantes 	device_read,
9369760dcaeSOliver Ruiz Dorantes 	device_write,
9379760dcaeSOliver Ruiz Dorantes 	NULL,
9389760dcaeSOliver Ruiz Dorantes 	NULL,
9399760dcaeSOliver Ruiz Dorantes 	NULL,
9409760dcaeSOliver Ruiz Dorantes 	NULL
9419760dcaeSOliver Ruiz Dorantes };
9429760dcaeSOliver Ruiz Dorantes 
9439760dcaeSOliver Ruiz Dorantes 
9449760dcaeSOliver Ruiz Dorantes device_hooks*
find_device(const char * name)9459760dcaeSOliver Ruiz Dorantes find_device(const char* name)
9469760dcaeSOliver Ruiz Dorantes {
9471f2fa6cdSAlexander von Gluck IV 	CALLED();
9489760dcaeSOliver Ruiz Dorantes 
9499760dcaeSOliver Ruiz Dorantes 	return &hooks;
9509760dcaeSOliver Ruiz Dorantes }
951