2014/11/28

關於802.11ac 怎麼來?

根據802.11ac的介紹說明, 是延續802.11n與802.11a而來

然而wifi的發展過程都是有其當下的時空背景與需求的

就我所知, 順序是:

802.11 > 802.11a > 802.11b > 802.11g > 802.11n > 802.11ac

(可參考: 網路架構大概論6-看懂無線網路 802.11 b/g/n/ac 演進歷史)

不外乎就是下一代去改善上一代的問題

像802.11a推出的時候是避免干擾 所以選擇5Ghz 頻率

因為2.4Ghz太多訊號走這條路啦, 原因不外乎免費通道加上很多店子產品都走這裡 2.4Ghz

但802.11a 失敗在於製作成本過高

而802.11b雖然頻率是再2.4Ghz 但是成本製作較低, 加上低頻率的波長較長因此可以傳輸距離遠

在當時 802.11b 幾乎取代了 802.11a

後來802.11b又有加強版: 802.11g 一樣是2.4Ghz 但調變有更改~

於是802.11b/g 混合版讓大家用了好長一段時間 2003~2009左右吧

但是現在網路影音需求大增, 新的協定(n, ac)蠢蠢欲動

加上2.4Ghz 總體的頻寬又不夠大, 所以到了802.11n 與 802.11ac 又回過頭來加入5Ghz的路


這幾篇文章寫得很好!!

3 倍速!802.11ac 來襲:標配與選配頻寬,應用技術全面剖析

無線網路新趨勢–漫談 802.11ac 新協定

次世代Wi-Fi標準IEEE 802.11ac的5大技術特性

看一下 wiki的模板:802.11網路標準

主要有幾點是802.11ac 改變的地方(與802.11n比較)


1) 支援更寬的頻寬(RF Bandwidth): 最高160 MHz(802.11n上限是 40 MHz)

2) 傳送波束成型正式納入標準(Beam forming) (802.11n 非標準功能)

3) 支援最多 8空間串流(MIMO Spatial Streams)(802.11n僅支援4個)

4) 支援高密度的解調變(Modulation): 256 QAM (802.11n 最高 64-QAM)

5) 多使用者的 MIMO (Multi-user MIMO) (802.11n 無此功能)

2014/11/25

android 使用SMD(共享内存)作為跨processes溝通媒介

首先我也是參考大陸筆者網站, 最近念到SMD的部分! 一樣的Qualcomm的處理器裡面有許多subsystem 個別子處理器負責不同sub system的正常運行, 而我讀到的是負責Wifi/BT/FM的WCN36x0 chip! 很有趣的歷史背景, 因為WCN3680這個chip你可以看見是Qualcomm買下的 Atheros 所製作…………..

前言: 多核間的通訊

在智慧型手機SOC平台中,為了保證個別功能在平台上的流暢運行,都會依照功能使用專門的處理器來處理。如在Qucalcomm MSM 7K 平台上,就包含了4 個處理器內核,Qucalcomm MSM 7K 平台採用ARM 9(mARM,modemARM)處理基帶業務;採用mDSP(Modem DSP)來處理協議protocol的事情;採用ARM 11(aARM ,application ARM)來負責Linux 操作系統的運行;採用aDSP(Application DSP)來處理多媒體業務方面的編/解碼加速工作。

在2010 年末,smartphone or Tablet 終端的CPU 得到了快速發展,高端的smart devices終端已經採用了Cortex-A8 的雙核處理器。而在平板電腦上,Nvidia 開發的基於Cortex-A9 的雙核處理器Tegra 2 則成了市場的寵兒。通信離不開memory記憶體的操作,在Qualcomm平台上,記憶體一般分為3種:基帶內存(Modem Memory)、應用記憶體(Application Memory)和共享記憶體,其中系統MPU保護基帶記憶體不被aARM接入,ARM MMU保護應用記憶體不被mARM接入。

共享內存share-meory

在Linux 中,實現進程通信的機制有很多種,如信號signal、管道Pipeline、信號量Semaphore 、消息隊列Message queue、共享內存share-meory和套接字socket等,但共享內存的方式效率最高。

共享內存是多核通信的物理基礎,其實現主要包括3 個部分:共享內存驅動(SMD,Shared Memory Driver)、共享內存狀態機(SMSM,Shared Memory State Machine)和共享內存管理器(SMEM,Shared Memory Manager)。
其中
SMD 用於多核之間的數據通信;
SMSM用於多核之間的狀態通信;
SMEM是一個底層的協議,是物理RAM共享內存的管理接口,是SMD和SMSM的基礎。

SMEM 具有兩種分配模式:動態SMEM 和靜態SMEM,
動態SMEM 根據需要實時分配,靜態SMEM則會預先分配。

SMEM的主要接口為:smem_alloc()、smem_find()、smem_init()等。
SMEM、SMD、SMSM的實現都需要硬件平台廠商提供支持。

同步與互斥- Synchronization and mutual exclusion

