Newer
Older
if (epno >= STM32_NENDPOINTS)
{
usbtrace(TRACE_DEVERROR(STM32_TRACEERR_BADEPNO), (uint16)epno);
return NULL;
}
/* Convert the logical address to a physical OUT endpoint address and
* remove all of the candidate endpoints from the bitset except for the
* the IN/OUT pair for this logical address.
*/
epset = STM32_ENDP_BIT(epno);
}
/* Check if the selected endpoint number is available */
if (!privep)
{
usbtrace(TRACE_DEVERROR(STM32_TRACEERR_EPRESERVE), (uint16)epset);
goto errout;
}
epno = USB_EPNO(privep->ep.eplog);
/* Allocate a PMA buffer for this endpoint */
#warning "REVISIT: Should configure BULK EPs using double buffer feature"
if (bufno < 0)
{
usbtrace(TRACE_DEVERROR(STM32_TRACEERR_EPBUFFER), 0);
goto errout_with_ep;
}
privep->bufno = (ubyte)bufno;
return &privep->ep;
errout_with_ep:
errout:
return NULL;
}
/****************************************************************************
* Name: stm32_freeep
****************************************************************************/
static void stm32_freeep(struct usbdev_s *dev, struct usbdev_ep_s *ep)
{
struct stm32_usbdev_s *priv;
struct stm32_ep_s *privep;
#ifdef CONFIG_DEBUG
if (!dev || !ep)
{
usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDPARMS), 0);
}
#endif
priv = (struct stm32_usbdev_s *)dev;
privep = (struct stm32_ep_s *)ep;
usbtrace(TRACE_DEVFREEEP, (uint16)USB_EPNO(ep->eplog));
if (priv && privep)
{
/* Free the PMA buffer assigned to this endpoint */
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
}
}
/****************************************************************************
* Name: stm32_getframe
****************************************************************************/
static int stm32_getframe(struct usbdev_s *dev)
{
uint16 fnr;
#ifdef CONFIG_DEBUG
if (!dev)
{
usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDPARMS), 0);
return -EINVAL;
}
#endif
/* Return the last frame number detected by the hardware */
fnr = stm32_getreg(STM32_USB_FNR);
usbtrace(TRACE_DEVGETFRAME, fnr);
return (fnr & USB_FNR_FN_MASK);
}
/****************************************************************************
* Name: stm32_wakeup
****************************************************************************/
static int stm32_wakeup(struct usbdev_s *dev)
{
struct stm32_usbdev_s *priv = (struct stm32_usbdev_s *)dev;
irqstate_t flags;
usbtrace(TRACE_DEVWAKEUP, 0);
#ifdef CONFIG_DEBUG
if (!dev)
{
usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDPARMS), 0);
return -EINVAL;
}
#endif
/* Start the resume sequence. The actual resume steps will be driven
* by the ESOF interrupt.
*/
flags = irqsave();
stm32_initresume(priv);
priv->rsmstate = RSMSTATE_STARTED;
/* Disable the SUSP interrupt (until we are fully resumed), disable
* the WKUP interrupt (we are already waking up), and enable the
* ESOF interrupt that will drive the resume operations. Clear any
* pending ESOF interrupt.
stm32_setimask(priv, USB_CNTR_ESOFM, USB_CNTR_WKUPM|USB_CNTR_SUSPM);
stm32_putreg(~USB_ISTR_ESOF, STM32_USB_ISTR);
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
irqrestore(flags);
return OK;
}
/****************************************************************************
* Name: stm32_selfpowered
****************************************************************************/
static int stm32_selfpowered(struct usbdev_s *dev, boolean selfpowered)
{
struct stm32_usbdev_s *priv = (struct stm32_usbdev_s *)dev;
usbtrace(TRACE_DEVSELFPOWERED, (uint16)selfpowered);
#ifdef CONFIG_DEBUG
if (!dev)
{
usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDPARMS), 0);
return -ENODEV;
}
#endif
priv->selfpowered = selfpowered;
return OK;
}
/****************************************************************************
****************************************************************************/
/****************************************************************************
* Name: stm32_reset
****************************************************************************/
static void stm32_reset(struct stm32_usbdev_s *priv)
{
int epno;
/* Put the USB controller in reset, disable all interrupts */
stm32_putreg(USB_CNTR_FRES, STM32_USB_CNTR);
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
/* Reset the device state structure */
priv->devstate = DEVSTATE_INIT;
priv->rsmstate = RSMSTATE_IDLE;
priv->rxpending = FALSE;
/* Reset endpoints */
for (epno = 0; epno < STM32_NENDPOINTS; epno++)
{
struct stm32_ep_s *privep = &priv->eplist[epno];
/* Cancel any queue requests */
stm32_cancelrequests(privep);
/* Reset endpoint status */
privep->stalled = FALSE;
privep->halted = FALSE;
privep->txbusy = FALSE;
privep->txnullpkt = FALSE;
}
/* Re-configure the USB controller in its initial, unconnected state */
stm32_hwreset(priv);
}
/****************************************************************************
* Name: stm32_hwreset
****************************************************************************/
static void stm32_hwreset(struct stm32_usbdev_s *priv)
{
/* Put the USB controller into reset, clear all interrupt enables */
/* Disable interrupts (and perhaps take the USB controller out of reset) */
priv->imask = 0;
stm32_putreg(priv->imask, STM32_USB_CNTR);
/* Set the STM32 BTABLE address */
stm32_putreg(STM32_BTABLE_ADDRESS & 0xfff8, STM32_USB_BTABLE);
/* Initialize EP0 */
stm32_seteptype(EP0, USB_EPR_EPTYPE_CONTROL);
stm32_seteptxstatus(EP0, USB_EPR_STATTX_NAK);
stm32_seteprxaddr(EP0, STM32_EP0_RXADDR);
stm32_seteptxaddr(EP0, STM32_EP0_TXADDR);
stm32_clrstatusout(EP0);
stm32_seteprxstatus(EP0, USB_EPR_STATRX_VALID);
/* Set the device to respond on default address */
stm32_setdevaddr(priv, 0);
/* Clear any pending interrupts */
stm32_putreg(0, STM32_USB_ISTR);
/* Enable interrupts at the USB controller */
stm32_setimask(priv, STM32_CNTR_SETUP, (USB_CNTR_ALLINTS & ~STM32_CNTR_SETUP));
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: up_usbinitialize
* Description:
* Initialize the USB driver
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
void up_usbinitialize(void)
{
/* For now there is only one USB controller, but we will always refer to
* it using a pointer to make any future ports to multiple USB controllers
* easier.
*/
struct stm32_usbdev_s *priv = &g_usbdev;
int epno;
usbtrace(TRACE_DEVINIT, 0);
/* Power the USB controller, put the USB controller into reset, disable
* all USB interrupts
*/
stm32_putreg(USB_CNTR_FRES|USB_CNTR_PDWN, STM32_USB_CNTR);
/* Disconnect the device / disable the pull-up. We don't want the
* host to enumerate us until the class driver is registered.
*/
stm32_usbpullup(&priv->usbdev, FALSE);
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
/* Initialize the device state structure. NOTE: many fields
* have the initial value of zero and, hence, are not explicitly
* initialized here.
*/
memset(priv, 0, sizeof(struct stm32_usbdev_s));
priv->usbdev.ops = &g_devops;
priv->usbdev.ep0 = &priv->eplist[EP0].ep;
priv->epavail = STM32_ENDP_ALLSET & ~STM32_ENDP_BIT(EP0);
priv->bufavail = STM32_BUFFER_ALLSET & ~STM32_BUFFER_EP0;
/* Initialize the endpoint list */
for (epno = 0; epno < STM32_NENDPOINTS; epno++)
{
/* Set endpoint operations, reference to driver structure (not
* really necessary because there is only one controller), and
* the (physical) endpoint number which is just the index to the
* endpoint.
*/
priv->eplist[epno].ep.ops = &g_epops;
priv->eplist[epno].dev = priv;
priv->eplist[epno].ep.eplog = epno;
/* We will use a fixed maxpacket size for all endpoints (perhaps
* ISOC endpoints could have larger maxpacket???). A smaller
* packet size can be selected when the endpoint is configured.
*/
priv->eplist[epno].ep.maxpacket = STM32_MAXPACKET_SIZE;
}
/* Select a smaller endpoint size for EP0 */
#if STM32_EP0MAXPACKET < STM32_MAXPACKET_SIZE
priv->eplist[EP0].ep.maxpacket = STM32_EP0MAXPACKET;
#endif
/* Power up the USB controller, holding it in reset. There is a delay of
* about 1uS after applying power before the USB will behave predictably.
* A 5MS delay is more than enough. NOTE that we leave the USB controller
* in the reset state; the hardware will not be initialized until the
* class driver has been bound.
*/
stm32_putreg(USB_CNTR_FRES, STM32_USB_CNTR);
/* Attach USB controller interrupt handlers. The hardware will not be
* initialized and interrupts will not be enabled until the class device
* driver is bound. Getting the IRQs here only makes sure that we have
* them when we need them later.
if (irq_attach(STM32_IRQ_USBHPCANTX, stm32_hpinterrupt) != 0)
{
usbtrace(TRACE_DEVERROR(STM32_TRACEERR_IRQREGISTRATION),
(uint16)STM32_IRQ_USBHPCANTX);
goto errout;
}
if (irq_attach(STM32_IRQ_USBLPCANRX0, stm32_lpinterrupt) != 0)
{
usbtrace(TRACE_DEVERROR(STM32_TRACEERR_IRQREGISTRATION),
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
goto errout;
}
return;
errout:
up_usbuninitialize();
}
/****************************************************************************
* Name: up_usbuninitialize
* Description:
* Initialize the USB driver
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
void up_usbuninitialize(void)
{
/* For now there is only one USB controller, but we will always refer to
* it using a pointer to make any future ports to multiple USB controllers
* easier.
*/
struct stm32_usbdev_s *priv = &g_usbdev;
uint16 regval;
irqstate_t flags;
usbtrace(TRACE_DEVUNINIT, 0);
if (priv->driver)
{
usbtrace(TRACE_DEVERROR(STM32_TRACEERR_DRIVERREGISTERED), 0);
usbdev_unregister(priv->driver);
}
flags = irqsave();
priv->usbdev.speed = USB_SPEED_UNKNOWN;
/* Disable and detach IRQs */
up_disable_irq(STM32_IRQ_USBHPCANTX);
up_disable_irq(STM32_IRQ_USBLPCANRX0);
irq_detach(STM32_IRQ_USBHPCANTX);
/* Disable all interrupts and force the USB controller into reset */
stm32_putreg(USB_CNTR_FRES, STM32_USB_CNTR);
/* Clear any pending interrupts */
/* Disconnect the device / disable the pull-up */
stm32_usbpullup(&priv->usbdev, FALSE);
/* Power down the USB controller */
stm32_putreg(USB_CNTR_FRES|USB_CNTR_PDWN, STM32_USB_CNTR);
irqrestore(flags);
}
/****************************************************************************
* Name: usbdev_register
*
* Description:
* Register a USB device class driver. The class driver's bind() method will be
* called to bind it to a USB device driver.
*
****************************************************************************/
int usbdev_register(struct usbdevclass_driver_s *driver)
{
/* For now there is only one USB controller, but we will always refer to
* it using a pointer to make any future ports to multiple USB controllers
* easier.
*/
struct stm32_usbdev_s *priv = &g_usbdev;
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
int ret;
usbtrace(TRACE_DEVREGISTER, 0);
#ifdef CONFIG_DEBUG
if (!driver || !driver->ops->bind || !driver->ops->unbind ||
!driver->ops->disconnect || !driver->ops->setup)
{
usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDPARMS), 0);
return -EINVAL;
}
if (priv->driver)
{
usbtrace(TRACE_DEVERROR(STM32_TRACEERR_DRIVER), 0);
return -EBUSY;
}
#endif
/* First hook up the driver */
ret = CLASS_BIND(driver, &priv->usbdev);
if (ret)
{
usbtrace(TRACE_DEVERROR(STM32_TRACEERR_BINDFAILED), (uint16)-ret);
/* Setup the USB controller -- enabling interrupts at the USB controller */
stm32_hwreset(priv);
/* Enable USB controller interrupts at the NVIC */
/* Set the interrrupt priority */
up_prioritize_irq(STM32_IRQ_USBHPCANTX, CONFIG_USB_PRI);
/* Enable pull-up to connect the device. The host should enumerate us
* some time after this
*/
}
return ret;
}
/****************************************************************************
* Name: usbdev_unregister
*
* Description:
* Un-register usbdev class driver.If the USB device is connected to a USB host,
* it will first disconnect(). The driver is also requested to unbind() and clean
* up any device state, before this procedure finally returns.
*
****************************************************************************/
int usbdev_unregister(struct usbdevclass_driver_s *driver)
{
/* For now there is only one USB controller, but we will always refer to
* it using a pointer to make any future ports to multiple USB controllers
* easier.
*/
struct stm32_usbdev_s *priv = &g_usbdev;
usbtrace(TRACE_DEVUNREGISTER, 0);
#ifdef CONFIG_DEBUG
if (driver != priv->driver)
{
usbtrace(TRACE_DEVERROR(STM32_TRACEERR_INVALIDPARMS), 0);
return -EINVAL;
}
#endif
/* Unbind the class driver */
CLASS_UNBIND(driver, &priv->usbdev);
/* Disable USB controller interrupts */
up_disable_irq(STM32_IRQ_USBHPCANTX);
up_disable_irq(STM32_IRQ_USBLPCANRX0);
/* Unhook the driver */