diff --git a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2cfg.h b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2cfg.h index a990dcdbfe..471fd61c17 100644 --- a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2cfg.h +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2cfg.h @@ -1,43 +1,43 @@ -/* - * 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_ - - -#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 - -/* TODO: move exclusive header for drivers*/ -#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 - -//////////////////////////////////// - -#ifndef BLUETOOTH_DEVICE_TRANSPORT -#error BLUETOOTH_DEVICE_TRANSPORT must be defined to build the publishing path -#endif - -#ifndef BLUETOOTH_DEVICE_NAME -#error BLUETOOTH_DEVICE_NAME must be defined to build the publishing path -#endif - -#define BLUETOOTH_DEVICE_DEVFS_NAME BLUETOOTH_DEVICE_TRANSPORT BLUETOOTH_DEVICE_NAME -#define BLUETOOTH_DEVICE_PATH "bluetooth/" BLUETOOTH_DEVICE_DEVFS_NAME - - -#endif +/* + * 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_ + + +#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 + +/* TODO: move exclusive header for drivers*/ +#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 + +//////////////////////////////////// + +#ifndef BLUETOOTH_DEVICE_TRANSPORT +#error BLUETOOTH_DEVICE_TRANSPORT must be defined to build the publishing path +#endif + +#ifndef BLUETOOTH_DEVICE_NAME +#error BLUETOOTH_DEVICE_NAME must be defined to build the publishing path +#endif + +#define BLUETOOTH_DEVICE_DEVFS_NAME BLUETOOTH_DEVICE_TRANSPORT BLUETOOTH_DEVICE_NAME +#define BLUETOOTH_DEVICE_PATH "bluetooth/" BLUETOOTH_DEVICE_DEVFS_NAME + + +#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 index fe5ef65033..394a18b7bb 100644 --- a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2generic.c +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2generic.c @@ -1,829 +1,829 @@ -/* - * 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 "snet_buffer.h" - -#include -#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 = 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, BLUETOOTH_DEVICE_DEVFS_NAME "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, BLUETOOTH_DEVICE_DEVFS_NAME "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", BLUETOOTH_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) -{ - 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; - - debugf("device_added(%p, %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; - - 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); - - flowf(" successful\n"); - 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 %ld\n", 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 \n",BLUETOOTH_DEVICE_PATH); - - - 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* bdev = (bt_usb_dev*)cookie; - snet_buffer* snbuf; - TOUCH(size); - - debugf("ioctl() opcode %ld size %ld.\n", msg, size); - - if (bdev == NULL) { - flowf("Bad cookie\n"); - return B_BAD_VALUE; - } - - if (params == NULL) { - flowf("Invalid pointer control\n"); - return B_BAD_VALUE; - } - - acquire_sem(bdev->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**)¶ms)++; -#endif - - // TODO: Reuse from some TXcompleted queue - snbuf = snb_create(size); - snb_put(snbuf, params, size); - - err = submit_tx_command(bdev, snbuf); - - break; - - case GET_STATICS: - memcpy(params, &bdev->stat, sizeof(bt_hci_statistics)); - err = B_OK; - break; - - case GET_HCI_ID: - *(hci_id*)params = bdev->hdev; - err = B_OK; - break; - - - default: - debugf("Invalid opcode %ld.\n", msg); - err = B_DEV_INVALID_IOCTL; - break; - } - - release_sem(bdev->lock); - return err; -} - - -/* implements the POSIX read() */ -static status_t -device_read(void *cookie, off_t pos, void *buf, size_t *count) -{ - debugf("Reading... count = %ld\n", *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, BLUETOOTH_DEVICE_DEVFS_NAME "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(BLUETOOTH_DEVICE_DEVFS_NAME, supported_devices, 1, NULL); - usb->install_notify(BLUETOOTH_DEVICE_DEVFS_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(BLUETOOTH_DEVICE_DEVFS_NAME); - - /* 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; -} +/* + * 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 "snet_buffer.h" + +#include +#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 = 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, BLUETOOTH_DEVICE_DEVFS_NAME "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, BLUETOOTH_DEVICE_DEVFS_NAME "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", BLUETOOTH_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) +{ + 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; + + debugf("device_added(%p, %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; + + 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); + + flowf(" successful\n"); + 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 %ld\n", 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 \n",BLUETOOTH_DEVICE_PATH); + + + 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* bdev = (bt_usb_dev*)cookie; + snet_buffer* snbuf; + TOUCH(size); + + debugf("ioctl() opcode %ld size %ld.\n", msg, size); + + if (bdev == NULL) { + flowf("Bad cookie\n"); + return B_BAD_VALUE; + } + + if (params == NULL) { + flowf("Invalid pointer control\n"); + return B_BAD_VALUE; + } + + acquire_sem(bdev->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**)¶ms)++; +#endif + + // TODO: Reuse from some TXcompleted queue + snbuf = snb_create(size); + snb_put(snbuf, params, size); + + err = submit_tx_command(bdev, snbuf); + + break; + + case GET_STATICS: + memcpy(params, &bdev->stat, sizeof(bt_hci_statistics)); + err = B_OK; + break; + + case GET_HCI_ID: + *(hci_id*)params = bdev->hdev; + err = B_OK; + break; + + + default: + debugf("Invalid opcode %ld.\n", msg); + err = B_DEV_INVALID_IOCTL; + break; + } + + release_sem(bdev->lock); + return err; +} + + +/* implements the POSIX read() */ +static status_t +device_read(void *cookie, off_t pos, void *buf, size_t *count) +{ + debugf("Reading... count = %ld\n", *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, BLUETOOTH_DEVICE_DEVFS_NAME "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(BLUETOOTH_DEVICE_DEVFS_NAME, supported_devices, 1, NULL); + usb->install_notify(BLUETOOTH_DEVICE_DEVFS_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(BLUETOOTH_DEVICE_DEVFS_NAME); + + /* 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/h2transactions.c b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2transactions.c index 7862b2be96..edc7826fb6 100644 --- a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2transactions.c +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2transactions.c @@ -1,458 +1,458 @@ -/* - * 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 - -#include - -#define BT_DEBUG_THIS_MODULE -#include - - -/* Forward declaration */ - -#ifndef HAIKU_TARGET_PLATFORM_HAIKU -void acl_tx_complete(void* cookie, uint32 status, void* data, uint32 actual_len); -void acl_rx_complete(void* cookie, uint32 status, void* data, uint32 actual_len); -void command_complete(void* cookie, uint32 status, void* data, uint32 actual_len); -void event_complete(void* cookie, uint32 status, void* data, uint32 actual_len); -#else -void acl_tx_complete(void* cookie, status_t status, void* data, size_t actual_len); -void acl_rx_complete(void* cookie, status_t status, void* data, size_t actual_len); -void command_complete(void* cookie, status_t status, void* data, size_t actual_len); -void event_complete(void* cookie, status_t status, void* data, size_t actual_len); -#endif - - -static status_t -assembly_rx(bt_usb_dev* bdev, bt_packet_t type, void *data, int count) -{ - - net_buffer* nbuf = NULL; - snet_buffer* snbuf = NULL; - - size_t currentPacketLen = 0; - size_t expectedPacketLen = 0; - - bdev->stat.bytesRX += count; - - if (type == BT_EVENT) - snbuf = bdev->eventRx; - else - nbuf = bdev->nbufferRx[type]; - - while (count) { - - debugf("count %d %p %p\n",count, nbuf, nb); - - - if ( (type != BT_EVENT && nbuf == NULL) || - (type == BT_EVENT && (snbuf == NULL || 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"); - post_packet_up(bdev, type, snbuf); - snbuf = bdev->eventRx = NULL; - - } - - if (type != BT_EVENT && (get_expected_size(nbuf) - nbuf->size) == 0 ) { - - flowf("Frame goes up!\n"); - post_packet_up(bdev, type, nbuf); - bdev->nbufferRx[type] = nbuf = NULL; - } - - /* in case in the pipe there is info about the next buffer ... */ - count -= currentPacketLen; - data += currentPacketLen; - } - - return B_OK; -} - - -#if 0 -#pragma mark --- RX Complete --- -#endif - - -void -#ifndef HAIKU_TARGET_PLATFORM_HAIKU -event_complete(void* cookie, uint32 status, void* data, uint32 actual_len) -#else -event_complete(void* cookie, status_t status, void* data, size_t actual_len) -#endif -{ - - bt_usb_dev* bdev = cookie; - status_t err; - - /* TODO: or not running anymore */ - if (status == B_CANCELED) - return; - - 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 -#ifndef HAIKU_TARGET_PLATFORM_HAIKU -acl_rx_complete(void* cookie, uint32 status, void* data, uint32 actual_len) -#else -acl_rx_complete(void* cookie, status_t status, void* data, size_t actual_len) -#endif -{ - bt_usb_dev* bdev = cookie; - status_t err; - - /* TODO: or not running anymore? */ - if (status == B_CANCELED) - return; - - 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, (void*) 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, (void*) bdev); - if (err != B_OK ) { - reuse_room(&bdev->eventRoom, buf); - bdev->stat.rejectedRX++; - } - else { - bdev->stat.acceptedRX++; - debugf("Accepted RX Event %d\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 -#ifndef HAIKU_TARGET_PLATFORM_HAIKU -command_complete(void* cookie, uint32 status, void* data, uint32 actual_len) -#else -command_complete(void* cookie, status_t status, void* data, size_t actual_len) -#endif -{ - snet_buffer* snbuf = (snet_buffer*) cookie; - bt_usb_dev* bdev = snb_cookie(snbuf); - - debugf("%ld %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 -#ifndef HAIKU_TARGET_PLATFORM_HAIKU -acl_tx_complete(void* cookie, uint32 status, void* data, uint32 actual_len) -#else -acl_tx_complete(void* cookie, status_t status, void* data, size_t actual_len) -#endif - -{ - - net_buffer* nbuf = (net_buffer*) cookie; - bt_usb_dev* bdev = GET_DEVICE(nbuf); - - 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)); - - if (!GET_BIT(bdev->state, RUNNING) ) { - return B_DEV_NOT_READY; - } - - /* set cookie */ - snb_set_cookie(snbuf, bdev); - - err = usb->queue_request(bdev->dev, bRequestType, bRequest, - value, wIndex, wLength, - snb_get(snbuf), wLength //??? - ,command_complete, (void*) 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); - - if (!GET_BIT(bdev->state, RUNNING) ) { - return B_DEV_NOT_READY; - } - - - err = usb->queue_bulk(bdev->bulk_out_ep->handle, - nb_get_whole_buffer(nbuf), nbuf->size, - acl_tx_complete, (void*) nbuf); - - if (err != B_OK ) { - bdev->stat.rejectedTX++; - } - else { - bdev->stat.acceptedTX++; - } - - return err; -} - - -status_t -submit_tx_sco(bt_usb_dev* bdev) -{ - - if (!GET_BIT(bdev->state, RUNNING) ) { - return B_DEV_NOT_READY; - } - - /* not yet implemented */ - return B_ERROR; -} - +/* + * 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 + +#include + +#define BT_DEBUG_THIS_MODULE +#include + + +/* Forward declaration */ + +#ifndef HAIKU_TARGET_PLATFORM_HAIKU +void acl_tx_complete(void* cookie, uint32 status, void* data, uint32 actual_len); +void acl_rx_complete(void* cookie, uint32 status, void* data, uint32 actual_len); +void command_complete(void* cookie, uint32 status, void* data, uint32 actual_len); +void event_complete(void* cookie, uint32 status, void* data, uint32 actual_len); +#else +void acl_tx_complete(void* cookie, status_t status, void* data, size_t actual_len); +void acl_rx_complete(void* cookie, status_t status, void* data, size_t actual_len); +void command_complete(void* cookie, status_t status, void* data, size_t actual_len); +void event_complete(void* cookie, status_t status, void* data, size_t actual_len); +#endif + + +static status_t +assembly_rx(bt_usb_dev* bdev, bt_packet_t type, void *data, int count) +{ + + net_buffer* nbuf = NULL; + snet_buffer* snbuf = NULL; + + size_t currentPacketLen = 0; + size_t expectedPacketLen = 0; + + bdev->stat.bytesRX += count; + + if (type == BT_EVENT) + snbuf = bdev->eventRx; + else + nbuf = bdev->nbufferRx[type]; + + while (count) { + + debugf("count %d %p %p\n",count, nbuf, nb); + + + if ( (type != BT_EVENT && nbuf == NULL) || + (type == BT_EVENT && (snbuf == NULL || 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"); + post_packet_up(bdev, type, snbuf); + snbuf = bdev->eventRx = NULL; + + } + + if (type != BT_EVENT && (get_expected_size(nbuf) - nbuf->size) == 0 ) { + + flowf("Frame goes up!\n"); + post_packet_up(bdev, type, nbuf); + bdev->nbufferRx[type] = nbuf = NULL; + } + + /* in case in the pipe there is info about the next buffer ... */ + count -= currentPacketLen; + data += currentPacketLen; + } + + return B_OK; +} + + +#if 0 +#pragma mark --- RX Complete --- +#endif + + +void +#ifndef HAIKU_TARGET_PLATFORM_HAIKU +event_complete(void* cookie, uint32 status, void* data, uint32 actual_len) +#else +event_complete(void* cookie, status_t status, void* data, size_t actual_len) +#endif +{ + + bt_usb_dev* bdev = cookie; + status_t err; + + /* TODO: or not running anymore */ + if (status == B_CANCELED) + return; + + 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 +#ifndef HAIKU_TARGET_PLATFORM_HAIKU +acl_rx_complete(void* cookie, uint32 status, void* data, uint32 actual_len) +#else +acl_rx_complete(void* cookie, status_t status, void* data, size_t actual_len) +#endif +{ + bt_usb_dev* bdev = cookie; + status_t err; + + /* TODO: or not running anymore? */ + if (status == B_CANCELED) + return; + + 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, (void*) 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, (void*) bdev); + if (err != B_OK ) { + reuse_room(&bdev->eventRoom, buf); + bdev->stat.rejectedRX++; + } + else { + bdev->stat.acceptedRX++; + debugf("Accepted RX Event %d\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 +#ifndef HAIKU_TARGET_PLATFORM_HAIKU +command_complete(void* cookie, uint32 status, void* data, uint32 actual_len) +#else +command_complete(void* cookie, status_t status, void* data, size_t actual_len) +#endif +{ + snet_buffer* snbuf = (snet_buffer*) cookie; + bt_usb_dev* bdev = snb_cookie(snbuf); + + debugf("%ld %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 +#ifndef HAIKU_TARGET_PLATFORM_HAIKU +acl_tx_complete(void* cookie, uint32 status, void* data, uint32 actual_len) +#else +acl_tx_complete(void* cookie, status_t status, void* data, size_t actual_len) +#endif + +{ + + net_buffer* nbuf = (net_buffer*) cookie; + bt_usb_dev* bdev = GET_DEVICE(nbuf); + + 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)); + + if (!GET_BIT(bdev->state, RUNNING) ) { + return B_DEV_NOT_READY; + } + + /* set cookie */ + snb_set_cookie(snbuf, bdev); + + err = usb->queue_request(bdev->dev, bRequestType, bRequest, + value, wIndex, wLength, + snb_get(snbuf), wLength //??? + ,command_complete, (void*) 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); + + if (!GET_BIT(bdev->state, RUNNING) ) { + return B_DEV_NOT_READY; + } + + + err = usb->queue_bulk(bdev->bulk_out_ep->handle, + nb_get_whole_buffer(nbuf), nbuf->size, + acl_tx_complete, (void*) nbuf); + + if (err != B_OK ) { + bdev->stat.rejectedTX++; + } + else { + bdev->stat.acceptedTX++; + } + + return err; +} + + +status_t +submit_tx_sco(bt_usb_dev* bdev) +{ + + if (!GET_BIT(bdev->state, RUNNING) ) { + return B_DEV_NOT_READY; + } + + /* 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 index 7bd2b75e5e..92137527b2 100644 --- a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2transactions.h +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2transactions.h @@ -1,21 +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); - +/* + * 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 index 4b7ee8a59a..d3e644db96 100644 --- a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2upper.c +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2upper.c @@ -1,203 +1,203 @@ -/* - * 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 "h2upper.h" -#include "h2transactions.h" -#include "snet_buffer.h" - -#define BT_DEBUG_THIS_MODULE -#include - - -/* 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 = B_OK; - port_id port; - - if (hci == NULL) { - - err = B_ERROR; - - // ERROR but we will try to send if its a event! - if (type == BT_EVENT) { - - 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_PORTCODE(type,bdev->hdev, -1), - 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; -} +/* + * 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 "h2upper.h" +#include "h2transactions.h" +#include "snet_buffer.h" + +#define BT_DEBUG_THIS_MODULE +#include + + +/* 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 = B_OK; + port_id port; + + if (hci == NULL) { + + err = B_ERROR; + + // ERROR but we will try to send if its a event! + if (type == BT_EVENT) { + + 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_PORTCODE(type,bdev->hdev, -1), + 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 index be6c45b05a..de7be20949 100644 --- a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2upper.h +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2upper.h @@ -1,21 +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 _H2UPPER_H_ -#define _H2UPPER_H_ - -#include - -#include "h2generic.h" - -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); -status_t send_command(hci_id hid, snet_buffer* snbuf); - -void sched_tx_processing(bt_usb_dev* bdev); - +/* + * 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" + +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); +status_t send_command(hci_id hid, snet_buffer* snbuf); + +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 index 78b52a74a7..3bc3c86550 100644 --- a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2util.c +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2util.c @@ -1,150 +1,150 @@ -/* - * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com - * - * All rights reserved. Distributed under the terms of the MIT License. - * - */ - -#include - -#include "h2upper.h" -#include "h2util.h" -#include "h2transactions.h" - -#include -#include -#include - -#define BT_DEBUG_THIS_MODULE -#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((void*) 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; - } - - return B_ERROR; -} - -#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); - } -} +/* + * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * + * All rights reserved. Distributed under the terms of the MIT License. + * + */ + +#include + +#include "h2upper.h" +#include "h2util.h" +#include "h2transactions.h" + +#include +#include +#include + +#define BT_DEBUG_THIS_MODULE +#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((void*) 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; + } + + return B_ERROR; +} + +#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 index 311ad9859b..d859568c64 100644 --- a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2util.h +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/h2util.h @@ -1,34 +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 reviewed */ -#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 +/* + * 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 reviewed */ +#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 diff --git a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/snet_buffer.c b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/snet_buffer.c index 0bd1ab886e..afd4170896 100644 --- a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/snet_buffer.c +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/snet_buffer.c @@ -1,225 +1,225 @@ -/* - * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com - * - * All rights reserved. Distributed under the terms of the MIT License. - * - */ - -#include "snet_buffer.h" - -#include -#include - -struct snet_buffer { - struct list_link link; - - uint8* buffer; - - uint16 allocatedSize; - uint16 expectedSize; - uint16 puttingSize; - uint16 pullingSize; - - void* cookie; - -}; - - -snet_buffer* -snb_create(uint16 size) -{ - /* TODO: pointer checking */ - -#ifdef SNB_BUFFER_ATTACHED - /* Allocating these 2 buffers together might prevent memory fragmentation? */ - snet_buffer* snb = (snet_buffer*) malloc(sizeof(snet_buffer) + size); - snb->buffer = ((uint8*)snb) + sizeof(snet_buffer); -#else - snet_buffer* snb = malloc(sizeof (snet_buffer)); - snb->buffer = malloc(size); -#endif - - snb->pullingSize = snb->puttingSize = 0; - snb->expectedSize = snb->allocatedSize = size; - - return snb; - -} - - -void -snb_put(snet_buffer* snb, void* data, uint16 size) -{ - /* TODO: check overflow */ - memcpy( &snb->buffer[snb->puttingSize], data, size); - snb->puttingSize+=size; -} - - -void* -snb_pull(snet_buffer* snb, uint16 size) -{ - /* TODO: check overflow */ - snb->pullingSize+=size; - return &snb->buffer[snb->pullingSize-size]; - -} - - -inline void -snb_reset(snet_buffer* snb) -{ - snb->puttingSize = snb->pullingSize = 0; -} - - -void -snb_free(snet_buffer* snb) -{ - if (snb == NULL) - return; - -#ifdef SNB_BUFFER_ATTACHED - free(snb); -#else - free(snb->buffer); - free(snb); -#endif - -} - - -inline void* -snb_get(snet_buffer* snb) -{ - /* TODO: pointer checking */ - return snb->buffer; -} - - -inline uint16 -snb_size(snet_buffer* snb) -{ - /* TODO: pointer checking */ - return snb->expectedSize; -} - - -inline void* -snb_cookie(snet_buffer* snb) -{ - /* TODO: pointer checking */ - return snb->cookie; -} - - -inline void -snb_set_cookie(snet_buffer* snb, void* cookie) -{ - /* TODO: pointer checking */ - snb->cookie = cookie; -} - - -/* Return true if we canot "put" more data in the buffer */ -inline bool snb_completed(snet_buffer* snb) -{ - return (snb->expectedSize == snb->puttingSize); -} - - -/* Return true if we cannot pull more more data from the buffer */ -inline bool snb_finished(snet_buffer* snb) -{ - return (snb->expectedSize == snb->pullingSize); -} - - -inline uint16 snb_remaining_to_put(snet_buffer* snb) -{ - return (snb->expectedSize - snb->puttingSize); -} - - -inline uint16 snb_remaining_to_pull(snet_buffer* snb) -{ - return (snb->expectedSize - snb->pullingSize); -} - - -/* ISSUE1: Number of packets in the worst case(we always need a bigger - buffer than before) increases, never decreases: - - SOL1: Delete the smallest when the queue is bigger than X elements - SOL2: ? - - ISSUE2: If the queue is not gonna be used for long time. Memory c - ould be freed - - SOL1: Provide purge func. - SOL2: ? - - */ -static snet_buffer* -snb_attempt_reuse(snet_buffer* snb, uint16 size) -{ - if ( snb == NULL || - ((int16)snb->allocatedSize - (int16)size) < 0 ) { - - /* Impossible or not worth, Creating a new one */ - snb_free(snb); - return snb_create(size); - - } - else { - snb_reset(snb); - snb->expectedSize = size; - return snb; - } - -} - - -void -snb_park(struct list* l, snet_buffer* snb) -{ - snet_buffer* item = NULL; - /* insert it by order */ - while ((item = list_get_next_item(l, item)) != NULL) { - if (item->allocatedSize > snb->allocatedSize) - list_insert_item_before(l, item, snb); - } -} - - -snet_buffer* -snb_fetch(struct list* l, uint16 size) -{ - - snet_buffer* item = NULL; - snet_buffer* previous = NULL; - - if (!list_is_empty(l)) - while ((item = list_get_next_item(l, item)) != NULL) { - if (item->allocatedSize == size) { - /* This one is for us*/ - break; - } - else if (item->allocatedSize > size) { - /* get the previous*/ - item = previous; - break; - } - previous = item; - } - - // reusing previous pointer for another proposit - previous = snb_attempt_reuse(item, size); - - /* the resulting reused one is the same as we fetched? => remove it from list*/ - if (item == previous) { - list_remove_item(l, item); - } - - return previous; -} +/* + * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * + * All rights reserved. Distributed under the terms of the MIT License. + * + */ + +#include "snet_buffer.h" + +#include +#include + +struct snet_buffer { + struct list_link link; + + uint8* buffer; + + uint16 allocatedSize; + uint16 expectedSize; + uint16 puttingSize; + uint16 pullingSize; + + void* cookie; + +}; + + +snet_buffer* +snb_create(uint16 size) +{ + /* TODO: pointer checking */ + +#ifdef SNB_BUFFER_ATTACHED + /* Allocating these 2 buffers together might prevent memory fragmentation? */ + snet_buffer* snb = (snet_buffer*) malloc(sizeof(snet_buffer) + size); + snb->buffer = ((uint8*)snb) + sizeof(snet_buffer); +#else + snet_buffer* snb = malloc(sizeof (snet_buffer)); + snb->buffer = malloc(size); +#endif + + snb->pullingSize = snb->puttingSize = 0; + snb->expectedSize = snb->allocatedSize = size; + + return snb; + +} + + +void +snb_put(snet_buffer* snb, void* data, uint16 size) +{ + /* TODO: check overflow */ + memcpy( &snb->buffer[snb->puttingSize], data, size); + snb->puttingSize+=size; +} + + +void* +snb_pull(snet_buffer* snb, uint16 size) +{ + /* TODO: check overflow */ + snb->pullingSize+=size; + return &snb->buffer[snb->pullingSize-size]; + +} + + +inline void +snb_reset(snet_buffer* snb) +{ + snb->puttingSize = snb->pullingSize = 0; +} + + +void +snb_free(snet_buffer* snb) +{ + if (snb == NULL) + return; + +#ifdef SNB_BUFFER_ATTACHED + free(snb); +#else + free(snb->buffer); + free(snb); +#endif + +} + + +inline void* +snb_get(snet_buffer* snb) +{ + /* TODO: pointer checking */ + return snb->buffer; +} + + +inline uint16 +snb_size(snet_buffer* snb) +{ + /* TODO: pointer checking */ + return snb->expectedSize; +} + + +inline void* +snb_cookie(snet_buffer* snb) +{ + /* TODO: pointer checking */ + return snb->cookie; +} + + +inline void +snb_set_cookie(snet_buffer* snb, void* cookie) +{ + /* TODO: pointer checking */ + snb->cookie = cookie; +} + + +/* Return true if we canot "put" more data in the buffer */ +inline bool snb_completed(snet_buffer* snb) +{ + return (snb->expectedSize == snb->puttingSize); +} + + +/* Return true if we cannot pull more more data from the buffer */ +inline bool snb_finished(snet_buffer* snb) +{ + return (snb->expectedSize == snb->pullingSize); +} + + +inline uint16 snb_remaining_to_put(snet_buffer* snb) +{ + return (snb->expectedSize - snb->puttingSize); +} + + +inline uint16 snb_remaining_to_pull(snet_buffer* snb) +{ + return (snb->expectedSize - snb->pullingSize); +} + + +/* ISSUE1: Number of packets in the worst case(we always need a bigger + buffer than before) increases, never decreases: + + SOL1: Delete the smallest when the queue is bigger than X elements + SOL2: ? + + ISSUE2: If the queue is not gonna be used for long time. Memory c + ould be freed + + SOL1: Provide purge func. + SOL2: ? + + */ +static snet_buffer* +snb_attempt_reuse(snet_buffer* snb, uint16 size) +{ + if ( snb == NULL || + ((int16)snb->allocatedSize - (int16)size) < 0 ) { + + /* Impossible or not worth, Creating a new one */ + snb_free(snb); + return snb_create(size); + + } + else { + snb_reset(snb); + snb->expectedSize = size; + return snb; + } + +} + + +void +snb_park(struct list* l, snet_buffer* snb) +{ + snet_buffer* item = NULL; + /* insert it by order */ + while ((item = list_get_next_item(l, item)) != NULL) { + if (item->allocatedSize > snb->allocatedSize) + list_insert_item_before(l, item, snb); + } +} + + +snet_buffer* +snb_fetch(struct list* l, uint16 size) +{ + + snet_buffer* item = NULL; + snet_buffer* previous = NULL; + + if (!list_is_empty(l)) + while ((item = list_get_next_item(l, item)) != NULL) { + if (item->allocatedSize == size) { + /* This one is for us*/ + break; + } + else if (item->allocatedSize > size) { + /* get the previous*/ + item = previous; + break; + } + previous = item; + } + + // reusing previous pointer for another proposit + previous = snb_attempt_reuse(item, size); + + /* the resulting reused one is the same as we fetched? => remove it from list*/ + if (item == previous) { + list_remove_item(l, item); + } + + return previous; +} diff --git a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/snet_buffer.h b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/snet_buffer.h index f32458de24..71222a65c0 100644 --- a/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/snet_buffer.h +++ b/src/add-ons/kernel/drivers/bluetooth/h2/h2generic/snet_buffer.h @@ -1,81 +1,81 @@ -/* - * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com - * - * All rights reserved. Distributed under the terms of the MIT License. - * - */ - - -#ifndef _SNET_BUFFER_H_ -#define _SNET_BUFFER_H_ - -#include - -/* - * This is a simple data structure to hold network buffers. - * It drops many functionality that the Haiku net_buffer provides. - * - * - Inspired by linux sk_buff/bsd mbuf (put/pull) - * - Contiguoussafe (no push operation) - * - * So snet_buffers are ONLY meant to be used when: - * 1) You know exactily the maximun/final size of the frame - * before allocating it, and you will never exceed it. - * 2) You are not supposed to prepend data, only append. - * - */ - -/* Configuration parameters */ -#define SNB_BUFFER_ATTACHED -//#define SNB_PERFORMS_OVERFLOW_CHECKS -//#define SNB_PERFORMS_POINTER_CHECKS - -struct snet_buffer; - -typedef struct snet_buffer snet_buffer; - -/* Creates a snb_buffer allocating size space for its full content */ -snet_buffer* snb_create(uint16 size); -/* Free the snb_buffer*/ -void snb_free(snet_buffer* snb); -/* Free the snb_buffer*/ -void* snb_get(snet_buffer* snb); -/* Size of the snb_buffer*/ -uint16 snb_size(snet_buffer* snb); - -/* Cookie of the snb_buffer*/ -void* snb_cookie(snet_buffer* snb); -/* Get Cookie of the snb_buffer*/ -void snb_set_cookie(snet_buffer* snb, void* cookie); - -/* Place the memory given by data to the "tail" of the snb */ -void snb_put(snet_buffer* snb, void* data, uint16 size); -/* Returns a header chunk of size data */ -void* snb_pull(snet_buffer* snb, uint16 size); -/* Discards all data put or pulled from the buffer */ -void snb_reset(snet_buffer* snb); - -/* Return true if we canot "put" more data in the buffer */ -bool snb_completed(snet_buffer* snb); -/* Return true if we cannot pull more more data from the buffer */ -bool snb_finished(snet_buffer* snb); -/* Return the amount of data we can still put in the buffer */ -uint16 snb_remaining_to_put(snet_buffer* snb); -/* Return the amount of data we can still pull in the buffer */ -uint16 snb_remaining_to_pull(snet_buffer* snb); - -/* These to functions are provided to avoid memory fragmentation - * allocating and freeing many snb_buffers and its possible overhead. - * Thypical scenario would be - * that you create a snb_buffer to send data, once you send you free it, - * and need another one to hold the response. The idea would be once you send - * that buffer, to snb_park the buffer, and whenever you need to allocate another - * one snb_fetch it. That funcion will reuse most appropiated previous used one - * snb_buff by its memory use. - */ -void snb_park(struct list* l, snet_buffer* snb); -snet_buffer* snb_fetch(struct list* l, uint16 size); - - - -#endif +/* + * Copyright 2007 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com + * + * All rights reserved. Distributed under the terms of the MIT License. + * + */ + + +#ifndef _SNET_BUFFER_H_ +#define _SNET_BUFFER_H_ + +#include + +/* + * This is a simple data structure to hold network buffers. + * It drops many functionality that the Haiku net_buffer provides. + * + * - Inspired by linux sk_buff/bsd mbuf (put/pull) + * - Contiguoussafe (no push operation) + * + * So snet_buffers are ONLY meant to be used when: + * 1) You know exactily the maximun/final size of the frame + * before allocating it, and you will never exceed it. + * 2) You are not supposed to prepend data, only append. + * + */ + +/* Configuration parameters */ +#define SNB_BUFFER_ATTACHED +//#define SNB_PERFORMS_OVERFLOW_CHECKS +//#define SNB_PERFORMS_POINTER_CHECKS + +struct snet_buffer; + +typedef struct snet_buffer snet_buffer; + +/* Creates a snb_buffer allocating size space for its full content */ +snet_buffer* snb_create(uint16 size); +/* Free the snb_buffer*/ +void snb_free(snet_buffer* snb); +/* Free the snb_buffer*/ +void* snb_get(snet_buffer* snb); +/* Size of the snb_buffer*/ +uint16 snb_size(snet_buffer* snb); + +/* Cookie of the snb_buffer*/ +void* snb_cookie(snet_buffer* snb); +/* Get Cookie of the snb_buffer*/ +void snb_set_cookie(snet_buffer* snb, void* cookie); + +/* Place the memory given by data to the "tail" of the snb */ +void snb_put(snet_buffer* snb, void* data, uint16 size); +/* Returns a header chunk of size data */ +void* snb_pull(snet_buffer* snb, uint16 size); +/* Discards all data put or pulled from the buffer */ +void snb_reset(snet_buffer* snb); + +/* Return true if we canot "put" more data in the buffer */ +bool snb_completed(snet_buffer* snb); +/* Return true if we cannot pull more more data from the buffer */ +bool snb_finished(snet_buffer* snb); +/* Return the amount of data we can still put in the buffer */ +uint16 snb_remaining_to_put(snet_buffer* snb); +/* Return the amount of data we can still pull in the buffer */ +uint16 snb_remaining_to_pull(snet_buffer* snb); + +/* These to functions are provided to avoid memory fragmentation + * allocating and freeing many snb_buffers and its possible overhead. + * Thypical scenario would be + * that you create a snb_buffer to send data, once you send you free it, + * and need another one to hold the response. The idea would be once you send + * that buffer, to snb_park the buffer, and whenever you need to allocate another + * one snb_fetch it. That funcion will reuse most appropiated previous used one + * snb_buff by its memory use. + */ +void snb_park(struct list* l, snet_buffer* snb); +snet_buffer* snb_fetch(struct list* l, uint16 size); + + + +#endif