From 90e2260736c67f290fe4fc7c3d67ae2dd845bdc3 Mon Sep 17 00:00:00 2001 From: Oliver Ruiz Dorantes Date: Fri, 30 Nov 2007 19:59:29 +0000 Subject: [PATCH] Remaining part of the USB-BT driver. Events are commands are tested and working. ACLcode is untested and needs review. Lacks some general headers to be able to compile it, as I am still considering making some org. changes. Commiting for possible reviews or suggestions. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23034 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../drivers/bluetooth/h2/h2generic/h2cfg.h | 33 + .../bluetooth/h2/h2generic/h2generic.c | 824 ++++++++++++++++++ .../bluetooth/h2/h2generic/h2generic.h | 107 +++ .../bluetooth/h2/h2generic/h2transactions.c | 402 +++++++++ .../bluetooth/h2/h2generic/h2transactions.h | 21 + .../drivers/bluetooth/h2/h2generic/h2upper.c | 201 +++++ .../drivers/bluetooth/h2/h2generic/h2upper.h | 22 + .../drivers/bluetooth/h2/h2generic/h2util.c | 147 ++++ .../drivers/bluetooth/h2/h2generic/h2util.h | 34 + 9 files changed, 1791 insertions(+) create mode 100644 src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2cfg.h create mode 100644 src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2generic.c create mode 100644 src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2generic.h create mode 100644 src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2transactions.c create mode 100644 src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2transactions.h create mode 100644 src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2upper.c create mode 100644 src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2upper.h create mode 100644 src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2util.c create mode 100644 src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2util.h diff --git a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2cfg.h b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2cfg.h new file mode 100644 index 0000000000..fafdd7cc0a --- /dev/null +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2cfg.h @@ -0,0 +1,33 @@ +/* + * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * + * All rights reserved. Distributed under the terms of the MIT License. + * + */ + +#ifndef _H2CFG_H_ +#define _H2CFG_H_ + +/* TODO: move exclusive header for drivers*/ +#define BT_DRIVER_SUPPORTS_CMD 1 +#define BT_DRIVER_SUPPORTS_EVT 1 +#define BT_DRIVER_SUPPORTS_ESCO 0 +#define BT_DRIVER_SUPPORTS_SCO 0 +#define BT_DRIVER_SUPPORTS_ACL 0 + +#define BT_DRIVER_RXCOVERAGE (BT_DRIVER_SUPPORTS_EVT+BT_DRIVER_SUPPORTS_ACL+BT_DRIVER_SUPPORTS_SCO+BT_DRIVER_SUPPORTS_ESCO) +#define BT_DRIVER_TXCOVERAGE (BT_DRIVER_SUPPORTS_CMD+BT_DRIVER_SUPPORTS_ACL+BT_DRIVER_SUPPORTS_SCO+BT_DRIVER_SUPPORTS_ESCO) + +#if BT_DRIVER_RXCOVERAGE<1 || BT_DRIVER_TXCOVERAGE<1 +#error incomplete Bluetooth driver Commands and Events should be implemented +#endif + + +//////////////////////////////////// + +#define BT_SURVIVE_WITHOUT_HCI +#define BT_SURVIVE_WITHOUT_NET_BUFFERS +//#define BT_IOCTLS_PASS_SIZE + + +#endif diff --git a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2generic.c b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2generic.c new file mode 100644 index 0000000000..0b3603c317 --- /dev/null +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2generic.c @@ -0,0 +1,824 @@ +/* + * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * + * All rights reserved. Distributed under the terms of the MIT License. + * + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include "snet_buffer.h" + +#include +#include + +#define BT_DEBUG_THIS_MODULE +#include + +#include "h2generic.h" +#include "h2transactions.h" +#include "h2util.h" + +#include "h2cfg.h" + +int32 api_version = B_CUR_DRIVER_API_VERSION; + +/* Modules */ +static char* usb_name = B_USB_MODULE_NAME; +static char* hci_name = B_BT_HCI_MODULE_NAME; + +usb_module_info *usb = NULL; +bt_hci_module_info *hci = NULL; +struct net_buffer_module_info *nb = NULL; + +/* Driver Global data */ +static char *publish_names[MAX_BT_GENERIC_USB_DEVICES]; + +int32 dev_count = 0; /* number of connected devices */ +static bt_usb_dev* bt_usb_devices[MAX_BT_GENERIC_USB_DEVICES]; +sem_id dev_table_sem = -1; /* sem to synchronize access to device table */ + +usb_support_descriptor supported_devices[] = +{ + /* Generic Bluetooth USB device */ + /* Class, SubClass, and Protocol codes that describe a Bluetooth device */ + { UDCLASS_WIRELESS, UDSUBCLASS_RF, UDPROTO_BLUETOOTH , 0 , 0 }, + + /* Generic devices */ + /* Broadcom BCM2035 */ + { 0, 0, 0, 0x0a5c, 0x200a }, + { 0, 0, 0, 0x0a5c, 0x2009 }, + + /* Devices taken from the linux Driver */ + /* AVM BlueFRITZ! USB v2.0 */ + { 0, 0, 0, 0x057c , 0x3800 }, + /* Bluetooth Ultraport Module from IBM */ + { 0, 0, 0, 0x04bf , 0x030a }, + /* ALPS Modules with non-standard id */ + { 0, 0, 0, 0x044e , 0x3001 }, + { 0, 0, 0, 0x044e , 0x3002 }, + /* Ericsson with non-standard id */ + { 0, 0, 0, 0x0bdb , 0x1002 } +}; + +/* add a device to the list of connected devices */ +static bt_usb_dev* +spawn_device(const usb_device* usb_dev) +{ + int32 i; + status_t err = B_OK; + bt_usb_dev* new_bt_dev = NULL; + + flowf("add_device()\n"); + + /* 16 usb dongles... u are unsane */ + if (dev_count >= MAX_BT_GENERIC_USB_DEVICES) { + flowf("device table full\n"); + goto exit; + } + + /* try the allocation */ + new_bt_dev = (bt_usb_dev*)malloc(sizeof(bt_usb_dev)); + if ( new_bt_dev == NULL ) { + flowf("no memoery allocating\n"); + goto exit; + } + memset(new_bt_dev, 0, sizeof(bt_usb_dev) ); + + /* We will need this sem for some flow control */ + new_bt_dev->cmd_complete = create_sem(1, ID "cmd_complete"); + if (new_bt_dev->cmd_complete < 0) { + err = new_bt_dev->cmd_complete; + goto bail0; + } + + /* and this for something else */ + new_bt_dev->lock = create_sem(1, ID "lock"); + if (new_bt_dev->lock < 0) { + err = new_bt_dev->lock; + goto bail1; + } + + /* find a free slot and fill out the name */ + acquire_sem(dev_table_sem); + for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { + if (bt_usb_devices[i] == NULL) { + bt_usb_devices[i] = new_bt_dev; + sprintf(new_bt_dev->name, "%s/%ld", DEVICE_PATH, i); + new_bt_dev->num = i; + debugf("added device %p %ld %s\n", bt_usb_devices[i] ,new_bt_dev->num,new_bt_dev->name); + break; + } + } + release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); + + /* In the case we cannot us */ + if (bt_usb_devices[i] != new_bt_dev) { + flowf("Device could not be added\n"); + goto bail2; + } + + new_bt_dev->dev = usb_dev; + /* TODO am i actually gonna use this? */ + new_bt_dev->open_count = 0; + + dev_count++; + return new_bt_dev; + +bail2: + delete_sem(new_bt_dev->lock); +bail1: + delete_sem(new_bt_dev->cmd_complete); +bail0: + free(new_bt_dev); +exit: + return new_bt_dev; +} + + +/* remove a device from the list of connected devices */ +static void +kill_device(bt_usb_dev* dev) +{ + uint16 i; + debugf("remove_device(%p)\n", dev); + + delete_sem(dev->lock); + delete_sem(dev->cmd_complete); + + free(dev); + dev_count--; +} + + +bt_usb_dev* +fetch_device(bt_usb_dev* dev, hci_id hid) +{ + int i; + + debugf("(%p)\n", dev); + + acquire_sem(dev_table_sem); + if (dev != NULL) + for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { + /* somehow the device is still around */ + if (bt_usb_devices[i] == dev) { + release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); + return bt_usb_devices[i]; + } + } + else + for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { + /* somehow the device is still around */ + if (bt_usb_devices[i] != NULL && bt_usb_devices[i]->hdev == hid) { + release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); + return bt_usb_devices[i]; + } + } + + + release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); + + return NULL; +} + +#if 0 +#pragma mark - +#endif + +static bt_hci_transport bt_usb_hooks = +{ + NULL, + NULL, + NULL, + NULL, + H2, + "H2 Bluetooth Device" +}; + +/* called by USB Manager when device is added to the USB */ +static status_t +device_added(const usb_device* dev, void** cookie) +{ + const usb_interface_info* interface; + const usb_device_descriptor* desc; + const usb_configuration_info* config; + const usb_interface_info* uif; + const usb_endpoint_info* ep; + + status_t err = B_ERROR; + bt_usb_dev* new_bt_dev = spawn_device(dev); + int e, i; + + debugf("device_added(%ld, %p)\n", dev, new_bt_dev); + + if (new_bt_dev == NULL) { + flowf("Couldn't allocate device record.\n"); + err = ENOMEM; + goto bail_no_mem; + } + + /* we only have 1 configuration number 0 */ + config = usb->get_nth_configuration(dev, 0); + //dump_usb_configuration_info(config); + if (config == NULL) { + flowf("couldn't get default config.\n"); + err = B_ERROR; + goto bail; + } + + debugf("found %ld alt interfaces.\n", config->interface->alt_count); + + /* set first interface */ + interface = &config->interface->alt[0]; + err = usb->set_alt_interface(new_bt_dev->dev, interface); + + if (err != B_OK) { + debugf("set_alt_interface() returned %ld.\n", err); + goto bail; + } + + /* call set_configuration() only after calling set_alt_interface()*/ + err = usb->set_configuration(dev, config); + if (err != B_OK) { + debugf("set_configuration() returned %ld.\n", err); + goto bail; + } + + /* Place to find out whats our concrete device and set up some special info to our driver */ + /* TODO: if this code increases too much reconsider this implementation*/ + desc = usb->get_device_descriptor(dev); + if ( desc->vendor_id == 0x0a5c && desc->product_id == 0x200a && desc->product_id == 0x2009) { + // Tecom Device VENDOR_ID 0x0a5c PRODUCT_ID 0x2035 + new_bt_dev->driver_info = BT_WILL_NEED_A_RESET | BT_SCO_NOT_WORKING; + } + /* + else if ( desc->vendor_id == YOUR_VENDOR_HERE && desc->product_id == YOUR_PRODUCT_HERE ) { + YOUR_SPECIAL_FLAGS_HERE + } + */ + + if (new_bt_dev->driver_info & BT_IGNORE_THIS_DEVICE){ + err = ENODEV; + goto bail; + } + + // security check + if (config->interface->active->descr->interface_number > 0){ + debugf("Strange condition happened %d\n", config->interface->active->descr->interface_number); + err = B_ERROR; + goto bail; + } + + debugf("Found %ld interfaces. Expected 3\n", config->interface_count); + /* Find endpoints that we need */ + uif = config->interface->active; + for (e = 0; e < uif->descr->num_endpoints; e++) { + + ep = &uif->endpoint[e]; + switch (ep->descr->attributes & USB_ENDPOINT_ATTR_MASK) + { + case USB_ENDPOINT_ATTR_INTERRUPT: + if (ep->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) + { + new_bt_dev->intr_in_ep = ep; + new_bt_dev->max_packet_size_intr_in = ep->descr->max_packet_size; + flowf("INT in\n"); + } else + { + ; + flowf("INT out\n"); + } + break; + + case USB_ENDPOINT_ATTR_BULK: + if (ep->descr->endpoint_address & USB_ENDPOINT_ADDR_DIR_IN) + { + new_bt_dev->bulk_in_ep = ep; + new_bt_dev->max_packet_size_bulk_in = ep->descr->max_packet_size;; + flowf("BULK int\n"); + } else + { + new_bt_dev->bulk_out_ep = ep; + new_bt_dev->max_packet_size_bulk_out = ep->descr->max_packet_size;; + flowf("BULK out\n"); + } + break; + } + } + + if (!new_bt_dev->bulk_in_ep || !new_bt_dev->bulk_out_ep || !new_bt_dev->intr_in_ep) { + flowf("Minimal # endpoints for BT not found\n"); + goto bail; + } + + // Look into the devices suported to understand this + if (new_bt_dev->driver_info & BT_DIGIANSWER) + new_bt_dev->ctrl_req = USB_TYPE_VENDOR; + else + new_bt_dev->ctrl_req = USB_TYPE_CLASS; + + new_bt_dev->connected = true; + + /* set the cookie that will be passed to other USB + hook functions (currently device_removed() is the only other) */ + *cookie = new_bt_dev; + debugf("Ok %p\n",bt_usb_devices[0]); + return B_OK; + +bail: + kill_device(new_bt_dev); +bail_no_mem: + *cookie = NULL; +done: + return err; +} + + +/* called by USB Manager when device is removed from the USB */ +static status_t +device_removed(void* cookie) +{ + int32 i; + void* item; + bt_usb_dev* bdev = (bt_usb_dev*) fetch_device(cookie, 0); + + debugf("device_removed(%p)\n", bdev); + + if (bdev == NULL) { + flowf("Weird condition...\n"); + return B_ERROR; + } + // TODO: Consider some other place + // TX + for (i = 0; i < BT_DRIVER_TXCOVERAGE; i++) { + if (i = BT_COMMAND) + while ((item = list_remove_head_item(&bdev->nbuffersTx[i])) != NULL) { + snb_free(item); + } + else + while ((item = list_remove_head_item(&bdev->nbuffersTx[i])) != NULL) { + nb_destroy(item); + } + + } + // RX + for (i = 0; i < BT_DRIVER_RXCOVERAGE; i++) { + nb_destroy(bdev->nbufferRx[i]); + } + snb_free(bdev->eventRx); + + purge_room(&bdev->eventRoom); + purge_room(&bdev->aclRoom); + // TODO: Consider some other place + + if (hci != NULL) + hci->UnregisterDriver(bdev->hdev); + + bdev->connected = false; + + /* TODO: maybe we still need this struct for close and free hooks */ + kill_device(bdev); + + return B_OK; +} + + +static usb_notify_hooks notify_hooks = +{ + &device_added, + &device_removed +}; + +#if 0 +#pragma mark - +#endif + +/* implements the POSIX open() */ +static status_t +device_open(const char *name, uint32 flags, void **cookie) +{ + status_t err = ENODEV; + bt_usb_dev* bdev = NULL; + hci_id hdev; + int i; + + flowf("device_open()\n"); + + acquire_sem(dev_table_sem); + for (i = 0; i < MAX_BT_GENERIC_USB_DEVICES; i++) { + if (bt_usb_devices[i] && !strcmp(name, bt_usb_devices[i]->name)) { + bdev = bt_usb_devices[i]; + break; + } + } + release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); + + if (bdev == NULL) { + flowf("Device not found in the open list!"); + *cookie = NULL; + return B_ERROR; + } + + acquire_sem(bdev->lock); + // Set HCI_RUNNING + if ( TEST_AND_SET(&bdev->state, RUNNING) ) { + flowf("dev already running! - reOpened device!\n"); + return B_ERROR; + } + + // TX structures + for (i = 0; i < BT_DRIVER_TXCOVERAGE; i++) { + list_init(&bdev->nbuffersTx[i]); + bdev->nbuffersPendingTx[i] = 0; + } + + // RX structures + bdev->eventRx = NULL; + for (i = 0; i < BT_DRIVER_RXCOVERAGE; i++) { + bdev->nbufferRx[i] = NULL; + } + + + // dumping the USB frames + init_room(&bdev->eventRoom); + init_room(&bdev->aclRoom); + //Init_room(new_bt_dev->scoRoom); + + list_init(&bdev->snetBufferRecycleTrash); + + // Allocate set and register the HCI device + if (hci != NULL) { + // TODO: Fill the transport descriptor + hci->RegisterDriver(&bt_usb_hooks, &hdev, (void*)bdev); + + if ( err != B_OK ) + { + flowf("Impossible to register a hci device.\n"); + hdev = bdev->num; /* XXX: Lets try to go on*/ + } + } + else { + hdev = bdev->num; + } + bdev->hdev = hdev; + + // H: set the special flags + + // EVENTS + err = submit_rx_event(bdev); + if (err != B_OK) + goto unrun; +#if BT_DRIVER_SUPPORTS_ACL + // ACL + for (i = 0; i < MAX_ACL_IN_WINDOW; i++) { + err = submit_rx_acl(bdev); + if (err != B_OK && i == 0 ) + goto unrun; + } +#endif + +#if BT_DRIVER_SUPPORTS_SCO + // TODO: SCO / eSCO +#endif + + *cookie = bdev; + release_sem(bdev->lock); + + return B_OK; + +unrun: + CLEAR_BIT(bdev->state, RUNNING); // Set the flaq in the HCI world + flowf("Queuing failed device stops running\n"); + + return err; +} + + +/* called when a client calls POSIX close() on the driver, but I/O + ** requests may still be pending */ +static status_t +device_close(void *cookie) +{ + bt_usb_dev* bdev = (bt_usb_dev*)cookie; + + if (bdev == NULL) + panic("bad cookie"); + + debugf("device_close() called on %s\n", DEVICE_PATH, bdev->hdev ); + + + if (!TEST_AND_CLEAR(&bdev->state, RUNNING) ) { + flowf("Device wasnt running!!!\n"); + } + + flowf("Stopping device and cancelling queues...\n"); + + if ( bdev->intr_in_ep != NULL ) { + usb->cancel_queued_transfers(bdev->intr_in_ep->handle); + + } else { + flowf("Cancelling impossible EVENTS\n"); + } + + if (bdev->bulk_in_ep!=NULL) { + usb->cancel_queued_transfers(bdev->bulk_in_ep->handle); + } else { + flowf("Cancelling impossible ACL in\n"); + } + + if (bdev->bulk_out_ep!=NULL) { + usb->cancel_queued_transfers(bdev->bulk_out_ep->handle); + } else { + flowf("Cancelling impossible ACL out\n"); + } + + // TODO: Kill if its not connected? + + return B_OK; +} + + +/* called after device_close(), when all pending I/O requests have + * returned */ +static status_t +device_free (void *cookie) +{ + status_t err = B_OK; + bt_usb_dev* dev = (bt_usb_dev*)cookie; + + debugf("device_free() called on \"%s %ld\"\n",DEVICE_PATH, dev->num); + + + if (--dev->open_count == 0) { + + /* GotoLowPower */ + // interesting ..... + } + else { + /* The last client has closed, and the device is no longer + connected, so remove it from the list. */ + + } + + // TODO: Kill if its not connected? + + return err; +} + + +/* implements the POSIX ioctl() */ +static status_t +device_control(void *cookie, uint32 msg, void *params, size_t size) +{ + status_t err = B_ERROR; + bt_usb_dev* dev = (bt_usb_dev*)cookie; + snet_buffer* snbuf; + TOUCH(size); + + debugf("ioctl() opcode %ld size %ld.\n", msg, size); + + if (dev == NULL) { + flowf("Bad cookie\n"); + return B_BAD_VALUE; + } + + if (params == NULL) { + flowf("Invalid pointer control\n"); + return B_BAD_VALUE; + } + + acquire_sem(dev->lock); + + switch (msg) { + case ISSUE_BT_COMMAND: +#ifdef BT_IOCTLS_PASS_SIZE + if (size == 0) { + flowf("Invalid size control\n"); + err = B_BAD_VALUE; + break; + } +#else + size = (*((size_t*)params)); + ((size_t*)params)++; +#endif + + // TODO: Reuse from some TXcompleted queue + snbuf = snb_create(size); + snb_put(snbuf, params, size); + + err = send_command(dev->hdev, snbuf); + + break; + + case ISSUE_STATICS: + memcpy(params, &dev->stat, sizeof(bt_hci_statistics)); + err = B_OK; + break; + + default: + debugf("Invalid opcode %ld.\n", msg); + err = B_DEV_INVALID_IOCTL; + break; + } + + release_sem(dev->lock); + return err; +} + + +/* implements the POSIX read() */ +static status_t +device_read(void *cookie, off_t pos, void *buf, size_t *count) +{ + debugf("Reading... pos = %ld || count = %ld\n", pos, *count); + + *count = 0; + return B_OK; +} + + +/* implements the POSIX write() */ +static status_t +device_write(void *cookie, off_t pos, const void *buf, size_t *count) +{ + flowf("device_write()\n"); + + return B_ERROR; +} + +#if 0 +#pragma mark - +#endif + +/* called each time the driver is loaded by the kernel */ +status_t +init_driver(void) +{ + int j; + flowf("init_driver()\n"); + + // HCI MODULE INITS + if (get_module(hci_name,(module_info**)&hci) != B_OK) { + debugf("cannot get module \"%s\"\n", hci_name); +#ifndef BT_SURVIVE_WITHOUT_HCI + return B_ERROR; +#endif + } + debugf("hci module at %p\n", hci); + + // USB MODULE INITS + if (get_module(usb_name,(module_info**)&usb) != B_OK) { + debugf("cannot get module \"%s\"\n", usb_name); + goto err_release; + } + debugf("usb module at %p\n", usb); + + + if (get_module(NET_BUFFER_MODULE_NAME,(module_info**)&nb) != B_OK) { + debugf("cannot get module \"%s\"\n", NET_BUFFER_MODULE_NAME); +#ifndef BT_SURVIVE_WITHOUT_NET_BUFFERS + goto err_release; +#endif + } + debugf("nb module at %p\n", nb); + + // GENERAL INITS + dev_table_sem = create_sem(1, ID "dev_table_lock"); + if (dev_table_sem < 0) { + goto err; + } + + for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) { + bt_usb_devices[j] = NULL; + } + + /* After here device_added and publish devices hooks are called + be carefull USB devs */ + usb->register_driver(DEVICE_NAME, supported_devices, 1, NULL); + usb->install_notify(DEVICE_NAME, ¬ify_hooks); + + return B_OK; + +err: // Releasing + put_module(usb_name); +err_release: + put_module(hci_name); + return B_ERROR; +} + + +/* called just before the kernel unloads the driver */ +void +uninit_driver(void) +{ + int32 j; + + flowf("uninit_driver()\n"); + + for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) { + + if (publish_names[j] != NULL) + free(publish_names[j]); + + if (bt_usb_devices[j] != NULL) { + // if (connected_dev != NULL) { + // debugf("Device %p still exists.\n", connected_dev); + // } + kill_device(bt_usb_devices[j]); + bt_usb_devices[j] = NULL; + } + + } + + usb->uninstall_notify(DEVICE_NAME); + usb->register_driver(DEVICE_NAME, supported_devices, 1, NULL); + + /* Releasing modules */ + put_module(usb_name); + put_module(hci_name); + // TODO: netbuffers + + delete_sem(dev_table_sem); +} + + +const char** +publish_devices(void) +{ + int32 j; + int32 i = 0; + + char* str; + + flowf("publish_devices()\n"); + + for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) { + if (publish_names[j]) { + free(publish_names[j]); + publish_names[j] = NULL; + } + } + + acquire_sem(dev_table_sem); + for (j = 0; j < MAX_BT_GENERIC_USB_DEVICES; j++) + { + if (bt_usb_devices[j] != NULL && bt_usb_devices[j]->connected) + { + str = strdup(bt_usb_devices[j]->name); + if (str) { + publish_names[i++] = str; + debugf("publishing %s\n", bt_usb_devices[j]->name); + } + } + } + release_sem_etc(dev_table_sem, 1, B_DO_NOT_RESCHEDULE); + + publish_names[i] = NULL; + debugf("published %ld devices\n", i); + +// TODO: this method might make better memory use +// dev_names = (char**)malloc(sizeof (char*) * (dev_count+1)); +// if (dev_names) { +// for (i = 0; i < MAX_NUM_DEVS; i++) { +// if ((dev != NULL) && +// (dev_names[i] = (char*)malloc(strlen(DEVICE_PATH)+2/* num + \n */))) { +// sprintf(dev_names[i], "%s%ld", DEVICE_PATH, dev->num); +// debugf("publishing \"%s\"\n", dev_names[i]); +// } +// } + + return (const char**)publish_names; +} + + +static device_hooks hooks = { + device_open, + device_close, + device_free, + device_control, + device_read, + device_write, + NULL, + NULL, + NULL, + NULL +}; + + +device_hooks* +find_device(const char* name) +{ + debugf("find_device(%s)\n", name); + + return &hooks; +} diff --git a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2generic.h b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2generic.h new file mode 100644 index 0000000000..6ade24431d --- /dev/null +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2generic.h @@ -0,0 +1,107 @@ +/* + * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * + * All rights reserved. Distributed under the terms of the MIT License. + * + */ + +#ifndef _H2GENERIC_H_ +#define _H2GENERIC_H_ + +#include +#include + +#include +#include + +#include + +#include "h2cfg.h" +#include "snet_buffer.h" + +/* USB definitions for the generic device*/ +#define UDCLASS_WIRELESS 0xe0 +#define UDSUBCLASS_RF 0x01 +#define UDPROTO_BLUETOOTH 0x01 + +#define TRANSPORT_NAME "h2" +#define DEVICE_NAME "generic" +#define DEVICE_PATH "bus/bluetooth/" TRANSPORT_NAME "/" DEVICE_NAME + +#define ID DEVICE_NAME ": " /* prefix for debug messages */ + +#define USB_TYPE_CLASS (0x01 << 5) /// Check if it is in some other header +#define USB_TYPE_VENDOR (0x02 << 5) + + +// Expecting nobody is gonna have 16 USB-BT dongles connected in their system +#define MAX_BT_GENERIC_USB_DEVICES 16 + +extern usb_module_info *usb; +extern bt_hci_module_info *hci; +extern struct net_buffer_module_info *nb; + +#define MAX_COMMAND_WINDOW 1 +#define MAX_ACL_OUT_WINDOW 4 +#define MAX_ACL_IN_WINDOW 1 + +#define MAX_NUM_QUEUED_PACKETS 1 +#define NUM_BUFFERS 1 + +typedef struct bt_usb_dev bt_usb_dev; + +struct bt_usb_dev { + const usb_device* dev; /* opaque handle */ + hci_id hdev; /* HCI device id*/ + + char name[B_OS_NAME_LENGTH]; + bool connected; /* is the device plugged into the USB? */ + int32 open_count; /* number of clients of the device */ + int32 num; /* instance number of the device */ + + sem_id lock; /* synchronize access to the device */ + sem_id cmd_complete; /* To synchronize completitions */ + + size_t actual_len; /* length of data returned by command */ + status_t cmd_status; /* result of command */ + + uint8 ctrl_req; + uint8 driver_info; + uint32 state; + + bt_hci_statistics stat; + + const usb_endpoint_info *bulk_in_ep; + uint16 max_packet_size_bulk_in; + const usb_endpoint_info *bulk_out_ep; + uint16 max_packet_size_bulk_out; + const usb_endpoint_info *intr_in_ep; + uint16 max_packet_size_intr_in; + +#ifdef BLUETOOTH_SUPPORTS_SCO + const usb_endpoint_info *iso_in_ep; + const usb_endpoint_info *iso_out_ep; +#endif + + /* This so called rooms, are for dumping the USB RX frames + and try to reuse the allocations. see util submodule */ + struct list eventRoom; + struct list aclRoom; + + // Tx buffers: net_buffers for BT_ACL and snet_buffers for BT_COMMAND + // in the same array + struct list nbuffersTx[BT_DRIVER_TXCOVERAGE]; + uint32 nbuffersPendingTx[BT_DRIVER_TXCOVERAGE]; + + // Rx buffer + net_buffer* nbufferRx[BT_DRIVER_RXCOVERAGE]; /* Wasting 1 pointer for BT_EVENT */ + snet_buffer* eventRx; /* <- which we hold here */ + + // for who ever needs preallocated buffers + struct list snetBufferRecycleTrash; + +}; + +bt_usb_dev* fetch_device(bt_usb_dev* dev, hci_id hid); + +#endif diff --git a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2transactions.c b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2transactions.c new file mode 100644 index 0000000000..2e2f64cdd8 --- /dev/null +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2transactions.c @@ -0,0 +1,402 @@ +/* + * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * + * All rights reserved. Distributed under the terms of the MIT License. + * + */ + +#include "h2generic.h" +#include "h2transactions.h" +#include "h2upper.h" +#include "h2util.h" + +#include +#include +#include + +#include + +#define BT_DEBUG_THIS_MODULE +#include "btDebug.h" + +#if 0 +#pragma mark --- RX Complete --- +#endif + + +status_t +assembly_rx(bt_usb_dev* bdev, bt_packet_t type, void *data, int count) +{ + + net_buffer* nbuf; + snet_buffer* snbuf; + + size_t currentPacketLen; + size_t expectedPacketLen; + + bdev->stat.bytesRX += count; + + while (count) { + + if (type == BT_EVENT) + snbuf = bdev->eventRx; + else + nbuf = bdev->nbufferRx[type]; + + debugf("count %d %p %p\n",count, nbuf, nb); + + + if ( (type != BT_EVENT && nbuf == NULL) || + (type == BT_EVENT && snb_completed(snbuf)) ) { + + /* new buffer incoming */ + switch (type) { + case BT_EVENT: + if (count >= HCI_EVENT_HDR_SIZE) { + + struct hci_event_header* headerPkt = data; + expectedPacketLen = HCI_EVENT_HDR_SIZE + headerPkt->elen; + snbuf = bdev->eventRx = snb_fetch(&bdev->snetBufferRecycleTrash, expectedPacketLen); + + } else { + flowf("EVENT frame corrupted\n"); + return -EILSEQ; + } + break; + + case BT_ACL: + if (count >= HCI_ACL_HDR_SIZE) { + + struct hci_acl_header* headerPkt = data; + expectedPacketLen = HCI_ACL_HDR_SIZE + B_LENDIAN_TO_HOST_INT16(headerPkt->alen); + + /* Create the buffer */ + bdev->nbufferRx[type] = nbuf = nb->create(expectedPacketLen); + nbuf->protocol = type; + + + } else { + flowf("ACL frame corrupted\n"); + return -EILSEQ; + } + break; + + case BT_SCO: + break; + + default: + panic("unkown packet type in assembly"); + break; + } +#if 0 + if (nb == NULL) { + port_id port; + /* Coded for test purpose only we should panic here */ + debugf("net_buffers are not ready post manually %d/%d\n",count,expectedPacketLen); + port = find_port(BT_USERLAND_PORT_NAME); + if (port != B_NAME_NOT_FOUND) { + (void)write_port(port, PACK_HEADER_PORT(bdev->num,type), data, count); + return B_OK; + } + panic("Algorithm just ready to arrive here"); + return B_ERROR; + } +#endif + + currentPacketLen = expectedPacketLen; + + } + else { + /* Continuation */ + if (type == BT_EVENT) + currentPacketLen = get_expected_size(nbuf) - nbuf->size; + else + currentPacketLen = snb_remaining_to_put(snbuf); + } + + currentPacketLen = min(currentPacketLen, count); + + if (type == BT_EVENT) + snb_put(snbuf, data, currentPacketLen); + else + nb->append(nbuf, data, currentPacketLen); + + /* Complete frame? */ + if (type == BT_EVENT && snb_completed(snbuf)) { + + flowf("Frame goes up!\n"); + snbuf = bdev->eventRx = NULL; + post_packet_up(bdev, type, snbuf); + + + } + + if (type != BT_EVENT && (get_expected_size(nbuf) - nbuf->size) == 0 ) { + + flowf("Frame goes up!\n"); + bdev->nbufferRx[type] = nbuf = NULL; + post_packet_up(bdev, type, nbuf); + } + + /* in case in the pipe there is info about the next buffer ... */ + count -= currentPacketLen; + data += currentPacketLen; + } +} + +void +event_complete(void* cookie, uint32 status, void* data, uint32 actual_len) +{ + + bt_usb_dev* bdev = cookie; + status_t err; + + /* TODO: check are we running? */ + + if (status != B_OK || actual_len == 0) + goto resubmit; + + if ( assembly_rx(cookie, BT_EVENT, data, actual_len) == B_OK ) { + bdev->stat.successfulTX++; + } else { + bdev->stat.errorRX++; + } + +resubmit: + + err = usb->queue_interrupt(bdev->intr_in_ep->handle, + data, bdev->max_packet_size_intr_in , + event_complete, bdev); + + if (err != B_OK ) { + reuse_room(&bdev->eventRoom, data); + bdev->stat.rejectedRX++; + debugf("RX event resubmittion failed %s\n",strerror(err)); + } + else { + bdev->stat.acceptedRX++; + } + +} + +void +acl_rx_complete(void* cookie, uint32 status, void* data, uint32 actual_len) +{ + bt_usb_dev* bdev = cookie; + status_t err; + + /* TODO: check are we running? */ + + if (status != B_OK || actual_len == 0) + goto resubmit; + + if ( assembly_rx(cookie, BT_ACL, data, actual_len) == B_OK ) { + bdev->stat.successfulRX++; + } else { + bdev->stat.errorRX++; + } + +resubmit: + + err = usb->queue_bulk(bdev->bulk_in_ep->handle, data, + max(HCI_MAX_FRAME_SIZE,bdev->max_packet_size_bulk_in), + acl_rx_complete, bdev); + + if (err != B_OK ) { + reuse_room(&bdev->aclRoom, data); + bdev->stat.rejectedRX++; + debugf("RX acl resubmittion failed %s\n",strerror(err)); + } + else { + bdev->stat.acceptedRX++; + } +} + +#if 0 +#pragma mark --- RX --- +#endif + +status_t +submit_rx_event(bt_usb_dev* bdev) +{ + status_t err; + size_t size = bdev->max_packet_size_intr_in; + void* buf = alloc_room(&bdev->eventRoom, size); + + if (buf == NULL) + return ENOMEM; + + err = usb->queue_interrupt(bdev->intr_in_ep->handle, + buf, size , + event_complete, bdev); + if (err != B_OK ) { + reuse_room(&bdev->eventRoom, buf); + bdev->stat.rejectedRX++; + } + else { + bdev->stat.acceptedRX++; + debugf("Accepted RX Event\n",bdev->stat.acceptedRX); + } + + return err; +} + + +status_t +submit_rx_acl(bt_usb_dev* bdev) +{ + + status_t err; + size_t size = max(HCI_MAX_FRAME_SIZE,bdev->max_packet_size_bulk_in); + void* buf = alloc_room(&bdev->aclRoom, size); + + if (buf == NULL) + return ENOMEM; + + err = usb->queue_bulk(bdev->bulk_in_ep->handle, buf, size , + acl_rx_complete, bdev); + + if (err != B_OK ) { + reuse_room(&bdev->aclRoom, buf); + bdev->stat.rejectedRX++; + } + else { + bdev->stat.acceptedRX++; + } + + return B_ERROR; +} + + +status_t +submit_rx_sco(bt_usb_dev* bdev) +{ + + /* not yet implemented */ + return B_ERROR; +} + + + +#if 0 +#pragma mark --- TX Complete --- +#endif + +void +command_complete(void* cookie, uint32 status, void* data, uint32 actual_len) +{ + snet_buffer* snbuf = (snet_buffer*) cookie; + bt_usb_dev* bdev = snb_cookie(snbuf); + status_t err; + + debugf("%d %02x:%02x:%02x:\n", actual_len, ((uint8*)data)[0],((uint8*)data)[1],((uint8*)data)[2]); + + if (status != B_OK) { + + bdev->stat.successfulTX++; + bdev->stat.bytesTX += actual_len; + } + else { + bdev->stat.errorTX++; + /* the packet has been lost */ + /* too late to requeue it? */ + } + + snb_park(&bdev->snetBufferRecycleTrash, snbuf); + +#ifdef BT_RESCHEDULING_AFTER_COMPLETITIONS + // TODO: check just the empty queues? + schedTxProcessing(bdev); +#endif +} + +void +aclTxComplete(void* cookie, uint32 status, void* data, uint32 actual_len) +{ + + net_buffer* nbuf = (net_buffer*) cookie; + bt_usb_dev* bdev = GET_DEVICE(nbuf); + status_t err; + + if (status != B_OK) { + + bdev->stat.successfulTX++; + bdev->stat.bytesTX += actual_len; + } + else { + bdev->stat.errorTX++; + /* the packet has been lost */ + /* too late to requeue it? */ + } + + nb_destroy(nbuf); +#ifdef BT_RESCHEDULING_AFTER_COMPLETITIONS + schedTxProcessing(bdev); +#endif +} + + +#if 0 +#pragma mark --- TX --- +#endif + +status_t +submit_tx_command(bt_usb_dev* bdev, snet_buffer* snbuf) +{ + status_t err; + + uint8 bRequestType = bdev->ctrl_req; + uint8 bRequest = 0; + uint16 wIndex = 0; + uint16 value = 0; + uint16 wLength = B_HOST_TO_LENDIAN_INT16(snb_size(snbuf)); + + /* set cookie */ + snb_set_cookie(snbuf, bdev); + + err = usb->queue_request(bdev->dev, bRequestType, bRequest, + value, wIndex, wLength, + snb_get(snbuf), wLength //??? + ,command_complete, snbuf); + + if (err != B_OK ) { + bdev->stat.rejectedTX++; + } + else { + bdev->stat.acceptedTX++; + } + + return err; +} + +status_t +submit_tx_acl(bt_usb_dev* bdev, net_buffer* nbuf) +{ + status_t err; + + /* set cookie */ + SET_DEVICE(nbuf,bdev->hdev); + + err = usb->queue_bulk(bdev->bulk_out_ep->handle, + nb_get_whole_buffer(nbuf), nbuf->size, + aclTxComplete, nbuf); + + if (err != B_OK ) { + bdev->stat.rejectedTX++; + } + else { + bdev->stat.acceptedTX++; + } + + return err; +} + + +status_t +submit_tx_sco(bt_usb_dev* bdev) +{ + + /* not yet implemented */ + return B_ERROR; +} + diff --git a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2transactions.h b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2transactions.h new file mode 100644 index 0000000000..7bd2b75e5e --- /dev/null +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2transactions.h @@ -0,0 +1,21 @@ +/* + * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * + * All rights reserved. Distributed under the terms of the MIT License. + * + */ + +#ifndef _H2TRANSACTION_H_ +#define _H2TRANSACTION_H_ + +#include "h2generic.h" + +status_t submit_rx_event(bt_usb_dev* bdev); +status_t submit_rx_acl(bt_usb_dev* bdev); +status_t submit_rx_sco(bt_usb_dev* bdev); + +status_t submit_tx_command(bt_usb_dev* bdev, snet_buffer* snbuf); +status_t submit_tx_acl(bt_usb_dev* bdev, net_buffer* nbuf); +status_t submit_tx_sco(bt_usb_dev* bdev); + +#endif \ No newline at end of file diff --git a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2upper.c b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2upper.c new file mode 100644 index 0000000000..002cf4acf0 --- /dev/null +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2upper.c @@ -0,0 +1,201 @@ +/* + * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * + * All rights reserved. Distributed under the terms of the MIT License. + * + */ + +#include "h2upper.h" +#include "h2transactions.h" + +#define BT_DEBUG_THIS_MODULE +#include "btDebug.h" + +#include +#include + +#include "snet_buffer.h" + +/* TODO: split for commands and comunication(ACL&SCO) */ +void +sched_tx_processing(bt_usb_dev* bdev) +{ + + net_buffer* nbuf; + snet_buffer* snbuf; + status_t err; + flowf("sched\n") + if (!TEST_AND_SET(&bdev->state, PROCESSING)) { + /* We are not processing in another thread so... START!! */ + + do { + /* Do while this bit is on... so someone should set it before we stop the iterations*/ + CLEAR_BIT(bdev->state, SENDING); + /* check Commands*/ + #ifdef EMPTY_COMMAND_QUEUE + while (!list_is_empty(&bdev->nbuffersTx[BT_COMMAND]) ) { + #else + if (!list_is_empty(&bdev->nbuffersTx[BT_COMMAND]) ) { + #endif + snbuf = list_remove_head_item(&bdev->nbuffersTx[BT_COMMAND]); + err = submit_tx_command(bdev, snbuf); + if (err != B_OK) { + /* re-head it*/ + list_insert_item_before(&bdev->nbuffersTx[BT_COMMAND], + list_get_first_item(&bdev->nbuffersTx[BT_COMMAND]), snbuf); + } + } + + /* check Acl */ + #define EMPTY_ACL_QUEUE + #ifdef EMPTY_ACL_QUEUE + while (!list_is_empty(&bdev->nbuffersTx[BT_ACL]) ) { + #else + if (!list_is_empty(&bdev->nbuffersTx[BT_ACL]) ) { + #endif + nbuf = list_remove_head_item(&bdev->nbuffersTx[BT_ACL]); + err = submit_tx_acl(bdev, nbuf); + if (err != B_OK) { + /* re-head it*/ + list_insert_item_before(&bdev->nbuffersTx[BT_ACL], + list_get_first_item(&bdev->nbuffersTx[BT_ACL]), nbuf); + } + + } + + if (!list_is_empty(&bdev->nbuffersTx[BT_SCO]) ) { + /* TODO to be implemented */ + + } + + + } while (GET_BIT(bdev->state, SENDING)); + + CLEAR_BIT(bdev->state, PROCESSING); + + } else { + /* We are processing so MARK that we need to still go on with that ... */ + SET_BIT(bdev->state, SENDING); + } + +} + +status_t +post_packet_up(bt_usb_dev* bdev, bt_packet_t type, void* buf) +{ + + status_t err; + port_id port; + + if (hci == NULL) { + + err = B_ERROR; + + // ERROR but we will try to send if its a event! + if (type != BT_EVENT) { + err = B_ERROR; + } else { + snet_buffer* snbuf = (snet_buffer*)buf; + + flowf("HCI not present, Posting to userland\n"); + port = find_port(BT_USERLAND_PORT_NAME); + if (port != B_NAME_NOT_FOUND) { + + + err = write_port_etc(port, PACK_HEADER_PORT(bdev->num,type), + snb_get(snbuf), snb_size(snbuf), B_TIMEOUT, 1*1000*1000); + if (err != B_OK) + debugf("Error posting userland %s\n",strerror(err)); + + } + else { + flowf("ERROR:bluetooth_server not found for posting\n"); + err = B_NAME_NOT_FOUND; + } + /* No need to free the buffer at allocation is gonna be reused */ + } + } + else { + // TODO: Upper layer comunication + /* Not freeing because is being used by upper layers*/ + } + + + return err; +} + +status_t +send_packet(hci_id hid, bt_packet_t type, net_buffer* nbuf) +{ + bt_usb_dev* bdev = fetch_device(NULL, hid); + status_t err = B_OK; + + if (bdev == NULL) + return B_ERROR; + + // TODO: check if device is actually ready for this + // TODO: Lock Device + + if (nbuf != NULL) { + if (type != nbuf->protocol) // a bit strict maybe? + panic("Upper layer has not filled correctly a packet"); + + switch (type) { + case BT_COMMAND: + case BT_ACL: + case BT_SCO: + + list_add_item(&bdev->nbuffersTx[type],nbuf); + bdev->nbuffersPendingTx[type]++; + break; + default: + debugf("Unkown packet type for sending %d\n",type); + // TODO: free the net_buffer -> no, allow upper layer + // handle it with the given error + err = B_BAD_VALUE; + break; + } + } else { + flowf("tx sched provoked"); + } + + // TODO: check if device is actually ready for this + // TODO: unLock device + + /* sched in All cases even if nbuf is null (hidden way to provoke re-scheduling)*/ + sched_tx_processing(bdev); + + return err; +} + + +status_t +send_command(hci_id hid, snet_buffer* snbuf) +{ + + bt_usb_dev* bdev = fetch_device(NULL, hid); + status_t err = B_OK; + + if (bdev == NULL) + return B_ERROR; + + // TODO: check if device is actually ready for this + // TODO: mutex? + + if (snbuf != NULL) { + + list_add_item(&bdev->nbuffersTx[BT_COMMAND],snbuf); + bdev->nbuffersPendingTx[BT_COMMAND]++; + } else { + err = B_BAD_VALUE; + flowf("tx sched provoked"); + } + + // TODO: check if device is actually ready for this + // TODO: mutex? + + /* sched in All cases even if nbuf is null (hidden way to provoke re-scheduling)*/ + sched_tx_processing(bdev); + + return err; +} diff --git a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2upper.h b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2upper.h new file mode 100644 index 0000000000..cd5b1b74ec --- /dev/null +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2upper.h @@ -0,0 +1,22 @@ +/* + * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * + * All rights reserved. Distributed under the terms of the MIT License. + * + */ + +#ifndef _H2UPPER_H_ +#define _H2UPPER_H_ + +#include + +#include "h2generic.h" + +#define PACK_HEADER_PORT(x,y) (x<<24|y<<16) + +status_t post_packet_up(bt_usb_dev* bdev, bt_packet_t type, void* buf); +status_t send_packet(hci_id hid, bt_packet_t type, net_buffer* nbuf); + +void sched_tx_processing(bt_usb_dev* bdev); + +#endif \ No newline at end of file diff --git a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2util.c b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2util.c new file mode 100644 index 0000000000..fcc5be1545 --- /dev/null +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2util.c @@ -0,0 +1,147 @@ +/* + * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * + * All rights reserved. Distributed under the terms of the MIT License. + * + */ + +#include "h2upper.h" +#include "h2util.h" +#include "h2transactions.h" + +#define BT_DEBUG_THIS_MODULE +#include "btDebug.h" + +#include +#include +#include +#include + +void* +nb_get_whole_buffer(net_buffer* nbuf) +{ + + void* conPointer; + status_t err; + + /* the job could be already done */ + // !!! it could be trash from other upper protocols... + if (nbuf->COOKIEFIELD != NULL) + return (void*)nbuf->COOKIEFIELD; + + if (nb == NULL) + goto fail; + + err = nb->direct_access(nbuf, 0, nbuf->size, &conPointer); + + if (err != B_OK) { + + /* pity, we are gonna need a realocation */ + nbuf->COOKIEFIELD = (uint32) malloc(nbuf->size); + if (nbuf->COOKIEFIELD == NULL) + goto fail; + + err = nb->write(nbuf, 0, (void*) nbuf->COOKIEFIELD, nbuf->size); + if (err != B_OK) + goto free; + + conPointer = (void*)nbuf->COOKIEFIELD; + + } + + return conPointer; + +free: + free(nbuf->COOKIEFIELD); +fail: + return NULL; +} + + +void +nb_destroy(net_buffer* nbuf) +{ + + /* Free possible allocated */ + if (nbuf->COOKIEFIELD != NULL) + free((void*)nbuf->COOKIEFIELD); + +// TODO check for survivers... + if (nb != NULL) + nb->free(nbuf); + +} + + +/* Check from the completition if the queue is empty */ +size_t +get_expected_size(net_buffer* nbuf) +{ + + if (nbuf == NULL) + panic("Analizing NULL packet"); + + switch (nbuf->protocol) { + + case BT_ACL: { + struct hci_acl_header* header = nb_get_whole_buffer(nbuf); + return header->alen; + } + + case BT_COMMAND: { + struct hci_command_header* header = nb_get_whole_buffer(nbuf); + return header->clen; + } + + + case BT_EVENT: { + struct hci_event_header* header = nb_get_whole_buffer(nbuf); + return header->elen; + } + default: + + break; + } +} + +#if 0 +#pragma mark - room util - +#endif + +inline void +init_room(struct list* l) +{ + list_init(l); +} + + +void* +alloc_room(struct list* l, size_t size) +{ + + void* item = list_get_first_item(l); + + if (item == NULL) + item = (void*) malloc(size); + + return item; + +} + + +inline void +reuse_room(struct list* l, void* room) +{ + list_add_item(l, room); +} + + +void +purge_room(struct list* l) +{ + void* item; + + while ((item = list_remove_head_item(l)) != NULL) { + free(item); + } +} diff --git a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2util.h b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2util.h new file mode 100644 index 0000000000..5ba3c678a2 --- /dev/null +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2util.h @@ -0,0 +1,34 @@ +/* + * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * + * All rights reserved. Distributed under the terms of the MIT License. + * + */ + +#ifndef _H2UTIL_H_ +#define _H2UTIL_H_ + +#include + +#include "h2generic.h" + +/* net buffer utils for ACL, to be reviwed */ +#define DEVICEFIELD type +#define SET_DEVICE(nbuf,hid) (nbuf->DEVICEFIELD=(nbuf->DEVICEFIELD&0xFFF0)|(hid&0xF)) +#define GET_DEVICE(nbuf) fetch_device(NULL,(nbuf->DEVICEFIELD&0x0F)) + +#define COOKIEFIELD flags +void* nb_get_whole_buffer(net_buffer* nbuf); +void nb_destroy(net_buffer* nbuf); +size_t get_expected_size(net_buffer* nbuf); + +/* Room utils */ +inline void init_room(struct list* l); +void* alloc_room(struct list* l, size_t size); +inline void reuse_room(struct list* l, void* room); +void purge_room(struct list* l); + +/* list utils */ +#define list_purge(x) purge_room(x) + +#endif