📄 hc_sl811.c
字号:
goto out_unlock;
}
if (!sl811_alloc_urb_priv(urb)) {
ret = -ENOMEM;
//printk("righto: run to sl811_alloc_urb_priv()\n");
goto out_unlock;
}
switch (usb_pipetype(urb->pipe))
{
case PIPE_ISOCHRONOUS:
if (urb->number_of_packets <= 0) {
ret = -EINVAL;
break;
}
bustime = usb_check_bandwidth(urb->dev, urb);
if (bustime < 0) {
ret = bustime;
break;
}
if (!(ret = sl811_submit_isochronous(urb)))
usb_claim_bandwidth(urb->dev, urb, bustime, 1);
//printk("righto: run to PIPE_ISOCHRONOUS\n");
break;
case PIPE_INTERRUPT:
bustime = usb_check_bandwidth(urb->dev, urb);
if (bustime < 0)
ret = bustime;
else if (!(ret = sl811_submit_interrupt(urb)))
usb_claim_bandwidth(urb->dev, urb, bustime, 0);
//printk("righto: run to PIPE_INTERRUPT\n");
break;
case PIPE_CONTROL:
ret = sl811_submit_control(urb);
//printk("righto: run to PIPE_CONTOL\n");
break;
case PIPE_BULK:
ret = sl811_submit_bulk(urb);
//printk("righto: run to PIPE_BULK\n");
break;
}
if (!ret) {
((struct sl811_urb_priv *)urb->hcpriv)->inserttime = jiffies;
list_add(&urb->urb_list, head);
PDEBUG(4, "add to type list");
urb->status = -EINPROGRESS;
if (++hc->active_urbs == 1)
{
//printk("righto: sl811_enable_interrupt()\n");
sl811_enable_interrupt(hc);
}
//printk("righto: run to ret\n");
goto out_unlock;
} else {
PDEBUG(2, "submit urb fail! error = %d", ret);
//printk("righto: run to else");
sl811_free_urb_priv(urb);
}
out_unlock:
spin_unlock(&urb->lock);
spin_unlock_irqrestore(&hc->hc_lock, flags);
return ret;
}
/*
* Submit the urb the wait list.
*/
static int sl811_submit_urb_with_lock(struct urb *urb)
{
struct sl811_hc *hc = urb->dev->bus->hcpriv;
struct list_head *head = NULL;
int bustime;
int ret = 0;
spin_lock(&urb->lock);
switch (usb_pipetype(urb->pipe)) {
case PIPE_ISOCHRONOUS:
head = &hc->iso_list;
break;
case PIPE_INTERRUPT:
head = &hc->intr_list;
break;
case PIPE_CONTROL:
head = &hc->ctrl_list;
break;
case PIPE_BULK:
head = &hc->bulk_list;
break;
}
if (!sl811_alloc_urb_priv(urb)) {
ret = -ENOMEM;
goto out_unlock;
}
switch (usb_pipetype(urb->pipe)) {
case PIPE_ISOCHRONOUS:
if (urb->number_of_packets <= 0) {
ret = -EINVAL;
break;
}
bustime = usb_check_bandwidth(urb->dev, urb);
if (bustime < 0) {
ret = bustime;
break;
}
if (!(ret = sl811_submit_isochronous(urb)))
usb_claim_bandwidth(urb->dev, urb, bustime, 1);
break;
case PIPE_INTERRUPT:
bustime = usb_check_bandwidth(urb->dev, urb);
if (bustime < 0)
ret = bustime;
else if (!(ret = sl811_submit_interrupt(urb)))
usb_claim_bandwidth(urb->dev, urb, bustime, 0);
break;
case PIPE_CONTROL:
ret = sl811_submit_control(urb);
break;
case PIPE_BULK:
ret = sl811_submit_bulk(urb);
break;
}
if (ret == 0) {
((struct sl811_urb_priv *)urb->hcpriv)->inserttime = jiffies;
list_add(&urb->urb_list, head);
PDEBUG(4, "add to type list");
urb->status = -EINPROGRESS;
if (++hc->active_urbs == 1)
sl811_enable_interrupt(hc);
goto out_unlock;
} else {
PDEBUG(2, "submit urb fail! error = %d", ret);
sl811_free_urb_priv(urb);
}
out_unlock:
spin_unlock(&urb->lock);
return ret;
}
/*
* Reset the urb
*/
static void sl811_reset_urb(struct urb *urb)
{
struct sl811_urb_priv *urbp = urb->hcpriv;
switch (usb_pipetype(urb->pipe)) {
case PIPE_ISOCHRONOUS:
sl811_reset_isochronous(urb);
break;
case PIPE_INTERRUPT:
sl811_reset_interrupt(urb);
break;
case PIPE_CONTROL:
return;
case PIPE_BULK:
sl811_reset_bulk(urb);
break;
}
urbp->inserttime = jiffies;
}
/*
* Return the result of a transfer
*/
static void sl811_result_urb(struct urb *urb)
{
struct sl811_urb_priv *urbp = urb->hcpriv;
struct sl811_hc *hc = urb->dev->bus->hcpriv;
struct list_head *head = NULL;
struct urb *u = NULL;
int reset = 0;
int ring = 0;
if (urb->status != -EINPROGRESS) {
PDEBUG(1, "urb status is not EINPROGRESS!");
return ;
}
spin_lock(&urb->lock);
switch (usb_pipetype(urb->pipe)) {
case PIPE_ISOCHRONOUS:
head = &hc->iso_list;
sl811_result_isochronous(urb);
// if the urb is not unlink and is in a urb "ring", we reset it
if (!urbp->unlink && urb->next)
ring = 1;
break;
case PIPE_INTERRUPT:
head = &hc->intr_list;
sl811_result_interrupt(urb);
// if the urb is not unlink and not "once" query, we reset.
if (!urbp->unlink && urb->interval)
reset = 1;
break;
case PIPE_CONTROL:
head = &hc->ctrl_list;
sl811_result_control(urb);
break;
case PIPE_BULK:
head = &hc->bulk_list;
sl811_result_bulk(urb);
// if the urb is not unlink and is in a urb "ring", we reset it
if (!urbp->unlink && urb->next)
ring = 1;
break;
}
PDEBUG(4, "result urb status = %d", urb->status);
if (ring && urb->next == urb)
reset = 1;
if (!reset) {
switch (usb_pipetype(urb->pipe)) {
case PIPE_ISOCHRONOUS:
usb_release_bandwidth(urb->dev, urb, 1);
break;
case PIPE_INTERRUPT:
usb_release_bandwidth(urb->dev, urb, 0);
break;
}
sl811_free_urb_priv(urb);
}
spin_unlock(&urb->lock);
if (urb->complete)
urb->complete(urb);
if (reset) {
spin_lock(&urb->lock);
sl811_reset_urb(urb);
if (usb_pipeint(urb->pipe))
list_add(&urb->urb_list, &hc->idle_intr_list);
else
list_add(&urb->urb_list, head);
spin_unlock(&urb->lock);
} else {
if (--hc->active_urbs <= 0) {
hc->active_urbs = 0;
sl811_disable_interrupt(hc);
}
if (ring)
u = urb->next;
else
u = sl811_find_same_devep(&hc->wait_list, urb);
if (u) {
if (!list_empty(&u->urb_list))
list_del(&u->urb_list);
if (sl811_submit_urb_with_lock(u))
list_add(&u->urb_list, &hc->wait_list);
}
}
}
#ifdef SL811_TIMEOUT
/*
* Unlink the urb from the urb list
*/
static int sl811_unlink_urb(struct urb *urb)
{
unsigned long flags;
struct sl811_hc *hc;
struct sl811_urb_priv *urbp;
int call = 0;
int schedule = 0;
int count = 0;
if (!urb) {
PDEBUG(1, "urb is null");
return -EINVAL;
}
if (!urb->dev || !urb->dev->bus) {
PDEBUG(1, "dev or bus is null");
return -ENODEV;
}
hc = urb->dev->bus->hcpriv;
urbp = urb->hcpriv;
/* a request to the virtual root hub */
if (usb_pipedevice(urb->pipe) == hc->rh.devnum)
return sl811_rh_unlink_urb(urb);
spin_lock_irqsave(&hc->hc_lock, flags);
spin_lock(&urb->lock);
// in wait list
if (sl811_find_same_urb(&hc->wait_list, urb)) {
PDEBUG(4, "unlink urb in wait list");
list_del_init(&urb->urb_list);
urb->status = -ENOENT;
call = 1;
goto out;
}
// in intr idle list.
if (sl811_find_same_urb(&hc->idle_intr_list, urb)) {
PDEBUG(4, "unlink urb in idle intr list");
list_del_init(&urb->urb_list);
urb->status = -ENOENT;
sl811_free_urb_priv(urb);
usb_release_bandwidth(urb->dev, urb, 0);
if (--hc->active_urbs <= 0) {
hc->active_urbs = 0;
sl811_disable_interrupt(hc);
}
call = 1;
goto out;
}
if (urb->status == -EINPROGRESS) {
PDEBUG(3, "urb is still in progress");
urbp->unlink = 1;
re_unlink:
// Is it in progress?
urbp = urb->hcpriv;
if (urbp && hc->cur_td == urbp->cur_td) {
++count;
if (sl811_read(hc, 0) & SL811_USB_CTRL_ARM) {
PDEBUG(3, "unlink: cur td is still in progress! count = %d", count);
re_schedule:
schedule = 1;
spin_unlock(&urb->lock);
spin_unlock_irqrestore(&hc->hc_lock, flags);
schedule_timeout(HZ/50);
spin_lock_irqsave(&hc->hc_lock, flags);
spin_lock(&urb->lock);
} else {
PDEBUG(3, "unlink: lost of interrupt? do parse! count = %d", count);
spin_unlock(&urb->lock);
sl811_transfer_done(hc, 0);
spin_lock(&urb->lock);
}
goto re_unlink;
}
if (list_empty(&urb->urb_list)) {
PDEBUG(3, "unlink: list empty!");
goto out;
}
if (urb->transfer_flags & USB_TIMEOUT_KILLED) {
PDEBUG(3, "unlink: time out killed");
// it is timeout killed by us
goto result;
} else if (urb->transfer_flags & USB_ASYNC_UNLINK) {
// we do nothing, just let it be processing later
PDEBUG(3, "unlink async, do nothing");
goto out;
} else {
// synchron without callback
PDEBUG(3, "unlink synchron, we wait the urb complete or timeout");
if (schedule == 0) {
PDEBUG(3, "goto re_schedule");
goto re_schedule;
} else {
PDEBUG(3, "already scheduled");
goto result;
}
}
} else if (!list_empty(&urb->urb_list)) {
PDEBUG(1, "urb = %p, status = %d is in a list, why?", urb, urb->status);
//list_del_init(&urb->urb_list);
//call = 1;
}
out:
spin_unlock(&urb->lock);
spin_unlock_irqrestore(&hc->hc_lock, flags);
if (call && urb->complete)
urb->complete(urb);
return 0;
result:
spin_unlock(&urb->lock);
list_del_init(&urb->urb_list);
sl811_result_urb(urb);
spin_unlock_irqrestore(&hc->hc_lock, flags);
return 0;
}
#else
/*
* Unlink the urb from the urb list
*/
static int sl811_unlink_urb(struct urb *urb)
{
unsigned long flags;
struct sl811_hc *hc;
struct sl811_urb_priv *urbp;
int call = 0;
if (!urb) {
PDEBUG(1, "urb is null");
return -EINVAL;
}
if (!urb->dev || !urb->dev->bus) {
PDEBUG(1, "dev or bus is null");
return -ENODEV;
}
hc = urb->dev->bus->hcpriv;
urbp = urb->hcpriv;
/* a request to the virtual root hub */
if (usb_pipedevice(urb->pipe) == hc->rh.devnum)
return sl811_rh_unlink_urb(urb);
spin_lock_irqsave(&hc->hc_lock, flags);
spin_lock(&urb->lock);
// in wait list
if (sl811_find_same_urb(&hc->wait_list, urb)) {
PDEBUG(2, "unlink urb in wait list");
list_del_init(&urb->urb_list);
urb->status = -ENOENT;
call = 1;
goto out;
}
if (urb->status == -EINPROGRESS) {
PDEBUG(2, "urb is still in progress");
urbp->unlink = 1;
// Is it in progress?
urbp = urb->hcpriv;
if (urbp && hc->cur_td == urbp->cur_td) {
// simple, let it out
PDEBUG(2, "unlink: cur td is still in progress!");
hc->cur_td = NULL;
}
goto result;
} else if (!list_empty(&urb->urb_list)) {
PDEBUG(1, "urb = %p, status = %d is in a list, why?", urb, urb->status);
list_del_init(&urb->urb_list);
if (urbp)
goto result;
else
call = 1;
}
out:
spin_unlock(&urb->lock);
spin_unlock_irqrestore(&hc->hc_lock, flags);
if (call && urb->complete)
urb->complete(urb);
return 0;
result:
spin_unlock(&urb->lock);
list_del_init(&urb->urb_list);
sl811_result_urb(urb);
spin_unlock_irqrestore(&hc->hc_lock, flags);
return 0;
}
#endif
static int sl811_get_current_frame_number(struct usb_device *usb_dev)
{
return ((struct sl811_hc *)(usb_dev->bus->hcpriv))->frame_number;
}
static struct usb_operations sl811_device_operations =
{
sl811_alloc_dev_priv,
sl811_free_dev_priv,
sl811_get_current_frame_number,
sl811_submit_urb,
sl811_unlink_urb
};
/*
* This functions transmit a td.
*/
static inline void sl811_trans_cur_td(struct sl811_hc *hc, struct sl811_td *td)
{
sl811_print_td(4, td);
sl811_write_buf(hc, SL811_ADDR_A, &td->addr, 4);
if (td->len && (td->ctrl & SL811_USB_CTRL_DIR_OUT))
sl811_write_buf(hc, td->addr, td->buf, td->len);
sl811_write(hc, SL811_CTRL_A, td->ctrl);
}
/*
* This function checks the status of the transmitted or received packet
* and copy the data from the SL811HS register into a buffer.
*/
static void sl811_parse_cur_td(struct sl811_hc *hc, struct sl811_td *td)
{
struct urb *urb = td->urb;
#ifdef SL811_DEBUG
int dev = usb_pipedevice(td->urb->pipe);
int ep = usb_pipeendpoint(td->urb->pipe);
#endif
sl811_read_buf(hc, SL811_STS_A, &td->status, 2);
if (td->status & SL811_USB_STS_ACK) {
td->done = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -