2017年7月28日 星期五

從驅動程式原始碼認識USB OTG

USB OTG,

是USB-On-The-Go 的縮寫,

為USB 規格中的一個延伸,

擁有USB OTG功能的系統,(例如: 手機)

可以根據ID pin狀態的不同,

自行切換為host端或者client端,

已達到不同的目的使用.

例如:

a. 以手機接電腦,

手機會切換為client端,

這時可以把手機當隨身碟使用

b. 以手機接隨身碟,

手機會轉為host端,

讓手機能夠不透過電腦直接存取隨身碟裡面資料,





Google Git 上面可找到otg.c

可以讓我們

從驅動程式原始碼認識USB OTG


/**
* ci_otg_work - perform otg (vbus/id) event handle
* @work: work struct
*/
static void ci_otg_work(struct work_struct *work)
{
struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work);
if (ci_otg_is_fsm_mode(ci) && !ci_otg_fsm_work(ci)) {
enable_irq(ci->irq);
return;
}
if (ci->id_event) {
ci->id_event = false;
ci_handle_id_switch(ci);
} else if (ci->b_sess_valid_event) {
ci->b_sess_valid_event = false;
ci_handle_vbus_change(ci);
} else
dev_err(ci->dev, "unexpected event occurs at %s\n", __func__);
enable_irq(ci->irq);
}
當ID pin產生變化,

系統偵測到事件觸發,

執行ci_handle_id_switch(ci);

#define CI_VBUS_STABLE_TIMEOUT_MS 5000
static void ci_handle_id_switch(struct ci_hdrc *ci)
{
enum ci_role role = ci_otg_role(ci);
if (role != ci->role) {
dev_dbg(ci->dev, "switching from %s to %s\n",
ci_role(ci)->name, ci->roles[role]->name);
ci_role_stop(ci);
/* wait vbus lower than OTGSC_BSV */
hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0,
CI_VBUS_STABLE_TIMEOUT_MS);
ci_role_start(ci, role);
}
}
ci_otg_role(ci);

根據ID pin 腳位的不同

會選擇USB功能為:

CI_ROLE_GADGET (client)

CI_ROLE_HOST (host)

/**
* ci_otg_role - pick role based on ID pin state
* @ci: the controller
*/
enum ci_role ci_otg_role(struct ci_hdrc *ci)
{
enum ci_role role = hw_read_otgsc(ci, OTGSC_ID)
? CI_ROLE_GADGET
: CI_ROLE_HOST;
return role;
}

接著driver 會將此變化傳到應用層,

如果是Android 系統,

USB功能的變化就會傳給Android 做相對應的處理



沒有留言: