blob: f9aad06d1ae51c43029ac0cbaabc23c9a94e2145 [file] [log] [blame]
Pavan Savoy53618cc2010-04-08 13:16:53 -05001/*
2 * Shared Transport Line discipline driver Core
3 * This hooks up ST KIM driver and ST LL driver
Pavan Savoya0cc2f32010-10-06 12:18:14 -04004 * Copyright (C) 2009-2010 Texas Instruments
5 * Author: Pavan Savoy <pavan_savoy@ti.com>
Pavan Savoy53618cc2010-04-08 13:16:53 -05006 *
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
28/* understand BT, FM and GPS for now */
29#include <net/bluetooth/bluetooth.h>
30#include <net/bluetooth/hci_core.h>
31#include <net/bluetooth/hci.h>
Pavan Savoye5558672010-09-30 16:13:30 -040032#include <linux/ti_wilink_st.h>
Pavan Savoy53618cc2010-04-08 13:16:53 -050033
Pavan Savoy53618cc2010-04-08 13:16:53 -050034/* function pointer pointing to either,
35 * st_kim_recv during registration to receive fw download responses
36 * st_int_recv after registration to receive proto stack responses
37 */
38void (*st_recv) (void*, const unsigned char*, long);
39
40/********************************************************************/
41#if 0
42/* internal misc functions */
43bool is_protocol_list_empty(void)
44{
45 unsigned char i = 0;
Pavan Savoye6d9e642010-07-22 05:32:05 -050046 pr_debug(" %s ", __func__);
Pavan Savoy53618cc2010-04-08 13:16:53 -050047 for (i = 0; i < ST_MAX; i++) {
48 if (st_gdata->list[i] != NULL)
49 return ST_NOTEMPTY;
50 /* not empty */
51 }
52 /* list empty */
53 return ST_EMPTY;
54}
55#endif
Pavan Savoy36b5aee2010-07-22 05:32:06 -050056
Pavan Savoy53618cc2010-04-08 13:16:53 -050057/* can be called in from
58 * -- KIM (during fw download)
59 * -- ST Core (during st_write)
60 *
61 * This is the internal write function - a wrapper
62 * to tty->ops->write
63 */
64int st_int_write(struct st_data_s *st_gdata,
65 const unsigned char *data, int count)
66{
Pavan Savoy53618cc2010-04-08 13:16:53 -050067 struct tty_struct *tty;
68 if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) {
69 pr_err("tty unavailable to perform write");
Pavan Savoy320920c2010-07-14 08:21:12 -050070 return -1;
Pavan Savoy53618cc2010-04-08 13:16:53 -050071 }
72 tty = st_gdata->tty;
73#ifdef VERBOSE
Pavan Savoye6d9e642010-07-22 05:32:05 -050074 print_hex_dump(KERN_DEBUG, "<out<", DUMP_PREFIX_NONE,
75 16, 1, data, count, 0);
Pavan Savoy53618cc2010-04-08 13:16:53 -050076#endif
77 return tty->ops->write(tty, data, count);
78
79}
80
81/*
82 * push the skb received to relevant
83 * protocol stacks
84 */
85void st_send_frame(enum proto_type protoid, struct st_data_s *st_gdata)
86{
87 pr_info(" %s(prot:%d) ", __func__, protoid);
88
89 if (unlikely
90 (st_gdata == NULL || st_gdata->rx_skb == NULL
91 || st_gdata->list[protoid] == NULL)) {
92 pr_err("protocol %d not registered, no data to send?",
93 protoid);
94 kfree_skb(st_gdata->rx_skb);
95 return;
96 }
97 /* this cannot fail
98 * this shouldn't take long
99 * - should be just skb_queue_tail for the
100 * protocol stack driver
101 */
102 if (likely(st_gdata->list[protoid]->recv != NULL)) {
Pavan Savoybb8f3c02010-07-22 05:32:07 -0500103 if (unlikely
104 (st_gdata->list[protoid]->recv
105 (st_gdata->list[protoid]->priv_data, st_gdata->rx_skb)
Pavan Savoy320920c2010-07-14 08:21:12 -0500106 != 0)) {
Pavan Savoy53618cc2010-04-08 13:16:53 -0500107 pr_err(" proto stack %d's ->recv failed", protoid);
108 kfree_skb(st_gdata->rx_skb);
109 return;
110 }
111 } else {
112 pr_err(" proto stack %d's ->recv null", protoid);
113 kfree_skb(st_gdata->rx_skb);
114 }
Pavan Savoy53618cc2010-04-08 13:16:53 -0500115 return;
116}
117
Pavan Savoy36b5aee2010-07-22 05:32:06 -0500118/**
119 * st_reg_complete -
Pavan Savoy53618cc2010-04-08 13:16:53 -0500120 * to call registration complete callbacks
121 * of all protocol stack drivers
122 */
123void st_reg_complete(struct st_data_s *st_gdata, char err)
124{
125 unsigned char i = 0;
126 pr_info(" %s ", __func__);
127 for (i = 0; i < ST_MAX; i++) {
128 if (likely(st_gdata != NULL && st_gdata->list[i] != NULL &&
129 st_gdata->list[i]->reg_complete_cb != NULL))
Pavan Savoybb8f3c02010-07-22 05:32:07 -0500130 st_gdata->list[i]->reg_complete_cb
131 (st_gdata->list[i]->priv_data, err);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500132 }
133}
134
135static inline int st_check_data_len(struct st_data_s *st_gdata,
136 int protoid, int len)
137{
Pavan Savoy73f12e82010-10-12 16:27:38 -0400138 int room = skb_tailroom(st_gdata->rx_skb);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500139
Pavan Savoye6d9e642010-07-22 05:32:05 -0500140 pr_debug("len %d room %d", len, room);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500141
142 if (!len) {
143 /* Received packet has only packet header and
144 * has zero length payload. So, ask ST CORE to
145 * forward the packet to protocol driver (BT/FM/GPS)
146 */
147 st_send_frame(protoid, st_gdata);
148
149 } else if (len > room) {
150 /* Received packet's payload length is larger.
151 * We can't accommodate it in created skb.
152 */
153 pr_err("Data length is too large len %d room %d", len,
154 room);
155 kfree_skb(st_gdata->rx_skb);
156 } else {
157 /* Packet header has non-zero payload length and
158 * we have enough space in created skb. Lets read
159 * payload data */
160 st_gdata->rx_state = ST_BT_W4_DATA;
161 st_gdata->rx_count = len;
162 return len;
163 }
164
165 /* Change ST state to continue to process next
166 * packet */
167 st_gdata->rx_state = ST_W4_PACKET_TYPE;
168 st_gdata->rx_skb = NULL;
169 st_gdata->rx_count = 0;
170
171 return 0;
172}
173
Pavan Savoy36b5aee2010-07-22 05:32:06 -0500174/**
175 * st_wakeup_ack - internal function for action when wake-up ack
176 * received
Pavan Savoy53618cc2010-04-08 13:16:53 -0500177 */
178static inline void st_wakeup_ack(struct st_data_s *st_gdata,
179 unsigned char cmd)
180{
Pavan Savoy73f12e82010-10-12 16:27:38 -0400181 struct sk_buff *waiting_skb;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500182 unsigned long flags = 0;
183
184 spin_lock_irqsave(&st_gdata->lock, flags);
185 /* de-Q from waitQ and Q in txQ now that the
186 * chip is awake
187 */
188 while ((waiting_skb = skb_dequeue(&st_gdata->tx_waitq)))
189 skb_queue_tail(&st_gdata->txq, waiting_skb);
190
191 /* state forwarded to ST LL */
192 st_ll_sleep_state(st_gdata, (unsigned long)cmd);
193 spin_unlock_irqrestore(&st_gdata->lock, flags);
194
195 /* wake up to send the recently copied skbs from waitQ */
196 st_tx_wakeup(st_gdata);
197}
198
Pavan Savoy36b5aee2010-07-22 05:32:06 -0500199/**
200 * st_int_recv - ST's internal receive function.
201 * Decodes received RAW data and forwards to corresponding
202 * client drivers (Bluetooth,FM,GPS..etc).
203 * This can receive various types of packets,
204 * HCI-Events, ACL, SCO, 4 types of HCI-LL PM packets
205 * CH-8 packets from FM, CH-9 packets from GPS cores.
Pavan Savoy53618cc2010-04-08 13:16:53 -0500206 */
207void st_int_recv(void *disc_data,
208 const unsigned char *data, long count)
209{
Pavan Savoy73f12e82010-10-12 16:27:38 -0400210 char *ptr;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500211 struct hci_event_hdr *eh;
212 struct hci_acl_hdr *ah;
213 struct hci_sco_hdr *sh;
214 struct fm_event_hdr *fm;
215 struct gps_event_hdr *gps;
Pavan Savoy73f12e82010-10-12 16:27:38 -0400216 int len = 0, type = 0, dlen = 0;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500217 static enum proto_type protoid = ST_MAX;
218 struct st_data_s *st_gdata = (struct st_data_s *)disc_data;
219
220 ptr = (char *)data;
221 /* tty_receive sent null ? */
222 if (unlikely(ptr == NULL) || (st_gdata == NULL)) {
223 pr_err(" received null from TTY ");
224 return;
225 }
226
227 pr_info("count %ld rx_state %ld"
228 "rx_count %ld", count, st_gdata->rx_state,
229 st_gdata->rx_count);
230
231 /* Decode received bytes here */
232 while (count) {
233 if (st_gdata->rx_count) {
234 len = min_t(unsigned int, st_gdata->rx_count, count);
235 memcpy(skb_put(st_gdata->rx_skb, len), ptr, len);
236 st_gdata->rx_count -= len;
237 count -= len;
238 ptr += len;
239
240 if (st_gdata->rx_count)
241 continue;
242
243 /* Check ST RX state machine , where are we? */
244 switch (st_gdata->rx_state) {
245
246 /* Waiting for complete packet ? */
247 case ST_BT_W4_DATA:
Pavan Savoye6d9e642010-07-22 05:32:05 -0500248 pr_debug("Complete pkt received");
Pavan Savoy53618cc2010-04-08 13:16:53 -0500249
250 /* Ask ST CORE to forward
251 * the packet to protocol driver */
252 st_send_frame(protoid, st_gdata);
253
254 st_gdata->rx_state = ST_W4_PACKET_TYPE;
255 st_gdata->rx_skb = NULL;
256 protoid = ST_MAX; /* is this required ? */
257 continue;
258
259 /* Waiting for Bluetooth event header ? */
260 case ST_BT_W4_EVENT_HDR:
261 eh = (struct hci_event_hdr *)st_gdata->rx_skb->
262 data;
263
Pavan Savoye6d9e642010-07-22 05:32:05 -0500264 pr_debug("Event header: evt 0x%2.2x"
Pavan Savoy53618cc2010-04-08 13:16:53 -0500265 "plen %d", eh->evt, eh->plen);
266
267 st_check_data_len(st_gdata, protoid, eh->plen);
268 continue;
269
270 /* Waiting for Bluetooth acl header ? */
271 case ST_BT_W4_ACL_HDR:
272 ah = (struct hci_acl_hdr *)st_gdata->rx_skb->
273 data;
274 dlen = __le16_to_cpu(ah->dlen);
275
276 pr_info("ACL header: dlen %d", dlen);
277
278 st_check_data_len(st_gdata, protoid, dlen);
279 continue;
280
281 /* Waiting for Bluetooth sco header ? */
282 case ST_BT_W4_SCO_HDR:
283 sh = (struct hci_sco_hdr *)st_gdata->rx_skb->
284 data;
285
286 pr_info("SCO header: dlen %d", sh->dlen);
287
288 st_check_data_len(st_gdata, protoid, sh->dlen);
289 continue;
290 case ST_FM_W4_EVENT_HDR:
291 fm = (struct fm_event_hdr *)st_gdata->rx_skb->
292 data;
293 pr_info("FM Header: ");
294 st_check_data_len(st_gdata, ST_FM, fm->plen);
295 continue;
296 /* TODO : Add GPS packet machine logic here */
297 case ST_GPS_W4_EVENT_HDR:
298 /* [0x09 pkt hdr][R/W byte][2 byte len] */
299 gps = (struct gps_event_hdr *)st_gdata->rx_skb->
300 data;
301 pr_info("GPS Header: ");
302 st_check_data_len(st_gdata, ST_GPS, gps->plen);
303 continue;
304 } /* end of switch rx_state */
305 }
306
307 /* end of if rx_count */
308 /* Check first byte of packet and identify module
309 * owner (BT/FM/GPS) */
310 switch (*ptr) {
311
312 /* Bluetooth event packet? */
313 case HCI_EVENT_PKT:
314 pr_info("Event packet");
315 st_gdata->rx_state = ST_BT_W4_EVENT_HDR;
316 st_gdata->rx_count = HCI_EVENT_HDR_SIZE;
317 type = HCI_EVENT_PKT;
318 protoid = ST_BT;
319 break;
320
321 /* Bluetooth acl packet? */
322 case HCI_ACLDATA_PKT:
323 pr_info("ACL packet");
324 st_gdata->rx_state = ST_BT_W4_ACL_HDR;
325 st_gdata->rx_count = HCI_ACL_HDR_SIZE;
326 type = HCI_ACLDATA_PKT;
327 protoid = ST_BT;
328 break;
329
330 /* Bluetooth sco packet? */
331 case HCI_SCODATA_PKT:
332 pr_info("SCO packet");
333 st_gdata->rx_state = ST_BT_W4_SCO_HDR;
334 st_gdata->rx_count = HCI_SCO_HDR_SIZE;
335 type = HCI_SCODATA_PKT;
336 protoid = ST_BT;
337 break;
338
339 /* Channel 8(FM) packet? */
340 case ST_FM_CH8_PKT:
341 pr_info("FM CH8 packet");
342 type = ST_FM_CH8_PKT;
343 st_gdata->rx_state = ST_FM_W4_EVENT_HDR;
344 st_gdata->rx_count = FM_EVENT_HDR_SIZE;
345 protoid = ST_FM;
346 break;
347
348 /* Channel 9(GPS) packet? */
349 case 0x9: /*ST_LL_GPS_CH9_PKT */
350 pr_info("GPS CH9 packet");
351 type = 0x9; /* ST_LL_GPS_CH9_PKT; */
352 protoid = ST_GPS;
353 st_gdata->rx_state = ST_GPS_W4_EVENT_HDR;
354 st_gdata->rx_count = 3; /* GPS_EVENT_HDR_SIZE -1*/
355 break;
356 case LL_SLEEP_IND:
357 case LL_SLEEP_ACK:
358 case LL_WAKE_UP_IND:
359 pr_info("PM packet");
360 /* this takes appropriate action based on
361 * sleep state received --
362 */
363 st_ll_sleep_state(st_gdata, *ptr);
364 ptr++;
365 count--;
366 continue;
367 case LL_WAKE_UP_ACK:
368 pr_info("PM packet");
369 /* wake up ack received */
370 st_wakeup_ack(st_gdata, *ptr);
371 ptr++;
372 count--;
373 continue;
374 /* Unknow packet? */
375 default:
376 pr_err("Unknown packet type %2.2x", (__u8) *ptr);
377 ptr++;
378 count--;
379 continue;
380 };
381 ptr++;
382 count--;
383
384 switch (protoid) {
385 case ST_BT:
386 /* Allocate new packet to hold received data */
387 st_gdata->rx_skb =
388 bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
389 if (!st_gdata->rx_skb) {
390 pr_err("Can't allocate mem for new packet");
391 st_gdata->rx_state = ST_W4_PACKET_TYPE;
392 st_gdata->rx_count = 0;
393 return;
394 }
395 bt_cb(st_gdata->rx_skb)->pkt_type = type;
396 break;
397 case ST_FM: /* for FM */
398 st_gdata->rx_skb =
399 alloc_skb(FM_MAX_FRAME_SIZE, GFP_ATOMIC);
400 if (!st_gdata->rx_skb) {
401 pr_err("Can't allocate mem for new packet");
402 st_gdata->rx_state = ST_W4_PACKET_TYPE;
403 st_gdata->rx_count = 0;
404 return;
405 }
406 /* place holder 0x08 */
407 skb_reserve(st_gdata->rx_skb, 1);
408 st_gdata->rx_skb->cb[0] = ST_FM_CH8_PKT;
409 break;
410 case ST_GPS:
411 /* for GPS */
412 st_gdata->rx_skb =
413 alloc_skb(100 /*GPS_MAX_FRAME_SIZE */ , GFP_ATOMIC);
414 if (!st_gdata->rx_skb) {
415 pr_err("Can't allocate mem for new packet");
416 st_gdata->rx_state = ST_W4_PACKET_TYPE;
417 st_gdata->rx_count = 0;
418 return;
419 }
420 /* place holder 0x09 */
421 skb_reserve(st_gdata->rx_skb, 1);
422 st_gdata->rx_skb->cb[0] = 0x09; /*ST_GPS_CH9_PKT; */
423 break;
424 case ST_MAX:
425 break;
426 }
427 }
Pavan Savoye6d9e642010-07-22 05:32:05 -0500428 pr_debug("done %s", __func__);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500429 return;
430}
431
Pavan Savoy36b5aee2010-07-22 05:32:06 -0500432/**
433 * st_int_dequeue - internal de-Q function.
434 * If the previous data set was not written
435 * completely, return that skb which has the pending data.
436 * In normal cases, return top of txq.
Pavan Savoy53618cc2010-04-08 13:16:53 -0500437 */
438struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata)
439{
440 struct sk_buff *returning_skb;
441
Pavan Savoye6d9e642010-07-22 05:32:05 -0500442 pr_debug("%s", __func__);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500443 if (st_gdata->tx_skb != NULL) {
444 returning_skb = st_gdata->tx_skb;
445 st_gdata->tx_skb = NULL;
446 return returning_skb;
447 }
Pavan Savoy53618cc2010-04-08 13:16:53 -0500448 return skb_dequeue(&st_gdata->txq);
449}
450
Pavan Savoy36b5aee2010-07-22 05:32:06 -0500451/**
452 * st_int_enqueue - internal Q-ing function.
453 * Will either Q the skb to txq or the tx_waitq
454 * depending on the ST LL state.
455 * If the chip is asleep, then Q it onto waitq and
456 * wakeup the chip.
457 * txq and waitq needs protection since the other contexts
458 * may be sending data, waking up chip.
Pavan Savoy53618cc2010-04-08 13:16:53 -0500459 */
460void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb)
461{
462 unsigned long flags = 0;
463
Pavan Savoye6d9e642010-07-22 05:32:05 -0500464 pr_debug("%s", __func__);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500465 spin_lock_irqsave(&st_gdata->lock, flags);
466
467 switch (st_ll_getstate(st_gdata)) {
468 case ST_LL_AWAKE:
469 pr_info("ST LL is AWAKE, sending normally");
470 skb_queue_tail(&st_gdata->txq, skb);
471 break;
472 case ST_LL_ASLEEP_TO_AWAKE:
473 skb_queue_tail(&st_gdata->tx_waitq, skb);
474 break;
Pavan Savoy36b5aee2010-07-22 05:32:06 -0500475 case ST_LL_AWAKE_TO_ASLEEP:
Pavan Savoy53618cc2010-04-08 13:16:53 -0500476 pr_err("ST LL is illegal state(%ld),"
477 "purging received skb.", st_ll_getstate(st_gdata));
478 kfree_skb(skb);
479 break;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500480 case ST_LL_ASLEEP:
Pavan Savoy53618cc2010-04-08 13:16:53 -0500481 skb_queue_tail(&st_gdata->tx_waitq, skb);
482 st_ll_wakeup(st_gdata);
483 break;
484 default:
485 pr_err("ST LL is illegal state(%ld),"
486 "purging received skb.", st_ll_getstate(st_gdata));
487 kfree_skb(skb);
488 break;
489 }
Pavan Savoy36b5aee2010-07-22 05:32:06 -0500490
Pavan Savoy53618cc2010-04-08 13:16:53 -0500491 spin_unlock_irqrestore(&st_gdata->lock, flags);
Pavan Savoye6d9e642010-07-22 05:32:05 -0500492 pr_debug("done %s", __func__);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500493 return;
494}
495
496/*
497 * internal wakeup function
498 * called from either
499 * - TTY layer when write's finished
500 * - st_write (in context of the protocol stack)
501 */
502void st_tx_wakeup(struct st_data_s *st_data)
503{
504 struct sk_buff *skb;
505 unsigned long flags; /* for irq save flags */
Pavan Savoye6d9e642010-07-22 05:32:05 -0500506 pr_debug("%s", __func__);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500507 /* check for sending & set flag sending here */
508 if (test_and_set_bit(ST_TX_SENDING, &st_data->tx_state)) {
509 pr_info("ST already sending");
510 /* keep sending */
511 set_bit(ST_TX_WAKEUP, &st_data->tx_state);
512 return;
513 /* TX_WAKEUP will be checked in another
514 * context
515 */
516 }
517 do { /* come back if st_tx_wakeup is set */
518 /* woke-up to write */
519 clear_bit(ST_TX_WAKEUP, &st_data->tx_state);
520 while ((skb = st_int_dequeue(st_data))) {
521 int len;
522 spin_lock_irqsave(&st_data->lock, flags);
523 /* enable wake-up from TTY */
524 set_bit(TTY_DO_WRITE_WAKEUP, &st_data->tty->flags);
525 len = st_int_write(st_data, skb->data, skb->len);
526 skb_pull(skb, len);
527 /* if skb->len = len as expected, skb->len=0 */
528 if (skb->len) {
529 /* would be the next skb to be sent */
530 st_data->tx_skb = skb;
531 spin_unlock_irqrestore(&st_data->lock, flags);
532 break;
533 }
534 kfree_skb(skb);
535 spin_unlock_irqrestore(&st_data->lock, flags);
536 }
537 /* if wake-up is set in another context- restart sending */
538 } while (test_bit(ST_TX_WAKEUP, &st_data->tx_state));
539
540 /* clear flag sending */
541 clear_bit(ST_TX_SENDING, &st_data->tx_state);
542}
543
544/********************************************************************/
545/* functions called from ST KIM
546*/
Pavan Savoyc1afac12010-07-28 02:25:59 -0500547void kim_st_list_protocols(struct st_data_s *st_gdata, void *buf)
Pavan Savoy53618cc2010-04-08 13:16:53 -0500548{
Pavan Savoyc1afac12010-07-28 02:25:59 -0500549 seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n",
Naveen Jain36e574f2010-06-09 07:20:40 -0500550 st_gdata->protos_registered,
551 st_gdata->list[ST_BT] != NULL ? 'R' : 'U',
552 st_gdata->list[ST_FM] != NULL ? 'R' : 'U',
553 st_gdata->list[ST_GPS] != NULL ? 'R' : 'U');
Pavan Savoy53618cc2010-04-08 13:16:53 -0500554}
555
556/********************************************************************/
557/*
558 * functions called from protocol stack drivers
559 * to be EXPORT-ed
560 */
561long st_register(struct st_proto_s *new_proto)
562{
563 struct st_data_s *st_gdata;
Pavan Savoy320920c2010-07-14 08:21:12 -0500564 long err = 0;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500565 unsigned long flags = 0;
566
Pavan Savoydbd3a872010-08-19 14:08:51 -0400567 st_kim_ref(&st_gdata, 0);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500568 pr_info("%s(%d) ", __func__, new_proto->type);
569 if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL
570 || new_proto->reg_complete_cb == NULL) {
571 pr_err("gdata/new_proto/recv or reg_complete_cb not ready");
Pavan Savoy320920c2010-07-14 08:21:12 -0500572 return -1;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500573 }
574
575 if (new_proto->type < ST_BT || new_proto->type >= ST_MAX) {
576 pr_err("protocol %d not supported", new_proto->type);
Pavan Savoy320920c2010-07-14 08:21:12 -0500577 return -EPROTONOSUPPORT;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500578 }
579
580 if (st_gdata->list[new_proto->type] != NULL) {
581 pr_err("protocol %d already registered", new_proto->type);
Pavan Savoy320920c2010-07-14 08:21:12 -0500582 return -EALREADY;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500583 }
584
585 /* can be from process context only */
586 spin_lock_irqsave(&st_gdata->lock, flags);
587
588 if (test_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state)) {
589 pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->type);
590 /* fw download in progress */
591 st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
592
593 st_gdata->list[new_proto->type] = new_proto;
Naveen Jain36e574f2010-06-09 07:20:40 -0500594 st_gdata->protos_registered++;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500595 new_proto->write = st_write;
596
597 set_bit(ST_REG_PENDING, &st_gdata->st_state);
598 spin_unlock_irqrestore(&st_gdata->lock, flags);
Pavan Savoy320920c2010-07-14 08:21:12 -0500599 return -EINPROGRESS;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500600 } else if (st_gdata->protos_registered == ST_EMPTY) {
601 pr_info(" protocol list empty :%d ", new_proto->type);
602 set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
603 st_recv = st_kim_recv;
604
605 /* release lock previously held - re-locked below */
606 spin_unlock_irqrestore(&st_gdata->lock, flags);
607
608 /* enable the ST LL - to set default chip state */
609 st_ll_enable(st_gdata);
610 /* this may take a while to complete
611 * since it involves BT fw download
612 */
Pavan Savoy38d9df42010-07-08 08:55:17 -0500613 err = st_kim_start(st_gdata->kim_data);
Pavan Savoy320920c2010-07-14 08:21:12 -0500614 if (err != 0) {
Pavan Savoy53618cc2010-04-08 13:16:53 -0500615 clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
616 if ((st_gdata->protos_registered != ST_EMPTY) &&
617 (test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
618 pr_err(" KIM failure complete callback ");
Pavan Savoy320920c2010-07-14 08:21:12 -0500619 st_reg_complete(st_gdata, -1);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500620 }
621
Pavan Savoy320920c2010-07-14 08:21:12 -0500622 return -1;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500623 }
624
625 /* the protocol might require other gpios to be toggled
626 */
627 st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
628
629 clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
630 st_recv = st_int_recv;
631
632 /* this is where all pending registration
633 * are signalled to be complete by calling callback functions
634 */
635 if ((st_gdata->protos_registered != ST_EMPTY) &&
636 (test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
Pavan Savoye6d9e642010-07-22 05:32:05 -0500637 pr_debug(" call reg complete callback ");
Pavan Savoy320920c2010-07-14 08:21:12 -0500638 st_reg_complete(st_gdata, 0);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500639 }
640 clear_bit(ST_REG_PENDING, &st_gdata->st_state);
641
642 /* check for already registered once more,
643 * since the above check is old
644 */
645 if (st_gdata->list[new_proto->type] != NULL) {
646 pr_err(" proto %d already registered ",
647 new_proto->type);
Pavan Savoy320920c2010-07-14 08:21:12 -0500648 return -EALREADY;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500649 }
650
651 spin_lock_irqsave(&st_gdata->lock, flags);
652 st_gdata->list[new_proto->type] = new_proto;
Naveen Jain36e574f2010-06-09 07:20:40 -0500653 st_gdata->protos_registered++;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500654 new_proto->write = st_write;
655 spin_unlock_irqrestore(&st_gdata->lock, flags);
656 return err;
657 }
658 /* if fw is already downloaded & new stack registers protocol */
659 else {
660 switch (new_proto->type) {
661 case ST_BT:
662 /* do nothing */
663 break;
664 case ST_FM:
665 case ST_GPS:
666 st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
667 break;
668 case ST_MAX:
669 default:
670 pr_err("%d protocol not supported",
671 new_proto->type);
Dan Carpenter0b6e7222010-08-10 07:36:24 +0200672 spin_unlock_irqrestore(&st_gdata->lock, flags);
673 return -EPROTONOSUPPORT;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500674 }
675 st_gdata->list[new_proto->type] = new_proto;
Naveen Jain36e574f2010-06-09 07:20:40 -0500676 st_gdata->protos_registered++;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500677 new_proto->write = st_write;
678
679 /* lock already held before entering else */
680 spin_unlock_irqrestore(&st_gdata->lock, flags);
681 return err;
682 }
Pavan Savoye6d9e642010-07-22 05:32:05 -0500683 pr_debug("done %s(%d) ", __func__, new_proto->type);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500684}
685EXPORT_SYMBOL_GPL(st_register);
686
687/* to unregister a protocol -
688 * to be called from protocol stack driver
689 */
690long st_unregister(enum proto_type type)
691{
Pavan Savoy320920c2010-07-14 08:21:12 -0500692 long err = 0;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500693 unsigned long flags = 0;
694 struct st_data_s *st_gdata;
695
Pavan Savoye6d9e642010-07-22 05:32:05 -0500696 pr_debug("%s: %d ", __func__, type);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500697
Pavan Savoydbd3a872010-08-19 14:08:51 -0400698 st_kim_ref(&st_gdata, 0);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500699 if (type < ST_BT || type >= ST_MAX) {
700 pr_err(" protocol %d not supported", type);
Pavan Savoy320920c2010-07-14 08:21:12 -0500701 return -EPROTONOSUPPORT;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500702 }
703
704 spin_lock_irqsave(&st_gdata->lock, flags);
705
706 if (st_gdata->list[type] == NULL) {
707 pr_err(" protocol %d not registered", type);
708 spin_unlock_irqrestore(&st_gdata->lock, flags);
Pavan Savoy320920c2010-07-14 08:21:12 -0500709 return -EPROTONOSUPPORT;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500710 }
711
712 st_gdata->protos_registered--;
713 st_gdata->list[type] = NULL;
714
715 /* kim ignores BT in the below function
716 * and handles the rest, BT is toggled
717 * only in kim_start and kim_stop
718 */
719 st_kim_chip_toggle(type, KIM_GPIO_INACTIVE);
720 spin_unlock_irqrestore(&st_gdata->lock, flags);
721
722 if ((st_gdata->protos_registered == ST_EMPTY) &&
723 (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
724 pr_info(" all protocols unregistered ");
725
726 /* stop traffic on tty */
727 if (st_gdata->tty) {
728 tty_ldisc_flush(st_gdata->tty);
729 stop_tty(st_gdata->tty);
730 }
731
732 /* all protocols now unregistered */
Pavan Savoy38d9df42010-07-08 08:55:17 -0500733 st_kim_stop(st_gdata->kim_data);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500734 /* disable ST LL */
735 st_ll_disable(st_gdata);
736 }
737 return err;
738}
739
740/*
741 * called in protocol stack drivers
742 * via the write function pointer
743 */
744long st_write(struct sk_buff *skb)
745{
746 struct st_data_s *st_gdata;
747#ifdef DEBUG
748 enum proto_type protoid = ST_MAX;
749#endif
750 long len;
751
Pavan Savoydbd3a872010-08-19 14:08:51 -0400752 st_kim_ref(&st_gdata, 0);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500753 if (unlikely(skb == NULL || st_gdata == NULL
754 || st_gdata->tty == NULL)) {
755 pr_err("data/tty unavailable to perform write");
Pavan Savoy320920c2010-07-14 08:21:12 -0500756 return -1;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500757 }
758#ifdef DEBUG /* open-up skb to read the 1st byte */
759 switch (skb->data[0]) {
760 case HCI_COMMAND_PKT:
761 case HCI_ACLDATA_PKT:
762 case HCI_SCODATA_PKT:
763 protoid = ST_BT;
764 break;
765 case ST_FM_CH8_PKT:
766 protoid = ST_FM;
767 break;
768 case 0x09:
769 protoid = ST_GPS;
770 break;
771 }
772 if (unlikely(st_gdata->list[protoid] == NULL)) {
773 pr_err(" protocol %d not registered, and writing? ",
774 protoid);
Pavan Savoy320920c2010-07-14 08:21:12 -0500775 return -1;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500776 }
777#endif
Pavan Savoye6d9e642010-07-22 05:32:05 -0500778 pr_debug("%d to be written", skb->len);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500779 len = skb->len;
780
781 /* st_ll to decide where to enqueue the skb */
782 st_int_enqueue(st_gdata, skb);
783 /* wake up */
784 st_tx_wakeup(st_gdata);
785
786 /* return number of bytes written */
787 return len;
788}
789
790/* for protocols making use of shared transport */
791EXPORT_SYMBOL_GPL(st_unregister);
792
793/********************************************************************/
794/*
795 * functions called from TTY layer
796 */
797static int st_tty_open(struct tty_struct *tty)
798{
Pavan Savoy320920c2010-07-14 08:21:12 -0500799 int err = 0;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500800 struct st_data_s *st_gdata;
801 pr_info("%s ", __func__);
802
Pavan Savoydbd3a872010-08-19 14:08:51 -0400803 st_kim_ref(&st_gdata, 0);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500804 st_gdata->tty = tty;
805 tty->disc_data = st_gdata;
806
807 /* don't do an wakeup for now */
808 clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
809
810 /* mem already allocated
811 */
812 tty->receive_room = 65536;
813 /* Flush any pending characters in the driver and discipline. */
814 tty_ldisc_flush(tty);
815 tty_driver_flush_buffer(tty);
816 /*
817 * signal to UIM via KIM that -
818 * installation of N_TI_WL ldisc is complete
819 */
Pavan Savoy38d9df42010-07-08 08:55:17 -0500820 st_kim_complete(st_gdata->kim_data);
Pavan Savoye6d9e642010-07-22 05:32:05 -0500821 pr_debug("done %s", __func__);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500822 return err;
823}
824
825static void st_tty_close(struct tty_struct *tty)
826{
827 unsigned char i = ST_MAX;
828 unsigned long flags = 0;
829 struct st_data_s *st_gdata = tty->disc_data;
830
831 pr_info("%s ", __func__);
832
833 /* TODO:
834 * if a protocol has been registered & line discipline
835 * un-installed for some reason - what should be done ?
836 */
837 spin_lock_irqsave(&st_gdata->lock, flags);
838 for (i = ST_BT; i < ST_MAX; i++) {
839 if (st_gdata->list[i] != NULL)
840 pr_err("%d not un-registered", i);
841 st_gdata->list[i] = NULL;
842 }
Pavan Savoybb8f3c02010-07-22 05:32:07 -0500843 st_gdata->protos_registered = 0;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500844 spin_unlock_irqrestore(&st_gdata->lock, flags);
845 /*
846 * signal to UIM via KIM that -
847 * N_TI_WL ldisc is un-installed
848 */
Pavan Savoy38d9df42010-07-08 08:55:17 -0500849 st_kim_complete(st_gdata->kim_data);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500850 st_gdata->tty = NULL;
851 /* Flush any pending characters in the driver and discipline. */
852 tty_ldisc_flush(tty);
853 tty_driver_flush_buffer(tty);
854
855 spin_lock_irqsave(&st_gdata->lock, flags);
856 /* empty out txq and tx_waitq */
857 skb_queue_purge(&st_gdata->txq);
858 skb_queue_purge(&st_gdata->tx_waitq);
859 /* reset the TTY Rx states of ST */
860 st_gdata->rx_count = 0;
861 st_gdata->rx_state = ST_W4_PACKET_TYPE;
862 kfree_skb(st_gdata->rx_skb);
863 st_gdata->rx_skb = NULL;
864 spin_unlock_irqrestore(&st_gdata->lock, flags);
865
Pavan Savoye6d9e642010-07-22 05:32:05 -0500866 pr_debug("%s: done ", __func__);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500867}
868
869static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
870 char *tty_flags, int count)
871{
872
873#ifdef VERBOSE
Pavan Savoye6d9e642010-07-22 05:32:05 -0500874 print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE,
875 16, 1, data, count, 0);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500876#endif
877
878 /*
879 * if fw download is in progress then route incoming data
880 * to KIM for validation
881 */
882 st_recv(tty->disc_data, data, count);
Pavan Savoye6d9e642010-07-22 05:32:05 -0500883 pr_debug("done %s", __func__);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500884}
885
886/* wake-up function called in from the TTY layer
887 * inside the internal wakeup function will be called
888 */
889static void st_tty_wakeup(struct tty_struct *tty)
890{
891 struct st_data_s *st_gdata = tty->disc_data;
Pavan Savoye6d9e642010-07-22 05:32:05 -0500892 pr_debug("%s ", __func__);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500893 /* don't do an wakeup for now */
894 clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
895
896 /* call our internal wakeup */
897 st_tx_wakeup((void *)st_gdata);
898}
899
900static void st_tty_flush_buffer(struct tty_struct *tty)
901{
902 struct st_data_s *st_gdata = tty->disc_data;
Pavan Savoye6d9e642010-07-22 05:32:05 -0500903 pr_debug("%s ", __func__);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500904
905 kfree_skb(st_gdata->tx_skb);
906 st_gdata->tx_skb = NULL;
907
908 tty->ops->flush_buffer(tty);
909 return;
910}
911
Pavan Savoy73f12e82010-10-12 16:27:38 -0400912static struct tty_ldisc_ops st_ldisc_ops = {
913 .magic = TTY_LDISC_MAGIC,
914 .name = "n_st",
915 .open = st_tty_open,
916 .close = st_tty_close,
917 .receive_buf = st_tty_receive,
918 .write_wakeup = st_tty_wakeup,
919 .flush_buffer = st_tty_flush_buffer,
920 .owner = THIS_MODULE
921};
922
Pavan Savoy53618cc2010-04-08 13:16:53 -0500923/********************************************************************/
924int st_core_init(struct st_data_s **core_data)
925{
926 struct st_data_s *st_gdata;
927 long err;
Pavan Savoy53618cc2010-04-08 13:16:53 -0500928
Pavan Savoy73f12e82010-10-12 16:27:38 -0400929 err = tty_register_ldisc(N_TI_WL, &st_ldisc_ops);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500930 if (err) {
931 pr_err("error registering %d line discipline %ld",
932 N_TI_WL, err);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500933 return err;
934 }
Pavan Savoye6d9e642010-07-22 05:32:05 -0500935 pr_debug("registered n_shared line discipline");
Pavan Savoy53618cc2010-04-08 13:16:53 -0500936
937 st_gdata = kzalloc(sizeof(struct st_data_s), GFP_KERNEL);
938 if (!st_gdata) {
939 pr_err("memory allocation failed");
940 err = tty_unregister_ldisc(N_TI_WL);
941 if (err)
942 pr_err("unable to un-register ldisc %ld", err);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500943 err = -ENOMEM;
944 return err;
945 }
946
947 /* Initialize ST TxQ and Tx waitQ queue head. All BT/FM/GPS module skb's
948 * will be pushed in this queue for actual transmission.
949 */
950 skb_queue_head_init(&st_gdata->txq);
951 skb_queue_head_init(&st_gdata->tx_waitq);
952
953 /* Locking used in st_int_enqueue() to avoid multiple execution */
954 spin_lock_init(&st_gdata->lock);
955
Pavan Savoy53618cc2010-04-08 13:16:53 -0500956 err = st_ll_init(st_gdata);
957 if (err) {
958 pr_err("error during st_ll initialization(%ld)", err);
959 kfree(st_gdata);
960 err = tty_unregister_ldisc(N_TI_WL);
961 if (err)
962 pr_err("unable to un-register ldisc");
Pavan Savoy53618cc2010-04-08 13:16:53 -0500963 return -1;
964 }
965 *core_data = st_gdata;
966 return 0;
967}
968
969void st_core_exit(struct st_data_s *st_gdata)
970{
971 long err;
972 /* internal module cleanup */
973 err = st_ll_deinit(st_gdata);
974 if (err)
975 pr_err("error during deinit of ST LL %ld", err);
Pavan Savoy73f12e82010-10-12 16:27:38 -0400976
Pavan Savoy53618cc2010-04-08 13:16:53 -0500977 if (st_gdata != NULL) {
978 /* Free ST Tx Qs and skbs */
979 skb_queue_purge(&st_gdata->txq);
980 skb_queue_purge(&st_gdata->tx_waitq);
981 kfree_skb(st_gdata->rx_skb);
982 kfree_skb(st_gdata->tx_skb);
983 /* TTY ldisc cleanup */
984 err = tty_unregister_ldisc(N_TI_WL);
985 if (err)
986 pr_err("unable to un-register ldisc %ld", err);
Pavan Savoy53618cc2010-04-08 13:16:53 -0500987 /* free the global data pointer */
988 kfree(st_gdata);
989 }
990}
991
992