1433d6423SLionel Sambuc #include <minix/config.h>
2433d6423SLionel Sambuc #include <minix/const.h>
3433d6423SLionel Sambuc #include <minix/usb.h>
4433d6423SLionel Sambuc #include <minix/com.h>
5433d6423SLionel Sambuc #include <minix/safecopies.h>
6433d6423SLionel Sambuc #include <minix/sysutil.h>
7433d6423SLionel Sambuc #include <minix/ds.h>
8433d6423SLionel Sambuc #include <stdlib.h>
9433d6423SLionel Sambuc #include <errno.h>
10433d6423SLionel Sambuc #include <string.h>
11433d6423SLionel Sambuc
12433d6423SLionel Sambuc static struct usb_urb * pending_urbs = NULL;
13433d6423SLionel Sambuc static endpoint_t hcd_ep;
14433d6423SLionel Sambuc
15*65f76edbSDavid van Moolenbroek static void _usb_urb_complete(struct usb_driver *ud, unsigned int urb_id);
16433d6423SLionel Sambuc
17433d6423SLionel Sambuc /*****************************************************************************
18433d6423SLionel Sambuc * usb_send_urb *
19433d6423SLionel Sambuc ****************************************************************************/
usb_send_urb(struct usb_urb * urb)20433d6423SLionel Sambuc int usb_send_urb(struct usb_urb* urb)
21433d6423SLionel Sambuc {
22433d6423SLionel Sambuc message msg;
23433d6423SLionel Sambuc int res;
24433d6423SLionel Sambuc cp_grant_id_t gid;
25433d6423SLionel Sambuc if (urb == NULL) {
26433d6423SLionel Sambuc return EINVAL;
27433d6423SLionel Sambuc }
28433d6423SLionel Sambuc
29433d6423SLionel Sambuc if (hcd_ep == 0) {
30433d6423SLionel Sambuc return EINVAL;
31433d6423SLionel Sambuc }
32433d6423SLionel Sambuc
33433d6423SLionel Sambuc /* setup grant */
34433d6423SLionel Sambuc gid = cpf_grant_direct(hcd_ep,(vir_bytes) &urb->dev_id,
35433d6423SLionel Sambuc urb->urb_size - sizeof(void*),CPF_WRITE|CPF_READ);
36433d6423SLionel Sambuc
37433d6423SLionel Sambuc if (gid == -1) {
38433d6423SLionel Sambuc printf("usb_send_urb: grant failed: "
39433d6423SLionel Sambuc "cpf_grant_direct(%d,%p,%d)\n", hcd_ep, urb, urb->urb_size);
40433d6423SLionel Sambuc return EINVAL;
41433d6423SLionel Sambuc }
42433d6423SLionel Sambuc
43433d6423SLionel Sambuc urb->gid = gid;
44433d6423SLionel Sambuc
45433d6423SLionel Sambuc /* prepare message */
46433d6423SLionel Sambuc msg.m_type = USB_RQ_SEND_URB;
47433d6423SLionel Sambuc msg.USB_GRANT_ID = gid;
48433d6423SLionel Sambuc msg.USB_GRANT_SIZE = urb->urb_size-sizeof(void*);
49433d6423SLionel Sambuc
50433d6423SLionel Sambuc /* send message */
51433d6423SLionel Sambuc res = ipc_sendrec(hcd_ep, &msg);
52433d6423SLionel Sambuc
53433d6423SLionel Sambuc if (res != 0) {
54433d6423SLionel Sambuc panic("usb_send_urb: could not talk to hcd: %d", res);
55433d6423SLionel Sambuc }
56433d6423SLionel Sambuc
57433d6423SLionel Sambuc if (msg.m_type != USB_REPLY) {
58433d6423SLionel Sambuc panic("usb_send_urb: got illegal response from hcd: %d", msg.m_type);
59433d6423SLionel Sambuc }
60433d6423SLionel Sambuc
61433d6423SLionel Sambuc if (msg.USB_RESULT != 0) {
62433d6423SLionel Sambuc panic("usb_send_urb: hcd could not enqueue URB: %ld", msg.USB_RESULT);
63433d6423SLionel Sambuc }
64433d6423SLionel Sambuc
65433d6423SLionel Sambuc /* everything ok, add urb to pending_urbs */
66433d6423SLionel Sambuc urb->urb_id = msg.USB_URB_ID;
67433d6423SLionel Sambuc urb->next = pending_urbs;
68433d6423SLionel Sambuc pending_urbs = urb;
69433d6423SLionel Sambuc
70433d6423SLionel Sambuc /* done. */
71433d6423SLionel Sambuc
72433d6423SLionel Sambuc /* (The HCD will send us a message when the URB is completed.) */
73433d6423SLionel Sambuc
74433d6423SLionel Sambuc return res;
75433d6423SLionel Sambuc }
76433d6423SLionel Sambuc
77433d6423SLionel Sambuc /*****************************************************************************
78433d6423SLionel Sambuc * usb_cancle_urb *
79433d6423SLionel Sambuc ****************************************************************************/
usb_cancle_urb(struct usb_urb * urb)80433d6423SLionel Sambuc int usb_cancle_urb(struct usb_urb* urb)
81433d6423SLionel Sambuc {
82433d6423SLionel Sambuc int res;
83433d6423SLionel Sambuc message msg;
84433d6423SLionel Sambuc
85433d6423SLionel Sambuc if (urb == NULL) {
86433d6423SLionel Sambuc panic("usb_send_urb: urb == NULL!");
87433d6423SLionel Sambuc }
88433d6423SLionel Sambuc
89433d6423SLionel Sambuc if (urb->urb_id == USB_INVALID_URB_ID) {
90433d6423SLionel Sambuc return EINVAL;
91433d6423SLionel Sambuc }
92433d6423SLionel Sambuc
93433d6423SLionel Sambuc /* prepare message */
94433d6423SLionel Sambuc msg.m_type = USB_RQ_CANCEL_URB;
95433d6423SLionel Sambuc msg.USB_URB_ID = urb->urb_id;
96433d6423SLionel Sambuc
97433d6423SLionel Sambuc /* send message */
98433d6423SLionel Sambuc res = ipc_sendrec(hcd_ep, &msg);
99433d6423SLionel Sambuc
100433d6423SLionel Sambuc if (res != 0) {
101433d6423SLionel Sambuc panic("usb_cancle_urb: could not talk to hcd: %d", res);
102433d6423SLionel Sambuc }
103433d6423SLionel Sambuc
104433d6423SLionel Sambuc if (msg.m_type != USB_REPLY) {
105433d6423SLionel Sambuc panic("usb_cancle_urb: got illegal response from hcd: %d", msg.m_type);
106433d6423SLionel Sambuc }
107433d6423SLionel Sambuc
108433d6423SLionel Sambuc if (msg.USB_RESULT != 0) {
109433d6423SLionel Sambuc panic("usb_cancle_urb: got illegal response from hcd: %d", msg.m_type);
110433d6423SLionel Sambuc }
111433d6423SLionel Sambuc
112433d6423SLionel Sambuc res = msg.USB_RESULT;
113433d6423SLionel Sambuc
114433d6423SLionel Sambuc /* done. */
115433d6423SLionel Sambuc return res;
116433d6423SLionel Sambuc }
117433d6423SLionel Sambuc
118433d6423SLionel Sambuc /*****************************************************************************
119433d6423SLionel Sambuc * usb_init *
120433d6423SLionel Sambuc ****************************************************************************/
usb_init(char * name)121433d6423SLionel Sambuc int usb_init(char *name)
122433d6423SLionel Sambuc {
123433d6423SLionel Sambuc int res;
124433d6423SLionel Sambuc message msg;
125433d6423SLionel Sambuc
126433d6423SLionel Sambuc /* get the endpoint of the HCD */
127433d6423SLionel Sambuc res = ds_retrieve_label_endpt("usbd", &hcd_ep);
128433d6423SLionel Sambuc
129433d6423SLionel Sambuc if (res != 0) {
130433d6423SLionel Sambuc panic("usb_init: ds_retrieve_label_endpt failed for 'usb': %d", res);
131433d6423SLionel Sambuc }
132433d6423SLionel Sambuc
133433d6423SLionel Sambuc msg.m_type = USB_RQ_INIT;
134433d6423SLionel Sambuc
135433d6423SLionel Sambuc strncpy(msg.USB_RB_INIT_NAME, name, M_PATH_STRING_MAX);
136433d6423SLionel Sambuc
137433d6423SLionel Sambuc res = ipc_sendrec(hcd_ep, &msg);
138433d6423SLionel Sambuc
139433d6423SLionel Sambuc if (res != 0) {
140433d6423SLionel Sambuc panic("usb_init: can't talk to USB: %d", res);
141433d6423SLionel Sambuc }
142433d6423SLionel Sambuc
143433d6423SLionel Sambuc if (msg.m_type != USB_REPLY) {
144433d6423SLionel Sambuc panic("usb_init: bad reply from USB: %d", msg.m_type);
145433d6423SLionel Sambuc }
146433d6423SLionel Sambuc
147433d6423SLionel Sambuc if (msg.USB_RESULT != 0 ) {
148433d6423SLionel Sambuc panic("usb_init: init failed: %ld", msg.USB_RESULT);
149433d6423SLionel Sambuc }
150433d6423SLionel Sambuc
151433d6423SLionel Sambuc return 0;
152433d6423SLionel Sambuc }
153433d6423SLionel Sambuc
154433d6423SLionel Sambuc /*****************************************************************************
155433d6423SLionel Sambuc * _usb_urb_complete *
156433d6423SLionel Sambuc ****************************************************************************/
_usb_urb_complete(struct usb_driver * ud,unsigned int urb_id)157*65f76edbSDavid van Moolenbroek static void _usb_urb_complete(struct usb_driver *ud, unsigned int urb_id)
158433d6423SLionel Sambuc {
159433d6423SLionel Sambuc /* find the corresponding URB in the urb_pending list. */
160433d6423SLionel Sambuc struct usb_urb * urb = NULL;
161433d6423SLionel Sambuc if (pending_urbs != NULL) {
162433d6423SLionel Sambuc if (pending_urbs->urb_id == urb_id) {
163433d6423SLionel Sambuc urb = pending_urbs;
164433d6423SLionel Sambuc pending_urbs = urb->next;
165433d6423SLionel Sambuc } else {
166433d6423SLionel Sambuc struct usb_urb *u = pending_urbs;
167433d6423SLionel Sambuc while (u->next) {
168433d6423SLionel Sambuc if (u->next->urb_id == urb_id) {
169433d6423SLionel Sambuc urb = u->next;
170433d6423SLionel Sambuc u->next = u->next->next;
171433d6423SLionel Sambuc urb->next = NULL;
172433d6423SLionel Sambuc break;
173433d6423SLionel Sambuc }
174433d6423SLionel Sambuc u = u->next;
175433d6423SLionel Sambuc }
176433d6423SLionel Sambuc }
177433d6423SLionel Sambuc }
178433d6423SLionel Sambuc
179433d6423SLionel Sambuc /* Did we find a URB? */
180433d6423SLionel Sambuc if (urb != NULL) {
181433d6423SLionel Sambuc /* revoke grant */
182433d6423SLionel Sambuc cpf_revoke(urb->gid);
183433d6423SLionel Sambuc /* call completion handler */
184433d6423SLionel Sambuc #if 0
185433d6423SLionel Sambuc dump_urb(urb);
186433d6423SLionel Sambuc #endif
187433d6423SLionel Sambuc ud->urb_completion(urb);
188433d6423SLionel Sambuc } else {
189*65f76edbSDavid van Moolenbroek printf("WARN: _usb_urb_complete: did not find URB with ID %u",
190*65f76edbSDavid van Moolenbroek urb_id);
191433d6423SLionel Sambuc }
192433d6423SLionel Sambuc }
193433d6423SLionel Sambuc
194433d6423SLionel Sambuc /*****************************************************************************
195433d6423SLionel Sambuc * usb_handle_msg *
196433d6423SLionel Sambuc ****************************************************************************/
usb_handle_msg(struct usb_driver * ud,message * msg)197433d6423SLionel Sambuc int usb_handle_msg(struct usb_driver *ud, message *msg)
198433d6423SLionel Sambuc {
199433d6423SLionel Sambuc /*
200433d6423SLionel Sambuc * we expect kind of messages:
201433d6423SLionel Sambuc * - new usb device
202433d6423SLionel Sambuc * - removed device
203433d6423SLionel Sambuc * - URB completed
204433d6423SLionel Sambuc *
205433d6423SLionel Sambuc * NOTE: the hcd driver doesn't expect replies for these messages.
206433d6423SLionel Sambuc */
207433d6423SLionel Sambuc
208433d6423SLionel Sambuc if (!ud) {
209433d6423SLionel Sambuc return -1;
210433d6423SLionel Sambuc }
211433d6423SLionel Sambuc
212433d6423SLionel Sambuc switch(msg->m_type) {
213433d6423SLionel Sambuc case USB_COMPLETE_URB:
214*65f76edbSDavid van Moolenbroek _usb_urb_complete(ud, (unsigned int)msg->USB_URB_ID);
215433d6423SLionel Sambuc return 0;
216433d6423SLionel Sambuc case USB_ANNOUCE_DEV:
217433d6423SLionel Sambuc ud->connect_device(msg->USB_DEV_ID, msg->USB_INTERFACES);
218433d6423SLionel Sambuc return 0;
219433d6423SLionel Sambuc case USB_WITHDRAW_DEV:
220433d6423SLionel Sambuc ud->disconnect_device(msg->USB_DEV_ID);
221433d6423SLionel Sambuc return 0;
222433d6423SLionel Sambuc default:
223433d6423SLionel Sambuc panic("usb_handle_msg: bogus message from USB");
224433d6423SLionel Sambuc }
225433d6423SLionel Sambuc }
226433d6423SLionel Sambuc
2272d64210cSWojciech Zajac
2282d64210cSWojciech Zajac /*****************************************************************************
2292d64210cSWojciech Zajac * usb_send_info *
2302d64210cSWojciech Zajac *****************************************************************************/
2312d64210cSWojciech Zajac int
usb_send_info(long info_type,long info_value)2322d64210cSWojciech Zajac usb_send_info(long info_type, long info_value)
2332d64210cSWojciech Zajac {
2342d64210cSWojciech Zajac int res;
2352d64210cSWojciech Zajac message msg;
2362d64210cSWojciech Zajac
2372d64210cSWojciech Zajac /* Prepare message */
2382d64210cSWojciech Zajac msg.m_type = USB_RQ_SEND_INFO;
2392d64210cSWojciech Zajac msg.USB_INFO_TYPE = info_type;
2402d64210cSWojciech Zajac msg.USB_INFO_VALUE = info_value;
2412d64210cSWojciech Zajac
2422d64210cSWojciech Zajac /* Send/receive message */
2432d64210cSWojciech Zajac res = ipc_sendrec(hcd_ep, &msg);
2442d64210cSWojciech Zajac
2452d64210cSWojciech Zajac if (res != 0)
2462d64210cSWojciech Zajac panic("usb_send_info: could not talk to HCD: %d", res);
2472d64210cSWojciech Zajac
2482d64210cSWojciech Zajac if (msg.m_type != USB_REPLY)
2492d64210cSWojciech Zajac panic("usb_send_info: got illegal response from HCD: %d", msg.m_type);
2502d64210cSWojciech Zajac
2512d64210cSWojciech Zajac if (msg.USB_RESULT != 0)
2522d64210cSWojciech Zajac panic("usb_send_info: got illegal response from HCD: %d", msg.m_type);
2532d64210cSWojciech Zajac
2542d64210cSWojciech Zajac return msg.USB_RESULT;
2552d64210cSWojciech Zajac }
256