📄 sl811ò»_uclinux_2.4.c
字号:
int ii, jj, kk;
DBGFUNC ("enter hc_addr_trans: len =0x%x, toggle:0x%x, endpoing:0x%x,"
" addr:0x%x, pid:0x%x,format:0x%x\n", len, toggle, endpoint,
i address, pid, format);
if (len > maxps) {
len = maxps;
}
speed = hp->RHportStatus->portStatus;
if (speed & PORT_LOW_SPEED_DEV_ATTACH_STAT) {
// ii = (8*7*8 + 6*3) * len + 800;
ii = 8 * 8 * len + 1024;
} else {
if (slow) {
// ii = (8*7*8 + 6*3) * len + 800;
ii = 8 * 8 * len + 2048;
} else
// ii = (8*7 + 6*3)*len + 110;
ii = 8 * len + 256;
}
ii += 2 * 10 * len;
jj = SL811Read (hci, SL11H_SOFTMRREG);
kk = (jj & 0xFF) * 64 - ii;
if (kk < 0) {
DBGVERBOSE
("hc_add_trans: no bandwidth for schedule, ii = 0x%x,"
"jj = 0x%x, len =0x%x, active_trans = 0x%x\n", ii, jj, len,
hci->active_trans);
return (-1);
}
if (pid != PID_IN) {
/* Load data into hc */
SL811BufWrite (hci, SL11H_DATA_START, (__u8 *) data, len);
}
/* transmit */
SL11StartXaction (hci, (__u8) address, (__u8) endpoint, (__u8) pid, len,
toggle, slow, urb_state);
return len;
}
/************************************************************************
* Function Name : hc_parse_trans
*
* This function checks the status of the transmitted or received packet
* and copy the data from the SL811HS register into a buffer.
*
* 1) Check the status of the packet
* 2) If successful, and IN packet then copy the data from the SL811HS register
* into a buffer
*
* Input: hci = data structure for the host controller
* actbytes = pointer to actual number of bytes
* data = data buffer
* cc = packet status
* length = the urb transmit length
* pid = packet ID
* urb_state = the current stage of USB transaction
*
* Return: 0
***********************************************************************/
static inline int hc_parse_trans (hci_t * hci, int *actbytes, __u8 * data,
int *cc, int *toggle, int length, int pid,
int urb_state)
{
__u8 addr;
__u8 len;
DBGFUNC ("enter hc_parse_trans\n");
/* get packet status; convert ack rcvd to ack-not-rcvd */
*cc = (int) SL811Read (hci, SL11H_PKTSTATREG);
if (*cc &
(SL11H_STATMASK_ERROR | SL11H_STATMASK_TMOUT | SL11H_STATMASK_OVF |
SL11H_STATMASK_NAK | SL11H_STATMASK_STALL)) {
if (*cc & SL11H_STATMASK_OVF)
DBGERR ("parse trans: error recv ack, cc = 0x%x, TX_BASE_Len = "
"0x%x, TX_count=0x%x\n", *cc,
SL811Read (hci, SL11H_BUFLNTHREG),
SL811Read (hci, SL11H_XFERCNTREG));
} else {
DBGVERBOSE ("parse trans: recv ack, cc = 0x%x, len = 0x%x, \n",
*cc, length);
/* Successful data */
if ((pid == PID_IN) && (urb_state != US_CTRL_SETUP)) {
/* Find the base address */
addr = SL811Read (hci, SL11H_BUFADDRREG);
/* Find the Transmit Length */
len = SL811Read (hci, SL11H_BUFLNTHREG);
/* The actual data length = xmit length reg - xfer count reg */
*actbytes = len - SL811Read (hci, SL11H_XFERCNTREG);
if ((data != NULL) && (*actbytes > 0)) {
SL811BufRead (hci, addr, data, *actbytes);
} else if ((data == NULL) && (*actbytes <= 0)) {
DBGERR ("hc_parse_trans: data = NULL or actbyte = 0x%x\n",
*actbytes);
return 0;
}
} else if (pid == PID_OUT) {
*actbytes = length;
} else {
// printk ("ERR:parse_trans, pid != IN or OUT, pid = 0x%x\n", pid);
}
*toggle = !*toggle;
}
return 0;
}
/************************************************************************
* Function Name : hc_start_int
*
* This function enables SL811HS interrupts
*
* Input: hci = data structure for the host controller
*
* Return: none
***********************************************************************/
static void hc_start_int (hci_t * hci)
{
#ifdef HC_SWITCH_INT
int mask =
SL11H_INTMASK_XFERDONE | SL11H_INTMASK_SOFINTR |
SL11H_INTMASK_INSRMV | SL11H_INTMASK_USBRESET;
SL811Write (hci, IntEna, mask);
#endif
}
/************************************************************************
* Function Name : hc_stop_int
*
* This function disables SL811HS interrupts
*
* Input: hci = data structure for the host controller
*
* Return: none
***********************************************************************/
static void hc_stop_int (hci_t * hci)
{
#ifdef HC_SWITCH_INT
SL811Write (hci, SL11H_INTSTATREG, 0xff);
// SL811Write(hci, SL11H_INTENBLREG, SL11H_INTMASK_INSRMV);
#endif
}
/************************************************************************
* Function Name : handleInsRmvIntr
*
* This function handles the insertion or removal of device on SL811HS.
* It resets the controller and updates the port status
*
* Input: hci = data structure for the host controller
*
* Return: none
***********************************************************************/
void handleInsRmvIntr (hci_t * hci)
{
hcipriv_t *hp = &hci->hp;
USBReset (hci);
/* Changes in connection status */
hp->RHportStatus->portChange |= PORT_CONNECT_CHANGE;
/* Port Enable or Disable */
if (hp->RHportStatus->portStatus & PORT_CONNECT_STAT) {
/* device is connected to the port:
* 1) Enable port
* 2) Resume ??
*/
// hp->RHportStatus->portChange |= PORT_ENABLE_CHANGE;
/* Over Current is not supported by the SL811 HW ?? */
/* How about the Port Power ?? */
} else {
/* Device has disconnect:
* 1) Disable port
*/
hp->RHportStatus->portStatus &= ~(PORT_ENABLE_STAT);
hp->RHportStatus->portChange |= PORT_ENABLE_CHANGE;
}
}
/*****************************************************************
*
* Function Name: SL11StartXaction
*
* This functions load the registers with appropriate value and
* transmit the packet.
*
* Input: hci = data structure for the host controller
* addr = USB address of the device
* epaddr = endpoint number
* pid = packet ID
* len = data length
* toggle = USB toggle bit, either 0 or 1
* slow = speed of the device
* urb_state = the current stage of USB transaction
*
* Return: 0 = error; 1 = successful
*
*****************************************************************/
int SL11StartXaction (hci_t * hci, __u8 addr, __u8 epaddr, int pid, int len,
int toggle, int slow, int urb_state)
{
hcipriv_t *hp = &hci->hp;
__u8 cmd = 0;
__u8 setup_data[4];
__u16 speed;
speed = hp->RHportStatus->portStatus;
if (!(speed & PORT_LOW_SPEED_DEV_ATTACH_STAT) && slow) {
cmd |= SL11H_HCTLMASK_PREAMBLE;
}
switch (pid) {
case PID_SETUP:
cmd &= SL11H_HCTLMASK_PREAMBLE;
cmd |=
(SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP |
SL11H_HCTLMASK_WRITE);
break;
case PID_OUT:
cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE);
cmd |=
(SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP |
SL11H_HCTLMASK_WRITE);
if (toggle) {
cmd |= SL11H_HCTLMASK_SEQ;
}
break;
case PID_IN:
cmd &= (SL11H_HCTLMASK_SEQ | SL11H_HCTLMASK_PREAMBLE);
cmd |= (SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENBLEP);
break;
default:
DBGERR ("ERR: SL11StartXaction: unknow pid = 0x%x\n", pid);
return 0;
}
setup_data[0] = SL11H_DATA_START;
setup_data[1] = len;
setup_data[2] = (((pid & 0x0F) << 4) | (epaddr & 0xF));
setup_data[3] = addr & 0x7F;
SL811BufWrite (hci, SL11H_BUFADDRREG, (__u8 *) & setup_data[0], 4);
SL811Write (hci, SL11H_HOSTCTLREG, cmd);
#if 0
/* The SL811 has a hardware flaw when hub devices sends out
* SE0 between packets. It has been found in a TI chipset and
* cypress hub chipset. It causes the SL811 to hang
* The workaround is to re-issue the preample again.
*/
if ((cmd & SL11H_HCTLMASK_PREAMBLE)) {
SL811Write (hci, SL11H_PIDEPREG_B, 0xc0);
SL811Write (hci, SL11H_HOSTCTLREG_B, 0x1); // send the premable
}
#endif
return 1;
}
/*****************************************************************
*
* Function Name: hc_interrupt
*
* Interrupt service routine.
*
* 1) determine the causes of interrupt
* 2) clears all interrupts
* 3) calls appropriate function to service the interrupt
*
* Input: irq = interrupt line associated with the controller
* hci = data structure for the host controller
* r = holds the snapshot of the processor's context before
* the processor entered interrupt code. (not used here)
*
* Return value : None.
*
*****************************************************************/
static void hc_interrupt (int irq, void *__hci, struct pt_regs *r)
{
char ii;
hci_t *hci = __hci;
int isExcessNak = 0;
int urb_state = 0;
char tmpIrq = 0;
/* Get value from interrupt status register */
ii = SL811Read (hci, SL11H_INTSTATREG);
if (ii & SL11H_INTMASK_INSRMV) {
/* Device insertion or removal detected for the USB port */
SL811Write (hci, SL11H_INTENBLREG, 0);
SL811Write (hci, SL11H_CTLREG1, 0);
mdelay (100); // wait for device stable
handleInsRmvIntr (hci);
return;
}
/* Clear all interrupts */
SL811Write (hci, SL11H_INTSTATREG, 0xff);
if (ii & SL11H_INTMASK_XFERDONE) {
/* USB Done interrupt occurred */
urb_state = sh_done_list (hci, &isExcessNak);
#ifdef WARNING
if (hci->td_array->len > 0)
printk ("WARNING: IRQ, td_array->len = 0x%x, s/b:0\n",
hci->td_array->len);
#endif
if (hci->td_array->len == 0 && !isExcessNak
&& !(ii & SL11H_INTMASK_SOFINTR) && (urb_state == 0)) {
if (urb_state == 0) {
/* All urb_state has not been finished yet!
* continue with the current urb transaction
*/
if (hci->last_packet_nak == 0) {
if (!usb_pipecontrol
(hci->td_array->td[0].urb->pipe))
sh_add_packet (hci, hci->td_array-> td[0].urb);
}
} else {
/* The last transaction has completed:
* schedule the next transaction
*/
sh_schedule_trans (hci, 0);
}
}
SL811Write (hci, SL11H_INTSTATREG, 0xff);
return;
}
if (ii & SL11H_INTMASK_SOFINTR) {
hci->frame_number = (hci->frame_number + 1) % 2048;
if (hci->td_array->len == 0)
sh_schedule_trans (hci, 1);
else {
if (sofWaitCnt++ > 100) {
/* The last transaction has not completed.
* Need to retire the current td, and let
* it transmit again later on.
* (THIS NEEDS TO BE WORK ON MORE, IT SHOULD NEVER
* GET TO THIS POINT)
*/
DBGERR ("SOF interrupt: td_array->len = 0x%x, s/b: 0\n",
hci->td_array->len);
urb_print (hci->td_array->td[hci->td_array->len - 1].urb,
"INTERRUPT", 0);
sh_done_list (hci, &isExcessNak);
SL811Write (hci, SL11H_INTSTATREG, 0xff);
hci->td_array->len = 0;
sofWaitCnt = 0;
}
}
tmpIrq = SL811Read (hci, SL11H_INTSTATREG) & SL811Read (hci, SL11H_INTENBLREG);
if (tmpIrq) {
DBG ("IRQ occurred while service SOF: irq = 0x%x\n",
tmpIrq);
/* If we receive a DONE IRQ after schedule, need to
* handle DONE IRQ again
*/
if (tmpIrq & SL11H_INTMASK_XFERDONE) {
DBGERR ("IRQ occurred while service SOF: irq = 0x%x\n",
tmpIrq);
urb_state = sh_done_list (hci, &isExcessNak);
}
SL811Write (hci, SL11H_INTSTATREG, 0xff);
}
} else {
DBG ("SL811 ISR: unknown, int = 0x%x \n", ii);
}
SL811Write (hci, SL11H_INTSTATREG, 0xff);
return;
}
/*****************************************************************
*
* Function Name: hc_reset
*
* This function does register test and resets the SL811HS
* controller.
*
* Input: hci = data structure for the host controller
*
* Return value : 0
*
*****************************************************************/
static int hc_reset (hci_t * hci)
{
int attachFlag = 0;
DBGFUNC ("Enter hc_reset\n");
regTest (hci);
attachFlag = USBReset (hci);
if (attachFlag) {
setPortChange (hci, PORT_CONNECT_CHANGE);
}
return (0);
}
/*****************************************************************
*
* Function Name: hc_alloc_trans_buffer
*
* This function allocates all transfer buffer
*
* Input: hci = data structure for the host controller
*
* Return value : 0
*
*****************************************************************/
static int hc_alloc_trans_buffer (hci_t * hci)
{
hcipriv_t *hp = &hci->hp;
int maxlen;
hp->itl0_len = 0;
hp->itl1_len = 0;
hp->atl_len = 0;
hp->itl_buffer_len = 1024;
hp->atl_buffer_len = 4096 - 2 * hp->itl_buffer_len; /* 2048 */
maxlen = (hp->itl_buffer_len > hp->atl_buffer_len) ? hp->itl_buffer_len : hp->atl_buffer_len;
hp->tl = kmalloc (maxlen, GFP_KERNEL);
if (!hp->tl)
return -ENOMEM;
memset (hp->tl, 0, maxlen);
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -