diff options
-rw-r--r-- | drivers/bluetooth/hci_h5.c | 52 |
1 files changed, 48 insertions, 4 deletions
diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 6a8d0d06aba7..672f63623bf7 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c | |||
@@ -23,6 +23,7 @@ | |||
23 | 23 | ||
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/errno.h> | 25 | #include <linux/errno.h> |
26 | #include <linux/serdev.h> | ||
26 | #include <linux/skbuff.h> | 27 | #include <linux/skbuff.h> |
27 | 28 | ||
28 | #include <net/bluetooth/bluetooth.h> | 29 | #include <net/bluetooth/bluetooth.h> |
@@ -65,6 +66,9 @@ enum { | |||
65 | }; | 66 | }; |
66 | 67 | ||
67 | struct h5 { | 68 | struct h5 { |
69 | /* Must be the first member, hci_serdev.c expects this. */ | ||
70 | struct hci_uart serdev_hu; | ||
71 | |||
68 | struct sk_buff_head unack; /* Unack'ed packets queue */ | 72 | struct sk_buff_head unack; /* Unack'ed packets queue */ |
69 | struct sk_buff_head rel; /* Reliable packets queue */ | 73 | struct sk_buff_head rel; /* Reliable packets queue */ |
70 | struct sk_buff_head unrel; /* Unreliable packets queue */ | 74 | struct sk_buff_head unrel; /* Unreliable packets queue */ |
@@ -193,9 +197,13 @@ static int h5_open(struct hci_uart *hu) | |||
193 | 197 | ||
194 | BT_DBG("hu %p", hu); | 198 | BT_DBG("hu %p", hu); |
195 | 199 | ||
196 | h5 = kzalloc(sizeof(*h5), GFP_KERNEL); | 200 | if (hu->serdev) { |
197 | if (!h5) | 201 | h5 = serdev_device_get_drvdata(hu->serdev); |
198 | return -ENOMEM; | 202 | } else { |
203 | h5 = kzalloc(sizeof(*h5), GFP_KERNEL); | ||
204 | if (!h5) | ||
205 | return -ENOMEM; | ||
206 | } | ||
199 | 207 | ||
200 | hu->priv = h5; | 208 | hu->priv = h5; |
201 | h5->hu = hu; | 209 | h5->hu = hu; |
@@ -229,7 +237,8 @@ static int h5_close(struct hci_uart *hu) | |||
229 | skb_queue_purge(&h5->rel); | 237 | skb_queue_purge(&h5->rel); |
230 | skb_queue_purge(&h5->unrel); | 238 | skb_queue_purge(&h5->unrel); |
231 | 239 | ||
232 | kfree(h5); | 240 | if (!hu->serdev) |
241 | kfree(h5); | ||
233 | 242 | ||
234 | return 0; | 243 | return 0; |
235 | } | 244 | } |
@@ -750,12 +759,47 @@ static const struct hci_uart_proto h5p = { | |||
750 | .flush = h5_flush, | 759 | .flush = h5_flush, |
751 | }; | 760 | }; |
752 | 761 | ||
762 | static int h5_serdev_probe(struct serdev_device *serdev) | ||
763 | { | ||
764 | struct device *dev = &serdev->dev; | ||
765 | struct h5 *h5; | ||
766 | |||
767 | h5 = devm_kzalloc(dev, sizeof(*h5), GFP_KERNEL); | ||
768 | if (!h5) | ||
769 | return -ENOMEM; | ||
770 | |||
771 | set_bit(HCI_UART_RESET_ON_INIT, &h5->serdev_hu.flags); | ||
772 | |||
773 | h5->hu = &h5->serdev_hu; | ||
774 | h5->serdev_hu.serdev = serdev; | ||
775 | serdev_device_set_drvdata(serdev, h5); | ||
776 | |||
777 | return hci_uart_register_device(&h5->serdev_hu, &h5p); | ||
778 | } | ||
779 | |||
780 | static void h5_serdev_remove(struct serdev_device *serdev) | ||
781 | { | ||
782 | struct h5 *h5 = serdev_device_get_drvdata(serdev); | ||
783 | |||
784 | hci_uart_unregister_device(&h5->serdev_hu); | ||
785 | } | ||
786 | |||
787 | static struct serdev_device_driver h5_serdev_driver = { | ||
788 | .probe = h5_serdev_probe, | ||
789 | .remove = h5_serdev_remove, | ||
790 | .driver = { | ||
791 | .name = "hci_uart_h5", | ||
792 | }, | ||
793 | }; | ||
794 | |||
753 | int __init h5_init(void) | 795 | int __init h5_init(void) |
754 | { | 796 | { |
797 | serdev_device_driver_register(&h5_serdev_driver); | ||
755 | return hci_uart_register_proto(&h5p); | 798 | return hci_uart_register_proto(&h5p); |
756 | } | 799 | } |
757 | 800 | ||
758 | int __exit h5_deinit(void) | 801 | int __exit h5_deinit(void) |
759 | { | 802 | { |
803 | serdev_device_driver_unregister(&h5_serdev_driver); | ||
760 | return hci_uart_unregister_proto(&h5p); | 804 | return hci_uart_unregister_proto(&h5p); |
761 | } | 805 | } |