2 * HCD (OHCI) Virtual Root Hub for USB.
4 * (C) Copyright 1999 Roman Weissgaerber (weissg@vienna.at)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * The Root Hub is build into the HC (UHCI or OHCI) hardware.
22 * This piece of code lets it look like it resides on the usb
23 * like the other hubs.
24 * (for anyone who wants to do a control operation on the root hub)
35 #include <linux/kernel.h>
36 #include <linux/delay.h>
37 #include <linux/ioport.h>
38 #include <linux/sched.h>
39 #include <linux/malloc.h>
40 #include <linux/string.h>
47 #include "ohci-root-hub.h"
49 static __u8 root_hub_dev_des
[] =
51 0x12, /* __u8 bLength; */
52 0x01, /* __u8 bDescriptorType; Device */
53 0x00, /* __u16 bcdUSB; v1.0 */
55 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
56 0x00, /* __u8 bDeviceSubClass; */
57 0x00, /* __u8 bDeviceProtocol; */
58 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
59 0x00, /* __u16 idVendor; */
61 0x00, /* __u16 idProduct; */
63 0x00, /* __u16 bcdDevice; */
65 0x00, /* __u8 iManufacturer; */
66 0x00, /* __u8 iProduct; */
67 0x00, /* __u8 iSerialNumber; */
68 0x01 /* __u8 bNumConfigurations; */
72 /* Configuration descriptor */
73 static __u8 root_hub_config_des
[] =
75 0x09, /* __u8 bLength; */
76 0x02, /* __u8 bDescriptorType; Configuration */
77 0x19, /* __u16 wTotalLength; */
79 0x01, /* __u8 bNumInterfaces; */
80 0x01, /* __u8 bConfigurationValue; */
81 0x00, /* __u8 iConfiguration; */
82 0x40, /* __u8 bmAttributes;
83 Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
84 0x00, /* __u8 MaxPower; */
87 0x09, /* __u8 if_bLength; */
88 0x04, /* __u8 if_bDescriptorType; Interface */
89 0x00, /* __u8 if_bInterfaceNumber; */
90 0x00, /* __u8 if_bAlternateSetting; */
91 0x01, /* __u8 if_bNumEndpoints; */
92 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
93 0x00, /* __u8 if_bInterfaceSubClass; */
94 0x00, /* __u8 if_bInterfaceProtocol; */
95 0x00, /* __u8 if_iInterface; */
98 0x07, /* __u8 ep_bLength; */
99 0x05, /* __u8 ep_bDescriptorType; Endpoint */
100 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
101 0x03, /* __u8 ep_bmAttributes; Interrupt */
102 0x08, /* __u16 ep_wMaxPacketSize; 8 Bytes */
104 0xff /* __u8 ep_bInterval; 255 ms */
108 For OHCI we need just the 2nd Byte, so we
109 don't need this constant byte-array
111 static __u8 root_hub_hub_des[] =
113 0x00, * __u8 bLength; *
114 0x29, * __u8 bDescriptorType; Hub-descriptor *
115 0x02, * __u8 bNbrPorts; *
116 0x00, * __u16 wHubCharacteristics; *
118 0x01, * __u8 bPwrOn2pwrGood; 2ms *
119 0x00, * __u8 bHubContrCurrent; 0 mA *
120 0x00, * __u8 DeviceRemovable; *** 8 Ports max *** *
121 0xff * __u8 PortPwrCtrlMask; *** 8 ports max *** *
125 #define OK(x) len = (x); req_reply = 0; break
126 #define WR_RH_STAT(x) writel((x), &ohci->regs->roothub.status)
127 #define WR_RH_PORTSTAT(x) writel((x), &ohci->regs->roothub.portstatus[wIndex-1])
128 #define RD_RH_STAT readl(&ohci->regs->roothub.status)
129 #define RD_RH_PORTSTAT readl(&ohci->regs->roothub.portstatus[wIndex-1])
131 int root_hub_control_msg(struct usb_device
*usb_dev
, unsigned int pipe
, devrequest
* cmd
, void *data
, int leni
)
133 struct ohci
* ohci
= usb_dev
->bus
->hcpriv
;
139 __u16 bmRType_bReq
= cmd
->requesttype
| (cmd
->request
<< 8);
140 __u16 wValue
= cpu_to_le16(cmd
->value
);
141 __u16 wIndex
= cpu_to_le16(cmd
->index
);
142 __u16 wLength
= cpu_to_le16(cmd
->length
);
144 OHCI_DEBUG(printk("USB root hub: adr: %2x cmd(%1x): ", ohci
->rh
.devnum
, 8);)
145 OHCI_DEBUG({ int i
; for(i
=0;i
<8;i
++) printk(" %02x", ((unsigned char *)cmd
)[i
]);})
146 OHCI_DEBUG(printk(" ; \n");)
148 switch (bmRType_bReq
) {
149 /* Request Destination:
150 without flags: Device,
151 RH_INTERFACE: interface,
152 RH_ENDPOINT: endpoint,
153 RH_CLASS means HUB here,
154 RH_OTHER | RH_CLASS almost ever means HUB_PORT here
157 case RH_GET_STATUS
: *(__u16
*)data
= cpu_to_le16(1); OK(2);
158 case RH_GET_STATUS
| RH_INTERFACE
: *(__u16
*)data
= cpu_to_le16(0); OK(2);
159 case RH_GET_STATUS
| RH_ENDPOINT
: *(__u16
*)data
= cpu_to_le16(0); OK(2);
160 case RH_GET_STATUS
| RH_CLASS
: *(__u32
*)data
= cpu_to_le32(RD_RH_STAT
& 0x7fff7fff); OK(4);
161 case RH_GET_STATUS
| RH_OTHER
| RH_CLASS
: *(__u32
*)data
= cpu_to_le32(RD_RH_PORTSTAT
); OK(4);
163 case RH_CLEAR_FEATURE
| RH_ENDPOINT
:
165 case (RH_ENDPOINT_STALL
): OK(0);
169 case RH_CLEAR_FEATURE
| RH_CLASS
:
171 case (RH_C_HUB_OVER_CURRENT
): WR_RH_STAT(RH_PS_OCIC
); OK(0);
175 case RH_CLEAR_FEATURE
| RH_OTHER
| RH_CLASS
:
177 case (RH_PORT_ENABLE
): WR_RH_PORTSTAT(RH_PS_CCS
); OK(0);
178 case (RH_PORT_SUSPEND
): WR_RH_PORTSTAT(RH_PS_POCI
); OK(0);
179 case (RH_PORT_POWER
): WR_RH_PORTSTAT(RH_PS_LSDA
); OK(0);
180 case (RH_C_PORT_CONNECTION
): WR_RH_PORTSTAT(RH_PS_CSC
); OK(0);
181 case (RH_C_PORT_ENABLE
): WR_RH_PORTSTAT(RH_PS_PESC
); OK(0);
182 case (RH_C_PORT_SUSPEND
): WR_RH_PORTSTAT(RH_PS_PSSC
); OK(0);
183 case (RH_C_PORT_OVER_CURRENT
): WR_RH_PORTSTAT(RH_PS_OCIC
); OK(0);
184 case (RH_C_PORT_RESET
): WR_RH_PORTSTAT(RH_PS_PRSC
); OK(0);
188 case RH_SET_FEATURE
| RH_OTHER
| RH_CLASS
:
190 case (RH_PORT_SUSPEND
): WR_RH_PORTSTAT(RH_PS_PSS
); OK(0);
191 case (RH_PORT_RESET
): if((RD_RH_PORTSTAT
&1) != 0) WR_RH_PORTSTAT(RH_PS_PRS
); /* BUG IN HUP CODE *********/ OK(0);
192 case (RH_PORT_POWER
): WR_RH_PORTSTAT(RH_PS_PPS
); OK(0);
193 case (RH_PORT_ENABLE
): WR_RH_PORTSTAT(RH_PS_PES
); OK(0);
197 case RH_SET_ADDRESS
: ohci
->rh
.devnum
= wValue
; OK(0);
199 case RH_GET_DESCRIPTOR
:
200 switch ((wValue
& 0xff00) >> 8) {
201 case (0x01): /* device descriptor */
202 len
= min(leni
, min(sizeof(root_hub_dev_des
), wLength
));
203 memcpy(data
, root_hub_dev_des
, len
); OK(len
);
204 case (0x02): /* configuration descriptor */
205 len
= min(leni
, min(sizeof(root_hub_config_des
), wLength
));
206 memcpy(data
, root_hub_config_des
, len
); OK(len
);
207 case (0x03): /* string descriptors */
212 case RH_GET_DESCRIPTOR
| RH_CLASS
:
213 *(__u8
*)(data_buf
+1) = 0x29;
214 *(__u32
*)(data_buf
+2) = cpu_to_le32(readl(&ohci
->regs
->roothub
.a
));
215 *(__u8
*)data_buf
= (*(__u8
*)(data_buf
+2) / 8) * 2 + 9; /* length of descriptor */
217 len
= min(leni
, min(*(__u8
*)data_buf
, wLength
));
218 *(__u8
*)(data_buf
+6) = 0; /* Root Hub needs no current from bus */
219 if(*(__u8
*)(data_buf
+2) < 8) { /* less than 8 Ports */
220 *(__u8
*) (data_buf
+7) = readl(&ohci
->regs
->roothub
.b
) & 0xff;
221 *(__u8
*) (data_buf
+8) = (readl(&ohci
->regs
->roothub
.b
) & 0xff0000) >> 16;
224 *(__u32
*) (data_buf
+7) = cpu_to_le32(readl(&ohci
->regs
->roothub
.b
));
226 memcpy(data
, data_buf
, len
);
229 case RH_GET_CONFIGURATION
: *(__u8
*)data
= 0x01; OK(1);
231 case RH_SET_CONFIGURATION
: WR_RH_STAT( 0x10000); OK(0);
234 OHCI_DEBUG(printk("USB HC roothubstat1: %x \n", readl( &(ohci
->regs
->roothub
.portstatus
[0]) ));)
235 OHCI_DEBUG(printk("USB HC roothubstat2: %x \n", readl( &(ohci
->regs
->roothub
.portstatus
[1]) ));)
241 /* prepare Interrupt pipe transaction data; HUB INTERRUPT ENDPOINT */
242 static int root_hub_send_irq(struct ohci
* ohci
, void * rh_data
, int rh_len
) {
249 __u8
* data
= rh_data
;
251 num_ports
= readl(&ohci
->regs
->roothub
.a
) & 0xff;
252 *(__u8
*)data
= (readl(&ohci
->regs
->roothub
.status
) & 0x00030000)>0?1:0;
255 for(i
=0; i
< num_ports
; i
++) {
256 *(__u8
*)(data
+i
/8) |= ((readl(&ohci
->regs
->roothub
.portstatus
[i
]) & 0x001f0000)>0?1:0) << ((i
+1) % 8);
257 ret
+= *(__u8
*)(data
+i
/8);
261 if (ret
> 0) return len
;
267 static int ohci_init_rh_int_timer(struct usb_device
* usb_dev
, int interval
);
269 /* Virtual Root Hub INTs are polled by this timer every "intervall" ms */
270 static void rh_int_timer_do(unsigned long ptr
) {
275 struct usb_device
* usb_dev
= (struct usb_device
*) ptr
;
276 struct ohci
* ohci
= usb_dev
->bus
->hcpriv
;
277 struct ohci_device
* dev
= usb_to_ohci(usb_dev
);
281 len
= root_hub_send_irq(ohci
, dev
->data
, 1 );
285 ret
= ohci
->rh
.handler(0, dev
->data
, len
, ohci
->rh
.dev_id
);
286 if(ret
<= 0)ohci
->rh
.send
= 0; /* 0 .. do not requeue */
289 interval
= ohci
->rh
.interval
;
290 ohci_init_rh_int_timer(usb_dev
, interval
);
293 /* Root Hub INTs are polled by this timer */
294 static int ohci_init_rh_int_timer(struct usb_device
* usb_dev
, int interval
) {
295 struct ohci
* ohci
= usb_dev
->bus
->hcpriv
;
297 ohci
->rh
.interval
= interval
;
298 init_timer(& ohci
->rh
.rh_int_timer
);
299 ohci
->rh
.rh_int_timer
.function
= rh_int_timer_do
;
300 ohci
->rh
.rh_int_timer
.data
= (unsigned long) usb_dev
;
301 ohci
->rh
.rh_int_timer
.expires
= jiffies
+ (HZ
* (interval
<30?30: interval
)) /1000;
302 add_timer(&ohci
->rh
.rh_int_timer
);
307 static int ohci_del_rh_int_timer(struct ohci
* ohci
) {
308 del_timer(&ohci
->rh
.rh_int_timer
);
312 void * root_hub_request_irq(struct usb_device
*usb_dev
, unsigned int pipe
, usb_device_irq handler
, int period
, void *dev_id
)
314 struct ohci
* ohci
= usb_dev
->bus
->hcpriv
;
316 OHCI_DEBUG( printk("USB HC-RH IRQ>>>: RH every %d ms\n", period
);)
317 ohci
->rh
.handler
= handler
;
318 ohci
->rh
.dev_id
= dev_id
;
320 ohci
->rh
.interval
= period
;
321 ohci_init_rh_int_timer(usb_dev
, period
);
322 return ohci
->rh
.int_addr
= usb_to_ohci(usb_dev
);
325 int root_hub_release_irq(struct usb_device
*usb_dev
, void * ed
)
327 // struct usb_device *usb_dev = ((struct ohci_device *) ((unsigned int)ed & 0xfffff000))->usb;
328 struct ohci
* ohci
= usb_dev
->bus
->hcpriv
;
330 OHCI_DEBUG( printk("USB HC-RH RM_IRQ>>>:\n");)
332 ohci_del_rh_int_timer(ohci
);