diff options
Diffstat (limited to 'drivers/bluetooth/hci_ath.c')
-rw-r--r-- | drivers/bluetooth/hci_ath.c | 98 |
1 files changed, 63 insertions, 35 deletions
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c index 1b3f8647ea2f..ec8fa0e0f036 100644 --- a/drivers/bluetooth/hci_ath.c +++ b/drivers/bluetooth/hci_ath.c | |||
@@ -95,7 +95,6 @@ static void ath_hci_uart_work(struct work_struct *work) | |||
95 | hci_uart_tx_wakeup(hu); | 95 | hci_uart_tx_wakeup(hu); |
96 | } | 96 | } |
97 | 97 | ||
98 | /* Initialize protocol */ | ||
99 | static int ath_open(struct hci_uart *hu) | 98 | static int ath_open(struct hci_uart *hu) |
100 | { | 99 | { |
101 | struct ath_struct *ath; | 100 | struct ath_struct *ath; |
@@ -116,8 +115,7 @@ static int ath_open(struct hci_uart *hu) | |||
116 | return 0; | 115 | return 0; |
117 | } | 116 | } |
118 | 117 | ||
119 | /* Flush protocol data */ | 118 | static int ath_close(struct hci_uart *hu) |
120 | static int ath_flush(struct hci_uart *hu) | ||
121 | { | 119 | { |
122 | struct ath_struct *ath = hu->priv; | 120 | struct ath_struct *ath = hu->priv; |
123 | 121 | ||
@@ -125,11 +123,17 @@ static int ath_flush(struct hci_uart *hu) | |||
125 | 123 | ||
126 | skb_queue_purge(&ath->txq); | 124 | skb_queue_purge(&ath->txq); |
127 | 125 | ||
126 | kfree_skb(ath->rx_skb); | ||
127 | |||
128 | cancel_work_sync(&ath->ctxtsw); | ||
129 | |||
130 | hu->priv = NULL; | ||
131 | kfree(ath); | ||
132 | |||
128 | return 0; | 133 | return 0; |
129 | } | 134 | } |
130 | 135 | ||
131 | /* Close protocol */ | 136 | static int ath_flush(struct hci_uart *hu) |
132 | static int ath_close(struct hci_uart *hu) | ||
133 | { | 137 | { |
134 | struct ath_struct *ath = hu->priv; | 138 | struct ath_struct *ath = hu->priv; |
135 | 139 | ||
@@ -137,19 +141,65 @@ static int ath_close(struct hci_uart *hu) | |||
137 | 141 | ||
138 | skb_queue_purge(&ath->txq); | 142 | skb_queue_purge(&ath->txq); |
139 | 143 | ||
140 | kfree_skb(ath->rx_skb); | 144 | return 0; |
145 | } | ||
141 | 146 | ||
142 | cancel_work_sync(&ath->ctxtsw); | 147 | static int ath_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) |
148 | { | ||
149 | struct sk_buff *skb; | ||
150 | u8 buf[10]; | ||
151 | int err; | ||
152 | |||
153 | buf[0] = 0x01; | ||
154 | buf[1] = 0x01; | ||
155 | buf[2] = 0x00; | ||
156 | buf[3] = sizeof(bdaddr_t); | ||
157 | memcpy(buf + 4, bdaddr, sizeof(bdaddr_t)); | ||
158 | |||
159 | skb = __hci_cmd_sync(hdev, 0xfc0b, sizeof(buf), buf, HCI_INIT_TIMEOUT); | ||
160 | if (IS_ERR(skb)) { | ||
161 | err = PTR_ERR(skb); | ||
162 | BT_ERR("%s: Change address command failed (%d)", | ||
163 | hdev->name, err); | ||
164 | return err; | ||
165 | } | ||
166 | kfree_skb(skb); | ||
143 | 167 | ||
144 | hu->priv = NULL; | 168 | return 0; |
145 | kfree(ath); | 169 | } |
170 | |||
171 | static int ath_setup(struct hci_uart *hu) | ||
172 | { | ||
173 | BT_DBG("hu %p", hu); | ||
174 | |||
175 | hu->hdev->set_bdaddr = ath_set_bdaddr; | ||
146 | 176 | ||
147 | return 0; | 177 | return 0; |
148 | } | 178 | } |
149 | 179 | ||
180 | static const struct h4_recv_pkt ath_recv_pkts[] = { | ||
181 | { H4_RECV_ACL, .recv = hci_recv_frame }, | ||
182 | { H4_RECV_SCO, .recv = hci_recv_frame }, | ||
183 | { H4_RECV_EVENT, .recv = hci_recv_frame }, | ||
184 | }; | ||
185 | |||
186 | static int ath_recv(struct hci_uart *hu, const void *data, int count) | ||
187 | { | ||
188 | struct ath_struct *ath = hu->priv; | ||
189 | |||
190 | ath->rx_skb = h4_recv_buf(hu->hdev, ath->rx_skb, data, count, | ||
191 | ath_recv_pkts, ARRAY_SIZE(ath_recv_pkts)); | ||
192 | if (IS_ERR(ath->rx_skb)) { | ||
193 | int err = PTR_ERR(ath->rx_skb); | ||
194 | BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); | ||
195 | return err; | ||
196 | } | ||
197 | |||
198 | return count; | ||
199 | } | ||
200 | |||
150 | #define HCI_OP_ATH_SLEEP 0xFC04 | 201 | #define HCI_OP_ATH_SLEEP 0xFC04 |
151 | 202 | ||
152 | /* Enqueue frame for transmittion */ | ||
153 | static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb) | 203 | static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb) |
154 | { | 204 | { |
155 | struct ath_struct *ath = hu->priv; | 205 | struct ath_struct *ath = hu->priv; |
@@ -159,8 +209,7 @@ static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb) | |||
159 | return 0; | 209 | return 0; |
160 | } | 210 | } |
161 | 211 | ||
162 | /* | 212 | /* Update power management enable flag with parameters of |
163 | * Update power management enable flag with parameters of | ||
164 | * HCI sleep enable vendor specific HCI command. | 213 | * HCI sleep enable vendor specific HCI command. |
165 | */ | 214 | */ |
166 | if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) { | 215 | if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) { |
@@ -190,37 +239,16 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu) | |||
190 | return skb_dequeue(&ath->txq); | 239 | return skb_dequeue(&ath->txq); |
191 | } | 240 | } |
192 | 241 | ||
193 | static const struct h4_recv_pkt ath_recv_pkts[] = { | ||
194 | { H4_RECV_ACL, .recv = hci_recv_frame }, | ||
195 | { H4_RECV_SCO, .recv = hci_recv_frame }, | ||
196 | { H4_RECV_EVENT, .recv = hci_recv_frame }, | ||
197 | }; | ||
198 | |||
199 | /* Recv data */ | ||
200 | static int ath_recv(struct hci_uart *hu, const void *data, int count) | ||
201 | { | ||
202 | struct ath_struct *ath = hu->priv; | ||
203 | |||
204 | ath->rx_skb = h4_recv_buf(hu->hdev, ath->rx_skb, data, count, | ||
205 | ath_recv_pkts, ARRAY_SIZE(ath_recv_pkts)); | ||
206 | if (IS_ERR(ath->rx_skb)) { | ||
207 | int err = PTR_ERR(ath->rx_skb); | ||
208 | BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); | ||
209 | return err; | ||
210 | } | ||
211 | |||
212 | return count; | ||
213 | } | ||
214 | |||
215 | static const struct hci_uart_proto athp = { | 242 | static const struct hci_uart_proto athp = { |
216 | .id = HCI_UART_ATH3K, | 243 | .id = HCI_UART_ATH3K, |
217 | .name = "ATH3K", | 244 | .name = "ATH3K", |
218 | .open = ath_open, | 245 | .open = ath_open, |
219 | .close = ath_close, | 246 | .close = ath_close, |
247 | .flush = ath_flush, | ||
248 | .setup = ath_setup, | ||
220 | .recv = ath_recv, | 249 | .recv = ath_recv, |
221 | .enqueue = ath_enqueue, | 250 | .enqueue = ath_enqueue, |
222 | .dequeue = ath_dequeue, | 251 | .dequeue = ath_dequeue, |
223 | .flush = ath_flush, | ||
224 | }; | 252 | }; |
225 | 253 | ||
226 | int __init ath_init(void) | 254 | int __init ath_init(void) |