lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Fri, 26 Mar 2010 11:36:39 -0500
From:	Pavan Savoy <pavan_savoy@...com>
To:	marcel@...tmann.org, gregkh@...e.de, alan@...rguk.ukuu.org.uk,
	linux-kernel@...r.kernel.org, pavan_savoy@...oo.co.in
Subject: Re: [PATCH] drivers:staging: sources for Init manager module

--- On Fri, 26/3/10, pavan_savoy@...com <pavan_savoy@...com> wrote:

 > From: pavan_savoy@...com <pavan_savoy@...com>
 > Subject: [PATCH] drivers:staging: sources for Init manager module
 > To: marcel@...tmann.org, gregkh@...e.de, alan@...rguk.ukuu.org.uk
 > Cc: linux-kernel@...r.kernel.org, pavan_savoy@...oo.co.in, "Pavan 
Savoy" <pavan_savoy@...com>
 > Date: Friday, 26 March, 2010, 4:50 AM
 > From: Pavan Savoy <pavan_savoy@...com>
 >
 > Kernel Space Init-Manager works along with User-Mode
 > Init Manager daemon running to maintain the UART state.
 >
 > Communication between user-space daemon and this module can
 > be
 >     1. Via the pid written onto sysfs entry
 >     2. Via the rfkill subsystem
 >
 > It also is a platform driver with a relevant platform
 > device
 > in the board-*.c along with the list of BT/FM/GPS chip
 > enable
 > gpio configuration
 >
 > Signed-off-by: Pavan Savoy <pavan_savoy@...com>
 > ---
 >  drivers/staging/ti-st/st_kim.c |  747
 > ++++++++++++++++++++++++++++++++++++++++
 >  drivers/staging/ti-st/st_kim.h |  152 ++++++++
 >  2 files changed, 899 insertions(+), 0 deletions(-)
 >  create mode 100644 drivers/staging/ti-st/st_kim.c
 >  create mode 100644 drivers/staging/ti-st/st_kim.h
 >
 > diff --git a/drivers/staging/ti-st/st_kim.c
 > b/drivers/staging/ti-st/st_kim.c
 > new file mode 100644
 > index 0000000..ba183f0
 > --- /dev/null
 > +++ b/drivers/staging/ti-st/st_kim.c
 > @@ -0,0 +1,747 @@
 > +/*
 > + *  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
 > + *
 > + */
 > +
 > +#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>
 > +
 > +
 > +/* all debug macros go in here */
 > +#define ST_KIM_ERR(fmt, arg...)  printk(KERN_ERR
 > "(stk):"fmt"\n" , ## arg)
 > +#if defined(DEBUG)        /*
 > limited debug messages */
 > +#define ST_KIM_DBG(fmt, arg...)  printk(KERN_INFO
 > "(stk):"fmt"\n" , ## arg)
 > +#define ST_KIM_VER(fmt, arg...)
 > +#elif defined(VERBOSE)
 >     /* very verbose */
 > +#define ST_KIM_DBG(fmt, arg...)  printk(KERN_INFO
 > "(stk):"fmt"\n" , ## arg)
 > +#define ST_KIM_VER(fmt, arg...)  printk(KERN_INFO
 > "(stk):"fmt"\n" , ## arg)
 > +#else /* error msgs only */
 > +#define ST_KIM_DBG(fmt, arg...)
 > +#define ST_KIM_VER(fmt, arg...)
 > +#endif
 > +
 > +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"),
 > +};
 > +
 > +static 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)) {
 > +        ST_KIM_ERR("no
 > proper response during fw download");
 > +        ST_KIM_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);
 > +
 > +    ST_KIM_DBG("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.
 > +         */
 > +        ST_KIM_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;
 > +
 > +    ST_KIM_DBG("%s", __func__);
 > +    /* Decode received bytes here */
 > +    ptr = (char *)data;
 > +    if (unlikely(ptr == NULL)) {
 > +        ST_KIM_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:
 > +
 >     ST_KIM_DBG("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;
 > +
 >     ST_KIM_DBG("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:
 > +
 > ST_KIM_DBG("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:
 > +
 > ST_KIM_DBG("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) {
 > +
 > ST_KIM_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 */
 > +    ST_KIM_DBG("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 };
 > +
 > +    ST_KIM_DBG("%s", __func__);
 > +
 > +
 > INIT_COMPLETION(kim_gdata->kim_rcvd);
 > +    if (4 != st_int_write(read_ver_cmd, 4))
 > {
 > +        ST_KIM_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))) {
 > +        ST_KIM_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);
 > +    ST_KIM_DBG("%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? */
 > +
 > +    ST_KIM_VER("%s", __func__);
 > +
 > +    err =
 > read_local_version(bts_scr_name);
 > +    if (err != ST_SUCCESS) {
 > +        ST_KIM_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)))
 > {
 > +        ST_KIM_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) {
 > +        ST_KIM_VER(" 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 */
 > +
 >     ST_KIM_ERR
 > +
 >         (" change remote baud\
 > +
 >         rate command in
 > firmware");
 > +
 >     break;
 > +
 > }
 > +
 > +
 > INIT_COMPLETION(kim_gdata->kim_rcvd);
 > +
 > err = st_int_write(((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)))
 > {
 > +
 >     ST_KIM_ERR
 > +
 >         (" response timeout during
 > fw download ");
 > +
 >     /* timed out */
 > +
 >
 > release_firmware(kim_gdata->fw_entry);
 > +
 >     return ST_ERR_FAILURE;
 > +
 > }
 > +
 > break;
 > +        case
 > ACTION_DELAY:    /* sleep */
 > +
 > ST_KIM_DBG("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)
 > +{
 > +    ST_KIM_DBG(" %s ", __func__);
 > +
 > +    if (kim_gdata->gpios[type] == -1) {
 > +        ST_KIM_DBG(" 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(const unsigned char *data, long count)
 > +{
 > +    ST_KIM_DBG(" %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;
 > +    ST_KIM_DBG(" %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_sw_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) {
 > +
 > ST_KIM_VER(" sending SIGUSR2 to uim failed %ld", err);
 > +
 > err = ST_ERR_FAILURE;
 > +
 > continue;
 > +        }
 > +#else
 > +        /* unblock and send
 > event to UIM via /dev/rfkill */
 > +
 > rfkill_set_sw_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 */
 > +
 > ST_KIM_ERR("line disc installation timed out ");
 > +
 > err = ST_ERR_FAILURE;
 > +
 > continue;
 > +        } else {
 > +
 > /* ldisc installed now */
 > +
 > ST_KIM_DBG(" line discipline installed ");
 > +
 > err = download_firmware();
 > +
 > if (err != ST_SUCCESS) {
 > +
 >     ST_KIM_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) {
 > +        ST_KIM_ERR("sending
 > SIGUSR2 to uim failed %ld", err);
 > +        return
 > ST_ERR_FAILURE;
 > +    }
 > +#else
 > +    /* set BT rfkill to be blocked */
 > +    err =
 > rfkill_set_sw_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 */
 > +        ST_KIM_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)
 > +{
 > +    ST_KIM_DBG("%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(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);
 > +    ST_KIM_DBG(" %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:
 > +        ST_KIM_ERR(" wrong
 > proto type ");
 > +    break;
 > +    }
 > +    return ST_SUCCESS;
 > +}
 > +
 > +#endif    /* LEGACY_RFKILL_SUPPORT */
 > +
 > +/**********************************************************************/
 > +/* 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;
 > +
 > +    for (proto = 0; proto < ST_MAX;
 > proto++) {
 > +
 > kim_gdata->gpios[proto] = gpios[proto];
 > +        ST_KIM_VER(" %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)) {
 > +
 > ST_KIM_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)) {
 > +
 > ST_KIM_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)) {
 > +        ST_KIM_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 */
 > +    }
 > +    ST_KIM_DBG(" 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) {
 > +
 > ST_KIM_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)) {
 > +
 > ST_KIM_ERR("rfkill registration failed for gpio %ld",
 > +
 >        gpios[proto]);
 > +
 > rfkill_unregister(kim_gdata->rfkill[proto]);
 > +
 > continue;
 > +        }
 > +        ST_KIM_DBG("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
 > +    }
 > +    ST_KIM_DBG("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;
 > +    return ST_SUCCESS;
 > +}
 > +
 > +/**********************************************************************/
 > +/* entry point for ST KIM module, called in from ST Core
 > */
 > +
 > +long st_kim_init(void)
 > +{
 > +    long ret = ST_SUCCESS;
 > +    kim_gdata = kzalloc(sizeof(struct
 > kim_data_s), GFP_ATOMIC);
 > +    if (!kim_gdata) {
 > +        ST_KIM_ERR("no mem
 > to allocate");
 > +        return -ENOMEM;
 > +    }
 > +    ret =
 > platform_driver_register(&kim_platform_driver);
 > +    if (ret != 0) {
 > +        ST_KIM_ERR("platform
 > drv registration failed");
 > +        return
 > ST_ERR_FAILURE;
 > +    }
 > +    return ST_SUCCESS;
 > +}
 > +
 > +long st_kim_deinit(void)
 > +{
 > +    /* the following returns void */
 > +
 > platform_driver_unregister(&kim_platform_driver);
 > +    kfree(kim_gdata);
 > +    kim_gdata = NULL;
 > +    return ST_SUCCESS;
 > +}
 > diff --git a/drivers/staging/ti-st/st_kim.h
 > b/drivers/staging/ti-st/st_kim.h
 > new file mode 100644
 > index 0000000..d4d03b4
 > --- /dev/null
 > +++ b/drivers/staging/ti-st/st_kim.h
 > @@ -0,0 +1,152 @@
 > +/*
 > + *  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
 > +};
 > +
 > +long st_kim_init(void);
 > +long st_kim_deinit(void);
 > +
 > +long st_kim_start(void);
 > +long st_kim_stop(void);
 > +/*
 > + * called from st_tty_receive to authenticate fw_download
 > + */
 > +void st_kim_recv(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(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 */
 > --
 > 1.5.4.3
 >

Greg,

Please consider the below patch, since there were few problems with the 
older one.

Small modification though, the rfkill_set_hw_state is used instead of 
the rfkill_set_sw_state.



 From 9dbbd31e55e30f6aaea7f3ca830cf359cdd9f0f8 Mon Sep 17 00:00:00 2001
From: Pavan Savoy <pavan_savoy@...com>
Date: Mon, 22 Mar 2010 13:19:39 -0400
Subject: [PATCH 3/8] drivers:staging: sources for Init manager module

Kernel Space Init-Manager works along with User-Mode
Init Manager daemon running to maintain the UART state.

Communication between user-space daemon and this module can be
	1. Via the pid written onto sysfs entry
	2. Via the rfkill subsystem

It also is a platform driver with a relevant platform device
in the board-*.c along with the list of BT/FM/GPS chip enable
gpio configuration

Signed-off-by: Pavan Savoy <pavan_savoy@...com>
---
  drivers/staging/ti-st/st_kim.c |  747 
++++++++++++++++++++++++++++++++++++++++
  drivers/staging/ti-st/st_kim.h |  152 ++++++++
  2 files changed, 899 insertions(+), 0 deletions(-)
  create mode 100644 drivers/staging/ti-st/st_kim.c
  create mode 100644 drivers/staging/ti-st/st_kim.h

diff --git a/drivers/staging/ti-st/st_kim.c b/drivers/staging/ti-st/st_kim.c
new file mode 100644
index 0000000..ac4e6a2
--- /dev/null
+++ b/drivers/staging/ti-st/st_kim.c
@@ -0,0 +1,747 @@
+/*
+ *  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
+ *
+ */
+
+#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>
+
+
+/* all debug macros go in here */
+#define ST_KIM_ERR(fmt, arg...)  printk(KERN_ERR "(stk):"fmt"\n" , ## arg)
+#if defined(DEBUG)		/* limited debug messages */
+#define ST_KIM_DBG(fmt, arg...)  printk(KERN_INFO "(stk):"fmt"\n" , ## arg)
+#define ST_KIM_VER(fmt, arg...)
+#elif defined(VERBOSE)		/* very verbose */
+#define ST_KIM_DBG(fmt, arg...)  printk(KERN_INFO "(stk):"fmt"\n" , ## arg)
+#define ST_KIM_VER(fmt, arg...)  printk(KERN_INFO "(stk):"fmt"\n" , ## arg)
+#else /* error msgs only */
+#define ST_KIM_DBG(fmt, arg...)
+#define ST_KIM_VER(fmt, arg...)
+#endif
+
+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"),
+};
+
+static 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)) {
+		ST_KIM_ERR("no proper response during fw download");
+		ST_KIM_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);
+
+	ST_KIM_DBG("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.
+		 */
+		ST_KIM_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;
+
+	ST_KIM_DBG("%s", __func__);
+	/* Decode received bytes here */
+	ptr = (char *)data;
+	if (unlikely(ptr == NULL)) {
+		ST_KIM_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:
+				ST_KIM_DBG("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;
+				ST_KIM_DBG("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:
+			ST_KIM_DBG("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:
+			ST_KIM_DBG("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) {
+			ST_KIM_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 */
+	ST_KIM_DBG("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 };
+
+	ST_KIM_DBG("%s", __func__);
+
+	INIT_COMPLETION(kim_gdata->kim_rcvd);
+	if (4 != st_int_write(read_ver_cmd, 4)) {
+		ST_KIM_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))) {
+		ST_KIM_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);
+	ST_KIM_DBG("%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? */
+
+	ST_KIM_VER("%s", __func__);
+
+	err = read_local_version(bts_scr_name);
+	if (err != ST_SUCCESS) {
+		ST_KIM_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))) {
+		ST_KIM_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) {
+		ST_KIM_VER(" 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 */
+				ST_KIM_ERR
+				    (" change remote baud\
+				    rate command in firmware");
+				break;
+			}
+
+			INIT_COMPLETION(kim_gdata->kim_rcvd);
+			err = st_int_write(((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))) {
+				ST_KIM_ERR
+				    (" response timeout during fw download ");
+				/* timed out */
+				release_firmware(kim_gdata->fw_entry);
+				return ST_ERR_FAILURE;
+			}
+			break;
+		case ACTION_DELAY:	/* sleep */
+			ST_KIM_DBG("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)
+{
+	ST_KIM_DBG(" %s ", __func__);
+
+	if (kim_gdata->gpios[type] == -1) {
+		ST_KIM_DBG(" 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(const unsigned char *data, long count)
+{
+	ST_KIM_DBG(" %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;
+	ST_KIM_DBG(" %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) {
+			ST_KIM_VER(" 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 */
+			ST_KIM_ERR("line disc installation timed out ");
+			err = ST_ERR_FAILURE;
+			continue;
+		} else {
+			/* ldisc installed now */
+			ST_KIM_DBG(" line discipline installed ");
+			err = download_firmware();
+			if (err != ST_SUCCESS) {
+				ST_KIM_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) {
+		ST_KIM_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 */
+		ST_KIM_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)
+{
+	ST_KIM_DBG("%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(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);
+	ST_KIM_DBG(" %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:
+		ST_KIM_ERR(" wrong proto type ");
+	break;
+	}
+	return ST_SUCCESS;
+}
+
+#endif	/* LEGACY_RFKILL_SUPPORT */
+
+/**********************************************************************/
+/* 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;
+
+	for (proto = 0; proto < ST_MAX; proto++) {
+		kim_gdata->gpios[proto] = gpios[proto];
+		ST_KIM_VER(" %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)) {
+			ST_KIM_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)) {
+			ST_KIM_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)) {
+		ST_KIM_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 */
+	}
+	ST_KIM_DBG(" 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) {
+			ST_KIM_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)) {
+			ST_KIM_ERR("rfkill registration failed for gpio %ld",
+				   gpios[proto]);
+			rfkill_unregister(kim_gdata->rfkill[proto]);
+			continue;
+		}
+		ST_KIM_DBG("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
+	}
+	ST_KIM_DBG("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;
+	return ST_SUCCESS;
+}
+
+/**********************************************************************/
+/* entry point for ST KIM module, called in from ST Core */
+
+long st_kim_init(void)
+{
+	long ret = ST_SUCCESS;
+	kim_gdata = kzalloc(sizeof(struct kim_data_s), GFP_ATOMIC);
+	if (!kim_gdata) {
+		ST_KIM_ERR("no mem to allocate");
+		return -ENOMEM;
+	}
+	ret = platform_driver_register(&kim_platform_driver);
+	if (ret != 0) {
+		ST_KIM_ERR("platform drv registration failed");
+		return ST_ERR_FAILURE;
+	}
+	return ST_SUCCESS;
+}
+
+long st_kim_deinit(void)
+{
+	/* the following returns void */
+	platform_driver_unregister(&kim_platform_driver);
+	kfree(kim_gdata);
+	kim_gdata = NULL;
+	return ST_SUCCESS;
+}
diff --git a/drivers/staging/ti-st/st_kim.h b/drivers/staging/ti-st/st_kim.h
new file mode 100644
index 0000000..d4d03b4
--- /dev/null
+++ b/drivers/staging/ti-st/st_kim.h
@@ -0,0 +1,152 @@
+/*
+ *  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
+};
+
+long st_kim_init(void);
+long st_kim_deinit(void);
+
+long st_kim_start(void);
+long st_kim_stop(void);
+/*
+ * called from st_tty_receive to authenticate fw_download
+ */
+void st_kim_recv(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(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 */
-- 
1.5.4.3





--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