Example #1
0
static inline int mio283qt2_hwinitialize(FAR struct mio283qt2_dev_s *priv)
{
  FAR struct mio283qt2_lcd_s *lcd  = priv->lcd;
#ifndef CONFIG_LCD_NOGETRUN
  uint16_t id;
#endif
  int ret;

  /* Select the LCD */

  lcd->select(lcd);

  /* Read the HIMAX ID registger (0x00) */

#ifndef CONFIG_LCD_NOGETRUN
  id = mio283qt2_readreg(lcd, 0x00);
  lcddbg("LCD ID: %04x\n", id);

  /* Check if the ID is for the MIO283QT2 */

  if (id == HIMAX_ID)
#endif
    {
      /* Driving ability */

      mio283qt2_putreg(lcd, 0xea, 0x0000);  /* PTBA[15:8] */
      mio283qt2_putreg(lcd, 0xeb, 0x0020);  /* PTBA[7:0] */
      mio283qt2_putreg(lcd, 0xec, 0x000c);  /* STBA[15:8] */
      mio283qt2_putreg(lcd, 0xed, 0x00c4);  /* STBA[7:0] */
      mio283qt2_putreg(lcd, 0xe8, 0x0040);  /* OPON[7:0] */
      mio283qt2_putreg(lcd, 0xe9, 0x0038);  /* OPON1[7:0] */
      mio283qt2_putreg(lcd, 0xf1, 0x0001);  /* OTPS1B */
      mio283qt2_putreg(lcd, 0xf2, 0x0010);  /* GEN */
      mio283qt2_putreg(lcd, 0x27, 0x00a3);

      /* Power voltage */

      mio283qt2_putreg(lcd, 0x1b, 0x001b);  /* VRH = 4.65 */
      mio283qt2_putreg(lcd, 0x1a, 0x0001);  /* BT */
      mio283qt2_putreg(lcd, 0x24, 0x002f);  /* VMH */
      mio283qt2_putreg(lcd, 0x25, 0x0057);  /* VML */

      /* Vcom offset */

      mio283qt2_putreg(lcd, 0x23, 0x008d);  /* For flicker adjust */

      /* Power on */

      mio283qt2_putreg(lcd, 0x18, 0x0036);
      mio283qt2_putreg(lcd, 0x19, 0x0001); /* Start oscillator */
      mio283qt2_putreg(lcd, 0x01, 0x0000); /* Wakeup */
      mio283qt2_putreg(lcd, 0x1f, 0x0088);
      up_mdelay(5);
      mio283qt2_putreg(lcd, 0x1f, 0x0080);
      up_mdelay(5);
      mio283qt2_putreg(lcd, 0x1f, 0x0090);
      up_mdelay(5);
      mio283qt2_putreg(lcd, 0x1f, 0x00d0);
      up_mdelay(5);

      /* Gamma 2.8 setting  */

      mio283qt2_putreg(lcd, 0x40, 0x0000);
      mio283qt2_putreg(lcd, 0x41, 0x0000);
      mio283qt2_putreg(lcd, 0x42, 0x0001);
      mio283qt2_putreg(lcd, 0x43, 0x0013);
      mio283qt2_putreg(lcd, 0x44, 0x0010);
      mio283qt2_putreg(lcd, 0x45, 0x0026);
      mio283qt2_putreg(lcd, 0x46, 0x0008);
      mio283qt2_putreg(lcd, 0x47, 0x0051);
      mio283qt2_putreg(lcd, 0x48, 0x0002);
      mio283qt2_putreg(lcd, 0x49, 0x0012);
      mio283qt2_putreg(lcd, 0x4a, 0x0018);
      mio283qt2_putreg(lcd, 0x4b, 0x0019);
      mio283qt2_putreg(lcd, 0x4c, 0x0014);

      mio283qt2_putreg(lcd, 0x50, 0x0019);
      mio283qt2_putreg(lcd, 0x51, 0x002f);
      mio283qt2_putreg(lcd, 0x52, 0x002c);
      mio283qt2_putreg(lcd, 0x53, 0x003e);
      mio283qt2_putreg(lcd, 0x54, 0x003f);
      mio283qt2_putreg(lcd, 0x55, 0x003f);
      mio283qt2_putreg(lcd, 0x56, 0x002e);
      mio283qt2_putreg(lcd, 0x57, 0x0077);
      mio283qt2_putreg(lcd, 0x58, 0x000b);
      mio283qt2_putreg(lcd, 0x59, 0x0006);
      mio283qt2_putreg(lcd, 0x5a, 0x0007);
      mio283qt2_putreg(lcd, 0x5b, 0x000d);
      mio283qt2_putreg(lcd, 0x5c, 0x001d);
      mio283qt2_putreg(lcd, 0x5d, 0x00cc);

      /* 4K Color Selection */

      mio283qt2_putreg(lcd, 0x17, 0x0003);
      mio283qt2_putreg(lcd, 0x17, 0x0005); /* 0x0005=65k, 0x0006=262k */

      /* Panel characteristics */

      mio283qt2_putreg(lcd, 0x36, 0x0000);

      /* Display Setting */

      mio283qt2_putreg(lcd, 0x01, 0x0000); /* IDMON=0, INVON=0, NORON=0, PTLON=0 */

#if defined(CONFIG_LCD_LANDSCAPE)
      mio283qt2_putreg(lcd, 0x16, 0x00a8); /* MY=1, MX=0, MV=1, ML=0, BGR=1 */
#elif defined(CONFIG_LCD_PORTRAIT)
      mio283qt2_putreg(lcd, 0x16, 0x0008); /* MY=0, MX=0, MV=0, ML=0, BGR=1 */
#elif defined(CONFIG_LCD_RLANDSCAPE)
      mio283qt2_putreg(lcd, 0x16, 0x0068); /* MY=0, MX=1, MV=1, ML=0, BGR=1 */
#elif defined(CONFIG_LCD_RPORTRAIT)
      mio283qt2_putreg(lcd, 0x16, 0x00c8); /* MY=1, MX=0, MV=1, ML=0, BGR=1 */
#endif

      /* Window setting */

      mio283qt2_setarea(lcd, 0, 0, (MIO283QT2_XRES-1), (MIO283QT2_YRES-1));
      ret = OK;
    }
#ifndef CONFIG_LCD_NOGETRUN
  else
    {
      lcddbg("Unsupported LCD type\n");
      ret = -ENODEV;
    }
#endif

  /* De-select the LCD */

  lcd->deselect(lcd);
  return ret;
}
Example #2
0
static int can_close(FAR struct file *filep)
{
  FAR struct inode     *inode = filep->f_inode;
  FAR struct can_dev_s *dev   = inode->i_private;
  irqstate_t            flags;
  int                   ret = OK;

  canvdbg("ocount: %d\n", dev->cd_ocount);

  if (sem_wait(&dev->cd_closesem) != OK)
    {
      ret = -get_errno();
    }
  else
    {
      /* Decrement the references to the driver.  If the reference count will
       * decrement to 0, then uninitialize the driver.
       */

      if (dev->cd_ocount > 1)
        {
          dev->cd_ocount--;
          sem_post(&dev->cd_closesem);
        }
      else
        {
          /* There are no more references to the port */

          dev->cd_ocount = 0;

          /* Stop accepting input */

          dev_rxint(dev, false);

          /* Now we wait for the transmit FIFO to clear */

          while (dev->cd_xmit.tx_head != dev->cd_xmit.tx_tail)
            {
#ifndef CONFIG_DISABLE_SIGNALS
               usleep(HALF_SECOND_USEC);
#else
               up_mdelay(HALF_SECOND_MSEC);
#endif
            }

          /* And wait for the TX hardware FIFO to drain */

          while (!dev_txempty(dev))
            {
#ifndef CONFIG_DISABLE_SIGNALS
              usleep(HALF_SECOND_USEC);
#else
              up_mdelay(HALF_SECOND_MSEC);
#endif
            }

          /* Free the IRQ and disable the CAN device */

          flags = irqsave();       /* Disable interrupts */
          dev_shutdown(dev);       /* Disable the CAN */
          irqrestore(flags);

          sem_post(&dev->cd_closesem);
        }
    }

  return ret;
}
Example #3
0
static inline int ssd1289_hwinitialize(FAR struct ssd1289_dev_s *priv)
{
  FAR struct ssd1289_lcd_s *lcd  = priv->lcd;
#ifndef CONFIG_LCD_NOGETRUN
  uint16_t id;
#endif
  int ret;

  /* Select the LCD */

  lcd->select(lcd);

  /* Read the device ID.  Skip verification of the device ID is the LCD is
   * write-only. What choice do we have?
   */

#ifndef CONFIG_LCD_NOGETRUN
  id = ssd1289_readreg(lcd, SSD1289_DEVCODE);
  if (id != 0)
    {
      lcddbg("LCD ID: %04x\n", id);
    }

  /* If we could not get the ID, then let's just assume that this is an SSD1289.
   * Perhaps we have some early register access issues.  This seems to happen.
   * But then perhaps we should not even bother to read the device ID at all?
   */

  else
    {
      lcddbg("No LCD ID, assuming SSD1289\n");
      id = SSD1289_DEVCODE_VALUE;
    }

  /* Check if the ID is for the SSD1289 */

  if (id == SSD1289_DEVCODE_VALUE)
#endif
    {
      /* LCD controller configuration.  Many details of the controller initialization
       * must, unfortunately, vary from LCD to LCD.  I have looked at the spec and at
       * three different drivers for LCDs that have SSD1289 controllers.  I have tried
       * to summarize these differences as profiles (defined above).  Some other
       * alternatives are noted below.
       *
       * Most of the differences between LCDs are nothing more than a few minor bit
       * settings.  The most significant difference betwen LCD drivers in is the
       * manner in which the LCD is powered up and in how the power controls are set.
       * My suggestion is that if you have working LCD initialization code, you should
       * simply replace the following guesses with your working code.
       */

      /* Most drivers just enable the oscillator */

#ifdef SSD1289_USE_SIMPLE_INIT
      ssd1289_putreg(lcd, SSD1289_OSCSTART, SSD1289_OSCSTART_OSCEN);
#else
      /* But one goes through a more complex start-up sequence.  Something like the
       * following:
       *
       * First, put the display in INTERNAL operation:
       * D=INTERNAL(1) CM=0 DTE=0 GON=1 SPT=0 VLE=0 PT=0
       */

      ssd1289_putreg(lcd, SSD1289_DSPCTRL,
                     (SSD1289_DSPCTRL_INTERNAL | SSD1289_DSPCTRL_GON |
                      SSD1289_DSPCTRL_VLE(0))); 

      /* Then enable the oscillator */

      ssd1289_putreg(lcd, SSD1289_OSCSTART, SSD1289_OSCSTART_OSCEN);

      /* Turn the display on:
       * D=ON(3) CM=0 DTE=0 GON=1 SPT=0 VLE=0 PT=0
       */

      ssd1289_putreg(lcd, SSD1289_DSPCTRL,
                     (SSD1289_DSPCTRL_ON | SSD1289_DSPCTRL_GON |
                      SSD1289_DSPCTRL_VLE(0))); 

     /* Take the LCD out of sleep mode */

      ssd1289_putreg(lcd, SSD1289_SLEEP, 0);
      up_mdelay(30);

      /* Turn the display on:
       * D=INTERNAL(1) CM=0 DTE=1 GON=1 SPT=0 VLE=0 PT=0
       */

      ssd1289_putreg(lcd, SSD1289_DSPCTRL,
                     (SSD1289_DSPCTRL_ON | SSD1289_DSPCTRL_DTE |
                      SSD1289_DSPCTRL_GON | SSD1289_DSPCTRL_VLE(0))); 
#endif

      /* Set up power control registers.  There is a lot of variability
       * from LCD-to-LCD in how the power registers are configured.
       */

      ssd1289_putreg(lcd, SSD1289_PWRCTRL1, PWRCTRL1_SETTING);
      ssd1289_putreg(lcd, SSD1289_PWRCTRL2, PWRCTRL2_SETTING);

      /* One driver adds a delay here.. I doubt that this is really necessary. */
      /* up_mdelay(15); */

      ssd1289_putreg(lcd, SSD1289_PWRCTRL3, PWRCTRL3_SETTING);
      ssd1289_putreg(lcd, SSD1289_PWRCTRL4, PWRCTRL4_SETTING);
      ssd1289_putreg(lcd, SSD1289_PWRCTRL5, PWRCTRL5_SETTING);

      /* One driver does an odd setting of the the driver output control.
       * No idea why.
       */
#if 0
      ssd1289_putreg(lcd, SSD1289_OUTCTRL,
                     (SSD1289_OUTCTRL_MUX(12) | SSD1289_OUTCTRL_TB |
                      SSD1289_OUTCTRL_BGR | SSD1289_OUTCTRL_CAD));

      /* The same driver does another small delay here */

      up_mdelay(15);
#endif

      /* After this point, the drivers differ only in some varying register
       * bit settings.
       */

      /* Set the driver output control.
       * PORTRAIT MODES:
       *    MUX=319, TB=1, SM=0, BGR=1, CAD=0, REV=1, RL=0
       * LANDSCAPE MODES:
       *    MUX=319, TB=0, SM=0, BGR=1, CAD=0, REV=1, RL=0
       */

#if defined(CONFIG_LCD_PORTRAIT) || defined(CONFIG_LCD_RPORTRAIT)
      ssd1289_putreg(lcd, SSD1289_OUTCTRL,
                     (SSD1289_OUTCTRL_MUX(319) | SSD1289_OUTCTRL_TB |
                      SSD1289_OUTCTRL_BGR      | SSD1289_OUTCTRL_REV);
#else
      ssd1289_putreg(lcd, SSD1289_OUTCTRL,
                     (SSD1289_OUTCTRL_MUX(319) | SSD1289_OUTCTRL_BGR |
                      SSD1289_OUTCTRL_REV));
#endif

      /* Set the LCD driving AC waveform
       * NW=0, WSMD=0, EOR=1, BC=1, ENWD=0, FLD=0
       */

      ssd1289_putreg(lcd, SSD1289_ACCTRL,
                     (SSD1289_ACCTRL_EOR | SSD1289_ACCTRL_BC));

      /* Take the LCD out of sleep mode (isn't this redundant in the non-
       * simple case?)
       */

      ssd1289_putreg(lcd, SSD1289_SLEEP, 0);

      /* Set entry mode */

#if defined(CONFIG_LCD_PORTRAIT) || defined(CONFIG_LCD_RPORTRAIT)
      /* LG=0, AM=0, ID=3, TY=2, DMODE=0, WMODE=0, OEDEF=0, TRANS=0, DRM=3
       * Alternative TY=2 (But TY only applies in 262K color mode anyway)
       */

      ssd1289_putreg(lcd, SSD1289_ENTRY,
                    (SSD1289_ENTRY_ID_HINCVINC | SSD1289_ENTRY_TY_C |
                     SSD1289_ENTRY_DMODE_RAM | SSD1289_ENTRY_DFM_65K));
#else
      /* LG=0, AM=1, ID=3, TY=2, DMODE=0, WMODE=0, OEDEF=0, TRANS=0, DRM=3 */
      /* Alternative TY=2 (But TY only applies in 262K color mode anyway) */

      ssd1289_putreg(lcd, SSD1289_ENTRY,
                    (SSD1289_ENTRY_AM | SSD1289_ENTRY_ID_HINCVINC |
                     SSD1289_ENTRY_TY_C | SSD1289_ENTRY_DMODE_RAM |
                     SSD1289_ENTRY_DFM_65K));
#endif

      /* Clear compare registers */

      ssd1289_putreg(lcd, SSD1289_CMP1, 0);
      ssd1289_putreg(lcd, SSD1289_CMP2, 0);

      /* One driver puts a huge, 100 millisecond delay here */
      /* up_mdelay(100); */

      /* Set Horizontal and vertical porch.
       * Horizontal porch:  239 pixels per line, delay=28
       * Vertical porch:    VBP=3, XFP=0
       */

      ssd1289_putreg(lcd, SSD1289_HPORCH,
                     (28 << SSD1289_HPORCH_HBP_SHIFT) | (239 << SSD1289_HPORCH_XL_SHIFT));
      ssd1289_putreg(lcd, SSD1289_VPORCH,
                     (3 << SSD1289_VPORCH_VBP_SHIFT)  | (0 << SSD1289_VPORCH_XFP_SHIFT));

      /* Set display control.
       * D=ON(3), CM=0 (not 8-color), DTE=1, GON=1, SPT=0, VLE=1 PT=0
       */

      ssd1289_putreg(lcd, SSD1289_DSPCTRL,
                     (SSD1289_DSPCTRL_ON  | SSD1289_DSPCTRL_DTE |
                      SSD1289_DSPCTRL_GON | SSD1289_DSPCTRL_VLE(1))); 

      /* Frame cycle control.  Alternative: SSD1289_FCYCCTRL_DIV8 */

      ssd1289_putreg(lcd, SSD1289_FCYCCTRL, 0);

      /* Gate scan start position = 0 */

      ssd1289_putreg(lcd, SSD1289_GSTART, 0);

      /* Clear vertical scrolling */

      ssd1289_putreg(lcd, SSD1289_VSCROLL1, 0);
      ssd1289_putreg(lcd, SSD1289_VSCROLL2, 0);

      /* Setup window 1 (0-319) */

      ssd1289_putreg(lcd, SSD1289_W1START, 0);
      ssd1289_putreg(lcd, SSD1289_W1END, 319);

      /* Disable window 2 (0-0) */

      ssd1289_putreg(lcd, SSD1289_W2START, 0);
      ssd1289_putreg(lcd, SSD1289_W2END, 0);

      /* Horizontal start and end (0-239) */

      ssd1289_putreg(lcd, SSD1289_HADDR,
                    (0 << SSD1289_HADDR_HSA_SHIFT) | (239 << SSD1289_HADDR_HEA_SHIFT));

      /* Vertical start and end (0-319) */

      ssd1289_putreg(lcd, SSD1289_VSTART, 0);
      ssd1289_putreg(lcd, SSD1289_VEND, 319);

      /* Gamma controls */

      ssd1289_putreg(lcd, SSD1289_GAMMA1, 0x0707);
      ssd1289_putreg(lcd, SSD1289_GAMMA2, 0x0204); /* Alternative: 0x0704 */
      ssd1289_putreg(lcd, SSD1289_GAMMA3, 0x0204);
      ssd1289_putreg(lcd, SSD1289_GAMMA4, 0x0502);
      ssd1289_putreg(lcd, SSD1289_GAMMA5, 0x0507);
      ssd1289_putreg(lcd, SSD1289_GAMMA6, 0x0204);
      ssd1289_putreg(lcd, SSD1289_GAMMA7, 0x0204);
      ssd1289_putreg(lcd, SSD1289_GAMMA8, 0x0502);
      ssd1289_putreg(lcd, SSD1289_GAMMA9, 0x0302);
      ssd1289_putreg(lcd, SSD1289_GAMMA10, 0x0302); /* Alternative: 0x1f00 */

      /* Clear write mask */

      ssd1289_putreg(lcd, SSD1289_WRMASK1, 0);
      ssd1289_putreg(lcd, SSD1289_WRMASK2, 0);

      /* Set frame frequency = 65Hz (This should not be necessary since this
       * is the default POR value)
       */

      ssd1289_putreg(lcd, SSD1289_FFREQ, SSD1289_FFREQ_OSC_FF65);

      /* Set the cursor at the home position and set the index register to
       * the gram data register (I can't imagine these are necessary).
       */

      ssd1289_setcursor(lcd, 0, 0);
      ssd1289_gramselect(lcd);

      /* One driver has a 50 msec delay here */
      /* up_mdelay(50); */

      ret = OK;
    }
Example #4
0
static void usbclass_unbind(struct usbdevclass_driver_s *driver,
                            struct usbdev_s *dev)
{
    struct apbridge_dev_s *priv;

    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 = ((struct apbridge_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 the bulk OUT endpoint */

        if (priv->epbulkout) {
            DEV_FREEEP(dev, priv->epbulkout);
            priv->epbulkout = NULL;
        }
    }
}
Example #5
0
static int uart_close(FAR struct file *filep)
{
  FAR struct inode *inode = filep->f_inode;
  FAR uart_dev_t   *dev   = inode->i_private;
  irqstate_t        flags;

  /* Get exclusive access to the close semaphore (to synchronize open/close operations.
   * NOTE: that we do not let this wait be interrupted by a signal.  Technically, we
   * should, but almost no one every checks the return value from close() so we avoid
   * a potential memory leak by ignoring signals in this case.
   */

  (void)uart_takesem(&dev->closesem, false);
  if (dev->open_count > 1)
    {
      dev->open_count--;
      uart_givesem(&dev->closesem);
      return OK;
    }

  /* There are no more references to the port */

  dev->open_count = 0;

  /* Stop accepting input */

  uart_disablerxint(dev);

  /* Now we wait for the transmit buffer to clear */

  while (dev->xmit.head != dev->xmit.tail)
    {
#ifndef CONFIG_DISABLE_SIGNALS
      usleep(HALF_SECOND_USEC);
#else
      up_mdelay(HALF_SECOND_MSEC);
#endif
    }

  /* And wait for the TX fifo to drain */

  while (!uart_txempty(dev))
    {
#ifndef CONFIG_DISABLE_SIGNALS
      usleep(HALF_SECOND_USEC);
#else
      up_mdelay(HALF_SECOND_MSEC);
#endif
    }

  /* Free the IRQ and disable the UART */

  flags = irqsave();       /* Disable interrupts */
  uart_detach(dev);        /* Detach interrupts */
  if (!dev->isconsole)     /* Check for the serial console UART */
    {
      uart_shutdown(dev);  /* Disable the UART */
    }
  irqrestore(flags);

  uart_givesem(&dev->closesem);
  return OK;
 }
Example #6
0
static int uart_close(FAR struct file *filep)
{
  FAR struct inode *inode = filep->f_inode;
  FAR uart_dev_t   *dev   = inode->i_private;
  irqstate_t        flags;

  /* Get exclusive access to the close semaphore (to synchronize open/close operations.
   * NOTE: that we do not let this wait be interrupted by a signal.  Technically, we
   * should, but almost no one every checks the return value from close() so we avoid
   * a potential memory leak by ignoring signals in this case.
   */

  (void)uart_takesem(&dev->closesem, false);
  if (dev->open_count > 1)
    {
      dev->open_count--;
      uart_givesem(&dev->closesem);
      return OK;
    }

  /* There are no more references to the port */

  dev->open_count = 0;

  /* Stop accepting input */

  uart_disablerxint(dev);

  /* Now we wait for the transmit buffer to clear */

  while (dev->xmit.head != dev->xmit.tail)
    {
#ifndef CONFIG_DISABLE_SIGNALS
      usleep(HALF_SECOND_USEC);
#else
      up_mdelay(HALF_SECOND_MSEC);
#endif
    }

  /* And wait for the TX fifo to drain */

  while (!uart_txempty(dev))
    {
#ifndef CONFIG_DISABLE_SIGNALS
      usleep(HALF_SECOND_USEC);
#else
      up_mdelay(HALF_SECOND_MSEC);
#endif
    }

  /* Free the IRQ and disable the UART */

  flags = irqsave();       /* Disable interrupts */
  uart_detach(dev);        /* Detach interrupts */
  if (!dev->isconsole)     /* Check for the serial console UART */
    {
      uart_shutdown(dev);  /* Disable the UART */
    }

  irqrestore(flags);

  /* We need to re-initialize the semaphores if this is the last close
   * of the device, as the close might be caused by pthread_cancel() of
   * a thread currently blocking on any of them.
   *
   * REVISIT:  This logic *only* works in the case where the cancelled
   * thread had the only reference to the serial driver.  If there other
   * references, then the this logic will not be executed and the
   * semaphore count will still be incorrect.
   */

  sem_reinit(&dev->xmitsem,  0, 0);
  sem_reinit(&dev->recvsem,  0, 0);
  sem_reinit(&dev->xmit.sem, 0, 1);
  sem_reinit(&dev->recv.sem, 0, 1);
#ifndef CONFIG_DISABLE_POLL
  sem_reinit(&dev->pollsem,  0, 1);
#endif

  uart_givesem(&dev->closesem);
  return OK;
}