Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752785Ab0DMPGx (ORCPT ); Tue, 13 Apr 2010 11:06:53 -0400 Received: from web94913.mail.in2.yahoo.com ([203.104.17.184]:33465 "HELO web94913.mail.in2.yahoo.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1752545Ab0DMPGu convert rfc822-to-8bit (ORCPT ); Tue, 13 Apr 2010 11:06:50 -0400 Message-ID: <306017.12231.qm@web94913.mail.in2.yahoo.com> X-YMail-OSG: Tqb6VMwVM1n5pGmNrDTeH4byPGz5844XuV_lltsU0eeXoB9 zjl7lsf.SLVI.oosSMKYGOUu2JT3HGPsj1fMXesuB78F3u74oQm87lBIh4dk ODoeXv7WrmIL3zEnDbqqRDqrdpMGBcvVPEHnf3tJthzO.i_42NzI2ISmnNwO kwRJoyD6dGJy.wB9zRkcEVJ9TfyDgVjRoF2yphP034RzdtcoFw.Ey8JKs80W VZEXL0oqs5HtQGCVrMz2.i.EPkLG1bV9Mp0BfmMK0tlezg1p3RpnKEmeRw_w u3N_707Q2ZCBPfDNn X-RocketYMMF: pavan_savoy X-Mailer: YahooMailClassic/10.1.8 YahooMailWebService/0.8.100.260964 Date: Tue, 13 Apr 2010 20:36:45 +0530 (IST) From: Pavan Savoy Reply-To: pavan_savoy@ti.com Subject: Re: [PATCH] drivers:staging: sources for ST core To: alan Cc: linux-kernel@vger.kernel.org In-Reply-To: <1270750619-19174-3-git-send-email-pavan_savoy@ti.com> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8BIT Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 41457 Lines: 1756 Alan, --- On Thu, 8/4/10, pavan_savoy@ti.com wrote: > From: pavan_savoy@ti.com > Subject: [PATCH] drivers:staging: sources for ST core > To: gregkh@suse.de, alan@lxorguk.ukuu.org.uk > Cc: linux-kernel@vger.kernel.org, npelly@google.com, pavan_savoy@yahoo.co.in, "Pavan Savoy" > Date: Thursday, 8 April, 2010, 11:46 PM > From: Pavan Savoy > > Texas Instruments BT, FM and GPS combo chips/drivers > make use of a single TTY to communicate with the chip. > This module constitutes the core logic, TTY ldisc driver > and the exported symbols for registering/unregistering of > the protocol drivers such as BT/FM/GPS. > > Signed-off-by: Pavan Savoy > --- > drivers/staging/ti-st/st_core.c | 1062 > +++++++++++++++++++++++++++++++++++++++ > drivers/staging/ti-st/st_core.h |???98 > ++++ > 2 files changed, 1160 insertions(+), 0 deletions(-) > create mode 100644 drivers/staging/ti-st/st_core.c > create mode 100644 drivers/staging/ti-st/st_core.h > > diff --git a/drivers/staging/ti-st/st_core.c > b/drivers/staging/ti-st/st_core.c > new file mode 100644 > index 0000000..4e93694 > --- /dev/null > +++ b/drivers/staging/ti-st/st_core.c > @@ -0,0 +1,1062 @@ > +/* > + *? Shared Transport Line discipline driver Core > + *??? This hooks up ST KIM driver and ST LL > driver > + *? Copyright (C) 2009 Texas Instruments > + * > + *? This program is free software; you can > redistribute it and/or modify > + *? it under the terms of the GNU General Public > License version 2 as > + *? published by the Free Software Foundation. > + * > + *? This program is distributed in the hope that it > will be useful, > + *? but WITHOUT ANY WARRANTY; without even the > implied warranty of > + *? MERCHANTABILITY or FITNESS FOR A PARTICULAR > PURPOSE.? See the > + *? GNU General Public License for more details. > + * > + *? You should have received a copy of the GNU > General Public License > + *? along with this program; if not, write to the > Free Software > + *? Foundation, Inc., 59 Temple Place, Suite 330, > Boston, MA? 02111-1307? USA > + * > + */ > + > +#define pr_fmt(fmt)??? "(stc): " fmt > +#include > +#include > +#include > +#include > + > +/* understand BT, FM and GPS for now */ > +#include > +#include > +#include > +#include "fm.h" > +/* > + * packet formats for fm and gps > + * #include "gps.h" > + */ > +#include "st_core.h" > +#include "st_kim.h" > +#include "st_ll.h" > +#include "st.h" > + > +#ifdef DEBUG > +/* strings to be used for rfkill entries and by > + * ST Core to be used for sysfs debug entry > + */ > +#define PROTO_ENTRY(type, name)??? name > +const unsigned char *protocol_strngs[] = { > +??? PROTO_ENTRY(ST_BT, "Bluetooth"), > +??? PROTO_ENTRY(ST_FM, "FM"), > +??? PROTO_ENTRY(ST_GPS, "GPS"), > +}; > +#endif > +/* function pointer pointing to either, > + * st_kim_recv during registration to receive fw download > responses > + * st_int_recv after registration to receive proto stack > responses > + */ > +void (*st_recv) (void*, const unsigned char*, long); > + > +/********************************************************************/ > +#if 0 > +/* internal misc functions */ > +bool is_protocol_list_empty(void) > +{ > +??? unsigned char i = 0; > +??? pr_info(" %s ", __func__); > +??? for (i = 0; i < ST_MAX; i++) { > +??? ??? if > (st_gdata->list[i] != NULL) > +??? ??? ??? > return ST_NOTEMPTY; > +??? ??? /* not empty */ > +??? } > +??? /* list empty */ > +??? return ST_EMPTY; > +} > +#endif > +/* can be called in from > + * -- KIM (during fw download) > + * -- ST Core (during st_write) > + * > + *? This is the internal write function - a wrapper > + *? to tty->ops->write > + */ > +int st_int_write(struct st_data_s *st_gdata, > +??? const unsigned char *data, int count) > +{ > +#ifdef VERBOSE??? ??? > ??? /* for debug */ > +??? int i; > +#endif > +??? struct tty_struct *tty; > +??? if (unlikely(st_gdata == NULL || > st_gdata->tty == NULL)) { > +??? ??? pr_err("tty > unavailable to perform write"); > +??? ??? return > ST_ERR_FAILURE; > +??? } > +??? tty = st_gdata->tty; > +#ifdef VERBOSE > +??? printk(KERN_ERR "start data..\n"); > +??? for (i = 0; i < count; > i++)??? /* no newlines for each datum */ > +??? ??? printk(" %x", > data[i]); > +??? printk(KERN_ERR "\n ..end data\n"); > +#endif > +??? return tty->ops->write(tty, data, > count); > + > +} > + > +/* > + * push the skb received to relevant > + * protocol stacks > + */ > +void st_send_frame(enum proto_type protoid, struct > st_data_s *st_gdata) > +{ > +??? pr_info(" %s(prot:%d) ", __func__, > protoid); > + > +??? if (unlikely > +??? ? ? (st_gdata == NULL || > st_gdata->rx_skb == NULL > +??? ? ???|| > st_gdata->list[protoid] == NULL)) { > +??? ??? pr_err("protocol %d > not registered, no data to send?", > +??? ??? ??? > ???protoid); > +??? ??? > kfree_skb(st_gdata->rx_skb); > +??? ??? return; > +??? } > +??? /* this cannot fail > +?????* this shouldn't take long > +?????* - should be just > skb_queue_tail for the > +?????*???protocol > stack driver > +?????*/ > +??? if > (likely(st_gdata->list[protoid]->recv != NULL)) { > +??? ??? if > (unlikely(st_gdata->list[protoid]->recv(st_gdata->rx_skb) > +??? ??? ??? > ? ???!= ST_SUCCESS)) { > +??? ??? ??? > pr_err(" proto stack %d's ->recv failed", protoid); > +??? ??? ??? > kfree_skb(st_gdata->rx_skb); > +??? ??? ??? > return; > +??? ??? } > +??? } else { > +??? ??? pr_err(" proto stack > %d's ->recv null", protoid); > +??? ??? > kfree_skb(st_gdata->rx_skb); > +??? } > +??? pr_info(" done %s", __func__); > +??? return; > +} > + > +/* > + * to call registration complete callbacks > + * of all protocol stack drivers > + */ > +void st_reg_complete(struct st_data_s *st_gdata, char > err) > +{ > +??? unsigned char i = 0; > +??? pr_info(" %s ", __func__); > +??? for (i = 0; i < ST_MAX; i++) { > +??? ??? if (likely(st_gdata > != NULL && st_gdata->list[i] != NULL && > +??? ??? ??? > ???st_gdata->list[i]->reg_complete_cb > != NULL)) > +??? ??? ??? > st_gdata->list[i]->reg_complete_cb(err); > +??? } > +} > + > +static inline int st_check_data_len(struct st_data_s > *st_gdata, > +??? int protoid, int len) > +{ > +??? register int room = > skb_tailroom(st_gdata->rx_skb); > + > +??? pr_info("len %d room %d", len, room); > + > +??? if (!len) { > +??? ??? /* Received packet > has only packet header and > +??? ?????* has > zero length payload. So, ask ST CORE to > +??? ?????* forward > the packet to protocol driver (BT/FM/GPS) > +??? ?????*/ > +??? ??? > st_send_frame(protoid, st_gdata); > + > +??? } else if (len > room) { > +??? ??? /* Received packet's > payload length is larger. > +??? ?????* We > can't accommodate it in created skb. > +??? ?????*/ > +??? ??? pr_err("Data length > is too large len %d room %d", len, > +??? ??? ??? > ???room); > +??? ??? > kfree_skb(st_gdata->rx_skb); > +??? } else { > +??? ??? /* Packet header has > non-zero payload length and > +??? ?????* we have > enough space in created skb. Lets read > +??? ?????* payload > data */ > +??? ??? > st_gdata->rx_state = ST_BT_W4_DATA; > +??? ??? > st_gdata->rx_count = len; > +??? ??? return len; > +??? } > + > +??? /* Change ST state to continue to > process next > +?????* packet */ > +??? st_gdata->rx_state = > ST_W4_PACKET_TYPE; > +??? st_gdata->rx_skb = NULL; > +??? st_gdata->rx_count = 0; > + > +??? return 0; > +} > + > +/* internal function for action when wake-up ack > + * received > + */ > +static inline void st_wakeup_ack(struct st_data_s > *st_gdata, > +??? unsigned char cmd) > +{ > +??? register struct sk_buff *waiting_skb; > +??? unsigned long flags = 0; > + > +??? > spin_lock_irqsave(&st_gdata->lock, flags); > +??? /* de-Q from waitQ and Q in txQ now > that the > +?????* chip is awake > +?????*/ > +??? while ((waiting_skb = > skb_dequeue(&st_gdata->tx_waitq))) > +??? ??? > skb_queue_tail(&st_gdata->txq, waiting_skb); > + > +??? /* state forwarded to ST LL */ > +??? st_ll_sleep_state(st_gdata, (unsigned > long)cmd); > +??? > spin_unlock_irqrestore(&st_gdata->lock, flags); > + > +??? /* wake up to send the recently copied > skbs from waitQ */ > +??? st_tx_wakeup(st_gdata); > +} > + > +/* Decodes received RAW data and forwards to > corresponding > + * client drivers (Bluetooth,FM,GPS..etc). > + * > + */ > +void st_int_recv(void *disc_data, > +??? const unsigned char *data, long count) > +{ > +??? register char *ptr; > +??? struct hci_event_hdr *eh; > +??? struct hci_acl_hdr *ah; > +??? struct hci_sco_hdr *sh; > +??? struct fm_event_hdr *fm; > +??? struct gps_event_hdr *gps; > +??? register int len = 0, type = 0, dlen = > 0; > +??? static enum proto_type protoid = > ST_MAX; > +??? struct st_data_s *st_gdata = (struct > st_data_s *)disc_data; > + > +??? ptr = (char *)data; > +??? /* tty_receive sent null ? */ > +??? if (unlikely(ptr == NULL) || (st_gdata > == NULL)) { > +??? ??? pr_err(" received > null from TTY "); > +??? ??? return; > +??? } > + > +??? pr_info("count %ld rx_state %ld" > +??? ??? > ???"rx_count %ld", count, > st_gdata->rx_state, > +??? ??? > ???st_gdata->rx_count); > + > +??? /* Decode received bytes here */ > +??? while (count) { > +??? ??? if > (st_gdata->rx_count) { > +??? ??? ??? > len = min_t(unsigned int, st_gdata->rx_count, count); > +??? ??? ??? > memcpy(skb_put(st_gdata->rx_skb, len), ptr, len); > +??? ??? ??? > st_gdata->rx_count -= len; > +??? ??? ??? > count -= len; > +??? ??? ??? > ptr += len; > + > +??? ??? ??? > if (st_gdata->rx_count) > +??? ??? ??? > ??? continue; > + > +??? ??? ??? > /* Check ST RX state machine , where are we? */ > +??? ??? ??? > switch (st_gdata->rx_state) { > + > +??? ??? ??? > ??? /* Waiting for complete packet ? */ > +??? ??? ??? > case ST_BT_W4_DATA: > +??? ??? ??? > ??? pr_info("Complete pkt received"); > + > +??? ??? ??? > ??? /* Ask ST CORE to forward > +??? ??? ??? > ?????* the packet to protocol > driver */ > +??? ??? ??? > ??? st_send_frame(protoid, st_gdata); > + > +??? ??? ??? > ??? st_gdata->rx_state = > ST_W4_PACKET_TYPE; > +??? ??? ??? > ??? st_gdata->rx_skb = NULL; > +??? ??? ??? > ??? protoid = ST_MAX;??? /* is > this required ? */ > +??? ??? ??? > ??? continue; > + > +??? ??? ??? > ??? /* Waiting for Bluetooth event header ? > */ > +??? ??? ??? > case ST_BT_W4_EVENT_HDR: > +??? ??? ??? > ??? eh = (struct hci_event_hdr > *)st_gdata->rx_skb-> > +??? ??? ??? > ??? ? ? data; > + > +??? ??? ??? > ??? pr_info("Event header: evt 0x%2.2x" > +??? ??? ??? > ??? ??? > ???"plen %d", eh->evt, eh->plen); > + > +??? ??? ??? > ??? st_check_data_len(st_gdata, protoid, > eh->plen); > +??? ??? ??? > ??? continue; > + > +??? ??? ??? > ??? /* Waiting for Bluetooth acl header ? */ > +??? ??? ??? > case ST_BT_W4_ACL_HDR: > +??? ??? ??? > ??? ah = (struct hci_acl_hdr > *)st_gdata->rx_skb-> > +??? ??? ??? > ??? ? ? data; > +??? ??? ??? > ??? dlen = __le16_to_cpu(ah->dlen); > + > +??? ??? ??? > ??? pr_info("ACL header: dlen %d", dlen); > + > +??? ??? ??? > ??? st_check_data_len(st_gdata, protoid, > dlen); > +??? ??? ??? > ??? continue; > + > +??? ??? ??? > ??? /* Waiting for Bluetooth sco header ? */ > +??? ??? ??? > case ST_BT_W4_SCO_HDR: > +??? ??? ??? > ??? sh = (struct hci_sco_hdr > *)st_gdata->rx_skb-> > +??? ??? ??? > ??? ? ? data; > + > +??? ??? ??? > ??? pr_info("SCO header: dlen %d", > sh->dlen); > + > +??? ??? ??? > ??? st_check_data_len(st_gdata, protoid, > sh->dlen); > +??? ??? ??? > ??? continue; > +??? ??? ??? > case ST_FM_W4_EVENT_HDR: > +??? ??? ??? > ??? fm = (struct fm_event_hdr > *)st_gdata->rx_skb-> > +??? ??? ??? > ??? ? ? data; > +??? ??? ??? > ??? pr_info("FM Header: "); > +??? ??? ??? > ??? st_check_data_len(st_gdata, ST_FM, > fm->plen); > +??? ??? ??? > ??? continue; > +??? ??? ??? > ??? /* TODO : Add GPS packet machine logic > here */ > +??? ??? ??? > case ST_GPS_W4_EVENT_HDR: > +??? ??? ??? > ??? /* [0x09 pkt hdr][R/W byte][2 byte len] > */ > +??? ??? ??? > ??? gps = (struct gps_event_hdr > *)st_gdata->rx_skb-> > +??? ??? ??? > ??? ? ???data; > +??? ??? ??? > ??? pr_info("GPS Header: "); > +??? ??? ??? > ??? st_check_data_len(st_gdata, ST_GPS, > gps->plen); > +??? ??? ??? > ??? continue; > +??? ??? ??? > }??? /* end of switch rx_state */ > +??? ??? } > + > +??? ??? /* end of if > rx_count */ > +??? ??? /* Check first byte > of packet and identify module > +??? ?????* owner > (BT/FM/GPS) */ > +??? ??? switch (*ptr) { > + > +??? ??? ??? > /* Bluetooth event packet? */ > +??? ??? case HCI_EVENT_PKT: > +??? ??? ??? > pr_info("Event packet"); > +??? ??? ??? > st_gdata->rx_state = ST_BT_W4_EVENT_HDR; > +??? ??? ??? > st_gdata->rx_count = HCI_EVENT_HDR_SIZE; > +??? ??? ??? > type = HCI_EVENT_PKT; > +??? ??? ??? > protoid = ST_BT; > +??? ??? ??? > break; > + > +??? ??? ??? > /* Bluetooth acl packet? */ > +??? ??? case > HCI_ACLDATA_PKT: > +??? ??? ??? > pr_info("ACL packet"); > +??? ??? ??? > st_gdata->rx_state = ST_BT_W4_ACL_HDR; > +??? ??? ??? > st_gdata->rx_count = HCI_ACL_HDR_SIZE; > +??? ??? ??? > type = HCI_ACLDATA_PKT; > +??? ??? ??? > protoid = ST_BT; > +??? ??? ??? > break; > + > +??? ??? ??? > /* Bluetooth sco packet? */ > +??? ??? case > HCI_SCODATA_PKT: > +??? ??? ??? > pr_info("SCO packet"); > +??? ??? ??? > st_gdata->rx_state = ST_BT_W4_SCO_HDR; > +??? ??? ??? > st_gdata->rx_count = HCI_SCO_HDR_SIZE; > +??? ??? ??? > type = HCI_SCODATA_PKT; > +??? ??? ??? > protoid = ST_BT; > +??? ??? ??? > break; > + > +??? ??? ??? > /* Channel 8(FM) packet? */ > +??? ??? case ST_FM_CH8_PKT: > +??? ??? ??? > pr_info("FM CH8 packet"); > +??? ??? ??? > type = ST_FM_CH8_PKT; > +??? ??? ??? > st_gdata->rx_state = ST_FM_W4_EVENT_HDR; > +??? ??? ??? > st_gdata->rx_count = FM_EVENT_HDR_SIZE; > +??? ??? ??? > protoid = ST_FM; > +??? ??? ??? > break; > + > +??? ??? ??? > /* Channel 9(GPS) packet? */ > +??? ??? case > 0x9:??? /*ST_LL_GPS_CH9_PKT */ > +??? ??? ??? > pr_info("GPS CH9 packet"); > +??? ??? ??? > type = 0x9;??? /* ST_LL_GPS_CH9_PKT; */ > +??? ??? ??? > protoid = ST_GPS; > +??? ??? ??? > st_gdata->rx_state = ST_GPS_W4_EVENT_HDR; > +??? ??? ??? > st_gdata->rx_count = 3;??? /* > GPS_EVENT_HDR_SIZE -1*/ > +??? ??? ??? > break; > +??? ??? case LL_SLEEP_IND: > +??? ??? case LL_SLEEP_ACK: > +??? ??? case > LL_WAKE_UP_IND: > +??? ??? ??? > pr_info("PM packet"); > +??? ??? ??? > /* this takes appropriate action based on > +??? ??? > ?????* sleep state received -- > +??? ??? > ?????*/ > +??? ??? ??? > st_ll_sleep_state(st_gdata, *ptr); > +??? ??? ??? > ptr++; > +??? ??? ??? > count--; > +??? ??? ??? > continue; > +??? ??? case > LL_WAKE_UP_ACK: > +??? ??? ??? > pr_info("PM packet"); > +??? ??? ??? > /* wake up ack received */ > +??? ??? ??? > st_wakeup_ack(st_gdata, *ptr); > +??? ??? ??? > ptr++; > +??? ??? ??? > count--; > +??? ??? ??? > continue; > +??? ??? ??? > /* Unknow packet? */ > +??? ??? default: > +??? ??? ??? > pr_err("Unknown packet type %2.2x", (__u8) *ptr); > +??? ??? ??? > ptr++; > +??? ??? ??? > count--; > +??? ??? ??? > continue; > +??? ??? }; > +??? ??? ptr++; > +??? ??? count--; > + > +??? ??? switch (protoid) { > +??? ??? case ST_BT: > +??? ??? ??? > /* Allocate new packet to hold received data */ > +??? ??? ??? > st_gdata->rx_skb = > +??? ??? ??? > ? ? bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); > +??? ??? ??? > if (!st_gdata->rx_skb) { > +??? ??? ??? > ??? pr_err("Can't allocate mem for new > packet"); > +??? ??? ??? > ??? st_gdata->rx_state = > ST_W4_PACKET_TYPE; > +??? ??? ??? > ??? st_gdata->rx_count = 0; > +??? ??? ??? > ??? return; > +??? ??? ??? > } > +??? ??? ??? > bt_cb(st_gdata->rx_skb)->pkt_type = type; > +??? ??? ??? > break; > +??? ??? case > ST_FM:??? /* for FM */ > +??? ??? ??? > st_gdata->rx_skb = > +??? ??? ??? > ? ? alloc_skb(FM_MAX_FRAME_SIZE, GFP_ATOMIC); > +??? ??? ??? > if (!st_gdata->rx_skb) { > +??? ??? ??? > ??? pr_err("Can't allocate mem for new > packet"); > +??? ??? ??? > ??? st_gdata->rx_state = > ST_W4_PACKET_TYPE; > +??? ??? ??? > ??? st_gdata->rx_count = 0; > +??? ??? ??? > ??? return; > +??? ??? ??? > } > +??? ??? ??? > /* place holder 0x08 */ > +??? ??? ??? > skb_reserve(st_gdata->rx_skb, 1); > +??? ??? ??? > st_gdata->rx_skb->cb[0] = ST_FM_CH8_PKT; > +??? ??? ??? > break; > +??? ??? case ST_GPS: > +??? ??? ??? > /* for GPS */ > +??? ??? ??? > st_gdata->rx_skb = > +??? ??? ??? > ? ? alloc_skb(100 /*GPS_MAX_FRAME_SIZE */ , > GFP_ATOMIC); > +??? ??? ??? > if (!st_gdata->rx_skb) { > +??? ??? ??? > ??? pr_err("Can't allocate mem for new > packet"); > +??? ??? ??? > ??? st_gdata->rx_state = > ST_W4_PACKET_TYPE; > +??? ??? ??? > ??? st_gdata->rx_count = 0; > +??? ??? ??? > ??? return; > +??? ??? ??? > } > +??? ??? ??? > /* place holder 0x09 */ > +??? ??? ??? > skb_reserve(st_gdata->rx_skb, 1); > +??? ??? ??? > st_gdata->rx_skb->cb[0] = 0x09;??? > /*ST_GPS_CH9_PKT; */ > +??? ??? ??? > break; > +??? ??? case ST_MAX: > +??? ??? ??? > break; > +??? ??? } > +??? } > +??? pr_info("done %s", __func__); > +??? return; > +} > + > +/* internal de-Q function > + * -- return previous in-completely written skb > + *? or return the skb in the txQ > + */ > +struct sk_buff *st_int_dequeue(struct st_data_s > *st_gdata) > +{ > +??? struct sk_buff *returning_skb; > + > +??? pr_info("%s", __func__); > +??? /* if the previous skb wasn't written > completely > +?????*/ > +??? if (st_gdata->tx_skb != NULL) { > +??? ??? returning_skb = > st_gdata->tx_skb; > +??? ??? st_gdata->tx_skb > = NULL; > +??? ??? return > returning_skb; > +??? } > + > +??? /* de-Q from the txQ always if previous > write is complete */ > +??? return > skb_dequeue(&st_gdata->txq); > +} > + > +/* internal Q-ing function > + * will either Q the skb to txq or the tx_waitq > + * depending on the ST LL state > + * > + * lock the whole func - since ll_getstate and Q-ing > should happen > + * in one-shot > + */ > +void st_int_enqueue(struct st_data_s *st_gdata, struct > sk_buff *skb) > +{ > +??? unsigned long flags = 0; > + > +??? pr_info("%s", __func__); > +??? /* this function can be invoked in more > then one context. > +?????* so have a lock */ > +??? > spin_lock_irqsave(&st_gdata->lock, flags); > + > +??? switch (st_ll_getstate(st_gdata)) { > +??? case ST_LL_AWAKE: > +??? ??? pr_info("ST LL is > AWAKE, sending normally"); > +??? ??? > skb_queue_tail(&st_gdata->txq, skb); > +??? ??? break; > +??? case ST_LL_ASLEEP_TO_AWAKE: > +??? ??? > skb_queue_tail(&st_gdata->tx_waitq, skb); > +??? ??? break; > +??? case > ST_LL_AWAKE_TO_ASLEEP:??? /* host cannot be > in this state */ > +??? ??? pr_err("ST LL is > illegal state(%ld)," > +??? ??? ??? > ???"purging received skb.", > st_ll_getstate(st_gdata)); > +??? ??? kfree_skb(skb); > +??? ??? break; > + > +??? case ST_LL_ASLEEP: > +??? ??? /* call a function > of ST LL to put data > +??? ?????* in > tx_waitQ and wake_ind in txQ > +??? ?????*/ > +??? ??? > skb_queue_tail(&st_gdata->tx_waitq, skb); > +??? ??? > st_ll_wakeup(st_gdata); > +??? ??? break; > +??? default: > +??? ??? pr_err("ST LL is > illegal state(%ld)," > +??? ??? ??? > ???"purging received skb.", > st_ll_getstate(st_gdata)); > +??? ??? kfree_skb(skb); > +??? ??? break; > +??? } > +??? > spin_unlock_irqrestore(&st_gdata->lock, flags); > +??? pr_info("done %s", __func__); > +??? return; > +} > + > +/* > + * internal wakeup function > + * called from either > + * - TTY layer when write's finished > + * - st_write (in context of the protocol stack) > + */ > +void st_tx_wakeup(struct st_data_s *st_data) > +{ > +??? struct sk_buff *skb; > +??? unsigned long flags;??? > /* for irq save flags */ > +??? pr_info("%s", __func__); > +??? /* check for sending & set flag > sending here */ > +??? if (test_and_set_bit(ST_TX_SENDING, > &st_data->tx_state)) { > +??? ??? pr_info("ST already > sending"); > +??? ??? /* keep sending */ > +??? ??? > set_bit(ST_TX_WAKEUP, &st_data->tx_state); > +??? ??? return; > +??? ??? /* TX_WAKEUP will be > checked in another > +??? ?????* > context > +??? ?????*/ > +??? } > +??? do {??? > ??? ??? /* come back if > st_tx_wakeup is set */ > +??? ??? /* woke-up to write > */ > +??? ??? > clear_bit(ST_TX_WAKEUP, &st_data->tx_state); > +??? ??? while ((skb = > st_int_dequeue(st_data))) { > +??? ??? ??? > int len; > +??? ??? ??? > spin_lock_irqsave(&st_data->lock, flags); > +??? ??? ??? > /* enable wake-up from TTY */ > +??? ??? ??? > set_bit(TTY_DO_WRITE_WAKEUP, > &st_data->tty->flags); > +??? ??? ??? > len = st_int_write(st_data, skb->data, skb->len); > +??? ??? ??? > skb_pull(skb, len); > +??? ??? ??? > /* if skb->len = len as expected, skb->len=0 */ > +??? ??? ??? > if (skb->len) { > +??? ??? ??? > ??? /* would be the next skb to be sent */ > +??? ??? ??? > ??? st_data->tx_skb = skb; > +??? ??? ??? > ??? > spin_unlock_irqrestore(&st_data->lock, flags); > +??? ??? ??? > ??? break; > +??? ??? ??? > } > +??? ??? ??? > kfree_skb(skb); > +??? ??? ??? > spin_unlock_irqrestore(&st_data->lock, flags); > +??? ??? } > +??? ??? /* if wake-up is set > in another context- restart sending */ > +??? } while (test_bit(ST_TX_WAKEUP, > &st_data->tx_state)); > + > +??? /* clear flag sending */ > +??? clear_bit(ST_TX_SENDING, > &st_data->tx_state); > +} > + > +/********************************************************************/ > +/* functions called from ST KIM > +*/ > +void kim_st_list_protocols(struct st_data_s *st_gdata, > char *buf) > +{ > +??? unsigned long flags = 0; > +#ifdef DEBUG > +??? unsigned char i = ST_MAX; > +#endif > +??? > spin_lock_irqsave(&st_gdata->lock, flags); > +#ifdef DEBUG??? ??? > ??? /* more detailed log */ > +??? for (i = 0; i < ST_MAX; i++) { > +??? ??? if (i == 0) { > +??? ??? ??? > sprintf(buf, "%s is %s", protocol_strngs[i], > +??? ??? ??? > ??? st_gdata->list[i] != > +??? ??? ??? > ??? NULL ? "Registered" : "Unregistered"); > +??? ??? } else { > +??? ??? ??? > sprintf(buf, "%s\n%s is %s", buf, protocol_strngs[i], > +??? ??? ??? > ??? st_gdata->list[i] != > +??? ??? ??? > ??? NULL ? "Registered" : "Unregistered"); > +??? ??? } > +??? } > +??? sprintf(buf, "%s\n", buf); > +#else /* limited info */ > +??? sprintf(buf, "BT=%c\nFM=%c\nGPS=%c\n", > +??? ??? > st_gdata->list[ST_BT] != NULL ? 'R' : 'U', > +??? ??? > st_gdata->list[ST_FM] != NULL ? 'R' : 'U', > +??? ??? > st_gdata->list[ST_GPS] != NULL ? 'R' : 'U'); > +#endif > +??? > spin_unlock_irqrestore(&st_gdata->lock, flags); > +} > + > +/********************************************************************/ > +/* > + * functions called from protocol stack drivers > + * to be EXPORT-ed > + */ > +long st_register(struct st_proto_s *new_proto) > +{ > +??? struct st_data_s??? > *st_gdata; > +??? long err = ST_SUCCESS; > +??? unsigned long flags = 0; > + > +??? st_kim_ref(&st_gdata); > +??? pr_info("%s(%d) ", __func__, > new_proto->type); > +??? if (st_gdata == NULL || new_proto == > NULL || new_proto->recv == NULL > +??? ? ? || > new_proto->reg_complete_cb == NULL) { > +??? ??? > pr_err("gdata/new_proto/recv or reg_complete_cb not > ready"); > +??? ??? return > ST_ERR_FAILURE; > +??? } > + > +??? if (new_proto->type < ST_BT || > new_proto->type >= ST_MAX) { > +??? ??? pr_err("protocol %d > not supported", new_proto->type); > +??? ??? return > ST_ERR_NOPROTO; > +??? } > + > +??? if > (st_gdata->list[new_proto->type] != NULL) { > +??? ??? pr_err("protocol %d > already registered", new_proto->type); > +??? ??? return > ST_ERR_ALREADY; > +??? } > + > +??? /* can be from process context only */ > +??? > spin_lock_irqsave(&st_gdata->lock, flags); > + > +??? if (test_bit(ST_REG_IN_PROGRESS, > &st_gdata->st_state)) { > +??? ??? pr_info(" > ST_REG_IN_PROGRESS:%d ", new_proto->type); > +??? ??? /* fw download in > progress */ > +??? ??? > st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE); > + > +??? ??? > st_gdata->list[new_proto->type] = new_proto; > +??? ??? new_proto->write > = st_write; > + > +??? ??? > set_bit(ST_REG_PENDING, &st_gdata->st_state); > +??? ??? > spin_unlock_irqrestore(&st_gdata->lock, flags); > +??? ??? return > ST_ERR_PENDING; > +??? } else if > (st_gdata->protos_registered == ST_EMPTY) { > +??? ??? pr_info(" protocol > list empty :%d ", new_proto->type); > +??? ??? > set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); > +??? ??? st_recv = > st_kim_recv; > + > +??? ??? /* release lock > previously held - re-locked below */ > +??? ??? > spin_unlock_irqrestore(&st_gdata->lock, flags); > + > +??? ??? /* enable the ST LL > - to set default chip state */ > +??? ??? > st_ll_enable(st_gdata); > +??? ??? /* this may take a > while to complete > +??? ?????* since > it involves BT fw download > +??? ?????*/ > +??? ??? err = > st_kim_start(); > +??? ??? if (err != > ST_SUCCESS) { > +??? ??? ??? > clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); > +??? ??? ??? > if ((st_gdata->protos_registered != ST_EMPTY) && > +??? ??? ??? > ? ? (test_bit(ST_REG_PENDING, > &st_gdata->st_state))) { > +??? ??? ??? > ??? pr_err(" KIM failure complete callback > "); > +??? ??? ??? > ??? st_reg_complete(st_gdata, > ST_ERR_FAILURE); > +??? ??? ??? > } > + > +??? ??? ??? > return ST_ERR_FAILURE; > +??? ??? } > + > +??? ??? /* the protocol > might require other gpios to be toggled > +??? ?????*/ > +??? ??? > st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE); > + > +??? ??? > clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); > +??? ??? st_recv = > st_int_recv; > + > +??? ??? /* this is where all > pending registration > +??? ?????* are > signalled to be complete by calling callback functions > +??? ?????*/ > +??? ??? if > ((st_gdata->protos_registered != ST_EMPTY) && > +??? ??? ? ? > (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { > +??? ??? ??? > pr_info(" call reg complete callback "); > +??? ??? ??? > st_gdata->protos_registered++; > +??? ??? ??? > st_reg_complete(st_gdata, ST_SUCCESS); > +??? ??? } > +??? ??? > clear_bit(ST_REG_PENDING, &st_gdata->st_state); > + > +??? ??? /* check for already > registered once more, > +??? ?????* since > the above check is old > +??? ?????*/ > +??? ??? if > (st_gdata->list[new_proto->type] != NULL) { > +??? ??? ??? > pr_err(" proto %d already registered ", > +??? ??? ??? > ??? ???new_proto->type); > +??? ??? ??? > return ST_ERR_ALREADY; > +??? ??? } > + > +??? ??? > spin_lock_irqsave(&st_gdata->lock, flags); > +??? ??? > st_gdata->list[new_proto->type] = new_proto; > +??? ??? new_proto->write > = st_write; > +??? ??? > spin_unlock_irqrestore(&st_gdata->lock, flags); > +??? ??? return err; > +??? } > +??? /* if fw is already downloaded & > new stack registers protocol */ > +??? else { > +??? ??? switch > (new_proto->type) { > +??? ??? case ST_BT: > +??? ??? ??? > /* do nothing */ > +??? ??? ??? > break; > +??? ??? case ST_FM: > +??? ??? case ST_GPS: > +??? ??? ??? > st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE); > +??? ??? ??? > break; > +??? ??? case ST_MAX: > +??? ??? default: > +??? ??? ??? > pr_err("%d protocol not supported", > +??? ??? ??? > ??? ???new_proto->type); > +??? ??? ??? > err = ST_ERR_NOPROTO; > +??? ??? ??? > /* something wrong */ > +??? ??? ??? > break; > +??? ??? } > +??? ??? > st_gdata->list[new_proto->type] = new_proto; > +??? ??? new_proto->write > = st_write; > + > +??? ??? /* lock already held > before entering else */ > +??? ??? > spin_unlock_irqrestore(&st_gdata->lock, flags); > +??? ??? return err; > +??? } > +??? pr_info("done %s(%d) ", __func__, > new_proto->type); > +} > +EXPORT_SYMBOL_GPL(st_register); > + > +/* to unregister a protocol - > + * to be called from protocol stack driver > + */ > +long st_unregister(enum proto_type type) > +{ > +??? long err = ST_SUCCESS; > +??? unsigned long flags = 0; > +??? struct st_data_s??? > *st_gdata; > + > +??? pr_info("%s: %d ", __func__, type); > + > +??? st_kim_ref(&st_gdata); > +??? if (type < ST_BT || type >= > ST_MAX) { > +??? ??? pr_err(" protocol %d > not supported", type); > +??? ??? return > ST_ERR_NOPROTO; > +??? } > + > +??? > spin_lock_irqsave(&st_gdata->lock, flags); > + > +??? if (st_gdata->list[type] == NULL) { > +??? ??? pr_err(" protocol %d > not registered", type); > +??? ??? > spin_unlock_irqrestore(&st_gdata->lock, flags); > +??? ??? return > ST_ERR_NOPROTO; > +??? } > + > +??? st_gdata->protos_registered--; > +??? st_gdata->list[type] = NULL; > + > +??? /* kim ignores BT in the below > function > +?????* and handles the rest, BT > is toggled > +?????* only in kim_start and > kim_stop > +?????*/ > +??? st_kim_chip_toggle(type, > KIM_GPIO_INACTIVE); > +??? > spin_unlock_irqrestore(&st_gdata->lock, flags); > + > +??? if ((st_gdata->protos_registered == > ST_EMPTY) && > +??? ? ? > (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) { > +??? ??? pr_info(" all > protocols unregistered "); > + > +??? ??? /* stop traffic on > tty */ > +??? ??? if > (st_gdata->tty) { > +??? ??? ??? > tty_ldisc_flush(st_gdata->tty); > +??? ??? ??? > stop_tty(st_gdata->tty); > +??? ??? } > + > +??? ??? /* all protocols now > unregistered */ > +??? ??? st_kim_stop(); > +??? ??? /* disable ST LL */ > +??? ??? > st_ll_disable(st_gdata); > +??? } > +??? return err; > +} > + > +/* > + * called in protocol stack drivers > + * via the write function pointer > + */ > +long st_write(struct sk_buff *skb) > +{ > +??? struct st_data_s *st_gdata; > +#ifdef DEBUG > +??? enum proto_type protoid = ST_MAX; > +#endif > +??? long len; > + > +??? st_kim_ref(&st_gdata); > +??? if (unlikely(skb == NULL || st_gdata == > NULL > +??? ??? || st_gdata->tty > == NULL)) { > +??? ??? pr_err("data/tty > unavailable to perform write"); > +??? ??? return > ST_ERR_FAILURE; > +??? } > +#ifdef DEBUG??? ??? > ??? /* open-up skb to read the 1st byte */ > +??? switch (skb->data[0]) { > +??? case HCI_COMMAND_PKT: > +??? case HCI_ACLDATA_PKT: > +??? case HCI_SCODATA_PKT: > +??? ??? protoid = ST_BT; > +??? ??? break; > +??? case ST_FM_CH8_PKT: > +??? ??? protoid = ST_FM; > +??? ??? break; > +??? case 0x09: > +??? ??? protoid = ST_GPS; > +??? ??? break; > +??? } > +??? if (unlikely(st_gdata->list[protoid] > == NULL)) { > +??? ??? pr_err(" protocol %d > not registered, and writing? ", > +??? ??? ??? > ???protoid); > +??? ??? return > ST_ERR_FAILURE; > +??? } > +#endif > +??? pr_info("%d to be written", > skb->len); > +??? len = skb->len; > + > +??? /* st_ll to decide where to enqueue the > skb */ > +??? st_int_enqueue(st_gdata, skb); > +??? /* wake up */ > +??? st_tx_wakeup(st_gdata); > + > +??? /* return number of bytes written */ > +??? return len; > +} > + > +/* for protocols making use of shared transport */ > +EXPORT_SYMBOL_GPL(st_unregister); > + > +/********************************************************************/ > +/* > + * functions called from TTY layer > + */ > +static int st_tty_open(struct tty_struct *tty) > +{ > +??? int err = ST_SUCCESS; > +??? struct st_data_s *st_gdata; > +??? pr_info("%s ", __func__); > + > +??? st_kim_ref(&st_gdata); > +??? st_gdata->tty = tty; > +??? tty->disc_data = st_gdata; > + > +??? /* don't do an wakeup for now */ > +??? clear_bit(TTY_DO_WRITE_WAKEUP, > &tty->flags); > + > +??? /* mem already allocated > +?????*/ > +??? tty->receive_room = 65536; > +??? /* Flush any pending characters in the > driver and discipline. */ > +??? tty_ldisc_flush(tty); > +??? tty_driver_flush_buffer(tty); > +??? /* > +?????* signal to UIM via KIM that > - > +?????* installation of N_TI_WL > ldisc is complete > +?????*/ > +??? st_kim_complete(); > +??? pr_info("done %s", __func__); > +??? return err; > +} > + > +static void st_tty_close(struct tty_struct *tty) > +{ > +??? unsigned char i = ST_MAX; > +??? unsigned long flags = 0; > +??? struct??? st_data_s > *st_gdata = tty->disc_data; > + > +??? pr_info("%s ", __func__); > + > +??? /* TODO: > +?????* if a protocol has been > registered & line discipline > +?????* un-installed for some > reason - what should be done ? > +?????*/ > +??? > spin_lock_irqsave(&st_gdata->lock, flags); > +??? for (i = ST_BT; i < ST_MAX; i++) { > +??? ??? if > (st_gdata->list[i] != NULL) > +??? ??? ??? > pr_err("%d not un-registered", i); > +??? ??? st_gdata->list[i] > = NULL; > +??? } > +??? > spin_unlock_irqrestore(&st_gdata->lock, flags); > +??? /* > +?????* signal to UIM via KIM that > - > +?????* N_TI_WL ldisc is > un-installed > +?????*/ > +??? st_kim_complete(); > +??? st_gdata->tty = NULL; > +??? /* Flush any pending characters in the > driver and discipline. */ > +??? tty_ldisc_flush(tty); > +??? tty_driver_flush_buffer(tty); > + > +??? > spin_lock_irqsave(&st_gdata->lock, flags); > +??? /* empty out txq and tx_waitq */ > +??? > skb_queue_purge(&st_gdata->txq); > +??? > skb_queue_purge(&st_gdata->tx_waitq); > +??? /* reset the TTY Rx states of ST */ > +??? st_gdata->rx_count = 0; > +??? st_gdata->rx_state = > ST_W4_PACKET_TYPE; > +??? kfree_skb(st_gdata->rx_skb); > +??? st_gdata->rx_skb = NULL; > +??? > spin_unlock_irqrestore(&st_gdata->lock, flags); > + > +??? pr_info("%s: done ", __func__); > +} > + > +static void st_tty_receive(struct tty_struct *tty, const > unsigned char *data, > +??? ??? ??? > ???char *tty_flags, int count) > +{ > + > +#ifdef VERBOSE > +??? long i; > +??? printk(KERN_ERR "incoming data...\n"); > +??? for (i = 0; i < count; i++) > +??? ??? printk(" %x", > data[i]); > +??? printk(KERN_ERR "\n.. data end\n"); > +#endif > + > +??? /* > +?????* if fw download is in > progress then route incoming data > +?????* to KIM for validation > +?????*/ > +??? st_recv(tty->disc_data, data, > count); > +??? pr_info("done %s", __func__); > +} > + > +/* wake-up function called in from the TTY layer > + * inside the internal wakeup function will be called > + */ > +static void st_tty_wakeup(struct tty_struct *tty) > +{ > +??? struct??? st_data_s > *st_gdata = tty->disc_data; > +??? pr_info("%s ", __func__); > +??? /* don't do an wakeup for now */ > +??? clear_bit(TTY_DO_WRITE_WAKEUP, > &tty->flags); > + > +??? /* call our internal wakeup */ > +??? st_tx_wakeup((void *)st_gdata); > +} > + > +static void st_tty_flush_buffer(struct tty_struct *tty) > +{ > +??? struct??? st_data_s > *st_gdata = tty->disc_data; > +??? pr_info("%s ", __func__); > + > +??? kfree_skb(st_gdata->tx_skb); > +??? st_gdata->tx_skb = NULL; > + > +??? tty->ops->flush_buffer(tty); > +??? return; > +} > + > +/********************************************************************/ > +int st_core_init(struct st_data_s **core_data) > +{ > +??? struct st_data_s *st_gdata; > +??? long err; > +??? static struct tty_ldisc_ops > *st_ldisc_ops; > + > +??? /* populate and register to TTY line > discipline */ > +??? st_ldisc_ops = > kzalloc(sizeof(*st_ldisc_ops), GFP_KERNEL); > +??? if (!st_ldisc_ops) { > +??? ??? pr_err("no mem to > allocate"); > +??? ??? return -ENOMEM; > +??? } > + > +??? st_ldisc_ops->magic = > TTY_LDISC_MAGIC; > +??? st_ldisc_ops->name = > "n_st";??? /*"n_hci"; */ > +??? st_ldisc_ops->open = st_tty_open; > +??? st_ldisc_ops->close = st_tty_close; > +??? st_ldisc_ops->receive_buf = > st_tty_receive; > +??? st_ldisc_ops->write_wakeup = > st_tty_wakeup; > +??? st_ldisc_ops->flush_buffer = > st_tty_flush_buffer; > +??? st_ldisc_ops->owner = THIS_MODULE; > + > +??? err = tty_register_ldisc(N_TI_WL, > st_ldisc_ops); > +??? if (err) { > +??? ??? pr_err("error > registering %d line discipline %ld", > +??? ??? ??? > ???N_TI_WL, err); > +??? ??? > kfree(st_ldisc_ops); > +??? ??? return err; > +??? } > +??? pr_info("registered n_shared line > discipline"); > + > +??? st_gdata = kzalloc(sizeof(struct > st_data_s), GFP_KERNEL); > +??? if (!st_gdata) { > +??? ??? pr_err("memory > allocation failed"); > +??? ??? err = > tty_unregister_ldisc(N_TI_WL); > +??? ??? if (err) > +??? ??? ??? > pr_err("unable to un-register ldisc %ld", err); > +??? ??? > kfree(st_ldisc_ops); > +??? ??? err = -ENOMEM; > +??? ??? return err; > +??? } > + > +??? /* Initialize ST TxQ and Tx waitQ queue > head. All BT/FM/GPS module skb's > +?????* will be pushed in this > queue for actual transmission. > +?????*/ > +??? > skb_queue_head_init(&st_gdata->txq); > +??? > skb_queue_head_init(&st_gdata->tx_waitq); > + > +??? /* Locking used in st_int_enqueue() to > avoid multiple execution */ > +??? > spin_lock_init(&st_gdata->lock); > + > +??? /* ldisc_ops ref to be only used in > __exit of module */ > +??? st_gdata->ldisc_ops = st_ldisc_ops; > + > +#if 0 > +??? err = st_kim_init(); > +??? if (err) { > +??? ??? pr_err("error during > kim initialization(%ld)", err); > +??? ??? kfree(st_gdata); > +??? ??? err = > tty_unregister_ldisc(N_TI_WL); > +??? ??? if (err) > +??? ??? ??? > pr_err("unable to un-register ldisc"); > +??? ??? > kfree(st_ldisc_ops); > +??? ??? return -1; > +??? } > +#endif > + > +??? err = st_ll_init(st_gdata); > +??? if (err) { > +??? ??? pr_err("error during > st_ll initialization(%ld)", err); > +??? ??? kfree(st_gdata); > +??? ??? err = > tty_unregister_ldisc(N_TI_WL); > +??? ??? if (err) > +??? ??? ??? > pr_err("unable to un-register ldisc"); > +??? ??? > kfree(st_ldisc_ops); > +??? ??? return -1; > +??? } > +??? *core_data = st_gdata; > +??? return 0; > +} > + > +void st_core_exit(struct st_data_s *st_gdata) > +{ > +??? long err; > +??? /* internal module cleanup */ > +??? err = st_ll_deinit(st_gdata); > +??? if (err) > +??? ??? pr_err("error during > deinit of ST LL %ld", err); > +#if 0 > +??? err = st_kim_deinit(); > +??? if (err) > +??? ??? pr_err("error during > deinit of ST KIM %ld", err); > +#endif > +??? if (st_gdata != NULL) { > +??? ??? /* Free ST Tx Qs and > skbs */ > +??? ??? > skb_queue_purge(&st_gdata->txq); > +??? ??? > skb_queue_purge(&st_gdata->tx_waitq); > +??? ??? > kfree_skb(st_gdata->rx_skb); > +??? ??? > kfree_skb(st_gdata->tx_skb); > +??? ??? /* TTY ldisc cleanup > */ > +??? ??? err = > tty_unregister_ldisc(N_TI_WL); > +??? ??? if (err) > +??? ??? ??? > pr_err("unable to un-register ldisc %ld", err); > +??? ??? > kfree(st_gdata->ldisc_ops); > +??? ??? /* free the global > data pointer */ > +??? ??? kfree(st_gdata); > +??? } > +} > + > + > diff --git a/drivers/staging/ti-st/st_core.h > b/drivers/staging/ti-st/st_core.h > new file mode 100644 > index 0000000..f271c88 > --- /dev/null > +++ b/drivers/staging/ti-st/st_core.h > @@ -0,0 +1,98 @@ > +/* > + *? Shared Transport Core header file > + * > + *? Copyright (C) 2009 Texas Instruments > + * > + *? This program is free software; you can > redistribute it and/or modify > + *? it under the terms of the GNU General Public > License version 2 as > + *? published by the Free Software Foundation. > + * > + *? This program is distributed in the hope that it > will be useful, > + *? but WITHOUT ANY WARRANTY; without even the > implied warranty of > + *? MERCHANTABILITY or FITNESS FOR A PARTICULAR > PURPOSE.? See the > + *? GNU General Public License for more details. > + * > + *? You should have received a copy of the GNU > General Public License > + *? along with this program; if not, write to the > Free Software > + *? Foundation, Inc., 59 Temple Place, Suite 330, > Boston, MA? 02111-1307? USA > + * > + */ > + > +#ifndef ST_CORE_H > +#define ST_CORE_H > + > +#include > +#include "st.h" > + > +/* states of protocol list */ > +#define ST_NOTEMPTY??? 1 > +#define ST_EMPTY??? 0 > + > +/* > + * possible st_states > + */ > +#define ST_INITIALIZING??? > ??? 1 > +#define ST_REG_IN_PROGRESS??? 2 > +#define ST_REG_PENDING??? > ??? 3 > +#define ST_WAITING_FOR_RESP??? 4 > + > +/* > + * local data required for ST/KIM/ST-HCI-LL > + */ > +struct st_data_s { > +??? unsigned long st_state; > +/* > + * an instance of tty_struct & ldisc ops to move > around > + */ > +??? struct tty_struct *tty; > +??? struct tty_ldisc_ops *ldisc_ops; > +/* > + * the tx skb - > + * if the skb is already dequeued and the tty failed to > write the same > + * maintain the skb to write in the next transaction > + */ > +??? struct sk_buff *tx_skb; > +#define ST_TX_SENDING??? 1 > +#define ST_TX_WAKEUP??? 2 > +??? unsigned long tx_state; > +/* > + * list of protocol registered > + */ > +??? struct st_proto_s *list[ST_MAX]; > +/* > + * lock > + */ > +??? unsigned long rx_state; > +??? unsigned long rx_count; > +??? struct sk_buff *rx_skb; > +??? struct sk_buff_head txq, tx_waitq; > +??? spinlock_t lock;??? /* > ST LL state lock? */ > +??? unsigned char??? > protos_registered; > +??? unsigned long > ll_state;??? /* ST LL power state */ > +}; > + > +/* point this to tty->driver->write or > tty->ops->write > + * depending upon the kernel version > + */ > +int st_int_write(struct st_data_s*, const unsigned char*, > int); > +/* internal write function, passed onto protocol drivers > + * via the write function ptr of protocol struct > + */ > +long st_write(struct sk_buff *); > +/* function to be called from ST-LL > + */ > +void st_ll_send_frame(enum proto_type, struct sk_buff *); > +/* internal wake up function */ > +void st_tx_wakeup(struct st_data_s *st_data); > + > +int st_core_init(struct st_data_s **); > +void st_core_exit(struct st_data_s *); > +void st_kim_ref(struct st_data_s **); > + > +#define GPS_STUB_TEST > +#ifdef GPS_STUB_TEST > +int gps_chrdrv_stub_write(const unsigned char*, int); > +void gps_chrdrv_stub_init(void); > +#endif > + > +#endif /*ST_CORE_H */ > -- > 1.5.4.3 > > Any comments on these patches ? The INTERNET now has a personality. YOURS! See your Yahoo! Homepage. http://in.yahoo.com/ -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/