Bluetooth Driver acts as interface between HCI Core and TI Shared Transport Layer.
/DRIVERS/BLUETOOTH/BTWILINK.C:
#include <linux/platform_device.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_ core.h> #include <net/bluetooth/hci.h> #include <linux/ti_wilink_st.h> #include <linux/module.h > #define Debug#define VERSION "1.0" #define Max_bt_chnl_ids3#define bt_register_timeout 6000
struct Ti_st {struct Hci_dev *hdev;char reg_status;long (*st_write) (struct sk_buff *); struct completion Wait_reg_complet Ion;};
struct Ti_st-module operation structure Body
@hdev: The HCI device pointer is bound to the Bluetooth module
@reg_status: ST Registration return status
@st_write: Write function used by send_frame
@wait_reg_completion end synchronization between-ti_st_open and ST_REG_COMPLETION_CB
static inline void Ti_st_tx_complete (struct ti_st *hst, int pkt_type) {struct Hci_dev *hdev = hst->hdev;/* Update HCI St At Counters */switch (pkt_type) {case Hci_command_pkt:hdev->stat.cmd_tx++;break;case hci_acldata_pkt:hdev-> Stat.acl_tx++;break;case Hci_scodata_pkt:hdev->stat.sco_tx++;break;}}
Pocket ID (Cmd,acl,sco) Count
static void St_reg_completion_cb (void *priv_data, char data) {struct Ti_st *lhst = priv_data;/* Save registration status fo R use in Ti_st_open () */lhst->reg_status = data;/* Complete the wait in Ti_st_open () */complete (&lhst->wait_reg_ completion);}
The Status.ti_st_open () function waits for the st_pending signal returned by the St_register ()
static long st_receive (void *priv_data, struct sk_buff *skb) {struct Ti_st *lhst = Priv_data;int err;if (!SKB) Return-efaul T;if (!lhst) {KFREE_SKB (SKB); return-efault;} Skb->dev = (void *) lhst->hdev;/* Forward SKB to HCI core layer */err = Hci_recv_frame (SKB); if (Err < 0) {Bt_err ( "Unable to push SKB to HCI core (%d)", err); return err;} Lhst->hdev->stat.byte_rx + = Skb->len;return 0;}
Called by the shared transport layer when data is received
static struct st_proto_s Ti_st_proto[max_bt_chnl_ids] = {{. chnl_id = hci_event_pkt,/* HCI Events */.hdr_len = sizeof (Stru CT Hci_event_hdr),. Offset_len_in_hdr = Offsetof (struct HCI_EVENT_HDR, Plen),. len_size = 1,/* sizeof (Plen) in struct hci_e Vent_hdr */.reserve = 8,},{.chnl_id = hci_acldata_pkt,/* ACL */.hdr_len = sizeof (struct HCI_ACL_HDR),. Offset_len_in_hdr = Offsetof (struct HCI_ACL_HDR, Dlen),. len_size = 2,/* sizeof (dlen) in struct hci_acl_hdr */.reserve = 8,},{.chnl_id = hci_s CODATA_PKT,/* SCO */.hdr_len = sizeof (struct HCI_SCO_HDR),. Offset_len_in_hdr = Offsetof (struct HCI_SCO_HDR, Dlen),. Len_ Size = 1,/* sizeof (Dlen) in struct HCI_SCO_HDR */.reserve = 8,},};
interface of the HCI layer
Definition of struct st_proto_s:/include/linux/ti_wilink_st.h:
struct st_proto_s {
enum proto_type type;
long (*RECV) (void *, struct sk_buff *);
unsigned char (*match_packet) (const unsigned char *data);
void (*REG_COMPLETE_CB) (void *, char data);
long (*write) (struct sk_buff *skb);
void *priv_data;
unsigned Char chnl_id;
unsigned The size of the maximum frame max_frame_size; //can receive
unsigned char Hdr_len; //Head structure length
unsigned char offset_len_in_hdr; //provides length offset in the header structure
unsigned char len_size; //2 byte or 1 bytes
unsigned Char reserve; //st the number of bytes to swap};
static int Ti_st_open (struct Hci_dev *hdev) {unsigned long timeleft;struct ti_st *hst;int err, I; bt_dbg ("%s%p", Hdev->name, Hdev); if (Test_and_set_bit (hci_running, &hdev->flags)) return-ebusy;/* provide Contexts for callbacks from ST */hst = hdev->driver_data;for (i = 0; i < max_bt_chnl_ids; i++) {ti_st_proto[i].priv_ data = Hst;ti_st_proto[i].max_frame_size = HCI_MAX_FRAME_SIZE;TI_ST_PROTO[I].RECV = St_receive;ti_st_proto[i].reg_ COMPLETE_CB = st_reg_completion_cb;/* Prepare wait-for-completion handler */init_completion (&hst->wait_reg_ completion);/* Reset ST Registration callback status Flag, * This value would be updated in * ST_REG_COMPLETION_CB () * func tion whenever it called from ST driver. */hst->reg_status =-einprogress;err = St_register (&ti_st_proto[i]), if (!err) goto done;if (Err! =-EINPROGRESS) { Clear_bit (hci_running, &hdev->flags); Bt_err ("St_register failed%d", err); return err;} /* ST is busy with either protocol * registration or firmwareDownload. */bt_dbg ("Waiting for Registration", "completion signal from ST"); timeleft = Wait_for_completion_timeout (&hst-> Wait_reg_completion, Msecs_to_jiffies (bt_register_timeout)); if (!timeleft) {clear_bit (hci_running, &hdev-> Flags); Bt_err ("Timeout (%d sec), didn ' t get reg" "Completion signal from ST", bt_register_timeout/1000); return-etimedout;} /* is ST registration callback * called with ERROR status? */if (Hst->reg_status! = 0) {clear_bit (hci_running, &hdev->flags); Bt_err ("ST registration completed with invalid" "Status%d", hst->reg_status); return-eagain;} Done:hst->st_write = Ti_st_proto[i].write;if (!hst->st_write) {bt_err ("Undefined st write function"); Clear_bit ( Hci_running, &hdev->flags); for (i = 0; i < max_bt_chnl_ids; i++) {/* Undo registration with ST */err = St_unregi Ster (&ti_st_proto[i]); if (err) Bt_err ("St_unregister () failed with" "Error%d", err); hst->st_write = NULL;} Return-eio;}} return 0;}
HCI Core invocation, initializing the device
static int ti_st_close (struct Hci_dev *hdev) {int err, i;struct ti_st *hst = hdev->driver_data;if (!test_and_clear_bit ( Hci_running, &hdev->flags)) return 0;for (i = max_bt_chnl_ids-1; I >= 0; i--) {err = St_unregister (&ti_st_pro To[i]); if (err) Bt_err ("St_unregister (%d) failed with error%d", ti_st_proto[i].chnl_id, err);} Hst->st_write = Null;return err;}
Turn off the device
static int ti_st_send_frame (struct sk_buff *skb) {struct Hci_dev *hdev;struct ti_st *hst;long len;hdev = (struct Hci_dev *) Skb->dev;if (!test_bit (hci_running, &hdev->flags)) Return-ebusy;hst = hdev->driver_data;/* Prepend SKB With frame type */memcpy (Skb_push (SKB, 1), &BT_CB (SKB)->pkt_type, 1); bt_dbg ("%s:type%d len%d", Hdev->name, BT_CB (SKB)->pkt_type,skb->len);/* Insert SKB to shared transport layer ' s Transmit queue. * Freeing SKB memory is taken care on shared transport layer, * so don ' t free SKB memory here. */len = Hst->st_write (SKB), if (Len < 0) {KFREE_SKB (SKB); Bt_err ("ST Write Failed (%ld)", Len);/* Try Again, would only fail if UART have gone bad */return-eagain;} /* ST accepted our SKB. So, Go ahead and do rest */hdev->stat.byte_tx + = Len;ti_st_tx_complete (HST, BT_CB (SKB)->pkt_type); return 0;} static void Ti_st_destruct (struct Hci_dev *hdev) {bt_dbg ("%s", hdev->name);/* do nothing here, since platform remove * w Ould Free the Hdev->dRiver_data */}
Send Frame
static int bt_ti_probe (struct platform_device *pdev) {static struct Ti_st *hst;struct hci_dev *hdev;int err;hst = Kzalloc (s izeof (struct ti_st), Gfp_kernel), if (!hst) return-enomem;/* Expose "HCIX" device to user space */hdev = Hci_alloc_dev (); if (!hdev) {Kfree (HST); return-enomem;} bt_dbg ("Hdev%p", hdev); Hst->hdev = Hdev;hdev->bus = Hci_uart;hdev->driver_data = Hst;hdev->open = Ti_st_ Open;hdev->close = Ti_st_close;hdev->flush = Null;hdev->send = Ti_st_send_frame;hdev->destruct = Ti_st_ Destruct;hdev->owner = This_module;err = Hci_register_dev (Hdev), if (Err < 0) {Bt_err ("Can ' t register HCI device Erro R%d ", err); Kfree (HST); Hci_free_dev (Hdev); return err;} bt_dbg ("HCI device registered (Hdev%p)", Hdev);d ev_set_drvdata (&pdev->dev, HST); return err;}
Device detection
static int bt_ti_remove (struct platform_device *pdev) {struct Hci_dev *hdev;struct ti_st *hst = Dev_get_drvdata (& Pdev->dev); if (!hst) Return-efault; bt_dbg ("%s", hst->hdev->name); Hdev = Hst->hdev;ti_st_close (Hdev); Hci_unregister_dev (Hdev); Hci_free_dev ( Hdev); Kfree (HST);d ev_set_drvdata (&pdev->dev, NULL); return 0;}
Device Uninstall
static struct Platform_driver Btwilink_driver = {. Probe = Bt_ti_probe,.remove = Bt_ti_remove,.driver = {. Name = "Btwilink" ,. Owner = This_module,},};
Platform Driver
static int __init btwilink_init (void) {Bt_info ("Bluetooth Driver for TI wilink-version%s", Version); return Platform_driv Er_register (&btwilink_driver);} static void __exit btwilink_exit (void) {platform_driver_unregister (&btwilink_driver);} Module_init (Btwilink_init); Module_exit (Btwilink_exit);
Device Init and exit
Module_author ("Raja Mani <[email protected]>"); Module_description ("Bluetooth Driver for TI Shared Transport" VERSION); Module_version (VERSION); Module_license ("GPL");
Texas instrument ' s Bluetooth Driver for Shared Transport notes