usb_dfu_rt.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /*
  2. * usb_dfu_rt.c
  3. *
  4. * Copyright (C) 2019 Sylvain Munaut
  5. * All rights reserved.
  6. *
  7. * LGPL v3+, see LICENSE.lgpl3
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation; either
  12. * version 3 of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public License
  20. * along with this program; if not, write to the Free Software Foundation,
  21. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22. */
  23. #include <stdint.h>
  24. #include <stdbool.h>
  25. #include <string.h>
  26. #include "usb.h"
  27. #include "usb_dfu_rt.h"
  28. #include "usb_dfu_proto.h"
  29. #define DFU_POLL_MS 250
  30. static int g_dfu_rt_intf;
  31. static bool
  32. _dfu_detach_done_cb(struct usb_xfer *xfer)
  33. {
  34. usb_dfu_rt_cb_reboot();
  35. return true;
  36. }
  37. static enum usb_fnd_resp
  38. _dfu_ctrl_req(struct usb_ctrl_req *req, struct usb_xfer *xfer)
  39. {
  40. /* If this a class request for DFU interface ? */
  41. if ((USB_REQ_TYPE(req) | USB_REQ_RCPT(req)) != (USB_REQ_TYPE_CLASS | USB_REQ_RCPT_INTF))
  42. return USB_FND_CONTINUE;
  43. if (req->wIndex != g_dfu_rt_intf)
  44. return USB_FND_CONTINUE;
  45. /* Handle request */
  46. switch (req->wRequestAndType)
  47. {
  48. case USB_RT_DFU_DETACH:
  49. xfer->cb_done = _dfu_detach_done_cb;
  50. break;
  51. case USB_RT_DFU_GETSTATUS:
  52. /* Return data */
  53. xfer->data[0] = OK;
  54. xfer->data[1] = (DFU_POLL_MS >> 0) & 0xff;
  55. xfer->data[2] = (DFU_POLL_MS >> 8) & 0xff;
  56. xfer->data[3] = (DFU_POLL_MS >> 16) & 0xff;
  57. xfer->data[4] = appIDLE;
  58. xfer->data[5] = 0;
  59. break;
  60. case USB_RT_DFU_GETSTATE:
  61. /* Return state */
  62. xfer->data[0] = appIDLE;
  63. break;
  64. default:
  65. return USB_FND_ERROR;
  66. }
  67. return USB_FND_SUCCESS;
  68. }
  69. static enum usb_fnd_resp
  70. _dfu_set_intf(const struct usb_intf_desc *base, const struct usb_intf_desc *sel)
  71. {
  72. if ((sel->bInterfaceClass != 0xfe) ||
  73. (sel->bInterfaceSubClass != 0x01) ||
  74. (sel->bInterfaceProtocol != 0x01))
  75. return USB_FND_CONTINUE;
  76. g_dfu_rt_intf = base->bInterfaceNumber;
  77. return USB_FND_SUCCESS;
  78. }
  79. static struct usb_fn_drv _dfu_rt_drv = {
  80. .ctrl_req = _dfu_ctrl_req,
  81. .set_intf = _dfu_set_intf,
  82. };
  83. void __attribute__((weak))
  84. usb_dfu_rt_cb_reboot(void)
  85. {
  86. /* Nothing */
  87. }
  88. void
  89. usb_dfu_rt_init(void)
  90. {
  91. usb_register_function_driver(&_dfu_rt_drv);
  92. g_dfu_rt_intf = -1;
  93. }