netbsd_usb.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617
  1. /*
  2. * Copyright © 2011 Martin Pieuchot <mpi@openbsd.org>
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include <config.h>
  19. #include <sys/time.h>
  20. #include <sys/types.h>
  21. #include <errno.h>
  22. #include <fcntl.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <unistd.h>
  27. #include <dev/usb/usb.h>
  28. #include "libusbi.h"
  29. struct device_priv {
  30. char devnode[16];
  31. int fd;
  32. usb_config_descriptor_t *cdesc; /* active config descriptor */
  33. };
  34. struct handle_priv {
  35. int endpoints[USB_MAX_ENDPOINTS];
  36. };
  37. /*
  38. * Backend functions
  39. */
  40. static int netbsd_get_device_list(struct libusb_context *,
  41. struct discovered_devs **);
  42. static int netbsd_open(struct libusb_device_handle *);
  43. static void netbsd_close(struct libusb_device_handle *);
  44. static int netbsd_get_active_config_descriptor(struct libusb_device *,
  45. void *, size_t);
  46. static int netbsd_get_config_descriptor(struct libusb_device *, uint8_t,
  47. void *, size_t);
  48. static int netbsd_get_configuration(struct libusb_device_handle *, uint8_t *);
  49. static int netbsd_set_configuration(struct libusb_device_handle *, int);
  50. static int netbsd_claim_interface(struct libusb_device_handle *, uint8_t);
  51. static int netbsd_release_interface(struct libusb_device_handle *, uint8_t);
  52. static int netbsd_set_interface_altsetting(struct libusb_device_handle *,
  53. uint8_t, uint8_t);
  54. static int netbsd_clear_halt(struct libusb_device_handle *, unsigned char);
  55. static void netbsd_destroy_device(struct libusb_device *);
  56. static int netbsd_submit_transfer(struct usbi_transfer *);
  57. static int netbsd_cancel_transfer(struct usbi_transfer *);
  58. static int netbsd_handle_transfer_completion(struct usbi_transfer *);
  59. /*
  60. * Private functions
  61. */
  62. static int _errno_to_libusb(int);
  63. static int _cache_active_config_descriptor(struct libusb_device *, int);
  64. static int _sync_control_transfer(struct usbi_transfer *);
  65. static int _sync_gen_transfer(struct usbi_transfer *);
  66. static int _access_endpoint(struct libusb_transfer *);
  67. const struct usbi_os_backend usbi_backend = {
  68. .name = "Synchronous NetBSD backend",
  69. .caps = 0,
  70. .get_device_list = netbsd_get_device_list,
  71. .open = netbsd_open,
  72. .close = netbsd_close,
  73. .get_active_config_descriptor = netbsd_get_active_config_descriptor,
  74. .get_config_descriptor = netbsd_get_config_descriptor,
  75. .get_configuration = netbsd_get_configuration,
  76. .set_configuration = netbsd_set_configuration,
  77. .claim_interface = netbsd_claim_interface,
  78. .release_interface = netbsd_release_interface,
  79. .set_interface_altsetting = netbsd_set_interface_altsetting,
  80. .clear_halt = netbsd_clear_halt,
  81. .destroy_device = netbsd_destroy_device,
  82. .submit_transfer = netbsd_submit_transfer,
  83. .cancel_transfer = netbsd_cancel_transfer,
  84. .handle_transfer_completion = netbsd_handle_transfer_completion,
  85. .device_priv_size = sizeof(struct device_priv),
  86. .device_handle_priv_size = sizeof(struct handle_priv),
  87. };
  88. int
  89. netbsd_get_device_list(struct libusb_context * ctx,
  90. struct discovered_devs **discdevs)
  91. {
  92. struct libusb_device *dev;
  93. struct device_priv *dpriv;
  94. struct usb_device_info di;
  95. usb_device_descriptor_t ddesc;
  96. unsigned long session_id;
  97. char devnode[16];
  98. int fd, err, i;
  99. usbi_dbg(ctx, " ");
  100. /* Only ugen(4) is supported */
  101. for (i = 0; i < USB_MAX_DEVICES; i++) {
  102. /* Control endpoint is always .00 */
  103. snprintf(devnode, sizeof(devnode), "/dev/ugen%d.00", i);
  104. if ((fd = open(devnode, O_RDONLY)) < 0) {
  105. if (errno != ENOENT && errno != ENXIO)
  106. usbi_err(ctx, "could not open %s", devnode);
  107. continue;
  108. }
  109. if (ioctl(fd, USB_GET_DEVICEINFO, &di) < 0)
  110. continue;
  111. session_id = (di.udi_bus << 8 | di.udi_addr);
  112. dev = usbi_get_device_by_session_id(ctx, session_id);
  113. if (dev == NULL) {
  114. dev = usbi_alloc_device(ctx, session_id);
  115. if (dev == NULL)
  116. return (LIBUSB_ERROR_NO_MEM);
  117. dev->bus_number = di.udi_bus;
  118. dev->device_address = di.udi_addr;
  119. dev->speed = di.udi_speed;
  120. dpriv = usbi_get_device_priv(dev);
  121. strlcpy(dpriv->devnode, devnode, sizeof(devnode));
  122. dpriv->fd = -1;
  123. if (ioctl(fd, USB_GET_DEVICE_DESC, &ddesc) < 0) {
  124. err = errno;
  125. goto error;
  126. }
  127. static_assert(sizeof(dev->device_descriptor) == sizeof(ddesc),
  128. "mismatch between libusb and OS device descriptor sizes");
  129. memcpy(&dev->device_descriptor, &ddesc, LIBUSB_DT_DEVICE_SIZE);
  130. usbi_localize_device_descriptor(&dev->device_descriptor);
  131. if (_cache_active_config_descriptor(dev, fd)) {
  132. err = errno;
  133. goto error;
  134. }
  135. if ((err = usbi_sanitize_device(dev)))
  136. goto error;
  137. }
  138. close(fd);
  139. if (discovered_devs_append(*discdevs, dev) == NULL)
  140. return (LIBUSB_ERROR_NO_MEM);
  141. libusb_unref_device(dev);
  142. }
  143. return (LIBUSB_SUCCESS);
  144. error:
  145. close(fd);
  146. libusb_unref_device(dev);
  147. return _errno_to_libusb(err);
  148. }
  149. int
  150. netbsd_open(struct libusb_device_handle *handle)
  151. {
  152. struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
  153. struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
  154. int i;
  155. dpriv->fd = open(dpriv->devnode, O_RDWR);
  156. if (dpriv->fd < 0) {
  157. dpriv->fd = open(dpriv->devnode, O_RDONLY);
  158. if (dpriv->fd < 0)
  159. return _errno_to_libusb(errno);
  160. }
  161. for (i = 0; i < USB_MAX_ENDPOINTS; i++)
  162. hpriv->endpoints[i] = -1;
  163. usbi_dbg(HANDLE_CTX(handle), "open %s: fd %d", dpriv->devnode, dpriv->fd);
  164. return (LIBUSB_SUCCESS);
  165. }
  166. void
  167. netbsd_close(struct libusb_device_handle *handle)
  168. {
  169. struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
  170. usbi_dbg(HANDLE_CTX(handle), "close: fd %d", dpriv->fd);
  171. close(dpriv->fd);
  172. dpriv->fd = -1;
  173. }
  174. int
  175. netbsd_get_active_config_descriptor(struct libusb_device *dev,
  176. void *buf, size_t len)
  177. {
  178. struct device_priv *dpriv = usbi_get_device_priv(dev);
  179. len = MIN(len, (size_t)UGETW(dpriv->cdesc->wTotalLength));
  180. usbi_dbg(DEVICE_CTX(dev), "len %zu", len);
  181. memcpy(buf, dpriv->cdesc, len);
  182. return (int)len;
  183. }
  184. int
  185. netbsd_get_config_descriptor(struct libusb_device *dev, uint8_t idx,
  186. void *buf, size_t len)
  187. {
  188. struct device_priv *dpriv = usbi_get_device_priv(dev);
  189. struct usb_full_desc ufd;
  190. int fd, err;
  191. usbi_dbg(DEVICE_CTX(dev), "index %u, len %zu", idx, len);
  192. /* A config descriptor may be requested before opening the device */
  193. if (dpriv->fd >= 0) {
  194. fd = dpriv->fd;
  195. } else {
  196. fd = open(dpriv->devnode, O_RDONLY);
  197. if (fd < 0)
  198. return _errno_to_libusb(errno);
  199. }
  200. ufd.ufd_config_index = idx;
  201. ufd.ufd_size = len;
  202. ufd.ufd_data = buf;
  203. if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
  204. err = errno;
  205. if (dpriv->fd < 0)
  206. close(fd);
  207. return _errno_to_libusb(err);
  208. }
  209. if (dpriv->fd < 0)
  210. close(fd);
  211. return (int)len;
  212. }
  213. int
  214. netbsd_get_configuration(struct libusb_device_handle *handle, uint8_t *config)
  215. {
  216. struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
  217. int tmp;
  218. usbi_dbg(HANDLE_CTX(handle), " ");
  219. if (ioctl(dpriv->fd, USB_GET_CONFIG, &tmp) < 0)
  220. return _errno_to_libusb(errno);
  221. usbi_dbg(HANDLE_CTX(handle), "configuration %d", tmp);
  222. *config = (uint8_t)tmp;
  223. return (LIBUSB_SUCCESS);
  224. }
  225. int
  226. netbsd_set_configuration(struct libusb_device_handle *handle, int config)
  227. {
  228. struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
  229. usbi_dbg(HANDLE_CTX(handle), "configuration %d", config);
  230. if (ioctl(dpriv->fd, USB_SET_CONFIG, &config) < 0)
  231. return _errno_to_libusb(errno);
  232. return _cache_active_config_descriptor(handle->dev, dpriv->fd);
  233. }
  234. int
  235. netbsd_claim_interface(struct libusb_device_handle *handle, uint8_t iface)
  236. {
  237. struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
  238. int i;
  239. UNUSED(iface);
  240. for (i = 0; i < USB_MAX_ENDPOINTS; i++)
  241. hpriv->endpoints[i] = -1;
  242. return (LIBUSB_SUCCESS);
  243. }
  244. int
  245. netbsd_release_interface(struct libusb_device_handle *handle, uint8_t iface)
  246. {
  247. struct handle_priv *hpriv = usbi_get_device_handle_priv(handle);
  248. int i;
  249. UNUSED(iface);
  250. for (i = 0; i < USB_MAX_ENDPOINTS; i++)
  251. if (hpriv->endpoints[i] >= 0)
  252. close(hpriv->endpoints[i]);
  253. return (LIBUSB_SUCCESS);
  254. }
  255. int
  256. netbsd_set_interface_altsetting(struct libusb_device_handle *handle, uint8_t iface,
  257. uint8_t altsetting)
  258. {
  259. struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
  260. struct usb_alt_interface intf;
  261. usbi_dbg(HANDLE_CTX(handle), "iface %u, setting %u", iface, altsetting);
  262. memset(&intf, 0, sizeof(intf));
  263. intf.uai_interface_index = iface;
  264. intf.uai_alt_no = altsetting;
  265. if (ioctl(dpriv->fd, USB_SET_ALTINTERFACE, &intf) < 0)
  266. return _errno_to_libusb(errno);
  267. return (LIBUSB_SUCCESS);
  268. }
  269. int
  270. netbsd_clear_halt(struct libusb_device_handle *handle, unsigned char endpoint)
  271. {
  272. struct device_priv *dpriv = usbi_get_device_priv(handle->dev);
  273. struct usb_ctl_request req;
  274. usbi_dbg(HANDLE_CTX(handle), " ");
  275. req.ucr_request.bmRequestType = UT_WRITE_ENDPOINT;
  276. req.ucr_request.bRequest = UR_CLEAR_FEATURE;
  277. USETW(req.ucr_request.wValue, UF_ENDPOINT_HALT);
  278. USETW(req.ucr_request.wIndex, endpoint);
  279. USETW(req.ucr_request.wLength, 0);
  280. if (ioctl(dpriv->fd, USB_DO_REQUEST, &req) < 0)
  281. return _errno_to_libusb(errno);
  282. return (LIBUSB_SUCCESS);
  283. }
  284. void
  285. netbsd_destroy_device(struct libusb_device *dev)
  286. {
  287. struct device_priv *dpriv = usbi_get_device_priv(dev);
  288. usbi_dbg(DEVICE_CTX(dev), " ");
  289. free(dpriv->cdesc);
  290. }
  291. int
  292. netbsd_submit_transfer(struct usbi_transfer *itransfer)
  293. {
  294. struct libusb_transfer *transfer;
  295. int err = 0;
  296. usbi_dbg(ITRANSFER_CTX(itransfer), " ");
  297. transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
  298. switch (transfer->type) {
  299. case LIBUSB_TRANSFER_TYPE_CONTROL:
  300. err = _sync_control_transfer(itransfer);
  301. break;
  302. case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
  303. if (IS_XFEROUT(transfer)) {
  304. /* Isochronous write is not supported */
  305. err = LIBUSB_ERROR_NOT_SUPPORTED;
  306. break;
  307. }
  308. err = _sync_gen_transfer(itransfer);
  309. break;
  310. case LIBUSB_TRANSFER_TYPE_BULK:
  311. case LIBUSB_TRANSFER_TYPE_INTERRUPT:
  312. if (IS_XFEROUT(transfer) &&
  313. transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) {
  314. err = LIBUSB_ERROR_NOT_SUPPORTED;
  315. break;
  316. }
  317. err = _sync_gen_transfer(itransfer);
  318. break;
  319. case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
  320. err = LIBUSB_ERROR_NOT_SUPPORTED;
  321. break;
  322. }
  323. if (err)
  324. return (err);
  325. usbi_signal_transfer_completion(itransfer);
  326. return (LIBUSB_SUCCESS);
  327. }
  328. int
  329. netbsd_cancel_transfer(struct usbi_transfer *itransfer)
  330. {
  331. UNUSED(itransfer);
  332. usbi_dbg(ITRANSFER_CTX(itransfer), " ");
  333. return (LIBUSB_ERROR_NOT_SUPPORTED);
  334. }
  335. int
  336. netbsd_handle_transfer_completion(struct usbi_transfer *itransfer)
  337. {
  338. return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_COMPLETED);
  339. }
  340. int
  341. _errno_to_libusb(int err)
  342. {
  343. switch (err) {
  344. case EIO:
  345. return (LIBUSB_ERROR_IO);
  346. case EACCES:
  347. return (LIBUSB_ERROR_ACCESS);
  348. case ENOENT:
  349. return (LIBUSB_ERROR_NO_DEVICE);
  350. case ENOMEM:
  351. return (LIBUSB_ERROR_NO_MEM);
  352. case EWOULDBLOCK:
  353. case ETIMEDOUT:
  354. return (LIBUSB_ERROR_TIMEOUT);
  355. }
  356. usbi_dbg(NULL, "error: %s", strerror(err));
  357. return (LIBUSB_ERROR_OTHER);
  358. }
  359. int
  360. _cache_active_config_descriptor(struct libusb_device *dev, int fd)
  361. {
  362. struct device_priv *dpriv = usbi_get_device_priv(dev);
  363. struct usb_config_desc ucd;
  364. struct usb_full_desc ufd;
  365. void *buf;
  366. int len;
  367. usbi_dbg(DEVICE_CTX(dev), "fd %d", fd);
  368. ucd.ucd_config_index = USB_CURRENT_CONFIG_INDEX;
  369. if ((ioctl(fd, USB_GET_CONFIG_DESC, &ucd)) < 0)
  370. return _errno_to_libusb(errno);
  371. usbi_dbg(DEVICE_CTX(dev), "active bLength %d", ucd.ucd_desc.bLength);
  372. len = UGETW(ucd.ucd_desc.wTotalLength);
  373. buf = malloc((size_t)len);
  374. if (buf == NULL)
  375. return (LIBUSB_ERROR_NO_MEM);
  376. ufd.ufd_config_index = ucd.ucd_config_index;
  377. ufd.ufd_size = len;
  378. ufd.ufd_data = buf;
  379. usbi_dbg(DEVICE_CTX(dev), "index %d, len %d", ufd.ufd_config_index, len);
  380. if ((ioctl(fd, USB_GET_FULL_DESC, &ufd)) < 0) {
  381. free(buf);
  382. return _errno_to_libusb(errno);
  383. }
  384. if (dpriv->cdesc)
  385. free(dpriv->cdesc);
  386. dpriv->cdesc = buf;
  387. return (0);
  388. }
  389. int
  390. _sync_control_transfer(struct usbi_transfer *itransfer)
  391. {
  392. struct libusb_transfer *transfer;
  393. struct libusb_control_setup *setup;
  394. struct device_priv *dpriv;
  395. struct usb_ctl_request req;
  396. transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
  397. dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
  398. setup = (struct libusb_control_setup *)transfer->buffer;
  399. usbi_dbg(ITRANSFER_CTX(itransfer), "type %d request %d value %d index %d length %d timeout %d",
  400. setup->bmRequestType, setup->bRequest,
  401. libusb_le16_to_cpu(setup->wValue),
  402. libusb_le16_to_cpu(setup->wIndex),
  403. libusb_le16_to_cpu(setup->wLength), transfer->timeout);
  404. req.ucr_request.bmRequestType = setup->bmRequestType;
  405. req.ucr_request.bRequest = setup->bRequest;
  406. /* Don't use USETW, libusb already deals with the endianness */
  407. (*(uint16_t *)req.ucr_request.wValue) = setup->wValue;
  408. (*(uint16_t *)req.ucr_request.wIndex) = setup->wIndex;
  409. (*(uint16_t *)req.ucr_request.wLength) = setup->wLength;
  410. req.ucr_data = transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE;
  411. if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
  412. req.ucr_flags = USBD_SHORT_XFER_OK;
  413. if ((ioctl(dpriv->fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
  414. return _errno_to_libusb(errno);
  415. if ((ioctl(dpriv->fd, USB_DO_REQUEST, &req)) < 0)
  416. return _errno_to_libusb(errno);
  417. itransfer->transferred = req.ucr_actlen;
  418. usbi_dbg(ITRANSFER_CTX(itransfer), "transferred %d", itransfer->transferred);
  419. return (0);
  420. }
  421. int
  422. _access_endpoint(struct libusb_transfer *transfer)
  423. {
  424. struct handle_priv *hpriv;
  425. struct device_priv *dpriv;
  426. char *s, devnode[16];
  427. int fd, endpt;
  428. mode_t mode;
  429. hpriv = usbi_get_device_handle_priv(transfer->dev_handle);
  430. dpriv = usbi_get_device_priv(transfer->dev_handle->dev);
  431. endpt = UE_GET_ADDR(transfer->endpoint);
  432. mode = IS_XFERIN(transfer) ? O_RDONLY : O_WRONLY;
  433. usbi_dbg(TRANSFER_CTX(transfer), "endpoint %d mode %d", endpt, mode);
  434. if (hpriv->endpoints[endpt] < 0) {
  435. /* Pick the right node given the control one */
  436. strlcpy(devnode, dpriv->devnode, sizeof(devnode));
  437. s = strchr(devnode, '.');
  438. snprintf(s, 4, ".%02d", endpt);
  439. /* We may need to read/write to the same endpoint later. */
  440. if (((fd = open(devnode, O_RDWR)) < 0) && (errno == ENXIO))
  441. if ((fd = open(devnode, mode)) < 0)
  442. return (-1);
  443. hpriv->endpoints[endpt] = fd;
  444. }
  445. return (hpriv->endpoints[endpt]);
  446. }
  447. int
  448. _sync_gen_transfer(struct usbi_transfer *itransfer)
  449. {
  450. struct libusb_transfer *transfer;
  451. int fd, nr = 1;
  452. transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
  453. /*
  454. * Bulk, Interrupt or Isochronous transfer depends on the
  455. * endpoint and thus the node to open.
  456. */
  457. if ((fd = _access_endpoint(transfer)) < 0)
  458. return _errno_to_libusb(errno);
  459. if ((ioctl(fd, USB_SET_TIMEOUT, &transfer->timeout)) < 0)
  460. return _errno_to_libusb(errno);
  461. if (IS_XFERIN(transfer)) {
  462. if ((transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) == 0)
  463. if ((ioctl(fd, USB_SET_SHORT_XFER, &nr)) < 0)
  464. return _errno_to_libusb(errno);
  465. nr = read(fd, transfer->buffer, transfer->length);
  466. } else {
  467. nr = write(fd, transfer->buffer, transfer->length);
  468. }
  469. if (nr < 0)
  470. return _errno_to_libusb(errno);
  471. itransfer->transferred = nr;
  472. return (0);
  473. }