Mistake on this page?
Report an issue in GitHub or email us
USBDevice.h
1 /*
2  * Copyright (c) 2018-2019, Arm Limited and affiliates.
3  * SPDX-License-Identifier: Apache-2.0
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #ifndef USBDEVICE_H
19 #define USBDEVICE_H
20 
21 #include <stddef.h>
22 #include "USBDevice_Types.h"
23 #include "USBPhy.h"
24 #include "mbed_critical.h"
25 
26 /**
27  * \defgroup usb_device USB Device
28  *
29  */
30 
31 /**
32  * \defgroup usb_device_core Core
33  *
34  * @ingroup usb_device
35  */
36 
37 /**
38  * Core USB Device driver
39  *
40  * USB driver which wraps and provides synchronization for a USBPhy object.
41  *
42  * @ingroup usb_device_core
43  */
44 class USBDevice: public USBPhyEvents {
45 public:
46  typedef void (USBDevice::*ep_cb_t)();
47 
48  enum RequestResult {
49  Receive = 0,
50  Send = 1,
51  Success = 2,
52  Failure = 3,
53  PassThrough = 4,
54  };
55 
56  enum DeviceState {
57  Attached,
58  Powered,
59  Default,
60  Address,
61  Configured
62  };
63 
64  struct setup_packet_t {
65  struct {
66  uint8_t dataTransferDirection;
67  uint8_t Type;
68  uint8_t Recipient;
69  } bmRequestType;
70  uint8_t bRequest;
71  uint16_t wValue;
72  uint16_t wIndex;
73  uint16_t wLength;
74  };
75 
76  /**
77  * Instantiate a new USBDevice with the given parameters
78  *
79  * @param phy The USBPhy providing physical USB access
80  * @param vendor_id The USB vendor ID
81  * @param product_id The USB product ID
82  * @param product_release The device release number
83  */
84  USBDevice(USBPhy *phy, uint16_t vendor_id, uint16_t product_id, uint16_t product_release);
85 
86  /**
87  * Cleanup this USBDevice
88  *
89  * This USBDevice must be uninitialized when the destructor is
90  * called or the behavior is undefined.
91  */
92  virtual ~USBDevice();
93 
94  /**
95  * Initialize this instance
96  *
97  * This function must be called before calling
98  * any other functions of this class, unless specifically
99  */
100  void init();
101 
102  /**
103  * Power down this instance
104  *
105  * Disable interrupts and stop sending events.
106  */
107  void deinit();
108 
109  /**
110  * Check if the device is configured
111  *
112  * @returns true if configured, false otherwise
113  */
114  bool configured();
115 
116  /**
117  * Connect a device
118  */
119  void connect();
120 
121  /**
122  * Disconnect a device
123  */
124  void disconnect();
125 
126  /**
127  * Enable the start of frame interrupt
128  *
129  * Call USBDevice::callback_sof on every frame.
130  */
131  void sof_enable();
132 
133  /**
134  * Disable the start of frame interrupt
135  *
136  * Stop calling USBDevice::callback_sof.
137  */
138  void sof_disable();
139 
140  /**
141  * Add an endpoint
142  *
143  * @param endpoint Endpoint to enable
144  * @param max_packet Maximum size of a packet which can be sent or received on this endpoint
145  * @param type Endpoint type - USB_EP_TYPE_BULK, USB_EP_TYPE_INT or USB_EP_TYPE_ISO
146  * @param callback Method pointer to be called when a packet is transferred
147  * @returns true if successful, false otherwise
148  */
149  bool endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type, ep_cb_t callback = NULL);
150 
151  /**
152  * Add an endpoint
153  *
154  * @param endpoint Endpoint to enable
155  * @param max_packet Maximum size of a packet which can be sent or received on this endpoint
156  * @param type Endpoint type - USB_EP_TYPE_BULK, USB_EP_TYPE_INT or USB_EP_TYPE_ISO
157  * @param callback Method pointer to be called when a packet is transferred
158  * @returns true if successful, false otherwise
159  */
160  template<typename T>
161  bool endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type, void (T::*callback)())
162  {
163  return endpoint_add(endpoint, max_packet, type, static_cast<ep_cb_t>(callback));
164  }
165 
166  /**
167  * Remove an endpoint
168  *
169  * @param endpoint Endpoint to disable
170  * @note This endpoint must already have been setup with endpoint_add
171  */
172  void endpoint_remove(usb_ep_t endpoint);
173 
174  /**
175  * Remove all non-zero endpoints
176  */
177  void endpoint_remove_all();
178 
179  /**
180  * Stall an endpoint
181  *
182  * If there is an ongoing transfer on this endpoint then it will
183  * be aborted.
184  *
185  * @param endpoint Endpoint to stall
186  * @note You cannot stall endpoint 0 with this function
187  * @note This endpoint must already have been setup with endpoint_add
188  */
189  void endpoint_stall(usb_ep_t endpoint);
190 
191  /**
192  * Unstall an endpoint
193  *
194  * Unstalling an endpoint resets data toggle back to DATA0.
195  * Additionally, if there is an ongoing transfer on this endpoint
196  * it will be aborted.
197  *
198  * @param endpoint Endpoint to unstall
199  * @note This endpoint must already have been setup with endpoint_add
200  */
201  void endpoint_unstall(usb_ep_t endpoint);
202 
203  /**
204  * Get the current maximum size for this endpoint
205  *
206  * Return the currently configured maximum packet size, wMaxPacketSize,
207  * for this endpoint.
208  * @note This endpoint must already have been setup with endpoint_add
209  */
210  uint32_t endpoint_max_packet_size(usb_ep_t endpoint);
211 
212  /**
213  * Abort the current transfer on this endpoint
214  *
215  * @param endpoint endpoint with transfer to abort
216  * @note This endpoint must already have been setup with endpoint_add
217  */
218  void endpoint_abort(usb_ep_t endpoint);
219 
220  /**
221  * start a read on the given endpoint
222  *
223  * Start a read on the given endpoint. The data buffer must remain
224  * unchanged until the transfer either completes or is aborted.
225  *
226  * @param endpoint endpoint to read data from
227  * @param buffer buffer to fill with read data
228  * @param size The size of data to read. This must be greater than or equal
229  * to the max packet size for this endpoint
230  * @return true if the read was completed, otherwise false
231  * @note This endpoint must already have been setup with endpoint_add
232  */
233  bool read_start(usb_ep_t endpoint, uint8_t *buffer, uint32_t size);
234 
235  /**
236  * Get the status of a read
237  *
238  * @param endpoint endpoint to get the status of
239  * @return number of bytes read by this endpoint
240  */
241  uint32_t read_finish(usb_ep_t endpoint);
242 
243  /**
244  * Write a data to the given endpoint
245  *
246  * Write data to an endpoint. The data sent must remain unchanged until
247  * the transfer either completes or is aborted.
248  *
249  * @param endpoint endpoint to write data to
250  * @param buffer data to write
251  * @param size the size of data to send. This must be less than or equal to the
252  * max packet size of this endpoint
253  * @note This endpoint must already have been setup with endpoint_add
254  */
255  bool write_start(usb_ep_t endpoint, uint8_t *buffer, uint32_t size);
256 
257  /**
258  * Get the status of a write
259  *
260  * @param endpoint endpoint to get the status of
261  * @return number of bytes sent by this endpoint
262  */
263  uint32_t write_finish(usb_ep_t endpoint);
264 
265  /*
266  * Get device descriptor.
267  *
268  * @returns pointer to the device descriptor
269  */
270  virtual const uint8_t *device_desc();
271 
272  /*
273  * Get configuration descriptor
274  *
275  * @param index descriptor index
276  * @returns pointer to the configuration descriptor
277  */
278  virtual const uint8_t *configuration_desc(uint8_t index) = 0;
279 
280  /*
281  * Get string lang id descriptor
282  *
283  * @return pointer to the string lang id descriptor
284  */
285  virtual const uint8_t *string_langid_desc();
286 
287  /*
288  * Get string manufacturer descriptor
289  *
290  * @returns pointer to the string manufacturer descriptor
291  */
292  virtual const uint8_t *string_imanufacturer_desc();
293 
294  /*
295  * Get string product descriptor
296  *
297  * @returns pointer to the string product descriptor
298  */
299  virtual const uint8_t *string_iproduct_desc();
300 
301  /*
302  * Get string serial descriptor
303  *
304  * @returns pointer to the string serial descriptor
305  */
306  virtual const uint8_t *string_iserial_desc();
307 
308  /*
309  * Get string configuration descriptor
310  *
311  * @returns pointer to the string configuration descriptor
312  */
313  virtual const uint8_t *string_iconfiguration_desc();
314 
315  /*
316  * Get string interface descriptor
317  *
318  * @returns pointer to the string interface descriptor
319  */
320  virtual const uint8_t *string_iinterface_desc();
321 
322  /*
323  * Get the length of the report descriptor
324  *
325  * @returns length of the report descriptor
326  */
327  virtual uint16_t report_desc_dength()
328  {
329  return 0;
330  };
331 
332 protected:
333 
334  /**
335  * Called by USBDevice layer on power state change.
336  *
337  * @param powered true if device is powered, false otherwise
338  *
339  * Warning: Called in ISR context
340  */
341  virtual void callback_power(bool powered)
342  {
343 
344  }
345 
346  /**
347  * Called by USBDevice layer on each new USB frame.
348  *
349  * Callbacks are enabled and disabled by calling sof_enable
350  * and sof_disable.
351  *
352  * @param frame_number The current frame number
353  *
354  * Warning: Called in ISR context
355  */
356  virtual void callback_sof(int frame_number)
357  {
358 
359  }
360 
361  /**
362  * Called by USBDevice layer on bus reset.
363  *
364  * complete_reset must be called after
365  * the device is fully reset.
366  *
367  * Warning: Called in ISR context
368  */
369  virtual void callback_reset()
370  {
371 
372  }
373 
374  /**
375  * Called when USB changes state
376  *
377  * @param new_state The new state of the USBDevice
378  *
379  * Warning: Called in ISR context
380  */
381  virtual void callback_state_change(DeviceState new_state) = 0;
382 
383  /**
384  * Called by USBDevice on Endpoint0 request.
385  *
386  * This is used to handle extensions to standard requests
387  * and class specific requests. The function complete_request
388  * must be always be called in response to this callback.
389  *
390  * Warning: Called in ISR context
391  */
392  virtual void callback_request(const setup_packet_t *setup) = 0;
393 
394  /**
395  * Called to complete the setup stage of a callback request
396  *
397  * Possible options that can be passed as a result are:
398  * - Receive - Start the data OUT phase of this control transfer
399  * - Send - Start the data IN phase of this control transfer
400  * - Success - Operation was a success so start the status phase
401  * - Failure - Operation failed or is unsupported so send a stall
402  * - PassThrough - Pass on the request for standard processing
403  *
404  * @param result The result of the setup phase.
405  * @param data Buffer to send or receive if the result is Send or Receive
406  * @param size Size to transfer if the result is Send or Receive
407  */
408  void complete_request(RequestResult result, uint8_t *data = NULL, uint32_t size = 0);
409 
410  /**
411  * Called by USBDevice on data stage completion
412  *
413  * The function complete_request_xfer_done must be always be called
414  * in response to this callback.
415  *
416  * @param setup Setup packet of the current request
417  * @param aborted false if the operation was aborted, true otherwise
418  *
419  * Warning: Called in ISR context
420  */
421  virtual void callback_request_xfer_done(const setup_packet_t *setup, bool aborted) = 0;
422 
423  /**
424  * Called to complete the data stage of a callback request
425  *
426  * @param success true if the operation was successful, false otherwise
427  */
428  void complete_request_xfer_done(bool success);
429 
430  /*
431  * Called by USBDevice layer in response to set_configuration.
432  *
433  * Upon reception of this command endpoints of the previous configuration
434  * if any must be removed with endpoint_remove and new endpoint added with
435  * endpoint_add.
436  *
437  * @param configuration Number of the configuration
438  *
439  * Warning: Called in ISR context
440  */
441  virtual void callback_set_configuration(uint8_t configuration) = 0;
442 
443  /**
444  * Called to complete a set configuration command
445  *
446  * @param success true if the configuration was set, false otherwise
447  */
448  void complete_set_configuration(bool success);
449 
450  /*
451  * Called by USBDevice layer in response to set_interface.
452  *
453  * Upon reception of this command endpoints of any previous interface
454  * if any must be removed with endpoint_remove and new endpoint added with
455  * endpoint_add.
456  *
457  * @param configuration Number of the configuration
458  *
459  * Warning: Called in ISR context
460  */
461  virtual void callback_set_interface(uint16_t interface, uint8_t alternate) = 0;
462 
463  /**
464  * Called to complete a set interface command
465  *
466  * @param success true if the interface was set, false otherwise
467  */
468  void complete_set_interface(bool success);
469 
470  /**
471  * Find a descriptor type inside the configuration descriptor
472  *
473  * @param descriptor_type Type of descriptor to find
474  * @param index Configuration descriptor index ( 0 if only one configuration present )
475  * @return A descriptor of the given type or NULL if none were found
476  */
477  uint8_t *find_descriptor(uint8_t descriptor_type, uint8_t index = 0);
478 
479  /**
480  * Get the endpoint table of this device
481  *
482  * @return Endpoint table of the USBPhy attached to this USBDevice
483  */
485 
486  /**
487  * Callback called to indicate the USB processing needs to be done
488  */
489  virtual void start_process();
490 
491  /**
492  * Acquire exclusive access to this instance USBDevice
493  */
494  virtual void lock();
495 
496  /**
497  * Release exclusive access to this instance USBDevice
498  */
499  virtual void unlock();
500 
501  /**
502  * Assert that the current thread of execution holds the lock
503  *
504  */
505  virtual void assert_locked();
506 
507  uint16_t vendor_id;
508  uint16_t product_id;
509  uint16_t product_release;
510  uint8_t device_descriptor[18];
511 
512 private:
513  // USBPhyEvents
514  virtual void power(bool powered);
515  virtual void suspend(bool suspended);
516  virtual void sof(int frame_number);
517  virtual void reset();
518  virtual void ep0_setup();
519  virtual void ep0_out();
520  virtual void ep0_in();
521  virtual void out(usb_ep_t endpoint);
522  virtual void in(usb_ep_t endpoint);
523 
524  bool _request_get_descriptor();
525  bool _control_out();
526  bool _control_in();
527  bool _request_set_address();
528  bool _request_set_configuration();
529  bool _request_set_feature();
530  bool _request_clear_feature();
531  bool _request_get_status();
532  bool _request_setup();
533  void _control_setup();
534  void _control_abort();
535  void _control_abort_start();
536  void _control_setup_continue();
537  void _decode_setup_packet(uint8_t *data, setup_packet_t *packet);
538  bool _request_get_configuration();
539  bool _request_get_interface();
540  bool _request_set_interface();
541  void _change_state(DeviceState state);
542  void _run_later(void (USBDevice::*function)());
543 
544  void _complete_request();
545  void _complete_request_xfer_done();
546  void _complete_set_configuration();
547  void _complete_set_interface();
548 
549  struct endpoint_info_t {
550  ep_cb_t callback;
551  uint16_t max_packet_size;
552  uint16_t transfer_size;
553  uint8_t flags;
554  uint8_t pending;
555  };
556 
557  struct usb_device_t {
558  volatile DeviceState state;
559  uint8_t configuration;
560  bool suspended;
561  };
562 
563  enum ControlState {
564  Setup,
565  DataOut,
566  DataIn,
567  Status
568  };
569 
570  enum UserCallback {
571  None,
572  Request,
573  RequestXferDone,
574  SetConfiguration,
575  SetInterface
576  };
577 
578  struct complete_request_t {
579  RequestResult result;
580  uint8_t *data;
581  uint32_t size;
582  };
583 
584  union complete_args_t {
585  complete_request_t request;
586  bool status;
587  };
588 
589  struct control_transfer_t {
590  setup_packet_t setup;
591  uint8_t *ptr;
592  uint32_t remaining;
593  uint8_t direction;
594  bool zlp;
595  bool notify;
596  ControlState stage;
597  UserCallback user_callback;
598  complete_args_t args;
599  };
600 
601  endpoint_info_t _endpoint_info[32 - 2];
602 
603  USBPhy *_phy;
604  bool _initialized;
605  bool _connected;
606  bool _endpoint_add_remove_allowed;
607  control_transfer_t _transfer;
608  usb_device_t _device;
609  uint32_t _max_packet_size_ep0;
610  void (USBDevice::*_post_process)();
611 
612  bool _setup_ready;
613  bool _abort_control;
614 
615  uint16_t _current_interface;
616  uint8_t _current_alternate;
617  uint32_t _locked;
618 };
619 
620 #endif
void complete_request(RequestResult result, uint8_t *data=NULL, uint32_t size=0)
Called to complete the setup stage of a callback request.
void sof_enable()
Enable the start of frame interrupt.
void endpoint_remove_all()
Remove all non-zero endpoints.
void deinit()
Power down this instance.
void complete_request_xfer_done(bool success)
Called to complete the data stage of a callback request.
void endpoint_stall(usb_ep_t endpoint)
Stall an endpoint.
void disconnect()
Disconnect a device.
bool endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type, ep_cb_t callback=NULL)
Add an endpoint.
void endpoint_remove(usb_ep_t endpoint)
Remove an endpoint.
uint32_t read_finish(usb_ep_t endpoint)
Get the status of a read.
virtual void callback_power(bool powered)
Called by USBDevice layer on power state change.
Definition: USBDevice.h:341
uint8_t * find_descriptor(uint8_t descriptor_type, uint8_t index=0)
Find a descriptor type inside the configuration descriptor.
virtual void callback_request_xfer_done(const setup_packet_t *setup, bool aborted)=0
Called by USBDevice on data stage completion.
void connect()
Connect a device.
Abstract interface to physical USB hardware.
Definition: USBPhy.h:82
virtual void callback_reset()
Called by USBDevice layer on bus reset.
Definition: USBDevice.h:369
Callback< R()> callback(R(*func)()=0)
Create a callback class with type inferred from the arguments.
Definition: Callback.h:3848
void endpoint_unstall(usb_ep_t endpoint)
Unstall an endpoint.
void complete_set_configuration(bool success)
Called to complete a set configuration command.
virtual void callback_request(const setup_packet_t *setup)=0
Called by USBDevice on Endpoint0 request.
virtual void callback_state_change(DeviceState new_state)=0
Called when USB changes state.
bool read_start(usb_ep_t endpoint, uint8_t *buffer, uint32_t size)
start a read on the given endpoint
void sof_disable()
Disable the start of frame interrupt.
virtual void lock()
Acquire exclusive access to this instance USBDevice.
Core USB Device driver.
Definition: USBDevice.h:44
const usb_ep_table_t * endpoint_table()
Get the endpoint table of this device.
virtual void start_process()
Callback called to indicate the USB processing needs to be done.
uint32_t endpoint_max_packet_size(usb_ep_t endpoint)
Get the current maximum size for this endpoint.
virtual void unlock()
Release exclusive access to this instance USBDevice.
void init()
Initialize this instance.
bool write_start(usb_ep_t endpoint, uint8_t *buffer, uint32_t size)
Write a data to the given endpoint.
virtual ~USBDevice()
Cleanup this USBDevice.
void endpoint_abort(usb_ep_t endpoint)
Abort the current transfer on this endpoint.
USBDevice(USBPhy *phy, uint16_t vendor_id, uint16_t product_id, uint16_t product_release)
Instantiate a new USBDevice with the given parameters.
bool configured()
Check if the device is configured.
void complete_set_interface(bool success)
Called to complete a set interface command.
virtual void callback_sof(int frame_number)
Called by USBDevice layer on each new USB frame.
Definition: USBDevice.h:356
Event handler for USBPhy.
Definition: USBPhyEvents.h:31
virtual void assert_locked()
Assert that the current thread of execution holds the lock.
uint32_t write_finish(usb_ep_t endpoint)
Get the status of a write.
bool endpoint_add(usb_ep_t endpoint, uint32_t max_packet, usb_ep_type_t type, void(T::*callback)())
Add an endpoint.
Definition: USBDevice.h:161
Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.