xref: /minix/minix/lib/libusb/usb.c (revision e3b78ef1)
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  ****************************************************************************/
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  ****************************************************************************/
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  ****************************************************************************/
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  ****************************************************************************/
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  ****************************************************************************/
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
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