下面继续看设备控制器,设备控制器的启动过程,以及枚举,充电的整个流程。
//启动设备控制器
msm_otg_start_peripheral(&dev->otg, 1);//启动设备控制器
static void msm_otg_start_peripheral(struct otg_transceiver *xceiv, int on)
{
struct msm_otg *dev = container_of(xceiv, struct msm_otg, otg);
struct msm_otg_platform_data *pdata = dev->pdata;
if (!xceiv->gadget)
return;
if (on) {
....................
/*使能vbus控制连接*/
usb_gadget_vbus_connect(xceiv->gadget);
} else {
atomic_set(&dev->chg_type, USB_CHG_TYPE__INVALID);
/*去使能vbus控制连接*/
usb_gadget_vbus_disconnect(xceiv->gadget);
...............
}
}
static inline int usb_gadget_vbus_connect(struct usb_gadget *gadget)
{
if (!gadget->ops->vbus_session)
return -EOPNOTSUPP;
return gadget->ops->vbus_session(gadget, 1);//调用gadget的回调函数
}
//设置操作函数,在设备控制器的probe函数中赋值的
ui->gadget.ops = &msm72k_ops;
static const struct usb_gadget_ops msm72k_ops = {
.get_frame = msm72k_get_frame,
.vbus_session = msm72k_udc_vbus_session,//调用该函数
.vbus_draw = msm72k_udc_vbus_draw,
.pullup = msm72k_pullup,
.wakeup = msm72k_wakeup,
.set_selfpowered = msm72k_set_selfpowered,
};
//继续跟踪该函数的实现
static int msm72k_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
{
struct usb_info *ui = container_of(_gadget, struct usb_info, gadget);
struct msm_otg *otg = to_msm_otg(ui->xceiv);
if (is_active || atomic_read(&otg->chg_type) == USB_CHG_TYPE__WALLCHARGER)
wake_lock(&ui->wlock);//上锁
/*报告状态*/
msm_hsusb_set_vbus_state(is_active);
return 0;
}
void msm_hsusb_set_vbus_state(int online)
{
unsigned long flags;
struct usb_info *ui = the_usb_info;
............
spin_lock_irqsave(&ui->lock, flags);
if (is_usb_online(ui) == online)//如果已经是处于想要的状态,则退出
goto out;
if (online) {//根据传入的参数,对不同的状态赋值
ui->usb_state = USB_STATE_POWERED;//该状态时usb设备的枚举状态
ui->flags |= USB_FLAG_VBUS_ONLINE;
} else {
ui->gadget.speed = USB_SPEED_UNKNOWN;
ui->usb_state = USB_STATE_NOTATTACHED;//该状态时usb设备的枚举状态
ui->flags |= USB_FLAG_VBUS_OFFLINE;
}
if (in_interrupt()) {//然后调度work
schedule_work(&ui->work);
} else {
spin_unlock_irqrestore(&ui->lock, flags);
usb_do_work(&ui->work);//调度work
return;
}
out:
spin_unlock_irqrestore(&ui->lock, flags);
}
/*usb设备的状态如下*/
enum usb_device_state {
USB_STATE_NOTATTACHED = 0,
USB_STATE_ATTACHED,
USB_STATE_POWERED, /* wired */
USB_STATE_RECONNECTING,/* auth */
USB_STATE_UNAUTHENTICATED, /* auth */
USB_STATE_DEFAULT, /* limited function */
USB_STATE_ADDRESS,
USB_STATE_CONFIGURED, /* most functions */
USB_STATE_SUSPENDED
};
//进入另外一个状态机的循环,跟踪usb_do_work,跟踪前看下该状态机的状态定义
#define USB_STATE_IDLE 0
#define USB_STATE_ONLINE 1
#define USB_STATE_OFFLINE 2
//驱动状态机的是ui的flag标记:
调度work前,看下该状态机现在处于什么状态:
//分析前先看下调度该work之前的状态
int usb_gadget_register_driver(struct usb_gadget_driver *driver)
{
struct usb_info *ui = the_usb_info;
................
atomic_set(&ui->softconnect, 1);//设置软件连接为1
...................
dev_dbg(&ui->pdev->dev, "registered gadget driver '%s'\n",driver->driver.name);
usb_start(ui);//usb启动
return 0;
}
static void usb_start(struct usb_info *ui)
{
unsigned long flags;
ui->flags |= USB_FLAG_START;
schedule_work(&ui->work);//调度work
}
//设置相应标记后调度work
static void usb_do_work(struct work_struct *w)
{
struct usb_info *ui = container_of(w, struct usb_info, work);
struct msm_otg *otg = to_msm_otg(ui->xceiv);
unsigned long iflags;
unsigned flags, _vbus;
for (;;) {
flags = ui->flags;
ui->flags = 0;
_vbus = is_usb_online(ui);
/* give up if we have nothing to do */
if (flags == 0)//如果没什么变化,跳出该work
break;
switch (ui->state) {//ui->state的默认状态为0
case USB_STATE_IDLE:
if (flags & USB_FLAG_START) {
if (!_vbus) {
ui->state = USB_STATE_OFFLINE;//停留在该状态
break;
}
............................
}//状态处理结束
}
}
//在进入该处理函数的时候,该状态机已经处于USB_STATE_OFFLINE状态
static void usb_do_work(struct work_struct *w)
{
struct usb_info *ui = container_of(w, struct usb_info, work);
struct msm_otg *otg = to_msm_otg(ui->xceiv);
unsigned long iflags;
unsigned flags, _vbus;
for (;;) {
spin_lock_irqsave(&ui->lock, iflags);
flags = ui->flags;//取出flag的值
ui->flags = 0;//清除flag
_vbus = is_usb_online(ui);//是否还在连接着?
spin_unlock_irqrestore(&ui->lock, iflags);
/* give up if we have nothing to do */
if (flags == 0)//没有改变,则退出
break;
switch (ui->state) {
.................
case USB_STATE_OFFLINE:
if ((flags & USB_FLAG_VBUS_ONLINE) && _vbus) {//从offline迁移到online
................
dev_dbg(&ui->pdev->dev,"msm72k_udc: OFFLINE -> ONLINE\n");
usb_reset(ui);
ui->state = USB_STATE_ONLINE;//设置状态为online
usb_do_work_check_vbus(ui);//再次检测vbus状态
ret = request_irq(otg->irq, usb_interrupt,/*注册中断处理函数*/IRQF_SHARED, ui->pdev->name, ui);
........................
ui->irq = otg->irq;
enable_irq_wake(otg->irq);//设置该中断有唤醒系统功能
if (!atomic_read(&ui->softconnect))//软连接已经置为1
break;
msm72k_pullup_internal(&ui->gadget, 1);//软件使能D+上拉电阻,使能后主机开始检查到有usb设备插入,开始漫长的枚举过程
if (!ui->gadget.is_a_peripheral)
schedule_delayed_work(&ui->chg_det, USB_CHG_DET_DELAY);//执行检查usb充电器类型的work
}
break;
}
}
}
/*下面看上拉电阻的使能实现*/
static int msm72k_pullup_internal(struct usb_gadget *_gadget, int is_active)
{
struct usb_info *ui = container_of(_gadget, struct usb_info, gadget);
unsigned long flags;
if (is_active) {
spin_lock_irqsave(&ui->lock, flags);
if (is_usb_online(ui) && ui->driver)
writel(readl(USB_USBCMD) | USBCMD_RS, USB_USBCMD);//往寄存器里面写入启动命令USBCMD_RS
spin_unlock_irqrestore(&ui->lock, flags);
} else {
writel(readl(USB_USBCMD) & ~USBCMD_RS, USB_USBCMD);
/* S/W workaround, Issue#1 */
otg_io_write(ui->xceiv, 0x48, 0x04);
}
/* Ensure pull-up operation is completed before returning */
mb();
return 0;
}
//在执行检查充电器的delay work之前进行的usb设备的枚举,枚举前先看spec上的定义
#define USB_USBSTS (MSM_USB_BASE + 0x0144)
#define STS_NAKI (1 << 16) /* */
#define STS_SLI (1 << 8) /* R/WC - suspend state entered */
#define STS_SRI (1 << 7) /* R/WC - SOF recv'd */
#define STS_URI (1 << 6) /* R/WC - RESET recv'd */
#define STS_FRI (1 << 3) /* R/WC - Frame List Rollover */
#define STS_PCI (1 << 2) /* R/WC - Port Change Detect */
#define STS_UEI (1 << 1) /* R/WC - USB Error */
#define STS_UI (1 << 0) /* R/WC - USB Transaction Complete */
STS_UI:
USB interrupt (USBINT)
Read/write control
This bit is set (1) by the host/device controller when the cause
of an interrupt is a completion of a USB transaction where the
transfer descriptor (TD) has an interrupt-on-complete (IOC) bit set (1).
This bit is also set (1) by the host/device controller when a
short packet is detected. A short packet is when the actual
number of bytes received was less than the expected number
of bytes.
STS_PCI:
Port change detect
Read/write control
The host controller sets (1) this bit when a connect status
occurs on any port, a port enable/disable change occurs on
any port, or the force port resume bit is set (1) as the result of
a J-K transition on the suspended port.
The device controller sets (1) this bit when the port controller
enters the full or high-speed operational state. When the port
controller exits the full or high-speed operation states due to
reset or suspend events, the notification mechanisms are the
USB reset received bit and the DC suspend bits, respectively.
This bit is not EHCI compatible
USB_ENDPTSETUPSTAT:
端点每接收到一个setup事务时,在寄存器中会设置相应的位,读取完该设置数据时,
软件必须向相应的位写1,以清除该位。该寄存器只用于设备模式。
static irqreturn_t usb_interrupt(int irq, void *data)
{
struct usb_info *ui = data;
unsigned n;
unsigned long flags;
n = readl(USB_USBSTS);//读取状态寄存器,并保存起来
writel(n, USB_USBSTS);//清除该状态寄存器
/* somehow we got an IRQ while in the reset sequence: ignore it */
if (!atomic_read(&ui->running))
return IRQ_HANDLED;
if (n & STS_PCI) {//端口有变化
msm_hsusb_set_speed(ui);
if (atomic_read(&ui->configured)) {
ui->usb_state = USB_STATE_CONFIGURED;
ui->flags = USB_FLAG_CONFIGURED;
ui->driver->resume(&ui->gadget);
schedule_work(&ui->work);
} else {
msm_hsusb_set_state(USB_STATE_DEFAULT);
}
}
if (n & STS_URI) {//重启
dev_dbg(&ui->pdev->dev, "reset\n");
ui->gadget.speed = USB_SPEED_UNKNOWN;
msm_hsusb_set_state(USB_STATE_DEFAULT);
..............
if (ui->driver) {
dev_dbg(&ui->pdev->dev,
"usb: notify offline\n");
ui->driver->disconnect(&ui->gadget);
}
}
if (n & STS_SLI) {//挂起
dev_dbg(&ui->pdev->dev, "suspend\n");
............
ui->usb_state = USB_STATE_SUSPENDED;
ui->flags = USB_FLAG_SUSPEND;
ui->driver->suspend(&ui->gadget);
schedule_work(&ui->work);
}
if (n & STS_UI) {//usb事务完成
n = readl(USB_ENDPTSETUPSTAT);
if (n & EPT_RX(0))/*取出接收端点0的状态#define EPT_RX(n) (1 << (n))*/
handle_setup(ui);//枚举开始
n = readl(USB_ENDPTCOMPLETE);
writel(n, USB_ENDPTCOMPLETE);
while (n) {
unsigned bit = __ffs(n);
handle_endpoint(ui, bit);
n = n & (~(1 << bit));
}
}
return IRQ_HANDLED;
}
static void handle_setup(struct usb_info *ui)
{
struct usb_ctrlrequest ctl;
struct usb_request *req = ui->setup_req;
int ret;
udelay(10);
memcpy(&ctl, ui->ep0out.head->setup_data, sizeof(ctl));//从ep0out的端点的队列头部取出setup数据
/* Ensure buffer is read before acknowledging to h/w */
dsb();
writel(EPT_RX(0), USB_ENDPTSETUPSTAT);//清除该端点的状态
if (ctl.bRequestType & USB_DIR_IN)//判断该请求的方向,并设置方向
atomic_set(&ui->ep0_dir, USB_DIR_IN);
else
atomic_set(&ui->ep0_dir, USB_DIR_OUT);
/* 取消任何被挂起的ep0事务 */
flush_endpoint(&ui->ep0out);
flush_endpoint(&ui->ep0in);
dev_dbg(&ui->pdev->dev,"setup: type=%02x req=%02x val=%04x idx=%04x len=%04x\n",
ctl.bRequestType, ctl.bRequest, ctl.wValue,
ctl.wIndex, ctl.wLength);
if ((ctl.bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) == (USB_DIR_IN | USB_TYPE_STANDARD)) {//收到的请求为in,类型为标准
if (ctl.bRequest == USB_REQ_GET_STATUS) {//获得usb状态
u8 len = 2;
switch (ctl.bRequestType & USB_RECIP_MASK) {//获得设备的状态
case USB_RECIP_ENDPOINT:
{
struct msm_endpoint *ept;
unsigned num =
ctl.wIndex & USB_ENDPOINT_NUMBER_MASK;
u16 temp = 0;
if (num == 0) {
memset(req->buf, 0, 2);
break;
}
if (ctl.wIndex & USB_ENDPOINT_DIR_MASK)
num += 16;
ept = &ui->ep0out + num;
temp = usb_ep_get_stall(ept);
temp = temp << USB_ENDPOINT_HALT;
memcpy(req->buf, &temp, 2);
break;
}
case USB_RECIP_DEVICE:
{
u16 temp = 0;
if (ctl.wIndex == OTG_STATUS_SELECTOR) {
goto stall;
} else {
temp = (atomic_read(&ui->self_powered)
<< USB_DEVICE_SELF_POWERED);
temp |= (atomic_read(&ui->remote_wakeup)
<< USB_DEVICE_REMOTE_WAKEUP);
memcpy(req->buf, &temp, 2);
}
break;
}
case USB_RECIP_INTERFACE:
memset(req->buf, 0, 2);
break;
default:
goto stall;
}
ep0_setup_send(ui, len);//把获得usb状态发送出去
return;
}
}
if (ctl.bRequestType == (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)) {//收到的请求是OUT,类型为标准,接收为端点
if ((ctl.bRequest == USB_REQ_CLEAR_FEATURE) ||(ctl.bRequest == USB_REQ_SET_FEATURE)) {//设置特性和清除特性
if ((ctl.wValue == 0) && (ctl.wLength == 0)) {
unsigned num = ctl.wIndex & 0x0f;
if (num != 0) {
struct msm_endpoint *ept;
if (ctl.wIndex & 0x80)
num += 16;
ept = &ui->ep0out + num;
if (ept->wedged)
goto ack;
if (ctl.bRequest == USB_REQ_SET_FEATURE)
usb_ept_set_halt(&ept->ep, 1);
else
usb_ept_set_halt(&ept->ep, 0);
}
goto ack;//先主机返回ack信号
}
}
}
if (ctl.bRequestType == (USB_DIR_OUT | USB_TYPE_STANDARD)) {//传输方向为out,类型为标准
if (ctl.bRequest == USB_REQ_SET_CONFIGURATION) {//设置请求
atomic_set(&ui->configured, !!ctl.wValue);//为该设备设置是否配置的标记,该标记在获得电流时要用到
msm_hsusb_set_state(USB_STATE_CONFIGURED);//状态为config状态
} else if (ctl.bRequest == USB_REQ_SET_ADDRESS) {//如果请求是设置地址
msm_hsusb_set_state(USB_STATE_ADDRESS);//设置状态迁移到地址
/* write address delayed (will take effect after the next IN txn)*/
writel((ctl.wValue << 25) | (1 << 24), USB_DEVICEADDR);//#define USB_DEVICEADDR (MSM_USB_BASE + 0x0154),写入分配的地址到硬件寄存器
goto ack;
} else if (ctl.bRequest == USB_REQ_SET_FEATURE) { //设置特性
switch (ctl.wValue) {
..................
case USB_DEVICE_REMOTE_WAKEUP:
atomic_set(&ui->remote_wakeup, 1);
goto ack;
}
} else if ((ctl.bRequest == USB_REQ_CLEAR_FEATURE) && (ctl.wValue == USB_DEVICE_REMOTE_WAKEUP)) {//清除特性
atomic_set(&ui->remote_wakeup, 0);
goto ack;
}
}
/* delegate if we get here */
if (ui->driver) {
ret = ui->driver->setup(&ui->gadget, &ctl);//调用driver的setup继续枚举
if (ret >= 0)
return;
}
stall:
/* stall ep0 on error */
ep0_setup_stall(ui);
return;
ack:
ep0_setup_ack(ui);//向对方发送ack信号
}
/*下一步调用的回调函数如下*/
static int composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = get_gadget_data(gadget);
struct usb_request *req = cdev->req;
int value = -EOPNOTSUPP;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u8 intf = w_index & 0xFF;
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
struct usb_function *f = NULL;
u8 endp;
int tmp = intf;
int id = 0;
unsigned long flags;
spin_lock_irqsave(&cdev->lock, flags);
if (!cdev->connected) {
cdev->connected = 1;//该cdev连接
schedule_work(&cdev->switch_work);
}
spin_unlock_irqrestore(&cdev->lock, flags);
req->zero = 0;
req->complete = composite_setup_complete;//回调函数
req->length = USB_BUFSIZ;
gadget->ep0->driver_data = cdev;
switch (ctrl->bRequest) {//处理请求
/* we handle all standard USB descriptors */
case USB_REQ_GET_DESCRIPTOR://只处理in请求
if (ctrl->bRequestType != USB_DIR_IN)
goto unknown;
switch (w_value >> 8) {
case USB_DT_DEVICE://设备描述符
cdev->desc.bNumConfigurations = count_configs(cdev, USB_DT_DEVICE);
value = min(w_length, (u16) sizeof cdev->desc);
memcpy(req->buf, &cdev->desc, value);//拷贝设备描述符到req的buf中
break;
case USB_DT_CONFIG://配置描述符
value = config_desc(cdev, w_value);//把描述符追加到一个buffer中
if (value >= 0)
value = min(w_length, (u16) value);
break;
case USB_DT_STRING://字符串描述符
value = get_string(cdev, req->buf,w_index, w_value & 0xff);
..............
if (value >= 0)
value = min(w_length, (u16) value);
break;
}
break;
/* any number of configs can work */
case USB_REQ_SET_CONFIGURATION://设置配置
if (ctrl->bRequestType != 0)
goto unknown;
value = set_config(cdev, ctrl, w_value);//继续调用设置配置函数
break;
case USB_REQ_GET_CONFIGURATION://获得配置值
if (ctrl->bRequestType != USB_DIR_IN)
goto unknown;
if (cdev->config)
*(u8 *)req->buf = cdev->config->bConfigurationValue;
else
*(u8 *)req->buf = 0;
value = min(w_length, (u16) 1);
break;
case USB_REQ_SET_INTERFACE://设置接口设置
if (ctrl->bRequestType != USB_RECIP_INTERFACE)
goto unknown;
f = cdev->config->interface[intf];
if (w_value && !f->set_alt)
break;
value = f->set_alt(f, w_index, w_value);//调用设置指定的funciton设置接口的函数
break;
case USB_REQ_GET_INTERFACE://获得接口设置
if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
goto unknown;
f = cdev->config->interface[intf];
/* lots of interfaces only need altsetting zero... */
value = f->get_alt ? f->get_alt(f, w_index) : 0;
*((u8 *)req->buf) = value;
value = min(w_length, (u16) 1);
break;
default:
............
/* respond with data transfer before status phase? */
if (value >= 0) {
req->length = value;//传输的长度
req->zero = value < w_length;
value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);//把该请求入队
if (value < 0) {
DBG(cdev, "ep_queue --> %d\n", value);
req->status = 0;
composite_setup_complete(gadget->ep0, req);
}
}
done:
return value;
}
/*下面主要分析是设置配置和设置接口*/
1、设置配置
static int set_config(struct usb_composite_dev *cdev, const struct usb_ctrlrequest *ctrl, unsigned number)/*number为设置的编号*/
{
struct usb_gadget *gadget = cdev->gadget;
struct usb_configuration *c = NULL;
int result = -EINVAL;
unsigned power = gadget_is_otg(gadget) ? 8 : 100;//没有配置提供100mA的电流
int tmp;
if (cdev->config)//如果config已经配置,则reset该config
reset_config(cdev);
if (number) {//如果配置号不为0,通过该配置号,找到配置
list_for_each_entry(c, &cdev->configs, list) {
if (c->bConfigurationValue == number) {
result = 0;//找到reuslt为0
break;
}
}
if (result < 0)
goto done;
} else
result = 0;
INFO(cdev, "%s speed config #%d: %s\n", //打印速度信息,以及所选择的配置
({ char *speed;
switch (gadget->speed) {
case USB_SPEED_LOW: speed = "low"; break;
case USB_SPEED_FULL: speed = "full"; break;
case USB_SPEED_HIGH: speed = "high"; break;
default: speed = "?"; break;
} ; speed; }), number, c ? c->label : "unconfigured");
if (!c)
goto done;
cdev->config = c;//把选到的配置挂到cdev上
/* Initialize all interfaces by setting them to altsetting zero. */
for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) {
struct usb_function *f = c->interface[tmp];//取出该配置下的每个接口
struct usb_descriptor_header **descriptors;
if (!f)//如果该接口为空,直接跳出
break;
if (f->disabled)//如果该funciton为disabled则继续下一个
continue;
if (gadget->speed == USB_SPEED_HIGH)//如果gadget为高速
descriptors = f->hs_descriptors;
else//如果为低速或者全速
descriptors = f->descriptors;
for (; *descriptors; ++descriptors) {//遍历所有的描述符,找到端点描述符
struct usb_endpoint_descriptor *ep;
int addr;
if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT)//如果描述符类型不为端点,则找下一个
continue;
ep = (struct usb_endpoint_descriptor *)*descriptors;//找到端点描述符
addr = ((ep->bEndpointAddress & 0x80) >> 3) | (ep->bEndpointAddress & 0x0f);/*计算出地址,方向位+端点地址*/
set_bit(addr, f->endpoints);//设置该fution的端点地址
}
result = f->set_alt(f, tmp, 0);//调用该function的设置函数
..........
}
/* when we return, be sure our power usage is valid */
power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW;//该配置需要的电流
done:
usb_gadget_vbus_draw(gadget, power);//该设备要拉多少电流
schedule_work(&cdev->switch_work);//调用switch work上报状态
return result;
}
下面以adb为例,说明set_alt的设置:
static int adb_function_set_alt(struct usb_function *f,unsigned intf, unsigned alt)/*传入的参数为接口号和设置号*/
{
struct adb_dev *dev = func_to_dev(f);
struct usb_composite_dev *cdev = f->config->cdev;
int ret;
DBG(cdev, "adb_function_set_alt intf: %d alt: %d\n", intf, alt);
ret = usb_ep_enable(dev->ep_in,ep_choose(cdev->gadget,&adb_highspeed_in_desc,&adb_fullspeed_in_desc));
if (ret)
return ret;
ret = usb_ep_enable(dev->ep_out,ep_choose(cdev->gadget, &adb_highspeed_out_desc, &adb_fullspeed_out_desc));
if (ret) {
usb_ep_disable(dev->ep_in);
return ret;
}
atomic_set(&dev->online, 1);//设置该adb device的状态为online
/* readers may be blocked waiting for us to go online */
wake_up(&dev->read_wq);//唤醒adb的读线程
return 0;
}
//支持双速,并且gadget又是高速,则返回高速描述符
static inline struct usb_endpoint_descriptor *ep_choose(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, struct usb_endpoint_descriptor *fs)
{
if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
return hs;
return fs;
}
static inline int usb_ep_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc)
{
return ep->ops->enable(ep, desc);//使能该接口用的各个端点
}
static const struct usb_ep_ops msm72k_ep_ops = {
.enable = msm72k_enable,
.disable = msm72k_disable,
.alloc_request = msm72k_alloc_request,
.free_request = msm72k_free_request,
.queue = msm72k_queue,
.dequeue = msm72k_dequeue,
.set_halt = msm72k_set_halt,
.set_wedge = msm72k_set_wedge,
.fifo_status = msm72k_fifo_status,
.fifo_flush = msm72k_fifo_flush,
};
static int msm72k_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)//传入的参数为端点和该端点的描述符
{
struct msm_endpoint *ept = to_msm_endpoint(_ep);
unsigned char ep_type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
_ep->maxpacket = le16_to_cpu(desc->wMaxPacketSize);
config_ept(ept);//配置端点
ept->wedged = 0;
usb_ept_enable(ept, 1, ep_type);//使能端点
return 0;
}
static void config_ept(struct msm_endpoint *ept)
{
struct usb_info *ui = ept->ui;
unsigned cfg = CONFIG_MAX_PKT(ept->ep.maxpacket) | CONFIG_ZLT;//#define CONFIG_ZLT (1 << 29) /* stop on zero-len xfer */
/* ep0 out needs interrupt-on-setup */
if (ept->bit == 0)//ep0 out端点,需要在设置数据包到来时,产生中断
cfg |= CONFIG_IOS;
ept->head->config = cfg; //把该配置挂到head的config上,表明该端点的所有配置
ept->head->next = TERMINATE;
}
static void usb_ept_enable(struct msm_endpoint *ept, int yes, unsigned char ep_type)//yes=1
{
struct usb_info *ui = ept->ui;
int in = ept->flags & EPT_FLAG_IN;//该端点的方向
unsigned n;
n = readl(USB_ENDPTCTRL(ept->num));//#define USB_ENDPTCTRL(n) (MSM_USB_BASE + 0x01C0 + (4 * (n)));获得该端点的控制寄存器,并读取该寄存器的值
if (in) {
if (yes) {
n = (n & (~CTRL_TXT_MASK)) | (ep_type << CTRL_TXT_EP_TYPE_SHIFT);//清除端点类型,重新赋值
n |= CTRL_TXE | CTRL_TXR;//发送端点使能
} else
n &= (~CTRL_TXE);//发送端点关闭
} else {
if (yes) {
n = (n & (~CTRL_RXT_MASK)) | (ep_type << CTRL_RXT_EP_TYPE_SHIFT);//清除端点类型,重新赋值
n |= CTRL_RXE | CTRL_RXR;
} else
n &= ~(CTRL_RXE);
}
/* complete all the updates to ept->head before enabling endpoint*/
mb();
writel(n, USB_ENDPTCTRL(ept->num));//把配置后的值,写入该控制寄存器
/* Ensure endpoint is enabled before returning */
dsb();
dev_dbg(&ui->pdev->dev, "ept %d %s %s\n", ept->num, in ? "in" : "out", yes ? "enabled" : "disabled");
}
#define CTRL_TXT_EP_TYPE_SHIFT 18
#define CTRL_TXT_MASK (3 << 18)
#define CTRL_TXE (1 << 23)
#define CTRL_TXR (1 << 22)
#define CTRL_RXT_EP_TYPE_SHIFT 2
#define CTRL_RXT_MASK (3 << 2)
#define CTRL_RXE (1 << 7)
#define CTRL_RXR (1 << 6)
下面是各个宏的解释:
23:TXE
Tx endpoint enable
value 0 = Disabled (default)
value 1 = Enabled
An endpoint should be enabled only after it has been configured.
22:TXR
Tx data toggle reset (WS)
value 1 = Reset PID sequence
Whenever a configuration event is received for this endpoint,
the software must set (1) this bit in order to synchronize the
data PIDs between the host and device.
18/19:TXT
Tx endpoint type
value 00 = Control
value 01 = Isochronous
value 10 = Bulk
value 11 = Interrupt
RXE
Rx endpoint enable
value 1 = Enabled
Endpoint0 is always enabled. Read only
usb_gadget_vbus_draw(gadget, power);//该设备要拉多少电流
//继续跟踪该函数的实现
static inline int usb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
{
if (!gadget->ops->vbus_draw)
return -EOPNOTSUPP;
return gadget->ops->vbus_draw(gadget, mA);
}
//继续跟中该回调函数
static int msm72k_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
{
struct usb_info *ui = container_of(_gadget, struct usb_info, gadget);
unsigned long flags;
pr_info("%s:The vbus draw %d mA.\n",__func__,mA);
ui->b_max_pow = mA;//最大电流
ui->flags = USB_FLAG_CONFIGURED;//配置状态
schedule_work(&ui->work);//此时的状态为ui->state = USB_STATE_ONLINE
return 0;
}
/***********************************************************************************/
//设置相应标记后调度work
static void usb_do_work(struct work_struct *w)
{
struct usb_info *ui = container_of(w, struct usb_info, work);
struct msm_otg *otg = to_msm_otg(ui->xceiv);
unsigned long iflags;
unsigned flags, _vbus;
for (;;) {
flags = ui->flags;
ui->flags = 0;
_vbus = is_usb_online(ui);
/* give up if we have nothing to do */
if (flags == 0)
break;
switch (ui->state) {
...................
case USB_STATE_ONLINE:
...........
if (flags & USB_FLAG_CONFIGURED) {
int maxpower = usb_get_max_power(ui);//实现下面有分析
switch_set_state(&ui->sdev,atomic_read(&ui->configured));//发送配置状态
if (maxpower < 0)
break;
ui->chg_current = maxpower;
otg_set_power(ui->xceiv, maxpower);
break;
}
break;
}//状态处理结束
}
}
下面看下usb_get_max_power()的实现
/*********************************************************************/
#define USB_WALLCHARGER_CHG_CURRENT 1000
#define USB_DOCKCHARGER_CHG_CURRENT 1800
static int usb_get_max_power(struct usb_info *ui)
{
struct msm_otg *otg = to_msm_otg(ui->xceiv);
unsigned long flags;
enum chg_type temp;
int suspended;
int configured;
unsigned bmaxpow;
temp = atomic_read(&otg->chg_type);
suspended = ui->usb_state == USB_STATE_SUSPENDED ? 1 : 0;
configured = atomic_read(&ui->configured);//该usb的配置值
bmaxpow = ui->b_max_pow;
if (temp == USB_CHG_TYPE__INVALID)
return -ENODEV;
if (temp == USB_CHG_TYPE__WALLCHARGER)
return USB_WALLCHARGER_CHG_CURRENT;//充电类型是wall charger时,返回1000
if (temp == USB_CHG_TYPE__DOCKCHARGER)
return USB_DOCKCHARGER_CHG_CURRENT;//充电器类型为dock charger时,返回1800
if (suspended || !configured)//如果设备挂起,或者没有进行配置时,返回0
return 0;
return bmaxpow;//返回usb配置后能从总线上获得的电流
}
/*********************************************************************/
/*下面的work是针对没有枚举过程的充电器检测*/
INIT_DELAYED_WORK(&ui->chg_det, usb_chg_detect);//检测充电器类型的work
static void usb_chg_detect(struct work_struct *w)
{
struct usb_info *ui = container_of(w, struct usb_info, chg_det.work);
struct msm_otg *otg = to_msm_otg(ui->xceiv);
enum chg_type temp = USB_CHG_TYPE__INVALID;
unsigned long flags;
int maxpower;
if (ui->usb_state == USB_STATE_NOTATTACHED) {
return;
}
temp = usb_get_chg_type(ui);//读取usb的
/*************************************************************************/
PORTSC_LS:寄存器
These bits reflect the current logical levels of the D+ (bit 11)
and D- (bit 10) signal lines:
Value Meaning
value 00 SE0
value 10 J-state
value 01 K-state
value 11 Undefined
In the host mode, the use of linestate by the host controller
driver is not necessary (unlike EHCI), because the port
controller state machine and the port routing manage the
connection of LS and FS.
In the device mode, the use of linestate by the device controller
driver is not necessary.
/*************************************************************************/
static inline enum chg_type usb_get_chg_type(struct usb_info *ui)
{
int status = (readl(USB_PORTSC) & PORTSC_LS) >> 10;
dev_info(&ui->pdev->dev, "PORTSC_LS is: 0x%x\n", status);
switch (status){
case 0:
case 1:
case 2:
return USB_CHG_TYPE__SDP;
case 3:
return USB_CHG_TYPE__WALLCHARGER;
default :
return -1;
}
}
/*************************************************************************/
atomic_set(&otg->chg_type, temp);
maxpower = usb_get_max_power(ui);//获得充电的最大电流
if (maxpower > 0)
otg_set_power(ui->xceiv, maxpower);//设置最大电流
}
static inline int otg_set_power(struct otg_transceiver *otg, unsigned mA)
{
return otg->set_power(otg, mA);
}
dev->otg.set_power = msm_otg_set_power;//该回调函数如下
static int msm_otg_set_power(struct otg_transceiver *xceiv, unsigned mA)
{
struct msm_otg *dev = container_of(xceiv, struct msm_otg, otg);
struct msm_otg_platform_data *pdata = dev->pdata;
enum chg_type new_chg = atomic_read(&dev->chg_type);
unsigned charge = mA;
pr_debug("Charging with %dmA current\n", charge);
/* Call vbus_draw only if the charger is of known type */
if (pdata->chg_vbus_draw )
pdata->chg_vbus_draw(charge);//调用充电流程
if (new_chg == USB_CHG_TYPE__WALLCHARGER) {
wake_lock(&dev->wlock);
queue_work(dev->wq, &dev->sm_work);
}
return 0;
}
/*注册的过程如下*/
static struct msm_otg_platform_data msm_otg_pdata = {
.............
#ifdef CONFIG_BATTERY_MSM8X60
.chg_vbus_draw = msm_charger_vbus_draw,
#endif
};
/* USB calls these to tell us how much charging current we should draw */
void msm_charger_vbus_draw(unsigned int mA)
{
struct msm_hardware_charger_priv *chg = NULL;
static struct msm_hardware_charger_priv *old = NULL;
pr_info("%s mA:%d\n", __func__, mA);
..........................
m_chg.current_chg_priv->max_source_current = mA;//能从主机获得充电器上获得电流
msm_charger_notify_event(msm_chg.current_chg_priv->hw_chg, CHG_ENUMERATED_EVENT);
return;
}
/*下面是该函数的大致调用流程*/
msm_charger_vbus_draw(unsigned int mA)
pr_info("%s mA:%d\n", __func__, mA);//正常时会打印该log:msm_charger_vbus_draw mA:500
msm_chg.current_chg_priv->max_source_current = mA;
msm_charger_notify_event(msm_chg.current_chg_priv->hw_chg, CHG_ENUMERATED_EVENT);
msm_chg_enqueue_event(hw_chg, event);
queue_work(msm_chg.event_wq_thread, &msm_chg.queue_work);
process_events(struct work_struct *work)
handle_event(event->hw_chg, event->event);
case CHG_ENUMERATED_EVENT: /* only in USB types */
priv->hw_chg_state = CHG_READY_STATE;
handle_charger_ready(priv);
msm_start_charging()//开始充电
priv->hw_chg->start_charging();//调用具体的芯片充电函数
msm_chg.batt_status = BATT_STATUS_TRKL_CHARGING;//设置msm_chg.batt_status的状态
case CHG_BATT_BEGIN_FAST_CHARGING:
/* only update if we are TRKL charging */
if (msm_chg.batt_status == BATT_STATUS_TRKL_CHARGING)
msm_chg.batt_status = BATT_STATUS_FAST_CHARGING;//设置msm_chg.batt_status的状态
到此设备控制器讲完,下一节看下主机控制器的整个启动流程。