diff options
Diffstat (limited to 'drivers/uwb')
-rw-r--r-- | drivers/uwb/Kconfig | 1 | ||||
-rw-r--r-- | drivers/uwb/driver.c | 11 | ||||
-rw-r--r-- | drivers/uwb/lc-dev.c | 32 | ||||
-rw-r--r-- | drivers/uwb/lc-rc.c | 99 | ||||
-rw-r--r-- | drivers/uwb/uwb-internal.h | 4 |
5 files changed, 133 insertions, 14 deletions
diff --git a/drivers/uwb/Kconfig b/drivers/uwb/Kconfig index 2431eedbe6a..c204094e1bb 100644 --- a/drivers/uwb/Kconfig +++ b/drivers/uwb/Kconfig @@ -4,7 +4,6 @@ menuconfig UWB tristate "Ultra Wideband devices" - depends on PCI default n help UWB is a high-bandwidth, low-power, point-to-point radio diff --git a/drivers/uwb/driver.c b/drivers/uwb/driver.c index 3e5454aba5d..776bcb3c214 100644 --- a/drivers/uwb/driver.c +++ b/drivers/uwb/driver.c @@ -121,9 +121,19 @@ static int __init uwb_subsys_init(void) result = class_register(&uwb_rc_class); if (result < 0) goto error_uwb_rc_class_register; + + /* Register the UWB bus */ + result = bus_register(&uwb_bus_type); + if (result) { + pr_err("%s - registering bus driver failed\n", __func__); + goto exit_bus; + } + uwb_dbg_init(); return 0; +exit_bus: + class_unregister(&uwb_rc_class); error_uwb_rc_class_register: uwb_est_destroy(); error_est_init: @@ -134,6 +144,7 @@ module_init(uwb_subsys_init); static void __exit uwb_subsys_exit(void) { uwb_dbg_exit(); + bus_unregister(&uwb_bus_type); class_unregister(&uwb_rc_class); uwb_est_destroy(); return; diff --git a/drivers/uwb/lc-dev.c b/drivers/uwb/lc-dev.c index 80079b8fed1..8c7cfab5cee 100644 --- a/drivers/uwb/lc-dev.c +++ b/drivers/uwb/lc-dev.c @@ -255,6 +255,12 @@ static struct attribute *uwb_dev_attrs[] = { }; ATTRIBUTE_GROUPS(uwb_dev); +/* UWB bus type. */ +struct bus_type uwb_bus_type = { + .name = "uwb", + .dev_groups = uwb_dev_groups, +}; + /** * Device SYSFS registration */ @@ -263,10 +269,6 @@ static int __uwb_dev_sys_add(struct uwb_dev *uwb_dev, struct device *parent_dev) struct device *dev; dev = &uwb_dev->dev; - /* Device sysfs files are only useful for neighbor devices not - local radio controllers. */ - if (&uwb_dev->rc->uwb_dev != uwb_dev) - dev->groups = uwb_dev_groups; dev->parent = parent_dev; dev_set_drvdata(dev, uwb_dev); @@ -365,8 +367,8 @@ int __uwb_dev_offair(struct uwb_dev *uwb_dev, struct uwb_rc *rc) uwb_dev_addr_print(devbuf, sizeof(devbuf), &uwb_dev->dev_addr); dev_info(dev, "uwb device (mac %s dev %s) disconnected from %s %s\n", macbuf, devbuf, - rc ? rc->uwb_dev.dev.parent->bus->name : "n/a", - rc ? dev_name(rc->uwb_dev.dev.parent) : ""); + uwb_dev->dev.bus->name, + rc ? dev_name(&(rc->uwb_dev.dev)) : ""); uwb_dev_rm(uwb_dev); list_del(&uwb_dev->bce->node); uwb_bce_put(uwb_dev->bce); @@ -428,26 +430,32 @@ void uwbd_dev_onair(struct uwb_rc *rc, struct uwb_beca_e *bce) return; } uwb_dev_init(uwb_dev); /* This sets refcnt to one, we own it */ + uwb_dev->dev.bus = &uwb_bus_type; uwb_dev->mac_addr = *bce->mac_addr; uwb_dev->dev_addr = bce->dev_addr; dev_set_name(&uwb_dev->dev, "%s", macbuf); + + /* plug the beacon cache */ + bce->uwb_dev = uwb_dev; + uwb_dev->bce = bce; + uwb_bce_get(bce); /* released in uwb_dev_sys_release() */ + result = uwb_dev_add(uwb_dev, &rc->uwb_dev.dev, rc); if (result < 0) { dev_err(dev, "new device %s: cannot instantiate device\n", macbuf); goto error_dev_add; } - /* plug the beacon cache */ - bce->uwb_dev = uwb_dev; - uwb_dev->bce = bce; - uwb_bce_get(bce); /* released in uwb_dev_sys_release() */ + dev_info(dev, "uwb device (mac %s dev %s) connected to %s %s\n", - macbuf, devbuf, rc->uwb_dev.dev.parent->bus->name, - dev_name(rc->uwb_dev.dev.parent)); + macbuf, devbuf, uwb_dev->dev.bus->name, + dev_name(&(rc->uwb_dev.dev))); uwb_notify(rc, uwb_dev, UWB_NOTIF_ONAIR); return; error_dev_add: + bce->uwb_dev = NULL; + uwb_bce_put(bce); kfree(uwb_dev); return; } diff --git a/drivers/uwb/lc-rc.c b/drivers/uwb/lc-rc.c index 3eca6ceb984..d059ad4d0db 100644 --- a/drivers/uwb/lc-rc.c +++ b/drivers/uwb/lc-rc.c @@ -119,10 +119,109 @@ struct uwb_rc *uwb_rc_alloc(void) } EXPORT_SYMBOL_GPL(uwb_rc_alloc); +/* + * Show the ASIE that is broadcast in the UWB beacon by this uwb_rc device. + */ +static ssize_t ASIE_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct uwb_dev *uwb_dev = to_uwb_dev(dev); + struct uwb_rc *rc = uwb_dev->rc; + struct uwb_ie_hdr *ie; + void *ptr; + size_t len; + int result = 0; + + /* init empty buffer. */ + result = scnprintf(buf, PAGE_SIZE, "\n"); + mutex_lock(&rc->ies_mutex); + /* walk IEData looking for an ASIE. */ + ptr = rc->ies->IEData; + len = le16_to_cpu(rc->ies->wIELength); + for (;;) { + ie = uwb_ie_next(&ptr, &len); + if (!ie) + break; + if (ie->element_id == UWB_APP_SPEC_IE) { + result = uwb_ie_dump_hex(ie, + ie->length + sizeof(struct uwb_ie_hdr), + buf, PAGE_SIZE); + break; + } + } + mutex_unlock(&rc->ies_mutex); + + return result; +} + +/* + * Update the ASIE that is broadcast in the UWB beacon by this uwb_rc device. + */ +static ssize_t ASIE_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct uwb_dev *uwb_dev = to_uwb_dev(dev); + struct uwb_rc *rc = uwb_dev->rc; + char ie_buf[255]; + int result, ie_len = 0; + const char *cur_ptr = buf; + struct uwb_ie_hdr *ie; + + /* empty string means clear the ASIE. */ + if (strlen(buf) <= 1) { + uwb_rc_ie_rm(rc, UWB_APP_SPEC_IE); + return size; + } + + /* if non-empty string, convert string of hex chars to binary. */ + while (ie_len < sizeof(ie_buf)) { + int char_count; + + if (sscanf(cur_ptr, " %02hhX %n", + &(ie_buf[ie_len]), &char_count) > 0) { + ++ie_len; + /* skip chars read from cur_ptr. */ + cur_ptr += char_count; + } else { + break; + } + } + + /* validate IE length and type. */ + if (ie_len < sizeof(struct uwb_ie_hdr)) { + dev_err(dev, "%s: Invalid ASIE size %d.\n", __func__, ie_len); + return -EINVAL; + } + + ie = (struct uwb_ie_hdr *)ie_buf; + if (ie->element_id != UWB_APP_SPEC_IE) { + dev_err(dev, "%s: Invalid IE element type size = 0x%02X.\n", + __func__, ie->element_id); + return -EINVAL; + } + + /* bounds check length field from user. */ + if (ie->length > (ie_len - sizeof(struct uwb_ie_hdr))) + ie->length = ie_len - sizeof(struct uwb_ie_hdr); + + /* + * Valid ASIE received. Remove current ASIE then add the new one using + * uwb_rc_ie_add. + */ + uwb_rc_ie_rm(rc, UWB_APP_SPEC_IE); + + result = uwb_rc_ie_add(rc, ie, ie->length + sizeof(struct uwb_ie_hdr)); + + return result >= 0 ? size : result; +} +static DEVICE_ATTR_RW(ASIE); + static struct attribute *rc_attrs[] = { &dev_attr_mac_address.attr, &dev_attr_scan.attr, &dev_attr_beacon.attr, + &dev_attr_ASIE.attr, NULL, }; diff --git a/drivers/uwb/uwb-internal.h b/drivers/uwb/uwb-internal.h index 9a103b100f1..353c0555a1f 100644 --- a/drivers/uwb/uwb-internal.h +++ b/drivers/uwb/uwb-internal.h @@ -172,7 +172,8 @@ struct uwb_rsv_alloc_info { int interval; }; -int uwb_rsv_find_best_allocation(struct uwb_rsv *rsv, struct uwb_mas_bm *available, +int uwb_rsv_find_best_allocation(struct uwb_rsv *rsv, + struct uwb_mas_bm *available, struct uwb_mas_bm *result); void uwb_rsv_handle_drp_avail_change(struct uwb_rc *rc); /* @@ -313,6 +314,7 @@ int uwb_radio_force_channel(struct uwb_rc *rc, int channel); /* -- UWB Sysfs representation */ extern struct class uwb_rc_class; +extern struct bus_type uwb_bus_type; extern struct device_attribute dev_attr_mac_address; extern struct device_attribute dev_attr_beacon; extern struct device_attribute dev_attr_scan; |