Commit | Line | Data |
---|---|---|
53618cc1 PS |
1 | /* |
2 | * Shared Transport Line discipline driver Core | |
3 | * This hooks up ST KIM driver and ST LL driver | |
a0cc2f3b PS |
4 | * Copyright (C) 2009-2010 Texas Instruments |
5 | * Author: Pavan Savoy <pavan_savoy@ti.com> | |
53618cc1 PS |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 as | |
9 | * published by the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | * | |
20 | */ | |
21 | ||
22 | #define pr_fmt(fmt) "(stc): " fmt | |
23 | #include <linux/module.h> | |
24 | #include <linux/kernel.h> | |
25 | #include <linux/init.h> | |
26 | #include <linux/tty.h> | |
27 | ||
5c88b021 PS |
28 | #include <linux/seq_file.h> |
29 | #include <linux/skbuff.h> | |
30 | ||
e5558679 | 31 | #include <linux/ti_wilink_st.h> |
53618cc1 | 32 | |
27712b39 PS |
33 | extern void st_kim_recv(void *, const unsigned char *, long); |
34 | void st_int_recv(void *, const unsigned char *, long); | |
53618cc1 PS |
35 | /* function pointer pointing to either, |
36 | * st_kim_recv during registration to receive fw download responses | |
37 | * st_int_recv after registration to receive proto stack responses | |
38 | */ | |
27712b39 | 39 | static void (*st_recv) (void *, const unsigned char *, long); |
53618cc1 PS |
40 | |
41 | /********************************************************************/ | |
5c88b021 PS |
42 | static void add_channel_to_table(struct st_data_s *st_gdata, |
43 | struct st_proto_s *new_proto) | |
53618cc1 | 44 | { |
5c88b021 PS |
45 | pr_info("%s: id %d\n", __func__, new_proto->chnl_id); |
46 | /* list now has the channel id as index itself */ | |
47 | st_gdata->list[new_proto->chnl_id] = new_proto; | |
764b0c4b | 48 | st_gdata->is_registered[new_proto->chnl_id] = true; |
5c88b021 PS |
49 | } |
50 | ||
51 | static void remove_channel_from_table(struct st_data_s *st_gdata, | |
52 | struct st_proto_s *proto) | |
53 | { | |
54 | pr_info("%s: id %d\n", __func__, proto->chnl_id); | |
764b0c4b PS |
55 | /* st_gdata->list[proto->chnl_id] = NULL; */ |
56 | st_gdata->is_registered[proto->chnl_id] = false; | |
53618cc1 | 57 | } |
36b5aee4 | 58 | |
ef04d121 PS |
59 | /* |
60 | * called from KIM during firmware download. | |
61 | * | |
62 | * This is a wrapper function to tty->ops->write_room. | |
63 | * It returns number of free space available in | |
64 | * uart tx buffer. | |
65 | */ | |
66 | int st_get_uart_wr_room(struct st_data_s *st_gdata) | |
67 | { | |
68 | struct tty_struct *tty; | |
69 | if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) { | |
70 | pr_err("tty unavailable to perform write"); | |
71 | return -1; | |
72 | } | |
73 | tty = st_gdata->tty; | |
74 | return tty->ops->write_room(tty); | |
75 | } | |
76 | ||
53618cc1 PS |
77 | /* can be called in from |
78 | * -- KIM (during fw download) | |
79 | * -- ST Core (during st_write) | |
80 | * | |
81 | * This is the internal write function - a wrapper | |
82 | * to tty->ops->write | |
83 | */ | |
84 | int st_int_write(struct st_data_s *st_gdata, | |
85 | const unsigned char *data, int count) | |
86 | { | |
53618cc1 PS |
87 | struct tty_struct *tty; |
88 | if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) { | |
89 | pr_err("tty unavailable to perform write"); | |
70442664 | 90 | return -EINVAL; |
53618cc1 PS |
91 | } |
92 | tty = st_gdata->tty; | |
93 | #ifdef VERBOSE | |
e6d9e64e PS |
94 | print_hex_dump(KERN_DEBUG, "<out<", DUMP_PREFIX_NONE, |
95 | 16, 1, data, count, 0); | |
53618cc1 PS |
96 | #endif |
97 | return tty->ops->write(tty, data, count); | |
98 | ||
99 | } | |
100 | ||
101 | /* | |
102 | * push the skb received to relevant | |
103 | * protocol stacks | |
104 | */ | |
27712b39 | 105 | static void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata) |
53618cc1 | 106 | { |
6710fcff | 107 | pr_debug(" %s(prot:%d) ", __func__, chnl_id); |
53618cc1 PS |
108 | |
109 | if (unlikely | |
110 | (st_gdata == NULL || st_gdata->rx_skb == NULL | |
764b0c4b | 111 | || st_gdata->is_registered[chnl_id] == false)) { |
5c88b021 PS |
112 | pr_err("chnl_id %d not registered, no data to send?", |
113 | chnl_id); | |
53618cc1 PS |
114 | kfree_skb(st_gdata->rx_skb); |
115 | return; | |
116 | } | |
117 | /* this cannot fail | |
118 | * this shouldn't take long | |
119 | * - should be just skb_queue_tail for the | |
120 | * protocol stack driver | |
121 | */ | |
5c88b021 | 122 | if (likely(st_gdata->list[chnl_id]->recv != NULL)) { |
bb8f3c06 | 123 | if (unlikely |
5c88b021 PS |
124 | (st_gdata->list[chnl_id]->recv |
125 | (st_gdata->list[chnl_id]->priv_data, st_gdata->rx_skb) | |
320920cb | 126 | != 0)) { |
5c88b021 | 127 | pr_err(" proto stack %d's ->recv failed", chnl_id); |
53618cc1 PS |
128 | kfree_skb(st_gdata->rx_skb); |
129 | return; | |
130 | } | |
131 | } else { | |
5c88b021 | 132 | pr_err(" proto stack %d's ->recv null", chnl_id); |
53618cc1 PS |
133 | kfree_skb(st_gdata->rx_skb); |
134 | } | |
53618cc1 PS |
135 | return; |
136 | } | |
137 | ||
36b5aee4 PS |
138 | /** |
139 | * st_reg_complete - | |
53618cc1 PS |
140 | * to call registration complete callbacks |
141 | * of all protocol stack drivers | |
bfb88d6c PS |
142 | * This function is being called with spin lock held, protocol drivers are |
143 | * only expected to complete their waits and do nothing more than that. | |
53618cc1 | 144 | */ |
27712b39 | 145 | static void st_reg_complete(struct st_data_s *st_gdata, char err) |
53618cc1 PS |
146 | { |
147 | unsigned char i = 0; | |
148 | pr_info(" %s ", __func__); | |
5c88b021 | 149 | for (i = 0; i < ST_MAX_CHANNELS; i++) { |
764b0c4b PS |
150 | if (likely(st_gdata != NULL && |
151 | st_gdata->is_registered[i] == true && | |
152 | st_gdata->list[i]->reg_complete_cb != NULL)) { | |
bb8f3c06 PS |
153 | st_gdata->list[i]->reg_complete_cb |
154 | (st_gdata->list[i]->priv_data, err); | |
70442664 PS |
155 | pr_info("protocol %d's cb sent %d\n", i, err); |
156 | if (err) { /* cleanup registered protocol */ | |
157 | st_gdata->protos_registered--; | |
764b0c4b | 158 | st_gdata->is_registered[i] = false; |
70442664 PS |
159 | } |
160 | } | |
53618cc1 PS |
161 | } |
162 | } | |
163 | ||
164 | static inline int st_check_data_len(struct st_data_s *st_gdata, | |
5c88b021 | 165 | unsigned char chnl_id, int len) |
53618cc1 | 166 | { |
73f12e8d | 167 | int room = skb_tailroom(st_gdata->rx_skb); |
53618cc1 | 168 | |
e6d9e64e | 169 | pr_debug("len %d room %d", len, room); |
53618cc1 PS |
170 | |
171 | if (!len) { | |
172 | /* Received packet has only packet header and | |
173 | * has zero length payload. So, ask ST CORE to | |
174 | * forward the packet to protocol driver (BT/FM/GPS) | |
175 | */ | |
5c88b021 | 176 | st_send_frame(chnl_id, st_gdata); |
53618cc1 PS |
177 | |
178 | } else if (len > room) { | |
179 | /* Received packet's payload length is larger. | |
180 | * We can't accommodate it in created skb. | |
181 | */ | |
182 | pr_err("Data length is too large len %d room %d", len, | |
183 | room); | |
184 | kfree_skb(st_gdata->rx_skb); | |
185 | } else { | |
186 | /* Packet header has non-zero payload length and | |
187 | * we have enough space in created skb. Lets read | |
188 | * payload data */ | |
5c88b021 | 189 | st_gdata->rx_state = ST_W4_DATA; |
53618cc1 PS |
190 | st_gdata->rx_count = len; |
191 | return len; | |
192 | } | |
193 | ||
194 | /* Change ST state to continue to process next | |
195 | * packet */ | |
196 | st_gdata->rx_state = ST_W4_PACKET_TYPE; | |
197 | st_gdata->rx_skb = NULL; | |
198 | st_gdata->rx_count = 0; | |
5c88b021 | 199 | st_gdata->rx_chnl = 0; |
53618cc1 PS |
200 | |
201 | return 0; | |
202 | } | |
203 | ||
36b5aee4 PS |
204 | /** |
205 | * st_wakeup_ack - internal function for action when wake-up ack | |
206 | * received | |
53618cc1 PS |
207 | */ |
208 | static inline void st_wakeup_ack(struct st_data_s *st_gdata, | |
209 | unsigned char cmd) | |
210 | { | |
73f12e8d | 211 | struct sk_buff *waiting_skb; |
53618cc1 PS |
212 | unsigned long flags = 0; |
213 | ||
214 | spin_lock_irqsave(&st_gdata->lock, flags); | |
215 | /* de-Q from waitQ and Q in txQ now that the | |
216 | * chip is awake | |
217 | */ | |
218 | while ((waiting_skb = skb_dequeue(&st_gdata->tx_waitq))) | |
219 | skb_queue_tail(&st_gdata->txq, waiting_skb); | |
220 | ||
221 | /* state forwarded to ST LL */ | |
222 | st_ll_sleep_state(st_gdata, (unsigned long)cmd); | |
223 | spin_unlock_irqrestore(&st_gdata->lock, flags); | |
224 | ||
225 | /* wake up to send the recently copied skbs from waitQ */ | |
226 | st_tx_wakeup(st_gdata); | |
227 | } | |
228 | ||
36b5aee4 PS |
229 | /** |
230 | * st_int_recv - ST's internal receive function. | |
231 | * Decodes received RAW data and forwards to corresponding | |
232 | * client drivers (Bluetooth,FM,GPS..etc). | |
233 | * This can receive various types of packets, | |
234 | * HCI-Events, ACL, SCO, 4 types of HCI-LL PM packets | |
235 | * CH-8 packets from FM, CH-9 packets from GPS cores. | |
53618cc1 PS |
236 | */ |
237 | void st_int_recv(void *disc_data, | |
238 | const unsigned char *data, long count) | |
239 | { | |
73f12e8d | 240 | char *ptr; |
5c88b021 PS |
241 | struct st_proto_s *proto; |
242 | unsigned short payload_len = 0; | |
25c22d5b | 243 | int len = 0; |
244 | unsigned char type = 0; | |
5c88b021 | 245 | unsigned char *plen; |
53618cc1 | 246 | struct st_data_s *st_gdata = (struct st_data_s *)disc_data; |
6d71ba21 | 247 | unsigned long flags; |
53618cc1 PS |
248 | |
249 | ptr = (char *)data; | |
250 | /* tty_receive sent null ? */ | |
251 | if (unlikely(ptr == NULL) || (st_gdata == NULL)) { | |
252 | pr_err(" received null from TTY "); | |
253 | return; | |
254 | } | |
255 | ||
6710fcff | 256 | pr_debug("count %ld rx_state %ld" |
53618cc1 PS |
257 | "rx_count %ld", count, st_gdata->rx_state, |
258 | st_gdata->rx_count); | |
259 | ||
6d71ba21 | 260 | spin_lock_irqsave(&st_gdata->lock, flags); |
53618cc1 PS |
261 | /* Decode received bytes here */ |
262 | while (count) { | |
263 | if (st_gdata->rx_count) { | |
264 | len = min_t(unsigned int, st_gdata->rx_count, count); | |
265 | memcpy(skb_put(st_gdata->rx_skb, len), ptr, len); | |
266 | st_gdata->rx_count -= len; | |
267 | count -= len; | |
268 | ptr += len; | |
269 | ||
270 | if (st_gdata->rx_count) | |
271 | continue; | |
272 | ||
273 | /* Check ST RX state machine , where are we? */ | |
274 | switch (st_gdata->rx_state) { | |
5c88b021 PS |
275 | /* Waiting for complete packet ? */ |
276 | case ST_W4_DATA: | |
e6d9e64e | 277 | pr_debug("Complete pkt received"); |
53618cc1 PS |
278 | /* Ask ST CORE to forward |
279 | * the packet to protocol driver */ | |
5c88b021 | 280 | st_send_frame(st_gdata->rx_chnl, st_gdata); |
53618cc1 PS |
281 | |
282 | st_gdata->rx_state = ST_W4_PACKET_TYPE; | |
283 | st_gdata->rx_skb = NULL; | |
53618cc1 | 284 | continue; |
5c88b021 PS |
285 | /* parse the header to know details */ |
286 | case ST_W4_HEADER: | |
287 | proto = st_gdata->list[st_gdata->rx_chnl]; | |
288 | plen = | |
289 | &st_gdata->rx_skb->data | |
290 | [proto->offset_len_in_hdr]; | |
6710fcff | 291 | pr_debug("plen pointing to %x\n", *plen); |
5c88b021 PS |
292 | if (proto->len_size == 1)/* 1 byte len field */ |
293 | payload_len = *(unsigned char *)plen; | |
294 | else if (proto->len_size == 2) | |
295 | payload_len = | |
296 | __le16_to_cpu(*(unsigned short *)plen); | |
297 | else | |
298 | pr_info("%s: invalid length " | |
299 | "for id %d\n", | |
300 | __func__, proto->chnl_id); | |
301 | st_check_data_len(st_gdata, proto->chnl_id, | |
302 | payload_len); | |
6710fcff | 303 | pr_debug("off %d, pay len %d\n", |
5c88b021 | 304 | proto->offset_len_in_hdr, payload_len); |
53618cc1 PS |
305 | continue; |
306 | } /* end of switch rx_state */ | |
307 | } | |
308 | ||
309 | /* end of if rx_count */ | |
310 | /* Check first byte of packet and identify module | |
311 | * owner (BT/FM/GPS) */ | |
312 | switch (*ptr) { | |
53618cc1 PS |
313 | case LL_SLEEP_IND: |
314 | case LL_SLEEP_ACK: | |
315 | case LL_WAKE_UP_IND: | |
6710fcff | 316 | pr_debug("PM packet"); |
53618cc1 PS |
317 | /* this takes appropriate action based on |
318 | * sleep state received -- | |
319 | */ | |
320 | st_ll_sleep_state(st_gdata, *ptr); | |
6d71ba21 PS |
321 | /* if WAKEUP_IND collides copy from waitq to txq |
322 | * and assume chip awake | |
323 | */ | |
324 | spin_unlock_irqrestore(&st_gdata->lock, flags); | |
325 | if (st_ll_getstate(st_gdata) == ST_LL_AWAKE) | |
326 | st_wakeup_ack(st_gdata, LL_WAKE_UP_ACK); | |
327 | spin_lock_irqsave(&st_gdata->lock, flags); | |
328 | ||
53618cc1 PS |
329 | ptr++; |
330 | count--; | |
331 | continue; | |
332 | case LL_WAKE_UP_ACK: | |
6710fcff | 333 | pr_debug("PM packet"); |
6d71ba21 PS |
334 | |
335 | spin_unlock_irqrestore(&st_gdata->lock, flags); | |
53618cc1 PS |
336 | /* wake up ack received */ |
337 | st_wakeup_ack(st_gdata, *ptr); | |
6d71ba21 PS |
338 | spin_lock_irqsave(&st_gdata->lock, flags); |
339 | ||
53618cc1 PS |
340 | ptr++; |
341 | count--; | |
342 | continue; | |
343 | /* Unknow packet? */ | |
344 | default: | |
5c88b021 | 345 | type = *ptr; |
78bb9697 VB |
346 | if (st_gdata->list[type] == NULL) { |
347 | pr_err("chip/interface misbehavior dropping" | |
348 | " frame starting with 0x%02x", type); | |
349 | goto done; | |
350 | ||
351 | } | |
5c88b021 PS |
352 | st_gdata->rx_skb = alloc_skb( |
353 | st_gdata->list[type]->max_frame_size, | |
354 | GFP_ATOMIC); | |
5353cf08 AC |
355 | if (st_gdata->rx_skb == NULL) { |
356 | pr_err("out of memory: dropping\n"); | |
357 | goto done; | |
358 | } | |
359 | ||
5c88b021 PS |
360 | skb_reserve(st_gdata->rx_skb, |
361 | st_gdata->list[type]->reserve); | |
362 | /* next 2 required for BT only */ | |
363 | st_gdata->rx_skb->cb[0] = type; /*pkt_type*/ | |
364 | st_gdata->rx_skb->cb[1] = 0; /*incoming*/ | |
365 | st_gdata->rx_chnl = *ptr; | |
366 | st_gdata->rx_state = ST_W4_HEADER; | |
367 | st_gdata->rx_count = st_gdata->list[type]->hdr_len; | |
6710fcff | 368 | pr_debug("rx_count %ld\n", st_gdata->rx_count); |
53618cc1 PS |
369 | }; |
370 | ptr++; | |
371 | count--; | |
53618cc1 | 372 | } |
78bb9697 | 373 | done: |
6d71ba21 | 374 | spin_unlock_irqrestore(&st_gdata->lock, flags); |
e6d9e64e | 375 | pr_debug("done %s", __func__); |
53618cc1 PS |
376 | return; |
377 | } | |
378 | ||
36b5aee4 PS |
379 | /** |
380 | * st_int_dequeue - internal de-Q function. | |
381 | * If the previous data set was not written | |
382 | * completely, return that skb which has the pending data. | |
383 | * In normal cases, return top of txq. | |
53618cc1 | 384 | */ |
27712b39 | 385 | static struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata) |
53618cc1 PS |
386 | { |
387 | struct sk_buff *returning_skb; | |
388 | ||
e6d9e64e | 389 | pr_debug("%s", __func__); |
53618cc1 PS |
390 | if (st_gdata->tx_skb != NULL) { |
391 | returning_skb = st_gdata->tx_skb; | |
392 | st_gdata->tx_skb = NULL; | |
393 | return returning_skb; | |
394 | } | |
53618cc1 PS |
395 | return skb_dequeue(&st_gdata->txq); |
396 | } | |
397 | ||
36b5aee4 PS |
398 | /** |
399 | * st_int_enqueue - internal Q-ing function. | |
400 | * Will either Q the skb to txq or the tx_waitq | |
401 | * depending on the ST LL state. | |
402 | * If the chip is asleep, then Q it onto waitq and | |
403 | * wakeup the chip. | |
404 | * txq and waitq needs protection since the other contexts | |
405 | * may be sending data, waking up chip. | |
53618cc1 | 406 | */ |
27712b39 | 407 | static void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb) |
53618cc1 PS |
408 | { |
409 | unsigned long flags = 0; | |
410 | ||
e6d9e64e | 411 | pr_debug("%s", __func__); |
53618cc1 PS |
412 | spin_lock_irqsave(&st_gdata->lock, flags); |
413 | ||
414 | switch (st_ll_getstate(st_gdata)) { | |
415 | case ST_LL_AWAKE: | |
6710fcff | 416 | pr_debug("ST LL is AWAKE, sending normally"); |
53618cc1 PS |
417 | skb_queue_tail(&st_gdata->txq, skb); |
418 | break; | |
419 | case ST_LL_ASLEEP_TO_AWAKE: | |
420 | skb_queue_tail(&st_gdata->tx_waitq, skb); | |
421 | break; | |
36b5aee4 | 422 | case ST_LL_AWAKE_TO_ASLEEP: |
53618cc1 PS |
423 | pr_err("ST LL is illegal state(%ld)," |
424 | "purging received skb.", st_ll_getstate(st_gdata)); | |
425 | kfree_skb(skb); | |
426 | break; | |
53618cc1 | 427 | case ST_LL_ASLEEP: |
53618cc1 PS |
428 | skb_queue_tail(&st_gdata->tx_waitq, skb); |
429 | st_ll_wakeup(st_gdata); | |
430 | break; | |
431 | default: | |
432 | pr_err("ST LL is illegal state(%ld)," | |
433 | "purging received skb.", st_ll_getstate(st_gdata)); | |
434 | kfree_skb(skb); | |
435 | break; | |
436 | } | |
36b5aee4 | 437 | |
53618cc1 | 438 | spin_unlock_irqrestore(&st_gdata->lock, flags); |
e6d9e64e | 439 | pr_debug("done %s", __func__); |
53618cc1 PS |
440 | return; |
441 | } | |
442 | ||
443 | /* | |
444 | * internal wakeup function | |
445 | * called from either | |
446 | * - TTY layer when write's finished | |
447 | * - st_write (in context of the protocol stack) | |
448 | */ | |
449 | void st_tx_wakeup(struct st_data_s *st_data) | |
450 | { | |
451 | struct sk_buff *skb; | |
452 | unsigned long flags; /* for irq save flags */ | |
e6d9e64e | 453 | pr_debug("%s", __func__); |
53618cc1 PS |
454 | /* check for sending & set flag sending here */ |
455 | if (test_and_set_bit(ST_TX_SENDING, &st_data->tx_state)) { | |
6710fcff | 456 | pr_debug("ST already sending"); |
53618cc1 PS |
457 | /* keep sending */ |
458 | set_bit(ST_TX_WAKEUP, &st_data->tx_state); | |
459 | return; | |
460 | /* TX_WAKEUP will be checked in another | |
461 | * context | |
462 | */ | |
463 | } | |
464 | do { /* come back if st_tx_wakeup is set */ | |
465 | /* woke-up to write */ | |
466 | clear_bit(ST_TX_WAKEUP, &st_data->tx_state); | |
467 | while ((skb = st_int_dequeue(st_data))) { | |
468 | int len; | |
469 | spin_lock_irqsave(&st_data->lock, flags); | |
470 | /* enable wake-up from TTY */ | |
471 | set_bit(TTY_DO_WRITE_WAKEUP, &st_data->tty->flags); | |
472 | len = st_int_write(st_data, skb->data, skb->len); | |
473 | skb_pull(skb, len); | |
474 | /* if skb->len = len as expected, skb->len=0 */ | |
475 | if (skb->len) { | |
476 | /* would be the next skb to be sent */ | |
477 | st_data->tx_skb = skb; | |
478 | spin_unlock_irqrestore(&st_data->lock, flags); | |
479 | break; | |
480 | } | |
481 | kfree_skb(skb); | |
482 | spin_unlock_irqrestore(&st_data->lock, flags); | |
483 | } | |
484 | /* if wake-up is set in another context- restart sending */ | |
485 | } while (test_bit(ST_TX_WAKEUP, &st_data->tx_state)); | |
486 | ||
487 | /* clear flag sending */ | |
488 | clear_bit(ST_TX_SENDING, &st_data->tx_state); | |
489 | } | |
490 | ||
491 | /********************************************************************/ | |
492 | /* functions called from ST KIM | |
493 | */ | |
c1afac15 | 494 | void kim_st_list_protocols(struct st_data_s *st_gdata, void *buf) |
53618cc1 | 495 | { |
c1afac15 | 496 | seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n", |
36e574fe | 497 | st_gdata->protos_registered, |
764b0c4b PS |
498 | st_gdata->is_registered[0x04] == true ? 'R' : 'U', |
499 | st_gdata->is_registered[0x08] == true ? 'R' : 'U', | |
500 | st_gdata->is_registered[0x09] == true ? 'R' : 'U'); | |
53618cc1 PS |
501 | } |
502 | ||
503 | /********************************************************************/ | |
504 | /* | |
505 | * functions called from protocol stack drivers | |
506 | * to be EXPORT-ed | |
507 | */ | |
508 | long st_register(struct st_proto_s *new_proto) | |
509 | { | |
510 | struct st_data_s *st_gdata; | |
320920cb | 511 | long err = 0; |
53618cc1 PS |
512 | unsigned long flags = 0; |
513 | ||
dbd3a870 | 514 | st_kim_ref(&st_gdata, 0); |
53618cc1 PS |
515 | if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL |
516 | || new_proto->reg_complete_cb == NULL) { | |
517 | pr_err("gdata/new_proto/recv or reg_complete_cb not ready"); | |
70442664 | 518 | return -EINVAL; |
53618cc1 PS |
519 | } |
520 | ||
5c88b021 PS |
521 | if (new_proto->chnl_id >= ST_MAX_CHANNELS) { |
522 | pr_err("chnl_id %d not supported", new_proto->chnl_id); | |
320920cb | 523 | return -EPROTONOSUPPORT; |
53618cc1 PS |
524 | } |
525 | ||
764b0c4b | 526 | if (st_gdata->is_registered[new_proto->chnl_id] == true) { |
5c88b021 | 527 | pr_err("chnl_id %d already registered", new_proto->chnl_id); |
320920cb | 528 | return -EALREADY; |
53618cc1 PS |
529 | } |
530 | ||
531 | /* can be from process context only */ | |
532 | spin_lock_irqsave(&st_gdata->lock, flags); | |
533 | ||
534 | if (test_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state)) { | |
5c88b021 | 535 | pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->chnl_id); |
53618cc1 | 536 | /* fw download in progress */ |
53618cc1 | 537 | |
5c88b021 | 538 | add_channel_to_table(st_gdata, new_proto); |
36e574fe | 539 | st_gdata->protos_registered++; |
53618cc1 PS |
540 | new_proto->write = st_write; |
541 | ||
542 | set_bit(ST_REG_PENDING, &st_gdata->st_state); | |
543 | spin_unlock_irqrestore(&st_gdata->lock, flags); | |
320920cb | 544 | return -EINPROGRESS; |
53618cc1 | 545 | } else if (st_gdata->protos_registered == ST_EMPTY) { |
5c88b021 | 546 | pr_info(" chnl_id list empty :%d ", new_proto->chnl_id); |
53618cc1 PS |
547 | set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); |
548 | st_recv = st_kim_recv; | |
549 | ||
bfb88d6c PS |
550 | /* enable the ST LL - to set default chip state */ |
551 | st_ll_enable(st_gdata); | |
552 | ||
53618cc1 PS |
553 | /* release lock previously held - re-locked below */ |
554 | spin_unlock_irqrestore(&st_gdata->lock, flags); | |
555 | ||
53618cc1 PS |
556 | /* this may take a while to complete |
557 | * since it involves BT fw download | |
558 | */ | |
38d9df49 | 559 | err = st_kim_start(st_gdata->kim_data); |
320920cb | 560 | if (err != 0) { |
53618cc1 PS |
561 | clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); |
562 | if ((st_gdata->protos_registered != ST_EMPTY) && | |
563 | (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { | |
564 | pr_err(" KIM failure complete callback "); | |
70442664 | 565 | st_reg_complete(st_gdata, err); |
bfb88d6c | 566 | clear_bit(ST_REG_PENDING, &st_gdata->st_state); |
53618cc1 | 567 | } |
70442664 | 568 | return -EINVAL; |
53618cc1 PS |
569 | } |
570 | ||
bfb88d6c PS |
571 | spin_lock_irqsave(&st_gdata->lock, flags); |
572 | ||
53618cc1 PS |
573 | clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); |
574 | st_recv = st_int_recv; | |
575 | ||
576 | /* this is where all pending registration | |
577 | * are signalled to be complete by calling callback functions | |
578 | */ | |
579 | if ((st_gdata->protos_registered != ST_EMPTY) && | |
580 | (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { | |
e6d9e64e | 581 | pr_debug(" call reg complete callback "); |
320920cb | 582 | st_reg_complete(st_gdata, 0); |
53618cc1 PS |
583 | } |
584 | clear_bit(ST_REG_PENDING, &st_gdata->st_state); | |
585 | ||
586 | /* check for already registered once more, | |
587 | * since the above check is old | |
588 | */ | |
764b0c4b | 589 | if (st_gdata->is_registered[new_proto->chnl_id] == true) { |
53618cc1 | 590 | pr_err(" proto %d already registered ", |
5c88b021 | 591 | new_proto->chnl_id); |
bfb88d6c | 592 | spin_unlock_irqrestore(&st_gdata->lock, flags); |
320920cb | 593 | return -EALREADY; |
53618cc1 PS |
594 | } |
595 | ||
5c88b021 | 596 | add_channel_to_table(st_gdata, new_proto); |
36e574fe | 597 | st_gdata->protos_registered++; |
53618cc1 PS |
598 | new_proto->write = st_write; |
599 | spin_unlock_irqrestore(&st_gdata->lock, flags); | |
600 | return err; | |
601 | } | |
602 | /* if fw is already downloaded & new stack registers protocol */ | |
603 | else { | |
5c88b021 | 604 | add_channel_to_table(st_gdata, new_proto); |
36e574fe | 605 | st_gdata->protos_registered++; |
53618cc1 PS |
606 | new_proto->write = st_write; |
607 | ||
608 | /* lock already held before entering else */ | |
609 | spin_unlock_irqrestore(&st_gdata->lock, flags); | |
610 | return err; | |
611 | } | |
5c88b021 | 612 | pr_debug("done %s(%d) ", __func__, new_proto->chnl_id); |
53618cc1 PS |
613 | } |
614 | EXPORT_SYMBOL_GPL(st_register); | |
615 | ||
616 | /* to unregister a protocol - | |
617 | * to be called from protocol stack driver | |
618 | */ | |
5c88b021 | 619 | long st_unregister(struct st_proto_s *proto) |
53618cc1 | 620 | { |
320920cb | 621 | long err = 0; |
53618cc1 PS |
622 | unsigned long flags = 0; |
623 | struct st_data_s *st_gdata; | |
624 | ||
5c88b021 | 625 | pr_debug("%s: %d ", __func__, proto->chnl_id); |
53618cc1 | 626 | |
dbd3a870 | 627 | st_kim_ref(&st_gdata, 0); |
7316a9f2 | 628 | if (!st_gdata || proto->chnl_id >= ST_MAX_CHANNELS) { |
5c88b021 | 629 | pr_err(" chnl_id %d not supported", proto->chnl_id); |
320920cb | 630 | return -EPROTONOSUPPORT; |
53618cc1 PS |
631 | } |
632 | ||
633 | spin_lock_irqsave(&st_gdata->lock, flags); | |
634 | ||
bfb88d6c | 635 | if (st_gdata->is_registered[proto->chnl_id] == false) { |
5c88b021 | 636 | pr_err(" chnl_id %d not registered", proto->chnl_id); |
53618cc1 | 637 | spin_unlock_irqrestore(&st_gdata->lock, flags); |
320920cb | 638 | return -EPROTONOSUPPORT; |
53618cc1 PS |
639 | } |
640 | ||
641 | st_gdata->protos_registered--; | |
5c88b021 | 642 | remove_channel_from_table(st_gdata, proto); |
53618cc1 PS |
643 | spin_unlock_irqrestore(&st_gdata->lock, flags); |
644 | ||
bfb88d6c PS |
645 | /* paranoid check */ |
646 | if (st_gdata->protos_registered < ST_EMPTY) | |
647 | st_gdata->protos_registered = ST_EMPTY; | |
648 | ||
53618cc1 PS |
649 | if ((st_gdata->protos_registered == ST_EMPTY) && |
650 | (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) { | |
5c88b021 | 651 | pr_info(" all chnl_ids unregistered "); |
53618cc1 PS |
652 | |
653 | /* stop traffic on tty */ | |
654 | if (st_gdata->tty) { | |
655 | tty_ldisc_flush(st_gdata->tty); | |
656 | stop_tty(st_gdata->tty); | |
657 | } | |
658 | ||
5c88b021 | 659 | /* all chnl_ids now unregistered */ |
38d9df49 | 660 | st_kim_stop(st_gdata->kim_data); |
53618cc1 PS |
661 | /* disable ST LL */ |
662 | st_ll_disable(st_gdata); | |
663 | } | |
664 | return err; | |
665 | } | |
666 | ||
667 | /* | |
668 | * called in protocol stack drivers | |
669 | * via the write function pointer | |
670 | */ | |
671 | long st_write(struct sk_buff *skb) | |
672 | { | |
673 | struct st_data_s *st_gdata; | |
53618cc1 PS |
674 | long len; |
675 | ||
dbd3a870 | 676 | st_kim_ref(&st_gdata, 0); |
53618cc1 PS |
677 | if (unlikely(skb == NULL || st_gdata == NULL |
678 | || st_gdata->tty == NULL)) { | |
679 | pr_err("data/tty unavailable to perform write"); | |
70442664 | 680 | return -EINVAL; |
53618cc1 | 681 | } |
c1605f2e | 682 | |
e6d9e64e | 683 | pr_debug("%d to be written", skb->len); |
53618cc1 PS |
684 | len = skb->len; |
685 | ||
686 | /* st_ll to decide where to enqueue the skb */ | |
687 | st_int_enqueue(st_gdata, skb); | |
688 | /* wake up */ | |
689 | st_tx_wakeup(st_gdata); | |
690 | ||
691 | /* return number of bytes written */ | |
692 | return len; | |
693 | } | |
694 | ||
695 | /* for protocols making use of shared transport */ | |
696 | EXPORT_SYMBOL_GPL(st_unregister); | |
697 | ||
698 | /********************************************************************/ | |
699 | /* | |
700 | * functions called from TTY layer | |
701 | */ | |
702 | static int st_tty_open(struct tty_struct *tty) | |
703 | { | |
320920cb | 704 | int err = 0; |
53618cc1 PS |
705 | struct st_data_s *st_gdata; |
706 | pr_info("%s ", __func__); | |
707 | ||
dbd3a870 | 708 | st_kim_ref(&st_gdata, 0); |
53618cc1 PS |
709 | st_gdata->tty = tty; |
710 | tty->disc_data = st_gdata; | |
711 | ||
712 | /* don't do an wakeup for now */ | |
713 | clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); | |
714 | ||
715 | /* mem already allocated | |
716 | */ | |
717 | tty->receive_room = 65536; | |
718 | /* Flush any pending characters in the driver and discipline. */ | |
719 | tty_ldisc_flush(tty); | |
720 | tty_driver_flush_buffer(tty); | |
721 | /* | |
722 | * signal to UIM via KIM that - | |
723 | * installation of N_TI_WL ldisc is complete | |
724 | */ | |
38d9df49 | 725 | st_kim_complete(st_gdata->kim_data); |
e6d9e64e | 726 | pr_debug("done %s", __func__); |
53618cc1 PS |
727 | return err; |
728 | } | |
729 | ||
730 | static void st_tty_close(struct tty_struct *tty) | |
731 | { | |
5c88b021 | 732 | unsigned char i = ST_MAX_CHANNELS; |
53618cc1 PS |
733 | unsigned long flags = 0; |
734 | struct st_data_s *st_gdata = tty->disc_data; | |
735 | ||
736 | pr_info("%s ", __func__); | |
737 | ||
738 | /* TODO: | |
739 | * if a protocol has been registered & line discipline | |
740 | * un-installed for some reason - what should be done ? | |
741 | */ | |
742 | spin_lock_irqsave(&st_gdata->lock, flags); | |
5c88b021 | 743 | for (i = ST_BT; i < ST_MAX_CHANNELS; i++) { |
5926cef2 | 744 | if (st_gdata->is_registered[i] == true) |
53618cc1 PS |
745 | pr_err("%d not un-registered", i); |
746 | st_gdata->list[i] = NULL; | |
651d62a8 | 747 | st_gdata->is_registered[i] = false; |
53618cc1 | 748 | } |
bb8f3c06 | 749 | st_gdata->protos_registered = 0; |
53618cc1 PS |
750 | spin_unlock_irqrestore(&st_gdata->lock, flags); |
751 | /* | |
752 | * signal to UIM via KIM that - | |
753 | * N_TI_WL ldisc is un-installed | |
754 | */ | |
38d9df49 | 755 | st_kim_complete(st_gdata->kim_data); |
53618cc1 PS |
756 | st_gdata->tty = NULL; |
757 | /* Flush any pending characters in the driver and discipline. */ | |
758 | tty_ldisc_flush(tty); | |
759 | tty_driver_flush_buffer(tty); | |
760 | ||
761 | spin_lock_irqsave(&st_gdata->lock, flags); | |
762 | /* empty out txq and tx_waitq */ | |
763 | skb_queue_purge(&st_gdata->txq); | |
764 | skb_queue_purge(&st_gdata->tx_waitq); | |
765 | /* reset the TTY Rx states of ST */ | |
766 | st_gdata->rx_count = 0; | |
767 | st_gdata->rx_state = ST_W4_PACKET_TYPE; | |
768 | kfree_skb(st_gdata->rx_skb); | |
769 | st_gdata->rx_skb = NULL; | |
770 | spin_unlock_irqrestore(&st_gdata->lock, flags); | |
771 | ||
e6d9e64e | 772 | pr_debug("%s: done ", __func__); |
53618cc1 PS |
773 | } |
774 | ||
55db4c64 LT |
775 | static void st_tty_receive(struct tty_struct *tty, const unsigned char *data, |
776 | char *tty_flags, int count) | |
53618cc1 | 777 | { |
53618cc1 | 778 | #ifdef VERBOSE |
e6d9e64e PS |
779 | print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE, |
780 | 16, 1, data, count, 0); | |
53618cc1 PS |
781 | #endif |
782 | ||
783 | /* | |
784 | * if fw download is in progress then route incoming data | |
785 | * to KIM for validation | |
786 | */ | |
787 | st_recv(tty->disc_data, data, count); | |
e6d9e64e | 788 | pr_debug("done %s", __func__); |
53618cc1 PS |
789 | } |
790 | ||
791 | /* wake-up function called in from the TTY layer | |
792 | * inside the internal wakeup function will be called | |
793 | */ | |
794 | static void st_tty_wakeup(struct tty_struct *tty) | |
795 | { | |
796 | struct st_data_s *st_gdata = tty->disc_data; | |
e6d9e64e | 797 | pr_debug("%s ", __func__); |
53618cc1 PS |
798 | /* don't do an wakeup for now */ |
799 | clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); | |
800 | ||
801 | /* call our internal wakeup */ | |
802 | st_tx_wakeup((void *)st_gdata); | |
803 | } | |
804 | ||
805 | static void st_tty_flush_buffer(struct tty_struct *tty) | |
806 | { | |
807 | struct st_data_s *st_gdata = tty->disc_data; | |
e6d9e64e | 808 | pr_debug("%s ", __func__); |
53618cc1 PS |
809 | |
810 | kfree_skb(st_gdata->tx_skb); | |
811 | st_gdata->tx_skb = NULL; | |
812 | ||
813 | tty->ops->flush_buffer(tty); | |
814 | return; | |
815 | } | |
816 | ||
73f12e8d PS |
817 | static struct tty_ldisc_ops st_ldisc_ops = { |
818 | .magic = TTY_LDISC_MAGIC, | |
819 | .name = "n_st", | |
820 | .open = st_tty_open, | |
821 | .close = st_tty_close, | |
822 | .receive_buf = st_tty_receive, | |
823 | .write_wakeup = st_tty_wakeup, | |
824 | .flush_buffer = st_tty_flush_buffer, | |
825 | .owner = THIS_MODULE | |
826 | }; | |
827 | ||
53618cc1 PS |
828 | /********************************************************************/ |
829 | int st_core_init(struct st_data_s **core_data) | |
830 | { | |
831 | struct st_data_s *st_gdata; | |
832 | long err; | |
53618cc1 | 833 | |
73f12e8d | 834 | err = tty_register_ldisc(N_TI_WL, &st_ldisc_ops); |
53618cc1 PS |
835 | if (err) { |
836 | pr_err("error registering %d line discipline %ld", | |
837 | N_TI_WL, err); | |
53618cc1 PS |
838 | return err; |
839 | } | |
e6d9e64e | 840 | pr_debug("registered n_shared line discipline"); |
53618cc1 PS |
841 | |
842 | st_gdata = kzalloc(sizeof(struct st_data_s), GFP_KERNEL); | |
843 | if (!st_gdata) { | |
844 | pr_err("memory allocation failed"); | |
845 | err = tty_unregister_ldisc(N_TI_WL); | |
846 | if (err) | |
847 | pr_err("unable to un-register ldisc %ld", err); | |
53618cc1 PS |
848 | err = -ENOMEM; |
849 | return err; | |
850 | } | |
851 | ||
852 | /* Initialize ST TxQ and Tx waitQ queue head. All BT/FM/GPS module skb's | |
853 | * will be pushed in this queue for actual transmission. | |
854 | */ | |
855 | skb_queue_head_init(&st_gdata->txq); | |
856 | skb_queue_head_init(&st_gdata->tx_waitq); | |
857 | ||
858 | /* Locking used in st_int_enqueue() to avoid multiple execution */ | |
859 | spin_lock_init(&st_gdata->lock); | |
860 | ||
53618cc1 PS |
861 | err = st_ll_init(st_gdata); |
862 | if (err) { | |
863 | pr_err("error during st_ll initialization(%ld)", err); | |
864 | kfree(st_gdata); | |
865 | err = tty_unregister_ldisc(N_TI_WL); | |
866 | if (err) | |
867 | pr_err("unable to un-register ldisc"); | |
70442664 | 868 | return err; |
53618cc1 PS |
869 | } |
870 | *core_data = st_gdata; | |
871 | return 0; | |
872 | } | |
873 | ||
874 | void st_core_exit(struct st_data_s *st_gdata) | |
875 | { | |
876 | long err; | |
877 | /* internal module cleanup */ | |
878 | err = st_ll_deinit(st_gdata); | |
879 | if (err) | |
880 | pr_err("error during deinit of ST LL %ld", err); | |
73f12e8d | 881 | |
53618cc1 PS |
882 | if (st_gdata != NULL) { |
883 | /* Free ST Tx Qs and skbs */ | |
884 | skb_queue_purge(&st_gdata->txq); | |
885 | skb_queue_purge(&st_gdata->tx_waitq); | |
886 | kfree_skb(st_gdata->rx_skb); | |
887 | kfree_skb(st_gdata->tx_skb); | |
888 | /* TTY ldisc cleanup */ | |
889 | err = tty_unregister_ldisc(N_TI_WL); | |
890 | if (err) | |
891 | pr_err("unable to un-register ldisc %ld", err); | |
53618cc1 PS |
892 | /* free the global data pointer */ |
893 | kfree(st_gdata); | |
894 | } | |
895 | } | |
896 | ||
897 |