usbhost_hidkbd.c 79 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592
  1. /****************************************************************************
  2. * drivers/usbhost/usbhost_hidkbd.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /****************************************************************************
  21. * Included Files
  22. ****************************************************************************/
  23. #include <nuttx/config.h>
  24. #include <sys/types.h>
  25. #include <stdbool.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <unistd.h>
  29. #include <string.h>
  30. #include <poll.h>
  31. #include <signal.h>
  32. #include <time.h>
  33. #include <fcntl.h>
  34. #include <assert.h>
  35. #include <errno.h>
  36. #include <debug.h>
  37. #include <nuttx/irq.h>
  38. #include <nuttx/kmalloc.h>
  39. #include <nuttx/kthread.h>
  40. #include <nuttx/arch.h>
  41. #include <nuttx/wqueue.h>
  42. #include <nuttx/signal.h>
  43. #include <nuttx/semaphore.h>
  44. #include <nuttx/fs/fs.h>
  45. #include <nuttx/usb/usb.h>
  46. #include <nuttx/usb/usbhost.h>
  47. #include <nuttx/usb/hid.h>
  48. #include <nuttx/usb/usbhost_devaddr.h>
  49. #ifdef CONFIG_HIDKBD_ENCODED
  50. # include <nuttx/streams.h>
  51. # include <nuttx/input/kbd_codec.h>
  52. #endif
  53. /* Don't compile if prerequisites are not met */
  54. #if defined(CONFIG_USBHOST) && !defined(CONFIG_USBHOST_INT_DISABLE)
  55. /****************************************************************************
  56. * Pre-processor Definitions
  57. ****************************************************************************/
  58. /* Configuration ************************************************************/
  59. /* This determines how often the USB keyboard will be polled in units of
  60. * of microseconds. The default is 100MS.
  61. */
  62. #ifndef CONFIG_HIDKBD_POLLUSEC
  63. # define CONFIG_HIDKBD_POLLUSEC (100*1000)
  64. #endif
  65. /* Worker thread is needed, unfortunately, to handle some cornercase failure
  66. * conditions. This is kind of wasteful and begs for a re-design.
  67. */
  68. #ifndef CONFIG_SCHED_WORKQUEUE
  69. # warning "Worker thread support is required (CONFIG_SCHED_WORKQUEUE)"
  70. #endif
  71. /* Provide some default values for other configuration settings */
  72. #ifndef CONFIG_HIDKBD_DEFPRIO
  73. # define CONFIG_HIDKBD_DEFPRIO 50
  74. #endif
  75. #ifndef CONFIG_HIDKBD_STACKSIZE
  76. # define CONFIG_HIDKBD_STACKSIZE 1024
  77. #endif
  78. #ifndef CONFIG_HIDKBD_BUFSIZE
  79. # define CONFIG_HIDKBD_BUFSIZE 64
  80. #endif
  81. #ifndef CONFIG_HIDKBD_NPOLLWAITERS
  82. # define CONFIG_HIDKBD_NPOLLWAITERS 2
  83. #endif
  84. /* The default is to support scancode mapping for the standard 104 key
  85. * keyboard. Setting CONFIG_HIDKBD_RAWSCANCODES will disable all scancode
  86. * mapping; Setting CONFIG_HIDKBD_ALLSCANCODES will enable mapping of all
  87. * scancodes;
  88. */
  89. #ifndef CONFIG_HIDKBD_RAWSCANCODES
  90. # ifdef CONFIG_HIDKBD_ALLSCANCODES
  91. # define USBHID_NUMSCANCODES (USBHID_KBDUSE_MAX+1)
  92. # else
  93. # define USBHID_NUMSCANCODES 104
  94. # endif
  95. #endif
  96. /* We can't support encoding of special characters of unless the Keyboard
  97. * CODEC is enabled.
  98. */
  99. #ifndef CONFIG_LIB_KBDCODEC
  100. # undef CONFIG_HIDKBD_ENCODED
  101. #endif
  102. /* If we are using raw scancodes, then we cannot support encoding of
  103. * special characters either.
  104. */
  105. #ifdef CONFIG_HIDKBD_RAWSCANCODES
  106. # undef CONFIG_HIDKBD_ENCODED
  107. #endif
  108. /* Driver support ***********************************************************/
  109. /* This format is used to construct the /dev/kbd[n] device driver path. It
  110. * defined here so that it will be used consistently in all places.
  111. */
  112. #define DEV_FORMAT "/dev/kbd%c"
  113. #define DEV_NAMELEN 11
  114. /* Used in usbhost_cfgdesc() */
  115. #define USBHOST_IFFOUND 0x01 /* Required I/F descriptor found */
  116. #define USBHOST_EPINFOUND 0x02 /* Required interrupt IN EP descriptor found */
  117. #define USBHOST_EPOUTFOUND 0x04 /* Optional interrupt OUT EP descriptor found */
  118. #define USBHOST_RQDFOUND (USBHOST_IFFOUND|USBHOST_EPINFOUND)
  119. #define USBHOST_ALLFOUND (USBHOST_RQDFOUND|USBHOST_EPOUTFOUND)
  120. #define USBHOST_MAX_CREFS 0x7fff
  121. /* Debug ********************************************************************/
  122. /* Both CONFIG_DEBUG_INPUT and CONFIG_DEBUG_USB could apply to this file.
  123. * We assume here that CONFIG_DEBUG_INPUT might be enabled separately, but
  124. * CONFIG_DEBUG_USB implies both.
  125. */
  126. #ifndef CONFIG_DEBUG_INPUT
  127. # undef ierr
  128. # define ierr uerr
  129. # undef iinfo
  130. # define iinfo uinfo
  131. #endif
  132. /****************************************************************************
  133. * Private Types
  134. ****************************************************************************/
  135. /* This structure contains the internal, private state of the USB host
  136. * keyboard storage class.
  137. */
  138. struct usbhost_state_s
  139. {
  140. /* This is the externally visible portion of the state */
  141. struct usbhost_class_s usbclass;
  142. /* The remainder of the fields are provide o the keyboard class driver */
  143. char devchar; /* Character identifying the /dev/kbd[n] device */
  144. volatile bool disconnected; /* TRUE: Device has been disconnected */
  145. volatile bool polling; /* TRUE: Poll thread is running */
  146. volatile bool open; /* TRUE: The keyboard device is open */
  147. volatile bool waiting; /* TRUE: waiting for keyboard data */
  148. uint8_t ifno; /* Interface number */
  149. int16_t crefs; /* Reference count on the driver instance */
  150. sem_t exclsem; /* Used to maintain mutual exclusive access */
  151. sem_t waitsem; /* Used to wait for keyboard data */
  152. FAR uint8_t *tbuffer; /* The allocated transfer buffer */
  153. size_t tbuflen; /* Size of the allocated transfer buffer */
  154. pid_t pollpid; /* PID of the poll task */
  155. struct work_s work; /* For cornercase error handling by the worker thread */
  156. /* Endpoints:
  157. * EP0 (Control):
  158. * - Receiving and responding to requests for USB control and class data.
  159. * - IN data when polled by the HID class driver (Get_Report)
  160. * - OUT data from the host.
  161. * EP Interrupt IN:
  162. * - Receiving asynchronous (unrequested) IN data from the device.
  163. * EP Interrupt OUT (optional):
  164. * - Transmitting low latency OUT data to the device.
  165. * - If not present, EP0 used.
  166. */
  167. usbhost_ep_t epin; /* Interrupt IN endpoint */
  168. usbhost_ep_t epout; /* Optional interrupt OUT endpoint */
  169. /* The following is a list if poll structures of threads waiting for
  170. * driver events. The 'struct pollfd' reference for each open is also
  171. * retained in the f_priv field of the 'struct file'.
  172. */
  173. struct pollfd *fds[CONFIG_HIDKBD_NPOLLWAITERS];
  174. /* Buffer used to collect and buffer incoming keyboard characters */
  175. volatile uint16_t headndx; /* Buffer head index */
  176. volatile uint16_t tailndx; /* Buffer tail index */
  177. uint8_t kbdbuffer[CONFIG_HIDKBD_BUFSIZE];
  178. };
  179. /* This type is used for encoding special characters */
  180. #ifdef CONFIG_HIDKBD_ENCODED
  181. struct usbhost_outstream_s
  182. {
  183. struct lib_outstream_s stream;
  184. FAR struct usbhost_state_s *priv;
  185. };
  186. #endif
  187. /****************************************************************************
  188. * Private Function Prototypes
  189. ****************************************************************************/
  190. /* Semaphores */
  191. static int usbhost_takesem(FAR sem_t *sem);
  192. static void usbhost_forcetake(FAR sem_t *sem);
  193. #define usbhost_givesem(s) nxsem_post(s);
  194. /* Polling support */
  195. static void usbhost_pollnotify(FAR struct usbhost_state_s *dev);
  196. /* Memory allocation services */
  197. static inline FAR struct usbhost_state_s *usbhost_allocclass(void);
  198. static inline void usbhost_freeclass(FAR struct usbhost_state_s *usbclass);
  199. /* Device name management */
  200. static int usbhost_allocdevno(FAR struct usbhost_state_s *priv);
  201. static void usbhost_freedevno(FAR struct usbhost_state_s *priv);
  202. static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv,
  203. FAR char *devname);
  204. /* Keyboard polling thread */
  205. static void usbhost_destroy(FAR void *arg);
  206. static void usbhost_putbuffer(FAR struct usbhost_state_s *priv,
  207. uint8_t keycode);
  208. #ifdef CONFIG_HIDKBD_ENCODED
  209. static void usbhost_putstream(FAR struct lib_outstream_s *this, int ch);
  210. #endif
  211. static inline uint8_t usbhost_mapscancode(uint8_t scancode,
  212. uint8_t modifier);
  213. #ifdef CONFIG_HIDKBD_ENCODED
  214. static inline void usbhost_encodescancode(FAR struct usbhost_state_s *priv,
  215. uint8_t scancode, uint8_t modifier);
  216. #endif
  217. static int usbhost_kbdpoll(int argc, char *argv[]);
  218. /* Helpers for usbhost_connect() */
  219. static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
  220. FAR const uint8_t *configdesc, int desclen);
  221. static inline int usbhost_devinit(FAR struct usbhost_state_s *priv);
  222. /* (Little Endian) Data helpers */
  223. static inline uint16_t usbhost_getle16(const uint8_t *val);
  224. static inline void usbhost_putle16(uint8_t *dest, uint16_t val);
  225. static inline uint32_t usbhost_getle32(const uint8_t *val);
  226. #if 0 /* Not used */
  227. static void usbhost_putle32(uint8_t *dest, uint32_t val);
  228. #endif
  229. /* Transfer descriptor memory management */
  230. static inline int usbhost_tdalloc(FAR struct usbhost_state_s *priv);
  231. static inline int usbhost_tdfree(FAR struct usbhost_state_s *priv);
  232. /* struct usbhost_registry_s methods */
  233. static struct usbhost_class_s *usbhost_create(
  234. FAR struct usbhost_hubport_s *hport,
  235. FAR const struct usbhost_id_s *id);
  236. /* struct usbhost_class_s methods */
  237. static int usbhost_connect(FAR struct usbhost_class_s *usbclass,
  238. FAR const uint8_t *configdesc, int desclen);
  239. static int usbhost_disconnected(FAR struct usbhost_class_s *usbclass);
  240. /* Driver methods. We export the keyboard as a standard character driver */
  241. static int usbhost_open(FAR struct file *filep);
  242. static int usbhost_close(FAR struct file *filep);
  243. static ssize_t usbhost_read(FAR struct file *filep,
  244. FAR char *buffer, size_t len);
  245. static ssize_t usbhost_write(FAR struct file *filep,
  246. FAR const char *buffer, size_t len);
  247. static int usbhost_poll(FAR struct file *filep, FAR struct pollfd *fds,
  248. bool setup);
  249. /****************************************************************************
  250. * Private Data
  251. ****************************************************************************/
  252. /* This structure provides the registry entry ID information that will be
  253. * used to associate the USB host keyboard class driver to a connected USB
  254. * device.
  255. */
  256. static const struct usbhost_id_s g_hidkbd_id =
  257. {
  258. USB_CLASS_HID, /* base */
  259. USBHID_SUBCLASS_BOOTIF, /* subclass */
  260. USBHID_PROTOCOL_KEYBOARD, /* proto */
  261. 0, /* vid */
  262. 0 /* pid */
  263. };
  264. /* This is the USB host storage class's registry entry */
  265. static struct usbhost_registry_s g_hidkbd =
  266. {
  267. NULL, /* flink */
  268. usbhost_create, /* create */
  269. 1, /* nids */
  270. &g_hidkbd_id /* id[] */
  271. };
  272. static const struct file_operations g_hidkbd_fops =
  273. {
  274. usbhost_open, /* open */
  275. usbhost_close, /* close */
  276. usbhost_read, /* read */
  277. usbhost_write, /* write */
  278. NULL, /* seek */
  279. NULL, /* ioctl */
  280. usbhost_poll /* poll */
  281. };
  282. /* This is a bitmap that is used to allocate device names /dev/kbda-z. */
  283. static uint32_t g_devinuse;
  284. /* The following are used to managed the class creation operation */
  285. static sem_t g_exclsem; /* For mutually exclusive thread creation */
  286. static sem_t g_syncsem; /* Thread data passing interlock */
  287. static struct usbhost_state_s *g_priv; /* Data passed to thread */
  288. /* The following tables map keyboard scan codes to printable ASIC
  289. * characters. There is no support here for function keys or cursor
  290. * controls.
  291. */
  292. #ifndef CONFIG_HIDKBD_RAWSCANCODES
  293. #ifdef CONFIG_HIDKBD_ENCODED
  294. /* The first and last scancode values with encode-able values */
  295. #define FIRST_ENCODING USBHID_KBDUSE_ENTER /* 0x28 Keyboard Return (ENTER) */
  296. #ifndef CONFIG_HIDKBD_ALLSCANCODES
  297. # define LAST_ENCODING USBHID_KBDUSE_POWER /* 0x66 Keyboard Power */
  298. #else
  299. # define LAST_ENCODING USBHID_KBDUSE_KPDHEXADECIMAL /* 0xdd Keypad Hexadecimal */
  300. #endif
  301. #define USBHID_NUMENCODINGS (LAST_ENCODING - FIRST_ENCODING + 1)
  302. static const uint8_t encoding[USBHID_NUMENCODINGS] =
  303. {
  304. /* 0x28-0x2f: Enter,escape,del,back-tab,space,_,+,{ */
  305. KEYCODE_ENTER, 0,
  306. KEYCODE_FWDDEL, KEYCODE_BACKDEL,
  307. 0, 0,
  308. 0, 0,
  309. /* 0x30-0x37: },|,Non-US tilde,:,",grave tilde,<,> */
  310. 0, 0,
  311. 0, 0,
  312. 0, 0,
  313. 0, 0,
  314. /* 0x38-0x3f: /,CapsLock,F1,F2,F3,F4,F5,F6 */
  315. 0, KEYCODE_CAPSLOCK,
  316. KEYCODE_F1, KEYCODE_F2,
  317. KEYCODE_F3, KEYCODE_F4,
  318. KEYCODE_F5, KEYCODE_F6,
  319. /* 0x40-0x47: F7,F8,F9,F10,F11,F12,PrtScn,ScrollLock */
  320. KEYCODE_F7, KEYCODE_F8,
  321. KEYCODE_F9, KEYCODE_F10,
  322. KEYCODE_F11, KEYCODE_F12,
  323. KEYCODE_PRTSCRN, KEYCODE_SCROLLLOCK,
  324. /* 0x48-0x4f: Pause,Insert,Home,PageUp,
  325. * DeleteForward,End,PageDown,RightArrow
  326. */
  327. KEYCODE_PAUSE, KEYCODE_INSERT,
  328. KEYCODE_HOME, KEYCODE_PAGEUP,
  329. KEYCODE_FWDDEL, KEYCODE_END,
  330. KEYCODE_PAGEDOWN, KEYCODE_RIGHT,
  331. /* 0x50-0x57: LeftArrow,DownArrow,UpArrow,Num Lock,/,*,-,+ */
  332. KEYCODE_LEFT, KEYCODE_DOWN,
  333. KEYCODE_UP, KEYCODE_NUMLOCK,
  334. 0, 0,
  335. 0, 0,
  336. /* 0x58-0x5f: Enter,1-7 */
  337. KEYCODE_ENTER, 0,
  338. 0, 0,
  339. 0, 0,
  340. 0, 0,
  341. /* 0x60-0x66: 8-9,0,.,Non-US \,Application,Power */
  342. 0, 0,
  343. 0, 0,
  344. 0, 0,
  345. KEYCODE_POWER,
  346. #ifdef CONFIG_HIDKBD_ALLSCANCODES
  347. 0, /* 0x67 = */
  348. /* 0x68-0x6f: F13,F14,F15,F16,F17,F18,F19,F20 */
  349. KEYCODE_F13, KEYCODE_F14,
  350. KEYCODE_F15, KEYCODE_F16,
  351. KEYCODE_F17, KEYCODE_F18,
  352. KEYCODE_F19, KEYCODE_F20,
  353. /* 0x70-0x77: F21,F22,F23,F24,Execute,Help,Menu,Select */
  354. KEYCODE_F21, KEYCODE_F22,
  355. KEYCODE_F23, KEYCODE_F24,
  356. KEYCODE_EXECUTE, KEYCODE_HELP,
  357. KEYCODE_MENU, KEYCODE_SELECT,
  358. /* 0x78-0x7f: Stop,Again,Undo,Cut,Copy,Paste,Find,Mute */
  359. KEYCODE_STOP, KEYCODE_AGAIN,
  360. KEYCODE_UNDO, KEYCODE_CUT,
  361. KEYCODE_COPY, KEYCODE_PASTE,
  362. KEYCODE_FIND, KEYCODE_MUTE,
  363. /* 0x80-0x87: VolUp,VolDown,LCapsLock,lNumLock,LScrollLock,,,
  364. * =,International1
  365. */
  366. KEYCODE_VOLUP, KEYCODE_VOLDOWN,
  367. KEYCODE_LCAPSLOCK, KEYCODE_LNUMLOCK,
  368. KEYCODE_LSCROLLLOCK, 0,
  369. 0, 0,
  370. /* 0x88-0x8f: International 2-9 */
  371. 0, 0,
  372. 0, 0,
  373. 0, 0,
  374. 0, 0,
  375. /* 0x90-0x97: LAN 1-8 */
  376. KEYCODE_LANG1, KEYCODE_LANG2,
  377. KEYCODE_LANG3, KEYCODE_LANG4,
  378. KEYCODE_LANG5, KEYCODE_LANG6,
  379. KEYCODE_LANG7, KEYCODE_LANG8,
  380. /* 0x98-0x9f: LAN 9,Erase,SysReq,Cancel,Clear,Prior,Return,Separator */
  381. 0, 0,
  382. KEYCODE_SYSREQ, KEYCODE_CANCEL,
  383. KEYCODE_CLEAR, 0,
  384. KEYCODE_ENTER, 0,
  385. /* 0xa0-0xa7: Out,Oper,Clear,CrSel,Excel,(reserved) */
  386. 0, 0,
  387. 0, 0,
  388. 0, 0,
  389. 0, 0,
  390. /* 0xa8-0xaf: (reserved) */
  391. 0, 0,
  392. 0, 0,
  393. 0, 0,
  394. 0, 0,
  395. /* 0xb0-0xb7: 00,000,ThouSeparator,DecSeparator,CurrencyUnit,SubUnit,(,) */
  396. 0, 0,
  397. 0, 0,
  398. 0, 0,
  399. 0, 0,
  400. /* 0xb8-0xbf: {,},tab,backspace,A-D */
  401. 0, 0,
  402. 0, KEYCODE_BACKDEL,
  403. 0, 0,
  404. 0, 0,
  405. /* 0xc0-0xc7: E-F,XOR,^,%,<,>,& */
  406. 0, 0,
  407. 0, 0,
  408. 0, 0,
  409. 0, 0,
  410. /* 0xc8-0xcf: &&,|,||,:,#, ,@,! */
  411. 0, 0,
  412. 0, 0,
  413. 0, 0,
  414. 0, 0,
  415. /* 0xd0-0xd7: Memory Store,Recall,Clear,Add,Subtract,Muliply,Divide,+/- */
  416. KEYCODE_MEMSTORE, KEYCODE_MEMRECALL,
  417. KEYCODE_MEMCLEAR, KEYCODE_MEMADD,
  418. KEYCODE_MEMSUB, KEYCODE_MEMMUL,
  419. KEYCODE_MEMDIV, KEYCODE_NEGATE,
  420. /* 0xd8-0xdd: Clear,ClearEntry,Binary,Octal,Decimal,Hexadecimal */
  421. KEYCODE_CLEAR, KEYCODE_CLEARENTRY,
  422. KEYCODE_BINARY, KEYCODE_OCTAL,
  423. KEYCODE_DECIMAL, KEYCODE_HEXADECIMAL
  424. #endif
  425. };
  426. #endif
  427. static const uint8_t ucmap[USBHID_NUMSCANCODES] =
  428. {
  429. 0, 0, 0, 0, 'A', 'B', 'C', 'D', /* 0x00-0x07: Reserved, errors, A-D */
  430. 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', /* 0x08-0x0f: E-L */
  431. 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 0x10-0x17: M-T */
  432. 'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@', /* 0x18-0x1f: U-Z,!,@ */
  433. '#', '$', '%', '^', '&', '*', '(', ')', /* 0x20-0x27: #,$,%,^,&,*,(,) */
  434. '\n', '\033', '\177', 0, ' ', '_', '+', '{', /* 0x28-0x2f: Enter,escape,del,back-tab,space,_,+,{ */
  435. '}', '|', 0, ':', '"', '~', '<', '>', /* 0x30-0x37: },|,Non-US tilde,:,",grave tilde,<,> */
  436. '?', 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f: /,CapsLock,F1,F2,F3,F4,F5,F6 */
  437. 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40-0x47: F7,F8,F9,F10,F11,F12,PrtScn,ScrollLock */
  438. 0, 0, 0, 0, 0, 0, 0, 0, /* 0x48-0x4f: Pause,Insert,Home,PageUp,DeleteForward,End,PageDown,RightArrow */
  439. 0, 0, 0, 0, '/', '*', '-', '+', /* 0x50-0x57: LeftArrow,DownArrow,UpArrow,Num Lock,/,*,-,+ */
  440. '\n', '1', '2', '3', '4', '5', '6', '7', /* 0x58-0x5f: Enter,1-7 */
  441. '8', '9', '0', '.', 0, 0, 0, '=', /* 0x60-0x67: 8-9,0,.,Non-US \,Application,Power,= */
  442. #ifdef CONFIG_HIDKBD_ALLSCANCODES
  443. 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68-0x6f: F13,F14,F15,F16,F17,F18,F19,F20 */
  444. 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77: F21,F22,F23,F24,Execute,Help,Menu,Select */
  445. 0, 0, 0, 0, 0, 0, 0, 0, /* 0x78-0x7f: Stop,Again,Undo,Cut,Copy,Paste,Find,Mute */
  446. 0, 0, 0, 0, 0, ',', 0, 0, /* 0x80-0x87: VolUp,VolDown,LCapsLock,lNumLock,LScrollLock,,,=,International1 */
  447. 0, 0, 0, 0, 0, 0, 0, 0, /* 0x88-0x8f: International 2-9 */
  448. 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x97: LAN 1-8 */
  449. 0, 0, 0, 0, 0, 0, '\n', 0, /* 0x98-0x9f: LAN 9,Erase,SysReq,Cancel,Clear,Prior,Return,Separator */
  450. 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0-0xa7: Out,Oper,Clear,CrSel,Excel,(reserved) */
  451. 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa8-0xaf: (reserved) */
  452. 0, 0, 0, 0, 0, 0, '(', ')', /* 0xb0-0xb7: 00,000,ThouSeparator,DecSeparator,CurrencyUnit,SubUnit,(,) */
  453. '{', '}', '\t', \177, 'A', 'B', 'C', 'D', /* 0xb8-0xbf: {,},tab,backspace,A-D */
  454. 'F', 'F', 0, '^', '%', '<', '>', '&', /* 0xc0-0xc7: E-F,XOR,^,%,<,>,& */
  455. 0, '|', 0, ':', '%', ' ', '@', '!', /* 0xc8-0xcf: &&,|,||,:,#, ,@,! */
  456. 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0-0xd7: Memory Store,Recall,Clear,Add,Subtract,Muliply,Divide,+/- */
  457. 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd8-0xdf: Clear,ClearEntry,Binary,Octal,Decimal,Hexadecimal */
  458. 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0-0xe7: Left Ctrl,Shift,Alt,GUI, Right Ctrl,Shift,Alt,GUI */
  459. #endif
  460. };
  461. static const uint8_t lcmap[USBHID_NUMSCANCODES] =
  462. {
  463. 0, 0, 0, 0, 'a', 'b', 'c', 'd', /* 0x00-0x07: Reserved, errors, a-d */
  464. 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', /* 0x08-0x0f: e-l */
  465. 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', /* 0x10-0x17: m-t */
  466. 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', /* 0x18-0x1f: u-z,1-2 */
  467. '3', '4', '5', '6', '7', '8', '9', '0', /* 0x20-0x27: 3-9,0 */
  468. '\n', '\033', '\177', '\t', ' ', '-', '=', '[', /* 0x28-0x2f: Enter,escape,del,tab,space,-,=,[ */
  469. ']', '\\', '\234', ';', '\'', '`', ',', '.', /* 0x30-0x37: ],\,Non-US pound,;,',grave accent,,,. */
  470. '/', 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f: /,CapsLock,F1,F2,F3,F4,F5,F6 */
  471. 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40-0x47: F7,F8,F9,F10,F11,F12,PrtScn,ScrollLock */
  472. 0, 0, 0, 0, 0, 0, 0, 0, /* 0x48-0x4f: Pause,Insert,Home,PageUp,DeleteForward,End,PageDown,RightArrow */
  473. 0, 0, 0, 0, '/', '*', '-', '+', /* 0x50-0x57: LeftArrow,DownArrow,UpArrow,Num Lock,/,*,-,+ */
  474. '\n', '1', '2', '3', '4', '5', '6', '7', /* 0x58-0x5f: Enter,1-7 */
  475. '8', '9', '0', '.', 0, 0, 0, '=', /* 0x60-0x67: 8-9,0,.,Non-US \,Application,Power,= */
  476. #ifdef CONFIG_HIDKBD_ALLSCANCODES
  477. 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68-0x6f: F13,F14,F15,F16,F17,F18,F19,F20 */
  478. 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77: F21,F22,F23,F24,Execute,Help,Menu,Select */
  479. 0, 0, 0, 0, 0, 0, 0, 0, /* 0x78-0x7f: Stop,Again,Undo,Cut,Copy,Paste,Find,Mute */
  480. 0, 0, 0, 0, 0, ',', 0, 0, /* 0x80-0x87: VolUp,VolDown,LCapsLock,lNumLock,LScrollLock,,,=,International1 */
  481. 0, 0, 0, 0, 0, 0, 0, 0, /* 0x88-0x8f: International 2-9 */
  482. 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x97: LAN 1-8 */
  483. 0, 0, 0, 0, 0, 0, '\n', 0, /* 0x98-0x9f: LAN 9,Erase,SysReq,Cancel,Clear,Prior,Return,Separator */
  484. 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0-0xa7: Out,Oper,Clear,CrSel,Excel,(reserved) */
  485. 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa8-0xaf: (reserved) */
  486. 0, 0, 0, 0, 0, 0, '(', ')', /* 0xb0-0xb7: 00,000,ThouSeparator,DecSeparator,CurrencyUnit,SubUnit,(,) */
  487. '{', '}', '\t', '\177', 'A', 'B', 'C', 'D', /* 0xb8-0xbf: {,},tab,backspace,A-D */
  488. 'F', 'F', 0, '^', '%', '<', '>', '&', /* 0xc0-0xc7: E-F,XOR,^,%,<,>,& */
  489. 0, '|', 0, ':', '%', ' ', '@', '!', /* 0xc8-0xcf: &&,|,||,:,#, ,@,! */
  490. 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0-0xd7: Memory Store,Recall,Clear,Add,Subtract,Muliply,Divide,+/- */
  491. 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd8-0xdf: Clear,ClearEntry,Binary,Octal,Decimal,Hexadecimal */
  492. 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0-0xe7: Left Ctrl,Shift,Alt,GUI, Right Ctrl,Shift,Alt,GUI */
  493. #endif
  494. };
  495. #endif /* CONFIG_HIDKBD_RAWSCANCODES */
  496. /****************************************************************************
  497. * Private Functions
  498. ****************************************************************************/
  499. /****************************************************************************
  500. * Name: usbhost_takesem
  501. *
  502. * Description:
  503. * This is just a wrapper to handle the annoying behavior of semaphore
  504. * waits that return due to the receipt of a signal.
  505. *
  506. ****************************************************************************/
  507. static int usbhost_takesem(FAR sem_t *sem)
  508. {
  509. return nxsem_wait_uninterruptible(sem);
  510. }
  511. /****************************************************************************
  512. * Name: usbhost_forcetake
  513. *
  514. * Description:
  515. * This is just another wrapper but this one continues even if the thread
  516. * is canceled. This must be done in certain conditions where were must
  517. * continue in order to clean-up resources.
  518. *
  519. ****************************************************************************/
  520. static void usbhost_forcetake(FAR sem_t *sem)
  521. {
  522. int ret;
  523. do
  524. {
  525. ret = nxsem_wait_uninterruptible(sem);
  526. /* The only expected error would -ECANCELED meaning that the
  527. * parent thread has been canceled. We have to continue and
  528. * terminate the poll in this case.
  529. */
  530. DEBUGASSERT(ret == OK || ret == -ECANCELED);
  531. }
  532. while (ret < 0);
  533. }
  534. /****************************************************************************
  535. * Name: usbhost_pollnotify
  536. ****************************************************************************/
  537. static void usbhost_pollnotify(FAR struct usbhost_state_s *priv)
  538. {
  539. int i;
  540. for (i = 0; i < CONFIG_HIDKBD_NPOLLWAITERS; i++)
  541. {
  542. struct pollfd *fds = priv->fds[i];
  543. if (fds)
  544. {
  545. fds->revents |= (fds->events & POLLIN);
  546. if (fds->revents != 0)
  547. {
  548. uinfo("Report events: %02x\n", fds->revents);
  549. nxsem_post(fds->sem);
  550. }
  551. }
  552. }
  553. }
  554. /****************************************************************************
  555. * Name: usbhost_allocclass
  556. *
  557. * Description:
  558. * This is really part of the logic that implements the create() method
  559. * of struct usbhost_registry_s. This function allocates memory for one
  560. * new class instance.
  561. *
  562. * Input Parameters:
  563. * None
  564. *
  565. * Returned Value:
  566. * On success, this function will return a non-NULL instance of struct
  567. * usbhost_class_s. NULL is returned on failure; this function will
  568. * will fail only if there are insufficient resources to create another
  569. * USB host class instance.
  570. *
  571. ****************************************************************************/
  572. static inline FAR struct usbhost_state_s *usbhost_allocclass(void)
  573. {
  574. FAR struct usbhost_state_s *priv;
  575. DEBUGASSERT(!up_interrupt_context());
  576. priv = (FAR struct usbhost_state_s *)
  577. kmm_malloc(sizeof(struct usbhost_state_s));
  578. uinfo("Allocated: %p\n", priv);
  579. return priv;
  580. }
  581. /****************************************************************************
  582. * Name: usbhost_freeclass
  583. *
  584. * Description:
  585. * Free a class instance previously allocated by usbhost_allocclass().
  586. *
  587. * Input Parameters:
  588. * usbclass - A reference to the class instance to be freed.
  589. *
  590. * Returned Value:
  591. * None
  592. *
  593. ****************************************************************************/
  594. static inline void usbhost_freeclass(FAR struct usbhost_state_s *usbclass)
  595. {
  596. DEBUGASSERT(usbclass != NULL);
  597. /* Free the class instance. */
  598. uinfo("Freeing: %p\n", usbclass);
  599. kmm_free(usbclass);
  600. }
  601. /****************************************************************************
  602. * Name: Device name management
  603. *
  604. * Description:
  605. * Some tiny functions to coordinate management of device names.
  606. *
  607. ****************************************************************************/
  608. static int usbhost_allocdevno(FAR struct usbhost_state_s *priv)
  609. {
  610. irqstate_t flags;
  611. int devno;
  612. flags = enter_critical_section();
  613. for (devno = 0; devno < 26; devno++)
  614. {
  615. uint32_t bitno = 1 << devno;
  616. if ((g_devinuse & bitno) == 0)
  617. {
  618. g_devinuse |= bitno;
  619. priv->devchar = 'a' + devno;
  620. leave_critical_section(flags);
  621. return OK;
  622. }
  623. }
  624. leave_critical_section(flags);
  625. return -EMFILE;
  626. }
  627. static void usbhost_freedevno(FAR struct usbhost_state_s *priv)
  628. {
  629. int devno = 'a' - priv->devchar;
  630. if (devno >= 0 && devno < 26)
  631. {
  632. irqstate_t flags = enter_critical_section();
  633. g_devinuse &= ~(1 << devno);
  634. leave_critical_section(flags);
  635. }
  636. }
  637. static inline void usbhost_mkdevname(FAR struct usbhost_state_s *priv,
  638. FAR char *devname)
  639. {
  640. snprintf(devname, DEV_NAMELEN, DEV_FORMAT, priv->devchar);
  641. }
  642. /****************************************************************************
  643. * Name: usbhost_destroy
  644. *
  645. * Description:
  646. * The USB device has been disconnected and the reference count on the USB
  647. * host class instance has gone to 1.. Time to destroy the USB host class
  648. * instance.
  649. *
  650. * Input Parameters:
  651. * arg - A reference to the class instance to be destroyed.
  652. *
  653. * Returned Value:
  654. * None
  655. *
  656. ****************************************************************************/
  657. static void usbhost_destroy(FAR void *arg)
  658. {
  659. FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)arg;
  660. FAR struct usbhost_hubport_s *hport;
  661. char devname[DEV_NAMELEN];
  662. DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL);
  663. hport = priv->usbclass.hport;
  664. uinfo("crefs: %d\n", priv->crefs);
  665. /* Unregister the driver */
  666. uinfo("Unregister driver\n");
  667. usbhost_mkdevname(priv, devname);
  668. unregister_driver(devname);
  669. /* Release the device name used by this connection */
  670. usbhost_freedevno(priv);
  671. /* Free the interrupt endpoints */
  672. if (priv->epin)
  673. {
  674. DRVR_EPFREE(hport->drvr, priv->epin);
  675. }
  676. if (priv->epout)
  677. {
  678. DRVR_EPFREE(hport->drvr, priv->epout);
  679. }
  680. /* Free any transfer buffers */
  681. usbhost_tdfree(priv);
  682. /* Destroy the semaphores */
  683. nxsem_destroy(&priv->exclsem);
  684. nxsem_destroy(&priv->waitsem);
  685. /* Disconnect the USB host device */
  686. DRVR_DISCONNECT(hport->drvr, hport);
  687. /* Free the function address assigned to this device */
  688. usbhost_devaddr_destroy(hport, hport->funcaddr);
  689. hport->funcaddr = 0;
  690. /* And free the class instance. */
  691. usbhost_freeclass(priv);
  692. }
  693. /****************************************************************************
  694. * Name: usbhost_putbuffer
  695. *
  696. * Description:
  697. * Add one character to the user buffer.
  698. *
  699. * Input Parameters:
  700. * priv - Driver internal state
  701. * keycode - The value to add to the user buffer
  702. *
  703. * Returned Value:
  704. * None
  705. *
  706. ****************************************************************************/
  707. static void usbhost_putbuffer(FAR struct usbhost_state_s *priv,
  708. uint8_t keycode)
  709. {
  710. register unsigned int head;
  711. register unsigned int tail;
  712. /* Copy the next keyboard character into the user buffer. */
  713. head = priv->headndx;
  714. priv->kbdbuffer[head] = keycode;
  715. /* Increment the head index */
  716. if (++head >= CONFIG_HIDKBD_BUFSIZE)
  717. {
  718. head = 0;
  719. }
  720. /* If the buffer is full, then increment the tail index to make space. Is
  721. * it better to lose old keystrokes or new?
  722. */
  723. tail = priv->tailndx;
  724. if (tail == head)
  725. {
  726. if (++tail >= CONFIG_HIDKBD_BUFSIZE)
  727. {
  728. tail = 0;
  729. }
  730. /* Save the updated tail index */
  731. priv->tailndx = tail;
  732. }
  733. /* Save the updated head index */
  734. priv->headndx = head;
  735. }
  736. /****************************************************************************
  737. * Name: usbhost_putstream
  738. *
  739. * Description:
  740. * A wrapper for usbhost_putc that is compatible with the lib_outstream_s
  741. * putc methods.
  742. *
  743. * Input Parameters:
  744. * stream - The struct lib_outstream_s reference
  745. * ch - The character to add to the user buffer
  746. *
  747. * Returned Value:
  748. * None
  749. *
  750. ****************************************************************************/
  751. #ifdef CONFIG_HIDKBD_ENCODED
  752. static void usbhost_putstream(FAR struct lib_outstream_s *stream, int ch)
  753. {
  754. FAR struct usbhost_outstream_s *privstream =
  755. (FAR struct usbhost_outstream_s *)stream;
  756. DEBUGASSERT(privstream && privstream->priv);
  757. usbhost_putbuffer(privstream->priv, (uint8_t)ch);
  758. stream->nput++;
  759. }
  760. #endif
  761. /****************************************************************************
  762. * Name: usbhost_mapscancode
  763. *
  764. * Description:
  765. * Map a keyboard scancode to a printable ASCII character. There is no
  766. * support here for function keys or cursor controls in this version of
  767. * the driver.
  768. *
  769. * Input Parameters:
  770. * scancode - Scan code to be mapped.
  771. * modifier - Ctrl,Alt,Shift,GUI modifier bits
  772. *
  773. * Returned Value:
  774. * None
  775. *
  776. ****************************************************************************/
  777. static inline uint8_t usbhost_mapscancode(uint8_t scancode, uint8_t modifier)
  778. {
  779. #ifndef CONFIG_HIDKBD_RAWSCANCODES
  780. /* Range check */
  781. if (scancode >= USBHID_NUMSCANCODES)
  782. {
  783. return 0;
  784. }
  785. /* Is either shift key pressed? */
  786. if ((modifier & (USBHID_MODIFER_LSHIFT | USBHID_MODIFER_RSHIFT)) != 0)
  787. {
  788. return ucmap[scancode];
  789. }
  790. else
  791. {
  792. return lcmap[scancode];
  793. }
  794. #else
  795. return scancode;
  796. #endif
  797. }
  798. /****************************************************************************
  799. * Name: usbhost_encodescancode
  800. *
  801. * Description:
  802. * Check if the key has a special function encoding and, if it does, add
  803. * the encoded value to the user buffer.
  804. *
  805. * Input Parameters:
  806. * priv - Driver internal state
  807. * scancode - Scan code to be mapped.
  808. * modifier - Ctrl, Alt, Shift, GUI modifier bits
  809. *
  810. * Returned Value:
  811. * None
  812. *
  813. ****************************************************************************/
  814. #ifdef CONFIG_HIDKBD_ENCODED
  815. static inline void usbhost_encodescancode(FAR struct usbhost_state_s *priv,
  816. uint8_t scancode, uint8_t modifier)
  817. {
  818. uint8_t encoded;
  819. /* Check if the raw scancode is in a valid range */
  820. if (scancode >= FIRST_ENCODING && scancode <= LAST_ENCODING)
  821. {
  822. /* Yes the value is within range */
  823. encoded = encoding[scancode - FIRST_ENCODING];
  824. iinfo(" scancode: %02x modifier: %02x encoded: %d\n",
  825. scancode, modifier, encoded);
  826. if (encoded)
  827. {
  828. struct usbhost_outstream_s usbstream;
  829. /* And it does correspond to a special function key */
  830. usbstream.stream.put = usbhost_putstream;
  831. usbstream.stream.nput = 0;
  832. usbstream.priv = priv;
  833. /* Add the special function value to the user buffer */
  834. kbd_specpress((enum kbd_keycode_e)encoded,
  835. (FAR struct lib_outstream_s *)&usbstream);
  836. }
  837. }
  838. }
  839. #endif
  840. /****************************************************************************
  841. * Name: usbhost_kbdpoll
  842. *
  843. * Description:
  844. * Periodically check for new keyboard data.
  845. *
  846. * Input Parameters:
  847. * arg - A reference to the class instance to be destroyed.
  848. *
  849. * Returned Value:
  850. * None
  851. *
  852. ****************************************************************************/
  853. static int usbhost_kbdpoll(int argc, char *argv[])
  854. {
  855. FAR struct usbhost_state_s *priv;
  856. FAR struct usbhost_hubport_s *hport;
  857. FAR struct usb_ctrlreq_s *ctrlreq;
  858. irqstate_t flags;
  859. #ifndef CONFIG_HIDKBD_NODEBOUNCE
  860. uint8_t lastkey[6] =
  861. {
  862. 0, 0, 0, 0, 0, 0
  863. };
  864. #endif
  865. #if defined(CONFIG_DEBUG_USB) && defined(CONFIG_DEBUG_INFO)
  866. unsigned int npolls = 0;
  867. #endif
  868. unsigned int nerrors = 0;
  869. useconds_t delay;
  870. bool empty = true;
  871. bool newstate;
  872. int ret;
  873. uinfo("Started\n");
  874. /* Synchronize with the start-up logic. Get the private instance, re-start
  875. * the start-up logic, and wait a bit to make sure that all of the class
  876. * creation logic has a chance to run to completion.
  877. *
  878. * NOTE: that the reference count is *not* incremented here. When the
  879. * driver structure was created, it was created with a reference count of
  880. * one. This thread is responsible for that count. The count will be
  881. * decrement when this thread exits.
  882. */
  883. priv = g_priv;
  884. DEBUGASSERT(priv != NULL && priv->usbclass.hport);
  885. hport = priv->usbclass.hport;
  886. priv->polling = true;
  887. usbhost_givesem(&g_syncsem);
  888. nxsig_sleep(1);
  889. /* Loop here until the device is disconnected */
  890. uinfo("Entering poll loop\n");
  891. while (!priv->disconnected)
  892. {
  893. /* Make sure that we have exclusive access to the private data
  894. * structure. There may now be other tasks with the character driver
  895. * open and actively trying to interact with the class driver.
  896. */
  897. ret = usbhost_takesem(&priv->exclsem);
  898. if (ret < 0)
  899. {
  900. return ret;
  901. }
  902. /* Format the HID report request:
  903. *
  904. * bmRequestType 10100001
  905. * bRequest GET_REPORT (0x01)
  906. * wValue Report Type and Report Index
  907. * wIndex Interface Number
  908. * wLength Descriptor Length
  909. * Data Descriptor Data
  910. */
  911. ctrlreq = (struct usb_ctrlreq_s *)priv->tbuffer;
  912. ctrlreq->type = USB_REQ_DIR_IN | USB_REQ_TYPE_CLASS |
  913. USB_REQ_RECIPIENT_INTERFACE;
  914. ctrlreq->req = USBHID_REQUEST_GETREPORT;
  915. usbhost_putle16(ctrlreq->value, (USBHID_REPORTTYPE_INPUT << 8));
  916. usbhost_putle16(ctrlreq->index, priv->ifno);
  917. usbhost_putle16(ctrlreq->len, sizeof(struct usbhid_kbdreport_s));
  918. /* Send HID report request */
  919. ret = DRVR_CTRLIN(hport->drvr, hport->ep0, ctrlreq, priv->tbuffer);
  920. usbhost_givesem(&priv->exclsem);
  921. /* Check for errors -- Bail if an excessive number of consecutive
  922. * errors are encountered.
  923. */
  924. if (ret < 0)
  925. {
  926. nerrors++;
  927. uerr("ERROR: GETREPORT/INPUT, DRVR_CTRLIN returned: %d/%d\n",
  928. ret, nerrors);
  929. if (nerrors > 200)
  930. {
  931. uerr(" Too many errors... aborting: %d\n", nerrors);
  932. break;
  933. }
  934. }
  935. /* The report was received correctly. But ignore the keystrokes if no
  936. * task has opened the driver.
  937. */
  938. else if (priv->open)
  939. {
  940. struct usbhid_kbdreport_s *rpt =
  941. (struct usbhid_kbdreport_s *)priv->tbuffer;
  942. uint8_t keycode;
  943. int i;
  944. /* Success, reset the error counter */
  945. nerrors = 0;
  946. /* Add the newly received keystrokes to our internal buffer */
  947. ret = usbhost_takesem(&priv->exclsem);
  948. if (ret < 0)
  949. {
  950. return ret;
  951. }
  952. for (i = 0; i < 6; i++)
  953. {
  954. /* Is this key pressed? But not pressed last time?
  955. * HID spec: "The order of keycodes in array fields has no
  956. * significance. Order determination is done by the host
  957. * software comparing the contents of the previous report to
  958. * the current report. If two or more keys are reported in
  959. * one report, their order is indeterminate. Keyboards may
  960. * buffer events that would have otherwise resulted in
  961. * multiple event in a single report.
  962. *
  963. * "'Repeat Rate' and 'Delay Before First Repeat' are
  964. * implemented by the host and not in the keyboard (this
  965. * means the BIOS in legacy mode). The host may use the
  966. * device report rate and the number of reports to determine
  967. * how long a key is being held down. Alternatively, the host
  968. * may use its own clock or the idle request for the timing
  969. * of these features."
  970. */
  971. if (rpt->key[i] != USBHID_KBDUSE_NONE
  972. #ifndef CONFIG_HIDKBD_NODEBOUNCE
  973. && rpt->key[i] != lastkey[0]
  974. && rpt->key[i] != lastkey[1]
  975. && rpt->key[i] != lastkey[2]
  976. && rpt->key[i] != lastkey[3]
  977. && rpt->key[i] != lastkey[4]
  978. && rpt->key[i] != lastkey[5]
  979. #endif
  980. )
  981. {
  982. /* Yes.. Add it to the buffer. */
  983. /* Map the keyboard scancode to a printable ASCII
  984. * character. There is no support here for function keys
  985. * or cursor controls in this version of the driver.
  986. */
  987. keycode = usbhost_mapscancode(rpt->key[i], rpt->modifier);
  988. iinfo("Key %d: %02x keycode:%c modifier: %02x\n",
  989. i, rpt->key[i], keycode ? keycode : ' ',
  990. rpt->modifier);
  991. /* Zero at this point means that the key does not map to a
  992. * printable character.
  993. */
  994. if (keycode != 0)
  995. {
  996. /* Handle control characters. Zero after this means
  997. * a valid, NUL character.
  998. */
  999. if ((rpt->modifier & (USBHID_MODIFER_LCTRL |
  1000. USBHID_MODIFER_RCTRL)) != 0)
  1001. {
  1002. keycode &= 0x1f;
  1003. }
  1004. /* Copy the next keyboard character into the user
  1005. * buffer.
  1006. */
  1007. usbhost_putbuffer(priv, keycode);
  1008. }
  1009. /* The zero might, however, map to a special keyboard
  1010. * action (such as a cursor movement or function key).
  1011. * Attempt to encode the special key.
  1012. */
  1013. #ifdef CONFIG_HIDKBD_ENCODED
  1014. else
  1015. {
  1016. usbhost_encodescancode(priv, rpt->key[i],
  1017. rpt->modifier);
  1018. }
  1019. #endif
  1020. }
  1021. /* Save the scancode (or lack thereof) for key debouncing on
  1022. * next keyboard report.
  1023. */
  1024. #ifndef CONFIG_HIDKBD_NODEBOUNCE
  1025. lastkey[i] = rpt->key[i];
  1026. #endif
  1027. }
  1028. /* Is there data available? */
  1029. newstate = (priv->headndx == priv->tailndx);
  1030. if (!newstate)
  1031. {
  1032. /* Did we just transition from no data available to data
  1033. * available? If so, wake up any threads waiting for the
  1034. * POLLIN event.
  1035. */
  1036. if (empty)
  1037. {
  1038. usbhost_pollnotify(priv);
  1039. }
  1040. /* Yes.. Is there a thread waiting for keyboard data now? */
  1041. if (priv->waiting)
  1042. {
  1043. /* Yes.. wake it up */
  1044. usbhost_givesem(&priv->waitsem);
  1045. priv->waiting = false;
  1046. }
  1047. }
  1048. empty = newstate;
  1049. usbhost_givesem(&priv->exclsem);
  1050. }
  1051. /* If USB debug is on, then provide some periodic indication that
  1052. * polling is still happening.
  1053. */
  1054. #if defined(CONFIG_DEBUG_USB) && defined(CONFIG_DEBUG_INFO)
  1055. npolls++;
  1056. if ((npolls & 31) == 0)
  1057. {
  1058. uinfo("Still polling: %d\n", npolls);
  1059. }
  1060. #endif
  1061. /* Wait for the required amount (or until a signal is received). We
  1062. * will wake up when either the delay elapses or we are signalled that
  1063. * the device has been disconnected.
  1064. *
  1065. * If we are getting errors, then sleep longer. In the event that
  1066. * the keyboard is connected via a hub, there may be a significant
  1067. * amount of time after the keyboard is removed before we are stopped.
  1068. */
  1069. if (nerrors > 1)
  1070. {
  1071. delay = nerrors * CONFIG_HIDKBD_POLLUSEC;
  1072. }
  1073. else
  1074. {
  1075. delay = CONFIG_HIDKBD_POLLUSEC;
  1076. }
  1077. nxsig_usleep(delay);
  1078. }
  1079. /* We get here when the driver is removed.. or when too many errors have
  1080. * been encountered.
  1081. *
  1082. * Make sure that we have exclusive access to the private data structure.
  1083. * There may now be other tasks with the character driver open and actively
  1084. * trying to interact with the class driver.
  1085. */
  1086. usbhost_forcetake(&priv->exclsem);
  1087. /* Indicate that we are no longer running and decrement the reference
  1088. * count held by this thread. If there are no other users of the class,
  1089. * we can destroy it now. Otherwise, we have to wait until the all
  1090. * of the file descriptors are closed.
  1091. */
  1092. uinfo("Keyboard removed, polling halted\n");
  1093. flags = enter_critical_section();
  1094. priv->polling = false;
  1095. /* Decrement the reference count held by this thread. */
  1096. DEBUGASSERT(priv->crefs > 0);
  1097. priv->crefs--;
  1098. /* There are two possibilities:
  1099. * 1) The reference count is greater than zero. This means that there
  1100. * are still open references to the keyboard driver. In this case
  1101. * we need to wait until usbhost_close() is called and all of the
  1102. * open driver references are decremented. Then usbhost_destroy() can
  1103. * be called from usbhost_close().
  1104. * 2) The reference count is now zero. This means that there are no
  1105. * further open references and we can call usbhost_destroy() now.
  1106. */
  1107. if (priv->crefs < 1)
  1108. {
  1109. /* Unregister the driver and destroy the instance (while we hold
  1110. * the semaphore!)
  1111. */
  1112. usbhost_destroy(priv);
  1113. }
  1114. else
  1115. {
  1116. /* No, we will destroy the driver instance when it is final open
  1117. * reference is closed
  1118. */
  1119. usbhost_givesem(&priv->exclsem);
  1120. }
  1121. leave_critical_section(flags);
  1122. return 0;
  1123. }
  1124. /****************************************************************************
  1125. * Name: usbhost_cfgdesc
  1126. *
  1127. * Description:
  1128. * This function implements the connect() method of struct
  1129. * usbhost_class_s. This method is a callback into the class
  1130. * implementation. It is used to provide the device's configuration
  1131. * descriptor to the class so that the class may initialize properly
  1132. *
  1133. * Input Parameters:
  1134. * priv - The USB host class instance.
  1135. * configdesc - A pointer to a uint8_t buffer container the configuration
  1136. * descriptor.
  1137. * desclen - The length in bytes of the configuration descriptor.
  1138. *
  1139. * Returned Value:
  1140. * On success, zero (OK) is returned. On a failure, a negated errno value
  1141. * is returned indicating the nature of the failure
  1142. *
  1143. * Assumptions:
  1144. * This function will *not* be called from an interrupt handler.
  1145. *
  1146. ****************************************************************************/
  1147. static inline int usbhost_cfgdesc(FAR struct usbhost_state_s *priv,
  1148. FAR const uint8_t *configdesc, int desclen)
  1149. {
  1150. FAR struct usbhost_hubport_s *hport;
  1151. FAR struct usb_cfgdesc_s *cfgdesc;
  1152. FAR struct usb_desc_s *desc;
  1153. FAR struct usbhost_epdesc_s epindesc;
  1154. FAR struct usbhost_epdesc_s epoutdesc;
  1155. int remaining;
  1156. uint8_t found = 0;
  1157. bool done = false;
  1158. int ret;
  1159. DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL &&
  1160. configdesc != NULL && desclen >= sizeof(struct usb_cfgdesc_s));
  1161. hport = priv->usbclass.hport;
  1162. /* Keep the compiler from complaining about uninitialized variables */
  1163. memset(&epindesc, 0, sizeof(struct usbhost_epdesc_s));
  1164. memset(&epoutdesc, 0, sizeof(struct usbhost_epdesc_s));
  1165. /* Verify that we were passed a configuration descriptor */
  1166. cfgdesc = (FAR struct usb_cfgdesc_s *)configdesc;
  1167. if (cfgdesc->type != USB_DESC_TYPE_CONFIG)
  1168. {
  1169. return -EINVAL;
  1170. }
  1171. /* Get the total length of the configuration descriptor (little endian).
  1172. * It might be a good check to get the number of interfaces here too.
  1173. */
  1174. remaining = (int)usbhost_getle16(cfgdesc->totallen);
  1175. /* Skip to the next entry descriptor */
  1176. configdesc += cfgdesc->len;
  1177. remaining -= cfgdesc->len;
  1178. /* Loop where there are more descriptors to examine */
  1179. while (remaining >= sizeof(struct usb_desc_s) && !done)
  1180. {
  1181. /* What is the next descriptor? */
  1182. desc = (FAR struct usb_desc_s *)configdesc;
  1183. switch (desc->type)
  1184. {
  1185. /* Interface descriptor. We really should get the number of endpoints
  1186. * from this descriptor too.
  1187. */
  1188. case USB_DESC_TYPE_INTERFACE:
  1189. {
  1190. FAR struct usb_ifdesc_s *ifdesc =
  1191. (FAR struct usb_ifdesc_s *)configdesc;
  1192. uinfo("Interface descriptor\n");
  1193. DEBUGASSERT(remaining >= USB_SIZEOF_IFDESC);
  1194. /* Did we already find what we needed
  1195. * from a preceding interface?
  1196. */
  1197. if ((found & USBHOST_RQDFOUND) == USBHOST_RQDFOUND)
  1198. {
  1199. /* Yes.. then break out of the loop and use the preceding
  1200. * interface.
  1201. */
  1202. done = true;
  1203. }
  1204. else
  1205. {
  1206. /* Otherwise, save the interface number and discard any
  1207. * endpoints previously found
  1208. */
  1209. priv->ifno = ifdesc->ifno;
  1210. found = USBHOST_IFFOUND;
  1211. }
  1212. }
  1213. break;
  1214. /* HID descriptor */
  1215. case USBHID_DESCTYPE_HID:
  1216. uinfo("HID descriptor\n");
  1217. break;
  1218. /* Endpoint descriptor. We expect one or two interrupt endpoints,
  1219. * a required IN endpoint and an optional OUT endpoint.
  1220. */
  1221. case USB_DESC_TYPE_ENDPOINT:
  1222. {
  1223. FAR struct usb_epdesc_s *epdesc =
  1224. (FAR struct usb_epdesc_s *)configdesc;
  1225. uinfo("Endpoint descriptor\n");
  1226. DEBUGASSERT(remaining >= USB_SIZEOF_EPDESC);
  1227. /* Check for an interrupt endpoint. */
  1228. if ((epdesc->attr & USB_EP_ATTR_XFERTYPE_MASK) ==
  1229. USB_EP_ATTR_XFER_INT)
  1230. {
  1231. /* Yes.. it is a interrupt endpoint. IN or OUT? */
  1232. if (USB_ISEPOUT(epdesc->addr))
  1233. {
  1234. /* It is an interrupt OUT endpoint. There not be more
  1235. * than one interrupt OUT endpoint.
  1236. */
  1237. if ((found & USBHOST_EPOUTFOUND) != 0)
  1238. {
  1239. /* Oops.. more than one endpoint. We don't know what
  1240. * to do with this.
  1241. */
  1242. return -EINVAL;
  1243. }
  1244. found |= USBHOST_EPOUTFOUND;
  1245. /* Save the interrupt OUT endpoint information */
  1246. epoutdesc.hport = hport;
  1247. epoutdesc.addr = epdesc->addr &
  1248. USB_EP_ADDR_NUMBER_MASK;
  1249. epoutdesc.in = false;
  1250. epoutdesc.xfrtype = USB_EP_ATTR_XFER_INT;
  1251. epoutdesc.interval = epdesc->interval;
  1252. epoutdesc.mxpacketsize =
  1253. usbhost_getle16(epdesc->mxpacketsize);
  1254. uinfo("Interrupt OUT EP addr:%d mxpacketsize:%d\n",
  1255. epoutdesc.addr, epoutdesc.mxpacketsize);
  1256. }
  1257. else
  1258. {
  1259. /* It is an interrupt IN endpoint. There should be only
  1260. * one interrupt IN endpoint.
  1261. */
  1262. if ((found & USBHOST_EPINFOUND) != 0)
  1263. {
  1264. /* Oops.. more than one endpoint. We don't know what
  1265. * to do with this.
  1266. */
  1267. return -EINVAL;
  1268. }
  1269. found |= USBHOST_EPINFOUND;
  1270. /* Save the interrupt IN endpoint information */
  1271. epindesc.hport = hport;
  1272. epindesc.addr = epdesc->addr &
  1273. USB_EP_ADDR_NUMBER_MASK;
  1274. epindesc.in = 1;
  1275. epindesc.xfrtype = USB_EP_ATTR_XFER_INT;
  1276. epindesc.interval = epdesc->interval;
  1277. epindesc.mxpacketsize =
  1278. usbhost_getle16(epdesc->mxpacketsize);
  1279. uinfo("Interrupt IN EP addr:%d mxpacketsize:%d\n",
  1280. epindesc.addr, epindesc.mxpacketsize);
  1281. }
  1282. }
  1283. }
  1284. break;
  1285. /* Other descriptors are just ignored for now */
  1286. default:
  1287. uinfo("Other descriptor: %d\n", desc->type);
  1288. break;
  1289. }
  1290. /* What we found everything that we are going to find? */
  1291. if (found == USBHOST_ALLFOUND)
  1292. {
  1293. /* Yes.. then break out of the loop
  1294. * and use the preceding interface
  1295. */
  1296. done = true;
  1297. }
  1298. /* Increment the address of the next descriptor */
  1299. configdesc += desc->len;
  1300. remaining -= desc->len;
  1301. }
  1302. /* Sanity checking... did we find all of things that we need? */
  1303. if ((found & USBHOST_RQDFOUND) != USBHOST_RQDFOUND)
  1304. {
  1305. uerr("ERROR: Found IF:%s EPIN:%s\n",
  1306. (found & USBHOST_IFFOUND) != 0 ? "YES" : "NO",
  1307. (found & USBHOST_EPINFOUND) != 0 ? "YES" : "NO");
  1308. return -EINVAL;
  1309. }
  1310. /* We are good... Allocate the endpoints. First, the required interrupt
  1311. * IN endpoint.
  1312. */
  1313. ret = DRVR_EPALLOC(hport->drvr, &epindesc, &priv->epin);
  1314. if (ret < 0)
  1315. {
  1316. uerr("ERROR: Failed to allocate interrupt IN endpoint\n");
  1317. return ret;
  1318. }
  1319. /* Then the optional interrupt OUT endpoint */
  1320. uinfo("Found EPOOUT:%s\n",
  1321. (found & USBHOST_EPOUTFOUND) != 0 ? "YES" : "NO");
  1322. if ((found & USBHOST_EPOUTFOUND) != 0)
  1323. {
  1324. ret = DRVR_EPALLOC(hport->drvr, &epoutdesc, &priv->epout);
  1325. if (ret < 0)
  1326. {
  1327. uerr("ERROR: Failed to allocate interrupt OUT endpoint\n");
  1328. DRVR_EPFREE(hport->drvr, priv->epin);
  1329. return ret;
  1330. }
  1331. }
  1332. uinfo("Endpoints allocated\n");
  1333. return OK;
  1334. }
  1335. /****************************************************************************
  1336. * Name: usbhost_devinit
  1337. *
  1338. * Description:
  1339. * The USB device has been successfully connected. This completes the
  1340. * initialization operations. It is first called after the
  1341. * configuration descriptor has been received.
  1342. *
  1343. * This function is called from the connect() method. This function always
  1344. * executes on the thread of the caller of connect().
  1345. *
  1346. * Input Parameters:
  1347. * priv - A reference to the class instance.
  1348. *
  1349. * Returned Value:
  1350. * None
  1351. *
  1352. ****************************************************************************/
  1353. static inline int usbhost_devinit(FAR struct usbhost_state_s *priv)
  1354. {
  1355. char devname[DEV_NAMELEN];
  1356. int ret;
  1357. /* Set aside a transfer buffer for exclusive
  1358. * use by the keyboard class driver
  1359. */
  1360. ret = usbhost_tdalloc(priv);
  1361. if (ret < 0)
  1362. {
  1363. uerr("ERROR: Failed to allocate transfer buffer\n");
  1364. return ret;
  1365. }
  1366. /* Increment the reference count. This will prevent usbhost_destroy() from
  1367. * being called asynchronously if the device is removed.
  1368. */
  1369. priv->crefs++;
  1370. DEBUGASSERT(priv->crefs == 2);
  1371. /* Start a worker task to poll the USB device. It would be nice to use
  1372. * the NuttX worker thread to do this, but this task needs to wait for
  1373. * events and activities on the worker thread should not involve
  1374. * significant waiting. Having a dedicated thread is more efficient in
  1375. * this sense, but requires more memory resources, primarily for the
  1376. * dedicated stack (CONFIG_HIDKBD_STACKSIZE).
  1377. */
  1378. uinfo("Start poll task\n");
  1379. /* The inputs to a task started by kthread_create() are very awkard for
  1380. * this purpose. They are really designed for command line tasks
  1381. * (argc/argv). So the following is kludge pass binary data when the
  1382. * keyboard poll task is started.
  1383. *
  1384. * First, make sure we have exclusive access to g_priv (what is the
  1385. * likelihood of this being used? About zero, but we protect it anyway).
  1386. */
  1387. ret = usbhost_takesem(&g_exclsem);
  1388. if (ret < 0)
  1389. {
  1390. usbhost_tdfree(priv);
  1391. goto errout;
  1392. }
  1393. g_priv = priv;
  1394. priv->pollpid = kthread_create("kbdpoll", CONFIG_HIDKBD_DEFPRIO,
  1395. CONFIG_HIDKBD_STACKSIZE,
  1396. (main_t)usbhost_kbdpoll,
  1397. (FAR char * const *)NULL);
  1398. if (priv->pollpid < 0)
  1399. {
  1400. /* Failed to started the poll thread...
  1401. * probably due to memory resources
  1402. */
  1403. usbhost_givesem(&g_exclsem);
  1404. ret = (int)priv->pollpid;
  1405. goto errout;
  1406. }
  1407. /* Now wait for the poll task to get properly initialized */
  1408. ret = usbhost_takesem(&g_syncsem);
  1409. usbhost_givesem(&g_exclsem);
  1410. if (ret < 0)
  1411. {
  1412. goto errout;
  1413. }
  1414. /* Register the driver */
  1415. uinfo("Register driver\n");
  1416. usbhost_mkdevname(priv, devname);
  1417. ret = register_driver(devname, &g_hidkbd_fops, 0666, priv);
  1418. /* We now have to be concerned about asynchronous modification of crefs
  1419. * because the driver has been registered.
  1420. */
  1421. errout:
  1422. usbhost_forcetake(&priv->exclsem);
  1423. priv->crefs--;
  1424. usbhost_givesem(&priv->exclsem);
  1425. return ret;
  1426. }
  1427. /****************************************************************************
  1428. * Name: usbhost_getle16
  1429. *
  1430. * Description:
  1431. * Get a (possibly unaligned) 16-bit little endian value.
  1432. *
  1433. * Input Parameters:
  1434. * val - A pointer to the first byte of the little endian value.
  1435. *
  1436. * Returned Value:
  1437. * A uint16_t representing the whole 16-bit integer value
  1438. *
  1439. ****************************************************************************/
  1440. static inline uint16_t usbhost_getle16(const uint8_t *val)
  1441. {
  1442. return (uint16_t)val[1] << 8 | (uint16_t)val[0];
  1443. }
  1444. /****************************************************************************
  1445. * Name: usbhost_putle16
  1446. *
  1447. * Description:
  1448. * Put a (possibly unaligned) 16-bit little endian value.
  1449. *
  1450. * Input Parameters:
  1451. * dest - A pointer to the first byte to save the little endian value.
  1452. * val - The 16-bit value to be saved.
  1453. *
  1454. * Returned Value:
  1455. * None
  1456. *
  1457. ****************************************************************************/
  1458. static void usbhost_putle16(uint8_t *dest, uint16_t val)
  1459. {
  1460. dest[0] = val & 0xff; /* Little endian means LS byte first in byte stream */
  1461. dest[1] = val >> 8;
  1462. }
  1463. /****************************************************************************
  1464. * Name: usbhost_getle32
  1465. *
  1466. * Description:
  1467. * Get a (possibly unaligned) 32-bit little endian value.
  1468. *
  1469. * Input Parameters:
  1470. * dest - A pointer to the first byte to save the big endian value.
  1471. * val - The 32-bit value to be saved.
  1472. *
  1473. * Returned Value:
  1474. * None
  1475. *
  1476. ****************************************************************************/
  1477. static inline uint32_t usbhost_getle32(const uint8_t *val)
  1478. {
  1479. /* Little endian means LS halfword first in byte stream */
  1480. return (uint32_t)usbhost_getle16(&val[2]) << 16 |
  1481. (uint32_t)usbhost_getle16(val);
  1482. }
  1483. /****************************************************************************
  1484. * Name: usbhost_putle32
  1485. *
  1486. * Description:
  1487. * Put a (possibly unaligned) 32-bit little endian value.
  1488. *
  1489. * Input Parameters:
  1490. * dest - A pointer to the first byte to save the little endian value.
  1491. * val - The 32-bit value to be saved.
  1492. *
  1493. * Returned Value:
  1494. * None
  1495. *
  1496. ****************************************************************************/
  1497. #if 0 /* Not used */
  1498. static void usbhost_putle32(uint8_t *dest, uint32_t val)
  1499. {
  1500. /* Little endian means LS halfword first in byte stream */
  1501. usbhost_putle16(dest, (uint16_t)(val & 0xffff));
  1502. usbhost_putle16(dest + 2, (uint16_t)(val >> 16));
  1503. }
  1504. #endif
  1505. /****************************************************************************
  1506. * Name: usbhost_tdalloc
  1507. *
  1508. * Description:
  1509. * Allocate transfer buffer memory.
  1510. *
  1511. * Input Parameters:
  1512. * priv - A reference to the class instance.
  1513. *
  1514. * Returned Value:
  1515. * On success, zero (OK) is returned. On failure, an negated errno value
  1516. * is returned to indicate the nature of the failure.
  1517. *
  1518. ****************************************************************************/
  1519. static int usbhost_tdalloc(FAR struct usbhost_state_s *priv)
  1520. {
  1521. FAR struct usbhost_hubport_s *hport;
  1522. DEBUGASSERT(priv != NULL && priv->usbclass.hport != NULL &&
  1523. priv->tbuffer == NULL);
  1524. hport = priv->usbclass.hport;
  1525. return DRVR_ALLOC(hport->drvr, &priv->tbuffer, &priv->tbuflen);
  1526. }
  1527. /****************************************************************************
  1528. * Name: usbhost_tdfree
  1529. *
  1530. * Description:
  1531. * Free transfer buffer memory.
  1532. *
  1533. * Input Parameters:
  1534. * priv - A reference to the class instance.
  1535. *
  1536. * Returned Value:
  1537. * On success, zero (OK) is returned. On failure, an negated errno value
  1538. * is returned to indicate the nature of the failure.
  1539. *
  1540. ****************************************************************************/
  1541. static int usbhost_tdfree(FAR struct usbhost_state_s *priv)
  1542. {
  1543. FAR struct usbhost_hubport_s *hport;
  1544. int result = OK;
  1545. DEBUGASSERT(priv);
  1546. if (priv->tbuffer)
  1547. {
  1548. DEBUGASSERT(priv->usbclass.hport);
  1549. hport = priv->usbclass.hport;
  1550. result = DRVR_FREE(hport->drvr, priv->tbuffer);
  1551. priv->tbuffer = NULL;
  1552. priv->tbuflen = 0;
  1553. }
  1554. return result;
  1555. }
  1556. /****************************************************************************
  1557. * struct usbhost_registry_s methods
  1558. ****************************************************************************/
  1559. /****************************************************************************
  1560. * Name: usbhost_create
  1561. *
  1562. * Description:
  1563. * This function implements the create() method of struct
  1564. * usbhost_registry_s. The create() method is a callback into the class
  1565. * implementation. It is used to (1) create a new instance of the USB
  1566. * host class state and to (2) bind a USB host driver "session" to the
  1567. * class instance. Use of this create() method will support environments
  1568. * where there may be multiple USB ports and multiple USB devices
  1569. * simultaneously connected.
  1570. *
  1571. * Input Parameters:
  1572. * hport - The hub port that manages the new class instance.
  1573. * id - In the case where the device supports multiple base classes,
  1574. * subclasses, or protocols, this specifies which to configure for.
  1575. *
  1576. * Returned Value:
  1577. * On success, this function will return a non-NULL instance of struct
  1578. * usbhost_class_s that can be used by the USB host driver to communicate
  1579. * with the USB host class. NULL is returned on failure; this function
  1580. * will fail only if the hport input parameter is NULL or if there are
  1581. * insufficient resources to create another USB host class instance.
  1582. *
  1583. ****************************************************************************/
  1584. static FAR struct usbhost_class_s *
  1585. usbhost_create(FAR struct usbhost_hubport_s *hport,
  1586. FAR const struct usbhost_id_s *id)
  1587. {
  1588. FAR struct usbhost_state_s *priv;
  1589. /* Allocate a USB host class instance */
  1590. priv = usbhost_allocclass();
  1591. if (priv)
  1592. {
  1593. /* Initialize the allocated storage class instance */
  1594. memset(priv, 0, sizeof(struct usbhost_state_s));
  1595. /* Assign a device number to this class instance */
  1596. if (usbhost_allocdevno(priv) == OK)
  1597. {
  1598. /* Initialize class method function pointers */
  1599. priv->usbclass.hport = hport;
  1600. priv->usbclass.connect = usbhost_connect;
  1601. priv->usbclass.disconnected = usbhost_disconnected;
  1602. /* The initial reference count is 1... One reference is held by
  1603. * the driver's usbhost_kbdpoll() task.
  1604. */
  1605. priv->crefs = 1;
  1606. /* Initialize semaphores */
  1607. nxsem_init(&priv->exclsem, 0, 1);
  1608. nxsem_init(&priv->waitsem, 0, 0);
  1609. /* The waitsem semaphore is used for signaling and, hence, should
  1610. * not have priority inheritance enabled.
  1611. */
  1612. nxsem_set_protocol(&priv->waitsem, SEM_PRIO_NONE);
  1613. /* Return the instance of the USB keyboard class driver */
  1614. return &priv->usbclass;
  1615. }
  1616. }
  1617. /* An error occurred. Free the allocation and return NULL on all failures */
  1618. if (priv)
  1619. {
  1620. usbhost_freeclass(priv);
  1621. }
  1622. return NULL;
  1623. }
  1624. /****************************************************************************
  1625. * Name: usbhost_connect
  1626. *
  1627. * Description:
  1628. * This function implements the connect() method of struct
  1629. * usbhost_class_s. This method is a callback into the class
  1630. * implementation. It is used to provide the device's configuration
  1631. * descriptor to the class so that the class may initialize properly
  1632. *
  1633. * Input Parameters:
  1634. * usbclass - The USB host class entry previously obtained from a call
  1635. * to create().
  1636. * configdesc - A pointer to a uint8_t buffer container the configuration
  1637. * descriptor.
  1638. * desclen - The length in bytes of the configuration descriptor.
  1639. *
  1640. * Returned Value:
  1641. * On success, zero (OK) is returned. On a failure, a negated errno value
  1642. * is returned indicating the nature of the failure
  1643. *
  1644. * NOTE that the class instance remains valid upon return with a failure.
  1645. * It is the responsibility of the higher level enumeration logic to call
  1646. * CLASS_DISCONNECTED to free up the class driver resources.
  1647. *
  1648. * Assumptions:
  1649. * - This function will *not* be called from an interrupt handler.
  1650. * - If this function returns an error, the USB host controller driver
  1651. * must call to DISCONNECTED method to recover from the error
  1652. *
  1653. ****************************************************************************/
  1654. static int usbhost_connect(FAR struct usbhost_class_s *usbclass,
  1655. FAR const uint8_t *configdesc, int desclen)
  1656. {
  1657. FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)usbclass;
  1658. int ret;
  1659. DEBUGASSERT(priv != NULL &&
  1660. configdesc != NULL &&
  1661. desclen >= sizeof(struct usb_cfgdesc_s));
  1662. /* Parse the configuration descriptor to get the endpoints */
  1663. ret = usbhost_cfgdesc(priv, configdesc, desclen);
  1664. if (ret < 0)
  1665. {
  1666. uerr("ERROR: usbhost_cfgdesc() failed: %d\n", ret);
  1667. }
  1668. else
  1669. {
  1670. /* Now configure the device and register the NuttX driver */
  1671. ret = usbhost_devinit(priv);
  1672. if (ret < 0)
  1673. {
  1674. uerr("ERROR: usbhost_devinit() failed: %d\n", ret);
  1675. }
  1676. }
  1677. /* ERROR handling: Do nothing. If we return and error during connection,
  1678. * the driver is required to call the DISCONNECT method. Possibilities:
  1679. *
  1680. * - Failure occurred before the kbdpoll task was started successfully.
  1681. * In this case, the disconnection will have to be handled on the worker
  1682. * task.
  1683. * - Failure occurred after the kbdpoll task was started successfully. In
  1684. * this case, the disconnection can be performed on the kbdpoll thread.
  1685. */
  1686. return ret;
  1687. }
  1688. /****************************************************************************
  1689. * Name: usbhost_disconnected
  1690. *
  1691. * Description:
  1692. * This function implements the disconnected() method of struct
  1693. * usbhost_class_s. This method is a callback into the class
  1694. * implementation. It is used to inform the class that the USB device has
  1695. * been disconnected.
  1696. *
  1697. * Input Parameters:
  1698. * usbclass - The USB host class entry previously obtained from a call to
  1699. * create().
  1700. *
  1701. * Returned Value:
  1702. * On success, zero (OK) is returned. On a failure, a negated errno value
  1703. * is returned indicating the nature of the failure
  1704. *
  1705. * Assumptions:
  1706. * This function may be called from an interrupt handler.
  1707. *
  1708. ****************************************************************************/
  1709. static int usbhost_disconnected(struct usbhost_class_s *usbclass)
  1710. {
  1711. FAR struct usbhost_state_s *priv = (FAR struct usbhost_state_s *)usbclass;
  1712. DEBUGASSERT(priv != NULL);
  1713. /* Set an indication to any users of the keyboard device that the device
  1714. * is no longer available.
  1715. */
  1716. priv->disconnected = true;
  1717. uinfo("Disconnected\n");
  1718. /* Is there a thread waiting for keyboard data that will never come? */
  1719. if (priv->waiting)
  1720. {
  1721. /* Yes.. wake it up */
  1722. usbhost_givesem(&priv->waitsem);
  1723. priv->waiting = false;
  1724. }
  1725. /* Possibilities:
  1726. *
  1727. * - Failure occurred before the kbdpoll task was started successfully.
  1728. * In this case, the disconnection will have to be handled on the worker
  1729. * task.
  1730. * - Failure occurred after the kbdpoll task was started successfully. In
  1731. * this case, the disconnection can be performed on the kbdpoll thread.
  1732. */
  1733. if (priv->polling)
  1734. {
  1735. /* The polling task is still alive. Signal the keyboard polling task.
  1736. * When that task wakes up, it will decrement the reference count and,
  1737. * perhaps, destroy the class instance. Then it will exit.
  1738. */
  1739. nxsig_kill(priv->pollpid, SIGALRM);
  1740. }
  1741. else
  1742. {
  1743. /* In the case where the failure occurs before the polling task was
  1744. * started. Now what? We are probably executing from an interrupt
  1745. * handler here. We will use the worker thread. This is kind of
  1746. * wasteful and begs for a re-design.
  1747. */
  1748. DEBUGASSERT(priv->work.worker == NULL);
  1749. work_queue(HPWORK, &priv->work, usbhost_destroy, priv, 0);
  1750. }
  1751. return OK;
  1752. }
  1753. /****************************************************************************
  1754. * Name: usbhost_open
  1755. *
  1756. * Description:
  1757. * Standard character driver open method.
  1758. *
  1759. ****************************************************************************/
  1760. static int usbhost_open(FAR struct file *filep)
  1761. {
  1762. FAR struct inode *inode;
  1763. FAR struct usbhost_state_s *priv;
  1764. irqstate_t flags;
  1765. int ret;
  1766. uinfo("Entry\n");
  1767. DEBUGASSERT(filep && filep->f_inode);
  1768. inode = filep->f_inode;
  1769. priv = inode->i_private;
  1770. /* Make sure that we have exclusive access to the private data structure */
  1771. DEBUGASSERT(priv && priv->crefs > 0 && priv->crefs < USBHOST_MAX_CREFS);
  1772. ret = usbhost_takesem(&priv->exclsem);
  1773. if (ret < 0)
  1774. {
  1775. return ret;
  1776. }
  1777. /* Check if the keyboard device is still connected. We need to disable
  1778. * interrupts momentarily to assure that there are no asynchronous
  1779. * disconnect events.
  1780. */
  1781. flags = enter_critical_section();
  1782. if (priv->disconnected)
  1783. {
  1784. /* No... the driver is no longer bound to the class. That means that
  1785. * the USB storage device is no longer connected. Refuse any further
  1786. * attempts to open the driver.
  1787. */
  1788. ret = -ENODEV;
  1789. }
  1790. else
  1791. {
  1792. /* Otherwise, just increment the reference count on the driver */
  1793. priv->crefs++;
  1794. priv->open = true;
  1795. ret = OK;
  1796. }
  1797. leave_critical_section(flags);
  1798. usbhost_givesem(&priv->exclsem);
  1799. return ret;
  1800. }
  1801. /****************************************************************************
  1802. * Name: usbhost_close
  1803. *
  1804. * Description:
  1805. * Standard character driver close method.
  1806. *
  1807. ****************************************************************************/
  1808. static int usbhost_close(FAR struct file *filep)
  1809. {
  1810. FAR struct inode *inode;
  1811. FAR struct usbhost_state_s *priv;
  1812. irqstate_t flags;
  1813. int ret;
  1814. uinfo("Entry\n");
  1815. DEBUGASSERT(filep && filep->f_inode);
  1816. inode = filep->f_inode;
  1817. priv = inode->i_private;
  1818. /* Decrement the reference count on the driver */
  1819. DEBUGASSERT(priv->crefs >= 1);
  1820. ret = usbhost_takesem(&priv->exclsem);
  1821. if (ret < 0)
  1822. {
  1823. return ret;
  1824. }
  1825. /* We need to disable interrupts momentarily to assure that there are no
  1826. * asynchronous poll or disconnect events.
  1827. */
  1828. flags = enter_critical_section();
  1829. priv->crefs--;
  1830. /* Check if the USB mouse device is still connected. If the device is
  1831. * no longer connected, then unregister the driver and free the driver
  1832. * class instance.
  1833. */
  1834. if (priv->disconnected)
  1835. {
  1836. /* If the reference count is one or less then there are two
  1837. * possibilities:
  1838. *
  1839. * 1) It might be zero meaning that the polling thread has already
  1840. * exited and decremented its count.
  1841. * 2) If might be one meaning either that (a) the polling thread is
  1842. * still running and still holds a count, or (b) the polling thread
  1843. * has exited, but there is still an outstanding open reference.
  1844. */
  1845. if (priv->crefs == 0 || (priv->crefs == 1 && priv->polling))
  1846. {
  1847. /* Yes.. In either case, then the driver is no longer open */
  1848. priv->open = false;
  1849. priv->headndx = 0;
  1850. priv->tailndx = 0;
  1851. /* Check if the USB keyboard device is still connected. */
  1852. if (priv->crefs == 0)
  1853. {
  1854. /* The polling thread is no longer running */
  1855. DEBUGASSERT(!priv->polling);
  1856. /* If the device is no longer connected, unregister the driver
  1857. * and free the driver class instance.
  1858. */
  1859. usbhost_destroy(priv);
  1860. /* Skip giving the semaphore... it is no longer valid */
  1861. leave_critical_section(flags);
  1862. return OK;
  1863. }
  1864. else /* if (priv->crefs == 1) */
  1865. {
  1866. /* The polling thread is still running. Signal it so that it
  1867. * will wake up and call usbhost_destroy(). The particular
  1868. * signal that we use does not matter in this case.
  1869. */
  1870. nxsig_kill(priv->pollpid, SIGALRM);
  1871. }
  1872. }
  1873. }
  1874. usbhost_givesem(&priv->exclsem);
  1875. leave_critical_section(flags);
  1876. return OK;
  1877. }
  1878. /****************************************************************************
  1879. * Name: usbhost_read
  1880. *
  1881. * Description:
  1882. * Standard character driver read method.
  1883. *
  1884. ****************************************************************************/
  1885. static ssize_t usbhost_read(FAR struct file *filep, FAR char *buffer,
  1886. size_t len)
  1887. {
  1888. FAR struct inode *inode;
  1889. FAR struct usbhost_state_s *priv;
  1890. size_t nbytes;
  1891. unsigned int tail;
  1892. int ret;
  1893. uinfo("Entry\n");
  1894. DEBUGASSERT(filep && filep->f_inode && buffer);
  1895. inode = filep->f_inode;
  1896. priv = inode->i_private;
  1897. /* Make sure that we have exclusive access to the private data structure */
  1898. DEBUGASSERT(priv && priv->crefs > 0 && priv->crefs < USBHOST_MAX_CREFS);
  1899. ret = usbhost_takesem(&priv->exclsem);
  1900. if (ret < 0)
  1901. {
  1902. return ret;
  1903. }
  1904. /* Check if the keyboard is still connected. We need to disable interrupts
  1905. * momentarily to assure that there are no asynchronous disconnect events.
  1906. */
  1907. if (priv->disconnected)
  1908. {
  1909. /* No... the driver is no longer bound to the class. That means that
  1910. * the USB keyboard is no longer connected. Refuse any further
  1911. * attempts to access the driver.
  1912. */
  1913. ret = -ENODEV;
  1914. }
  1915. else
  1916. {
  1917. /* Is there keyboard data now? */
  1918. while (priv->tailndx == priv->headndx)
  1919. {
  1920. /* No.. were we open non-blocking? */
  1921. if (filep->f_oflags & O_NONBLOCK)
  1922. {
  1923. /* Yes.. then return a failure */
  1924. ret = -EAGAIN;
  1925. goto errout;
  1926. }
  1927. /* Wait for data to be available */
  1928. uinfo("Waiting...\n");
  1929. priv->waiting = true;
  1930. usbhost_givesem(&priv->exclsem);
  1931. ret = usbhost_takesem(&priv->waitsem);
  1932. if (ret < 0)
  1933. {
  1934. return ret;
  1935. }
  1936. ret = usbhost_takesem(&priv->exclsem);
  1937. if (ret < 0)
  1938. {
  1939. return ret;
  1940. }
  1941. /* Did the keyboard become disconnected while we were waiting */
  1942. if (priv->disconnected)
  1943. {
  1944. ret = -ENODEV;
  1945. goto errout;
  1946. }
  1947. }
  1948. /* Read data from our internal buffer of received characters */
  1949. for (tail = priv->tailndx, nbytes = 0;
  1950. tail != priv->headndx && nbytes < len;
  1951. nbytes++)
  1952. {
  1953. /* Copy the next keyboard character into the user buffer */
  1954. *buffer++ = priv->kbdbuffer[tail];
  1955. /* Handle wrap-around of the tail index */
  1956. if (++tail >= CONFIG_HIDKBD_BUFSIZE)
  1957. {
  1958. tail = 0;
  1959. }
  1960. }
  1961. ret = nbytes;
  1962. /* Update the tail index (perhaps marking the buffer empty) */
  1963. priv->tailndx = tail;
  1964. }
  1965. errout:
  1966. usbhost_givesem(&priv->exclsem);
  1967. return (ssize_t)ret;
  1968. }
  1969. /****************************************************************************
  1970. * Name: usbhost_write
  1971. *
  1972. * Description:
  1973. * Standard character driver write method.
  1974. *
  1975. ****************************************************************************/
  1976. static ssize_t usbhost_write(FAR struct file *filep, FAR const char *buffer,
  1977. size_t len)
  1978. {
  1979. /* We won't try to write to the keyboard */
  1980. return -ENOSYS;
  1981. }
  1982. /****************************************************************************
  1983. * Name: usbhost_poll
  1984. *
  1985. * Description:
  1986. * Standard character driver poll method.
  1987. *
  1988. ****************************************************************************/
  1989. static int usbhost_poll(FAR struct file *filep, FAR struct pollfd *fds,
  1990. bool setup)
  1991. {
  1992. FAR struct inode *inode;
  1993. FAR struct usbhost_state_s *priv;
  1994. int ret;
  1995. int i;
  1996. uinfo("Entry\n");
  1997. DEBUGASSERT(filep && filep->f_inode && fds);
  1998. inode = filep->f_inode;
  1999. priv = inode->i_private;
  2000. /* Make sure that we have exclusive access to the private data structure */
  2001. DEBUGASSERT(priv);
  2002. ret = usbhost_takesem(&priv->exclsem);
  2003. if (ret < 0)
  2004. {
  2005. return ret;
  2006. }
  2007. /* Check if the keyboard is still connected. We need to disable interrupts
  2008. * momentarily to assure that there are no asynchronous disconnect events.
  2009. */
  2010. if (priv->disconnected)
  2011. {
  2012. /* No... the driver is no longer bound to the class. That means that
  2013. * the USB keyboard is no longer connected. Refuse any further
  2014. * attempts to access the driver.
  2015. */
  2016. ret = -ENODEV;
  2017. }
  2018. else if (setup)
  2019. {
  2020. /* This is a request to set up the poll. Find an available slot for
  2021. * the poll structure reference
  2022. */
  2023. for (i = 0; i < CONFIG_HIDKBD_NPOLLWAITERS; i++)
  2024. {
  2025. /* Find an available slot */
  2026. if (!priv->fds[i])
  2027. {
  2028. /* Bind the poll structure and this slot */
  2029. priv->fds[i] = fds;
  2030. fds->priv = &priv->fds[i];
  2031. break;
  2032. }
  2033. }
  2034. if (i >= CONFIG_HIDKBD_NPOLLWAITERS)
  2035. {
  2036. fds->priv = NULL;
  2037. ret = -EBUSY;
  2038. goto errout;
  2039. }
  2040. /* Should we immediately notify on any of the requested events? Notify
  2041. * the POLLIN event if there is buffered keyboard data.
  2042. */
  2043. if (priv->headndx != priv->tailndx)
  2044. {
  2045. usbhost_pollnotify(priv);
  2046. }
  2047. }
  2048. else
  2049. {
  2050. /* This is a request to tear down the poll. */
  2051. struct pollfd **slot = (struct pollfd **)fds->priv;
  2052. DEBUGASSERT(slot);
  2053. /* Remove all memory of the poll setup */
  2054. *slot = NULL;
  2055. fds->priv = NULL;
  2056. }
  2057. errout:
  2058. nxsem_post(&priv->exclsem);
  2059. return ret;
  2060. }
  2061. /****************************************************************************
  2062. * Public Functions
  2063. ****************************************************************************/
  2064. /****************************************************************************
  2065. * Name: usbhost_kbdinit
  2066. *
  2067. * Description:
  2068. * Initialize the USB storage HID keyboard class driver. This function
  2069. * should be called be platform-specific code in order to initialize and
  2070. * register support for the USB host HID keyboard class device.
  2071. *
  2072. * Input Parameters:
  2073. * None
  2074. *
  2075. * Returned Value:
  2076. * On success this function will return zero (OK); A negated errno value
  2077. * will be returned on failure.
  2078. *
  2079. ****************************************************************************/
  2080. int usbhost_kbdinit(void)
  2081. {
  2082. /* Perform any one-time initialization of the class implementation */
  2083. nxsem_init(&g_exclsem, 0, 1);
  2084. nxsem_init(&g_syncsem, 0, 0);
  2085. /* The g_syncsem semaphore is used for signaling and, hence, should not
  2086. * have priority inheritance enabled.
  2087. */
  2088. nxsem_set_protocol(&g_syncsem, SEM_PRIO_NONE);
  2089. /* Advertise our availability to support (certain) devices */
  2090. return usbhost_registerclass(&g_hidkbd);
  2091. }
  2092. #endif /* CONFIG_USBHOST)&& !CONFIG_USBHOST_INT_DISABLE */