Share meomry用到了自旋鎖(spinlock)和互斥鎖(Mutual exclusion)的概念。
自旋鎖(spinlock)是Linux 內核的同步機制之一,與互斥鎖(Mutual exclusion)類似,但自旋鎖使用者一般保持鎖的時間非常短。自旋鎖的效率遠高於互斥鎖。
自旋鎖的定義位於 xxx\include\linux\spinlock_*.h文件中。

typedef struct {volatile unsigned int lock; // unsigned integer} Raw_spinlock_t;

lock雖然被定義為無符號整數,但是實際上被當做有符號整數使用。
slock值為1 代表鎖未被佔用,值為0 或負數代表鎖被佔用。初始化時slock被置為1。
與信號量Semaphore和讀寫信號量導致調用者睡眠不同,自旋鎖spinlock不會引起調用者睡眠。如果自旋鎖已被別的執行單元保持,調用者就一直循環以確定是否該自旋鎖的保持者已經釋放了鎖。

由於自旋鎖spinlock適用的訪問共享資源的時間非常短, 導致自旋鎖spinlock通常應用於中斷上下文Interrupt Context訪問和對共享資源訪問文件非常短的場景中,如果被保護的共享資源在進程process上下文訪問,則應使用信號量。

與信號量Semaphore和讀寫信號量rw_semaphore在保持期間可以被搶占的情況不同,自旋鎖spinlock在保持期間是搶占失效的,自旋鎖只有在內核可搶占或SMP(Symmetrical Multi-Processing)的情況下才真正需要,在單CPU且不可搶占的內核下,自旋鎖spinlock的所有操作都是空操作。

由於smart devices平台上通常存在多個CPU 或DSP,自旋鎖的運用就顯得非常重要。
在mach-msm Kernel裡的SMD 和SMSM的實現上,自旋鎖spinlock主要運用於中斷處理、信道列表List_of_WLAN_channels和信道狀態Channel State Information的變更過程中,自旋鎖的定義如下:

/* the spinlock is used to synchronize between the * irq handler and code that mutates the channel * list or fiddles with channel state */static DEFINE_SPINLOCK(smd_lock);DEFINE_SPINLOCK(smem_lock);

互斥鎖主要用於實現Linux 內核中的互斥訪問功能,在mach-msm Kernel的SMD 的實現上,互斥鎖主要用於SMD 信道的打開或關閉過程。定義如下:

/* the mutex is used during open() and close() * operations to avoid races while creating or * destroying smd_channel structures */static DEFINE_MUTEX(smd_creation_mutex);

SMD 控制訊號傳遞

在Linux 中,基於SMD 的訊號傳遞是以channel的形式作為一個設備存在的,作為一種雙向信道Channel,其接口的實現遵循Linux 設備驅動規範。
在Qucalcomm 平台上,SMD 的緩衝buffer大小為8192bit,最大信道數為64,SMD的頭head大小為20bit。

SMD 的相關代碼實現主要位於 arch\arm\mach-msm目錄下。
主要文件包括: smd.c、smd_nmea.c、smd_qmi.c、smd_rpcrouter.c、smd_rpcrouter_clients.c、smd_rpcrouter_device.c、smd_rpcrouter_servers.c、smd_tty.c等。

SMD 信道Channel需要同時維護接收信道、發送信道的狀態和數據信息,SMD 的信道定義如下:

smd_private.h

struct smd_channel {	volatile void __iomem *send; /* some variant of smd_half_channel 發送握手channel訊息 */	volatile void __iomem *recv; /* some variant of smd_half_channel 接收握手channel訊息*/	unsigned char *send_data; //發送chaneel 數據資料	unsigned char *recv_data; //接收chaneel 數據資料	unsigned fifo_size;	unsigned fifo_mask;	struct list_head ch_list;	unsigned current_packet;	unsigned n;	void *priv;	void (*notify)(void *priv, unsigned flags);	int (*read)(smd_channel_t *ch, void *data, int len, int user_buf); //讀取	int (*write)(smd_channel_t *ch, const void *data, int len,  //寫入			int user_buf);	int (*read_avail)(smd_channel_t *ch); //可否讀取	int (*write_avail)(smd_channel_t *ch); //可否寫入	int (*read_from_cb)(smd_channel_t *ch, void *data, int len,			int user_buf);	void (*update_state)(smd_channel_t *ch);	unsigned last_state;	void (*notify_other_cpu)(smd_channel_t *ch);	char name[20];	struct platform_device pdev;	unsigned type;	int pending_pkt_sz;	char is_pkt_ch;	/*	 * private internal functions to access *send and *recv.	 * never to be exported outside of smd	 */	struct smd_half_channel_access *half_ch;};

SMD 初始化過程

msm_smd_init()

	for (i = 0; i < NUM_SMD_SUBSYSTEMS; ++i) {		remote_info[i].remote_pid = i;		remote_info[i].free_space = UINT_MAX;		INIT_WORK(&remote_info[i].probe_work, smd_channel_probe_worker);		INIT_LIST_HEAD(&remote_info[i].ch_list);	}

smd_channel_probe_worker()
– Scan for newly created SMD channels and init local structures so the channels are visable to local clients
==> scan_alloc_table(shared, &(r_info->ch_allocated[SMEM_NUM_SMD_STREAM_CHANNELS]), SEC_ALLOC_TBL, tbl_size / sizeof(*shared), r_info);

scan_alloc_table()

/** * scan_alloc_table - Scans a specified SMD channel allocation table in SMEM for newly created channels that need to be made locally visable * @shared: pointer to the table array in SMEM * @smd_ch_allocated: pointer to an array indicating already allocated channels * @table_id: identifier for this channel allocation table * @num_entries: number of entries in this allocation table * @r_info: pointer to the info structure of the remote proc we care about * The smd_probe_lock must be locked by the calling function.  Shared and smd_ch_allocated are assumed to be valid pointers. */static void scan_alloc_table(struct smd_alloc_elm *shared, char *smd_ch_allocated, int table_id, unsigned num_entries, struct remote_proc_info *r_info){	unsigned n;	uint32_t type;	for (n = 0; n < num_entries; n++) {		if (smd_ch_allocated[n])			continue;		/*		 * channel should be allocated only if APPS processor is involved		 */		type = SMD_CHANNEL_TYPE(shared[n].type);		if (!pid_is_on_edge(type, SMD_APPS) ||				!pid_is_on_edge(type, r_info->remote_pid))			continue;		if (!shared[n].ref_count)			continue;		if (!shared[n].name[0])			continue;		if (!smd_initialized && !smd_edge_inited(type)) {			SMD_INFO(				"Probe skipping proc %d, tbl %d, ch %d, edge not inited r_info->remote_pid, table_id, n);			continue;		}		if (!smd_alloc_channel(&shared[n], table_id, r_info))			smd_ch_allocated[n] = 1;		else			SMD_INFO(				"Probe skipping proc %d, tbl %d, ch %d, not allocated r_info->remote_pid, table_id, n);	}}

smd_alloc_channel(): 分配channel

/** * smd_alloc_channel() - Create and init local structures for a newly allocated SMD channel * @alloc_elm: the allocation element stored in SMEM for this channel * @table_id: the id of the table this channel resides in. 1 = first table, 2 = *		seconds table, etc * @r_info: pointer to the info structure of the remote proc for this channel * @returns: -1 for failure; 0 for success */static int smd_alloc_channel(struct smd_alloc_elm *alloc_elm, int table_id,				struct remote_proc_info *r_info){	struct smd_channel *ch;	ch = kzalloc(sizeof(struct smd_channel), GFP_KERNEL);	if (ch == 0) {		pr_err("smd_alloc_channel() out of memory\n");		return -1;	}	ch->n = alloc_elm->cid;	ch->type = SMD_CHANNEL_TYPE(alloc_elm->type);	if (smd_alloc_v2(ch, table_id, r_info) && smd_alloc_v1(ch)) {		kfree(ch);		return -1;	}	ch->fifo_mask = ch->fifo_size - 1;	/* probe_worker guarentees ch->type will be a valid type */	if (ch->type == SMD_APPS_MODEM)		ch->notify_other_cpu = notify_modem_smd;	else if (ch->type == SMD_APPS_QDSP)		ch->notify_other_cpu = notify_dsp_smd;	else if (ch->type == SMD_APPS_DSPS)		ch->notify_other_cpu = notify_dsps_smd;	else if (ch->type == SMD_APPS_WCNSS)		ch->notify_other_cpu = notify_wcnss_smd;	else if (ch->type == SMD_APPS_RPM)		ch->notify_other_cpu = notify_rpm_smd;	if (smd_is_packet(alloc_elm)) {   //如果是 packet包 channel		ch->read = smd_packet_read;		ch->write = smd_packet_write;		ch->read_avail = smd_packet_read_avail;		ch->write_avail = smd_packet_write_avail;		ch->update_state = update_packet_state;		ch->read_from_cb = smd_packet_read_from_cb;		ch->is_pkt_ch = 1;	} else {                     //如果是 stream流 channel		ch->read = smd_stream_read;		ch->write = smd_stream_write;		ch->read_avail = smd_stream_read_avail;		ch->write_avail = smd_stream_write_avail;		ch->update_state = update_stream_state;		ch->read_from_cb = smd_stream_read;	}	memcpy(ch->name, alloc_elm->name, SMD_MAX_CH_NAME_LEN);	ch->name[SMD_MAX_CH_NAME_LEN-1] = 0;	ch->pdev.name = ch->name;	ch->pdev.id = ch->type;	SMD_INFO("smd_alloc_channel() '%s' cid=%d\n",		 ch->name, ch->n);	mutex_lock(&smd_creation_mutex);/互斥锁  	list_add(&ch->ch_list, &smd_ch_closed_list); //将信道添加到“smd_ch_closed_list”列表中	mutex_unlock(&smd_creation_mutex);	platform_device_register(&ch->pdev); //注册设备	if (!strncmp(ch->name, "LOOPBACK", 8) && ch->type == SMD_APPS_MODEM) {		/* create a platform driver to be used by smd_tty driver		 * so that it can access the loopback port		 */		loopback_tty_pdev.id = ch->type;		platform_device_register(&loopback_tty_pdev);	}	return 0;}

開啟channel- Open the SMD channel

常見在wifi driver初始化過程中會呼叫, 或是該driver需要SMD的話就會打開SMD啦…
為了打開一個信道channel,首先要判斷SMD 信道是否已經初始化。
如果SMD 信道已經初始化,就根據信道channel名獲得信道channel,將信道channel加入到“smd_ch_list”信道列表中並設置該信道的狀態為SMD_SS_OPENING,然後調用notify_other_smd()函數通知其他的信道該信道已經激活enable。

在默認default情況下,其信道類型為SMD_APPS_MODEM,打開一個SMD信道的實現如下:

int smd_named_open_on_edge(const char *name, uint32_t edge,			   smd_channel_t **_ch,			   void *priv, void (*notify)(void *, unsigned)){	struct smd_channel *ch;	unsigned long flags;	if (smd_initialized == 0 && !smd_edge_inited(edge)) {  //判断SMD 信道是否已初始化 		SMD_INFO("smd_open() before smd_init()\n");		return -ENODEV;	}	SMD_DBG("smd_open('%s', %p, %p)\n", name, priv, notify);	ch = smd_get_channel(name, edge);  //獲得channel頻道	if (!ch) {		/* check closing list for port */		spin_lock_irqsave(&smd_lock, flags); //自旋锁  		list_for_each_entry(ch, &smd_ch_closing_list, ch_list) {			if (!strncmp(name, ch->name, 20) &&				(edge == ch->type)) {				/* channel exists, but is being closed */				spin_unlock_irqrestore(&smd_lock, flags);				return -EAGAIN;			}		}		/* check closing workqueue list for port */		list_for_each_entry(ch, &smd_ch_to_close_list, ch_list) {			if (!strncmp(name, ch->name, 20) &&				(edge == ch->type)) {				/* channel exists, but is being closed */				spin_unlock_irqrestore(&smd_lock, flags);				return -EAGAIN;			}		}		spin_unlock_irqrestore(&smd_lock, flags);		/* one final check to handle closing->closed race condition */		ch = smd_get_channel(name, edge);		if (!ch)			return -ENODEV;	}	if (notify == 0)		notify = do_nothing_notify;	ch->notify = notify;	ch->current_packet = 0;	ch->last_state = SMD_SS_CLOSED;	ch->priv = priv;	if (edge == SMD_LOOPBACK_TYPE) {		ch->last_state = SMD_SS_OPENED;		ch->half_ch->set_state(ch->send, SMD_SS_OPENED);		ch->half_ch->set_fDSR(ch->send, 1);		ch->half_ch->set_fCTS(ch->send, 1);		ch->half_ch->set_fCD(ch->send, 1);	}	*_ch = ch;	SMD_DBG("smd_open: opening '%s'\n", ch->name);	spin_lock_irqsave(&smd_lock, flags); //自旋锁 	if (unlikely(ch->type == SMD_LOOPBACK_TYPE))		list_add(&ch->ch_list, &smd_ch_list_loopback); //将信道添加到“smd_ch_list_loopback”列表中	else		list_add(&ch->ch_list, &remote_info[edge_to_pids[ch->type].remote_pid].ch_list);	SMD_DBG("%s: opening ch %d\n", __func__, ch->n);	if (edge != SMD_LOOPBACK_TYPE)		smd_state_change(ch, ch->last_state, SMD_SS_OPENING); //信道状态变更 	spin_unlock_irqrestore(&smd_lock, flags);	return 0;}EXPORT_SYMBOL(smd_named_open_on_edge);

關閉信道- smd_close()

關閉信道的操作相對簡單,首先將信道從“smd_ch_list”信道列表中刪除,然後將信道狀態設置為SMD_SS_CLOSED,並將信道添加到“smd_ch_closed_list”信道列表中即可。關閉SMD 信道的實現如下:

int smd_close(smd_channel_t *ch){	unsigned long flags;	if (ch == 0)		return -1;	SMD_INFO("smd_close(%s)\n", ch->name);	spin_lock_irqsave(&smd_lock, flags); //自旋锁	list_del(&ch->ch_list); //从打开信道列表中去除该信道	if (ch->n == SMD_LOOPBACK_CID) {		ch->half_ch->set_fDSR(ch->send, 0);		ch->half_ch->set_fCTS(ch->send, 0);		ch->half_ch->set_fCD(ch->send, 0);		ch->half_ch->set_state(ch->send, SMD_SS_CLOSED);	} else		ch_set_state(ch, SMD_SS_CLOSED);   //设置信道状态	if (ch->half_ch->get_state(ch->recv) == SMD_SS_OPENED) {		list_add(&ch->ch_list, &smd_ch_closing_list);		spin_unlock_irqrestore(&smd_lock, flags);	} else {		spin_unlock_irqrestore(&smd_lock, flags);		ch->notify = do_nothing_notify;		mutex_lock(&smd_creation_mutex);  //互斥锁		list_add(&ch->ch_list, &smd_ch_closed_list); //将信道添加至关闭信道列表 		mutex_unlock(&smd_creation_mutex);	}	return 0;}EXPORT_SYMBOL(smd_close);

channel內容讀取-1. smd_packet_read

packet channel的內容讀取涉及緩衝的複制、與其他SMD 的消息通信和包狀態的更新。
從packet channel讀取數據的實現如下:

static int smd_packet_read(smd_channel_t *ch, void *data, int len, int user_buf){	unsigned long flags;	int r;	if (len < 0)		return -EINVAL;	if (len > ch->current_packet)		len = ch->current_packet;	r = ch_read(ch, data, len, user_buf); //读取数据	if (r > 0)		if (!read_intr_blocked(ch))			ch->notify_other_cpu(ch);	spin_lock_irqsave(&smd_lock, flags); //自旋锁	ch->current_packet -= r;	update_packet_state(ch); //更新包状态 	spin_unlock_irqrestore(&smd_lock, flags);	return r;

channel內容讀取-2. smd_stream_read

流信道的內容讀取非常簡單,只需要調用ch_read()函數讀取數據並通知其他SMD 該信道處於打開狀態即可。
smd_stream_read 流信道讀取的實現如下:

static int smd_stream_read(smd_channel_t *ch, void *data, int len, int user_buf){	int r;	if (len < 0)		return -EINVAL;	r = ch_read(ch, data, len, user_buf); //读取数据 	if (r > 0)		if (!read_intr_blocked(ch))			ch->notify_other_cpu(ch); //通知其他CPU,该信道处于激活状态。	return r;}

流信道和包信道在讀取信道數據時,
都需要調用ch_read()函數來實現真正的數據讀取

ch_read()函數的實現如下:

/* basic read interface to ch_read_{buffer,done} used * by smd_*_read() and update_packet_state() * will read-and-discard if the _data pointer is null */static int ch_read(struct smd_channel *ch, void *_data, int len, int user_buf){	void *ptr;	unsigned n;	unsigned char *data = _data;	int orig_len = len;	int r = 0;	while (len > 0) {		n = ch_read_buffer(ch, &ptr); //將channel的		if (n == 0)			break;		if (n > len)			n = len;		if (_data) {			if (user_buf) { //如果是來自user space的, 但我們目前看到的是 kernel 內部呼叫所以為else..				r = copy_to_user(data, ptr, n);				if (r > 0) {					pr_err("%s: "						"copy_to_user could not copy "						"%i bytes.\n",						__func__,						r);				}			} else				memcpy(data, ptr, n); //数据复制		}		data += n;		len -= n;		ch_read_done(ch, n); //读取完成	}	return orig_len - len;}

信道寫入-smd_packet_write

在信道的數據寫入方面,同樣分為流信道數據的寫入和包信道數據的寫入兩種類型。向包信道中寫入數據的過程和讀取數據不同,在寫入數據前,要首先利用smd_stream_write_avail()函數判斷是否有數據可供寫入,在確定有可供寫入的數據的情況下才調用sm​​d_stream_write()函數執行數據的寫入操作。包信道寫入數據的實現如下

static int smd_packet_write(smd_channel_t *ch, const void *_data, int len,				int user_buf){	int ret;	unsigned hdr[5];	SMD_DBG("smd_packet_write() %d -> ch%d\n", len, ch->n);	if (len < 0)		return -EINVAL;	else if (len == 0)		return 0;	if (smd_stream_write_avail(ch) < (len + SMD_HEADER_SIZE))		return -ENOMEM;	hdr[0] = len;	hdr[1] = hdr[2] = hdr[3] = hdr[4] = 0;	ret = smd_stream_write(ch, hdr, sizeof(hdr), 0); //流写入	if (ret < 0 || ret != sizeof(hdr)) {		SMD_DBG("%s failed to write pkt header: "			"%d returned\n", __func__, ret);		return -1;	}	ret = smd_stream_write(ch, _data, len, user_buf);	if (ret < 0 || ret != len) {		SMD_DBG("%s failed to write pkt data: "			"%d returned\n", __func__, ret);		return ret;	}	return len;}

smd_stream_write流信道數據的寫入
和包信道數據的寫入不同,
其首先獲得下一段可用緩衝的指針,然後執行內存複製,流信道寫入數據的實現如下:

static int smd_stream_write(smd_channel_t *ch, const void *_data, int len,				int user_buf){	void *ptr;	const unsigned char *buf = _data;	unsigned xfer;	int orig_len = len;	int r = 0;	SMD_DBG("smd_stream_write() %d -> ch%d\n", len, ch->n);	if (len < 0)		return -EINVAL;	else if (len == 0)		return 0;	while ((xfer = ch_write_buffer(ch, &ptr)) != 0) { //写入数据		if (!ch_is_open(ch)) {			len = orig_len;			break;		}		if (xfer > len)			xfer = len;		if (user_buf) {			r = copy_from_user(ptr, buf, xfer);			if (r > 0) {				pr_err("%s: "					"copy_from_user could not copy %i "					"bytes.\n",					__func__,					r);			}		} else			memcpy(ptr, buf, xfer);		ch_write_done(ch, xfer); //完成写入数据		len -= xfer;		buf += xfer;		if (len == 0)			break;	}	if (orig_len - len)		ch->notify_other_cpu(ch);	return orig_len - len;}

更仔細看 ch_write_buffer()

會提供指標給呼叫者, 也回傳寫入數目數字

static unsigned ch_write_buffer(struct smd_channel *ch, void **ptr){	unsigned head = ch->half_ch->get_head(ch->send); //得到head 頭的數字	unsigned tail = ch->half_ch->get_tail(ch->send); //得到tail 尾的數字	*ptr = (void *) (ch->send_data + head);   //將channel的傳送資料位置加上頭的數字, 則此指標就是可以寫入資料的位置	if (head < tail) {		return tail - head - SMD_FIFO_FULL_RESERVE; //如果頭數字反而比較小, 表示只有尾到頭這段是可以寫入(還要再扣掉保留區)	} else {		if (tail < SMD_FIFO_FULL_RESERVE)			return ch->fifo_size + tail - head - SMD_FIFO_FULL_RESERVE; //如果頭比尾的數字大, 可寫入的位置就是全部-頭+尾(還要再扣掉保留區)		else			return ch->fifo_size - head;	}}

FIFO 示意圖

更仔細看 ch_read_buffer()

會在FIFO中, 提供一個指標和可讀數據長度

static unsigned ch_read_buffer(struct smd_channel *ch, void **ptr){	unsigned head = ch->half_ch->get_head(ch->recv); //得到head 頭的數字	unsigned tail = ch->half_ch->get_tail(ch->recv); //得到tail 尾的數字	*ptr = (void *) (ch->recv_data + tail); //將channel的接受資料位置加上尾的數字, 則此指標就是可以接收資料的位置	if (tail <= head)		return head - tail; //由於要接收, 所以直觀上若尾比頭小, 表示尾到頭這段是可以接收的	else		return ch->fifo_size - tail; //反之, 由於要接收, 所以若頭比尾小, 表示全部扣掉尾那段是可以接收的}

SMD 是多核通信的基礎,
通過SMD,可以為系統提供RPC、DIAG、AT命令、NMEA(GPS數據)、數據服務、撥號等服務。

2014/11/10

android_get_control_socket() 是什麼用途啊?

看見ctrl_iface_unix.c的函式wpa_supplicant_global_ctrl_iface_init()有一段寫到
而ctrl為 wpa_wlan0

		/*		 * Backwards compatibility - try to open an Android control		 * socket and if that fails, assume this was a UNIX domain		 * socket instead.		 */		priv->sock = android_get_control_socket(ctrl);		if (priv->sock >= 0) {			wpa_printf(MSG_INFO,				   "Using Android control socket '%s'",				   ctrl);			goto havesock;		}

这个android_get_control_socket函数有什么作用呢?
android_get_control_socket函数定义在/system/core/include/cutils/sockets.h:

#define ANDROID_SOCKET_ENV_PREFIX   "ANDROID_SOCKET_"#define ANDROID_SOCKET_DIR      "/dev/socket"#ifdef __cplusplusextern "C" {#endif/* * android_get_control_socket - simple helper function to get the file * descriptor of our init-managed Unix domain socket. `name' is the name of the * socket, as given in init.rc. Returns -1 on error.翻成中文就是android_get_control_socket - 簡單的輔助功能,讓我們的初始化管理Unix domain socket的文件描述符(file descriptor)。 參數`name'是socket的名字,可在init.rc類型檔案被找到. 如果Return -1表示錯誤。 * * This is inline and not in libcutils proper because we want to use this in * third-party daemons with minimal modification. */static inline int android_get_control_socket(const char *name){    char key[64] = ANDROID_SOCKET_ENV_PREFIX;    const char *val;    int fd;    /* build our environment variable, counting cycles like a wolf ... */#if HAVE_STRLCPY    strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,        name,        sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));#else   /* for the host, which may lack the almightly strncpy ... */    strncpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,        name,        sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));    key[sizeof(key)-1] = '\0';#endif    val = getenv(key); // socket名字和对应的socket文件的文件描述符以键值对的形式存储在环境变量中,     if (!val)        return -1;    errno = 0;    fd = strtol(val, NULL, 10);    if (errno)        return -1;    return fd;}

也就是說…

//这一步很关键,就是获取init.rc中配置的名为 “SOCKET_NAME定義的字串” 的socket
fdListen = android_get_control_socket(SOCKET_NAME);

2014/11/04

source insight- 無法寫入SI.LOG檔 導致某檔案無法開啟

這幾天一直困擾我的問題竟然解決了
而且還是用一個超簡單方式

就是用 source insight我要開啟某一個檔案, 姑且叫做 werea_kick.c 檔
然後這個檔案怎樣都開不起來 = =!!!
顯示大致上說: “錯誤發生無法開啟xx/xx/xx/xx/werea_kick.c 也無法寫入SI.LOG檔”

方法:
後來就只是把SI.LOG備份成另一個SI.LOGBAK, 竟然就好了可以開啟了…
路徑如下:
C:\Users\YOURNAME\Documents\Source Insight\Logs\SI.LOG

2014/11/03

android 如何知道partition的分隔情形

常用有

mount
cat /proc/mtd
cat /proc/mounts
cat /proc/partitions
cat /proc/emmc

busybox fdisk -l /dev/block/mmcblk0
parted -l /dev/block/mmcblk0
gdisk -l /dev/block/mmcblk0

dmesg |grep “mmc”
dmesg |grep “partition”
cat /proc/kmesg >/path-to-your-writeable-area/kmesg.log

其他如下
可參考 http://forum.xda-developers.com/showthread.php?t=1959445

root@xxx:/ # df
df
Filesystem Size Used Free Blksize
/dev 910.6M 128.0K 910.5M 4096
/sys/fs/cgroup 910.6M 12.0K 910.6M 4096
/mnt/asec 910.6M 0.0K 910.6M 4096
/mnt/obb 910.6M 0.0K 910.6M 4096
/system 1.5G 349.8M 1.1G 4096
/data 25.6G 280.9M 25.3G 4096
/cache 251.8M 4.0M 247.8M 4096
/persist 4.9M 4.1M 804.0K 4096
/firmware 64.0M 58.0M 6.0M 16384
/fota 688.2M 10.9M 677.3M 4096
/carrier 31.4M 4.0M 27.4M 4096
/hidden 61.0M 15.2M 45.8M 4096
/BBSYS 7.8M 5.1M 2.8M 4096
/mnt/shell/emulated 25.6G 280.9M 25.3G 4096
/storage/emulated/legacy 25.6G 280.9M 25.3G 4096

root@xxx:/proc # cat partitions
cat partitions
major minor #blocks name
7 1 11458 loop1
179 0 30535680 mmcblk0
179 1 512 mmcblk0p1
179 2 32 mmcblk0p2
179 3 512 mmcblk0p3
179 4 512 mmcblk0p4
179 5 1024 mmcblk0p5
179 6 32 mmcblk0p6
179 7 5551 mmcblk0p7
179 8 1024 mmcblk0p8
179 9 3072 mmcblk0p9
179 10 3072 mmcblk0p10
179 11 3072 mmcblk0p11
179 12 3072 mmcblk0p12
179 13 3072 mmcblk0p13
179 14 1 mmcblk0p14
179 15 32 mmcblk0p15
179 16 8 mmcblk0p16
179 17 8151 mmcblk0p17
179 18 8192 mmcblk0p18
179 19 1024 mmcblk0p19
179 20 1024 mmcblk0p20
179 21 24576 mmcblk0p21
179 22 22528 mmcblk0p22
179 23 8192 mmcblk0p23
179 24 16384 mmcblk0p24
179 25 131072 mmcblk0p25
179 26 32768 mmcblk0p26
179 27 16384 mmcblk0p27
179 28 16384 mmcblk0p28
179 29 131072 mmcblk0p29
179 30 32768 mmcblk0p30
179 31 65536 mmcblk0p31
259 0 131072 mmcblk0p32
259 1 716800 mmcblk0p33
259 2 4096 mmcblk0p34
259 3 32768 mmcblk0p35
259 4 1572864 mmcblk0p36
259 5 262144 mmcblk0p37
259 6 27275247 mmcblk0p38
179 32 4096 mmcblk0rpmb

root@xxx:/ # ls -l /dev/block/platform/msm_sdcc.1/by-name/
ls -l /dev/block/platform/msm_sdcc.1/by-name/lrwxrwxrwx root root 1970-01-06 01:52 DDR -> /dev/block/mmcblk0p2lrwxrwxrwx root root 1970-01-06 01:52 aboot -> /dev/block/mmcblk0p5lrwxrwxrwx root root 1970-01-06 01:52 boot -> /dev/block/mmcblk0p27lrwxrwxrwx root root 1970-01-06 01:52 box -> /dev/block/mmcblk0p23lrwxrwxrwx root root 1970-01-06 01:52 cache -> /dev/block/mmcblk0p37lrwxrwxrwx root root 1970-01-06 01:52 carrier -> /dev/block/mmcblk0p35lrwxrwxrwx root root 1970-01-06 01:52 cda -> /dev/block/mmcblk0p32lrwxrwxrwx root root 1970-01-06 01:52 cust_nv -> /dev/block/mmcblk0p10lrwxrwxrwx root root 1970-01-06 01:52 dbi -> /dev/block/mmcblk0p15lrwxrwxrwx root root 1970-01-06 01:52 deviceinfo -> /dev/block/mmcblk0p8lrwxrwxrwx root root 1970-01-06 01:52 fotafs -> /dev/block/mmcblk0p33lrwxrwxrwx root root 1970-01-06 01:52 fotaraw -> /dev/block/mmcblk0p34lrwxrwxrwx root root 1970-01-06 01:52 fsc -> /dev/block/mmcblk0p14lrwxrwxrwx root root 1970-01-06 01:52 fsg -> /dev/block/mmcblk0p13lrwxrwxrwx root root 1970-01-06 01:52 ftmboot -> /dev/block/mmcblk0p24lrwxrwxrwx root root 1970-01-06 01:52 ftmdata -> /dev/block/mmcblk0p26lrwxrwxrwx root root 1970-01-06 01:52 ftmsys -> /dev/block/mmcblk0p25lrwxrwxrwx root root 1970-01-06 01:52 hidden -> /dev/block/mmcblk0p31lrwxrwxrwx root root 1970-01-06 01:52 hwcfg -> /dev/block/mmcblk0p6lrwxrwxrwx root root 1970-01-06 01:52 misc -> /dev/block/mmcblk0p17lrwxrwxrwx root root 1970-01-06 01:52 modem -> /dev/block/mmcblk0p29lrwxrwxrwx root root 1970-01-06 01:52 modemst1 -> /dev/block/mmcblk0p11lrwxrwxrwx root root 1970-01-06 01:52 modemst2 -> /dev/block/mmcblk0p12lrwxrwxrwx root root 1970-01-06 01:52 multisplash -> /dev/block/mmcblk0p22lrwxrwxrwx root root 1970-01-06 01:52 pad -> /dev/block/mmcblk0p7lrwxrwxrwx root root 1970-01-06 01:52 persist -> /dev/block/mmcblk0p30lrwxrwxrwx root root 1970-01-06 01:52 recovery -> /dev/block/mmcblk0p28lrwxrwxrwx root root 1970-01-06 01:52 rf_nv -> /dev/block/mmcblk0p9lrwxrwxrwx root root 1970-01-06 01:52 rpm -> /dev/block/mmcblk0p3lrwxrwxrwx root root 1970-01-06 01:52 sbl1 -> /dev/block/mmcblk0p1lrwxrwxrwx root root 1970-01-06 01:52 securefs -> /dev/block/mmcblk0p18lrwxrwxrwx root root 1970-01-06 01:52 splash -> /dev/block/mmcblk0p21lrwxrwxrwx root root 1970-01-06 01:52 ssd -> /dev/block/mmcblk0p16lrwxrwxrwx root root 1970-01-06 01:52 sutinfo -> /dev/block/mmcblk0p19lrwxrwxrwx root root 1970-01-06 01:52 system -> /dev/block/mmcblk0p36lrwxrwxrwx root root 1970-01-06 01:52 systeminfo -> /dev/block/mmcblk0p20lrwxrwxrwx root root 1970-01-06 01:52 tz -> /dev/block/mmcblk0p4lrwxrwxrwx root root 1970-01-06 01:52 userdata -> /dev/block/mmcblk0p38

關於分割partition:
#dmesg
<6>[ 4.836883] mmc0: BKOPS_EN bit = 0 ==> driver/core/mmc.c
<6>[ 4.850081] mmc0: new HS200 MMC card at address 0001 ==> driver/core/bus.c<6>[ 4.854226] mmcblk0: mmc0:0001 SEM32G 29.1 GiB<6>[ 4.858692] mmcblk0rpmb: mmc0:0001 SEM32G partition 3 4.00 MiB<3>[ 4.864333] qup_i2c f9928000.i2c: QUP: I2C status flags :0xc1300c8, irq:132<3>[ 4.871290] qup_i2c f9928000.i2c: I2C slave addr:0x33 not connected<3>[ 4.877589] lp5523x 6-0033: device detection err: -107<6>[ 4.878370] [bq2419x_charger_read_status] Read Reg08=0x6C, Reg09=0x00, stat_gpio:0/0, pg_gpio:0/0, hiz: 0/0<6>[ 4.882382] mmcblk0: p1 p2 p3 p4 p5 p6 p7 p8 p9 p10 p11 p12 p13 p14 p15 p16 p17 p18 p19 p20 p21 p22 p23 p24 p25 p26 p27 p28 p29 p30 p31 p32 p33 p34 p35 p36 p37 p38