summaryrefslogtreecommitdiffstats
path: root/drivers/bluetooth/hci_ldisc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/bluetooth/hci_ldisc.c')
-rw-r--r--drivers/bluetooth/hci_ldisc.c99
1 files changed, 80 insertions, 19 deletions
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index dc487b5d1156..5c9a73f02664 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -44,13 +44,15 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
+#include "btintel.h"
+#include "btbcm.h"
#include "hci_uart.h"
-#define VERSION "2.2"
+#define VERSION "2.3"
-static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
+static const struct hci_uart_proto *hup[HCI_UART_MAX_PROTO];
-int hci_uart_register_proto(struct hci_uart_proto *p)
+int hci_uart_register_proto(const struct hci_uart_proto *p)
{
if (p->id >= HCI_UART_MAX_PROTO)
return -EINVAL;
@@ -60,10 +62,12 @@ int hci_uart_register_proto(struct hci_uart_proto *p)
hup[p->id] = p;
+ BT_INFO("HCI UART protocol %s registered", p->name);
+
return 0;
}
-int hci_uart_unregister_proto(struct hci_uart_proto *p)
+int hci_uart_unregister_proto(const struct hci_uart_proto *p)
{
if (p->id >= HCI_UART_MAX_PROTO)
return -EINVAL;
@@ -76,7 +80,7 @@ int hci_uart_unregister_proto(struct hci_uart_proto *p)
return 0;
}
-static struct hci_uart_proto *hci_uart_get_proto(unsigned int id)
+static const struct hci_uart_proto *hci_uart_get_proto(unsigned int id)
{
if (id >= HCI_UART_MAX_PROTO)
return NULL;
@@ -261,6 +265,54 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
return 0;
}
+static int hci_uart_setup(struct hci_dev *hdev)
+{
+ struct hci_uart *hu = hci_get_drvdata(hdev);
+ struct hci_rp_read_local_version *ver;
+ struct sk_buff *skb;
+
+ if (hu->proto->setup)
+ return hu->proto->setup(hu);
+
+ if (!test_bit(HCI_UART_VND_DETECT, &hu->hdev_flags))
+ return 0;
+
+ skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: Reading local version information failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return 0;
+ }
+
+ if (skb->len != sizeof(*ver)) {
+ BT_ERR("%s: Event length mismatch for version information",
+ hdev->name);
+ goto done;
+ }
+
+ ver = (struct hci_rp_read_local_version *)skb->data;
+
+ switch (le16_to_cpu(ver->manufacturer)) {
+#ifdef CONFIG_BT_HCIUART_INTEL
+ case 2:
+ hdev->set_bdaddr = btintel_set_bdaddr;
+ btintel_check_bdaddr(hdev);
+ break;
+#endif
+#ifdef CONFIG_BT_HCIUART_BCM
+ case 15:
+ hdev->set_bdaddr = btbcm_set_bdaddr;
+ btbcm_check_bdaddr(hdev);
+ break;
+#endif
+ }
+
+done:
+ kfree_skb(skb);
+ return 0;
+}
+
/* ------ LDISC part ------ */
/* hci_uart_tty_open
*
@@ -316,7 +368,7 @@ static int hci_uart_tty_open(struct tty_struct *tty)
*/
static void hci_uart_tty_close(struct tty_struct *tty)
{
- struct hci_uart *hu = (void *)tty->disc_data;
+ struct hci_uart *hu = tty->disc_data;
struct hci_dev *hdev;
BT_DBG("tty %p", tty);
@@ -355,7 +407,7 @@ static void hci_uart_tty_close(struct tty_struct *tty)
*/
static void hci_uart_tty_wakeup(struct tty_struct *tty)
{
- struct hci_uart *hu = (void *)tty->disc_data;
+ struct hci_uart *hu = tty->disc_data;
BT_DBG("");
@@ -383,9 +435,10 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
*
* Return Value: None
*/
-static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
+static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data,
+ char *flags, int count)
{
- struct hci_uart *hu = (void *)tty->disc_data;
+ struct hci_uart *hu = tty->disc_data;
if (!hu || tty != hu->tty)
return;
@@ -394,7 +447,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f
return;
spin_lock(&hu->rx_lock);
- hu->proto->recv(hu, (void *) data, count);
+ hu->proto->recv(hu, data, count);
if (hu->hdev)
hu->hdev->stat.byte_rx += count;
@@ -426,6 +479,7 @@ static int hci_uart_register_dev(struct hci_uart *hu)
hdev->close = hci_uart_close;
hdev->flush = hci_uart_flush;
hdev->send = hci_uart_send_frame;
+ hdev->setup = hci_uart_setup;
SET_HCIDEV_DEV(hdev, hu->tty->dev);
if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
@@ -458,7 +512,7 @@ static int hci_uart_register_dev(struct hci_uart *hu)
static int hci_uart_set_proto(struct hci_uart *hu, int id)
{
- struct hci_uart_proto *p;
+ const struct hci_uart_proto *p;
int err;
p = hci_uart_get_proto(id);
@@ -486,9 +540,10 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags)
BIT(HCI_UART_RESET_ON_INIT) |
BIT(HCI_UART_CREATE_AMP) |
BIT(HCI_UART_INIT_PENDING) |
- BIT(HCI_UART_EXT_CONFIG);
+ BIT(HCI_UART_EXT_CONFIG) |
+ BIT(HCI_UART_VND_DETECT);
- if ((flags & ~valid_flags))
+ if (flags & ~valid_flags)
return -EINVAL;
hu->hdev_flags = flags;
@@ -509,10 +564,10 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags)
*
* Return Value: Command dependent
*/
-static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg)
+static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
- struct hci_uart *hu = (void *)tty->disc_data;
+ struct hci_uart *hu = tty->disc_data;
int err = 0;
BT_DBG("");
@@ -566,19 +621,19 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
* We don't provide read/write/poll interface for user space.
*/
static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file,
- unsigned char __user *buf, size_t nr)
+ unsigned char __user *buf, size_t nr)
{
return 0;
}
static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file,
- const unsigned char *data, size_t count)
+ const unsigned char *data, size_t count)
{
return 0;
}
static unsigned int hci_uart_tty_poll(struct tty_struct *tty,
- struct file *filp, poll_table *wait)
+ struct file *filp, poll_table *wait)
{
return 0;
}
@@ -626,6 +681,9 @@ static int __init hci_uart_init(void)
#ifdef CONFIG_BT_HCIUART_3WIRE
h5_init();
#endif
+#ifdef CONFIG_BT_HCIUART_BCM
+ bcm_init();
+#endif
return 0;
}
@@ -649,6 +707,9 @@ static void __exit hci_uart_exit(void)
#ifdef CONFIG_BT_HCIUART_3WIRE
h5_deinit();
#endif
+#ifdef CONFIG_BT_HCIUART_BCM
+ bcm_deinit();
+#endif
/* Release tty registration of line discipline */
err = tty_unregister_ldisc(N_HCI);
OpenPOWER on IntegriCloud