Exemplo n.º 1
0
/************************************************************************
 * 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;
}
Exemplo n.º 2
0
/************************************************************************
 * Function Name : hc_add_trans
 *  
 * This function sets up the SL811HS register and transmit the USB packets.
 * 
 * 1) Determine if enough time within the current frame to send the packet
 * 2) Load the data into the SL811HS register
 * 3) Set the appropriate command to the register and trigger the transmit
 *
 * Input:  hci = data structure for the host controller
 *         len = data length
 *         data = transmitting data
 *         toggle = USB toggle bit, either 0 or 1
 *         maxps = maximum packet size for this endpoint
 *         slow = speed of the device
 *         endpoint = endpoint number
 *         address = USB address of the device
 *         pid = packet ID
 *         format = 
 *         urb_state = the current stage of USB transaction
 *       
 * Return: 0 = no time left to schedule the transfer
 *         1 = success 
 *                
 ***********************************************************************/
static inline int hc_add_trans (hci_t * hci, int len, void *data, int toggle,
				int maxps, int slow, int endpoint, int address,
				int pid, int format, int urb_state)
{
	hcipriv_t *hp = &hci->hp;
	__u16 speed;
	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;
}
Exemplo n.º 3
0
/***************************************************************************
 * Function Name : rh_submit_urb
 * 
 * This function handles all USB request to the the virtual root hub
 * 
 * Input: urb = USB request block 
 *
 * Return: 0  
 **************************************************************************/
