Subversion Repositories shark

Rev

Rev 846 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
846 giacomo 1
/*
2
 * Universal Host Controller Interface driver for USB.
3
 *
4
 * Maintainer: Johannes Erdfelt <johannes@erdfelt.com>
5
 *
6
 * (C) Copyright 1999 Linus Torvalds
7
 * (C) Copyright 1999-2002 Johannes Erdfelt, johannes@erdfelt.com
8
 * (C) Copyright 1999 Randy Dunlap
9
 * (C) Copyright 1999 Georg Acher, acher@in.tum.de
10
 * (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
11
 * (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
12
 */
13
 
14
static __u8 root_hub_hub_des[] =
15
{
16
        0x09,                   /*  __u8  bLength; */
17
        0x29,                   /*  __u8  bDescriptorType; Hub-descriptor */
18
        0x02,                   /*  __u8  bNbrPorts; */
19
        0x00,                   /* __u16  wHubCharacteristics; */
20
        0x00,
21
        0x01,                   /*  __u8  bPwrOn2pwrGood; 2ms */
22
        0x00,                   /*  __u8  bHubContrCurrent; 0 mA */
23
        0x00,                   /*  __u8  DeviceRemovable; *** 7 Ports max *** */
24
        0xff                    /*  __u8  PortPwrCtrlMask; *** 7 ports max *** */
25
};
26
 
27
static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
28
{
29
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
30
        unsigned int io_addr = uhci->io_addr;
31
        int i, len = 1;
32
 
33
        *buf = 0;
34
        for (i = 0; i < uhci->rh_numports; i++) {
35
                *buf |= ((inw(io_addr + USBPORTSC1 + i * 2) & 0xa) > 0 ? (1 << (i + 1)) : 0);
36
                len = (i + 1) / 8 + 1;
37
        }
38
 
39
        return !!*buf;
40
}
41
 
42
#define OK(x)                   len = (x); break
43
 
44
#define CLR_RH_PORTSTAT(x) \
45
        status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
46
        status = (status & 0xfff5) & ~(x); \
47
        outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
48
 
49
#define SET_RH_PORTSTAT(x) \
50
        status = inw(io_addr + USBPORTSC1 + 2 * (wIndex-1)); \
51
        status = (status & 0xfff5) | (x); \
52
        outw(status, io_addr + USBPORTSC1 + 2 * (wIndex-1))
53
 
54
 
55
/* size of returned buffer is part of USB spec */
56
static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
57
                        u16 wIndex, char *buf, u16 wLength)
