1 #include <minix/config.h>
2 #include <minix/const.h>
3 #include <minix/usb.h>
4 #include <minix/com.h>
5 #include <minix/safecopies.h>
6 #include <minix/sysutil.h>
7 #include <minix/ds.h>
8 #include <stdlib.h>
9 #include <errno.h>
10 #include <string.h>
11
12 static struct usb_urb * pending_urbs = NULL;
13 static endpoint_t hcd_ep;
14
15 static void _usb_urb_complete(struct usb_driver *ud, unsigned int urb_id);
16
17 /*****************************************************************************
18 * usb_send_urb *
19 ****************************************************************************/
usb_send_urb(struct usb_urb * urb)20 int usb_send_urb(struct usb_urb* urb)
21 {
22 message msg;
23 int res;
24 cp_grant_id_t gid;
25 if (urb == NULL) {
26 return EINVAL;
27 }
28
29 if (hcd_ep == 0) {
30 return EINVAL;
31 }
32
33 /* setup grant */
34 gid = cpf_grant_direct(hcd_ep,(vir_bytes) &urb->dev_id,
35 urb->urb_size - sizeof(void*),CPF_WRITE|CPF_READ);
36
37 if (gid == -1) {
38 printf("usb_send_urb: grant failed: "
39 "cpf_grant_direct(%d,%p,%d)\n", hcd_ep, urb, urb->urb_size);
40 return EINVAL;
41 }
42
43 urb->gid = gid;
44
45 /* prepare message */
46 msg.m_type = USB_RQ_SEND_URB;
47 msg.USB_GRANT_ID = gid;
48 msg.USB_GRANT_SIZE = urb->urb_size-sizeof(void*);
49
50 /* send message */
51 res = ipc_sendrec(hcd_ep, &msg);
52
53 if (res != 0) {
54 panic("usb_send_urb: could not talk to hcd: %d", res);
55 }
56
57 if (msg.m_type != USB_REPLY) {
58 panic("usb_send_urb: got illegal response from hcd: %d", msg.m_type);
59 }
60
61 if (msg.USB_RESULT != 0) {
62 panic("usb_send_urb: hcd could not enqueue URB: %ld", msg.USB_RESULT);
63 }
64
65 /* everything ok, add urb to pending_urbs */
66 urb->urb_id = msg.USB_URB_ID;
67 urb->next = pending_urbs;
68 pending_urbs = urb;
69
70 /* done. */
71
72 /* (The HCD will send us a message when the URB is completed.) */
73
74 return res;
75 }
76
77 /*****************************************************************************
78 * usb_cancle_urb *
79 ****************************************************************************/
usb_cancle_urb(struct usb_urb * urb)80 int usb_cancle_urb(struct usb_urb* urb)
81 {
82 int res;
83 message msg;
84
85 if (urb == NULL) {
86 panic("usb_send_urb: urb == NULL!");
87 }
88
89 if (urb->urb_id == USB_INVALID_URB_ID) {
90 return EINVAL;
91 }
92
93 /* prepare message */
94 msg.m_type = USB_RQ_CANCEL_URB;
95 msg.USB_URB_ID = urb->urb_id;
96
97 /* send message */
98 res = ipc_sendrec(hcd_ep, &msg);
99
100 if (res != 0) {
101 panic("usb_cancle_urb: could not talk to hcd: %d", res);
102 }
103
104 if (msg.m_type != USB_REPLY) {
105 panic("usb_cancle_urb: got illegal response from hcd: %d", msg.m_type);
106 }
107
108 if (msg.USB_RESULT != 0) {
109 panic("usb_cancle_urb: got illegal response from hcd: %d", msg.m_type);
110 }
111
112 res = msg.USB_RESULT;
113
114 /* done. */
115 return res;
116 }
117
118 /*****************************************************************************
119 * usb_init *
120 ****************************************************************************/
usb_init(char * name)121 int usb_init(char *name)
122 {
123 int res;
124 message msg;
125
126 /* get the endpoint of the HCD */
127 res = ds_retrieve_label_endpt("usbd", &hcd_ep);
128
129 if (res != 0) {
130 panic("usb_init: ds_retrieve_label_endpt failed for 'usb': %d", res);
131 }
132
133 msg.m_type = USB_RQ_INIT;
134
135 strncpy(msg.USB_RB_INIT_NAME, name, M_PATH_STRING_MAX);
136
137 res = ipc_sendrec(hcd_ep, &msg);
138
139 if (res != 0) {
140 panic("usb_init: can't talk to USB: %d", res);
141 }
142
143 if (msg.m_type != USB_REPLY) {
144 panic("usb_init: bad reply from USB: %d", msg.m_type);
145 }
146
147 if (msg.USB_RESULT != 0 ) {
148 panic("usb_init: init failed: %ld", msg.USB_RESULT);
149 }
150
151 return 0;
152 }
153
154 /*****************************************************************************
155 * _usb_urb_complete *
156 ****************************************************************************/
_usb_urb_complete(struct usb_driver * ud,unsigned int urb_id)157 static void _usb_urb_complete(struct usb_driver *ud, unsigned int urb_id)
158 {
159 /* find the corresponding URB in the urb_pending list. */
160 struct usb_urb * urb = NULL;
161 if (pending_urbs != NULL) {
162 if (pending_urbs->urb_id == urb_id) {
163 urb = pending_urbs;
164 pending_urbs = urb->next;
165 } else {
166 struct usb_urb *u = pending_urbs;
167 while (u->next) {
168 if (u->next->urb_id == urb_id) {
169 urb = u->next;
170 u->next = u->next->next;
171 urb->next = NULL;
172 break;
173 }
174 u = u->next;
175 }
176 }
177 }
178
179 /* Did we find a URB? */
180 if (urb != NULL) {
181 /* revoke grant */
182 cpf_revoke(urb->gid);
183 /* call completion handler */
184 #if 0
185 dump_urb(urb);
186 #endif
187 ud->urb_completion(urb);
188 } else {
189 printf("WARN: _usb_urb_complete: did not find URB with ID %u",
190 urb_id);
191 }
192 }
193
194 /*****************************************************************************
195 * usb_handle_msg *
196 ****************************************************************************/
usb_handle_msg(struct usb_driver * ud,message * msg)197 int usb_handle_msg(struct usb_driver *ud, message *msg)
198 {
199 /*
200 * we expect kind of messages:
201 * - new usb device
202 * - removed device
203 * - URB completed
204 *
205 * NOTE: the hcd driver doesn't expect replies for these messages.
206 */
207
208 if (!ud) {
209 return -1;
210 }
211
212 switch(msg->m_type) {
213 case USB_COMPLETE_URB:
214 _usb_urb_complete(ud, (unsigned int)msg->USB_URB_ID);
215 return 0;
216 case USB_ANNOUCE_DEV:
217 ud->connect_device(msg->USB_DEV_ID, msg->USB_INTERFACES);
218 return 0;
219 case USB_WITHDRAW_DEV:
220 ud->disconnect_device(msg->USB_DEV_ID);
221 return 0;
222 default:
223 panic("usb_handle_msg: bogus message from USB");
224 }
225 }
226
227
228 /*****************************************************************************
229 * usb_send_info *
230 *****************************************************************************/
231 int
usb_send_info(long info_type,long info_value)232 usb_send_info(long info_type, long info_value)
233 {
234 int res;
235 message msg;
236
237 /* Prepare message */
238 msg.m_type = USB_RQ_SEND_INFO;
239 msg.USB_INFO_TYPE = info_type;
240 msg.USB_INFO_VALUE = info_value;
241
242 /* Send/receive message */
243 res = ipc_sendrec(hcd_ep, &msg);
244
245 if (res != 0)
246 panic("usb_send_info: could not talk to HCD: %d", res);
247
248 if (msg.m_type != USB_REPLY)
249 panic("usb_send_info: got illegal response from HCD: %d", msg.m_type);
250
251 if (msg.USB_RESULT != 0)
252 panic("usb_send_info: got illegal response from HCD: %d", msg.m_type);
253
254 return msg.USB_RESULT;
255 }
256