12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348 |
- /****************************************************************************
- * drivers/usbdev/pl2303.c
- *
- * Copyright (C) 2008-2013 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- *
- * This logic emulates the Prolific PL2303 serial/USB converter
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
- /****************************************************************************
- * Included Files
- ****************************************************************************/
- #include <nuttx/config.h>
- #include <sys/types.h>
- #include <stdint.h>
- #include <stdbool.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <semaphore.h>
- #include <string.h>
- #include <errno.h>
- #include <queue.h>
- #include <debug.h>
- #include <nuttx/kmalloc.h>
- #include <nuttx/arch.h>
- #include <nuttx/serial/serial.h>
- #include <nuttx/usb/usb.h>
- #include <nuttx/usb/usbdev.h>
- #include <nuttx/usb/usbdev_trace.h>
- /****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
- /* Configuration ************************************************************/
- /* Number of requests in the write queue */
- #ifndef CONFIG_PL2303_NWRREQS
- # define CONFIG_PL2303_NWRREQS 4
- #endif
- /* Number of requests in the read queue */
- #ifndef CONFIG_PL2303_NRDREQS
- # define CONFIG_PL2303_NRDREQS 4
- #endif
- /* Logical endpoint numbers / max packet sizes */
- #ifndef CONFIG_PL2303_EPINTIN
- # warning "EPINTIN not defined in the configuration"
- # define CONFIG_PL2303_EPINTIN 1
- #endif
- #ifndef CONFIG_PL2303_EPBULKOUT
- # warning "EPBULKOUT not defined in the configuration"
- # define CONFIG_PL2303_EPBULKOUT 2
- #endif
- #ifndef CONFIG_PL2303_EPBULKIN
- # warning "EPBULKIN not defined in the configuration"
- # define CONFIG_PL2303_EPBULKIN 3
- #endif
- /* Packet and request buffer sizes */
- #ifndef CONFIG_PL2303_EP0MAXPACKET
- # define CONFIG_PL2303_EP0MAXPACKET 64
- #endif
- /* Ideally, the BULKOUT request size should *not* be the same size as the
- * maxpacket size. That is because IN transfers of exactly the maxpacket
- * size will be followed by a NULL packet. The BULKOUT request buffer
- * size, on the other hand, is always the same as the maxpacket size.
- */
- #ifndef CONFIG_PL2303_BULKIN_REQLEN
- # define CONFIG_PL2303_BULKIN_REQLEN 96
- #endif
- /* Vendor and product IDs and strings */
- #ifndef CONFIG_PL2303_VENDORID
- # define CONFIG_PL2303_VENDORID 0x067b
- #endif
- #ifndef CONFIG_PL2303_PRODUCTID
- # define CONFIG_PL2303_PRODUCTID 0x2303
- #endif
- #ifndef CONFIG_PL2303_VENDORSTR
- # warning "No Vendor string specified"
- # define CONFIG_PL2303_VENDORSTR "NuttX"
- #endif
- #ifndef CONFIG_PL2303_PRODUCTSTR
- # warning "No Product string specified"
- # define CONFIG_PL2303_PRODUCTSTR "USBdev Serial"
- #endif
- #undef CONFIG_PL2303_SERIALSTR
- #define CONFIG_PL2303_SERIALSTR "0"
- #undef CONFIG_PL2303_CONFIGSTR
- #define CONFIG_PL2303_CONFIGSTR "Bulk"
- /* USB Controller */
- #ifndef CONFIG_USBDEV_SELFPOWERED
- # define SELFPOWERED USB_CONFIG_ATTR_SELFPOWER
- #else
- # define SELFPOWERED (0)
- #endif
- #ifndef CONFIG_USBDEV_REMOTEWAKEUP
- # define REMOTEWAKEUP USB_CONFIG_ATTR_WAKEUP
- #else
- # define REMOTEWAKEUP (0)
- #endif
- #ifndef CONFIG_USBDEV_MAXPOWER
- # define CONFIG_USBDEV_MAXPOWER 100
- #endif
- /* Descriptors ****************************************************************/
- /* These settings are not modifiable via the NuttX configuration */
- #define PL2303_VERSIONNO (0x0202) /* Device version number */
- #define PL2303_CONFIGIDNONE (0) /* Config ID means to return to address mode */
- #define PL2303_CONFIGID (1) /* The only supported configuration ID */
- #define PL2303_NCONFIGS (1) /* Number of configurations supported */
- #define PL2303_INTERFACEID (0)
- #define PL2303_ALTINTERFACEID (0)
- #define PL2303_NINTERFACES (1) /* Number of interfaces in the configuration */
- #define PL2303_NENDPOINTS (3) /* Number of endpoints in the interface */
- /* Endpoint configuration */
- #define PL2303_EPINTIN_ADDR (USB_DIR_IN|CONFIG_PL2303_EPINTIN)
- #define PL2303_EPINTIN_ATTR (USB_EP_ATTR_XFER_INT)
- #define PL2303_EPINTIN_MXPACKET (10)
- #define PL2303_EPOUTBULK_ADDR (CONFIG_PL2303_EPBULKOUT)
- #define PL2303_EPOUTBULK_ATTR (USB_EP_ATTR_XFER_BULK)
- #define PL2303_EPINBULK_ADDR (USB_DIR_IN|CONFIG_PL2303_EPBULKIN)
- #define PL2303_EPINBULK_ATTR (USB_EP_ATTR_XFER_BULK)
- /* String language */
- #define PL2303_STR_LANGUAGE (0x0409) /* en-us */
- /* Descriptor strings */
- #define PL2303_MANUFACTURERSTRID (1)
- #define PL2303_PRODUCTSTRID (2)
- #define PL2303_SERIALSTRID (3)
- #define PL2303_CONFIGSTRID (4)
- /* Buffer big enough for any of our descriptors */
- #define PL2303_MXDESCLEN (64)
- /* Vender specific control requests *******************************************/
- #define PL2303_CONTROL_TYPE (0x20)
- #define PL2303_SETLINEREQUEST (0x20) /* OUT, Recipient interface */
- #define PL2303_GETLINEREQUEST (0x21) /* IN, Recipient interface */
- #define PL2303_SETCONTROLREQUEST (0x22) /* OUT, Recipient interface */
- #define PL2303_BREAKREQUEST (0x23) /* OUT, Recipient interface */
- /* Vendor read/write */
- #define PL2303_RWREQUEST_TYPE (0x40)
- #define PL2303_RWREQUEST (0x01) /* IN/OUT, Recipient device */
- /* Misc Macros ****************************************************************/
- /* min/max macros */
- #ifndef min
- # define min(a,b) ((a)<(b)?(a):(b))
- #endif
- #ifndef max
- # define max(a,b) ((a)>(b)?(a):(b))
- #endif
- /* Trace values *************************************************************/
- #define PL2303_CLASSAPI_SETUP TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_SETUP)
- #define PL2303_CLASSAPI_SHUTDOWN TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_SHUTDOWN)
- #define PL2303_CLASSAPI_ATTACH TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_ATTACH)
- #define PL2303_CLASSAPI_DETACH TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_DETACH)
- #define PL2303_CLASSAPI_IOCTL TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_IOCTL)
- #define PL2303_CLASSAPI_RECEIVE TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_RECEIVE)
- #define PL2303_CLASSAPI_RXINT TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_RXINT)
- #define PL2303_CLASSAPI_RXAVAILABLE TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_RXAVAILABLE)
- #define PL2303_CLASSAPI_SEND TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_SEND)
- #define PL2303_CLASSAPI_TXINT TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_TXINT)
- #define PL2303_CLASSAPI_TXREADY TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_TXREADY)
- #define PL2303_CLASSAPI_TXEMPTY TRACE_EVENT(TRACE_CLASSAPI_ID, USBSER_TRACECLASSAPI_TXEMPTY)
- /****************************************************************************
- * Private Types
- ****************************************************************************/
- /* Container to support a list of requests */
- struct pl2303_req_s
- {
- FAR struct pl2303_req_s *flink; /* Implements a singly linked list */
- FAR struct usbdev_req_s *req; /* The contained request */
- };
- /* This structure describes the internal state of the driver */
- struct pl2303_dev_s
- {
- FAR struct uart_dev_s serdev; /* Serial device structure */
- FAR struct usbdev_s *usbdev; /* usbdev driver pointer */
- uint8_t config; /* Configuration number */
- uint8_t nwrq; /* Number of queue write requests (in reqlist)*/
- uint8_t nrdq; /* Number of queue read requests (in epbulkout) */
- bool rxenabled; /* true: UART RX "interrupts" enabled */
- uint8_t linest[7]; /* Fake line status */
- int16_t rxhead; /* Working head; used when rx int disabled */
- FAR struct usbdev_ep_s *epintin; /* Interrupt IN endpoint structure */
- FAR struct usbdev_ep_s *epbulkin; /* Bulk IN endpoint structure */
- FAR struct usbdev_ep_s *epbulkout; /* Bulk OUT endpoint structure */
- FAR struct usbdev_req_s *ctrlreq; /* Control request */
- struct sq_queue_s reqlist; /* List of write request containers */
- /* Pre-allocated write request containers. The write requests will
- * be linked in a free list (reqlist), and used to send requests to
- * EPBULKIN; Read requests will be queued in the EBULKOUT.
- */
- struct pl2303_req_s wrreqs[CONFIG_PL2303_NWRREQS];
- struct pl2303_req_s rdreqs[CONFIG_PL2303_NWRREQS];
- /* Serial I/O buffers */
- char rxbuffer[CONFIG_PL2303_RXBUFSIZE];
- char txbuffer[CONFIG_PL2303_TXBUFSIZE];
- };
- /* The internal version of the class driver */
- struct pl2303_driver_s
- {
- struct usbdevclass_driver_s drvr;
- FAR struct pl2303_dev_s *dev;
- };
- /* This is what is allocated */
- struct pl2303_alloc_s
- {
- struct pl2303_dev_s dev;
- struct pl2303_driver_s drvr;
- };
- /****************************************************************************
- * Private Function Prototypes
- ****************************************************************************/
- /* Transfer helpers *********************************************************/
- static uint16_t usbclass_fillrequest(FAR struct pl2303_dev_s *priv,
- uint8_t *reqbuf, uint16_t reqlen);
- static int usbclass_sndpacket(FAR struct pl2303_dev_s *priv);
- static inline int usbclass_recvpacket(FAR struct pl2303_dev_s *priv,
- uint8_t *reqbuf, uint16_t reqlen);
- /* Request helpers *********************************************************/
- static struct usbdev_req_s *usbclass_allocreq(FAR struct usbdev_ep_s *ep,
- uint16_t len);
- static void usbclass_freereq(FAR struct usbdev_ep_s *ep,
- FAR struct usbdev_req_s *req);
- /* Configuration ***********************************************************/
- static int usbclass_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc);
- #ifdef CONFIG_USBDEV_DUALSPEED
- static void usbclass_mkepbulkdesc(const struct usb_epdesc_s *indesc,
- uint16_t mxpacket, struct usb_epdesc_s *outdesc);
- static int16_t usbclass_mkcfgdesc(uint8_t *buf, uint8_t speed, uint8_t type);
- #else
- static int16_t usbclass_mkcfgdesc(uint8_t *buf);
- #endif
- static void usbclass_resetconfig(FAR struct pl2303_dev_s *priv);
- static int usbclass_setconfig(FAR struct pl2303_dev_s *priv,
- uint8_t config);
- /* Completion event handlers ***********************************************/
- static void usbclass_ep0incomplete(FAR struct usbdev_ep_s *ep,
- FAR struct usbdev_req_s *req);
- static void usbclass_rdcomplete(FAR struct usbdev_ep_s *ep,
- FAR struct usbdev_req_s *req);
- static void usbclass_wrcomplete(FAR struct usbdev_ep_s *ep,
- FAR struct usbdev_req_s *req);
- /* USB class device ********************************************************/
- static int usbclass_bind(FAR struct usbdevclass_driver_s *driver,
- FAR struct usbdev_s *dev);
- static void usbclass_unbind(FAR struct usbdevclass_driver_s *driver,
- FAR struct usbdev_s *dev);
- static int usbclass_setup(FAR struct usbdevclass_driver_s *driver,
- FAR struct usbdev_s *dev,
- FAR const struct usb_ctrlreq_s *ctrl, FAR uint8_t *dataout,
- size_t outlen);
- static void usbclass_disconnect(FAR struct usbdevclass_driver_s *driver,
- FAR struct usbdev_s *dev);
- #ifdef CONFIG_SERIAL_REMOVABLE
- static void usbclass_suspend(FAR struct usbdevclass_driver_s *driver,
- FAR struct usbdev_s *dev);
- static void usbclass_resume(FAR struct usbdevclass_driver_s *driver,
- FAR struct usbdev_s *dev);
- #endif
- /* Serial port *************************************************************/
- static int usbser_setup(FAR struct uart_dev_s *dev);
- static void usbser_shutdown(FAR struct uart_dev_s *dev);
- static int usbser_attach(FAR struct uart_dev_s *dev);
- static void usbser_detach(FAR struct uart_dev_s *dev);
- static void usbser_rxint(FAR struct uart_dev_s *dev, bool enable);
- static void usbser_txint(FAR struct uart_dev_s *dev, bool enable);
- static bool usbser_txempty(FAR struct uart_dev_s *dev);
- /****************************************************************************
- * Private Variables
- ****************************************************************************/
- /* USB class device ********************************************************/
- static const struct usbdevclass_driverops_s g_driverops =
- {
- usbclass_bind, /* bind */
- usbclass_unbind, /* unbind */
- usbclass_setup, /* setup */
- usbclass_disconnect, /* disconnect */
- #ifdef CONFIG_SERIAL_REMOVABLE
- usbclass_suspend, /* suspend */
- usbclass_resume, /* resume */
- #else
- NULL, /* suspend */
- NULL, /* resume */
- #endif
- };
- /* Serial port *************************************************************/
- static const struct uart_ops_s g_uartops =
- {
- usbser_setup, /* setup */
- usbser_shutdown, /* shutdown */
- usbser_attach, /* attach */
- usbser_detach, /* detach */
- NULL, /* ioctl */
- NULL, /* receive */
- usbser_rxint, /* rxinit */
- NULL, /* rxavailable */
- NULL, /* send */
- usbser_txint, /* txinit */
- NULL, /* txready */
- usbser_txempty /* txempty */
- };
- /* USB descriptor templates these will be copied and modified **************/
- static const struct usb_devdesc_s g_devdesc =
- {
- USB_SIZEOF_DEVDESC, /* len */
- USB_DESC_TYPE_DEVICE, /* type */
- {LSBYTE(0x0200), MSBYTE(0x0200)}, /* usb */
- USB_CLASS_PER_INTERFACE, /* classid */
- 0, /* subclass */
- 0, /* protocol */
- CONFIG_PL2303_EP0MAXPACKET, /* maxpacketsize */
- { LSBYTE(CONFIG_PL2303_VENDORID), /* vendor */
- MSBYTE(CONFIG_PL2303_VENDORID) },
- { LSBYTE(CONFIG_PL2303_PRODUCTID), /* product */
- MSBYTE(CONFIG_PL2303_PRODUCTID) },
- { LSBYTE(PL2303_VERSIONNO), /* device */
- MSBYTE(PL2303_VERSIONNO) },
- PL2303_MANUFACTURERSTRID, /* imfgr */
- PL2303_PRODUCTSTRID, /* iproduct */
- PL2303_SERIALSTRID, /* serno */
- PL2303_NCONFIGS /* nconfigs */
- };
- static const struct usb_cfgdesc_s g_cfgdesc =
- {
- USB_SIZEOF_CFGDESC, /* len */
- USB_DESC_TYPE_CONFIG, /* type */
- {0, 0}, /* totallen -- to be provided */
- PL2303_NINTERFACES, /* ninterfaces */
- PL2303_CONFIGID, /* cfgvalue */
- PL2303_CONFIGSTRID, /* icfg */
- USB_CONFIG_ATTR_ONE|SELFPOWERED|REMOTEWAKEUP, /* attr */
- (CONFIG_USBDEV_MAXPOWER + 1) / 2 /* mxpower */
- };
- static const struct usb_ifdesc_s g_ifdesc =
- {
- USB_SIZEOF_IFDESC, /* len */
- USB_DESC_TYPE_INTERFACE, /* type */
- 0, /* ifno */
- 0, /* alt */
- PL2303_NENDPOINTS, /* neps */
- USB_CLASS_VENDOR_SPEC, /* classid */
- 0, /* subclass */
- 0, /* protocol */
- PL2303_CONFIGSTRID /* iif */
- };
- static const struct usb_epdesc_s g_epintindesc =
- {
- USB_SIZEOF_EPDESC, /* len */
- USB_DESC_TYPE_ENDPOINT, /* type */
- PL2303_EPINTIN_ADDR, /* addr */
- PL2303_EPINTIN_ATTR, /* attr */
- { LSBYTE(PL2303_EPINTIN_MXPACKET), /* maxpacket */
- MSBYTE(PL2303_EPINTIN_MXPACKET) },
- 1 /* interval */
- };
- static const struct usb_epdesc_s g_epbulkoutdesc =
- {
- USB_SIZEOF_EPDESC, /* len */
- USB_DESC_TYPE_ENDPOINT, /* type */
- PL2303_EPOUTBULK_ADDR, /* addr */
- PL2303_EPOUTBULK_ATTR, /* attr */
- { LSBYTE(64), MSBYTE(64) }, /* maxpacket -- might change to 512*/
- 0 /* interval */
- };
- static const struct usb_epdesc_s g_epbulkindesc =
- {
- USB_SIZEOF_EPDESC, /* len */
- USB_DESC_TYPE_ENDPOINT, /* type */
- PL2303_EPINBULK_ADDR, /* addr */
- PL2303_EPINBULK_ATTR, /* attr */
- { LSBYTE(64), MSBYTE(64) }, /* maxpacket -- might change to 512*/
- 0 /* interval */
- };
- #ifdef CONFIG_USBDEV_DUALSPEED
- static const struct usb_qualdesc_s g_qualdesc =
- {
- USB_SIZEOF_QUALDESC, /* len */
- USB_DESC_TYPE_DEVICEQUALIFIER, /* type */
- {LSBYTE(0x0200), MSBYTE(0x0200) }, /* USB */
- USB_CLASS_VENDOR_SPEC, /* classid */
- 0, /* subclass */
- 0, /* protocol */
- CONFIG_PL2303_EP0MAXPACKET, /* mxpacketsize */
- PL2303_NCONFIGS, /* nconfigs */
- 0, /* reserved */
- };
- #endif
- /****************************************************************************
- * Private Functions
- ****************************************************************************/
- /************************************************************************************
- * Name: usbclass_fillrequest
- *
- * Description:
- * If there is data to send it is copied to the given buffer. Called either
- * to initiate the first write operation, or from the completion interrupt handler
- * service consecutive write operations.
- *
- * NOTE: The USB serial driver does not use the serial drivers uart_xmitchars()
- * API. That logic is essentially duplicated here because unlike UART hardware,
- * we need to be able to handle writes not byte-by-byte, but packet-by-packet.
- * Unfortunately, that decision also exposes some internals of the serial driver
- * in the following.
- *
- ************************************************************************************/
- static uint16_t usbclass_fillrequest(FAR struct pl2303_dev_s *priv, uint8_t *reqbuf,
- uint16_t reqlen)
- {
- FAR uart_dev_t *serdev = &priv->serdev;
- FAR struct uart_buffer_s *xmit = &serdev->xmit;
- irqstate_t flags;
- uint16_t nbytes = 0;
- /* Disable interrupts */
- flags = irqsave();
- /* Transfer bytes while we have bytes available and there is room in the request */
- while (xmit->head != xmit->tail && nbytes < reqlen)
- {
- *reqbuf++ = xmit->buffer[xmit->tail];
- nbytes++;
- /* Increment the tail pointer */
- if (++(xmit->tail) >= xmit->size)
- {
- xmit->tail = 0;
- }
- }
- /* When all of the characters have been sent from the buffer
- * disable the "TX interrupt".
- */
- if (xmit->head == xmit->tail)
- {
- uart_disabletxint(serdev);
- }
- /* If any bytes were removed from the buffer, inform any waiters
- * there there is space available.
- */
- if (nbytes)
- {
- uart_datasent(serdev);
- }
- irqrestore(flags);
- return nbytes;
- }
- /************************************************************************************
- * Name: usbclass_sndpacket
- *
- * Description:
- * This function obtains write requests, transfers the TX data into the request,
- * and submits the requests to the USB controller. This continues untils either
- * (1) there are no further packets available, or (2) thre is not further data
- * to send.
- *
- ************************************************************************************/
- static int usbclass_sndpacket(FAR struct pl2303_dev_s *priv)
- {
- FAR struct usbdev_ep_s *ep;
- FAR struct usbdev_req_s *req;
- FAR struct pl2303_req_s *reqcontainer;
- uint16_t reqlen;
- irqstate_t flags;
- int len;
- int ret = OK;
- #ifdef CONFIG_DEBUG
- if (priv == NULL)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
- return -ENODEV;
- }
- #endif
- flags = irqsave();
- /* Use our IN endpoint for the transfer */
- ep = priv->epbulkin;
- /* Loop until either (1) we run out or write requests, or (2) usbclass_fillrequest()
- * is unable to fill the request with data (i.e., until there is no more data
- * to be sent).
- */
- uvdbg("head=%d tail=%d nwrq=%d empty=%d\n",
- priv->serdev.xmit.head, priv->serdev.xmit.tail,
- priv->nwrq, sq_empty(&priv->reqlist));
- /* Get the maximum number of bytes that will fit into one bulk IN request */
- reqlen = max(CONFIG_PL2303_BULKIN_REQLEN, ep->maxpacket);
- while (!sq_empty(&priv->reqlist))
- {
- /* Peek at the request in the container at the head of the list */
- reqcontainer = (struct pl2303_req_s *)sq_peek(&priv->reqlist);
- req = reqcontainer->req;
- /* Fill the request with serial TX data */
- len = usbclass_fillrequest(priv, req->buf, reqlen);
- if (len > 0)
- {
- /* Remove the empty container from the request list */
- (void)sq_remfirst(&priv->reqlist);
- priv->nwrq--;
- /* Then submit the request to the endpoint */
- req->len = len;
- req->priv = reqcontainer;
- req->flags = USBDEV_REQFLAGS_NULLPKT;
- ret = EP_SUBMIT(ep, req);
- if (ret != OK)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_SUBMITFAIL), (uint16_t)-ret);
- break;
- }
- }
- else
- {
- break;
- }
- }
- irqrestore(flags);
- return ret;
- }
- /************************************************************************************
- * Name: usbclass_recvpacket
- *
- * Description:
- * A normal completion event was received by the read completion handler at the
- * interrupt level (with interrupts disabled). This function handles the USB packet
- * and provides the received data to the uart RX buffer.
- *
- * Assumptions:
- * Called from the USB interrupt handler with interrupts disabled.
- *
- ************************************************************************************/
- static inline int usbclass_recvpacket(FAR struct pl2303_dev_s *priv,
- uint8_t *reqbuf, uint16_t reqlen)
- {
- FAR uart_dev_t *serdev = &priv->serdev;
- FAR struct uart_buffer_s *recv = &serdev->recv;
- uint16_t currhead;
- uint16_t nexthead;
- uint16_t nbytes = 0;
- /* Get the next head index. During the time that RX interrupts are disabled, the
- * the serial driver will be extracting data from the circular buffer and modifying
- * recv.tail. During this time, we should avoid modifying recv.head; Instead we will
- * use a shadow copy of the index. When interrupts are restored, the real recv.head
- * will be updated with this indes.
- */
- if (priv->rxenabled)
- {
- currhead = recv->head;
- }
- else
- {
- currhead = priv->rxhead;
- }
- /* Pre-calculate the head index and check for wrap around. We need to do this
- * so that we can determine if the circular buffer will overrun BEFORE we
- * overrun the buffer!
- */
- nexthead = currhead + 1;
- if (nexthead >= recv->size)
- {
- nexthead = 0;
- }
- /* Then copy data into the RX buffer until either: (1) all of the data has been
- * copied, or (2) the RX buffer is full. NOTE: If the RX buffer becomes full,
- * then we have overrun the serial driver and data will be lost.
- */
- while (nexthead != recv->tail && nbytes < reqlen)
- {
- /* Copy one byte to the head of the circular RX buffer */
- recv->buffer[currhead] = *reqbuf++;
- /* Update counts and indices */
- currhead = nexthead;
- nbytes++;
- /* Increment the head index and check for wrap around */
- nexthead = currhead + 1;
- if (nexthead >= recv->size)
- {
- nexthead = 0;
- }
- }
- /* Write back the head pointer using the shadow index if RX "interrupts"
- * are disabled.
- */
- if (priv->rxenabled)
- {
- recv->head = currhead;
- }
- else
- {
- priv->rxhead = currhead;
- }
- /* If data was added to the incoming serial buffer, then wake up any
- * threads is waiting for incoming data. If we are running in an interrupt
- * handler, then the serial driver will not run until the interrupt handler
- * returns.
- */
- if (priv->rxenabled && nbytes > 0)
- {
- uart_datareceived(serdev);
- }
- /* Return an error if the entire packet could not be transferred */
- if (nbytes < reqlen)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RXOVERRUN), 0);
- return -ENOSPC;
- }
- return OK;
- }
- /****************************************************************************
- * Name: usbclass_allocreq
- *
- * Description:
- * Allocate a request instance along with its buffer
- *
- ****************************************************************************/
- static struct usbdev_req_s *usbclass_allocreq(FAR struct usbdev_ep_s *ep,
- uint16_t len)
- {
- FAR struct usbdev_req_s *req;
- req = EP_ALLOCREQ(ep);
- if (req != NULL)
- {
- req->len = len;
- req->buf = EP_ALLOCBUFFER(ep, len);
- if (!req->buf)
- {
- EP_FREEREQ(ep, req);
- req = NULL;
- }
- }
- return req;
- }
- /****************************************************************************
- * Name: usbclass_freereq
- *
- * Description:
- * Free a request instance along with its buffer
- *
- ****************************************************************************/
- static void usbclass_freereq(FAR struct usbdev_ep_s *ep,
- FAR struct usbdev_req_s *req)
- {
- if (ep != NULL && req != NULL)
- {
- if (req->buf != NULL)
- {
- EP_FREEBUFFER(ep, req->buf);
- }
- EP_FREEREQ(ep, req);
- }
- }
- /****************************************************************************
- * Name: usbclass_mkstrdesc
- *
- * Description:
- * Construct a string descriptor
- *
- ****************************************************************************/
- static int usbclass_mkstrdesc(uint8_t id, struct usb_strdesc_s *strdesc)
- {
- const char *str;
- int len;
- int ndata;
- int i;
- switch (id)
- {
- case 0:
- {
- /* Descriptor 0 is the language id */
- strdesc->len = 4;
- strdesc->type = USB_DESC_TYPE_STRING;
- strdesc->data[0] = LSBYTE(PL2303_STR_LANGUAGE);
- strdesc->data[1] = MSBYTE(PL2303_STR_LANGUAGE);
- return 4;
- }
- case PL2303_MANUFACTURERSTRID:
- str = CONFIG_PL2303_VENDORSTR;
- break;
- case PL2303_PRODUCTSTRID:
- str = CONFIG_PL2303_PRODUCTSTR;
- break;
- case PL2303_SERIALSTRID:
- str = CONFIG_PL2303_SERIALSTR;
- break;
- case PL2303_CONFIGSTRID:
- str = CONFIG_PL2303_CONFIGSTR;
- break;
- default:
- return -EINVAL;
- }
- /* The string is utf16-le. The poor man's utf-8 to utf16-le
- * conversion below will only handle 7-bit en-us ascii
- */
- len = strlen(str);
- for (i = 0, ndata = 0; i < len; i++, ndata += 2)
- {
- strdesc->data[ndata] = str[i];
- strdesc->data[ndata+1] = 0;
- }
- strdesc->len = ndata+2;
- strdesc->type = USB_DESC_TYPE_STRING;
- return strdesc->len;
- }
- /****************************************************************************
- * Name: usbclass_mkepbulkdesc
- *
- * Description:
- * Construct the endpoint descriptor
- *
- ****************************************************************************/
- #ifdef CONFIG_USBDEV_DUALSPEED
- static inline void usbclass_mkepbulkdesc(const FAR struct usb_epdesc_s *indesc,
- uint16_t mxpacket,
- FAR struct usb_epdesc_s *outdesc)
- {
- /* Copy the canned descriptor */
- memcpy(outdesc, indesc, USB_SIZEOF_EPDESC);
- /* Then add the correct max packet size */
- outdesc->mxpacketsize[0] = LSBYTE(mxpacket);
- outdesc->mxpacketsize[1] = MSBYTE(mxpacket);
- }
- #endif
- /****************************************************************************
- * Name: usbclass_mkcfgdesc
- *
- * Description:
- * Construct the configuration descriptor
- *
- ****************************************************************************/
- #ifdef CONFIG_USBDEV_DUALSPEED
- static int16_t usbclass_mkcfgdesc(uint8_t *buf, uint8_t speed, uint8_t type)
- #else
- static int16_t usbclass_mkcfgdesc(uint8_t *buf)
- #endif
- {
- FAR struct usb_cfgdesc_s *cfgdesc = (struct usb_cfgdesc_s*)buf;
- #ifdef CONFIG_USBDEV_DUALSPEED
- bool hispeed = (speed == USB_SPEED_HIGH);
- uint16_t bulkmxpacket;
- #endif
- uint16_t totallen;
- /* This is the total length of the configuration (not necessarily the
- * size that we will be sending now.
- */
- totallen = USB_SIZEOF_CFGDESC + USB_SIZEOF_IFDESC + PL2303_NENDPOINTS * USB_SIZEOF_EPDESC;
- /* Configuration descriptor -- Copy the canned descriptor and fill in the
- * type (we'll also need to update the size below
- */
- memcpy(cfgdesc, &g_cfgdesc, USB_SIZEOF_CFGDESC);
- buf += USB_SIZEOF_CFGDESC;
- /* Copy the canned interface descriptor */
- memcpy(buf, &g_ifdesc, USB_SIZEOF_IFDESC);
- buf += USB_SIZEOF_IFDESC;
- /* Make the three endpoint configurations. First, check for switches
- * between high and full speed
- */
- #ifdef CONFIG_USBDEV_DUALSPEED
- if (type == USB_DESC_TYPE_OTHERSPEEDCONFIG)
- {
- hispeed = !hispeed;
- }
- #endif
- memcpy(buf, &g_epintindesc, USB_SIZEOF_EPDESC);
- buf += USB_SIZEOF_EPDESC;
- #ifdef CONFIG_USBDEV_DUALSPEED
- if (hispeed)
- {
- bulkmxpacket = 512;
- }
- else
- {
- bulkmxpacket = 64;
- }
- usbclass_mkepbulkdesc(&g_epbulkoutdesc, bulkmxpacket, (struct usb_epdesc_s*)buf);
- buf += USB_SIZEOF_EPDESC;
- usbclass_mkepbulkdesc(&g_epbulkindesc, bulkmxpacket, (struct usb_epdesc_s*)buf);
- #else
- memcpy(buf, &g_epbulkoutdesc, USB_SIZEOF_EPDESC);
- buf += USB_SIZEOF_EPDESC;
- memcpy(buf, &g_epbulkindesc, USB_SIZEOF_EPDESC);
- #endif
- /* Finally, fill in the total size of the configuration descriptor */
- cfgdesc->totallen[0] = LSBYTE(totallen);
- cfgdesc->totallen[1] = MSBYTE(totallen);
- return totallen;
- }
- /****************************************************************************
- * Name: usbclass_resetconfig
- *
- * Description:
- * Mark the device as not configured and disable all endpoints.
- *
- ****************************************************************************/
- static void usbclass_resetconfig(FAR struct pl2303_dev_s *priv)
- {
- /* Are we configured? */
- if (priv->config != PL2303_CONFIGIDNONE)
- {
- /* Yes.. but not anymore */
- priv->config = PL2303_CONFIGIDNONE;
- /* Inform the "upper half" driver that there is no (functional) USB
- * connection.
- */
- #ifdef CONFIG_SERIAL_REMOVABLE
- uart_connected(&priv->serdev, false);
- #endif
- /* Disable endpoints. This should force completion of all pending
- * transfers.
- */
- EP_DISABLE(priv->epintin);
- EP_DISABLE(priv->epbulkin);
- EP_DISABLE(priv->epbulkout);
- }
- }
- /****************************************************************************
- * Name: usbclass_setconfig
- *
- * Description:
- * Set the device configuration by allocating and configuring endpoints and
- * by allocating and queue read and write requests.
- *
- ****************************************************************************/
- static int usbclass_setconfig(FAR struct pl2303_dev_s *priv, uint8_t config)
- {
- FAR struct usbdev_req_s *req;
- #ifdef CONFIG_USBDEV_DUALSPEED
- struct usb_epdesc_s epdesc;
- uint16_t bulkmxpacket;
- #endif
- int i;
- int ret = 0;
- #if CONFIG_DEBUG
- if (priv == NULL)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
- return -EIO;
- }
- #endif
- if (config == priv->config)
- {
- /* Already configured -- Do nothing */
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_ALREADYCONFIGURED), 0);
- return 0;
- }
- /* Discard the previous configuration data */
- usbclass_resetconfig(priv);
- /* Was this a request to simply discard the current configuration? */
- if (config == PL2303_CONFIGIDNONE)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_CONFIGNONE), 0);
- return 0;
- }
- /* We only accept one configuration */
- if (config != PL2303_CONFIGID)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_CONFIGIDBAD), 0);
- return -EINVAL;
- }
- /* Configure the IN interrupt endpoint */
- ret = EP_CONFIGURE(priv->epintin, &g_epintindesc, false);
- if (ret < 0)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPINTINCONFIGFAIL), 0);
- goto errout;
- }
- priv->epintin->priv = priv;
- /* Configure the IN bulk endpoint */
- #ifdef CONFIG_USBDEV_DUALSPEED
- if (priv->usbdev->speed == USB_SPEED_HIGH)
- {
- bulkmxpacket = 512;
- }
- else
- {
- bulkmxpacket = 64;
- }
- usbclass_mkepbulkdesc(&g_epbulkindesc, bulkmxpacket, &epdesc);
- ret = EP_CONFIGURE(priv->epbulkin, &epdesc, false);
- #else
- ret = EP_CONFIGURE(priv->epbulkin, &g_epbulkindesc, false);
- #endif
- if (ret < 0)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKINCONFIGFAIL), 0);
- goto errout;
- }
- priv->epbulkin->priv = priv;
- /* Configure the OUT bulk endpoint */
- #ifdef CONFIG_USBDEV_DUALSPEED
- usbclass_mkepbulkdesc(&g_epbulkoutdesc, bulkmxpacket, &epdesc);
- ret = EP_CONFIGURE(priv->epbulkout, &epdesc, true);
- #else
- ret = EP_CONFIGURE(priv->epbulkout, &g_epbulkoutdesc, true);
- #endif
- if (ret < 0)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKOUTCONFIGFAIL), 0);
- goto errout;
- }
- priv->epbulkout->priv = priv;
- /* Queue read requests in the bulk OUT endpoint */
- DEBUGASSERT(priv->nrdq == 0);
- for (i = 0; i < CONFIG_PL2303_NRDREQS; i++)
- {
- req = priv->rdreqs[i].req;
- req->callback = usbclass_rdcomplete;
- ret = EP_SUBMIT(priv->epbulkout, req);
- if (ret != OK)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16_t)-ret);
- goto errout;
- }
- priv->nrdq++;
- }
- /* We are successfully configured */
- priv->config = config;
- /* Inform the "upper half" driver that we are "open for business" */
- #ifdef CONFIG_SERIAL_REMOVABLE
- uart_connected(&priv->serdev, true);
- #endif
- return OK;
- errout:
- usbclass_resetconfig(priv);
- return ret;
- }
- /****************************************************************************
- * Name: usbclass_ep0incomplete
- *
- * Description:
- * Handle completion of EP0 control operations
- *
- ****************************************************************************/
- static void usbclass_ep0incomplete(FAR struct usbdev_ep_s *ep,
- FAR struct usbdev_req_s *req)
- {
- if (req->result || req->xfrd != req->len)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_REQRESULT), (uint16_t)-req->result);
- }
- }
- /****************************************************************************
- * Name: usbclass_rdcomplete
- *
- * Description:
- * Handle completion of read request on the bulk OUT endpoint. This
- * is handled like the receipt of serial data on the "UART"
- *
- ****************************************************************************/
- static void usbclass_rdcomplete(FAR struct usbdev_ep_s *ep,
- FAR struct usbdev_req_s *req)
- {
- FAR struct pl2303_dev_s *priv;
- irqstate_t flags;
- int ret;
- /* Sanity check */
- #ifdef CONFIG_DEBUG
- if (!ep || !ep->priv || !req)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
- return;
- }
- #endif
- /* Extract references to private data */
- priv = (FAR struct pl2303_dev_s*)ep->priv;
- /* Process the received data unless this is some unusual condition */
- flags = irqsave();
- switch (req->result)
- {
- case 0: /* Normal completion */
- usbtrace(TRACE_CLASSRDCOMPLETE, priv->nrdq);
- usbclass_recvpacket(priv, req->buf, req->xfrd);
- break;
- case -ESHUTDOWN: /* Disconnection */
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSHUTDOWN), 0);
- priv->nrdq--;
- irqrestore(flags);
- return;
- default: /* Some other error occurred */
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDUNEXPECTED), (uint16_t)-req->result);
- break;
- };
- /* Requeue the read request */
- req->len = ep->maxpacket;
- ret = EP_SUBMIT(ep, req);
- if (ret != OK)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDSUBMIT), (uint16_t)-req->result);
- }
- irqrestore(flags);
- }
- /****************************************************************************
- * Name: usbclass_wrcomplete
- *
- * Description:
- * Handle completion of write request. This function probably executes
- * in the context of an interrupt handler.
- *
- ****************************************************************************/
- static void usbclass_wrcomplete(FAR struct usbdev_ep_s *ep,
- FAR struct usbdev_req_s *req)
- {
- FAR struct pl2303_dev_s *priv;
- FAR struct pl2303_req_s *reqcontainer;
- irqstate_t flags;
- /* Sanity check */
- #ifdef CONFIG_DEBUG
- if (!ep || !ep->priv || !req || !req->priv)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
- return;
- }
- #endif
- /* Extract references to our private data */
- priv = (FAR struct pl2303_dev_s *)ep->priv;
- reqcontainer = (FAR struct pl2303_req_s *)req->priv;
- /* Return the write request to the free list */
- flags = irqsave();
- sq_addlast((sq_entry_t*)reqcontainer, &priv->reqlist);
- priv->nwrq++;
- irqrestore(flags);
- /* Send the next packet unless this was some unusual termination
- * condition
- */
- switch (req->result)
- {
- case OK: /* Normal completion */
- usbtrace(TRACE_CLASSWRCOMPLETE, priv->nwrq);
- usbclass_sndpacket(priv);
- break;
- case -ESHUTDOWN: /* Disconnection */
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRSHUTDOWN), priv->nwrq);
- break;
- default: /* Some other error occurred */
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRUNEXPECTED), (uint16_t)-req->result);
- break;
- }
- }
- /****************************************************************************
- * USB Class Driver Methods
- ****************************************************************************/
- /****************************************************************************
- * Name: usbclass_bind
- *
- * Description:
- * Invoked when the driver is bound to a USB device driver
- *
- ****************************************************************************/
- static int usbclass_bind(FAR struct usbdevclass_driver_s *driver,
- FAR struct usbdev_s *dev)
- {
- FAR struct pl2303_dev_s *priv = ((FAR struct pl2303_driver_s*)driver)->dev;
- FAR struct pl2303_req_s *reqcontainer;
- irqstate_t flags;
- uint16_t reqlen;
- int ret;
- int i;
- usbtrace(TRACE_CLASSBIND, 0);
- /* Bind the structures */
- priv->usbdev = dev;
- /* Save the reference to our private data structure in EP0 so that it
- * can be recovered in ep0 completion events (Unless we are part of
- * a composite device and, in that case, the composite device owns
- * EP0).
- */
- dev->ep0->priv = priv;
- /* Preallocate control request */
- priv->ctrlreq = usbclass_allocreq(dev->ep0, PL2303_MXDESCLEN);
- if (priv->ctrlreq == NULL)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_ALLOCCTRLREQ), 0);
- ret = -ENOMEM;
- goto errout;
- }
- priv->ctrlreq->callback = usbclass_ep0incomplete;
- /* Pre-allocate all endpoints... the endpoints will not be functional
- * until the SET CONFIGURATION request is processed in usbclass_setconfig.
- * This is done here because there may be calls to kmalloc and the SET
- * CONFIGURATION processing probably occurrs within interrupt handling
- * logic where kmalloc calls will fail.
- */
- /* Pre-allocate the IN interrupt endpoint */
- priv->epintin = DEV_ALLOCEP(dev, PL2303_EPINTIN_ADDR, true, USB_EP_ATTR_XFER_INT);
- if (!priv->epintin)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPINTINALLOCFAIL), 0);
- ret = -ENODEV;
- goto errout;
- }
- priv->epintin->priv = priv;
- /* Pre-allocate the IN bulk endpoint */
- priv->epbulkin = DEV_ALLOCEP(dev, PL2303_EPINBULK_ADDR, true, USB_EP_ATTR_XFER_BULK);
- if (!priv->epbulkin)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKINALLOCFAIL), 0);
- ret = -ENODEV;
- goto errout;
- }
- priv->epbulkin->priv = priv;
- /* Pre-allocate the OUT bulk endpoint */
- priv->epbulkout = DEV_ALLOCEP(dev, PL2303_EPOUTBULK_ADDR, false, USB_EP_ATTR_XFER_BULK);
- if (!priv->epbulkout)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPBULKOUTALLOCFAIL), 0);
- ret = -ENODEV;
- goto errout;
- }
- priv->epbulkout->priv = priv;
- /* Pre-allocate read requests */
- reqlen = priv->epbulkout->maxpacket;
- for (i = 0; i < CONFIG_PL2303_NRDREQS; i++)
- {
- reqcontainer = &priv->rdreqs[i];
- reqcontainer->req = usbclass_allocreq(priv->epbulkout, reqlen);
- if (reqcontainer->req == NULL)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_RDALLOCREQ), -ENOMEM);
- ret = -ENOMEM;
- goto errout;
- }
- reqcontainer->req->priv = reqcontainer;
- reqcontainer->req->callback = usbclass_rdcomplete;
- }
- /* Pre-allocate write request containers and put in a free list */
- reqlen = max(CONFIG_PL2303_BULKIN_REQLEN, priv->epbulkin->maxpacket);
- for (i = 0; i < CONFIG_PL2303_NWRREQS; i++)
- {
- reqcontainer = &priv->wrreqs[i];
- reqcontainer->req = usbclass_allocreq(priv->epbulkin, reqlen);
- if (reqcontainer->req == NULL)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_WRALLOCREQ), -ENOMEM);
- ret = -ENOMEM;
- goto errout;
- }
- reqcontainer->req->priv = reqcontainer;
- reqcontainer->req->callback = usbclass_wrcomplete;
- flags = irqsave();
- sq_addlast((sq_entry_t*)reqcontainer, &priv->reqlist);
- priv->nwrq++; /* Count of write requests available */
- irqrestore(flags);
- }
- /* Report if we are selfpowered */
- #ifdef CONFIG_USBDEV_SELFPOWERED
- DEV_SETSELFPOWERED(dev);
- #endif
- /* And pull-up the data line for the soft connect function */
- DEV_CONNECT(dev);
- return OK;
- errout:
- usbclass_unbind(driver, dev);
- return ret;
- }
- /****************************************************************************
- * Name: usbclass_unbind
- *
- * Description:
- * Invoked when the driver is unbound from a USB device driver
- *
- ****************************************************************************/
- static void usbclass_unbind(FAR struct usbdevclass_driver_s *driver,
- FAR struct usbdev_s *dev)
- {
- FAR struct pl2303_dev_s *priv;
- FAR struct pl2303_req_s *reqcontainer;
- irqstate_t flags;
- int i;
- usbtrace(TRACE_CLASSUNBIND, 0);
- #ifdef CONFIG_DEBUG
- if (!driver || !dev || !dev->ep0)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
- return;
- }
- #endif
- /* Extract reference to private data */
- priv = ((FAR struct pl2303_driver_s*)driver)->dev;
- #ifdef CONFIG_DEBUG
- if (!priv)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EP0NOTBOUND), 0);
- return;
- }
- #endif
- /* Make sure that we are not already unbound */
- if (priv != NULL)
- {
- /* Make sure that the endpoints have been unconfigured. If
- * we were terminated gracefully, then the configuration should
- * already have been reset. If not, then calling usbclass_resetconfig
- * should cause the endpoints to immediately terminate all
- * transfers and return the requests to us (with result == -ESHUTDOWN)
- */
- usbclass_resetconfig(priv);
- up_mdelay(50);
- /* Free the interrupt IN endpoint */
- if (priv->epintin)
- {
- DEV_FREEEP(dev, priv->epintin);
- priv->epintin = NULL;
- }
- /* Free the bulk IN endpoint */
- if (priv->epbulkin)
- {
- DEV_FREEEP(dev, priv->epbulkin);
- priv->epbulkin = NULL;
- }
- /* Free the pre-allocated control request */
- if (priv->ctrlreq != NULL)
- {
- usbclass_freereq(dev->ep0, priv->ctrlreq);
- priv->ctrlreq = NULL;
- }
- /* Free pre-allocated read requests (which should all have
- * been returned to the free list at this time -- we don't check)
- */
- DEBUGASSERT(priv->nrdq == 0);
- for (i = 0; i < CONFIG_PL2303_NRDREQS; i++)
- {
- reqcontainer = &priv->rdreqs[i];
- if (reqcontainer->req)
- {
- usbclass_freereq(priv->epbulkout, reqcontainer->req);
- reqcontainer->req = NULL;
- }
- }
- /* Free the bulk OUT endpoint */
- if (priv->epbulkout)
- {
- DEV_FREEEP(dev, priv->epbulkout);
- priv->epbulkout = NULL;
- }
- /* Free write requests that are not in use (which should be all
- * of them
- */
- flags = irqsave();
- DEBUGASSERT(priv->nwrq == CONFIG_PL2303_NWRREQS);
- while (!sq_empty(&priv->reqlist))
- {
- reqcontainer = (struct pl2303_req_s *)sq_remfirst(&priv->reqlist);
- if (reqcontainer->req != NULL)
- {
- usbclass_freereq(priv->epbulkin, reqcontainer->req);
- priv->nwrq--; /* Number of write requests queued */
- }
- }
- DEBUGASSERT(priv->nwrq == 0);
- irqrestore(flags);
- }
- /* Clear out all data in the circular buffer */
- priv->serdev.xmit.head = 0;
- priv->serdev.xmit.tail = 0;
- }
- /****************************************************************************
- * Name: usbclass_setup
- *
- * Description:
- * Invoked for ep0 control requests. This function probably executes
- * in the context of an interrupt handler.
- *
- ****************************************************************************/
- static int usbclass_setup(FAR struct usbdevclass_driver_s *driver,
- FAR struct usbdev_s *dev,
- FAR const struct usb_ctrlreq_s *ctrl,
- FAR uint8_t *dataout, size_t outlen)
- {
- FAR struct pl2303_dev_s *priv;
- FAR struct usbdev_req_s *ctrlreq;
- uint16_t value;
- uint16_t index;
- uint16_t len;
- int ret = -EOPNOTSUPP;
- #ifdef CONFIG_DEBUG
- if (!driver || !dev || !dev->ep0 || !ctrl)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
- return -EIO;
- }
- #endif
- /* Extract reference to private data */
- usbtrace(TRACE_CLASSSETUP, ctrl->req);
- priv = ((FAR struct pl2303_driver_s*)driver)->dev;
- #ifdef CONFIG_DEBUG
- if (!priv || !priv->ctrlreq)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EP0NOTBOUND), 0);
- return -ENODEV;
- }
- #endif
- ctrlreq = priv->ctrlreq;
- /* Extract the little-endian 16-bit values to host order */
- value = GETUINT16(ctrl->value);
- index = GETUINT16(ctrl->index);
- len = GETUINT16(ctrl->len);
- uvdbg("type=%02x req=%02x value=%04x index=%04x len=%04x\n",
- ctrl->type, ctrl->req, value, index, len);
- switch (ctrl->type & USB_REQ_TYPE_MASK)
- {
- /***********************************************************************
- * Standard Requests
- ***********************************************************************/
- case USB_REQ_TYPE_STANDARD:
- {
- switch (ctrl->req)
- {
- case USB_REQ_GETDESCRIPTOR:
- {
- /* The value field specifies the descriptor type in the MS byte and the
- * descriptor index in the LS byte (order is little endian)
- */
- switch (ctrl->value[1])
- {
- case USB_DESC_TYPE_DEVICE:
- {
- ret = USB_SIZEOF_DEVDESC;
- memcpy(ctrlreq->buf, &g_devdesc, ret);
- }
- break;
- #ifdef CONFIG_USBDEV_DUALSPEED
- case USB_DESC_TYPE_DEVICEQUALIFIER:
- {
- ret = USB_SIZEOF_QUALDESC;
- memcpy(ctrlreq->buf, &g_qualdesc, ret);
- }
- break;
- case USB_DESC_TYPE_OTHERSPEEDCONFIG:
- #endif /* CONFIG_USBDEV_DUALSPEED */
- case USB_DESC_TYPE_CONFIG:
- {
- #ifdef CONFIG_USBDEV_DUALSPEED
- ret = usbclass_mkcfgdesc(ctrlreq->buf, dev->speed, ctrl->req);
- #else
- ret = usbclass_mkcfgdesc(ctrlreq->buf);
- #endif
- }
- break;
- case USB_DESC_TYPE_STRING:
- {
- /* index == language code. */
- ret = usbclass_mkstrdesc(ctrl->value[0], (struct usb_strdesc_s *)ctrlreq->buf);
- }
- break;
- default:
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_GETUNKNOWNDESC), value);
- }
- break;
- }
- }
- break;
- case USB_REQ_SETCONFIGURATION:
- {
- if (ctrl->type == 0)
- {
- ret = usbclass_setconfig(priv, value);
- }
- }
- break;
- case USB_REQ_GETCONFIGURATION:
- {
- if (ctrl->type == USB_DIR_IN)
- {
- *(uint8_t*)ctrlreq->buf = priv->config;
- ret = 1;
- }
- }
- break;
- case USB_REQ_SETINTERFACE:
- {
- if (ctrl->type == USB_REQ_RECIPIENT_INTERFACE)
- {
- if (priv->config == PL2303_CONFIGID &&
- index == PL2303_INTERFACEID &&
- value == PL2303_ALTINTERFACEID)
- {
- usbclass_resetconfig(priv);
- usbclass_setconfig(priv, priv->config);
- ret = 0;
- }
- }
- }
- break;
- case USB_REQ_GETINTERFACE:
- {
- if (ctrl->type == (USB_DIR_IN|USB_REQ_RECIPIENT_INTERFACE) &&
- priv->config == PL2303_CONFIGIDNONE)
- {
- if (index != PL2303_INTERFACEID)
- {
- ret = -EDOM;
- }
- else
- {
- *(uint8_t*) ctrlreq->buf = PL2303_ALTINTERFACEID;
- ret = 1;
- }
- }
- }
- break;
- default:
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDSTDREQ), ctrl->req);
- break;
- }
- }
- break;
- /***********************************************************************
- * PL2303 Vendor-Specific Requests
- ***********************************************************************/
- case PL2303_CONTROL_TYPE:
- {
- if ((ctrl->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_INTERFACE)
- {
- switch (ctrl->req)
- {
- case PL2303_SETLINEREQUEST:
- {
- memcpy(priv->linest, ctrlreq->buf, min(len, 7));
- ret = 0;
- }
- break;
- case PL2303_GETLINEREQUEST:
- {
- memcpy(ctrlreq->buf, priv->linest, 7);
- ret = 7;
- }
- break;
- case PL2303_SETCONTROLREQUEST:
- case PL2303_BREAKREQUEST:
- {
- ret = 0;
- }
- break;
- default:
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type);
- break;
- }
- }
- }
- break;
- case PL2303_RWREQUEST_TYPE:
- {
- if ((ctrl->type & USB_REQ_RECIPIENT_MASK) == USB_REQ_RECIPIENT_DEVICE)
- {
- if (ctrl->req == PL2303_RWREQUEST)
- {
- if ((ctrl->type & USB_DIR_IN) != 0)
- {
- *(uint32_t*)ctrlreq->buf = 0xdeadbeef;
- ret = 4;
- }
- else
- {
- ret = 0;
- }
- }
- else
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDCLASSREQ), ctrl->type);
- }
- }
- }
- break;
- default:
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UNSUPPORTEDTYPE), ctrl->type);
- break;
- }
- /* Respond to the setup command if data was returned. On an error return
- * value (ret < 0), the USB driver will stall.
- */
- if (ret >= 0)
- {
- ctrlreq->len = min(len, ret);
- ctrlreq->flags = USBDEV_REQFLAGS_NULLPKT;
- ret = EP_SUBMIT(dev->ep0, ctrlreq);
- if (ret < 0)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EPRESPQ), (uint16_t)-ret);
- ctrlreq->result = OK;
- usbclass_ep0incomplete(dev->ep0, ctrlreq);
- }
- }
- return ret;
- }
- /****************************************************************************
- * Name: usbclass_disconnect
- *
- * Description:
- * Invoked after all transfers have been stopped, when the host is
- * disconnected. This function is probably called from the context of an
- * interrupt handler.
- *
- ****************************************************************************/
- static void usbclass_disconnect(FAR struct usbdevclass_driver_s *driver,
- FAR struct usbdev_s *dev)
- {
- FAR struct pl2303_dev_s *priv;
- irqstate_t flags;
- usbtrace(TRACE_CLASSDISCONNECT, 0);
- #ifdef CONFIG_DEBUG
- if (!driver || !dev || !dev->ep0)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
- return;
- }
- #endif
- /* Extract reference to private data */
- priv = ((FAR struct pl2303_driver_s*)driver)->dev;
- #ifdef CONFIG_DEBUG
- if (!priv)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_EP0NOTBOUND), 0);
- return;
- }
- #endif
- /* Inform the "upper half serial driver that we have lost the USB serial
- * connection.
- */
- flags = irqsave();
- #ifdef CONFIG_SERIAL_REMOVABLE
- uart_connected(&priv->serdev, false);
- #endif
- /* Reset the configuration */
- usbclass_resetconfig(priv);
- /* Clear out all outgoing data in the circular buffer */
- priv->serdev.xmit.head = 0;
- priv->serdev.xmit.tail = 0;
- irqrestore(flags);
- /* Perform the soft connect function so that we will we can be
- * re-enumerated.
- */
- DEV_CONNECT(dev);
- }
- /****************************************************************************
- * Name: usbclass_suspend
- *
- * Description:
- * Handle the USB suspend event.
- *
- ****************************************************************************/
- #ifdef CONFIG_SERIAL_REMOVABLE
- static void usbclass_suspend(FAR struct usbdevclass_driver_s *driver,
- FAR struct usbdev_s *dev)
- {
- FAR struct pl2303_dev_s *priv;
- usbtrace(TRACE_CLASSSUSPEND, 0);
- #ifdef CONFIG_DEBUG
- if (!driver || !dev)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
- return;
- }
- #endif
- /* Extract reference to private data */
- priv = ((FAR struct pl2303_driver_s*)driver)->dev;
- /* And let the "upper half" driver now that we are suspended */
- uart_connected(&priv->serdev, false);
- }
- #endif
- /****************************************************************************
- * Name: usbclass_resume
- *
- * Description:
- * Handle the USB resume event.
- *
- ****************************************************************************/
- #ifdef CONFIG_SERIAL_REMOVABLE
- static void usbclass_resume(FAR struct usbdevclass_driver_s *driver,
- FAR struct usbdev_s *dev)
- {
- FAR struct pl2303_dev_s *priv;
- usbtrace(TRACE_CLASSRESUME, 0);
- #ifdef CONFIG_DEBUG
- if (!driver || !dev)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
- return;
- }
- #endif
- /* Extract reference to private data */
- priv = ((FAR struct pl2303_driver_s*)driver)->dev;
- /* Are we still configured? */
- if (priv->config != PL2303_CONFIGIDNONE)
- {
- /* Yes.. let the "upper half" know that have resumed */
- uart_connected(&priv->serdev, true);
- }
- }
- #endif
- /****************************************************************************
- * Serial Device Methods
- ****************************************************************************/
- /****************************************************************************
- * Name: usbser_setup
- *
- * Description:
- * This method is called the first time that the serial port is opened.
- *
- ****************************************************************************/
- static int usbser_setup(FAR struct uart_dev_s *dev)
- {
- FAR struct pl2303_dev_s *priv;
- usbtrace(PL2303_CLASSAPI_SETUP, 0);
- /* Sanity check */
- #if CONFIG_DEBUG
- if (!dev || !dev->priv)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
- return -EIO;
- }
- #endif
- /* Extract reference to private data */
- priv = (FAR struct pl2303_dev_s*)dev->priv;
- /* Check if we have been configured */
- if (priv->config == PL2303_CONFIGIDNONE)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_SETUPNOTCONNECTED), 0);
- return -ENOTCONN;
- }
- return OK;
- }
- /****************************************************************************
- * Name: usbser_shutdown
- *
- * Description:
- * This method is called when the serial port is closed. This operation
- * is very simple for the USB serial backend because the serial driver
- * has already assured that the TX data has full drained -- it calls
- * usbser_txempty() until that function returns true before calling this
- * function.
- *
- ****************************************************************************/
- static void usbser_shutdown(FAR struct uart_dev_s *dev)
- {
- usbtrace(PL2303_CLASSAPI_SHUTDOWN, 0);
- /* Sanity check */
- #if CONFIG_DEBUG
- if (!dev || !dev->priv)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
- }
- #endif
- }
- /****************************************************************************
- * Name: usbser_attach
- *
- * Description:
- * Does not apply to the USB serial class device
- *
- ****************************************************************************/
- static int usbser_attach(FAR struct uart_dev_s *dev)
- {
- usbtrace(PL2303_CLASSAPI_ATTACH, 0);
- return OK;
- }
- /****************************************************************************
- * Name: usbser_detach
- *
- * Description:
- * Does not apply to the USB serial class device
- *
- ****************************************************************************/
- static void usbser_detach(FAR struct uart_dev_s *dev)
- {
- usbtrace(PL2303_CLASSAPI_DETACH, 0);
- }
- /****************************************************************************
- * Name: usbser_rxint
- *
- * Description:
- * Called by the serial driver to enable or disable RX interrupts. We, of
- * course, have no RX interrupts but must behave consistently. This method
- * is called under the conditions:
- *
- * 1. With enable==true when the port is opened (just after usbser_setup
- * and usbser_attach are called called)
- * 2. With enable==false while transferring data from the RX buffer
- * 2. With enable==true while waiting for more incoming data
- * 3. With enable==false when the port is closed (just before usbser_detach
- * and usbser_shutdown are called).
- *
- ****************************************************************************/
- static void usbser_rxint(FAR struct uart_dev_s *dev, bool enable)
- {
- FAR struct pl2303_dev_s *priv;
- FAR uart_dev_t *serdev;
- irqstate_t flags;
- usbtrace(PL2303_CLASSAPI_RXINT, (uint16_t)enable);
- /* Sanity check */
- #if CONFIG_DEBUG
- if (!dev || !dev->priv)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
- return;
- }
- #endif
- /* Extract reference to private data */
- priv = (FAR struct pl2303_dev_s*)dev->priv;
- serdev = &priv->serdev;
- /* We need exclusive access to the RX buffer and private structure
- * in the following.
- */
- flags = irqsave();
- if (enable)
- {
- /* RX "interrupts" are enabled. Is this a transition from disabled
- * to enabled state?
- */
- if (!priv->rxenabled)
- {
- /* Yes. During the time that RX interrupts are disabled, the
- * the serial driver will be extracting data from the circular
- * buffer and modifying recv.tail. During this time, we
- * should avoid modifying recv.head; When interrupts are restored,
- * we can update the head pointer for all of the data that we
- * put into cicular buffer while "interrupts" were disabled.
- */
- if (priv->rxhead != serdev->recv.head)
- {
- serdev->recv.head = priv->rxhead;
- /* Yes... signal the availability of new data */
- uart_datareceived(serdev);
- }
- /* RX "interrupts are no longer disabled */
- priv->rxenabled = true;
- }
- }
- /* RX "interrupts" are disabled. Is this a transition from enabled
- * to disabled state?
- */
- else if (priv->rxenabled)
- {
- /* Yes. During the time that RX interrupts are disabled, the
- * the serial driver will be extracting data from the circular
- * buffer and modifying recv.tail. During this time, we
- * should avoid modifying recv.head; When interrupts are disabled,
- * we use a shadow index and continue adding data to the circular
- * buffer.
- */
- priv->rxhead = serdev->recv.head;
- priv->rxenabled = false;
- }
- irqrestore(flags);
- }
- /****************************************************************************
- * Name: usbser_txint
- *
- * Description:
- * Called by the serial driver to enable or disable TX interrupts. We, of
- * course, have no TX interrupts but must behave consistently. Initially,
- * TX interrupts are disabled. This method is called under the conditions:
- *
- * 1. With enable==false while transferring data into the TX buffer
- * 2. With enable==true when data may be taken from the buffer.
- * 3. With enable==false when the TX buffer is empty
- *
- ****************************************************************************/
- static void usbser_txint(FAR struct uart_dev_s *dev, bool enable)
- {
- FAR struct pl2303_dev_s *priv;
- usbtrace(PL2303_CLASSAPI_TXINT, (uint16_t)enable);
- /* Sanity checks */
- #if CONFIG_DEBUG
- if (!dev || !dev->priv)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
- return;
- }
- #endif
- /* Extract references to private data */
- priv = (FAR struct pl2303_dev_s*)dev->priv;
- /* If the new state is enabled and if there is data in the XMIT buffer,
- * send the next packet now.
- */
- uvdbg("enable=%d head=%d tail=%d\n",
- enable, priv->serdev.xmit.head, priv->serdev.xmit.tail);
- if (enable && priv->serdev.xmit.head != priv->serdev.xmit.tail)
- {
- usbclass_sndpacket(priv);
- }
- }
- /****************************************************************************
- * Name: usbser_txempty
- *
- * Description:
- * Return true when all data has been sent. This is called from the
- * serial driver when the driver is closed. It will call this API
- * periodically until it reports true. NOTE that the serial driver takes all
- * responsibility for flushing TX data through the hardware so we can be
- * a bit sloppy about that.
- *
- ****************************************************************************/
- static bool usbser_txempty(FAR struct uart_dev_s *dev)
- {
- FAR struct pl2303_dev_s *priv = (FAR struct pl2303_dev_s*)dev->priv;
- usbtrace(PL2303_CLASSAPI_TXEMPTY, 0);
- #if CONFIG_DEBUG
- if (!priv)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_INVALIDARG), 0);
- return true;
- }
- #endif
- /* When all of the allocated write requests have been returned to the
- * reqlist, then there is no longer any TX data in flight.
- */
- return priv->nwrq >= CONFIG_PL2303_NWRREQS;
- }
- /****************************************************************************
- * Public Functions
- ****************************************************************************/
- /****************************************************************************
- * Name: usbdev_serialinitialize
- *
- * Description:
- * Register USB serial port (and USB serial console if so configured).
- *
- ****************************************************************************/
- int usbdev_serialinitialize(int minor)
- {
- FAR struct pl2303_alloc_s *alloc;
- FAR struct pl2303_dev_s *priv;
- FAR struct pl2303_driver_s *drvr;
- char devname[16];
- int ret;
- /* Allocate the structures needed */
- alloc = (FAR struct pl2303_alloc_s*)kmalloc(sizeof(struct pl2303_alloc_s));
- if (!alloc)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_ALLOCDEVSTRUCT), 0);
- return -ENOMEM;
- }
- /* Convenience pointers into the allocated blob */
- priv = &alloc->dev;
- drvr = &alloc->drvr;
- /* Initialize the USB serial driver structure */
- memset(priv, 0, sizeof(struct pl2303_dev_s));
- sq_init(&priv->reqlist);
- /* Fake line status */
- priv->linest[0] = (115200) & 0xff; /* Baud=115200 */
- priv->linest[1] = (115200 >> 8) & 0xff;
- priv->linest[2] = (115200 >> 16) & 0xff;
- priv->linest[3] = (115200 >> 24) & 0xff;
- priv->linest[4] = 0; /* One stop bit */
- priv->linest[5] = 0; /* No parity */
- priv->linest[6] = 8; /*8 data bits */
- /* Initialize the serial driver sub-structure */
- #ifdef CONFIG_SERIAL_REMOVABLE
- priv->serdev.disconnected = true;
- #endif
- priv->serdev.recv.size = CONFIG_PL2303_RXBUFSIZE;
- priv->serdev.recv.buffer = priv->rxbuffer;
- priv->serdev.xmit.size = CONFIG_PL2303_TXBUFSIZE;
- priv->serdev.xmit.buffer = priv->txbuffer;
- priv->serdev.ops = &g_uartops;
- priv->serdev.priv = priv;
- /* Initialize the USB class driver structure */
- #ifdef CONFIG_USBDEV_DUALSPEED
- drvr->drvr.speed = USB_SPEED_HIGH;
- #else
- drvr->drvr.speed = USB_SPEED_FULL;
- #endif
- drvr->drvr.ops = &g_driverops;
- drvr->dev = priv;
- /* Register the USB serial class driver */
- ret = usbdev_register(&drvr->drvr);
- if (ret)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_DEVREGISTER), (uint16_t)-ret);
- goto errout_with_alloc;
- }
- /* Register the USB serial console */
- #ifdef CONFIG_PL2303_CONSOLE
- priv->serdev.isconsole = true;
- ret = uart_register("/dev/console", &priv->serdev);
- if (ret < 0)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_CONSOLEREGISTER), (uint16_t)-ret);
- goto errout_with_class;
- }
- #endif
- /* Register the single port supported by this implementation */
- sprintf(devname, "/dev/ttyUSB%d", minor);
- ret = uart_register(devname, &priv->serdev);
- if (ret)
- {
- usbtrace(TRACE_CLSERROR(USBSER_TRACEERR_UARTREGISTER), (uint16_t)-ret);
- goto errout_with_class;
- }
- return OK;
- errout_with_class:
- usbdev_unregister(&drvr->drvr);
- errout_with_alloc:
- kfree(alloc);
- return ret;
- }
|