編輯:關於Android編程
L2CAP層的實現在整個藍牙的使用過程中尤為關鍵和復雜的,它涉及的方方面面比較多,曉東可能會要花幾篇文章才能講個大概,這篇文章先介紹L2CAP的初始化,這還是沒有和controller交互的部分,要先建立整個L2CAP,還需要實現很多,後面的文章會慢慢道來。
5.5, L2CAPsocket的創建
上層調用的函數就是這個:
sock = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
很清晰地可以看到,其實就是L2CAP的proto了。所以,我們直接去l2cap_sock.c中去看看創建的函數吧,為什麼會走到這裡,我就不詳細分析了,網上關於socket的文章實在是太多了。
static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, int kern) { struct sock *sk; //會調用這裡的create socket的函數 BT_DBG("sock %p", sock); sock->state = SS_UNCONNECTED; //傳入的type但是SOCK_RWA if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM && sock->type != SOCK_DGRAM && sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; //若是應用層創建需要有net raw的權限,顯然我們是應用層過來的,所以一定要有NET_RAW的權限哦 if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW)) return -EPERM; //賦值l2cap層的ops sock->ops = &l2cap_sock_ops; //申請並初始化一個sock,詳細見5.5.1 sk = l2cap_sock_alloc(net, sock, protocol, GFP_ATOMIC); if (!sk) return -ENOMEM; //其實是進一步初始化l2cap channel,詳細見5.5.2 l2cap_sock_init(sk, NULL); return 0; }
5.5.1 l2capsocket的申請
static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio) { struct sock *sk; struct l2cap_chan *chan; //申請sock sk = sk_alloc(net, PF_BLUETOOTH, prio, &l2cap_proto); if (!sk) return NULL; //初始化申請的sock,和對應的socket關聯 sock_init_data(sock, sk); //初始化accept queue INIT_LIST_HEAD(&bt_sk(sk)->accept_q); //destruct和timeout的設置 sk->sk_destruct = l2cap_sock_destruct; sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT; //清空SOCK——ZAPPED位 sock_reset_flag(sk, SOCK_ZAPPED); sk->sk_protocol = proto; //state設為open sk->sk_state = BT_OPEN; //創建l2cap的通道,這個是l2cap channel相關的一些初始化 chan = l2cap_chan_create(sk); //賦值l2cap channel l2cap_pi(sk)->chan = chan; return sk; } struct l2cap_chan *l2cap_chan_create(struct sock *sk) { struct l2cap_chan *chan; //l2cap channel結構體的申請 chan = kzalloc(sizeof(*chan), GFP_ATOMIC); if (!chan) return NULL; chan->sk = sk; write_lock_bh(&chan_list_lock); //把申請的chan加入chan_list雙向鏈表中 list_add(&chan->global_l, &chan_list); write_unlock_bh(&chan_list_lock); //初始化計時器 setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan); //chanenl的state初始化位open chan->state = BT_OPEN; //chan refcnt 設為1 atomic_set(&chan->refcnt, 1); return chan; }
5.5.2 l2cap channel的進一步初始化
這個函數就是進一步的初始化l2cap的socket中的各個方面
static void l2cap_sock_init(struct sock *sk, struct sock *parent) { struct l2cap_pinfo *pi = l2cap_pi(sk); struct l2cap_chan *chan = pi->chan; BT_DBG("sk %p", sk); if (parent) { …… } else { //我們傳入的是null,若是會走到這裡 //得到sk的sk_type switch (sk->sk_type) { case SOCK_RAW: //若是raw,channel的type也是raw chan->chan_type = L2CAP_CHAN_RAW; break; case SOCK_DGRAM: chan->chan_type = L2CAP_CHAN_CONN_LESS; break; case SOCK_SEQPACKET: case SOCK_STREAM: chan->chan_type = L2CAP_CHAN_CONN_ORIENTED; break; } //設置default mtu chan->imtu = L2CAP_DEFAULT_MTU; chan->omtu = 0; if (!disable_ertm && sk->sk_type == SOCK_STREAM) { chan->mode = L2CAP_MODE_ERTM; set_bit(CONF_STATE2_DEVICE, &chan->conf_state); } else { //raw是basic chan->mode = L2CAP_MODE_BASIC; } //設置chan的別的值 chan->max_tx = L2CAP_DEFAULT_MAX_TX;//max tx是3 chan->fcs = L2CAP_FCS_CRC16;//l2cap的check是crc16 chan->tx_win = L2CAP_DEFAULT_TX_WINDOW;//tx window是63 chan->sec_level = BT_SECURITY_LOW;//sec level默認是low chan->role_switch = 0; chan->force_reliable = 0; chan->flushable = BT_FLUSHABLE_OFF;//flush disable chan->force_active = BT_POWER_FORCE_ACTIVE_ON;//power force active on } /* Default config options */ chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;//flush timeout 默認是FFFF chan->data = sk; chan->ops = &l2cap_chan_ops;//chan ops設置 }
到這裡,基本的L2CAP相關的初始化就完成了,還是蠻基本的,下面我們可以猜到就是bind了,因為bind中涉及的內容和新的概念比較多,我們會在下一篇中和大家詳細分析。
這是一個整理即時通訊(IM)和社交系統(SNS)優秀開源項目的文檔,項目上傳github歡迎提交更新。github地址:https://github.com/Camelo
最近在做的新聞客戶端用到了ViewPager,Android Studio如今集成的很好了,自動創建很多不必要寫的代碼。在使用過程中碰到了一個很奇怪的事:ViewPage
之前寫過一篇文章Android TextView 橫豎排切換(字方向不變) 是自定義了一個LinearLayout, 實現了當然還不夠, 還要對它進行操作, 平移,旋轉
紅米pro和小米max哪個好?下面小編帶來了紅米pro和小米max對比評測,感興趣的朋友一起來看看吧! 紅米pro和小米max對比評測: 紅米pro介紹