From 006f68b84fe19fc5015a8cf838a10d75f91f0218 Mon Sep 17 00:00:00 2001 From: Ralf Baechle DL5RB Date: Mon, 3 Jul 2006 19:30:18 -0700 Subject: [AX.25]: Reference counting for AX.25 routes. In the past routes could be freed even though the were possibly in use ... Signed-off-by: Ralf Baechle DL5RB Signed-off-by: David S. Miller --- include/net/ax25.h | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/net/ax25.h b/include/net/ax25.h index 7cd528e9d668..69374cd1a857 100644 --- a/include/net/ax25.h +++ b/include/net/ax25.h @@ -182,14 +182,26 @@ typedef struct { typedef struct ax25_route { struct ax25_route *next; - atomic_t ref; + atomic_t refcount; ax25_address callsign; struct net_device *dev; ax25_digi *digipeat; char ip_mode; - struct timer_list timer; } ax25_route; +static inline void ax25_hold_route(ax25_route *ax25_rt) +{ + atomic_inc(&ax25_rt->refcount); +} + +extern void __ax25_put_route(ax25_route *ax25_rt); + +static inline void ax25_put_route(ax25_route *ax25_rt) +{ + if (atomic_dec_and_test(&ax25_rt->refcount)) + __ax25_put_route(ax25_rt); +} + typedef struct { char slave; /* slave_mode? */ struct timer_list slave_timer; /* timeout timer */ @@ -348,17 +360,11 @@ extern int ax25_check_iframes_acked(ax25_cb *, unsigned short); extern void ax25_rt_device_down(struct net_device *); extern int ax25_rt_ioctl(unsigned int, void __user *); extern struct file_operations ax25_route_fops; +extern ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev); extern int ax25_rt_autobind(ax25_cb *, ax25_address *); -extern ax25_route *ax25_rt_find_route(ax25_route *, ax25_address *, - struct net_device *); extern struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *, ax25_address *, ax25_digi *); extern void ax25_rt_free(void); -static inline void ax25_put_route(ax25_route *ax25_rt) -{ - atomic_dec(&ax25_rt->ref); -} - /* ax25_std_in.c */ extern int ax25_std_frame_in(ax25_cb *, struct sk_buff *, int); -- cgit v1.2.3-58-ga151 From fe4ada2d6f0b746246e9b5bf0f4f2e4d3a07d26e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 3 Jul 2006 19:44:51 -0700 Subject: [IOAT]: fix header file kernel-doc Fix kernel-doc problems in include/linux/dmaengine.h: - add some fields/parameters - expand some descriptions - fix typos Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller --- include/linux/dmaengine.h | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) (limited to 'include') diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h index 272010a6078a..c94d8f1d62e5 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -44,7 +44,7 @@ enum dma_event { }; /** - * typedef dma_cookie_t + * typedef dma_cookie_t - an opaque DMA cookie * * if dma_cookie_t is >0 it's a DMA request cookie, <0 it's an error code */ @@ -80,14 +80,14 @@ struct dma_chan_percpu { /** * struct dma_chan - devices supply DMA channels, clients use them - * @client: ptr to the client user of this chan, will be NULL when unused - * @device: ptr to the dma device who supplies this channel, always !NULL + * @client: ptr to the client user of this chan, will be %NULL when unused + * @device: ptr to the dma device who supplies this channel, always !%NULL * @cookie: last cookie value returned to client - * @chan_id: - * @class_dev: + * @chan_id: channel ID for sysfs + * @class_dev: class device for sysfs * @refcount: kref, used in "bigref" slow-mode - * @slow_ref: - * @rcu: + * @slow_ref: indicates that the DMA channel is free + * @rcu: the DMA channel's RCU head * @client_node: used to add this to the client chan list * @device_node: used to add this to the device chan list * @local: per-cpu pointer to a struct dma_chan_percpu @@ -162,10 +162,17 @@ struct dma_client { * @chancnt: how many DMA channels are supported * @channels: the list of struct dma_chan * @global_node: list_head for global dma_device_list - * @refcount: - * @done: - * @dev_id: - * Other func ptrs: used to make use of this device's capabilities + * @refcount: reference count + * @done: IO completion struct + * @dev_id: unique device ID + * @device_alloc_chan_resources: allocate resources and return the + * number of allocated descriptors + * @device_free_chan_resources: release DMA channel's resources + * @device_memcpy_buf_to_buf: memcpy buf pointer to buf pointer + * @device_memcpy_buf_to_pg: memcpy buf pointer to struct page + * @device_memcpy_pg_to_pg: memcpy struct page/offset to struct page/offset + * @device_memcpy_complete: poll the status of an IOAT DMA transaction + * @device_memcpy_issue_pending: push appended descriptors to hardware */ struct dma_device { @@ -211,7 +218,7 @@ void dma_async_client_chan_request(struct dma_client *client, * Both @dest and @src must be mappable to a bus address according to the * DMA mapping API rules for streaming mappings. * Both @dest and @src must stay memory resident (kernel memory or locked - * user space pages) + * user space pages). */ static inline dma_cookie_t dma_async_memcpy_buf_to_buf(struct dma_chan *chan, void *dest, void *src, size_t len) @@ -225,7 +232,7 @@ static inline dma_cookie_t dma_async_memcpy_buf_to_buf(struct dma_chan *chan, } /** - * dma_async_memcpy_buf_to_pg - offloaded copy + * dma_async_memcpy_buf_to_pg - offloaded copy from address to page * @chan: DMA channel to offload copy to * @page: destination page * @offset: offset in page to copy to @@ -250,18 +257,18 @@ static inline dma_cookie_t dma_async_memcpy_buf_to_pg(struct dma_chan *chan, } /** - * dma_async_memcpy_buf_to_pg - offloaded copy + * dma_async_memcpy_pg_to_pg - offloaded copy from page to page * @chan: DMA channel to offload copy to - * @dest_page: destination page + * @dest_pg: destination page * @dest_off: offset in page to copy to - * @src_page: source page + * @src_pg: source page * @src_off: offset in page to copy from * @len: length * * Both @dest_page/@dest_off and @src_page/@src_off must be mappable to a bus * address according to the DMA mapping API rules for streaming mappings. * Both @dest_page/@dest_off and @src_page/@src_off must stay memory resident - * (kernel memory or locked user space pages) + * (kernel memory or locked user space pages). */ static inline dma_cookie_t dma_async_memcpy_pg_to_pg(struct dma_chan *chan, struct page *dest_pg, unsigned int dest_off, struct page *src_pg, @@ -278,7 +285,7 @@ static inline dma_cookie_t dma_async_memcpy_pg_to_pg(struct dma_chan *chan, /** * dma_async_memcpy_issue_pending - flush pending copies to HW - * @chan: + * @chan: target DMA channel * * This allows drivers to push copies to HW in batches, * reducing MMIO writes where possible. -- cgit v1.2.3-58-ga151 From 4bdbf6c033ba05bff65f69989baccd7103c5a530 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 3 Jul 2006 19:47:27 -0700 Subject: [NET]: add+use poison defines Add and use poison defines in net/. Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller --- include/linux/poison.h | 4 ++++ net/atm/clip.c | 3 ++- net/ipv6/netfilter/ip6_tables.c | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/linux/poison.h b/include/linux/poison.h index a5347c02432e..05d7d0fd6bdb 100644 --- a/include/linux/poison.h +++ b/include/linux/poison.h @@ -45,6 +45,10 @@ /********** drivers/atm/ **********/ #define ATM_POISON_FREE 0x12 +/********** net/ **********/ +#define NEIGHBOR_DEAD 0xdeadbeef +#define NETFILTER_LINK_POISON 0xdead57ac + /********** kernel/mutexes **********/ #define MUTEX_DEBUG_INIT 0x11 #define MUTEX_DEBUG_FREE 0x22 diff --git a/net/atm/clip.c b/net/atm/clip.c index 87a454f5c89c..121bf6f49148 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -23,6 +23,7 @@ #include /* for IFF_UP */ #include #include +#include #include #include #include @@ -266,7 +267,7 @@ static void clip_neigh_destroy(struct neighbour *neigh) DPRINTK("clip_neigh_destroy (neigh %p)\n", neigh); if (NEIGH2ENTRY(neigh)->vccs) printk(KERN_CRIT "clip_neigh_destroy: vccs != NULL !!!\n"); - NEIGH2ENTRY(neigh)->vccs = (void *) 0xdeadbeef; + NEIGH2ENTRY(neigh)->vccs = (void *) NEIGHBOR_DEAD; } static void clip_neigh_solicit(struct neighbour *neigh, struct sk_buff *skb) diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 7ef143c0ebf6..f26898b00347 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -376,7 +377,7 @@ ip6t_do_table(struct sk_buff **pskb, } while (!hotdrop); #ifdef CONFIG_NETFILTER_DEBUG - ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac; + ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON; #endif read_unlock_bh(&table->lock); -- cgit v1.2.3-58-ga151 From 3c6b377321678c649f9b3c66da0149975c614102 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 3 Jul 2006 19:48:25 -0700 Subject: [ATM]: add+use poison defines ATM: add and use POISON define values. Signed-off-by: Randy Dunlap Signed-off-by: David S. Miller --- drivers/atm/ambassador.c | 3 ++- drivers/atm/idt77252.c | 3 ++- include/linux/poison.h | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index d3b426313a41..4521a249dd56 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -1995,7 +1996,7 @@ static int __devinit ucode_init (loader_block * lb, amb_dev * dev) { } i += 1; } - if (*pointer == 0xdeadbeef) { + if (*pointer == ATM_POISON) { return loader_start (lb, dev, ucode_start); } else { // cast needed as there is no %? for pointer differnces diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index 5d1c6c95262c..b0369bb20f08 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -35,6 +35,7 @@ static char const rcsid[] = #include #include +#include #include #include #include @@ -3657,7 +3658,7 @@ probe_sram(struct idt77252_dev *card) writel(SAR_CMD_WRITE_SRAM | (0 << 2), SAR_REG_CMD); for (addr = 0x4000; addr < 0x80000; addr += 0x4000) { - writel(0xdeadbeef, SAR_REG_DR0); + writel(ATM_POISON, SAR_REG_DR0); writel(SAR_CMD_WRITE_SRAM | (addr << 2), SAR_REG_CMD); writel(SAR_CMD_READ_SRAM | (0 << 2), SAR_REG_CMD); diff --git a/include/linux/poison.h b/include/linux/poison.h index 05d7d0fd6bdb..3e628f990fdf 100644 --- a/include/linux/poison.h +++ b/include/linux/poison.h @@ -44,6 +44,7 @@ /********** drivers/atm/ **********/ #define ATM_POISON_FREE 0x12 +#define ATM_POISON 0xdeadbeef /********** net/ **********/ #define NEIGHBOR_DEAD 0xdeadbeef -- cgit v1.2.3-58-ga151 From da1f519851d1c66331363253f364bdb5d924ea96 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 3 Jul 2006 10:02:29 +0200 Subject: [Bluetooth] Correct SCO buffer size on request This patch introduces a quirk that allows the drivers to tell the host to correct the SCO buffer size values. Signed-off-by: Olivier Galibert Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_usb.c | 6 ++++++ drivers/bluetooth/hci_usb.h | 1 + include/net/bluetooth/hci.h | 3 ++- net/bluetooth/hci_event.c | 14 +++++++++++--- 4 files changed, 20 insertions(+), 4 deletions(-) (limited to 'include') diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c index 987a3dff8af9..6a0c2230f82f 100644 --- a/drivers/bluetooth/hci_usb.c +++ b/drivers/bluetooth/hci_usb.c @@ -122,6 +122,9 @@ static struct usb_device_id blacklist_ids[] = { /* RTX Telecom based adapter with buggy SCO support */ { USB_DEVICE(0x0400, 0x0807), .driver_info = HCI_BROKEN_ISOC }, + /* Belkin F8T012 */ + { USB_DEVICE(0x050d, 0x0012), .driver_info = HCI_WRONG_SCO_MTU }, + /* Digianswer devices */ { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER }, { USB_DEVICE(0x08fd, 0x0002), .driver_info = HCI_IGNORE }, @@ -987,6 +990,9 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id if (reset || id->driver_info & HCI_RESET) set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); + if (id->driver_info & HCI_WRONG_SCO_MTU) + set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks); + if (id->driver_info & HCI_SNIFFER) { if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); diff --git a/drivers/bluetooth/hci_usb.h b/drivers/bluetooth/hci_usb.h index 37100a6ea1a8..963fc55cdc85 100644 --- a/drivers/bluetooth/hci_usb.h +++ b/drivers/bluetooth/hci_usb.h @@ -35,6 +35,7 @@ #define HCI_SNIFFER 0x10 #define HCI_BCM92035 0x20 #define HCI_BROKEN_ISOC 0x40 +#define HCI_WRONG_SCO_MTU 0x80 #define HCI_MAX_IFACE_NUM 3 diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index b06a2d2f63d2..99c53f6b8252 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -54,7 +54,8 @@ /* HCI device quirks */ enum { HCI_QUIRK_RESET_ON_INIT, - HCI_QUIRK_RAW_DEVICE + HCI_QUIRK_RAW_DEVICE, + HCI_QUIRK_FIXUP_BUFFER_SIZE }; /* HCI device flags */ diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 618bacee1b1c..f41cf1a6c11a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -319,9 +319,17 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s } hdev->acl_mtu = __le16_to_cpu(bs->acl_mtu); - hdev->sco_mtu = bs->sco_mtu ? bs->sco_mtu : 64; - hdev->acl_pkts = hdev->acl_cnt = __le16_to_cpu(bs->acl_max_pkt); - hdev->sco_pkts = hdev->sco_cnt = __le16_to_cpu(bs->sco_max_pkt); + hdev->sco_mtu = bs->sco_mtu; + hdev->acl_pkts = __le16_to_cpu(bs->acl_max_pkt); + hdev->sco_pkts = __le16_to_cpu(bs->sco_max_pkt); + + if (test_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks)) { + hdev->sco_mtu = 64; + hdev->sco_pkts = 8; + } + + hdev->acl_cnt = hdev->acl_pkts; + hdev->sco_cnt = hdev->sco_pkts; BT_DBG("%s mtu: acl %d, sco %d max_pkt: acl %d, sco %d", hdev->name, hdev->acl_mtu, hdev->sco_mtu, hdev->acl_pkts, hdev->sco_pkts); -- cgit v1.2.3-58-ga151 From 04837f6447c7f3ef114cda1ad761822dedbff8cf Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 3 Jul 2006 10:02:33 +0200 Subject: [Bluetooth] Add automatic sniff mode support This patch introduces the automatic sniff mode feature. This allows the host to switch idle connections into sniff mode to safe power. Signed-off-by: Ulisses Furquim Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 70 +++++++++++--- include/net/bluetooth/hci_core.h | 54 ++++++----- net/bluetooth/af_bluetooth.c | 2 +- net/bluetooth/hci_conn.c | 100 +++++++++++++++++--- net/bluetooth/hci_core.c | 34 +++++-- net/bluetooth/hci_event.c | 192 +++++++++++++++++++++++++++++++++------ net/bluetooth/hci_sysfs.c | 88 ++++++++++++++++++ 7 files changed, 454 insertions(+), 86 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 99c53f6b8252..b2bdb1aa0429 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -101,9 +101,10 @@ enum { #define HCIINQUIRY _IOR('H', 240, int) /* HCI timeouts */ -#define HCI_CONN_TIMEOUT (HZ * 40) -#define HCI_DISCONN_TIMEOUT (HZ * 2) -#define HCI_CONN_IDLE_TIMEOUT (HZ * 60) +#define HCI_CONNECT_TIMEOUT (40000) /* 40 seconds */ +#define HCI_DISCONN_TIMEOUT (2000) /* 2 seconds */ +#define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */ +#define HCI_INIT_TIMEOUT (10000) /* 10 seconds */ /* HCI Packet types */ #define HCI_COMMAND_PKT 0x01 @@ -145,7 +146,7 @@ enum { #define LMP_TACCURACY 0x10 #define LMP_RSWITCH 0x20 #define LMP_HOLD 0x40 -#define LMP_SNIF 0x80 +#define LMP_SNIFF 0x80 #define LMP_PARK 0x01 #define LMP_RSSI 0x02 @@ -160,13 +161,21 @@ enum { #define LMP_PSCHEME 0x02 #define LMP_PCONTROL 0x04 +#define LMP_SNIFF_SUBR 0x02 + +/* Connection modes */ +#define HCI_CM_ACTIVE 0x0000 +#define HCI_CM_HOLD 0x0001 +#define HCI_CM_SNIFF 0x0002 +#define HCI_CM_PARK 0x0003 + /* Link policies */ #define HCI_LP_RSWITCH 0x0001 #define HCI_LP_HOLD 0x0002 #define HCI_LP_SNIFF 0x0004 #define HCI_LP_PARK 0x0008 -/* Link mode */ +/* Link modes */ #define HCI_LM_ACCEPT 0x8000 #define HCI_LM_MASTER 0x0001 #define HCI_LM_AUTH 0x0002 @@ -192,7 +201,7 @@ struct hci_rp_read_loc_version { } __attribute__ ((packed)); #define OCF_READ_LOCAL_FEATURES 0x0003 -struct hci_rp_read_loc_features { +struct hci_rp_read_local_features { __u8 status; __u8 features[8]; } __attribute__ ((packed)); @@ -376,17 +385,32 @@ struct hci_cp_change_conn_link_key { } __attribute__ ((packed)); #define OCF_READ_REMOTE_FEATURES 0x001B -struct hci_cp_read_rmt_features { +struct hci_cp_read_remote_features { __le16 handle; } __attribute__ ((packed)); #define OCF_READ_REMOTE_VERSION 0x001D -struct hci_cp_read_rmt_version { +struct hci_cp_read_remote_version { __le16 handle; } __attribute__ ((packed)); /* Link Policy */ -#define OGF_LINK_POLICY 0x02 +#define OGF_LINK_POLICY 0x02 + +#define OCF_SNIFF_MODE 0x0003 +struct hci_cp_sniff_mode { + __le16 handle; + __le16 max_interval; + __le16 min_interval; + __le16 attempt; + __le16 timeout; +} __attribute__ ((packed)); + +#define OCF_EXIT_SNIFF_MODE 0x0004 +struct hci_cp_exit_sniff_mode { + __le16 handle; +} __attribute__ ((packed)); + #define OCF_ROLE_DISCOVERY 0x0009 struct hci_cp_role_discovery { __le16 handle; @@ -407,7 +431,7 @@ struct hci_rp_read_link_policy { __le16 policy; } __attribute__ ((packed)); -#define OCF_SWITCH_ROLE 0x000B +#define OCF_SWITCH_ROLE 0x000B struct hci_cp_switch_role { bdaddr_t bdaddr; __u8 role; @@ -423,6 +447,14 @@ struct hci_rp_write_link_policy { __le16 handle; } __attribute__ ((packed)); +#define OCF_SNIFF_SUBRATE 0x0011 +struct hci_cp_sniff_subrate { + __le16 handle; + __le16 max_latency; + __le16 min_remote_timeout; + __le16 min_local_timeout; +} __attribute__ ((packed)); + /* Status params */ #define OGF_STATUS_PARAM 0x05 @@ -582,15 +614,15 @@ struct hci_ev_link_key_notify { __u8 key_type; } __attribute__ ((packed)); -#define HCI_EV_RMT_FEATURES 0x0B -struct hci_ev_rmt_features { +#define HCI_EV_REMOTE_FEATURES 0x0B +struct hci_ev_remote_features { __u8 status; __le16 handle; __u8 features[8]; } __attribute__ ((packed)); -#define HCI_EV_RMT_VERSION 0x0C -struct hci_ev_rmt_version { +#define HCI_EV_REMOTE_VERSION 0x0C +struct hci_ev_remote_version { __u8 status; __le16 handle; __u8 lmp_ver; @@ -611,6 +643,16 @@ struct hci_ev_pscan_rep_mode { __u8 pscan_rep_mode; } __attribute__ ((packed)); +#define HCI_EV_SNIFF_SUBRATE 0x2E +struct hci_ev_sniff_subrate { + __u8 status; + __le16 handle; + __le16 max_tx_latency; + __le16 max_rx_latency; + __le16 max_remote_timeout; + __le16 max_local_timeout; +} __attribute__ ((packed)); + /* Internal events generated by Bluetooth stack */ #define HCI_EV_STACK_INTERNAL 0xFD struct hci_ev_stack_internal { diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index bb9f81dc8723..f6852707bd64 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -31,10 +31,7 @@ #define HCI_PROTO_L2CAP 0 #define HCI_PROTO_SCO 1 -#define HCI_INIT_TIMEOUT (HZ * 10) - /* HCI Core structures */ - struct inquiry_data { bdaddr_t bdaddr; __u8 pscan_rep_mode; @@ -81,6 +78,10 @@ struct hci_dev { __u16 link_policy; __u16 link_mode; + __u32 idle_timeout; + __u16 sniff_min_interval; + __u16 sniff_max_interval; + unsigned long quirks; atomic_t cmd_cnt; @@ -145,18 +146,24 @@ struct hci_conn { bdaddr_t dst; __u16 handle; __u16 state; + __u8 mode; __u8 type; __u8 out; __u8 dev_class[3]; + __u8 features[8]; + __u16 interval; + __u16 link_policy; __u32 link_mode; + __u8 power_save; unsigned long pend; - + unsigned int sent; - + struct sk_buff_head data_q; - struct timer_list timer; - + struct timer_list disc_timer; + struct timer_list idle_timer; + struct hci_dev *hdev; void *l2cap_data; void *sco_data; @@ -211,7 +218,8 @@ void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data); enum { HCI_CONN_AUTH_PEND, HCI_CONN_ENCRYPT_PEND, - HCI_CONN_RSWITCH_PEND + HCI_CONN_RSWITCH_PEND, + HCI_CONN_MODE_CHANGE_PEND, }; static inline void hci_conn_hash_init(struct hci_dev *hdev) @@ -286,31 +294,27 @@ int hci_conn_encrypt(struct hci_conn *conn); int hci_conn_change_link_key(struct hci_conn *conn); int hci_conn_switch_role(struct hci_conn *conn, uint8_t role); -static inline void hci_conn_set_timer(struct hci_conn *conn, unsigned long timeout) -{ - mod_timer(&conn->timer, jiffies + timeout); -} - -static inline void hci_conn_del_timer(struct hci_conn *conn) -{ - del_timer(&conn->timer); -} +void hci_conn_enter_active_mode(struct hci_conn *conn); +void hci_conn_enter_sniff_mode(struct hci_conn *conn); static inline void hci_conn_hold(struct hci_conn *conn) { atomic_inc(&conn->refcnt); - hci_conn_del_timer(conn); + del_timer(&conn->disc_timer); } static inline void hci_conn_put(struct hci_conn *conn) { if (atomic_dec_and_test(&conn->refcnt)) { + unsigned long timeo; if (conn->type == ACL_LINK) { - unsigned long timeo = (conn->out) ? - HCI_DISCONN_TIMEOUT : HCI_DISCONN_TIMEOUT * 2; - hci_conn_set_timer(conn, timeo); + timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT); + if (!conn->out) + timeo *= 2; + del_timer(&conn->idle_timer); } else - hci_conn_set_timer(conn, HZ / 100); + timeo = msecs_to_jiffies(10); + mod_timer(&conn->disc_timer, jiffies + timeo); } } @@ -411,8 +415,10 @@ void hci_unregister_sysfs(struct hci_dev *hdev); #define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->class_dev.dev = (pdev)) /* ----- LMP capabilities ----- */ -#define lmp_rswitch_capable(dev) (dev->features[0] & LMP_RSWITCH) -#define lmp_encrypt_capable(dev) (dev->features[0] & LMP_ENCRYPT) +#define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH) +#define lmp_encrypt_capable(dev) ((dev)->features[0] & LMP_ENCRYPT) +#define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF) +#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR) /* ----- HCI protocols ----- */ struct hci_proto { diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 51f867062e1d..729461fcfe99 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -48,7 +48,7 @@ #define BT_DBG(D...) #endif -#define VERSION "2.8" +#define VERSION "2.9" /* Bluetooth sockets */ #define BT_MAX_PROTO 8 diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 5c0c2b1ef34a..420ed4d7e57e 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -115,8 +115,8 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle) static void hci_conn_timeout(unsigned long arg) { - struct hci_conn *conn = (void *)arg; - struct hci_dev *hdev = conn->hdev; + struct hci_conn *conn = (void *) arg; + struct hci_dev *hdev = conn->hdev; BT_DBG("conn %p state %d", conn, conn->state); @@ -132,11 +132,13 @@ static void hci_conn_timeout(unsigned long arg) return; } -static void hci_conn_init_timer(struct hci_conn *conn) +static void hci_conn_idle(unsigned long arg) { - init_timer(&conn->timer); - conn->timer.function = hci_conn_timeout; - conn->timer.data = (unsigned long)conn; + struct hci_conn *conn = (void *) arg; + + BT_DBG("conn %p mode %d", conn, conn->mode); + + hci_conn_enter_sniff_mode(conn); } struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) @@ -145,17 +147,27 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) BT_DBG("%s dst %s", hdev->name, batostr(dst)); - if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC))) + conn = kzalloc(sizeof(struct hci_conn), GFP_ATOMIC); + if (!conn) return NULL; - memset(conn, 0, sizeof(struct hci_conn)); bacpy(&conn->dst, dst); - conn->type = type; conn->hdev = hdev; + conn->type = type; + conn->mode = HCI_CM_ACTIVE; conn->state = BT_OPEN; + conn->power_save = 1; + skb_queue_head_init(&conn->data_q); - hci_conn_init_timer(conn); + + init_timer(&conn->disc_timer); + conn->disc_timer.function = hci_conn_timeout; + conn->disc_timer.data = (unsigned long) conn; + + init_timer(&conn->idle_timer); + conn->idle_timer.function = hci_conn_idle; + conn->idle_timer.data = (unsigned long) conn; atomic_set(&conn->refcnt, 0); @@ -178,7 +190,9 @@ int hci_conn_del(struct hci_conn *conn) BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle); - hci_conn_del_timer(conn); + del_timer(&conn->idle_timer); + + del_timer(&conn->disc_timer); if (conn->type == SCO_LINK) { struct hci_conn *acl = conn->link; @@ -364,6 +378,70 @@ int hci_conn_switch_role(struct hci_conn *conn, uint8_t role) } EXPORT_SYMBOL(hci_conn_switch_role); +/* Enter active mode */ +void hci_conn_enter_active_mode(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + + BT_DBG("conn %p mode %d", conn, conn->mode); + + if (test_bit(HCI_RAW, &hdev->flags)) + return; + + if (conn->mode != HCI_CM_SNIFF || !conn->power_save) + goto timer; + + if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { + struct hci_cp_exit_sniff_mode cp; + cp.handle = __cpu_to_le16(conn->handle); + hci_send_cmd(hdev, OGF_LINK_POLICY, + OCF_EXIT_SNIFF_MODE, sizeof(cp), &cp); + } + +timer: + if (hdev->idle_timeout > 0) + mod_timer(&conn->idle_timer, + jiffies + msecs_to_jiffies(hdev->idle_timeout)); +} + +/* Enter sniff mode */ +void hci_conn_enter_sniff_mode(struct hci_conn *conn) +{ + struct hci_dev *hdev = conn->hdev; + + BT_DBG("conn %p mode %d", conn, conn->mode); + + if (test_bit(HCI_RAW, &hdev->flags)) + return; + + if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn)) + return; + + if (conn->mode != HCI_CM_ACTIVE || !(conn->link_policy & HCI_LP_SNIFF)) + return; + + if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) { + struct hci_cp_sniff_subrate cp; + cp.handle = __cpu_to_le16(conn->handle); + cp.max_latency = __constant_cpu_to_le16(0); + cp.min_remote_timeout = __constant_cpu_to_le16(0); + cp.min_local_timeout = __constant_cpu_to_le16(0); + hci_send_cmd(hdev, OGF_LINK_POLICY, + OCF_SNIFF_SUBRATE, sizeof(cp), &cp); + } + + if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { + struct hci_cp_sniff_mode cp; + cp.handle = __cpu_to_le16(conn->handle); + cp.max_interval = __cpu_to_le16(hdev->sniff_max_interval); + cp.min_interval = __cpu_to_le16(hdev->sniff_min_interval); + cp.attempt = __constant_cpu_to_le16(4); + cp.timeout = __constant_cpu_to_le16(1); + hci_send_cmd(hdev, OGF_LINK_POLICY, + OCF_SNIFF_MODE, sizeof(cp), &cp); + } +} + /* Drop all connection on the device */ void hci_conn_hash_flush(struct hci_dev *hdev) { diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f67240beb0dd..3f9f1565bf06 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -411,7 +411,7 @@ int hci_inquiry(void __user *arg) } hci_dev_unlock_bh(hdev); - timeo = ir.length * 2 * HZ; + timeo = ir.length * msecs_to_jiffies(2000); if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0) goto done; @@ -479,7 +479,8 @@ int hci_dev_open(__u16 dev) set_bit(HCI_INIT, &hdev->flags); //__hci_request(hdev, hci_reset_req, 0, HZ); - ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT); + ret = __hci_request(hdev, hci_init_req, 0, + msecs_to_jiffies(HCI_INIT_TIMEOUT)); clear_bit(HCI_INIT, &hdev->flags); } @@ -546,7 +547,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) atomic_set(&hdev->cmd_cnt, 1); if (!test_bit(HCI_RAW, &hdev->flags)) { set_bit(HCI_INIT, &hdev->flags); - __hci_request(hdev, hci_reset_req, 0, HZ/4); + __hci_request(hdev, hci_reset_req, 0, + msecs_to_jiffies(250)); clear_bit(HCI_INIT, &hdev->flags); } @@ -619,7 +621,8 @@ int hci_dev_reset(__u16 dev) hdev->acl_cnt = 0; hdev->sco_cnt = 0; if (!test_bit(HCI_RAW, &hdev->flags)) - ret = __hci_request(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT); + ret = __hci_request(hdev, hci_reset_req, 0, + msecs_to_jiffies(HCI_INIT_TIMEOUT)); done: tasklet_enable(&hdev->tx_task); @@ -657,7 +660,8 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) switch (cmd) { case HCISETAUTH: - err = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT); + err = hci_request(hdev, hci_auth_req, dr.dev_opt, + msecs_to_jiffies(HCI_INIT_TIMEOUT)); break; case HCISETENCRYPT: @@ -668,18 +672,19 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) if (!test_bit(HCI_AUTH, &hdev->flags)) { /* Auth must be enabled first */ - err = hci_request(hdev, hci_auth_req, - dr.dev_opt, HCI_INIT_TIMEOUT); + err = hci_request(hdev, hci_auth_req, dr.dev_opt, + msecs_to_jiffies(HCI_INIT_TIMEOUT)); if (err) break; } - err = hci_request(hdev, hci_encrypt_req, - dr.dev_opt, HCI_INIT_TIMEOUT); + err = hci_request(hdev, hci_encrypt_req, dr.dev_opt, + msecs_to_jiffies(HCI_INIT_TIMEOUT)); break; case HCISETSCAN: - err = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT); + err = hci_request(hdev, hci_scan_req, dr.dev_opt, + msecs_to_jiffies(HCI_INIT_TIMEOUT)); break; case HCISETPTYPE: @@ -848,6 +853,10 @@ int hci_register_dev(struct hci_dev *hdev) hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1); hdev->link_mode = (HCI_LM_ACCEPT); + hdev->idle_timeout = 0; + hdev->sniff_max_interval = 800; + hdev->sniff_min_interval = 80; + tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev); tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); @@ -1220,6 +1229,9 @@ static inline void hci_sched_acl(struct hci_dev *hdev) while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, "e))) { while (quote-- && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); + + hci_conn_enter_active_mode(conn); + hci_send_frame(skb); hdev->acl_last_tx = jiffies; @@ -1298,6 +1310,8 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb) if (conn) { register struct hci_proto *hp; + hci_conn_enter_active_mode(conn); + /* Send to upper protocol */ if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) { hp->recv_acldata(conn, skb, flags); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f41cf1a6c11a..3896dabab11d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -83,6 +83,8 @@ static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff * { struct hci_conn *conn; struct hci_rp_role_discovery *rd; + struct hci_rp_write_link_policy *lp; + void *sent; BT_DBG("%s ocf 0x%x", hdev->name, ocf); @@ -106,6 +108,27 @@ static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff * hci_dev_unlock(hdev); break; + case OCF_WRITE_LINK_POLICY: + sent = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY); + if (!sent) + break; + + lp = (struct hci_rp_write_link_policy *) skb->data; + + if (lp->status) + break; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(lp->handle)); + if (conn) { + __le16 policy = get_unaligned((__le16 *) (sent + 2)); + conn->link_policy = __le16_to_cpu(policy); + } + + hci_dev_unlock(hdev); + break; + default: BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x", hdev->name, ocf); @@ -274,7 +297,7 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb /* Command Complete OGF INFO_PARAM */ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) { - struct hci_rp_read_loc_features *lf; + struct hci_rp_read_local_features *lf; struct hci_rp_read_buffer_size *bs; struct hci_rp_read_bd_addr *ba; @@ -282,7 +305,7 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s switch (ocf) { case OCF_READ_LOCAL_FEATURES: - lf = (struct hci_rp_read_loc_features *) skb->data; + lf = (struct hci_rp_read_local_features *) skb->data; if (lf->status) { BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status); @@ -447,8 +470,46 @@ static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status) BT_DBG("%s ocf 0x%x", hdev->name, ocf); switch (ocf) { + case OCF_SNIFF_MODE: + if (status) { + struct hci_conn *conn; + struct hci_cp_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_SNIFF_MODE); + + if (!cp) + break; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); + if (conn) { + clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend); + } + + hci_dev_unlock(hdev); + } + break; + + case OCF_EXIT_SNIFF_MODE: + if (status) { + struct hci_conn *conn; + struct hci_cp_exit_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_EXIT_SNIFF_MODE); + + if (!cp) + break; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); + if (conn) { + clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend); + } + + hci_dev_unlock(hdev); + } + break; + default: - BT_DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf); + BT_DBG("%s Command status: ogf LINK_POLICY ocf %x", hdev->name, ocf); break; } } @@ -630,14 +691,16 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk else cp.role = 0x01; /* Remain slave */ - hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, sizeof(cp), &cp); + hci_send_cmd(hdev, OGF_LINK_CTL, + OCF_ACCEPT_CONN_REQ, sizeof(cp), &cp); } else { /* Connection rejected */ struct hci_cp_reject_conn_req cp; bacpy(&cp.bdaddr, &ev->bdaddr); cp.reason = 0x0f; - hci_send_cmd(hdev, OGF_LINK_CTL, OCF_REJECT_CONN_REQ, sizeof(cp), &cp); + hci_send_cmd(hdev, OGF_LINK_CTL, + OCF_REJECT_CONN_REQ, sizeof(cp), &cp); } } @@ -645,7 +708,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data; - struct hci_conn *conn = NULL; + struct hci_conn *conn; BT_DBG("%s", hdev->name); @@ -667,12 +730,21 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s if (test_bit(HCI_ENCRYPT, &hdev->flags)) conn->link_mode |= HCI_LM_ENCRYPT; + /* Get remote features */ + if (conn->type == ACL_LINK) { + struct hci_cp_read_remote_features cp; + cp.handle = ev->handle; + hci_send_cmd(hdev, OGF_LINK_CTL, + OCF_READ_REMOTE_FEATURES, sizeof(cp), &cp); + } + /* Set link policy */ if (conn->type == ACL_LINK && hdev->link_policy) { struct hci_cp_write_link_policy cp; cp.handle = ev->handle; cp.policy = __cpu_to_le16(hdev->link_policy); - hci_send_cmd(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY, sizeof(cp), &cp); + hci_send_cmd(hdev, OGF_LINK_POLICY, + OCF_WRITE_LINK_POLICY, sizeof(cp), &cp); } /* Set packet type for incoming connection */ @@ -683,7 +755,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK): __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); - hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp); + hci_send_cmd(hdev, OGF_LINK_CTL, + OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp); } } else conn->state = BT_CLOSED; @@ -711,8 +784,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_disconn_complete *ev = (struct hci_ev_disconn_complete *) skb->data; - struct hci_conn *conn = NULL; - __u16 handle = __le16_to_cpu(ev->handle); + struct hci_conn *conn; BT_DBG("%s status %d", hdev->name, ev->status); @@ -721,7 +793,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff hci_dev_lock(hdev); - conn = hci_conn_hash_lookup_handle(hdev, handle); + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { conn->state = BT_CLOSED; hci_proto_disconn_ind(conn, ev->reason); @@ -778,7 +850,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_role_change *ev = (struct hci_ev_role_change *) skb->data; - struct hci_conn *conn = NULL; + struct hci_conn *conn; BT_DBG("%s status %d", hdev->name, ev->status); @@ -801,18 +873,43 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb hci_dev_unlock(hdev); } +/* Mode Change */ +static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_ev_mode_change *ev = (struct hci_ev_mode_change *) skb->data; + struct hci_conn *conn; + + BT_DBG("%s status %d", hdev->name, ev->status); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); + if (conn) { + conn->mode = ev->mode; + conn->interval = __le16_to_cpu(ev->interval); + + if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { + if (conn->mode == HCI_CM_ACTIVE) + conn->power_save = 1; + else + conn->power_save = 0; + } + } + + hci_dev_unlock(hdev); +} + /* Authentication Complete */ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_auth_complete *ev = (struct hci_ev_auth_complete *) skb->data; - struct hci_conn *conn = NULL; - __u16 handle = __le16_to_cpu(ev->handle); + struct hci_conn *conn; BT_DBG("%s status %d", hdev->name, ev->status); hci_dev_lock(hdev); - conn = hci_conn_hash_lookup_handle(hdev, handle); + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { if (!ev->status) conn->link_mode |= HCI_LM_AUTH; @@ -827,8 +924,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s cp.handle = __cpu_to_le16(conn->handle); cp.encrypt = 1; hci_send_cmd(conn->hdev, OGF_LINK_CTL, - OCF_SET_CONN_ENCRYPT, - sizeof(cp), &cp); + OCF_SET_CONN_ENCRYPT, sizeof(cp), &cp); } else { clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); hci_encrypt_cfm(conn, ev->status, 0x00); @@ -843,14 +939,13 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_encrypt_change *ev = (struct hci_ev_encrypt_change *) skb->data; - struct hci_conn *conn = NULL; - __u16 handle = __le16_to_cpu(ev->handle); + struct hci_conn *conn; BT_DBG("%s status %d", hdev->name, ev->status); hci_dev_lock(hdev); - conn = hci_conn_hash_lookup_handle(hdev, handle); + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { if (!ev->status) { if (ev->encrypt) @@ -871,14 +966,13 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff * static inline void hci_change_conn_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_change_conn_link_key_complete *ev = (struct hci_ev_change_conn_link_key_complete *) skb->data; - struct hci_conn *conn = NULL; - __u16 handle = __le16_to_cpu(ev->handle); + struct hci_conn *conn; BT_DBG("%s status %d", hdev->name, ev->status); hci_dev_lock(hdev); - conn = hci_conn_hash_lookup_handle(hdev, handle); + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn) { if (!ev->status) conn->link_mode |= HCI_LM_SECURE; @@ -906,18 +1000,35 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff { } +/* Remote Features */ +static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_ev_remote_features *ev = (struct hci_ev_remote_features *) skb->data; + struct hci_conn *conn; + + BT_DBG("%s status %d", hdev->name, ev->status); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); + if (conn && !ev->status) { + memcpy(conn->features, ev->features, sizeof(conn->features)); + } + + hci_dev_unlock(hdev); +} + /* Clock Offset */ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_clock_offset *ev = (struct hci_ev_clock_offset *) skb->data; - struct hci_conn *conn = NULL; - __u16 handle = __le16_to_cpu(ev->handle); + struct hci_conn *conn; BT_DBG("%s status %d", hdev->name, ev->status); hci_dev_lock(hdev); - conn = hci_conn_hash_lookup_handle(hdev, handle); + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); if (conn && !ev->status) { struct inquiry_entry *ie; @@ -948,6 +1059,23 @@ static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff * hci_dev_unlock(hdev); } +/* Sniff Subrate */ +static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_ev_sniff_subrate *ev = (struct hci_ev_sniff_subrate *) skb->data; + struct hci_conn *conn; + + BT_DBG("%s status %d", hdev->name, ev->status); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); + if (conn) { + } + + hci_dev_unlock(hdev); +} + void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_event_hdr *hdr = (struct hci_event_hdr *) skb->data; @@ -996,6 +1124,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_role_change_evt(hdev, skb); break; + case HCI_EV_MODE_CHANGE: + hci_mode_change_evt(hdev, skb); + break; + case HCI_EV_AUTH_COMPLETE: hci_auth_complete_evt(hdev, skb); break; @@ -1020,6 +1152,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_link_key_notify_evt(hdev, skb); break; + case HCI_EV_REMOTE_FEATURES: + hci_remote_features_evt(hdev, skb); + break; + case HCI_EV_CLOCK_OFFSET: hci_clock_offset_evt(hdev, skb); break; @@ -1028,6 +1164,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_pscan_rep_mode_evt(hdev, skb); break; + case HCI_EV_SNIFF_SUBRATE: + hci_sniff_subrate_evt(hdev, skb); + break; + case HCI_EV_CMD_STATUS: cs = (struct hci_ev_cmd_status *) skb->data; skb_pull(skb, sizeof(cs)); diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 19b234c86f33..89918d2f1fdc 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -61,18 +61,106 @@ static ssize_t show_inquiry_cache(struct class_device *cdev, char *buf) return n; } +static ssize_t show_idle_timeout(struct class_device *cdev, char *buf) +{ + struct hci_dev *hdev = class_get_devdata(cdev); + return sprintf(buf, "%d\n", hdev->idle_timeout); +} + +static ssize_t store_idle_timeout(struct class_device *cdev, const char *buf, size_t count) +{ + struct hci_dev *hdev = class_get_devdata(cdev); + char *ptr; + __u32 val; + + val = simple_strtoul(buf, &ptr, 10); + if (ptr == buf) + return -EINVAL; + + if (val != 0 && (val < 500 || val > 3600000)) + return -EINVAL; + + hdev->idle_timeout = val; + + return count; +} + +static ssize_t show_sniff_max_interval(struct class_device *cdev, char *buf) +{ + struct hci_dev *hdev = class_get_devdata(cdev); + return sprintf(buf, "%d\n", hdev->sniff_max_interval); +} + +static ssize_t store_sniff_max_interval(struct class_device *cdev, const char *buf, size_t count) +{ + struct hci_dev *hdev = class_get_devdata(cdev); + char *ptr; + __u16 val; + + val = simple_strtoul(buf, &ptr, 10); + if (ptr == buf) + return -EINVAL; + + if (val < 0x0002 || val > 0xFFFE || val % 2) + return -EINVAL; + + if (val < hdev->sniff_min_interval) + return -EINVAL; + + hdev->sniff_max_interval = val; + + return count; +} + +static ssize_t show_sniff_min_interval(struct class_device *cdev, char *buf) +{ + struct hci_dev *hdev = class_get_devdata(cdev); + return sprintf(buf, "%d\n", hdev->sniff_min_interval); +} + +static ssize_t store_sniff_min_interval(struct class_device *cdev, const char *buf, size_t count) +{ + struct hci_dev *hdev = class_get_devdata(cdev); + char *ptr; + __u16 val; + + val = simple_strtoul(buf, &ptr, 10); + if (ptr == buf) + return -EINVAL; + + if (val < 0x0002 || val > 0xFFFE || val % 2) + return -EINVAL; + + if (val > hdev->sniff_max_interval) + return -EINVAL; + + hdev->sniff_min_interval = val; + + return count; +} + static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL); static CLASS_DEVICE_ATTR(type, S_IRUGO, show_type, NULL); static CLASS_DEVICE_ATTR(address, S_IRUGO, show_address, NULL); static CLASS_DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL); static CLASS_DEVICE_ATTR(inquiry_cache, S_IRUGO, show_inquiry_cache, NULL); +static CLASS_DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR, + show_idle_timeout, store_idle_timeout); +static CLASS_DEVICE_ATTR(sniff_max_interval, S_IRUGO | S_IWUSR, + show_sniff_max_interval, store_sniff_max_interval); +static CLASS_DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR, + show_sniff_min_interval, store_sniff_min_interval); + static struct class_device_attribute *bt_attrs[] = { &class_device_attr_name, &class_device_attr_type, &class_device_attr_address, &class_device_attr_flags, &class_device_attr_inquiry_cache, + &class_device_attr_idle_timeout, + &class_device_attr_sniff_max_interval, + &class_device_attr_sniff_min_interval, NULL }; -- cgit v1.2.3-58-ga151 From 27d35284258c596900e0e41c46932ec4abe6a7b1 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 3 Jul 2006 10:02:37 +0200 Subject: [Bluetooth] Add platform device for virtual and serial devices This patch adds a generic Bluetooth platform device that can be used as parent device by virtual and serial devices. Signed-off-by: Marcel Holtmann --- drivers/bluetooth/bluecard_cs.c | 1 + drivers/bluetooth/bt3c_cs.c | 1 + drivers/bluetooth/btuart_cs.c | 1 + drivers/bluetooth/dtl1_cs.c | 1 + drivers/bluetooth/hci_vhci.c | 1 - include/net/bluetooth/hci_core.h | 1 + net/bluetooth/af_bluetooth.c | 20 ++++++++++++++------ net/bluetooth/hci_sysfs.c | 39 +++++++++++++++++++++++++++++++++++++-- 8 files changed, 56 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 2830f58d6f77..8eebf9ca3786 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -739,6 +739,7 @@ static int bluecard_open(bluecard_info_t *info) hdev->type = HCI_PCCARD; hdev->driver_data = info; + SET_HCIDEV_DEV(hdev, &info->p_dev->dev); hdev->open = bluecard_hci_open; hdev->close = bluecard_hci_close; diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index c9dba5565cac..df7bb016df49 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -582,6 +582,7 @@ static int bt3c_open(bt3c_info_t *info) hdev->type = HCI_PCCARD; hdev->driver_data = info; + SET_HCIDEV_DEV(hdev, &info->p_dev->dev); hdev->open = bt3c_hci_open; hdev->close = bt3c_hci_close; diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index c889bf8109a1..746ccca97f6f 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -502,6 +502,7 @@ static int btuart_open(btuart_info_t *info) hdev->type = HCI_PCCARD; hdev->driver_data = info; + SET_HCIDEV_DEV(hdev, &info->p_dev->dev); hdev->open = btuart_hci_open; hdev->close = btuart_hci_close; diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index be6eed175aa3..0e99def8a1e3 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -484,6 +484,7 @@ static int dtl1_open(dtl1_info_t *info) hdev->type = HCI_PCCARD; hdev->driver_data = info; + SET_HCIDEV_DEV(hdev, &info->p_dev->dev); hdev->open = dtl1_hci_open; hdev->close = dtl1_hci_close; diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index ea589007fa26..aac67a3a6019 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -277,7 +277,6 @@ static int vhci_open(struct inode *inode, struct file *file) hdev->type = HCI_VHCI; hdev->driver_data = vhci; - SET_HCIDEV_DEV(hdev, vhci_miscdev.dev); hdev->open = vhci_open_dev; hdev->close = vhci_close_dev; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index f6852707bd64..ae67b36d76dc 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -124,6 +124,7 @@ struct hci_dev { atomic_t promisc; + struct device *dev; struct class_device class_dev; struct module *owner; diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 729461fcfe99..788ea7a2b744 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -48,7 +48,7 @@ #define BT_DBG(D...) #endif -#define VERSION "2.9" +#define VERSION "2.10" /* Bluetooth sockets */ #define BT_MAX_PROTO 8 @@ -307,13 +307,21 @@ static struct net_proto_family bt_sock_family_ops = { static int __init bt_init(void) { + int err; + BT_INFO("Core ver %s", VERSION); - sock_register(&bt_sock_family_ops); + err = bt_sysfs_init(); + if (err < 0) + return err; - BT_INFO("HCI device and connection manager initialized"); + err = sock_register(&bt_sock_family_ops); + if (err < 0) { + bt_sysfs_cleanup(); + return err; + } - bt_sysfs_init(); + BT_INFO("HCI device and connection manager initialized"); hci_sock_init(); @@ -324,9 +332,9 @@ static void __exit bt_exit(void) { hci_sock_cleanup(); - bt_sysfs_cleanup(); - sock_unregister(PF_BLUETOOTH); + + bt_sysfs_cleanup(); } subsys_initcall(bt_init); diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 89918d2f1fdc..7789e26c84b9 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -3,6 +3,8 @@ #include #include +#include + #include #include @@ -197,9 +199,14 @@ struct class bt_class = { .uevent = bt_uevent, #endif }; - EXPORT_SYMBOL_GPL(bt_class); +static struct bus_type bt_bus = { + .name = "bluetooth", +}; + +static struct platform_device *bt_platform; + int hci_register_sysfs(struct hci_dev *hdev) { struct class_device *cdev = &hdev->class_dev; @@ -211,6 +218,11 @@ int hci_register_sysfs(struct hci_dev *hdev) cdev->class = &bt_class; class_set_devdata(cdev, hdev); + if (!cdev->dev) + cdev->dev = &bt_platform->dev; + + hdev->dev = cdev->dev; + strlcpy(cdev->class_id, hdev->name, BUS_ID_SIZE); err = class_device_register(cdev); if (err < 0) @@ -233,10 +245,33 @@ void hci_unregister_sysfs(struct hci_dev *hdev) int __init bt_sysfs_init(void) { - return class_register(&bt_class); + int err; + + bt_platform = platform_device_register_simple("bluetooth", -1, NULL, 0); + if (IS_ERR(bt_platform)) + return PTR_ERR(bt_platform); + + err = bus_register(&bt_bus); + if (err < 0) { + platform_device_unregister(bt_platform); + return err; + } + + err = class_register(&bt_class); + if (err < 0) { + bus_unregister(&bt_bus); + platform_device_unregister(bt_platform); + return err; + } + + return 0; } void __exit bt_sysfs_cleanup(void) { class_unregister(&bt_class); + + bus_unregister(&bt_bus); + + platform_device_unregister(bt_platform); } -- cgit v1.2.3-58-ga151 From a91f2e396f5b32b21d842b4757bc8de5e88eac66 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 3 Jul 2006 10:02:41 +0200 Subject: [Bluetooth] Use real devices for host controllers This patch converts the Bluetooth class devices into real devices. The Bluetooth class is kept and the driver core provides the appropriate symlinks for backward compatibility. Signed-off-by: Marcel Holtmann --- include/net/bluetooth/bluetooth.h | 2 +- include/net/bluetooth/hci_core.h | 6 +- net/bluetooth/hci_core.c | 4 +- net/bluetooth/hci_sysfs.c | 152 ++++++++++++++++---------------------- net/bluetooth/l2cap.c | 4 +- net/bluetooth/rfcomm/core.c | 4 +- net/bluetooth/rfcomm/sock.c | 4 +- net/bluetooth/sco.c | 4 +- 8 files changed, 79 insertions(+), 101 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 911ceb5cd263..771d17783c18 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -175,6 +175,6 @@ extern int hci_sock_cleanup(void); extern int bt_sysfs_init(void); extern void bt_sysfs_cleanup(void); -extern struct class bt_class; +extern struct class *bt_class; #endif /* __BLUETOOTH_H */ diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ae67b36d76dc..d84855fe7336 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -124,8 +124,8 @@ struct hci_dev { atomic_t promisc; - struct device *dev; - struct class_device class_dev; + struct device *parent; + struct device dev; struct module *owner; @@ -413,7 +413,7 @@ static inline int hci_recv_frame(struct sk_buff *skb) int hci_register_sysfs(struct hci_dev *hdev); void hci_unregister_sysfs(struct hci_dev *hdev); -#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->class_dev.dev = (pdev)) +#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev)) /* ----- LMP capabilities ----- */ #define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 3f9f1565bf06..54e8e5ea2154 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -817,8 +817,8 @@ void hci_free_dev(struct hci_dev *hdev) { skb_queue_purge(&hdev->driver_init); - /* will free via class release */ - class_device_put(&hdev->class_dev); + /* will free via device release */ + put_device(&hdev->dev); } EXPORT_SYMBOL(hci_free_dev); diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 7789e26c84b9..3987d167f04e 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -13,35 +13,35 @@ #define BT_DBG(D...) #endif -static ssize_t show_name(struct class_device *cdev, char *buf) +static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = class_get_devdata(cdev); + struct hci_dev *hdev = dev_get_drvdata(dev); return sprintf(buf, "%s\n", hdev->name); } -static ssize_t show_type(struct class_device *cdev, char *buf) +static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = class_get_devdata(cdev); + struct hci_dev *hdev = dev_get_drvdata(dev); return sprintf(buf, "%d\n", hdev->type); } -static ssize_t show_address(struct class_device *cdev, char *buf) +static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = class_get_devdata(cdev); + struct hci_dev *hdev = dev_get_drvdata(dev); bdaddr_t bdaddr; baswap(&bdaddr, &hdev->bdaddr); return sprintf(buf, "%s\n", batostr(&bdaddr)); } -static ssize_t show_flags(struct class_device *cdev, char *buf) +static ssize_t show_flags(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = class_get_devdata(cdev); + struct hci_dev *hdev = dev_get_drvdata(dev); return sprintf(buf, "0x%lx\n", hdev->flags); } -static ssize_t show_inquiry_cache(struct class_device *cdev, char *buf) +static ssize_t show_inquiry_cache(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = class_get_devdata(cdev); + struct hci_dev *hdev = dev_get_drvdata(dev); struct inquiry_cache *cache = &hdev->inq_cache; struct inquiry_entry *e; int n = 0; @@ -63,15 +63,15 @@ static ssize_t show_inquiry_cache(struct class_device *cdev, char *buf) return n; } -static ssize_t show_idle_timeout(struct class_device *cdev, char *buf) +static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = class_get_devdata(cdev); + struct hci_dev *hdev = dev_get_drvdata(dev); return sprintf(buf, "%d\n", hdev->idle_timeout); } -static ssize_t store_idle_timeout(struct class_device *cdev, const char *buf, size_t count) +static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct hci_dev *hdev = class_get_devdata(cdev); + struct hci_dev *hdev = dev_get_drvdata(dev); char *ptr; __u32 val; @@ -87,15 +87,15 @@ static ssize_t store_idle_timeout(struct class_device *cdev, const char *buf, si return count; } -static ssize_t show_sniff_max_interval(struct class_device *cdev, char *buf) +static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = class_get_devdata(cdev); + struct hci_dev *hdev = dev_get_drvdata(dev); return sprintf(buf, "%d\n", hdev->sniff_max_interval); } -static ssize_t store_sniff_max_interval(struct class_device *cdev, const char *buf, size_t count) +static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct hci_dev *hdev = class_get_devdata(cdev); + struct hci_dev *hdev = dev_get_drvdata(dev); char *ptr; __u16 val; @@ -114,15 +114,15 @@ static ssize_t store_sniff_max_interval(struct class_device *cdev, const char *b return count; } -static ssize_t show_sniff_min_interval(struct class_device *cdev, char *buf) +static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribute *attr, char *buf) { - struct hci_dev *hdev = class_get_devdata(cdev); + struct hci_dev *hdev = dev_get_drvdata(dev); return sprintf(buf, "%d\n", hdev->sniff_min_interval); } -static ssize_t store_sniff_min_interval(struct class_device *cdev, const char *buf, size_t count) +static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct hci_dev *hdev = class_get_devdata(cdev); + struct hci_dev *hdev = dev_get_drvdata(dev); char *ptr; __u16 val; @@ -141,64 +141,32 @@ static ssize_t store_sniff_min_interval(struct class_device *cdev, const char *b return count; } -static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL); -static CLASS_DEVICE_ATTR(type, S_IRUGO, show_type, NULL); -static CLASS_DEVICE_ATTR(address, S_IRUGO, show_address, NULL); -static CLASS_DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL); -static CLASS_DEVICE_ATTR(inquiry_cache, S_IRUGO, show_inquiry_cache, NULL); +static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); +static DEVICE_ATTR(type, S_IRUGO, show_type, NULL); +static DEVICE_ATTR(address, S_IRUGO, show_address, NULL); +static DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL); +static DEVICE_ATTR(inquiry_cache, S_IRUGO, show_inquiry_cache, NULL); -static CLASS_DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR, show_idle_timeout, store_idle_timeout); -static CLASS_DEVICE_ATTR(sniff_max_interval, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(sniff_max_interval, S_IRUGO | S_IWUSR, show_sniff_max_interval, store_sniff_max_interval); -static CLASS_DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR, +static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR, show_sniff_min_interval, store_sniff_min_interval); -static struct class_device_attribute *bt_attrs[] = { - &class_device_attr_name, - &class_device_attr_type, - &class_device_attr_address, - &class_device_attr_flags, - &class_device_attr_inquiry_cache, - &class_device_attr_idle_timeout, - &class_device_attr_sniff_max_interval, - &class_device_attr_sniff_min_interval, +static struct device_attribute *bt_attrs[] = { + &dev_attr_name, + &dev_attr_type, + &dev_attr_address, + &dev_attr_flags, + &dev_attr_inquiry_cache, + &dev_attr_idle_timeout, + &dev_attr_sniff_max_interval, + &dev_attr_sniff_min_interval, NULL }; -#ifdef CONFIG_HOTPLUG -static int bt_uevent(struct class_device *cdev, char **envp, int num_envp, char *buf, int size) -{ - struct hci_dev *hdev = class_get_devdata(cdev); - int n, i = 0; - - envp[i++] = buf; - n = snprintf(buf, size, "INTERFACE=%s", hdev->name) + 1; - buf += n; - size -= n; - - if ((size <= 0) || (i >= num_envp)) - return -ENOMEM; - - envp[i] = NULL; - return 0; -} -#endif - -static void bt_release(struct class_device *cdev) -{ - struct hci_dev *hdev = class_get_devdata(cdev); - - kfree(hdev); -} - -struct class bt_class = { - .name = "bluetooth", - .release = bt_release, -#ifdef CONFIG_HOTPLUG - .uevent = bt_uevent, -#endif -}; +struct class *bt_class = NULL; EXPORT_SYMBOL_GPL(bt_class); static struct bus_type bt_bus = { @@ -207,40 +175,50 @@ static struct bus_type bt_bus = { static struct platform_device *bt_platform; +static void bt_release(struct device *dev) +{ + struct hci_dev *hdev = dev_get_drvdata(dev); + kfree(hdev); +} + int hci_register_sysfs(struct hci_dev *hdev) { - struct class_device *cdev = &hdev->class_dev; + struct device *dev = &hdev->dev; unsigned int i; int err; BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type); - cdev->class = &bt_class; - class_set_devdata(cdev, hdev); + dev->class = bt_class; + + if (hdev->parent) + dev->parent = hdev->parent; + else + dev->parent = &bt_platform->dev; + + strlcpy(dev->bus_id, hdev->name, BUS_ID_SIZE); - if (!cdev->dev) - cdev->dev = &bt_platform->dev; + dev->release = bt_release; - hdev->dev = cdev->dev; + dev_set_drvdata(dev, hdev); - strlcpy(cdev->class_id, hdev->name, BUS_ID_SIZE); - err = class_device_register(cdev); + err = device_register(dev); if (err < 0) return err; for (i = 0; bt_attrs[i]; i++) - class_device_create_file(cdev, bt_attrs[i]); + device_create_file(dev, bt_attrs[i]); return 0; } void hci_unregister_sysfs(struct hci_dev *hdev) { - struct class_device * cdev = &hdev->class_dev; + struct device *dev = &hdev->dev; BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type); - class_device_del(cdev); + device_del(dev); } int __init bt_sysfs_init(void) @@ -257,11 +235,11 @@ int __init bt_sysfs_init(void) return err; } - err = class_register(&bt_class); - if (err < 0) { + bt_class = class_create(THIS_MODULE, "bluetooth"); + if (IS_ERR(bt_class)) { bus_unregister(&bt_bus); platform_device_unregister(bt_platform); - return err; + return PTR_ERR(bt_class); } return 0; @@ -269,7 +247,7 @@ int __init bt_sysfs_init(void) void __exit bt_sysfs_cleanup(void) { - class_unregister(&bt_class); + class_destroy(bt_class); bus_unregister(&bt_bus); diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 770101177da1..f6501fa0d59f 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -2219,7 +2219,7 @@ static int __init l2cap_init(void) goto error; } - class_create_file(&bt_class, &class_attr_l2cap); + class_create_file(bt_class, &class_attr_l2cap); BT_INFO("L2CAP ver %s", VERSION); BT_INFO("L2CAP socket layer initialized"); @@ -2233,7 +2233,7 @@ error: static void __exit l2cap_exit(void) { - class_remove_file(&bt_class, &class_attr_l2cap); + class_remove_file(bt_class, &class_attr_l2cap); if (bt_sock_unregister(BTPROTO_L2CAP) < 0) BT_ERR("L2CAP socket unregistration failed"); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index bd46e8927f29..6de33fe7bf5b 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -2035,7 +2035,7 @@ static int __init rfcomm_init(void) kernel_thread(rfcomm_run, NULL, CLONE_KERNEL); - class_create_file(&bt_class, &class_attr_rfcomm_dlc); + class_create_file(bt_class, &class_attr_rfcomm_dlc); rfcomm_init_sockets(); @@ -2050,7 +2050,7 @@ static int __init rfcomm_init(void) static void __exit rfcomm_exit(void) { - class_remove_file(&bt_class, &class_attr_rfcomm_dlc); + class_remove_file(bt_class, &class_attr_rfcomm_dlc); hci_unregister_cb(&rfcomm_cb); diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 4e9962c8cfa6..220fee04e7f2 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -944,7 +944,7 @@ int __init rfcomm_init_sockets(void) if (err < 0) goto error; - class_create_file(&bt_class, &class_attr_rfcomm); + class_create_file(bt_class, &class_attr_rfcomm); BT_INFO("RFCOMM socket layer initialized"); @@ -958,7 +958,7 @@ error: void __exit rfcomm_cleanup_sockets(void) { - class_remove_file(&bt_class, &class_attr_rfcomm); + class_remove_file(bt_class, &class_attr_rfcomm); if (bt_sock_unregister(BTPROTO_RFCOMM) < 0) BT_ERR("RFCOMM socket layer unregistration failed"); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index a5f1e44db5d3..85defccc0287 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -969,7 +969,7 @@ static int __init sco_init(void) goto error; } - class_create_file(&bt_class, &class_attr_sco); + class_create_file(bt_class, &class_attr_sco); BT_INFO("SCO (Voice Link) ver %s", VERSION); BT_INFO("SCO socket layer initialized"); @@ -983,7 +983,7 @@ error: static void __exit sco_exit(void) { - class_remove_file(&bt_class, &class_attr_sco); + class_remove_file(bt_class, &class_attr_sco); if (bt_sock_unregister(BTPROTO_SCO) < 0) BT_ERR("SCO socket unregistration failed"); -- cgit v1.2.3-58-ga151