|
@@ -23,6 +23,7 @@
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
#include <linux/errno.h>
|
|
|
+#include <linux/serdev.h>
|
|
|
#include <linux/skbuff.h>
|
|
|
|
|
|
#include <net/bluetooth/bluetooth.h>
|
|
@@ -65,6 +66,9 @@ enum {
|
|
|
};
|
|
|
|
|
|
struct h5 {
|
|
|
+ /* Must be the first member, hci_serdev.c expects this. */
|
|
|
+ struct hci_uart serdev_hu;
|
|
|
+
|
|
|
struct sk_buff_head unack; /* Unack'ed packets queue */
|
|
|
struct sk_buff_head rel; /* Reliable packets queue */
|
|
|
struct sk_buff_head unrel; /* Unreliable packets queue */
|
|
@@ -193,9 +197,13 @@ static int h5_open(struct hci_uart *hu)
|
|
|
|
|
|
BT_DBG("hu %p", hu);
|
|
|
|
|
|
- h5 = kzalloc(sizeof(*h5), GFP_KERNEL);
|
|
|
- if (!h5)
|
|
|
- return -ENOMEM;
|
|
|
+ if (hu->serdev) {
|
|
|
+ h5 = serdev_device_get_drvdata(hu->serdev);
|
|
|
+ } else {
|
|
|
+ h5 = kzalloc(sizeof(*h5), GFP_KERNEL);
|
|
|
+ if (!h5)
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
|
|
|
hu->priv = h5;
|
|
|
h5->hu = hu;
|
|
@@ -229,7 +237,8 @@ static int h5_close(struct hci_uart *hu)
|
|
|
skb_queue_purge(&h5->rel);
|
|
|
skb_queue_purge(&h5->unrel);
|
|
|
|
|
|
- kfree(h5);
|
|
|
+ if (!hu->serdev)
|
|
|
+ kfree(h5);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
@@ -750,12 +759,47 @@ static const struct hci_uart_proto h5p = {
|
|
|
.flush = h5_flush,
|
|
|
};
|
|
|
|
|
|
+static int h5_serdev_probe(struct serdev_device *serdev)
|
|
|
+{
|
|
|
+ struct device *dev = &serdev->dev;
|
|
|
+ struct h5 *h5;
|
|
|
+
|
|
|
+ h5 = devm_kzalloc(dev, sizeof(*h5), GFP_KERNEL);
|
|
|
+ if (!h5)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ set_bit(HCI_UART_RESET_ON_INIT, &h5->serdev_hu.flags);
|
|
|
+
|
|
|
+ h5->hu = &h5->serdev_hu;
|
|
|
+ h5->serdev_hu.serdev = serdev;
|
|
|
+ serdev_device_set_drvdata(serdev, h5);
|
|
|
+
|
|
|
+ return hci_uart_register_device(&h5->serdev_hu, &h5p);
|
|
|
+}
|
|
|
+
|
|
|
+static void h5_serdev_remove(struct serdev_device *serdev)
|
|
|
+{
|
|
|
+ struct h5 *h5 = serdev_device_get_drvdata(serdev);
|
|
|
+
|
|
|
+ hci_uart_unregister_device(&h5->serdev_hu);
|
|
|
+}
|
|
|
+
|
|
|
+static struct serdev_device_driver h5_serdev_driver = {
|
|
|
+ .probe = h5_serdev_probe,
|
|
|
+ .remove = h5_serdev_remove,
|
|
|
+ .driver = {
|
|
|
+ .name = "hci_uart_h5",
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
int __init h5_init(void)
|
|
|
{
|
|
|
+ serdev_device_driver_register(&h5_serdev_driver);
|
|
|
return hci_uart_register_proto(&h5p);
|
|
|
}
|
|
|
|
|
|
int __exit h5_deinit(void)
|
|
|
{
|
|
|
+ serdev_device_driver_unregister(&h5_serdev_driver);
|
|
|
return hci_uart_unregister_proto(&h5p);
|
|
|
}
|