static int rh_submit_urb (struct urb * urb)
{
	struct usb_device *usb_dev = urb->dev;
	hci_t *hci = usb_dev->bus->hcpriv;
	unsigned int pipe = urb->pipe;
	struct usb_ctrlrequest *cmd = (struct usb_ctrlrequest *) urb->setup_packet;
	void *data = urb->transfer_buffer;
	int leni = urb->transfer_buffer_length;
	int len = 0;
	int status = TD_CC_NOERROR;
	__u32 datab[4];
	__u8 *data_buf = (__u8 *) datab;

	__u16 bmRType_bReq;
	__u16 wValue;
	__u16 wIndex;
	__u16 wLength;

	DBGFUNC ("enter rh_submit_urb\n");
	if (usb_pipeint (pipe)) {
		hci->rh.urb = urb;
		hci->rh.send = 1;
		hci->rh.interval = urb->interval;
		rh_init_int_timer (urb);
		urb->status = cc_to_error (TD_CC_NOERROR);

		return 0;
	}

	bmRType_bReq = cmd->bRequestType | (cmd->bRequest << 8);
	wValue = le16_to_cpu (cmd->wValue);
	wIndex = le16_to_cpu (cmd->wIndex);
	wLength = le16_to_cpu (cmd->wLength);

	DBG ("rh_submit_urb, req = %d(%x) len=%d",
	     bmRType_bReq, bmRType_bReq, wLength);

	switch (bmRType_bReq) {
		/* Request Destination:
		   without flags: Device, 
		   RH_INTERFACE: interface, 
		   RH_ENDPOINT: endpoint,
		   RH_CLASS means HUB here, 
		   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here 
		 */

	case RH_GET_STATUS:
		*(__u16 *) data_buf = cpu_to_le16 (1);
		OK (2);

	case RH_GET_STATUS | RH_INTERFACE:
		*(__u16 *) data_buf = cpu_to_le16 (0);
		OK (2);

	case RH_GET_STATUS | RH_ENDPOINT:
		*(__u16 *) data_buf = cpu_to_le16 (0);
		OK (2);

	case RH_GET_STATUS | RH_CLASS:
		*(__u32 *) data_buf = cpu_to_le32 (0);
		OK (4);

	case RH_GET_STATUS | RH_OTHER | RH_CLASS:
		*(__u32 *) data_buf =
		    cpu_to_le32 (getPortStatusAndChange (hci));
		OK (4);

	case RH_CLEAR_FEATURE | RH_ENDPOINT:
		switch (wValue) {
		case (RH_ENDPOINT_STALL):
			OK (0);
		}
		break;

	case RH_CLEAR_FEATURE | RH_CLASS:
		switch (wValue) {
		case RH_C_HUB_LOCAL_POWER:
			OK (0);

		case (RH_C_HUB_OVER_CURRENT):
			/* Over Current Not Implemented */
			OK (0);
		}
		break;

	case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
		switch (wValue) {
		case (RH_PORT_ENABLE):
			clrPortStatus (hci, PORT_ENABLE_STAT);
			OK (0);

		case (RH_PORT_SUSPEND):
			clrPortStatus (hci, PORT_SUSPEND_STAT);
			OK (0);

		case (RH_PORT_POWER):
			clrPortStatus (hci, PORT_POWER_STAT);
			OK (0);

		case (RH_C_PORT_CONNECTION):
			clrPortChange (hci, PORT_CONNECT_STAT);
			OK (0);

		case (RH_C_PORT_ENABLE):
			clrPortChange (hci, PORT_ENABLE_STAT);
			OK (0);

		case (RH_C_PORT_SUSPEND):
			clrPortChange (hci, PORT_SUSPEND_STAT);
			OK (0);

		case (RH_C_PORT_OVER_CURRENT):
			clrPortChange (hci, PORT_OVER_CURRENT_STAT);
			OK (0);

		case (RH_C_PORT_RESET):
			clrPortChange (hci, PORT_RESET_STAT);
			OK (0);
		}
		break;

	case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
		switch (wValue) {
		case (RH_PORT_SUSPEND):
			setPortStatus (hci, PORT_SUSPEND_STAT);
			OK (0);

		case (RH_PORT_RESET):
			setPortStatus (hci, PORT_RESET_STAT);
			// USBReset(hci);
			clrPortChange (hci,
				       PORT_CONNECT_CHANGE | PORT_ENABLE_CHANGE
				       | PORT_SUSPEND_CHANGE |
				       PORT_OVER_CURRENT_CHANGE);
			setPortChange (hci, PORT_RESET_CHANGE);
			clrPortStatus (hci, PORT_RESET_STAT);
			setPortStatus (hci, PORT_ENABLE_STAT);

			OK (0);

		case (RH_PORT_POWER):
			setPortStatus (hci, PORT_POWER_STAT);
			OK (0);

		case (RH_PORT_ENABLE):
			setPortStatus (hci, PORT_ENABLE_STAT);
			OK (0);
		}
		break;

	case RH_SET_ADDRESS:
		hci->rh.devnum = wValue;
		OK (0);

	case RH_GET_DESCRIPTOR:
		DBGVERBOSE ("rh_submit_urb: RH_GET_DESCRIPTOR, wValue = 0x%x\n", wValue);
		switch ((wValue & 0xff00) >> 8) {
		case (0x01):	/* device descriptor */
			len = min (leni, min ((__u16)sizeof (root_hub_dev_des), wLength));
			data_buf = root_hub_dev_des;
			OK (len);

		case (0x02):	/* configuration descriptor */
			len = min (leni, min ((__u16)sizeof (root_hub_config_des), wLength));
			data_buf = root_hub_config_des;
			OK (len);

		case (0x03):	/* string descriptors */
			len = root_hub_string (wValue & 0xff, (int) (long) 0,
						   "SL811HS", data, wLength);
			if (len > 0) {
				data_buf = data;
				OK (min (leni, len));
			}

		default:
			status = SL11H_STATMASK_STALL;
		}
		break;

	case RH_GET_DESCRIPTOR | RH_CLASS:
		data_buf[0] = 9;	// min length;
		data_buf[1] = 0x29;
		data_buf[2] = 1;	// # of downstream port
		data_buf[3] = 0;
		datab[1] = 0;
		data_buf[5] = 50;	// 100 ms for port reset
		data_buf[7] = 0xfc;	// which port is attachable
		if (data_buf[2] < 7) {
			data_buf[8] = 0xff;
		} else {
		}

		len = min (leni, min ((__u16)data_buf[0], wLength));
		OK (len);

	case RH_GET_CONFIGURATION:
		*(__u8 *) data_buf = 0x01;
		OK (1);

	case RH_SET_CONFIGURATION:
		OK (0);

	default:
		DBGERR ("unsupported root hub command");
		status = SL11H_STATMASK_STALL;
	}

	len = min (len, leni);
	if (data != data_buf)
		memcpy (data, data_buf, len);
	urb->actual_length = len;
	urb->status = cc_to_error (status);

	urb->hcpriv = NULL;
	urb->dev = NULL;
	if (urb->complete) {
		urb->complete (urb, NULL);
	}

	return 0;
}