Example #1
0
int sam_usbhost_initialize(void)
{
  pid_t pid;
  int ret;

  /* First, register all of the class drivers needed to support the drivers
   * that we care about:
   */

  ret = usbhost_storageinit();
  if (ret != OK)
    {
      udbg("ERROR: Failed to register the mass storage class: %d\n", ret);
    }

#ifdef CONFIG_SAMA5_OHCI
  /* Get an instance of the USB OHCI interface */

  g_ohciconn = sam_ohci_initialize(0);
  if (!g_ohciconn)
    {
      udbg("ERROR: sam_ohci_initialize failed\n");
      return -ENODEV;
    }

  /* Start a thread to handle device connection. */

  pid = TASK_CREATE("usbhost", CONFIG_USBHOST_DEFPRIO,  CONFIG_USBHOST_STACKSIZE,
                    (main_t)ohci_waiter, (FAR char * const *)NULL);
  if (pid < 0)
    {
      udbg("ERROR: Failed to create ohci_waiter task: %d\n", ret);
      return -ENODEV;
    }
#endif

#ifdef CONFIG_SAMA5_EHCI
  /* Get an instance of the USB EHCI interface */

  g_ehciconn = sam_ehci_initialize(0);
  if (!g_ehciconn)
    {
      udbg("ERROR: sam_ehci_initialize failed\n");
      return -ENODEV;
    }

  /* Start a thread to handle device connection. */

  pid = TASK_CREATE("usbhost", CONFIG_USBHOST_DEFPRIO,  CONFIG_USBHOST_STACKSIZE,
                    (main_t)ehci_waiter, (FAR char * const *)NULL);
  if (pid < 0)
    {
      udbg("ERROR: Failed to create ehci_waiter task: %d\n", ret);
      return -ENODEV;
    }
#endif

  return OK;
}
Example #2
0
int stm32_usbhost_initialize(void)
{
  int pid;
  int ret;

  /* First, register all of the class drivers needed to support the drivers
   * that we care about:
   */

  uvdbg("Register class drivers\n");
  ret = usbhost_storageinit();
  if (ret != OK)
    {
      udbg("Failed to register the mass storage class\n");
    }

  /* Then get an instance of the USB host interface */

  uvdbg("Initialize USB host\n");
  g_drvr = usbhost_initialize(0);
  if (g_drvr)
    {
      /* Start a thread to handle device connection. */

      uvdbg("Start usbhost_waiter\n");

      pid = TASK_CREATE("usbhost", CONFIG_USBHOST_DEFPRIO,
                        CONFIG_USBHOST_STACKSIZE,
                        (main_t)usbhost_waiter, (FAR char * const *)NULL);
      return pid < 0 ? -ENOEXEC : OK;
    }

  return -ENODEV;
}
Example #3
0
int ftpd_main(int s_argc, char **s_argv)
{
  /* Check if we have already initialized the network */

  if (!g_ftpdglob.initialized)
    {
  
      /* Bring up the network */

      printf("Initializing the network\n");
      fptd_netinit();

      /* Initialize daemon state */

      g_ftpdglob.initialized = true;
      g_ftpdglob.pid         = -1;
#ifdef CONFIG_NSH_BUILTIN_APPS
      g_ftpdglob.stop        = false;
      g_ftpdglob.running     = false;
#endif
    }

  /* Then start the new daemon (if it is not already running) */

#ifdef CONFIG_NSH_BUILTIN_APPS
  if (g_ftpdglob.stop && g_ftpdglob.running)
    {
      printf("Waiting for FTP daemon [%d] to stop\n", g_ftpdglob.pid);
      return EXIT_FAILURE;
    }
  else
#endif
  if (!g_ftpdglob.running)
    {
      printf("Starting the FTP daemon\n");
      g_ftpdglob.pid = TASK_CREATE("FTP daemon", CONFIG_EXAMPLES_FTPD_PRIO,
                                   CONFIG_EXAMPLES_FTPD_STACKSIZE, 
                                   ftpd_daemon, NULL);
      if (g_ftpdglob.pid < 0)
        {
          printf("Failed to start the FTP daemon: %d\n", errno);
          return EXIT_FAILURE;
        }
    }
   else
    {
      printf("FTP daemon [%d] is running\n", g_ftpdglob.pid);
    }

  return EXIT_SUCCESS;
}
Example #4
0
int os_bringup(void)
{
  int taskid;

  /* Setup up the initial environment for the idle task.  At present, this
   * may consist of only the initial PATH variable.  The PATH variable is
   * (probably) not used by the IDLE task.  However, the environment
   * containing the PATH variable will be inherited by all of the threads
   * created by the IDLE task.
   */

#if !defined(CONFIG_DISABLE_ENVIRON) && defined(CONFIG_PATH_INITIAL)
  (void)setenv("PATH", CONFIG_PATH_INITIAL, 1);
#endif

  /* Start the page fill worker kernel thread that will resolve page faults.
   * This should always be the first thread started because it may have to
   * resolve page faults in other threads
   */

#ifdef CONFIG_PAGING
  svdbg("Starting paging thread\n");

  g_pgworker = KERNEL_THREAD("pgfill", CONFIG_PAGING_DEFPRIO,
                             CONFIG_PAGING_STACKSIZE,
                             (main_t)pg_worker, (FAR char * const *)NULL);
  DEBUGASSERT(g_pgworker > 0);
#endif

  /* Start the worker thread that will serve as the device driver "bottom-
   * half" and will perform misc garbage clean-up.
   */

#ifdef CONFIG_SCHED_WORKQUEUE
#ifdef CONFIG_SCHED_HPWORK

#ifdef CONFIG_SCHED_LPWORK
  svdbg("Starting high-priority kernel worker thread\n");
#else
  svdbg("Starting kernel worker thread\n");
#endif

  g_work[HPWORK].pid = KERNEL_THREAD(HPWORKNAME, CONFIG_SCHED_WORKPRIORITY,
                                     CONFIG_SCHED_WORKSTACKSIZE,
                                     (main_t)work_hpthread, (FAR char * const *)NULL);
  DEBUGASSERT(g_work[HPWORK].pid > 0);

  /* Start a lower priority worker thread for other, non-critical continuation
   * tasks
   */

#ifdef CONFIG_SCHED_LPWORK

  svdbg("Starting low-priority kernel worker thread\n");

  g_work[LPWORK].pid = KERNEL_THREAD(LPWORKNAME, CONFIG_SCHED_LPWORKPRIORITY,
                                     CONFIG_SCHED_LPWORKSTACKSIZE,
                                     (main_t)work_lpthread, (FAR char * const *)NULL);
  DEBUGASSERT(g_work[LPWORK].pid > 0);

#endif /* CONFIG_SCHED_LPWORK */
#endif /* CONFIG_SCHED_HPWORK */

#if defined(CONFIG_NUTTX_KERNEL) && defined(CONFIG_SCHED_USRWORK)
  /* Start the user-space work queue */

  DEBUGASSERT(USERSPACE->work_usrstart != NULL);
  taskid = USERSPACE->work_usrstart();
  DEBUGASSERT(taskid > 0);
#endif

#endif /* CONFIG_SCHED_WORKQUEUE */

  /* Once the operating system has been initialized, the system must be
   * started by spawning the user init thread of execution.  This is the
   * first user-mode thead.
   */

  svdbg("Starting init thread\n");

  /* Perform any last-minute, board-specific initialization, if so
   * configured.
   */

#ifdef CONFIG_BOARD_INITIALIZE
  board_initialize();
#endif

  /* Start the default application.  In a flat build, this is entrypoint
   * is given by the definitions, CONFIG_USER_ENTRYPOINT.  In the kernel
   * build, however, we must get the address of the entrypoint from the
   * header at the beginning of the user-space blob.
   */

#ifdef CONFIG_NUTTX_KERNEL
  DEBUGASSERT(USERSPACE->us_entrypoint != NULL);
  taskid = TASK_CREATE("init", SCHED_PRIORITY_DEFAULT,
                       CONFIG_USERMAIN_STACKSIZE, USERSPACE->us_entrypoint,
                       (FAR char * const *)NULL);
#else
  taskid = TASK_CREATE("init", SCHED_PRIORITY_DEFAULT,
                       CONFIG_USERMAIN_STACKSIZE,
                       (main_t)CONFIG_USER_ENTRYPOINT,
                       (FAR char * const *)NULL);
#endif
  ASSERT(taskid > 0);

  /* We an save a few bytes by discarding the IDLE thread's environment. */

#if !defined(CONFIG_DISABLE_ENVIRON) && defined(CONFIG_PATH_INITIAL)
  (void)clearenv();
#endif

  return OK;
}
Example #5
0
int os_bringup(void)
{
  int init_taskid;

  /* Setup up the initial environment for the idle task.  At present, this
   * may consist of only the initial PATH variable.  The PATH variable is
   * (probably) not used by the IDLE task.  However, the environment
   * containing the PATH variable will be inherited by all of the threads
   * created by the IDLE task.
   */

#if !defined(CONFIG_DISABLE_ENVIRON) && defined(CONFIG_PATH_INITIAL)
  (void)setenv("PATH", CONFIG_PATH_INITIAL, 1);
#endif

  /* Start the page fill worker kernel thread that will resolve page faults.
   * This should always be the first thread started because it may have to
   * resolve page faults in other threads
   */

#ifdef CONFIG_PAGING
  svdbg("Starting paging thread\n");

  g_pgworker = KERNEL_THREAD("pgfill", CONFIG_PAGING_DEFPRIO,
                             CONFIG_PAGING_STACKSIZE,
                             (main_t)pg_worker, (const char **)NULL);
  ASSERT(g_pgworker != ERROR);
#endif

  /* Start the worker thread that will serve as the device driver "bottom-
   * half" and will perform misc garbage clean-up.
   */

#ifdef CONFIG_SCHED_WORKQUEUE
  svdbg("Starting worker thread\n");

  g_work[HPWORK].pid = KERNEL_THREAD("work0", CONFIG_SCHED_WORKPRIORITY,
                                     CONFIG_SCHED_WORKSTACKSIZE,
                                     (main_t)work_hpthread, (const char **)NULL);
  ASSERT(g_work[HPWORK].pid != ERROR);

  /* Start a lower priority worker thread for other, non-critical continuation
   * tasks
   */

#ifdef CONFIG_SCHED_LPWORK
  svdbg("Starting worker thread\n");

  g_work[LPWORK].pid = KERNEL_THREAD("work1", CONFIG_SCHED_LPWORKPRIORITY,
                                     CONFIG_SCHED_LPWORKSTACKSIZE,
                                     (main_t)work_lpthread, (const char **)NULL);
  ASSERT(g_work[LPWORK].pid != ERROR);
#endif
#endif

  /* Once the operating system has been initialized, the system must be
   * started by spawning the user init thread of execution.  This is the
   * first user-mode thead.
   */

  svdbg("Starting init thread\n");

  /* Start the default application at CONFIG_USER_ENTRYPOINT() */

  init_taskid = TASK_CREATE("init", SCHED_PRIORITY_DEFAULT,
                            CONFIG_USERMAIN_STACKSIZE,
                            (main_t)CONFIG_USER_ENTRYPOINT, (const char **)NULL);
  ASSERT(init_taskid != ERROR);

  /* We an save a few bytes by discarding the IDLE thread's environment. */

#if !defined(CONFIG_DISABLE_ENVIRON) && defined(CONFIG_PATH_INITIAL)
  (void)clearenv();
#endif

  return OK;
}
Example #6
0
int posix_spawn(FAR pid_t *pid, FAR const char *path,
                FAR const posix_spawn_file_actions_t *file_actions,
                FAR const posix_spawnattr_t *attr,
                FAR char *const argv[], FAR char *const envp[])
