📄 hc_sl811.c
字号:
else if (td->done && td->td_status) {
urb->status = td->td_status;
reset_toggle:
toggle = (td->ctrl & SL811_USB_CTRL_TOGGLE_1) ? 1 : 0;
usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), toggle);
PDEBUG(3, "error: td = %p, td status = %d", td, td->td_status);
return ;
}
// unlink, and not do transfer yet
else if (td->done == 0 && urbp->unlink && td->td_status == 0) {
urb->status = -ENOENT;
PDEBUG(3, "unlink and not transfer!");
return ;
}
// unlink, and transfer not complete yet.
else if (td->done == 0 && urbp->unlink && td->td_status) {
urb->status = -ENOENT;
PDEBUG(3, "unlink and not complete!");
goto reset_toggle;
}
// must be bug!!!
else {// (td->done == 0 && urbp->unlink == 0)
PDEBUG(1, "we should not get here!");
urb->status = -EPIPE;
return ;
}
}
/*
* Control transfers
*/
static int sl811_submit_control(struct urb *urb)
{
int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
int len = urb->transfer_buffer_length;
__u8 *data = urb->transfer_buffer;
__u8 dev = usb_pipedevice(urb->pipe);
__u8 pidep = 0;
__u8 ctrl = 0;
struct sl811_hc *hc = urb->dev->bus->hcpriv;
struct sl811_urb_priv *urbp = urb->hcpriv;
struct sl811_td *td = NULL;
PDEBUG(4, "enter, urb = %p", urb);
if (usb_pipeslow(urb->pipe) && !(hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED))
ctrl |= SL811_USB_CTRL_PREAMBLE;
/* Build SETUP TD */
pidep = PIDEP(USB_PID_SETUP, usb_pipeendpoint(urb->pipe));
ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE | SL811_USB_CTRL_DIR_OUT;
td = sl811_alloc_td(urb);
if (!td)
return -ENOMEM;
sl811_fill_td(td, ctrl, SL811_DATA_START, 8, pidep, dev, urb->setup_packet);
sl811_calc_td_time(td);
urbp->cur_td = urbp->first_td = td;
/*
* If direction is "send", change the frame from SETUP (0x2D)
* to OUT (0xE1). Else change it from SETUP to IN (0x69).
*/
pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
if (usb_pipeout(urb->pipe))
ctrl |= SL811_USB_CTRL_DIR_OUT;
else
ctrl &= ~SL811_USB_CTRL_DIR_OUT;
/* Build the DATA TD's */
while (len > 0) {
int pktsze = len;
if (pktsze > maxsze)
pktsze = maxsze;
/* Alternate Data0/1 (start with Data1) */
ctrl ^= SL811_USB_CTRL_TOGGLE_1;
td = sl811_alloc_td(urb);
if (!td)
return -ENOMEM;
sl811_fill_td(td, ctrl, SL811_DATA_START, pktsze, pidep, dev, data);
sl811_calc_td_time(td);
data += pktsze;
len -= pktsze;
}
/* Build the final TD for control status */
td = sl811_alloc_td(urb);
if (!td)
return -ENOMEM;
/* It's IN if the pipe is an output pipe or we're not expecting data back */
if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length) {
pidep = PIDEP(USB_PID_IN, usb_pipeendpoint(urb->pipe));
ctrl &= ~SL811_USB_CTRL_DIR_OUT;
} else {
pidep = PIDEP(USB_PID_OUT, usb_pipeendpoint(urb->pipe));
ctrl |= SL811_USB_CTRL_DIR_OUT;
}
/* End in Data1 */
ctrl |= SL811_USB_CTRL_TOGGLE_1;
sl811_fill_td(td, ctrl, SL811_DATA_START, 0, pidep, dev, 0);
sl811_calc_td_time(td);
urbp->last_td = td;
/*
// for debug
{
struct list_head *head, *tmp;
struct sl811_td *td;
int i = 0;
head = &urbp->td_list;
tmp = head->next;
if (list_empty(&urbp->td_list)) {
PDEBUG(1, "bug!!! td list is empty!");
return -ENODEV;
}
while (tmp != head) {
++i;
td = list_entry(tmp, struct sl811_td, td_list);
PDEBUG(3, "td = %p, i = %d", td, i);
tmp = tmp->next;
}
}
*/
PDEBUG(4, "leave success");
return 0;
}
/*
* Result the control urb.
*/
static void sl811_result_control(struct urb *urb)
{
struct list_head *tmp, *head;
struct sl811_urb_priv *urbp = urb->hcpriv;
struct sl811_td *td;
PDEBUG(4, "enter, urb = %p", urb);
if (list_empty(&urbp->td_list)) {
PDEBUG(1, "td list is empty");
return ;
}
head = &urbp->td_list;
tmp = head->next;
td = list_entry(tmp, struct sl811_td, td_list);
/* The first TD is the SETUP phase, check the status, but skip the count */
if (!td->done) {
PDEBUG(3, "setup phase error, td = %p, done = %d", td, td->done);
goto err_done;
}
if (td->td_status) {
PDEBUG(3, "setup phase error, td = %p, td status = %d", td, td->td_status);
goto err_status;
}
urb->actual_length = 0;
/* The rest of the TD's (but the last) are data */
tmp = tmp->next;
while (tmp != head && tmp->next != head) {
td = list_entry(tmp, struct sl811_td, td_list);
tmp = tmp->next;
if (!td->done) {
PDEBUG(3, "data phase error, td = %p, done = %d", td, td->done);
goto err_done;
}
if (td->td_status) {
PDEBUG(3, "data phase error, td = %p, td status = %d", td, td->td_status);
goto err_status;
}
urb->actual_length += td->len - td->left;
// short packet.
if (td->left) {
PDEBUG(3, "data phase short packet, td = %p, count = %d", td, td->len - td->left);
break;
}
}
/* The last td is status phase */
td = urbp->last_td;
if (!td->done) {
PDEBUG(3, "status phase error, td = %p, done = %d", td, td->done);
goto err_done;
}
if (td->td_status) {
PDEBUG(3, "status phase error, td = %p, td status = %d", td, td->td_status);
goto err_status;
}
PDEBUG(4, "leave success");
urb->status = 0;
return ;
err_done:
if (urbp->unlink)
urb->status = -ENOENT;
else {
PDEBUG(1, "we should not get here! td = %p", td);
urb->status = -EPIPE;
}
return ;
err_status:
urb->status = td->td_status;
return ;
}
/*
* Bulk transfers
*/
static int sl811_submit_bulk(struct urb *urb)
{
int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
int len = urb->transfer_buffer_length;
__u8 *data = urb->transfer_buffer;
__u8 dev = usb_pipedevice(urb->pipe);
__u8 pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
__u8 ctrl = 0;
struct sl811_urb_priv *urbp = urb->hcpriv;
struct sl811_td *td = NULL;
PDEBUG(4, "enter, urb = %p", urb);
if (len < 0) {
PDEBUG(1, "error, urb = %p, len = %d", urb, len);
return -EINVAL;
}
/* Can't have low speed bulk transfers */
if (usb_pipeslow(urb->pipe)) {
PDEBUG(1, "error, urb = %p, low speed device", urb);
return -EINVAL;
}
if (usb_pipeout(urb->pipe))
ctrl |= SL811_USB_CTRL_DIR_OUT;
ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
/* Build the DATA TD's */
do { /* Allow zero length packets */
int pktsze = len;
if (pktsze > maxsze)
pktsze = maxsze;
td = sl811_alloc_td(urb);
if (!td)
return -ENOMEM;
/* Alternate Data0/1 (start with Data1) */
ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
ctrl |= SL811_USB_CTRL_TOGGLE_1;
usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
sl811_fill_td(td, ctrl, SL811_DATA_START, pktsze, pidep, dev, data);
sl811_calc_td_time(td);
if (urbp->cur_td == NULL)
urbp->cur_td = urbp->first_td = td;
data += pktsze;
len -= maxsze;
} while (len > 0);
/*
* USB_ZERO_PACKET means adding a 0-length packet, if
* direction is OUT and the transfer_length was an
* exact multiple of maxsze, hence
* (len = transfer_length - N * maxsze) == 0
* however, if transfer_length == 0, the zero packet
* was already prepared above.
*/
if (usb_pipeout(urb->pipe) && (urb->transfer_flags & USB_ZERO_PACKET) &&
!len && urb->transfer_buffer_length) {
td = sl811_alloc_td(urb);
if (!td)
return -ENOMEM;
/* Alternate Data0/1 (start with Data1) */
ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
ctrl |= SL811_USB_CTRL_TOGGLE_1;
usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
sl811_fill_td(td, ctrl, SL811_DATA_START, 0, pidep, dev, 0);
sl811_calc_td_time(td);
}
urbp->last_td = td;
PDEBUG(4, "leave success");
return 0;
}
/*
* Reset bulk transfers
*/
static int sl811_reset_bulk(struct urb *urb)
{
struct sl811_urb_priv *urbp = urb->hcpriv;
struct sl811_td *td;
struct list_head *head, *tmp;
PDEBUG(4, "enter, urb = %p", urb);
head = &urbp->td_list;
tmp = head->next;
while (tmp != head) {
td = list_entry(tmp, struct sl811_td, td_list);
/* Alternate Data0/1 (start with Data1) */
td->ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
td->ctrl |= SL811_USB_CTRL_TOGGLE_1;
usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
sl811_reset_td(td);
}
urb->status = -EINPROGRESS;
urb->actual_length = 0;
urbp->cur_td = urbp->first_td;
PDEBUG(4, "leave success");
return 0;
}
/*
* Result the bulk urb.
*/
static void sl811_result_bulk(struct urb *urb)
{
struct list_head *tmp, *head;
struct sl811_urb_priv *urbp = urb->hcpriv;
struct sl811_td *td = NULL;
int toggle;
PDEBUG(4, "enter, urb = %p", urb);
urb->actual_length = 0;
head = &urbp->td_list;
tmp = head->next;
while (tmp != head) {
td = list_entry(tmp, struct sl811_td, td_list);
tmp = tmp->next;
// success.
if (td->done && td->td_status == 0) {
urb->actual_length += td->len - td->left;
// short packet
if (td->left) {
urb->status = 0;
PDEBUG(3, "short packet, td = %p, count = %d", td, td->len - td->left);
goto reset_toggle;
}
}
// tranfer is done but fail, reset the toggle.
else if (td->done && td->td_status) {
urb->status = td->td_status;
PDEBUG(3, "error: td = %p, td status = %d", td, td->td_status);
goto reset_toggle;
}
// unlink, and not do transfer yet
else if (td->done == 0 && urbp->unlink && td->td_status == 0) {
urb->status = -ENOENT;
PDEBUG(3, "unlink and not transfer!");
return ;
}
// unlink, and transfer not complete yet.
else if (td->done == 0 && urbp->unlink && td->td_status) {
PDEBUG(3, "unlink and not complete!");
urb->status = -ENOENT;
goto reset_toggle;
}
// must be bug!!!
else {// (td->done == 0 && urbp->unlink == 0)
urb->status = -EPIPE;
PDEBUG(1, "we should not get here!");
return ;
}
}
PDEBUG(4, "leave success");
urb->status = 0;
return ;
reset_toggle:
toggle = (td->ctrl & SL811_USB_CTRL_TOGGLE_1) ? 1 : 0;
usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), toggle);
}
/*
* Find the first urb have the same dev and endpoint.
*/
static inline int sl811_find_same_urb(struct list_head *head, struct urb *urb)
{
struct list_head *tmp;
struct urb *u;
if (!head || !urb)
return 0;
tmp = head->next;
while (tmp != head) {
u = list_entry(tmp, struct urb, urb_list);
if (u == urb)
return 1;
tmp = tmp->next;
}
return 0;
}
/*
* Find the first urb have the same dev and endpoint.
*/
static inline struct urb* sl811_find_same_devep(struct list_head *head, struct urb *urb)
{
struct list_head *tmp;
struct urb *u;
if (!head || !urb)
return NULL;
tmp = head->next;
while (tmp != head) {
u = list_entry(tmp, struct urb, urb_list);
if ((usb_pipe_endpdev(u->pipe)) == (usb_pipe_endpdev(urb->pipe)))
return u;
tmp = tmp->next;
}
return NULL;
}
/*
* This function is called by the USB core API when an URB is available to
* process.
*/
static int sl811_submit_urb(struct urb *urb)
{
struct sl811_hc *hc = urb->dev->bus->hcpriv;
unsigned int pipe = urb->pipe;
struct list_head *head = NULL;
unsigned long flags;
int bustime;
int ret = 0;
int temp = 0;
if (!urb) {
PDEBUG(1, "urb is null");
return -EINVAL;
}
if (urb->hcpriv) {
PDEBUG(1, "urbp is not null, urb = %p, urbp = %p", urb, urb->hcpriv);
return -EINVAL;
}
if (!urb->dev || !urb->dev->bus || !hc) {
PDEBUG(1, "dev or bus or hc is null");
return -ENODEV;
}
if (usb_endpoint_halted(urb->dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
PDEBUG(2, "sl811_submit_urb: endpoint_halted");
return -EPIPE;
}
if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) > SL811_DATA_LIMIT) {
printk(KERN_ERR "Packet size is big for SL811, should < %d!\n", SL811_DATA_LIMIT);
return -EINVAL;
printk(KERN_ERR "out packet isze = %d in packet size = %d\n", urb->dev->epmaxpacketout[usb_pipeendpoint(pipe)], urb->dev->epmaxpacketin[usb_pipeendpoint(pipe)]);
return -EINVAL;
}
/* a request to the virtual root hub */
temp = pipe;
//printk("righto:usb_pipedevice:%d, pipe:%d, rh.devnum:%d\n",usb_pipedevice(temp), temp, hc->rh.devnum );
if ( usb_pipedevice(pipe) == hc->rh.devnum)
{
//printk("righto: run to usb_pipedevice(pipe), then return sl811_rh_submit_urb()\n");
return sl811_rh_submit_urb(urb);
}
spin_lock_irqsave(&hc->hc_lock, flags);
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_find_same_devep(head, urb)) {
list_add(&urb->urb_list, &hc->wait_list);
PDEBUG(4, "add to wait list");
//printk("righto: run to sl811_find_same_devep()\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -