diff options
Diffstat (limited to 'drivers/staging/ti-st')
| -rw-r--r-- | drivers/staging/ti-st/Kconfig | 25 | ||||
| -rw-r--r-- | drivers/staging/ti-st/Makefile | 7 | ||||
| -rw-r--r-- | drivers/staging/ti-st/TODO | 19 | ||||
| -rw-r--r-- | drivers/staging/ti-st/bt_drv.c | 502 | ||||
| -rw-r--r-- | drivers/staging/ti-st/bt_drv.h | 61 | ||||
| -rw-r--r-- | drivers/staging/ti-st/fm.h | 13 | ||||
| -rw-r--r-- | drivers/staging/ti-st/st.h | 90 | ||||
| -rw-r--r-- | drivers/staging/ti-st/st_core.c | 1062 | ||||
| -rw-r--r-- | drivers/staging/ti-st/st_core.h | 98 | ||||
| -rw-r--r-- | drivers/staging/ti-st/st_kim.c | 754 | ||||
| -rw-r--r-- | drivers/staging/ti-st/st_kim.h | 150 | ||||
| -rw-r--r-- | drivers/staging/ti-st/st_ll.c | 147 | ||||
| -rw-r--r-- | drivers/staging/ti-st/st_ll.h | 62 | ||||
| -rw-r--r-- | drivers/staging/ti-st/sysfs-uim | 16 |
14 files changed, 0 insertions, 3006 deletions
diff --git a/drivers/staging/ti-st/Kconfig b/drivers/staging/ti-st/Kconfig deleted file mode 100644 index 3ab204ddc29..00000000000 --- a/drivers/staging/ti-st/Kconfig +++ /dev/null @@ -1,25 +0,0 @@ -# -# TI's shared transport line discipline and the protocol -# drivers (BT, FM and GPS) -# -menu "Texas Instruments shared transport line discipline" -config TI_ST - tristate "shared transport core driver" - depends on RFKILL - select FW_LOADER - help - This enables the shared transport core driver for TI - BT / FM and GPS combo chips. This enables protocol drivers - to register themselves with core and send data, the responses - are returned to relevant protocol drivers based on their - packet types. - -config ST_BT - tristate "BlueZ bluetooth driver for ST" - depends on BT - select TI_ST - help - This enables the Bluetooth driver for TI BT/FM/GPS combo devices. - This makes use of shared transport line discipline core driver to - communicate with the BT core of the combo chip. -endmenu diff --git a/drivers/staging/ti-st/Makefile b/drivers/staging/ti-st/Makefile deleted file mode 100644 index 0167d1d2c25..00000000000 --- a/drivers/staging/ti-st/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for TI's shared transport line discipline -# and its protocol drivers (BT, FM, GPS) -# -obj-$(CONFIG_TI_ST) += st_drv.o -st_drv-objs := st_core.o st_kim.o st_ll.o -obj-$(CONFIG_ST_BT) += bt_drv.o diff --git a/drivers/staging/ti-st/TODO b/drivers/staging/ti-st/TODO deleted file mode 100644 index 2c4fe583901..00000000000 --- a/drivers/staging/ti-st/TODO +++ /dev/null @@ -1,19 +0,0 @@ -TODO: - -1. A per-device/tty port context required to support multiple devices -on same platform. - -2. REMOVE the sysfs entry PID passing mechanism, since there should -be a better way to request user-space to install line discipline. - -3. Re-view/Re-work on the locking. - -4. Re-structure to make the ldisc driver more generic for chipsets which mux -multiple connectivity (BT, FM, GPS) upon 1 TTY port. - -5. Step up and maintain this driver to ensure that it continues -to work. Having the hardware for this is pretty much a -requirement. If this does not happen, the will be removed in -the 2.6.35 kernel release. - -Please send patches to Greg Kroah-Hartman <greg@kroah.com>. diff --git a/drivers/staging/ti-st/bt_drv.c b/drivers/staging/ti-st/bt_drv.c deleted file mode 100644 index d8420b5c91f..00000000000 --- a/drivers/staging/ti-st/bt_drv.c +++ /dev/null @@ -1,502 +0,0 @@ -/* - * Texas Instrument's Bluetooth Driver For Shared Transport. - * - * Bluetooth Driver acts as interface between HCI CORE and - * TI Shared Transport Layer. - * - * 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 - * - */ - -#include <net/bluetooth/bluetooth.h> -#include <net/bluetooth/hci_core.h> - -#include "st.h" -#include "bt_drv.h" - -/* Define this macro to get debug msg */ -#undef DEBUG - -#ifdef DEBUG -#define BT_DRV_DBG(fmt, arg...) printk(KERN_INFO "(btdrv):"fmt"\n" , ## arg) -#define BTDRV_API_START() printk(KERN_INFO "(btdrv): %s Start\n", \ - __func__) -#define BTDRV_API_EXIT(errno) printk(KERN_INFO "(btdrv): %s Exit(%d)\n", \ - __func__, errno) -#else -#define BT_DRV_DBG(fmt, arg...) -#define BTDRV_API_START() -#define BTDRV_API_EXIT(errno) -#endif - -#define BT_DRV_ERR(fmt, arg...) printk(KERN_ERR "(btdrv):"fmt"\n" , ## arg) - -static int reset; -static struct hci_st *hst; - -/* Increments HCI counters based on pocket ID (cmd,acl,sco) */ -static inline void hci_st_tx_complete(struct hci_st *hst, int pkt_type) -{ - struct hci_dev *hdev; - - BTDRV_API_START(); - - hdev = hst->hdev; - - /* Update HCI stat counters */ - switch (pkt_type) { - case HCI_COMMAND_PKT: - hdev->stat.cmd_tx++; - break; - - case HCI_ACLDATA_PKT: - hdev->stat.acl_tx++; - break; - - case HCI_SCODATA_PKT: - hdev->stat.cmd_tx++; - break; - } - - BTDRV_API_EXIT(0); -} - -/* ------- Interfaces to Shared Transport ------ */ - -/* Called by ST layer to indicate protocol registration completion - * status.hci_st_open() function will wait for signal from this - * API when st_register() function returns ST_PENDING. - */ -static void hci_st_registration_completion_cb(char data) -{ - BTDRV_API_START(); - - /* hci_st_open() function needs value of 'data' to know - * the registration status(success/fail),So have a back - * up of it. - */ - hst->streg_cbdata = data; - - /* Got a feedback from ST for BT driver registration - * request.Wackup hci_st_open() function to continue - * it's open operation. - */ - complete(&hst->wait_for_btdrv_reg_completion); - - BTDRV_API_EXIT(0); -} - -/* Called by Shared Transport layer when receive data is - * available */ -static long hci_st_receive(struct sk_buff *skb) -{ - int err; - int len; - - BTDRV_API_START(); - - err = 0; - len = 0; - - if (skb == NULL) { - BT_DRV_ERR("Invalid SKB received from ST"); - BTDRV_API_EXIT(-EFAULT); - return -EFAULT; - } - if (!hst) { - kfree_skb(skb); - BT_DRV_ERR("Invalid hci_st memory,freeing SKB"); - BTDRV_API_EXIT(-EFAULT); - return -EFAULT; - } - if (!test_bit(BT_DRV_RUNNING, &hst->flags)) { - kfree_skb(skb); - BT_DRV_ERR("Device is not running,freeing SKB"); - BTDRV_API_EXIT(-EINVAL); - return -EINVAL; - } - - len = skb->len; - skb->dev = (struct net_device *)hst->hdev; - - /* Forward skb to HCI CORE layer */ - err = hci_recv_frame(skb); - if (err) { - kfree_skb(skb); - BT_DRV_ERR("Unable to push skb to HCI CORE(%d),freeing SKB", - err); - BTDRV_API_EXIT(err); - return err; - } - hst->hdev->stat.byte_rx += len; - - BTDRV_API_EXIT(0); - return 0; -} - -/* ------- Interfaces to HCI layer ------ */ - -/* Called from HCI core to initialize the device */ -static int hci_st_open(struct hci_dev *hdev) -{ - static struct st_proto_s hci_st_proto; - unsigned long timeleft; - int err; - - BTDRV_API_START(); - - err = 0; - - BT_DRV_DBG("%s %p", hdev->name, hdev); - - /* Already registered with ST ? */ - if (test_bit(BT_ST_REGISTERED, &hst->flags)) { - BT_DRV_ERR("Registered with ST already,open called again?"); - BTDRV_API_EXIT(0); - return 0; - } - - /* Populate BT driver info required by ST */ - memset(&hci_st_proto, 0, sizeof(hci_st_proto)); - - /* BT driver ID */ - hci_st_proto.type = ST_BT; - - /* Receive function which called from ST */ - hci_st_proto.recv = hci_st_receive; - - /* Packet match function may used in future */ - hci_st_proto.match_packet = NULL; - - /* Callback to be called when registration is pending */ - hci_st_proto.reg_complete_cb = hci_st_registration_completion_cb; - - /* This is write function pointer of ST. BT driver will make use of this - * for sending any packets to chip. ST will assign and give to us, so - * make it as NULL */ - hci_st_proto.write = NULL; - - /* Register with ST layer */ - err = st_register(&hci_st_proto); - if (err == ST_ERR_PENDING) { - /* Prepare wait-for-completion handler data structures. - * Needed to syncronize this and st_registration_completion_cb() - * functions. - */ - init_completion(&hst->wait_for_btdrv_reg_completion); - - /* Reset ST registration callback status flag , this value - * will be updated in hci_st_registration_completion_cb() - * function whenever it called from ST driver. - */ - hst->streg_cbdata = -EINPROGRESS; - - /* ST is busy with other protocol registration(may be busy with - * firmware download).So,Wait till the registration callback - * (passed as a argument to st_register() function) getting - * called from ST. - */ - BT_DRV_DBG(" %s waiting for reg completion signal from ST", - __func__); - - timeleft = - wait_for_completion_timeout - (&hst->wait_for_btdrv_reg_completion, - msecs_to_jiffies(BT_REGISTER_TIMEOUT)); - if (!timeleft) { - BT_DRV_ERR("Timeout(%ld sec),didn't get reg" - "completion signal from ST", - BT_REGISTER_TIMEOUT / 1000); - BTDRV_API_EXIT(-ETIMEDOUT); - return -ETIMEDOUT; - } - - /* Is ST registration callback called with ERROR value? */ - if (hst->streg_cbdata != 0) { - BT_DRV_ERR("ST reg completion CB called with invalid" - "status %d", hst->streg_cbdata); - BTDRV_API_EXIT(-EAGAIN); - return -EAGAIN; - } - err = 0; - } else if (err == ST_ERR_FAILURE) { - BT_DRV_ERR("st_register failed %d", err); - BTDRV_API_EXIT(-EAGAIN); - return -EAGAIN; - } - - /* Do we have proper ST write function? */ - if (hci_st_proto.write != NULL) { - /* We need this pointer for sending any Bluetooth pkts */ - hst->st_write = hci_st_proto.write; - } else { - BT_DRV_ERR("failed to get ST write func pointer"); - - /* Undo registration with ST */ - err = st_unregister(ST_BT); - if (err < 0) - BT_DRV_ERR("st_unregister failed %d", err); - - hst->st_write = NULL; - BTDRV_API_EXIT(-EAGAIN); - return -EAGAIN; - } - - /* Registration with ST layer is completed successfully, - * now chip is ready to accept commands from HCI CORE. - * Mark HCI Device flag as RUNNING - */ - set_bit(HCI_RUNNING, &hdev->flags); - - /* Registration with ST successful */ - set_bit(BT_ST_REGISTERED, &hst->flags); - - BTDRV_API_EXIT(err); - return err; -} - -/* Close device */ -static int hci_st_close(struct hci_dev *hdev) -{ - int err; - - BTDRV_API_START(); - - err = 0; - - /* Unregister from ST layer */ - if (test_and_clear_bit(BT_ST_REGISTERED, &hst->flags)) { - err = st_unregister(ST_BT); - if (err != ST_SUCCESS) { - BT_DRV_ERR("st_unregister failed %d", err); - BTDRV_API_EXIT(-EBUSY); - return -EBUSY; - } - } - - hst->st_write = NULL; - - /* ST layer would have moved chip to inactive state. - * So,clear HCI device RUNNING flag. - */ - if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) { - BTDRV_API_EXIT(0); - return 0; - } - - BTDRV_API_EXIT(err); - return err; -} - -/* Called from HCI CORE , Sends frames to Shared Transport */ -static int hci_st_send_frame(struct sk_buff *skb) -{ - struct hci_dev *hdev; - struct hci_st *hst; - long len; - - BTDRV_API_START(); - - if (skb == NULL) { - BT_DRV_ERR("Invalid skb received from HCI CORE"); - BTDRV_API_EXIT(-ENOMEM); - return -ENOMEM; - } - hdev = (struct hci_dev *)skb->dev; - if (!hdev) { - BT_DRV_ERR("SKB received for invalid HCI Device (hdev=NULL)"); - BTDRV_API_EXIT(-ENODEV); - return -ENODEV; - } - if (!test_bit(HCI_RUNNING, &hdev->flags)) { - BT_DRV_ERR("Device is not running"); - BTDRV_API_EXIT(-EBUSY); - return -EBUSY; - } - - hst = (struct hci_st *)hdev->driver_data; - - /* Prepend skb with frame type */ - memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); - - BT_DRV_DBG(" %s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type, - skb->len); - - /* Insert skb to shared transport layer's transmit queue. - * Freeing skb memory is taken care in shared transport layer, - * so don't free skb memory here. - */ - if (!hst->st_write) { - kfree_skb(skb); - BT_DRV_ERR(" Can't write to ST, st_write null?"); - BTDRV_API_EXIT(-EAGAIN); - return -EAGAIN; - } - len = hst->st_write(skb); - if (len < 0) { - /* Something went wrong in st write , free skb memory */ - kfree_skb(skb); - BT_DRV_ERR(" ST write failed (%ld)", len); - BTDRV_API_EXIT(-EAGAIN); - return -EAGAIN; - } - - /* ST accepted our skb. So, Go ahead and do rest */ - hdev->stat.byte_tx += len; - hci_st_tx_complete(hst, bt_cb(skb)->pkt_type); - - BTDRV_API_EXIT(0); - return 0; -} - -static void hci_st_destruct(struct hci_dev *hdev) -{ - BTDRV_API_START(); - - if (!hdev) { - BT_DRV_ERR("Destruct called with invalid HCI Device" - "(hdev=NULL)"); - BTDRV_API_EXIT(0); - return; - } - - BT_DRV_DBG("%s", hdev->name); - - /* free hci_st memory */ - if (hdev->driver_data != NULL) - kfree(hdev->driver_data); - - BTDRV_API_EXIT(0); - return; -} - -/* Creates new HCI device */ -static int hci_st_register_dev(struct hci_st *hst) -{ - struct hci_dev *hdev; - - BTDRV_API_START(); - - /* Initialize and register HCI device */ - hdev = hci_alloc_dev(); - if (!hdev) { - BT_DRV_ERR("Can't allocate HCI device"); - BTDRV_API_EXIT(-ENOMEM); - return -ENOMEM; - } - BT_DRV_DBG(" HCI device allocated. hdev= %p", hdev); - - hst->hdev = hdev; - hdev->bus = HCI_UART; - hdev->driver_data = hst; - hdev->open = hci_st_open; - hdev->close = hci_st_close; - hdev->flush = NULL; - hdev->send = hci_st_send_frame; - hdev->destruct = hci_st_destruct; - hdev->owner = THIS_MODULE; - - if (reset) - set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); - - if (hci_register_dev(hdev) < 0) { - BT_DRV_ERR("Can't register HCI device"); - hci_free_dev(hdev); - BTDRV_API_EXIT(-ENODEV); - return -ENODEV; - } - - BT_DRV_DBG(" HCI device registered. hdev= %p", hdev); - BTDRV_API_EXIT(0); - return 0; -} - -/* ------- Module Init interface ------ */ - -static int __init bt_drv_init(void) -{ - int err; - - BTDRV_API_START(); - - err = 0; - - BT_DRV_DBG(" Bluetooth Driver Version %s", VERSION); - - /* Allocate local resource memory */ - hst = kzalloc(sizeof(struct hci_st), GFP_KERNEL); - if (!hst) { - BT_DRV_ERR("Can't allocate control structure"); - BTDRV_API_EXIT(-ENFILE); - return -ENFILE; - } - - /* Expose "hciX" device to user space */ - err = hci_st_register_dev(hst); - if (err) { - /* Release local resource memory */ - kfree(hst); - - BT_DRV_ERR("Unable to expose hci0 device(%d)", err); - BTDRV_API_EXIT(err); - return err; - } - set_bit(BT_DRV_RUNNING, &hst->flags); - - BTDRV_API_EXIT(err); - return err; -} - -/* ------- Module Exit interface ------ */ - -static void __exit bt_drv_exit(void) -{ - BTDRV_API_START(); - - /* Deallocate local resource's memory */ - if (hst) { - struct hci_dev *hdev = hst->hdev; - - if (hdev == NULL) { - BT_DRV_ERR("Invalid hdev memory"); - kfree(hst); - } else { - hci_st_close(hdev); - if (test_and_clear_bit(BT_DRV_RUNNING, &hst->flags)) { - /* Remove HCI device (hciX) created - * in module init. - */ - hci_unregister_dev(hdev); - - /* Free HCI device memory */ - hci_free_dev(hdev); - } - } - } - BTDRV_API_EXIT(0); -} - -module_init(bt_drv_init); -module_exit(bt_drv_exit); - -/* ------ Module Info ------ */ - -module_param(reset, bool, 0644); -MODULE_PARM_DESC(reset, "Send HCI reset command on initialization"); -MODULE_AUTHOR("Raja Mani <raja_mani@ti.com>"); -MODULE_DESCRIPTION("Bluetooth Driver for TI Shared Transport" VERSION); -MODULE_VERSION(VERSION); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/ti-st/bt_drv.h b/drivers/staging/ti-st/bt_drv.h deleted file mode 100644 index a0beebec846..00000000000 --- a/drivers/staging/ti-st/bt_drv.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Texas Instrument's Bluetooth Driver For Shared Transport. - * - * Bluetooth Driver acts as interface between HCI CORE and - * TI Shared Transport Layer. - * - * 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 _BT_DRV_H -#define _BT_DRV_H - -/* Bluetooth Driver Version */ -#define VERSION "1.0" - -/* Defines number of seconds to wait for reg completion - * callback getting called from ST (in case,registration - * with ST returns PENDING status) - */ -#define BT_REGISTER_TIMEOUT msecs_to_jiffies(6000) /* 6 sec */ - -/* BT driver's local status */ -#define BT_DRV_RUNNING 0 -#define BT_ST_REGISTERED 1 - -/* BT driver operation structure */ -struct hci_st { - - /* hci device pointer which binds to bt driver */ - struct hci_dev *hdev; - - /* used locally,to maintain various BT driver status */ - unsigned long flags; - - /* to hold ST registration callback status */ - char streg_cbdata; - - /* write function pointer of ST driver */ - long (*st_write) (struct sk_buff *); - - /* Wait on comepletion handler needed to synchronize - * hci_st_open() and hci_st_registration_completion_cb() - * functions.*/ - struct completion wait_for_btdrv_reg_completion; -}; - -#endif diff --git a/drivers/staging/ti-st/fm.h b/drivers/staging/ti-st/fm.h deleted file mode 100644 index be41453649e..00000000000 --- a/drivers/staging/ti-st/fm.h +++ /dev/null @@ -1,13 +0,0 @@ -struct fm_event_hdr { - unsigned char plen; -} __attribute__ ((packed)); - -#define FM_MAX_FRAME_SIZE 0xFF /* TODO: */ -#define FM_EVENT_HDR_SIZE 1 /* size of fm_event_hdr */ -#define ST_FM_CH8_PKT 0x8 - -/* gps stuff */ -struct gps_event_hdr { -unsigned char opcode; -unsigned short plen; -} __attribute__ ((packed)); diff --git a/drivers/staging/ti-st/st.h b/drivers/staging/ti-st/st.h deleted file mode 100644 index e8fc97e32c9..00000000000 --- a/drivers/staging/ti-st/st.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Shared Transport Header file - * To be included by the protocol stack drivers for - * Texas Instruments BT,FM and GPS combo chip drivers - * - * 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_H -#define ST_H - -#include <linux/skbuff.h> -/* - * st.h - */ - -/* TODO: - * Move the following to tty.h upon acceptance - */ -#define N_TI_WL 20 /* Ldisc for TI's WL BT, FM, GPS combo chips */ - -/* some gpios have active high, others like fm have - * active low - */ -enum kim_gpio_state { - KIM_GPIO_INACTIVE, - KIM_GPIO_ACTIVE, -}; -/* - * the list of protocols on chip - */ -enum proto_type { - ST_BT, - ST_FM, - ST_GPS, - ST_MAX, -}; - -enum { - ST_ERR_FAILURE = -1, /* check struct */ - ST_SUCCESS, - ST_ERR_PENDING = -5, /* to call reg_complete_cb */ - ST_ERR_ALREADY, /* already registered */ - ST_ERR_INPROGRESS, - ST_ERR_NOPROTO, /* protocol not supported */ -}; - -/* per protocol structure - * for BT/FM and GPS - */ -struct st_proto_s { - enum proto_type type; -/* - * to be called by ST when data arrives - */ - long (*recv) (struct sk_buff *); -/* - * for future use, logic now to be in ST - */ - unsigned char (*match_packet) (const unsigned char *data); -/* - * subsequent registration return PENDING, - * signalled complete by this callback function - */ - void (*reg_complete_cb) (char data); -/* - * write function, sent in as NULL and to be returned to - * protocol drivers - */ - long (*write) (struct sk_buff *skb); -}; - -extern long st_register(struct st_proto_s *new_proto); -extern long st_unregister(enum proto_type type); - -#endif /* ST_H */ diff --git a/drivers/staging/ti-st/st_core.c b/drivers/staging/ti-st/st_core.c deleted file mode 100644 index 4e93694e1c2..00000000000 --- a/drivers/staging/ti-st/st_core.c +++ /dev/null @@ -1,1062 +0,0 @@ -/* - * 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 <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/tty.h> - -/* understand BT, FM and GPS for now */ -#include <net/bluetooth/bluetooth.h> -#include <net/bluetooth/hci_core.h> -#include <net/bluetooth/hci.h> -#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 deleted file mode 100644 index f271c88a808..00000000000 --- a/drivers/staging/ti-st/st_core.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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 <linux/skbuff.h> -#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 */ diff --git a/drivers/staging/ti-st/st_kim.c b/drivers/staging/ti-st/st_kim.c deleted file mode 100644 index 98cbabba384..00000000000 --- a/drivers/staging/ti-st/st_kim.c +++ /dev/null @@ -1,754 +0,0 @@ -/* - * Shared Transport Line discipline driver Core - * Init Manager module responsible for GPIO control - * and firmware download - * 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) "(stk) :" fmt -#include <linux/platform_device.h> -#include <linux/jiffies.h> -#include <linux/firmware.h> -#include <linux/delay.h> -#include <linux/wait.h> -#include <linux/gpio.h> - -#include <linux/sched.h> - -#include "st_kim.h" -/* understand BT events for fw response */ -#include <net/bluetooth/bluetooth.h> -#include <net/bluetooth/hci_core.h> -#include <net/bluetooth/hci.h> - - -static int kim_probe(struct platform_device *pdev); -static int kim_remove(struct platform_device *pdev); - -/* KIM platform device driver structure */ -static struct platform_driver kim_platform_driver = { - .probe = kim_probe, - .remove = kim_remove, - /* TODO: ST driver power management during suspend/resume ? - */ -#if 0 - .suspend = kim_suspend, - .resume = kim_resume, -#endif - .driver = { - .name = "kim", - .owner = THIS_MODULE, - }, -}; - -#ifndef LEGACY_RFKILL_SUPPORT -static ssize_t show_pid(struct device *dev, struct device_attribute - *attr, char *buf); -static ssize_t store_pid(struct device *dev, struct device_attribute - *devattr, char *buf, size_t count); -static ssize_t show_list(struct device *dev, struct device_attribute - *attr, char *buf); - -/* structures specific for sysfs entries */ -static struct kobj_attribute pid_attr = -__ATTR(pid, 0644, (void *)show_pid, (void *)store_pid); - -static struct kobj_attribute list_protocols = -__ATTR(protocols, 0444, (void *)show_list, NULL); - -static struct attribute *uim_attrs[] = { - &pid_attr.attr, - /* add more debug sysfs entries */ - &list_protocols.attr, - NULL, -}; - -static struct attribute_group uim_attr_grp = { - .attrs = uim_attrs, -}; -#else -static int kim_toggle_radio(void*, bool); -static const struct rfkill_ops kim_rfkill_ops = { - .set_block = kim_toggle_radio, -}; -#endif /* LEGACY_RFKILL_SUPPORT */ - -/* 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_names[] = { - PROTO_ENTRY(ST_BT, "Bluetooth"), - PROTO_ENTRY(ST_FM, "FM"), - PROTO_ENTRY(ST_GPS, "GPS"), -}; - -struct kim_data_s *kim_gdata; - -/**********************************************************************/ -/* internal functions */ - -/* - * function to return whether the firmware response was proper - * in case of error don't complete so that waiting for proper - * response times out - */ -void validate_firmware_response(struct sk_buff *skb) -{ - if (unlikely(skb->data[5] != 0)) { - pr_err("no proper response during fw download"); - pr_err("data6 %x", skb->data[5]); - return; /* keep waiting for the proper response */ - } - /* becos of all the script being downloaded */ - complete_all(&kim_gdata->kim_rcvd); - kfree_skb(skb); -} - -/* check for data len received inside kim_int_recv - * most often hit the last case to update state to waiting for data - */ -static inline int kim_check_data_len(int len) -{ - register int room = skb_tailroom(kim_gdata->rx_skb); - - pr_info("len %d room %d", len, room); - - if (!len) { - validate_firmware_response(kim_gdata->rx_skb); - } 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(kim_gdata->rx_skb); - } else { - /* Packet header has non-zero payload length and - * we have enough space in created skb. Lets read - * payload data */ - kim_gdata->rx_state = ST_BT_W4_DATA; - kim_gdata->rx_count = len; - return len; - } - - /* Change ST LL state to continue to process next - * packet */ - kim_gdata->rx_state = ST_W4_PACKET_TYPE; - kim_gdata->rx_skb = NULL; - kim_gdata->rx_count = 0; - - return 0; -} - -/* receive function called during firmware download - * - firmware download responses on different UART drivers - * have been observed to come in bursts of different - * tty_receive and hence the logic - */ -void kim_int_recv(const unsigned char *data, long count) -{ - register char *ptr; - struct hci_event_hdr *eh; - register int len = 0, type = 0; - - pr_info("%s", __func__); - /* Decode received bytes here */ - ptr = (char *)data; - if (unlikely(ptr == NULL)) { - pr_err(" received null from TTY "); - return; - } - while (count) { - if (kim_gdata->rx_count) { - len = min_t(unsigned int, kim_gdata->rx_count, count); - memcpy(skb_put(kim_gdata->rx_skb, len), ptr, len); - kim_gdata->rx_count -= len; - count -= len; - ptr += len; - - if (kim_gdata->rx_count) - continue; - - /* Check ST RX state machine , where are we? */ - switch (kim_gdata->rx_state) { - /* Waiting for complete packet ? */ - case ST_BT_W4_DATA: - pr_info("Complete pkt received"); - validate_firmware_response(kim_gdata->rx_skb); - kim_gdata->rx_state = ST_W4_PACKET_TYPE; - kim_gdata->rx_skb = NULL; - continue; - /* Waiting for Bluetooth event header ? */ - case ST_BT_W4_EVENT_HDR: - eh = (struct hci_event_hdr *)kim_gdata-> - rx_skb->data; - pr_info("Event header: evt 0x%2.2x" - "plen %d", eh->evt, eh->plen); - kim_check_data_len(eh->plen); - continue; - } /* end of switch */ - } /* end of if rx_state */ - switch (*ptr) { - /* Bluetooth event packet? */ - case HCI_EVENT_PKT: - pr_info("Event packet"); - kim_gdata->rx_state = ST_BT_W4_EVENT_HDR; - kim_gdata->rx_count = HCI_EVENT_HDR_SIZE; - type = HCI_EVENT_PKT; - break; - default: - pr_info("unknown packet"); - ptr++; - count--; - continue; - } /* end of switch *ptr */ - ptr++; - count--; - kim_gdata->rx_skb = - bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); - if (!kim_gdata->rx_skb) { - pr_err("can't allocate mem for new packet"); - kim_gdata->rx_state = ST_W4_PACKET_TYPE; - kim_gdata->rx_count = 0; - return; - } /* not necessary in this case */ - bt_cb(kim_gdata->rx_skb)->pkt_type = type; - } /* end of while count */ - pr_info("done %s", __func__); - return; -} - -static long read_local_version(char *bts_scr_name) -{ - unsigned short version = 0, chip = 0, min_ver = 0, maj_ver = 0; - char read_ver_cmd[] = { 0x01, 0x01, 0x10, 0x00 }; - - pr_info("%s", __func__); - - INIT_COMPLETION(kim_gdata->kim_rcvd); - if (4 != st_int_write(kim_gdata->core_data, read_ver_cmd, 4)) { - pr_err("kim: couldn't write 4 bytes"); - return ST_ERR_FAILURE; - } - - if (!wait_for_completion_timeout - (&kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) { - pr_err(" waiting for ver info- timed out "); - return ST_ERR_FAILURE; - } - - version = - MAKEWORD(kim_gdata->resp_buffer[13], kim_gdata->resp_buffer[14]); - chip = (version & 0x7C00) >> 10; - min_ver = (version & 0x007F); - maj_ver = (version & 0x0380) >> 7; - - if (version & 0x8000) - maj_ver |= 0x0008; - - sprintf(bts_scr_name, "TIInit_%d.%d.%d.bts", chip, maj_ver, min_ver); - pr_info("%s", bts_scr_name); - return ST_SUCCESS; -} - -/* internal function which parses through the .bts firmware script file - * intreprets SEND, DELAY actions only as of now - */ -static long download_firmware(void) -{ - long err = ST_SUCCESS; - long len = 0; - register unsigned char *ptr = NULL; - register unsigned char *action_ptr = NULL; - unsigned char bts_scr_name[30] = { 0 }; /* 30 char long bts scr name? */ - - pr_info("%s", __func__); - - err = read_local_version(bts_scr_name); - if (err != ST_SUCCESS) { - pr_err("kim: failed to read local ver"); - return err; - } - err = - request_firmware(&kim_gdata->fw_entry, bts_scr_name, - &kim_gdata->kim_pdev->dev); - if (unlikely((err != 0) || (kim_gdata->fw_entry->data == NULL) || - (kim_gdata->fw_entry->size == 0))) { - pr_err(" request_firmware failed(errno %ld) for %s", err, - bts_scr_name); - return ST_ERR_FAILURE; - } - ptr = (void *)kim_gdata->fw_entry->data; - len = kim_gdata->fw_entry->size; - /* bts_header to remove out magic number and - * version - */ - ptr += sizeof(struct bts_header); - len -= sizeof(struct bts_header); - - while (len > 0 && ptr) { - pr_info(" action size %d, type %d ", - ((struct bts_action *)ptr)->size, - ((struct bts_action *)ptr)->type); - - switch (((struct bts_action *)ptr)->type) { - case ACTION_SEND_COMMAND: /* action send */ - action_ptr = &(((struct bts_action *)ptr)->data[0]); - if (unlikely - (((struct hci_command *)action_ptr)->opcode == - 0xFF36)) { - /* ignore remote change - * baud rate HCI VS command */ - pr_err - (" change remote baud\ - rate command in firmware"); - break; - } - - INIT_COMPLETION(kim_gdata->kim_rcvd); - err = st_int_write(kim_gdata->core_data, - ((struct bts_action_send *)action_ptr)->data, - ((struct bts_action *)ptr)->size); - if (unlikely(err < 0)) { - release_firmware(kim_gdata->fw_entry); - return ST_ERR_FAILURE; - } - if (!wait_for_completion_timeout - (&kim_gdata->kim_rcvd, - msecs_to_jiffies(CMD_RESP_TIME))) { - pr_err - (" response timeout during fw download "); - /* timed out */ - release_firmware(kim_gdata->fw_entry); - return ST_ERR_FAILURE; - } - break; - case ACTION_DELAY: /* sleep */ - pr_info("sleep command in scr"); - action_ptr = &(((struct bts_action *)ptr)->data[0]); - mdelay(((struct bts_action_delay *)action_ptr)->msec); - break; - } - len = - len - (sizeof(struct bts_action) + - ((struct bts_action *)ptr)->size); - ptr = - ptr + sizeof(struct bts_action) + - ((struct bts_action *)ptr)->size; - } - /* fw download complete */ - release_firmware(kim_gdata->fw_entry); - return ST_SUCCESS; -} - -/**********************************************************************/ -/* functions called from ST core */ - -/* function to toggle the GPIO - * needs to know whether the GPIO is active high or active low - */ -void st_kim_chip_toggle(enum proto_type type, enum kim_gpio_state state) -{ - pr_info(" %s ", __func__); - - if (kim_gdata->gpios[type] == -1) { - pr_info(" gpio not requested for protocol %s", - protocol_names[type]); - return; - } - switch (type) { - case ST_BT: - /*Do Nothing */ - break; - - case ST_FM: - if (state == KIM_GPIO_ACTIVE) - gpio_set_value(kim_gdata->gpios[ST_FM], GPIO_LOW); - else - gpio_set_value(kim_gdata->gpios[ST_FM], GPIO_HIGH); - break; - - case ST_GPS: - if (state == KIM_GPIO_ACTIVE) - gpio_set_value(kim_gdata->gpios[ST_GPS], GPIO_HIGH); - else - gpio_set_value(kim_gdata->gpios[ST_GPS], GPIO_LOW); - break; - - case ST_MAX: - default: - break; - } - - return; -} - -/* called from ST Core, when REG_IN_PROGRESS (registration in progress) - * can be because of - * 1. response to read local version - * 2. during send/recv's of firmware download - */ -void st_kim_recv(void *disc_data, const unsigned char *data, long count) -{ - pr_info(" %s ", __func__); - /* copy to local buffer */ - if (unlikely(data[4] == 0x01 && data[5] == 0x10 && data[0] == 0x04)) { - /* must be the read_ver_cmd */ - memcpy(kim_gdata->resp_buffer, data, count); - complete_all(&kim_gdata->kim_rcvd); - return; - } else { - kim_int_recv(data, count); - /* either completes or times out */ - } - return; -} - -/* to signal completion of line discipline installation - * called from ST Core, upon tty_open - */ -void st_kim_complete(void) -{ - complete(&kim_gdata->ldisc_installed); -} - -/* called from ST Core upon 1st registration -*/ -long st_kim_start(void) -{ - long err = ST_SUCCESS; - long retry = POR_RETRY_COUNT; - pr_info(" %s", __func__); - - do { -#ifdef LEGACY_RFKILL_SUPPORT - /* TODO: this is only because rfkill sub-system - * doesn't send events to user-space if the state - * isn't changed - */ - rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 1); -#endif - /* Configure BT nShutdown to HIGH state */ - gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW); - mdelay(5); /* FIXME: a proper toggle */ - gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_HIGH); - mdelay(100); - /* re-initialize the completion */ - INIT_COMPLETION(kim_gdata->ldisc_installed); -#ifndef LEGACY_RFKILL_SUPPORT - /* send signal to UIM */ - err = kill_pid(find_get_pid(kim_gdata->uim_pid), SIGUSR2, 0); - if (err != 0) { - pr_info(" sending SIGUSR2 to uim failed %ld", err); - err = ST_ERR_FAILURE; - continue; - } -#else - /* unblock and send event to UIM via /dev/rfkill */ - rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 0); -#endif - /* wait for ldisc to be installed */ - err = wait_for_completion_timeout(&kim_gdata->ldisc_installed, - msecs_to_jiffies(LDISC_TIME)); - if (!err) { /* timeout */ - pr_err("line disc installation timed out "); - err = ST_ERR_FAILURE; - continue; - } else { - /* ldisc installed now */ - pr_info(" line discipline installed "); - err = download_firmware(); - if (err != ST_SUCCESS) { - pr_err("download firmware failed"); - continue; - } else { /* on success don't retry */ - break; - } - } - } while (retry--); - return err; -} - -/* called from ST Core, on the last un-registration -*/ -long st_kim_stop(void) -{ - long err = ST_SUCCESS; - - INIT_COMPLETION(kim_gdata->ldisc_installed); -#ifndef LEGACY_RFKILL_SUPPORT - /* send signal to UIM */ - err = kill_pid(find_get_pid(kim_gdata->uim_pid), SIGUSR2, 1); - if (err != 0) { - pr_err("sending SIGUSR2 to uim failed %ld", err); - return ST_ERR_FAILURE; - } -#else - /* set BT rfkill to be blocked */ - err = rfkill_set_hw_state(kim_gdata->rfkill[ST_BT], 1); -#endif - - /* wait for ldisc to be un-installed */ - err = wait_for_completion_timeout(&kim_gdata->ldisc_installed, - msecs_to_jiffies(LDISC_TIME)); - if (!err) { /* timeout */ - pr_err(" timed out waiting for ldisc to be un-installed"); - return ST_ERR_FAILURE; - } - - /* By default configure BT nShutdown to LOW state */ - gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW); - mdelay(1); - gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_HIGH); - mdelay(1); - gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW); - return err; -} - -/**********************************************************************/ -/* functions called from subsystems */ - -#ifndef LEGACY_RFKILL_SUPPORT -/* called when sysfs entry is written to */ -static ssize_t store_pid(struct device *dev, struct device_attribute - *devattr, char *buf, size_t count) -{ - pr_info("%s: pid %s ", __func__, buf); - sscanf(buf, "%ld", &kim_gdata->uim_pid); - /* to be made use by kim_start to signal SIGUSR2 - */ - return strlen(buf); -} - -/* called when sysfs entry is read from */ -static ssize_t show_pid(struct device *dev, struct device_attribute - *attr, char *buf) -{ - sprintf(buf, "%ld", kim_gdata->uim_pid); - return strlen(buf); -} - -/* called when sysfs entry is read from */ -static ssize_t show_list(struct device *dev, struct device_attribute - *attr, char *buf) -{ - kim_st_list_protocols(kim_gdata->core_data, buf); - return strlen(buf); -} - -#else /* LEGACY_RFKILL_SUPPORT */ - -/* function called from rfkill subsystem, when someone from - * user space would write 0/1 on the sysfs entry - * /sys/class/rfkill/rfkill0,1,3/state - */ -static int kim_toggle_radio(void *data, bool blocked) -{ - enum proto_type type = *((enum proto_type *)data); - pr_info(" %s: %d ", __func__, type); - - switch (type) { - case ST_BT: - /* do nothing */ - break; - case ST_FM: - case ST_GPS: - if (blocked) - st_kim_chip_toggle(type, KIM_GPIO_INACTIVE); - else - st_kim_chip_toggle(type, KIM_GPIO_ACTIVE); - break; - case ST_MAX: - pr_err(" wrong proto type "); - break; - } - return ST_SUCCESS; -} - -#endif /* LEGACY_RFKILL_SUPPORT */ - -void st_kim_ref(struct st_data_s **core_data) -{ - *core_data = kim_gdata->core_data; -} - -/**********************************************************************/ -/* functions called from platform device driver subsystem - * need to have a relevant platform device entry in the platform's - * board-*.c file - */ - -static int kim_probe(struct platform_device *pdev) -{ - long status; - long proto; - long *gpios = pdev->dev.platform_data; - - status = st_core_init(&kim_gdata->core_data); - if (status != 0) { - pr_err(" ST core init failed"); - return ST_ERR_FAILURE; - } - - for (proto = 0; proto < ST_MAX; proto++) { - kim_gdata->gpios[proto] = gpios[proto]; - pr_info(" %ld gpio to be requested", gpios[proto]); - } - - for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) { - /* Claim the Bluetooth/FM/GPIO - * nShutdown gpio from the system - */ - status = gpio_request(gpios[proto], "kim"); - if (unlikely(status)) { - pr_err(" gpio %ld request failed ", gpios[proto]); - proto -= 1; - while (proto >= 0) { - if (gpios[proto] != -1) - gpio_free(gpios[proto]); - } - return status; - } - - /* Configure nShutdown GPIO as output=0 */ - status = - gpio_direction_output(gpios[proto], 0); - if (unlikely(status)) { - pr_err(" unable to configure gpio %ld", - gpios[proto]); - proto -= 1; - while (proto >= 0) { - if (gpios[proto] != -1) - gpio_free(gpios[proto]); - } - return status; - } - } -#ifndef LEGACY_RFKILL_SUPPORT - /* pdev to contain BT, FM and GPS enable/N-Shutdown GPIOs - * execute request_gpio, set output direction - */ - kim_gdata->kim_kobj = kobject_create_and_add("uim", NULL); - /* create the sysfs entry for UIM to put in pid */ - if (sysfs_create_group(kim_gdata->kim_kobj, &uim_attr_grp)) { - pr_err(" sysfs entry creation failed"); - kobject_put(kim_gdata->kim_kobj); - /* free requested GPIOs and fail probe */ - for (proto = ST_BT; proto < ST_MAX; proto++) { - if (gpios[proto] != -1) - gpio_free(gpios[proto]); - } - return -1; /* fail insmod */ - } - pr_info(" sysfs entry created "); -#endif - /* get reference of pdev for request_firmware - */ - kim_gdata->kim_pdev = pdev; - init_completion(&kim_gdata->kim_rcvd); - init_completion(&kim_gdata->ldisc_installed); -#ifdef LEGACY_RFKILL_SUPPORT - for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) { - /* TODO: should all types be rfkill_type_bt ? */ - kim_gdata->rf_protos[proto] = proto; - kim_gdata->rfkill[proto] = rfkill_alloc(protocol_names[proto], - &pdev->dev, RFKILL_TYPE_BLUETOOTH, - &kim_rfkill_ops, &kim_gdata->rf_protos[proto]); - if (kim_gdata->rfkill[proto] == NULL) { - pr_err("cannot create rfkill entry for gpio %ld", - gpios[proto]); - continue; - } - /* block upon creation */ - rfkill_init_sw_state(kim_gdata->rfkill[proto], 1); - status = rfkill_register(kim_gdata->rfkill[proto]); - if (unlikely(status)) { - pr_err("rfkill registration failed for gpio %ld", - gpios[proto]); - rfkill_unregister(kim_gdata->rfkill[proto]); - continue; - } - pr_info("rfkill entry created for %ld", gpios[proto]); - } -#endif - return ST_SUCCESS; -} - -static int kim_remove(struct platform_device *pdev) -{ - /* free the GPIOs requested - */ - long *gpios = pdev->dev.platform_data; - long proto; - - for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) { - /* Claim the Bluetooth/FM/GPIO - * nShutdown gpio from the system - */ - gpio_free(gpios[proto]); -#ifdef LEGACY_RFKILL_SUPPORT - rfkill_unregister(kim_gdata->rfkill[proto]); - rfkill_destroy(kim_gdata->rfkill[proto]); - kim_gdata->rfkill[proto] = NULL; -#endif - } - pr_info("kim: GPIO Freed"); -#ifndef LEGACY_RFKILL_SUPPORT - /* delete the sysfs entries */ - sysfs_remove_group(kim_gdata->kim_kobj, &uim_attr_grp); - kobject_put(kim_gdata->kim_kobj); -#endif - kim_gdata->kim_pdev = NULL; - st_core_exit(kim_gdata->core_data); - return ST_SUCCESS; -} - -/**********************************************************************/ -/* entry point for ST KIM module, called in from ST Core */ - -static int __init st_kim_init(void) -{ - long ret = ST_SUCCESS; - kim_gdata = kzalloc(sizeof(struct kim_data_s), GFP_ATOMIC); - if (!kim_gdata) { - pr_err("no mem to allocate"); - return -ENOMEM; - } - - ret = platform_driver_register(&kim_platform_driver); - if (ret != 0) { - pr_err("platform drv registration failed"); - return ST_ERR_FAILURE; - } - return ST_SUCCESS; -} - -static void __exit st_kim_deinit(void) -{ - /* the following returns void */ - platform_driver_unregister(&kim_platform_driver); - kfree(kim_gdata); - kim_gdata = NULL; -} - - -module_init(st_kim_init); -module_exit(st_kim_deinit); -MODULE_AUTHOR("Pavan Savoy <pavan_savoy@ti.com>"); -MODULE_DESCRIPTION("Shared Transport Driver for TI BT/FM/GPS combo chips "); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/ti-st/st_kim.h b/drivers/staging/ti-st/st_kim.h deleted file mode 100644 index ff3270ec784..00000000000 --- a/drivers/staging/ti-st/st_kim.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Shared Transport Line discipline driver Core - * Init Manager Module 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_KIM_H -#define ST_KIM_H - -#include <linux/types.h> -#include "st.h" -#include "st_core.h" -#include "st_ll.h" -#include <linux/rfkill.h> - -/* time in msec to wait for - * line discipline to be installed - */ -#define LDISC_TIME 500 -#define CMD_RESP_TIME 500 -#define MAKEWORD(a, b) ((unsigned short)(((unsigned char)(a)) \ - | ((unsigned short)((unsigned char)(b))) << 8)) - -#define GPIO_HIGH 1 -#define GPIO_LOW 0 - -/* the Power-On-Reset logic, requires to attempt - * to download firmware onto chip more than once - * since the self-test for chip takes a while - */ -#define POR_RETRY_COUNT 5 -/* - * legacy rfkill support where-in 3 rfkill - * devices are created for the 3 gpios - * that ST has requested - */ -#define LEGACY_RFKILL_SUPPORT -/* - * header file for ST provided by KIM - */ -struct kim_data_s { - long uim_pid; - struct platform_device *kim_pdev; - struct completion kim_rcvd, ldisc_installed; - /* MAX len of the .bts firmware script name */ - char resp_buffer[30]; - const struct firmware *fw_entry; - long gpios[ST_MAX]; - struct kobject *kim_kobj; -/* used by kim_int_recv to validate fw response */ - unsigned long rx_state; - unsigned long rx_count; - struct sk_buff *rx_skb; -#ifdef LEGACY_RFKILL_SUPPORT - struct rfkill *rfkill[ST_MAX]; - enum proto_type rf_protos[ST_MAX]; -#endif - struct st_data_s *core_data; -}; - -long st_kim_start(void); -long st_kim_stop(void); -/* - * called from st_tty_receive to authenticate fw_download - */ -void st_kim_recv(void *, const unsigned char *, long count); - -void st_kim_chip_toggle(enum proto_type, enum kim_gpio_state); - -void st_kim_complete(void); - -/* function called from ST KIM to ST Core, to - * list out the protocols registered - */ -void kim_st_list_protocols(struct st_data_s *, char *); - -/* - * BTS headers - */ -#define ACTION_SEND_COMMAND 1 -#define ACTION_WAIT_EVENT 2 -#define ACTION_SERIAL 3 -#define ACTION_DELAY 4 -#define ACTION_RUN_SCRIPT 5 -#define ACTION_REMARKS 6 - -/* - * * BRF Firmware header - * */ -struct bts_header { - uint32_t magic; - uint32_t version; - uint8_t future[24]; - uint8_t actions[0]; -} __attribute__ ((packed)); - -/* - * * BRF Actions structure - * */ -struct bts_action { - uint16_t type; - uint16_t size; - uint8_t data[0]; -} __attribute__ ((packed)); - -struct bts_action_send { - uint8_t data[0]; -} __attribute__ ((packed)); - -struct bts_action_wait { - uint32_t msec; - uint32_t size; - uint8_t data[0]; -} __attribute__ ((packed)); - -struct bts_action_delay { - uint32_t msec; -} __attribute__ ((packed)); - -struct bts_action_serial { - uint32_t baud; - uint32_t flow_control; -} __attribute__ ((packed)); - -/* for identifying the change speed HCI VS - * command - */ -struct hci_command { - uint8_t prefix; - uint16_t opcode; - uint8_t plen; - uint32_t speed; -} __attribute__ ((packed)); - - -#endif /* ST_KIM_H */ diff --git a/drivers/staging/ti-st/st_ll.c b/drivers/staging/ti-st/st_ll.c deleted file mode 100644 index 0685a100db6..00000000000 --- a/drivers/staging/ti-st/st_ll.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Shared Transport driver - * HCI-LL module responsible for TI proprietary HCI_LL protocol - * 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) "(stll) :" fmt -#include "st_ll.h" - -/**********************************************************************/ -/* internal functions */ -static void send_ll_cmd(struct st_data_s *st_data, - unsigned char cmd) -{ - - pr_info("%s: writing %x", __func__, cmd); - st_int_write(st_data, &cmd, 1); - return; -} - -static void ll_device_want_to_sleep(struct st_data_s *st_data) -{ - pr_info("%s", __func__); - /* sanity check */ - if (st_data->ll_state != ST_LL_AWAKE) - pr_err("ERR hcill: ST_LL_GO_TO_SLEEP_IND" - "in state %ld", st_data->ll_state); - - send_ll_cmd(st_data, LL_SLEEP_ACK); - /* update state */ - st_data->ll_state = ST_LL_ASLEEP; -} - -static void ll_device_want_to_wakeup(struct st_data_s *st_data) -{ - /* diff actions in diff states */ - switch (st_data->ll_state) { - case ST_LL_ASLEEP: - send_ll_cmd(st_data, LL_WAKE_UP_ACK); /* send wake_ack */ - break; - case ST_LL_ASLEEP_TO_AWAKE: - /* duplicate wake_ind */ - pr_err("duplicate wake_ind while waiting for Wake ack"); - break; - case ST_LL_AWAKE: - /* duplicate wake_ind */ - pr_err("duplicate wake_ind already AWAKE"); - break; - case ST_LL_AWAKE_TO_ASLEEP: - /* duplicate wake_ind */ - pr_err("duplicate wake_ind"); - break; - } - /* update state */ - st_data->ll_state = ST_LL_AWAKE; -} - -/**********************************************************************/ -/* functions invoked by ST Core */ - -/* called when ST Core wants to - * enable ST LL */ -void st_ll_enable(struct st_data_s *ll) -{ - ll->ll_state = ST_LL_AWAKE; -} - -/* called when ST Core /local module wants to - * disable ST LL */ -void st_ll_disable(struct st_data_s *ll) -{ - ll->ll_state = ST_LL_INVALID; -} - -/* called when ST Core wants to update the state */ -void st_ll_wakeup(struct st_data_s *ll) -{ - if (likely(ll->ll_state != ST_LL_AWAKE)) { - send_ll_cmd(ll, LL_WAKE_UP_IND); /* WAKE_IND */ - ll->ll_state = ST_LL_ASLEEP_TO_AWAKE; - } else { - /* don't send the duplicate wake_indication */ - pr_err(" Chip already AWAKE "); - } -} - -/* called when ST Core wants the state */ -unsigned long st_ll_getstate(struct st_data_s *ll) -{ - pr_info(" returning state %ld", ll->ll_state); - return ll->ll_state; -} - -/* called from ST Core, when a PM related packet arrives */ -unsigned long st_ll_sleep_state(struct st_data_s *st_data, - unsigned char cmd) -{ - switch (cmd) { - case LL_SLEEP_IND: /* sleep ind */ - pr_info("sleep indication recvd"); - ll_device_want_to_sleep(st_data); - break; - case LL_SLEEP_ACK: /* sleep ack */ - pr_err("sleep ack rcvd: host shouldn't"); - break; - case LL_WAKE_UP_IND: /* wake ind */ - pr_info("wake indication recvd"); - ll_device_want_to_wakeup(st_data); - break; - case LL_WAKE_UP_ACK: /* wake ack */ - pr_info("wake ack rcvd"); - st_data->ll_state = ST_LL_AWAKE; - break; - default: - pr_err(" unknown input/state "); - return ST_ERR_FAILURE; - } - return ST_SUCCESS; -} - -/* Called from ST CORE to initialize ST LL */ -long st_ll_init(struct st_data_s *ll) -{ - /* set state to invalid */ - ll->ll_state = ST_LL_INVALID; - return 0; -} - -/* Called from ST CORE to de-initialize ST LL */ -long st_ll_deinit(struct st_data_s *ll) -{ - return 0; -} diff --git a/drivers/staging/ti-st/st_ll.h b/drivers/staging/ti-st/st_ll.h deleted file mode 100644 index 77dfbf07e7b..00000000000 --- a/drivers/staging/ti-st/st_ll.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Shared Transport Low Level (ST LL) - * - * 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_LL_H -#define ST_LL_H - -#include <linux/skbuff.h> -#include "st.h" -#include "st_core.h" - -/* ST LL receiver states */ -#define ST_W4_PACKET_TYPE 0 -#define ST_BT_W4_EVENT_HDR 1 -#define ST_BT_W4_ACL_HDR 2 -#define ST_BT_W4_SCO_HDR 3 -#define ST_BT_W4_DATA 4 -#define ST_FM_W4_EVENT_HDR 5 -#define ST_GPS_W4_EVENT_HDR 6 - -/* ST LL state machines */ -#define ST_LL_ASLEEP 0 -#define ST_LL_ASLEEP_TO_AWAKE 1 -#define ST_LL_AWAKE 2 -#define ST_LL_AWAKE_TO_ASLEEP 3 -#define ST_LL_INVALID 4 - -#define LL_SLEEP_IND 0x30 -#define LL_SLEEP_ACK 0x31 -#define LL_WAKE_UP_IND 0x32 -#define LL_WAKE_UP_ACK 0x33 - -/* initialize and de-init ST LL */ -long st_ll_init(struct st_data_s *); -long st_ll_deinit(struct st_data_s *); - -/* enable/disable ST LL along with KIM start/stop - * called by ST Core - */ -void st_ll_enable(struct st_data_s *); -void st_ll_disable(struct st_data_s *); - -unsigned long st_ll_getstate(struct st_data_s *); -unsigned long st_ll_sleep_state(struct st_data_s *, unsigned char); -void st_ll_wakeup(struct st_data_s *); -#endif /* ST_LL_H */ diff --git a/drivers/staging/ti-st/sysfs-uim b/drivers/staging/ti-st/sysfs-uim deleted file mode 100644 index 10311afcbd4..00000000000 --- a/drivers/staging/ti-st/sysfs-uim +++ /dev/null @@ -1,16 +0,0 @@ -What: /sys/class/rfkill/rfkill%d/ -Date: March 22 -Contact: Pavan Savoy <pavan_savoy@ti.com> -Description: - Creates the rfkill entries for Radio apps like - BT app, FM app or GPS app to toggle corresponding - cores of the chip - -What: /dev/rfkill -Date: March 22 -Contact: Pavan Savoy <pavan_savoy@ti.com> -Description: - A daemon which maintains the ldisc installation and - uninstallation would be ppolling on this device and listening - on events which would suggest either to install or un-install - line discipline |
