From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754859Ab0CYUZX (ORCPT ); Thu, 25 Mar 2010 16:25:23 -0400 Received: from web94911.mail.in2.yahoo.com ([203.104.17.176]:29095 "HELO web94911.mail.in2.yahoo.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with SMTP id S1752606Ab0CYUZU convert rfc822-to-8bit (ORCPT ); Thu, 25 Mar 2010 16:25:20 -0400 DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=s1024; d=yahoo.co.in; h=Message-ID:X-YMail-OSG:Received:X-Mailer:Date:From:Subject:To:Cc:In-Reply-To:MIME-Version:Content-Type:Content-Transfer-Encoding; b=QWHP1YQbuUCH+GepsIYccGG7TD4q1EZh2MAOtcJTu1JI7cGjLlHCt0syAKc595Lzzx1vQV7nU6nTu3uU01BG/kZbNAIBX5TJbgUsi6hJLHHE4749DQ7bSrDtkEYXcLrm/ZZKBoiGQ9zsZuOTcVKcJj/g5fgbhX4+fND7Ajkyyj4=; Message-ID: <98670.43991.qm@web94911.mail.in2.yahoo.com> X-YMail-OSG: hZSfqI0VM1moQCC760UQoWBKH_3JGD_vaX1INy.yDEWLXGb orlCPUO7WNVAPQYtiy.ZmK3td.tuHTzWv5BuPWoiXD8ftgnjFjKXW4u5JiaY L34Y_Tn.UIFxKxKALsUdWQhIPGfQwYnzDpVi1W1uLBqBpk8kkD.rtBvn1vGG a9PBc_sIgcyGl_iuQQPzevnnhF2EMhJRItVbCs5k.eHb_09_OMLOylbsdNSY uLlsG6jpYWfGQAVpGVdNBqEogaWDfMksJ6ijrgK_0vSLuSibZ3py0JJFeHOK TRhd0Q_D1zEhq5CBRbF89bto- X-Mailer: YahooMailClassic/10.0.8 YahooMailWebService/0.8.100.260964 Date: Fri, 26 Mar 2010 01:55:15 +0530 (IST) From: Pavan Savoy Subject: Re: [PATCH 3/7] drivers:staging: sources for Init manager module To: marcel@holtmann.org, gregkh@suse.de, alan@lxorguk.ukuu.org.uk, pavan_savoy@ti.com Cc: linux-kernel@vger.kernel.org, Pavan Savoy In-Reply-To: <1269548464-25629-1-git-send-email-pavan_savoy@ti.com> MIME-Version: 1.0 Content-Type: text/plain; charset=iso-8859-1 Content-Transfer-Encoding: 8BIT Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Marcel, Greg, Alan, --- On Fri, 26/3/10, pavan_savoy@ti.com wrote: > From: pavan_savoy@ti.com > Subject: [PATCH 3/7] drivers:staging: sources for Init manager module > To: marcel@holtmann.org, gregkh@suse.de, alan@lxorguk.ukuu.org.uk > Cc: linux-kernel@vger.kernel.org, pavan_savoy@yahoo.co.in, "Pavan Savoy" > Date: Friday, 26 March, 2010, 1:51 AM > From: Pavan Savoy > > 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 > --- > drivers/staging/ti-st/st_kim.c |  747 > ++++++++++++++++++++++++++++++++++++++++ > drivers/staging/ti-st/st_kim.h |  151 ++++++++ > 2 files changed, 898 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..eac470d > --- /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 > +#include > +#include > +#include > +#include > +#include > + > +#include > + > +#include "st_kim.h" > +/* understand BT events for fw response */ > +#include > +#include > +#include > + > + > +#define DEBUG > +/* 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->rfkill[proto] = > rfkill_alloc(protocol_names[proto], > +            > &pdev->dev, RFKILL_TYPE_BLUETOOTH, > +            > &kim_rfkill_ops, &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..4e73bb4 > --- /dev/null > +++ b/drivers/staging/ti-st/st_kim.h > @@ -0,0 +1,151 @@ > +/* > + *  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 > +#include "st.h" > +#include "st_core.h" > +#include "st_ll.h" > +#include > + > +/* 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]; > +#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@vger.kernel.org > More majordomo info at  http://vger.kernel.org/majordomo-info.html > Please read the FAQ at  http://www.tux.org/lkml/ Now, my user-space daemon doesn't need the sysfs entry to write it's PID, from user-space, I open the /dev/rfkill device and ppoll on it, to receive events, upon receiving them I can install/un-install the ldisc based on the blocked or non-blocked state. Your Mail works best with the New Yahoo Optimized IE8. Get it NOW! http://downloads.yahoo.com/in/internetexplorer/