58
{
59
        struct uhci_hcd *uhci = hcd_to_uhci(hcd);
60
        int i, status, retval = 0, len = 0;
61
        unsigned int io_addr = uhci->io_addr;
62
        __u16 cstatus;
63
        char c_p_r[8];
64
 
65
        for (i = 0; i < 8; i++)
66
                c_p_r[i] = 0;
67
 
68
        switch (typeReq) {
69
                /* Request Destination:
70
                   without flags: Device,
71
                   RH_INTERFACE: interface,
72
                   RH_ENDPOINT: endpoint,
73
                   RH_CLASS means HUB here,
74
                   RH_OTHER | RH_CLASS  almost ever means HUB_PORT here
75
                */
76
 
77
        case GetHubStatus:
78
                *(__u32 *)buf = cpu_to_le32(0);
79
                OK(4);          /* hub power */
80
        case GetPortStatus:
81
                status = inw(io_addr + USBPORTSC1 + 2 * (wIndex - 1));
82
                cstatus = ((status & USBPORTSC_CSC) >> (1 - 0)) |
83
                        ((status & USBPORTSC_PEC) >> (3 - 1)) |
84
                        (c_p_r[wIndex - 1] << (0 + 4));
85
                        status = (status & USBPORTSC_CCS) |
86
                        ((status & USBPORTSC_PE) >> (2 - 1)) |
87
                        ((status & USBPORTSC_SUSP) >> (12 - 2)) |
88
                        ((status & USBPORTSC_PR) >> (9 - 4)) |
89
                        (1 << 8) |      /* power on */
90
                        ((status & USBPORTSC_LSDA) << (-8 + 9));
91
 
92
                *(__u16 *)buf = cpu_to_le16(status);
93
                *(__u16 *)(buf + 2) = cpu_to_le16(cstatus);
94
                OK(4);
95
        case SetHubFeature:
96
                switch (wValue) {
97
                case C_HUB_OVER_CURRENT:
98
                case C_HUB_LOCAL_POWER:
99
                        break;
100
                default:
101
                        goto err;
102
                }
103
                break;
104
        case ClearHubFeature:
105
                switch (wValue) {
106
                case C_HUB_OVER_CURRENT:
107
                        OK(0);  /* hub power over current */
108
                default:
109
                        goto err;
110
                }
111
                break;
112
        case SetPortFeature:
113
                if (!wIndex || wIndex > uhci->rh_numports)
114
                        goto err;
115
 
116
                switch (wValue) {
117
                case USB_PORT_FEAT_SUSPEND:
118
                        SET_RH_PORTSTAT(USBPORTSC_SUSP);
119
                        OK(0);
120
                case USB_PORT_FEAT_RESET:
121
                        SET_RH_PORTSTAT(USBPORTSC_PR);
122
                        mdelay(50);     /* USB v1.1 7.1.7.3 */
123
                        c_p_r[wIndex - 1] = 1;
124
                        CLR_RH_PORTSTAT(USBPORTSC_PR);
125
                        udelay(10);
126
                        SET_RH_PORTSTAT(USBPORTSC_PE);
127
                        mdelay(10);
128
                        SET_RH_PORTSTAT(0xa);
129
                        OK(0);
130
                case USB_PORT_FEAT_POWER:
131
                        OK(0); /* port power ** */
132
                case USB_PORT_FEAT_ENABLE:
133
                        SET_RH_PORTSTAT(USBPORTSC_PE);
134
                        OK(0);
135
                default:
136
                        goto err;
137
                }
138
                break;
139
        case ClearPortFeature:
140
                if (!wIndex || wIndex > uhci->rh_numports)
141
                        goto err;
142
 
143
                switch (wValue) {
144
                case USB_PORT_FEAT_ENABLE:
145
                        CLR_RH_PORTSTAT(USBPORTSC_PE);
146
                        OK(0);
147
                case USB_PORT_FEAT_C_ENABLE:
148
                        SET_RH_PORTSTAT(USBPORTSC_PEC);
149
                        OK(0);
150
                case USB_PORT_FEAT_SUSPEND:
151
                        CLR_RH_PORTSTAT(USBPORTSC_SUSP);
152
                        OK(0);
153
                case USB_PORT_FEAT_C_SUSPEND:
154
                        /*** WR_RH_PORTSTAT(RH_PS_PSSC); */
155
                        OK(0);
156
                case USB_PORT_FEAT_POWER:
157
                        OK(0);  /* port power */
158
                case USB_PORT_FEAT_C_CONNECTION:
159
                        SET_RH_PORTSTAT(USBPORTSC_CSC);
160
                        OK(0);
161
                case USB_PORT_FEAT_C_OVER_CURRENT:
162
                        OK(0);  /* port power over current */
163
                case USB_PORT_FEAT_C_RESET:
164
                        c_p_r[wIndex - 1] = 0;
165
                        OK(0);
166
                default:
167
                        goto err;
168
                }
169
                break;
170
        case GetHubDescriptor:
171
                len = min_t(unsigned int, wLength,
172
                          min_t(unsigned int, sizeof(root_hub_hub_des), wLength));
173
                memcpy(buf, root_hub_hub_des, len);
174
                if (len > 2)
175
                        buf[2] = uhci->rh_numports;
176
                OK(len);
177
        default:
178
err:
179
                retval = -EPIPE;
180
        }
181
 
182
        return retval;
183
}
184