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, long 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, long 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 %ld", urb_id); 190 } 191 } 192 193 /***************************************************************************** 194 * usb_handle_msg * 195 ****************************************************************************/ 196 int usb_handle_msg(struct usb_driver *ud, message *msg) 197 { 198 /* 199 * we expect kind of messages: 200 * - new usb device 201 * - removed device 202 * - URB completed 203 * 204 * NOTE: the hcd driver doesn't expect replies for these messages. 205 */ 206 207 if (!ud) { 208 return -1; 209 } 210 211 switch(msg->m_type) { 212 case USB_COMPLETE_URB: 213 _usb_urb_complete(ud, msg->USB_URB_ID); 214 return 0; 215 case USB_ANNOUCE_DEV: 216 ud->connect_device(msg->USB_DEV_ID, msg->USB_INTERFACES); 217 return 0; 218 case USB_WITHDRAW_DEV: 219 ud->disconnect_device(msg->USB_DEV_ID); 220 return 0; 221 default: 222 panic("usb_handle_msg: bogus message from USB"); 223 } 224 } 225 226