#endif
{
  struct sched_param param;
  pid_t proxy;
#ifdef CONFIG_SCHED_WAITPID
  int status;
#endif
  int ret;

  DEBUGASSERT(path);

  svdbg("pid=%p path=%s file_actions=%p attr=%p argv=%p\n",
        pid, path, file_actions, attr, argv);

  /* If there are no file actions to be performed and there is no change to
   * the signal mask, then start the new child task directly from the parent task.
   */

#ifndef CONFIG_DISABLE_SIGNALS
  if ((file_actions == NULL || *file_actions == NULL) &&
      (attr == NULL || (attr->flags & POSIX_SPAWN_SETSIGMASK) == 0))
#else
  if (file_actions ==  NULL || *file_actions == NULL)
#endif
    {
      return spawn_exec(pid, path, attr, argv);
    }

  /* Otherwise, we will have to go through an intermediary/proxy task in order
   * to perform the I/O redirection.  This would be a natural place to fork().
   * However, true fork() behavior requires an MMU and most implementations
   * of vfork() are not capable of these operations.
   *
   * Even without fork(), we can still do the job, but parameter passing is
   * messier.  Unfortunately, there is no (clean) way to pass binary values
   * as a task parameter, so we will use a semaphore-protected global
   * structure.
   */

  /* Get exclusive access to the global parameter structure */

  spawn_semtake(&g_ps_parmsem);

  /* Populate the parameter structure */

  g_ps_parms.result       = ENOSYS;
  g_ps_parms.pid          = pid;
  g_ps_parms.path         = path;
  g_ps_parms.file_actions = file_actions;
  g_ps_parms.attr         = attr;
  g_ps_parms.argv         = argv;

  /* Get the priority of this (parent) task */

  ret = sched_getparam(0, &param);
  if (ret < 0)
    {
      int errcode = errno;

      sdbg("ERROR: sched_getparam failed: %d\n", errcode);
      spawn_semgive(&g_ps_parmsem);
      return errcode;
    }

  /* Disable pre-emption so that the proxy does not run until we waitpid
   * is called.  This is probably unnecessary since the spawn_proxy has
   * the same priority as this thread; it should be schedule behind this
   * task in the ready-to-run list.
   */

#ifdef CONFIG_SCHED_WAITPID
  sched_lock();
#endif

  /* Start the intermediary/proxy task at the same priority as the parent
   * task.
   */

  proxy = TASK_CREATE("spawn_proxy", param.sched_priority,
                      CONFIG_POSIX_SPAWN_STACKSIZE, (main_t)spawn_proxy,
                      (FAR const char **)NULL);
  if (proxy < 0)
    {
      ret = get_errno();
      sdbg("ERROR: Failed to start spawn_proxy: %d\n", ret);

      goto errout_with_lock;
    }

   /* Wait for the proxy to complete its job */

#ifdef CONFIG_SCHED_WAITPID
   ret = waitpid(proxy, &status, 0);
   if (ret < 0)
     {
       sdbg("ERROR: waitpid() failed: %d\n", errno);
       goto errout_with_lock;
     }
#else
   spawn_semtake(&g_ps_execsem);
#endif

   /* Get the result and relinquish our access to the parameter structure */

   ret = g_ps_parms.result;

errout_with_lock:
#ifdef CONFIG_SCHED_WAITPID
  sched_unlock();
#endif
  spawn_semgive(&g_ps_parmsem);
  return ret;
}
static int telnetd_daemon(int argc, char *argv[])
{
  FAR struct telnetd_s *daemon;
  struct sockaddr_in myaddr;
#ifdef CONFIG_NET_SOLINGER
  struct linger ling;
#endif
  socklen_t addrlen;
  FAR char *devpath;
  pid_t pid;
  int listensd;
  int acceptsd;
  int drvrfd;
#ifdef CONFIG_NET_HAVE_REUSEADDR
  int optval;
#endif

  /* Get daemon startup info */

  daemon = g_telnetdcommon.daemon;
  g_telnetdcommon.daemon = NULL;
  sem_post(&g_telnetdcommon.startsem);
  DEBUGASSERT(daemon != NULL);

  /* Create a new TCP socket to use to listen for connections */

  listensd = socket(PF_INET, SOCK_STREAM, 0);
  if (listensd < 0)
    {
      int errval = errno;
      ndbg("socket failure: %d\n", errval);
      return -errval;
    }

  /* Set socket to reuse address */

#ifdef CONFIG_NET_HAVE_REUSEADDR
  optval = 1;
  if (setsockopt(listensd, SOL_SOCKET, SO_REUSEADDR, (void*)&optval, sizeof(int)) < 0)
    {
      ndbg("setsockopt SO_REUSEADDR failure: %d\n", errno);
      goto errout_with_socket;
    }
#endif

  /* Bind the socket to a local address */

  myaddr.sin_family      = AF_INET;
  myaddr.sin_port        = daemon->port;
  myaddr.sin_addr.s_addr = INADDR_ANY;

  if (bind(listensd, (struct sockaddr*)&myaddr, sizeof(struct sockaddr_in)) < 0)
    {
      ndbg("bind failure: %d\n", errno);
      goto errout_with_socket;
    }

  /* Listen for connections on the bound TCP socket */

  if (listen(listensd, 5) < 0)
    {
      ndbg("listen failure %d\n", errno);
      goto errout_with_socket;
    }

  /* Now go silent.  Only the lldbg family of debug functions should
   * be used after this point because these do not depend on stdout
   * being available.
   */

#ifndef CONFIG_DEBUG
  close(0);
  close(1);
  close(2);
#endif

  /* Begin accepting connections */

  for (;;)
    {
      nllvdbg("Accepting connections on port %d\n", ntohs(daemon->port));

      addrlen = sizeof(struct sockaddr_in);
      acceptsd = accept(listensd, (struct sockaddr*)&myaddr, &addrlen);
      if (acceptsd < 0)
        {
          nlldbg("accept failed: %d\n", errno);
          goto errout_with_socket;
        }

      /* Configure to "linger" until all data is sent when the socket is closed */

#ifdef CONFIG_NET_SOLINGER
      ling.l_onoff  = 1;
      ling.l_linger = 30;     /* timeout is seconds */
      if (setsockopt(acceptsd, SOL_SOCKET, SO_LINGER, &ling, sizeof(struct linger)) < 0)
        {
          nlldbg("setsockopt failed: %d\n", errno);
          goto errout_with_acceptsd;
        }
#endif

      /* Create a character device to "wrap" the accepted socket descriptor */

      nllvdbg("Creating the telnet driver\n");
      devpath = telnetd_driver(acceptsd, daemon);
      if (devpath < 0)
        {
          nlldbg("telnetd_driver failed\n");
          goto errout_with_acceptsd;
        }

      /* Open the driver */

      nllvdbg("Opening the telnet driver\n");
      drvrfd = open(devpath, O_RDWR);
      if (drvrfd < 0)
        {
          nlldbg("Failed to open %s: %d\n", devpath, errno);
          goto errout_with_acceptsd;
        }

      /* We can now free the driver string */

      free(devpath);

      /* Use this driver as stdin, stdout, and stderror */

      (void)dup2(drvrfd, 0);
      (void)dup2(drvrfd, 1);
      (void)dup2(drvrfd, 2);

      /* And we can close our original driver fd */

      if (drvrfd > 2)
        {
          close(drvrfd);
        }

      /* Create a task to handle the connection.  The created task
       * will inherit the new stdin, stdout, and stderr.
       */

      nllvdbg("Starting the telnet session\n");
      pid = TASK_CREATE("Telnet session", daemon->priority, daemon->stacksize,
                         daemon->entry, NULL);
      if (pid < 0)
        {
          nlldbg("Failed start the telnet session: %d\n", errno);
          goto errout_with_acceptsd;
        }

      /* Forget about the connection. */

      close(0);
      close(1);
      close(2);
    }

errout_with_acceptsd:
  close(acceptsd);

errout_with_socket:
  close(listensd);
  free(daemon);
  return 1;
}
int telnetd_start(FAR struct telnetd_config_s *config)
{
  FAR struct telnetd_s *daemon;
  pid_t pid;
  int ret;

  /* Allocate a state structure for the new daemon */

  daemon = (FAR struct telnetd_s *)malloc(sizeof(struct telnetd_s));
  if (!daemon)
    {
      return -ENOMEM;
    }

  /* Initialize the daemon structure */

  daemon->port      = config->d_port;
  daemon->priority  = config->t_priority;
  daemon->stacksize = config->t_stacksize;
  daemon->entry     = config->t_entry;

  /* Initialize the common structure if this is the first daemon */

  if (g_telnetdcommon.ndaemons < 1)
    {
      sem_init(&g_telnetdcommon.startsem, 0, 0);
      sem_init(&g_telnetdcommon.exclsem, 0, 1);
      g_telnetdcommon.minor = 0;
    }

  /* Then start the new daemon */

  g_telnetdcommon.daemon = daemon;
  pid = TASK_CREATE("Telnet daemon", config->d_priority, config->d_stacksize,
                    telnetd_daemon, NULL);
  if (pid < 0)
    {
      int errval = errno;
      free(daemon);
      ndbg("Failed to start the telnet daemon: %d\n", errval);
      return -errval;
    }

  /* Then wait for the daemon to start and complete the handshake */

  do
    {
      ret = sem_wait(&g_telnetdcommon.startsem);

      /* The only expected error condition is for sem_wait to be awakened by
       * a receipt of a signal.
       */

      if (ret < 0)
        {
          DEBUGASSERT(errno == -EINTR);
        }
    }
  while (ret < 0);

  /* Return success */

  return pid;
}
int nxcon_main(int argc, char **argv)
{
  nxgl_mxpixel_t color;
  int fd;
  int ret;

  /* General Initialization *************************************************/
  /* Reset all global data */

  message("nxcon_main: Started\n");
  memset(&g_nxcon_vars, 0, sizeof(struct nxcon_state_s));

  /* Call all C++ static constructors */

#if defined(CONFIG_HAVE_CXX) && defined(CONFIG_HAVE_CXXINITIALIZE)
  up_cxxinitialize();
#endif

  /* NSH Initialization *****************************************************/
  /* Initialize the NSH library */

  message("nxcon_main: Initialize NSH\n");
  nsh_initialize();

  /* If the Telnet console is selected as a front-end, then start the
   * Telnet daemon.
   */

#ifdef CONFIG_NSH_TELNET
  ret = nsh_telnetstart();
  if (ret < 0)
    {
     /* The daemon is NOT running.  Report the the error then fail...
      * either with the serial console up or just exiting.
      */

     fprintf(stderr, "ERROR: Failed to start TELNET daemon: %d\n", ret);
   }
#endif
  /* NX Initialization ******************************************************/
  /* Initialize NX */

  message("nxcon_main: Initialize NX\n");
  ret = nxcon_initialize();
  message("nxcon_main: NX handle=%p\n", g_nxcon_vars.hnx);
  if (!g_nxcon_vars.hnx || ret < 0)
    {
      message("nxcon_main: Failed to get NX handle: %d\n", errno);
      goto errout;
    }

  /* Set the background to the configured background color */

  message("nxcon_main: Set background color=%d\n", CONFIG_EXAMPLES_NXCON_BGCOLOR);
  color = CONFIG_EXAMPLES_NXCON_BGCOLOR;
  ret = nx_setbgcolor(g_nxcon_vars.hnx, &color);
  if (ret < 0)
    {
      message("nxcon_main: nx_setbgcolor failed: %d\n", errno);
      goto errout_with_nx;
    }

  /* Window Configuration ***************************************************/
  /* Create a window */

  message("nxcon_main: Create window\n");
  g_nxcon_vars.hwnd = nxtk_openwindow(g_nxcon_vars.hnx, &g_nxconcb, NULL);
  if (!g_nxcon_vars.hwnd)
    {
      message("nxcon_main: nxtk_openwindow failed: %d\n", errno);
      goto errout_with_nx;
    }
  message("nxcon_main: hwnd=%p\n", g_nxcon_vars.hwnd);

  /* Wait until we have the screen resolution.  We'll have this immediately
   * unless we are dealing with the NX server.
   */

  while (!g_nxcon_vars.haveres)
    {
      (void)sem_wait(&g_nxcon_vars.eventsem);
    }
  message("nxcon_main: Screen resolution (%d,%d)\n", g_nxcon_vars.xres, g_nxcon_vars.yres);

  /* Determine the size and position of the window */

  g_nxcon_vars.wndo.wsize.w = g_nxcon_vars.xres / 2 + g_nxcon_vars.xres / 4;
  g_nxcon_vars.wndo.wsize.h = g_nxcon_vars.yres / 2 + g_nxcon_vars.yres / 4;

  g_nxcon_vars.wpos.x       = g_nxcon_vars.xres / 8;
  g_nxcon_vars.wpos.y       = g_nxcon_vars.yres / 8;

  /* Set the window position */

  message("nxcon_main: Set window position to (%d,%d)\n",
          g_nxcon_vars.wpos.x, g_nxcon_vars.wpos.y);

  ret = nxtk_setposition(g_nxcon_vars.hwnd, &g_nxcon_vars.wpos);
  if (ret < 0)
    {
      message("nxcon_main: nxtk_setposition failed: %d\n", errno);
      goto errout_with_hwnd;
    }

  /* Set the window size */

  message("nxcon_main: Set window size to (%d,%d)\n",
          g_nxcon_vars.wndo.wsize.w, g_nxcon_vars.wndo.wsize.h);

  ret = nxtk_setsize(g_nxcon_vars.hwnd, &g_nxcon_vars.wndo.wsize);
  if (ret < 0)
    {
      message("nxcon_main: nxtk_setsize failed: %d\n", errno);
      goto errout_with_hwnd;
    }

  /* Open the toolbar */

  message("nxcon_main: Add toolbar to window\n");
  ret = nxtk_opentoolbar(g_nxcon_vars.hwnd, CONFIG_EXAMPLES_NXCON_TOOLBAR_HEIGHT, &g_nxtoolcb, NULL);
  if (ret < 0)
    {
      message("nxcon_main: nxtk_opentoolbar failed: %d\n", errno);
      goto errout_with_hwnd;
    }

  /* Sleep a little bit to allow the server to catch up */
 
  sleep(2);

  /* NxConsole Configuration ************************************************/
  /* Use the window to create an NX console */

  g_nxcon_vars.wndo.wcolor[0] = CONFIG_EXAMPLES_NXCON_WCOLOR;
  g_nxcon_vars.wndo.fcolor[0] = CONFIG_EXAMPLES_NXCON_FONTCOLOR;
  g_nxcon_vars.wndo.fontid    = CONFIG_EXAMPLES_NXCON_FONTID;

  g_nxcon_vars.hdrvr = nxtk_register(g_nxcon_vars.hwnd, &g_nxcon_vars.wndo, CONFIG_EXAMPLES_NXCON_MINOR);
  if (!g_nxcon_vars.hdrvr)
    {
      message("nxcon_main: nxtk_register failed: %d\n", errno);
      goto errout_with_hwnd;
    }

  /* Open the NxConsole driver */

  fd = open(CONFIG_EXAMPLES_NXCON_DEVNAME, O_WRONLY);
  if (fd < 0)
    {
      message("nxcon_main: open %s read-only failed: %d\n",
              CONFIG_EXAMPLES_NXCON_DEVNAME, errno);
      goto errout_with_driver;
    }

  /* Start Console Task *****************************************************/
  /* Now re-direct stdout and stderr so that they use the NX console driver.
   * Note that stdin is retained (file descriptor 0, probably the the serial console).
    */

   message("nxcon_main: Starting the console task\n");
   msgflush();

  (void)fflush(stdout);
  (void)fflush(stderr);

  (void)fclose(stdout);
  (void)fclose(stderr);

  (void)dup2(fd, 1);
  (void)dup2(fd, 2);

   /* And we can close our original driver file descriptor */

   close(fd);

   /* And start the console task.  It will inherit stdin, stdout, and stderr
    * from this task.
    */
 
   g_nxcon_vars.pid = TASK_CREATE("NxConsole", CONFIG_EXAMPLES_NXCONSOLE_PRIO,
                                  CONFIG_EXAMPLES_NXCONSOLE_STACKSIZE,
                                  nxcon_task, NULL);
   ASSERT(g_nxcon_vars.pid > 0);
   return EXIT_SUCCESS;

  /* Error Exits ************************************************************/

errout_with_driver:
  (void)nxcon_unregister(g_nxcon_vars.hdrvr);

errout_with_hwnd:
  (void)nxtk_closewindow(g_nxcon_vars.hwnd);

errout_with_nx:
  /* Disconnect from the server */

  nx_disconnect(g_nxcon_vars.hnx);
errout:
  return EXIT_FAILURE;
}