patch-2.3.14 linux/drivers/usb/ohci-root-hub.c
Next file: linux/drivers/usb/ohci.c
Previous file: linux/drivers/usb/ohci-hcd.h
Back to the patch index
Back to the overall index
- Lines: 717
- Date:
Wed Aug 18 16:22:23 1999
- Orig file:
v2.3.13/linux/drivers/usb/ohci-root-hub.c
- Orig date:
Mon May 10 10:18:34 1999
diff -u --recursive --new-file v2.3.13/linux/drivers/usb/ohci-root-hub.c linux/drivers/usb/ohci-root-hub.c
@@ -3,11 +3,27 @@
*
* (C) Copyright 1999 Roman Weissgaerber (weissg@vienna.at)
*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
* The Root Hub is build into the HC (UHCI or OHCI) hardware.
* This piece of code lets it look like it resides on the usb
* like the other hubs.
* (for anyone who wants to do a control operation on the root hub)
- *
+ *
+ * v4.0 1999/08/18
* v2.1 1999/05/09
* v2.0 1999/05/04
* v1.0 1999/04/27
@@ -16,7 +32,6 @@
*/
-
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ioport.h>
@@ -31,7 +46,6 @@
#include "ohci-root-hub.h"
-
static __u8 root_hub_dev_des[] =
{
0x12, /* __u8 bLength; */
@@ -85,7 +99,7 @@
0x05, /* __u8 ep_bDescriptorType; Endpoint */
0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
0x03, /* __u8 ep_bmAttributes; Interrupt */
- 0x40, /* __u16 ep_wMaxPacketSize; 64 Bytes */
+ 0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */
0x00,
0xff /* __u8 ep_bInterval; 255 ms */
};
@@ -108,385 +122,128 @@
};
*/
+#define OK(x) len = (x); req_reply = 0; break
+#define WR_RH_STAT(x) writel((x), &ohci->regs->roothub.status)
+#define WR_RH_PORTSTAT(x) writel((x), &ohci->regs->roothub.portstatus[wIndex-1])
+#define RD_RH_STAT readl(&ohci->regs->roothub.status)
+#define RD_RH_PORTSTAT readl(&ohci->regs->roothub.portstatus[wIndex-1])
-int root_hub_control_msg(struct ohci *ohci, int cmd_len, void *rh_cmd, void *rh_data, int leni, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler)
+int root_hub_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest * cmd, void *data, int leni)
{
-
- __u32 stat;
- __u32 rep_handler;
- int req_reply=0;
- union ep_addr_ ep_addr;
- union ep_addr_ ep_addr_ret;
- __u8 * cmd = rh_cmd;
- __u8 * data = rh_data;
- int i;
+ struct ohci * ohci = usb_dev->bus->hcpriv;
+ __u8 data_buf[16];
+ int req_reply=4;
+
int len =leni;
- __u8 bmRequestType = cmd[0];
- __u8 bRequest = cmd[1];
- __u16 wValue = cmd[3] << 8 | cmd [2];
- __u16 wIndex = cmd[5] << 8 | cmd [4];
- __u16 wLength = cmd[7] << 8 | cmd [6];
-printk("USB root hub: adr: %8x cmd(%8x): ", ohci->root_hub_funct_addr, 8);
-for(i=0;i<8;i++)
- printk("%2x", ((char *)rh_cmd)[i]);
+ __u16 bmRType_bReq = cmd->requesttype | (cmd->request << 8);
+ __u16 wValue = cpu_to_le16(cmd->value);
+ __u16 wIndex = cpu_to_le16(cmd->index);
+ __u16 wLength = cpu_to_le16(cmd->length);
+
+ OHCI_DEBUG(printk("USB root hub: adr: %2x cmd(%1x): ", ohci->rh.devnum, 8);)
+ OHCI_DEBUG({ int i; for(i=0;i<8;i++) printk(" %02x", ((unsigned char *)cmd)[i]);})
+ OHCI_DEBUG(printk(" ; \n");)
-printk(" ; \n");
-
- ep_addr_ret.iep = 0;
- ep_addr_ret.bep.fa = ohci->root_hub_funct_addr;
- ep_addr_ret.bep.ep = (bmRequestType & 0x80) | 0x40;
-
- switch (bmRequestType | bRequest << 8) {
- /* 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
- */
+ 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:
- len = 2;
- data[0] = 0x01;
- data[1] = 0x00;
- req_reply = RH_ACK;
- break;
- case RH_GET_STATUS | RH_INTERFACE:
- len = 2;
- data[0] = 0x00;
- data[1] = 0x00;
- req_reply = RH_ACK;
- break;
- case RH_GET_STATUS | RH_ENDPOINT:
- len = 2;
- data[0] = 0x00;
- data[1] = 0x00;
- req_reply = RH_ACK;
- break;
- case RH_GET_STATUS | RH_CLASS: /* HUB_STATUS */
- stat = readl(&ohci->regs->roothub.status) & 0x7fff7fff; /* bit 31 u. 15 has other meaning */
- data[0] = stat & 0xff;
- data[1] = (stat >> 8) & 0xff;
- data[2] = (stat >> 16) & 0xff;
- data[3] = (stat >> 24) & 0xff;
- len = 4;
- req_reply = RH_ACK;
- break;
- case RH_GET_STATUS | RH_OTHER | RH_CLASS: /* PORT_STATUS */
- stat = readl(&ohci->regs->roothub.portstatus[wIndex-1]);
- data[0] = stat & 0xff;
- data[1] = (stat >> 8) & 0xff;
- data[2] = (stat >> 16) & 0xff;
- data[3] = (stat >> 24) & 0xff;
- len = 4;
- req_reply = RH_ACK;
- printk("rh: stat %4x wIndex %4x;\n", stat , wIndex);
- break;
-
- case RH_CLEAR_FEATURE:
- switch (wValue) {
- case (RH_DEVICE_REMOTE_WAKEUP):
- default:
- }
- break;
-
- case RH_CLEAR_FEATURE | RH_ENDPOINT:
- switch (wValue) {
- case (RH_ENDPOINT_STALL):
- len=0;
- req_reply = RH_ACK;
- break;
- default:
- }
- break;
-
- case RH_CLEAR_FEATURE | RH_CLASS:
- switch (wValue) {
- /* case (RH_C_HUB_LOCAL_POWER): OHCI says: no switching of this one */
- case (RH_C_HUB_OVER_CURRENT):
- writel(RH_PS_OCIC, &ohci->regs->roothub.status);
- len=0;
- req_reply = RH_ACK;
- break;
- default:
- }
- break;
- case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
- switch (wValue) {
- case (RH_PORT_ENABLE):
- writel(RH_PS_CCS, &ohci->regs->roothub.portstatus[wIndex-1]);
- len=0;
- req_reply = RH_ACK;
- break;
- case (RH_PORT_SUSPEND):
- writel(RH_PS_POCI, &ohci->regs->roothub.portstatus[wIndex-1]);
- len=0;
- req_reply = RH_ACK;
- break;
- case (RH_PORT_POWER):
- writel(RH_PS_LSDA, &ohci->regs->roothub.portstatus[wIndex-1]);
- len=0;
- req_reply = RH_ACK;
- break;
- case (RH_C_PORT_CONNECTION):
- writel(RH_PS_CSC, &ohci->regs->roothub.portstatus[wIndex-1]);
- len=0;
- req_reply = RH_ACK;
- break;
- case (RH_C_PORT_ENABLE):
- writel(RH_PS_PESC, &ohci->regs->roothub.portstatus[wIndex-1]);
- len=0;
- req_reply = RH_ACK;
- break;
- case (RH_C_PORT_SUSPEND):
- writel(RH_PS_PSSC, &ohci->regs->roothub.portstatus[wIndex-1]);
- len=0;
- req_reply = RH_ACK;
- break;
- case (RH_C_PORT_OVER_CURRENT):
- writel(RH_PS_OCIC, &ohci->regs->roothub.portstatus[wIndex-1]);
- len=0;
- req_reply = RH_ACK;
- break;
- case (RH_C_PORT_RESET):
- writel(RH_PS_PRSC, &ohci->regs->roothub.portstatus[wIndex-1]);
- len=0;
- req_reply = RH_ACK;
- break;
- /*
- case (RH_PORT_CONNECTION):
- case (RH_PORT_OVER_CURRENT):
- case (RH_PORT_RESET):
- case (RH_PORT_LOW_SPEED):
- */
- default:
- }
- break;
- case RH_SET_FEATURE:
- switch (wValue) {
- case (RH_DEVICE_REMOTE_WAKEUP):
- default:
- }
- break;
-
- case RH_SET_FEATURE | RH_ENDPOINT:
- switch (wValue) {
- case (RH_ENDPOINT_STALL):
- default:
- }
- break;
-
- case RH_SET_FEATURE | RH_CLASS:
- switch (wValue) {
- /* case (RH_C_HUB_LOCAL_POWER): Root Hub has no local Power
- case (RH_C_HUB_OVER_CURRENT): */
- default:
- }
- break;
- case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
- switch (wValue) {
- case (RH_PORT_SUSPEND):
- writel(RH_PS_PSS, &ohci->regs->roothub.portstatus[wIndex-1]);
- len=0;
- req_reply = RH_ACK;
- break;
- case (RH_PORT_RESET):
- if((readl(&ohci->regs->roothub.portstatus[wIndex-1]) &1) != 0) /* BUG IN HUP CODE *********/
- writel(RH_PS_PRS, &ohci->regs->roothub.portstatus[wIndex-1]);
- len=0;
- req_reply = RH_ACK;
- break;
- case (RH_PORT_POWER):
- writel(RH_PS_PPS, &ohci->regs->roothub.portstatus[wIndex-1]);
- len=0;
- req_reply = RH_ACK;
- break;
- case (RH_PORT_ENABLE):
- writel(RH_PS_PES, &ohci->regs->roothub.portstatus[wIndex-1]);
- len=0;
- req_reply = RH_ACK;
- break;
- /*
- case (RH_PORT_CONNECTION):
- case (RH_PORT_OVER_CURRENT):
- case (RH_PORT_LOW_SPEED):
- case (RH_C_PORT_CONNECTION):
- case (RH_C_PORT_ENABLE):
- case (RH_C_PORT_SUSPEND):
- case (RH_C_PORT_OVER_CURRENT):
- case (RH_C_PORT_RESET):
- */
- default:
- }
- break;
-
- case RH_SET_ADDRESS:
- ohci->root_hub_funct_addr = wValue;
- /* ohci->ed_func_ep0[wValue] = &ohci->ed_rh_ep0;
- ohci->ed_func_ep0[wValue]->ep_addr.bep.fa = wValue;
- ohci->ed_func_ep0[wValue]->ed_list = &ohci->ed_rh_epi; */
- ohci->ed_rh_epi.ed_list = NULL;
- ohci->ed_rh_epi.ep_addr.bep.fa = wValue;
- ohci->ed_rh_epi.ep_addr.bep.ep = 0xa1; /* Int in port 1 */
- ohci->ed_func_ep0[0]= NULL;
- len = 0;
- req_reply = RH_ACK;
- break;
-
- case RH_GET_DESCRIPTOR:
- switch ((wValue & 0xff00) >> 8) {
- case (0x01): /* device descriptor */
- len = min(sizeof(root_hub_dev_des), wLength);
- memcpy(data, root_hub_dev_des, len);
- req_reply = RH_ACK;
- break;
- case (0x02): /* configuration descriptor */
- len = min(sizeof(root_hub_config_des), wLength);
- memcpy(data, root_hub_config_des, len);
- req_reply = RH_ACK;
- break;
- case (0x03): /* string descriptors */
- default:
- }
- break;
- case RH_GET_DESCRIPTOR | RH_CLASS:
- data[1] = 0x29;
- stat = readl(&ohci->regs->roothub.a);
- data[2] = stat & 0xff; /* number of ports */
- data[0] = (data[2] / 8) * 2 + 9; /* length of descriptor */
- if(data[0] > wLength) {
- req_reply = RH_REQ_ERR;
- break;
- }
- data[3] = (stat >> 8) & 0xff;
- data[4] = (stat >> 16) & 0xff;
- data[5] = (stat >> 24) & 0xff;
- data[6] = 0; /* Root Hub needs no current from bus */
- stat = readl(&ohci->regs->roothub.b);
- if(data[2] <= 8) { /* less than 8 Ports */
- data[7] = stat & 0xff;
- data[8] = (stat >> 16) & 0xff; /* 0xff for USB Rev. 1.1 ?, stat >> 16 for USB Rev. 1.0 */
- }
- else {
- data[7] = stat & 0xff;
- data[8] = (stat >> 8) & 0xff;
- data[9] = (stat >> 16) & 0xff; /* 0xff for USB Rev. 1.1?, stat >> 16 for USB Rev. 1.0 */
- data[10] = (stat >> 24) & 0xff; /* 0xff for USB Rev. 1.1?, stat >> 24 for USB Rev. 1.0 */
- }
- len = data[0];
- req_reply = RH_ACK;
- break;
-
- case RH_SET_DESCRIPTOR:
- break;
-
- case RH_GET_CONFIGURATION:
- len = 1;
- data[0] = 0x01;
- req_reply = RH_ACK;
- break;
-
- case RH_SET_CONFIGURATION: /* start it up */
- writel( 0x10000, &ohci->regs->roothub.status);
- /*writel( OHCI_INTR_RHSC, &ohci->regs->intrenable);*/
- len = 0;
- req_reply = RH_ACK;
- break;
- /* Optional or meaningless requests
- case RH_GET_STATE | RH_OTHER | RH_CLASS:
- case RH_GET_INTERFACE | RH_INTERFACE:
- case RH_SET_INTERFACE | RH_INTERFACE:
- case RH_SYNC_FRAME | RH_ENDPOINT:
- */
-
- /* Vendor Requests, we are the vendor!
- Will the USB-Consortium give us a Vendor Id
- for a virtual hub-device :-) ?
- We could use these requests for configuration purposes on the HCD Driver, not used in the altenate usb !*/
-
- case RH_SET_FEATURE | RH_VENDOR: /* remove all endpoints of device wIndex = Dev << 8 */
- switch(wValue) {
- case RH_REMOVE_EP:
- ep_addr.iep = 0;
- ep_addr.bep.ep = wIndex & 0xff;
- ep_addr.bep.fa = (wIndex << 8) & 0xff00;
- usb_ohci_rm_function(ohci, ep_addr.iep);
- len=0;
- req_reply = RH_ACK;
- break;
- }
- break;
- case RH_SET_FEATURE | RH_ENDPOINT | RH_VENDOR: /* remove endpoint wIndex = Dev << 8 | EP */
- switch(wValue) {
- case RH_REMOVE_EP:
- ep_addr.iep = 0;
- ep_addr.bep.ep = wIndex & 0xff;
- ep_addr.bep.fa = (wIndex << 8) & 0xff00;
- usb_ohci_rm_ep(ohci, ohci_find_ep(ohci, ep_addr.iep));
- len=0;
- req_reply = RH_ACK;
- break;
- }
- break;
- case RH_SET_EP | RH_ENDPOINT | RH_VENDOR:
- ep_addr.bep.ep = data[0];
- ep_addr.bep.fa = data[1];
- ep_addr.bep.hc = data[2];
- ep_addr.bep.host = data[3];
- rep_handler = data[7] << 24 |data[6] << 16 | data[5] << 8 | data[4];
- /* struct usb_ohci_ed *usb_ohci_add_ep(union ep_addr_ ep_addr,
- struct ohci * ohci, int interval, int load, int (*handler)(int, void*), int ep_size, int speed) */
- usb_ohci_add_ep(ohci, ep_addr.iep, data[8], data[9], (f_handler) rep_handler, data[11] << 8 | data[10] , data[12]);
- len=0;
- req_reply = RH_ACK;
- break;
-
- default:
- }
- printk("USB HC roothubstat1: %x \n", readl( &(ohci->regs->roothub.portstatus[0]) ));
- printk("USB HC roothubstat2: %x \n", readl( &(ohci->regs->roothub.portstatus[1]) ));
-
- /* if (req_reply == RH_ACK) len; */
- queue_reply(ohci, ep_addr_ret.iep, 8, rh_cmd, data, len, lw0, lw1, handler);
- return 0;
-}
-
-int root_hub_int_req(struct ohci * ohci, int cmd_len, void * ctrl, void * data, int data_len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler){
+ case RH_GET_STATUS: *(__u16 *)data = cpu_to_le16(1); OK(2);
+ case RH_GET_STATUS | RH_INTERFACE: *(__u16 *)data = cpu_to_le16(0); OK(2);
+ case RH_GET_STATUS | RH_ENDPOINT: *(__u16 *)data = cpu_to_le16(0); OK(2);
+ case RH_GET_STATUS | RH_CLASS: *(__u32 *)data = cpu_to_le32(RD_RH_STAT & 0x7fff7fff); OK(4);
+ case RH_GET_STATUS | RH_OTHER | RH_CLASS: *(__u32 *)data = cpu_to_le32(RD_RH_PORTSTAT); 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_OVER_CURRENT): WR_RH_STAT(RH_PS_OCIC); OK(0);
+ }
+ break;
+
+ case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case (RH_PORT_ENABLE): WR_RH_PORTSTAT(RH_PS_CCS ); OK(0);
+ case (RH_PORT_SUSPEND): WR_RH_PORTSTAT(RH_PS_POCI); OK(0);
+ case (RH_PORT_POWER): WR_RH_PORTSTAT(RH_PS_LSDA); OK(0);
+ case (RH_C_PORT_CONNECTION): WR_RH_PORTSTAT(RH_PS_CSC ); OK(0);
+ case (RH_C_PORT_ENABLE): WR_RH_PORTSTAT(RH_PS_PESC); OK(0);
+ case (RH_C_PORT_SUSPEND): WR_RH_PORTSTAT(RH_PS_PSSC); OK(0);
+ case (RH_C_PORT_OVER_CURRENT): WR_RH_PORTSTAT(RH_PS_OCIC); OK(0);
+ case (RH_C_PORT_RESET): WR_RH_PORTSTAT(RH_PS_PRSC); OK(0);
+ }
+ break;
+
+ case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
+ switch (wValue) {
+ case (RH_PORT_SUSPEND): WR_RH_PORTSTAT(RH_PS_PSS ); OK(0);
+ case (RH_PORT_RESET): if((RD_RH_PORTSTAT &1) != 0) WR_RH_PORTSTAT(RH_PS_PRS ); /* BUG IN HUP CODE *********/ OK(0);
+ case (RH_PORT_POWER): WR_RH_PORTSTAT(RH_PS_PPS ); OK(0);
+ case (RH_PORT_ENABLE): WR_RH_PORTSTAT(RH_PS_PES ); OK(0);
+ }
+ break;
+
+ case RH_SET_ADDRESS: ohci->rh.devnum = wValue; OK(0);
+
+ case RH_GET_DESCRIPTOR:
+ switch ((wValue & 0xff00) >> 8) {
+ case (0x01): /* device descriptor */
+ len = min(leni, min(sizeof(root_hub_dev_des), wLength));
+ memcpy(data, root_hub_dev_des, len); OK(len);
+ case (0x02): /* configuration descriptor */
+ len = min(leni, min(sizeof(root_hub_config_des), wLength));
+ memcpy(data, root_hub_config_des, len); OK(len);
+ case (0x03): /* string descriptors */
+ default:
+ }
+ break;
+
+ case RH_GET_DESCRIPTOR | RH_CLASS:
+ *(__u8 *)(data_buf+1) = 0x29;
+ *(__u32 *)(data_buf+2) = cpu_to_le32(readl(&ohci->regs->roothub.a));
+ *(__u8 *)data_buf = (*(__u8 *)(data_buf+2) / 8) * 2 + 9; /* length of descriptor */
+
+ len = min(leni, min(*(__u8 *)data_buf, wLength));
+ *(__u8 *)(data_buf+6) = 0; /* Root Hub needs no current from bus */
+ if(*(__u8 *)(data_buf+2) < 8) { /* less than 8 Ports */
+ *(__u8 *) (data_buf+7) = readl(&ohci->regs->roothub.b) & 0xff;
+ *(__u8 *) (data_buf+8) = (readl(&ohci->regs->roothub.b) & 0xff0000) >> 16;
+ }
+ else {
+ *(__u32 *) (data_buf+7) = cpu_to_le32(readl(&ohci->regs->roothub.b));
+ }
+ memcpy(data, data_buf, len);
+ OK(len);
+
+ case RH_GET_CONFIGURATION: *(__u8 *)data = 0x01; OK(1);
- struct ohci_rep_td *td;
- struct ohci_rep_td *tmp;
- union ep_addr_ ep_addr;
-
- td = kmalloc(sizeof(td),GFP_KERNEL);
- tmp = ohci->td_rh_epi;
- td->next_td = NULL;
- if(tmp == NULL) { /* queue td */
- ohci->td_rh_epi = td;
- }
- else {
- while(tmp->next_td != NULL) tmp = tmp->next_td;
- tmp->next_td = td;
- }
- ep_addr.iep = 0;
- ep_addr.bep.fa = ohci->root_hub_funct_addr;
- ep_addr.bep.ep = 0xA1; /* INT IN EP endpoint 1 */
- td->cmd_len = 0;
- td->cmd = NULL;
- td->data = data;
- td->data_len = data_len;
- td->handler = handler;
- td->next_td = NULL;
- td->ep_addr = ep_addr.iep;
- td->lw0 = lw0;
- td->lw1 = lw1;
- ohci_init_rh_int_timer(ohci, 255);
- return 0;
+ case RH_SET_CONFIGURATION: WR_RH_STAT( 0x10000); OK(0);
+ }
+
+ OHCI_DEBUG(printk("USB HC roothubstat1: %x \n", readl( &(ohci->regs->roothub.portstatus[0]) ));)
+ OHCI_DEBUG(printk("USB HC roothubstat2: %x \n", readl( &(ohci->regs->roothub.portstatus[1]) ));)
+
+ OHCI_DEBUG( { int i; printk("USB HC RH bh <<<: 1: ");)
+ OHCI_DEBUG( printk(" data(%d):", len);)
+ OHCI_DEBUG( { for(i=0; i < len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
+ OHCI_DEBUG( printk(" ret_status: %x\n", req_reply); })
+
+ return req_reply;
}
-
-/* prepare Interrupt pipe transaction data; HUP INTERRUPT ENDPOINT */
-int root_hub_send_irq(struct ohci * ohci, void * rh_data, int rh_len ) {
+/* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
+static int root_hub_send_irq(struct ohci * ohci, void * rh_data, int rh_len ) {
int num_ports;
int i;
@@ -496,12 +253,12 @@
__u8 * data = rh_data;
num_ports = readl(&ohci->regs->roothub.a) & 0xff;
- data[0] = (readl(&ohci->regs->roothub.status) & 0x00030000)>0?1:0;
- ret = data[0];
+ *(__u8 *)data = (readl(&ohci->regs->roothub.status) & 0x00030000)>0?1:0;
+ ret = *(__u8 *)data;
for(i=0; i < num_ports; i++) {
- data[i/8] |= ((readl(&ohci->regs->roothub.portstatus[i]) & 0x001f0000)>0?1:0) << ((i+1) % 8);
- ret += data[i/8];
+ *(__u8 *)(data+i/8) |= ((readl(&ohci->regs->roothub.portstatus[i]) & 0x001f0000)>0?1:0) << ((i+1) % 8);
+ ret += *(__u8 *)(data+i/8);
}
len = i/8 + 1;
@@ -510,95 +267,79 @@
return RH_NACK;
}
-
-
-
-static struct timer_list rh_int_timer;
+static int ohci_init_rh_int_timer(struct usb_device * usb_dev, int interval);
/* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
static void rh_int_timer_do(unsigned long ptr) {
int len;
int interval;
- struct ohci * ohci = (struct ohci *) ptr;
- struct ohci_rep_td *td = ohci->td_rh_epi;
+ int ret;
+
+ struct usb_device * usb_dev = (struct usb_device *) ptr;
+ struct ohci * ohci = usb_dev->bus->hcpriv;
+ struct ohci_device * dev = usb_to_ohci(usb_dev);
- if(td != NULL) { /* if ther is a TD handle the INT request */
-
- len = root_hub_send_irq(ohci, td->data, td->data_len );
- if(len > 0) {
- ohci->td_rh_epi = td->next_td;
- td->next_td = ohci->repl_queue;
- ohci->repl_queue = td;
- send_replies(ohci);
+
+ if(ohci->rh.send) {
+ len = root_hub_send_irq(ohci, dev->data, 1 );
+
+ if(len > 0) {
+ OHCI_DEBUG({ int i; printk("USB HC IRQ <<<: RH data(%d):", len);)
+ OHCI_DEBUG( for(i=0; i < len; i++ ) printk(" %02x", ((__u8 *) dev->data)[i]);)
+ OHCI_DEBUG( printk(" ret_status: %x\n", 0); })
+
+ ret = ohci->rh.handler(0, dev->data, len, ohci->rh.dev_id);
+ if(ret <= 0)ohci->rh.send = 0; /* 0 .. do not requeue */
}
}
- interval = ohci->rh_int_interval;
- init_timer(& rh_int_timer);
- rh_int_timer.function = rh_int_timer_do;
- rh_int_timer.data = (unsigned long) ohci;
- rh_int_timer.expires = jiffies + (HZ * (interval<30?30: interval)) /1000;
- add_timer(&rh_int_timer);
+ interval = ohci->rh.interval;
+ ohci_init_rh_int_timer(usb_dev, interval);
}
/* Root Hub INTs are polled by this timer */
-int ohci_init_rh_int_timer(struct ohci * ohci, int interval) {
+static int ohci_init_rh_int_timer(struct usb_device * usb_dev, int interval) {
+ struct ohci * ohci = usb_dev->bus->hcpriv;
- if(!(ohci->rh_int_timer)) {
- ohci->rh_int_timer = 1;
- ohci->rh_int_interval = interval;
- init_timer(& rh_int_timer);
- rh_int_timer.function = rh_int_timer_do;
- rh_int_timer.data = (unsigned long) ohci;
- rh_int_timer.expires = jiffies + (HZ * (interval<30?30: interval)) /1000;
- add_timer(&rh_int_timer);
- }
+ ohci->rh.interval = interval;
+ init_timer(& ohci->rh.rh_int_timer);
+ ohci->rh.rh_int_timer.function = rh_int_timer_do;
+ ohci->rh.rh_int_timer.data = (unsigned long) usb_dev;
+ ohci->rh.rh_int_timer.expires = jiffies + (HZ * (interval<30?30: interval)) /1000;
+ add_timer(&ohci->rh.rh_int_timer);
+
return 0;
}
-int ohci_del_rh_int_timer(struct ohci * ohci) {
- del_timer(&rh_int_timer);
+static int ohci_del_rh_int_timer(struct ohci * ohci) {
+ del_timer(&ohci->rh.rh_int_timer);
return 0;
}
-/* for root hub replies, queue the reply, (it will be sent immediately now) */
-
-int queue_reply(struct ohci * ohci, unsigned int ep_addr, int cmd_len,void * cmd, void * data,int len, __OHCI_BAG lw0, __OHCI_BAG lw1, f_handler handler) {
-
- struct ohci_rep_td *td;
- int status = 0;
-printk("queue_reply ep: %x len: %x\n", ep_addr, len);
-td = kmalloc(sizeof(td), GFP_KERNEL);
-
- if (len < 0) { status = len; len = 0;}
- td->cmd_len = cmd_len;
- td->cmd = cmd;
- td->data = data;
- td->data_len = len;
- td->handler = handler;
- td->next_td = ohci->repl_queue; ohci->repl_queue = td;
- td->ep_addr = ep_addr;
- td->lw0 = lw0;
- td->lw1 = lw1;
- td->status = status;
- send_replies(ohci);
-return 0;
+void * root_hub_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+{
+ struct ohci * ohci = usb_dev->bus->hcpriv;
+
+ OHCI_DEBUG( printk("USB HC-RH IRQ>>>: RH every %d ms\n", period);)
+ ohci->rh.handler = handler;
+ ohci->rh.dev_id = dev_id;
+ ohci->rh.send = 1;
+ ohci->rh.interval = period;
+ ohci_init_rh_int_timer(usb_dev, period);
+ return ohci->rh.int_addr = usb_to_ohci(usb_dev);
}
-/* for root hub replies; send the reply */
-int send_replies(struct ohci * ohci) {
- struct ohci_rep_td *td;
- struct ohci_rep_td *tmp;
-
- td = ohci->repl_queue; ohci->repl_queue = NULL;
- while ( td != NULL) {
- td->handler((void *) ohci, td->ep_addr,td->cmd_len,td->cmd, td->data, td->data_len, td->status, td->lw0, td->lw1);
- tmp = td;
- td = td->next_td;
-
- kfree(tmp);
- }
+int root_hub_release_irq(struct usb_device *usb_dev, void * ed)
+{
+ // struct usb_device *usb_dev = ((struct ohci_device *) ((unsigned int)ed & 0xfffff000))->usb;
+ struct ohci * ohci = usb_dev->bus->hcpriv;
+
+ OHCI_DEBUG( printk("USB HC-RH RM_IRQ>>>:\n");)
+ ohci->rh.send = 0;
+ ohci_del_rh_int_timer(ohci);
return 0;
}
+
+
#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)