📄 hc_sl811.c
字号:
len = sizeof(sl811_rh_dev_des);
bufp = sl811_rh_dev_des;
OK(len);
case USB_DT_CONFIG:
len = sizeof(sl811_rh_config_des);
bufp = sl811_rh_config_des;
OK(len);
case USB_DT_STRING:
len = usb_root_hub_string(wValue & 0xff, (int)(long)0, "SL811HS", data, wLength);
if (len > 0) {
bufp = data;
OK(len);
}
default:
status = -EPIPE;
}
break;
case RH_GET_DESCRIPTOR | USB_TYPE_CLASS:
len = sizeof(sl811_rh_hub_des);
bufp = sl811_rh_hub_des;
OK(len);
case RH_GET_CONFIGURATION:
bufp[0] = 0x01;
OK(1);
case RH_SET_CONFIGURATION:
OK(0);
default:
PDEBUG(1, "unsupported root hub command");
status = -EPIPE;
}
len = min(len, buf_len);
if (data != bufp)
memcpy(data, bufp, len);
urb->actual_length = len;
urb->status = status;
PDEBUG(5, "len = %d, status = %d", len, status);
urb->hcpriv = NULL;
urb->dev = NULL;
if (urb->complete)
urb->complete(urb);
return 0;
}
/*
* This function unlinks the URB
*/
static int sl811_rh_unlink_urb(struct urb *urb)
{
struct sl811_hc *hc = urb->dev->bus->hcpriv;
PDEBUG(5, "enter");
if (hc->rh.urb == urb) {
hc->rh.send = 0;
del_timer(&hc->rh.rh_int_timer);
hc->rh.urb = NULL;
urb->hcpriv = NULL;
usb_dec_dev_use(urb->dev);
urb->dev = NULL;
if (urb->transfer_flags & USB_ASYNC_UNLINK) {
urb->status = -ECONNRESET;
if (urb->complete)
urb->complete(urb);
} else
urb->status = -ENOENT;
}
return 0;
}
/*
* This function connect the virtual root hub to the USB stack
*/
static int sl811_connect_rh(struct sl811_hc * hc)
{
struct usb_device *usb_dev;
hc->rh.devnum = 0;
usb_dev = usb_alloc_dev(NULL, hc->bus);
if (!usb_dev)
return -ENOMEM;
hc->bus->root_hub = usb_dev;
usb_connect(usb_dev);
if (usb_new_device(usb_dev)) {
usb_free_dev(usb_dev);
return -ENODEV;
}
PDEBUG(5, "leave success");
return 0;
}
/*
* This function allocates private data space for the usb device
*/
static int sl811_alloc_dev_priv(struct usb_device *usb_dev)
{
return 0;
}
/*
* This function de-allocates private data space for the usb devic
*/
static int sl811_free_dev_priv (struct usb_device *usb_dev)
{
return 0;
}
/*
* This function allocates private data space for the urb
*/
static struct sl811_urb_priv* sl811_alloc_urb_priv(struct urb *urb)
{
struct sl811_urb_priv *urbp;
urbp = kmalloc(sizeof(*urbp), GFP_KERNEL);
if (!urbp)
return NULL;
memset(urbp, 0, sizeof(*urbp));
INIT_LIST_HEAD(&urbp->td_list);
urbp->urb = urb;
urb->hcpriv = urbp;
return urbp;
}
/*
* This function free private data space for the urb
*/
static void sl811_free_urb_priv(struct urb *urb)
{
struct sl811_urb_priv *urbp = urb->hcpriv;
struct sl811_td *td;
struct list_head *head, *tmp;
if (!urbp)
return ;
head = &urbp->td_list;
tmp = head->next;
while (tmp != head) {
td = list_entry(tmp, struct sl811_td, td_list);
tmp = tmp->next;
kfree(td);
}
kfree(urbp);
urb->hcpriv = NULL;
return ;
}
/*
* This function calculate the bus time need by this td.
* Fix me! Can this use usb_calc_bus_time()?
*/
static void sl811_calc_td_time(struct sl811_td *td)
{
#if 1
int time;
int len = td->len;
struct sl811_hc *hc = td->urb->dev->bus->hcpriv;
if (hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED)
time = 8*8*len + 1024;
else {
if (td->ctrl & SL811_USB_CTRL_PREAMBLE)
time = 8*8*len + 2048;
else
time = 8*len + 256;
}
time += 2*10 * len;
td->bustime = time;
#else
unsigned long tmp;
int time;
int low_speed = usb_pipeslow(td->urb->pipe);
int input_dir = usb_pipein(td->urb->pipe);
int bytecount = td->len;
int isoc = usb_pipeisoc(td->urb->pipe);
if (low_speed) { /* no isoc. here */
if (input_dir) {
tmp = (67667L * (31L + 10L * BitTime (bytecount))) / 1000L;
time = (64060L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
} else {
tmp = (66700L * (31L + 10L * BitTime (bytecount))) / 1000L;
time = (64107L + (2 * BW_HUB_LS_SETUP) + BW_HOST_DELAY + tmp);
}
} else if (!isoc){ /* for full-speed: */
tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
time = (9107L + BW_HOST_DELAY + tmp);
} else { /* for isoc: */
tmp = (8354L * (31L + 10L * BitTime (bytecount))) / 1000L;
time = (((input_dir) ? 7268L : 6265L) + BW_HOST_DELAY + tmp);
}
td->bustime = time / 84;
#endif
}
/*
* This function calculate the remainder bus time in current frame.
*/
static inline int sl811_calc_bus_remainder(struct sl811_hc *hc)
{
return (sl811_read(hc, SL811_SOFCNTDIV) * 64);
}
/*
* This function allocates td for the urb
*/
static struct sl811_td* sl811_alloc_td(struct urb *urb)
{
struct sl811_urb_priv *urbp = urb->hcpriv;
struct sl811_td *td;
td = kmalloc(sizeof (*td), GFP_KERNEL);
if (!td)
return NULL;
memset(td, 0, sizeof(*td));
INIT_LIST_HEAD(&td->td_list);
td->urb = urb;
list_add_tail(&td->td_list, &urbp->td_list);
return td;
}
/*
* Fill the td.
*/
static inline void sl811_fill_td(struct sl811_td *td, __u8 ctrl, __u8 addr, __u8 len, __u8 pidep, __u8 dev, __u8 *buf)
{
td->ctrl = ctrl;
td->addr = addr;
td->len = len;
td->pidep = pidep;
td->dev = dev;
td->buf = buf;
td->left = len;
td->errcnt = 3;
}
/*
* Fill the td.
*/
static inline void sl811_reset_td(struct sl811_td *td)
{
td->status = 0;
td->left = td->len;
td->done = 0;
td->errcnt = 3;
td->nakcnt = 0;
td->td_status = 0;
}
static void sl811_print_td(int level, struct sl811_td *td)
{
PDEBUG(level, "td = %p, ctrl = %x, addr = %x, len = %x, pidep = %x\n
dev = %x, status = %x, left = %x, errcnt = %x, done = %x\n
buf = %p, bustime = %d, td_status = %d\n",
td, td->ctrl, td->addr, td->len, td->pidep,
td->dev, td->status, td->left, td->errcnt, td->done,
td->buf, td->bustime, td->td_status);
}
/*
* Isochronous transfers
*/
static int sl811_submit_isochronous(struct urb *urb)
{
__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;
int i;
PDEBUG(4, "enter, urb = %p, urbp = %p", urb, urbp);
/* 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 | SL811_USB_CTRL_ISO;
for (i = 0; i < urb->number_of_packets; i++) {
urb->iso_frame_desc[i].actual_length = 0;
urb->iso_frame_desc[i].status = -EXDEV;
td = sl811_alloc_td(urb);
if (!td)
return -ENOMEM;
sl811_fill_td(td, ctrl, SL811_DATA_START,
urb->iso_frame_desc[i].length,
pidep, dev,
urb->transfer_buffer + urb->iso_frame_desc[i].offset);
sl811_calc_td_time(td);
if (urbp->cur_td == NULL)
urbp->cur_td = urbp->first_td = td;
}
urbp->last_td = td;
PDEBUG(4, "leave success");
/*
// 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(2, "td = %p, i = %d", td, i);
tmp = tmp->next;
}
}
*/
return 0;
}
/*
* Reset isochronous transfers
*/
static void sl811_reset_isochronous(struct urb *urb)
{
struct sl811_urb_priv *urbp = urb->hcpriv;
struct sl811_td *td = NULL;
struct list_head *head, *tmp;
int i;
PDEBUG(4, "enter, urb = %p", urb);
for (i = 0; i < urb->number_of_packets; i++) {
urb->iso_frame_desc[i].actual_length = 0;
urb->iso_frame_desc[i].status = -EXDEV;
}
head = &urbp->td_list;
tmp = head->next;
while (tmp != head) {
td = list_entry(tmp, struct sl811_td, td_list);
tmp = tmp->next;
sl811_reset_td(td);
}
urbp->cur_td = urbp->first_td;
urb->status = -EINPROGRESS;
urb->actual_length = 0;
urb->error_count = 0;
}
/*
* Result the iso urb.
*/
static void sl811_result_isochronous(struct urb *urb)
{
struct list_head *tmp, *head;
struct sl811_urb_priv *urbp = urb->hcpriv;
int status = 0;
struct sl811_td *td;
int i;
PDEBUG(4, "enter, urb = %p", urb);
urb->actual_length = 0;
i = 0;
head = &urbp->td_list;
tmp = head->next;
while (tmp != head) {
td = list_entry(tmp, struct sl811_td, td_list);
tmp = tmp->next;
if (!td->done) {
if (urbp->unlink)
urb->status = -ENOENT;
else {
PDEBUG(1, "we should not get here!");
urb->status = -EXDEV;
}
return ;
}
if (td->td_status) {
status = td->td_status;
urb->error_count++;
PDEBUG(1, "error: td = %p, td status = %d", td, td->td_status);
}
urb->iso_frame_desc[i].actual_length = td->len - td->left;
urb->actual_length += td->len - td->left;
urb->iso_frame_desc[i].status = td->td_status;
++i;
if (td->left)
PDEBUG(3, "short packet, td = %p, len = %d, left = %d", td, td->len, td->left);
}
urb->status = status;
/*
// for debug
PDEBUG(2, "iso urb complete, len = %d, status =%d ", urb->actual_length, urb->status);
*/
PDEBUG(4, "leave success");
}
/*
* Interrupt transfers
*/
static int sl811_submit_interrupt(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_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 (len > maxsze) {
PDEBUG(1, "length is big than max packet size, len = %d, max packet = %d", len, maxsze);
return -EINVAL;
}
if (usb_pipeslow(urb->pipe) && !(hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED))
ctrl |= SL811_USB_CTRL_PREAMBLE;
ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
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));
td = sl811_alloc_td(urb);
if (!td)
return -ENOMEM;
sl811_fill_td(td, ctrl, SL811_DATA_START, len, pidep, dev, data);
sl811_calc_td_time(td);
urbp->cur_td = urbp->first_td = urbp->last_td = td;
urbp->interval = 0;
PDEBUG(4, "leave success");
return 0;
}
/*
* Reset interrupt transfers
*/
static void sl811_reset_interrupt(struct urb *urb)
{
struct sl811_urb_priv *urbp = urb->hcpriv;
struct sl811_td *td = urbp->cur_td;
PDEBUG(4, "enter, interval = %d", urb->interval);
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);
urbp->interval = urb->interval;
urb->status = -EINPROGRESS;
urb->actual_length = 0;
}
/*
* Result the interrupt urb.
*/
static void sl811_result_interrupt(struct urb *urb)
{
struct list_head *tmp;
struct sl811_urb_priv *urbp = urb->hcpriv;
struct sl811_td *td;
int toggle;
PDEBUG(4, "enter, urb = %p", urb);
urb->actual_length = 0;
tmp = &urbp->td_list;
tmp = tmp->next;
td = list_entry(tmp, struct sl811_td, td_list);
// success.
if (td->done && td->td_status == 0) {
urb->actual_length += td->len - td->left;
urb->status = 0;
return ;
}
// tranfer is done but fail, reset the toggle.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -