Logo Search packages:      
Sourcecode: baycomusb version File versions  Download package

mainwin32.c

/*****************************************************************************/

/*
 *      mainwin32.c  --  Transceiver control Win32 stuff.
 *
 *      Copyright (C) 2000-2001
 *          Thomas Sailer (t.sailer@alumni.ethz.ch)
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Please note that the GPL allows you to use the driver, NOT the radio.
 *  In order to use the radio, you need a license from the communications
 *  authority of your country.
 *
 *  History:
 *   0.1  19.09.2000  Created
 *
 *
 *  WARNING:
 *    malloc and free from MSVCRT cause almost immediate crashes.
 *    On the other hand, printf from CRTDLL does not support 64bit
 *    ints while the one from MSVCRT does...
 */

/*****************************************************************************/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#define _REENTRANT

#include "trx.h"
#include "simd.h"

#include <windows.h>
#include <winsock.h>
#include <wincon.h>
#include <process.h>
#include <errno.h>
#include <getopt.h>
#include <malloc.h>
#include <ctype.h>

#if defined(ORBITIPC)
#include <glib.h>
#endif

#include "list.h"

/* --------------------------------------------------------------------- */

static HANDLE devlist_mutex;
static HANDLE hglobalshmem;
static struct win32_global_state *globalstate;
static LIST_HEAD(devices_list);
static LIST_HEAD(orb_fds);
static int quit = 0;
static unsigned int fastpoll = 0;

#define POLLINTERVAL    10000  /* check all 10s for new modems */
#define FASTPOLLINTERVAL 1000  /* check all 1s for new modems when anticipated */

#define PAGE_ALIGN(x)     (((x)+((1<<12)-1))&~((1<<12)-1))

/* --------------------------------------------------------------------- */

void acquire_trxdata_mutex(struct trx_thread_state *state)
{
      WaitForSingleObject(state->hmutex, INFINITE);
}

void release_trxdata_mutex(struct trx_thread_state *state)
{
      ReleaseMutex(state->hmutex);
}

int check_quit(void)
{
      return quit;
}

static inline void acquire_devlist_mutex(void)
{
      WaitForSingleObject(devlist_mutex, INFINITE);
}

static inline void release_devlist_mutex(void)
{
      ReleaseMutex(devlist_mutex);
}

/* --------------------------------------------------------------------- */

int reopen_usbdev(struct trx_thread_state *state)
{
      DWORD r;
      HANDLE h[2];

      if (state->usbdev)
            usb_close(state->usbdev);
      state->usbdev = NULL;
      Sleep(500);  /* make sure device disconnected */
      acquire_devlist_mutex();
      if (WaitForSingleObject(state->hevent, 0) == WAIT_OBJECT_0)
            goto outok;
      state->devidx = -1;
      fastpoll = 10;
      release_devlist_mutex();
      /* now wait for device to connect */
      h[0] = devlist_mutex;
      h[1] = state->hevent;
      r = WaitForMultipleObjects(2, h, TRUE, 60000);
      if (r < WAIT_OBJECT_0 || r > (WAIT_OBJECT_0+1)) {
            lprintf(1, "Timeout reopening USB device %s (error %lu)\n", state->serial, r);
            return -1;
      }
  outok:
      release_devlist_mutex();
      if (!(state->usbdev = usb_open(BAYCOMUSB_VENDORID, -1, 0, state->devidx))) {
            lprintf(1, "Cannot open USB device %d (serial %s)\n", state->devidx, state->serial);
            return -1;
      }
      lprintf(10, "=== THREADCONTINUE: %d, %s\n", state->devidx, state->serial);
      return 0;
}

/* --------------------------------------------------------------------- */

void init_shmem_object(struct trx_thread_state *state)
{
      unsigned int j;

      destroy_shmem_object(state);
      for (j = 0; j < MAXUSBMODEMS; j++) {
            if (globalstate->modem[j].hshmem != NULL)
                  continue;
            globalstate->modem[j].hshmem = state->hshmem;
            state->globalidx = j;
            break;
      }
}

void destroy_shmem_object(struct trx_thread_state *state)
{
      if (state->globalidx != -1) {
            globalstate->modem[state->globalidx].hshmem = NULL;
            state->globalidx = -1;
      }
}

/* --------------------------------------------------------------------- */

static void thread_start(void *arg)
{
      struct trx_thread_state *state = arg;
      struct trx_thread_state *state2;
      struct list_head *list;
      int i;

      lprintf(10, ">>> THREADSTART: %d\n", state->devidx);
      /* open communications to device */
      state->netif_opened = 0;
      state->hmutex = CreateMutex(NULL, FALSE, NULL);
      if (!state->hmutex)
            goto ret;
      state->hevent = CreateEvent(NULL, FALSE, FALSE, NULL);
      if (!state->hevent)
            goto ret;
      state->hflxtxevent = CreateEvent(NULL, FALSE, FALSE, NULL);
      if (!state->hflxtxevent)
            goto ret;
      state->hflxrxevent = CreateEvent(NULL, FALSE, FALSE, NULL);
      if (!state->hflxrxevent)
            goto ret;
      /* get serial number from device */
      i = adapter_init_getserial(state);
      if (i < 0) {
            if (i == -2)
                  lprintf(1, "Error loading USB device %d\n", state->devidx);
            fastpoll = 10;
            goto ret;
      }
      lprintf(2, "USB device %d serial %s\n", state->devidx, state->serial);
      acquire_devlist_mutex();
      for (list = devices_list.next; list != &devices_list; list = list->next) {
            state2 = list_entry(list, struct trx_thread_state, device_list);
            if (state2 != state && !strcmp(state2->serial, state->serial)) {
                  state2->devidx = state->devidx;
                  state2->mode = state->mode;
                  list_del(&state->device_list);
                  INIT_LIST_HEAD(&state->device_list);
                  lprintf(2, "Thread for USB device %d serial %s already running\n", state->devidx, state->serial);
                  if (state->usbdev)
                        usb_close(state->usbdev);
                  state->usbdev = NULL;
                  SetEvent(state2->hevent);
                  release_devlist_mutex();
                  goto ret;
            }
      }
      release_devlist_mutex();
      state->flags = FLG_RELOADMODEM | FLG_MODEMERROR | FLG_T7FERROR;
      /* finally start thread */
      trx_thread(state);
      if (state->usbdev)
            adapter_reset(state->usbdev);

  ret:
      state->mode = MODE_DEAD;
      if (state->hflxrxevent) {
            CloseHandle(state->hflxrxevent);
            state->hflxrxevent = NULL;
      }
      if (state->hflxtxevent) {
            CloseHandle(state->hflxtxevent);
            state->hflxtxevent = NULL;
      }
      if (state->hevent) {
            CloseHandle(state->hevent);
            state->hevent = NULL;
      }
      if (state->hmutex) {
            CloseHandle(state->hmutex);
            state->hmutex = NULL;
      }
      if (state->hshmem) {
            CloseHandle(state->hshmem);
            state->hshmem = NULL;
      }
      if (state->usbdev)
            usb_close(state->usbdev);
      acquire_devlist_mutex();
      destroy_shmem_object(state);
      list_del(&state->device_list);
      fastpoll = 10;
      release_devlist_mutex();
      lprintf(10, "<<< THREADSTOP: %s\n", state->serial);
      UnmapViewOfFile(state);
      return;
}

/* --------------------------------------------------------------------- */

static void check_new_uninited_modems(void)
{
      struct list_head *list;
      struct trx_thread_state *state;
      unsigned int devmask = 0;
      unsigned int i;
      struct usbdevice *usbdev;
      HANDLE hshmem;

      for (list = devices_list.next; list != &devices_list; list = list->next) {
            state = list_entry(list, struct trx_thread_state, device_list);
            if (state->devidx == -1)
                  continue;
            devmask |= (1 << state->devidx);
      }
      for (i = 0; i < MAXUSBMODEMS; i++) {
            if (devmask & (1 << i))
                  continue;
            if (!(usbdev = usb_open(BAYCOMUSB_VENDORID, -1, 0, i)))
                  continue;
            hshmem = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
                                 PAGE_ALIGN(sizeof(struct trx_thread_state)), NULL);
            if (!hshmem) {
                  usb_close(usbdev);
                  lprintf(0, "Cannot create file mapping (error %ld)\n", GetLastError());
                  continue;
            }
            state = MapViewOfFile(hshmem, FILE_MAP_WRITE, 0, 0, 0);
            if (!state) {
                  usb_close(usbdev);
                  CloseHandle(hshmem);
                  lprintf(0, "Cannot map file mapping (error %ld)\n", GetLastError());
                  continue;
            }
            memset(state, 0, sizeof(struct trx_thread_state));
            state->hshmem = hshmem;
            state->devidx = i;
            state->usbdev = usbdev;
            state->globalidx = -1;
            _beginthread(thread_start, 0, state);
            list_add(&state->device_list, &devices_list);
      }
}

/* --------------------------------------------------------------------- */
#if defined(ORBITIPC)

struct orbfdlist {
      struct list_head list;
      GIOPConnection *conn;
};

/* --------------------------------------------------------------------- */

#ifdef USECRITICALSECT
static CRITICAL_SECTION orbit_mutex;
#else
static HANDLE orbit_mutex;
#endif

void acquire_orbit_mutex(void)
{
#ifdef USECRITICALSECT
      EnterCriticalSection(&orbit_mutex);
#else
      WaitForSingleObject(orbit_mutex, INFINITE);
#endif
}

void release_orbit_mutex(void)
{
#ifdef USECRITICALSECT
      LeaveCriticalSection(&orbit_mutex);
#else
      ReleaseMutex(orbit_mutex);
#endif
}

/* --------------------------------------------------------------------- */

static void orb_add_connection(GIOPConnection *cnx)
{
      struct orbfdlist *ofd;

      if (!(cnx->user_data = ofd = malloc(sizeof(struct orbfdlist))))
            return;
      ofd->conn = cnx;
      list_add(&ofd->list, &orb_fds);
}

static void orb_remove_connection(GIOPConnection *cnx)
{
        struct orbfdlist *ofd = cnx->user_data;

        if (!ofd)
                return;
        ofd->conn = NULL;
}

static void mainloop(void)
{
      struct list_head *list;
      struct orbfdlist *ofd;
      fd_set rmask, emask;
      int i, fd, maxfd;
      struct timeval tv;
      DWORD nextpolltime;
      long tdiff;

      nextpolltime = GetTickCount();
      while (!quit) {
            FD_ZERO(&rmask);
            FD_ZERO(&emask);
            maxfd = 0;
            for (list = orb_fds.next; list != &orb_fds;) {
                  ofd = list_entry(list, struct orbfdlist, list);
                        list = list->next;
                        if (!ofd->conn) {
                                list_del(&ofd->list);
                                free(ofd);
                                continue;
                        }
                  fd = GIOP_CONNECTION_GET_FD(ofd->conn);
                  if (fd >= maxfd)
                        maxfd = fd + 1;
                  FD_SET(fd, &rmask);
                  FD_SET(fd, &emask);
            }
            tdiff = nextpolltime - GetTickCount();
            if (tdiff < 0)
                  tdiff = 0;
            tv.tv_sec = tdiff / 1000;
            tv.tv_usec = (tdiff - tv.tv_sec * 1000) * 1000;
            i = select(maxfd, &rmask, NULL, &emask, &tv);
            if (i == -1 || errno == EINTR) {
                  lprintf(0, "poll: %s (%u)\n", strerror(errno), errno);
                  exit(1);
            }
            for (list = orb_fds.next; list != &orb_fds; list = list->next) {
                  ofd = list_entry(list, struct orbfdlist, list);
                  fd = GIOP_CONNECTION_GET_FD(ofd->conn);
                        if (FD_ISSET(fd, &emask) && ofd->conn)
                        giop_main_handle_connection_exception(ofd->conn);
                  if (FD_ISSET(fd, &rmask) && ofd->conn)
                        giop_main_handle_connection(ofd->conn);
            }
            tdiff = GetTickCount() - nextpolltime;
            if (tdiff >= 0) {
                  acquire_devlist_mutex();
                  check_new_uninited_modems();
                  if (fastpoll > 0) {
                        nextpolltime = GetTickCount() + FASTPOLLINTERVAL;
                        fastpoll--;
                  } else {
                        nextpolltime = GetTickCount() + POLLINTERVAL;
                  }
                  release_devlist_mutex();
            }
      }
}

/* --------------------------------------------------------------------- */
#else

static void mainloop(void)
{
      DWORD nextpolltime;
      long tdiff;

      nextpolltime = GetTickCount();
      while (!quit) {
            tdiff = nextpolltime - GetTickCount();
            if (tdiff < 0)
                  tdiff = 0;
            Sleep(tdiff);
            tdiff = GetTickCount() - nextpolltime;
            if (tdiff >= 0) {
                  acquire_devlist_mutex();
                  check_new_uninited_modems();
                  if (fastpoll > 0) {
                        nextpolltime = GetTickCount() + FASTPOLLINTERVAL;
                        fastpoll--;
                  } else {
                        nextpolltime = GetTickCount() + POLLINTERVAL;
                  }
                  release_devlist_mutex();
            }
      }
}

#endif
/* --------------------------------------------------------------------- */

void netif_close(struct trx_thread_state *state)
{
      unsigned int i;

      if (state->netif_opened) {
            /* kill pending URBs */
            acquire_trxdata_mutex(state);
            if (state->iurb.urbstate == URBSTATE_INPROGRESS) {
                  if (usb_discardurb(state->usbdev, &state->iurb.urb))
                        lprintf(1, "error %s (%d) killing interrupt urb\n", strerror(errno), errno);
            }
            if (state->curb.urbstate == URBSTATE_INPROGRESS) {
                  if (usb_discardurb(state->usbdev, &state->curb.urb))
                        lprintf(1, "error %s (%d) killing control urb\n", strerror(errno), errno);
            }
            if (state->mode == MODE_FSK || state->mode == MODE_EXTERNAL || state->mode == MODE_AFSK) {
                  for (i = 0; i < NUMRXPACKETS; i++) {
                        if (state->du.p.rxurb[i].urbstate != URBSTATE_INPROGRESS)
                              continue;
                        if (usb_discardurb(state->usbdev, &state->du.p.rxurb[i].urb))
                              lprintf(1, "error %s (%d) killing rx packet urb %u\n", strerror(errno), errno, i);
                  }
                  for (i = 0; i < NUMTXPACKETS; i++) {
                        if (state->du.p.txurb[i].urbstate != URBSTATE_INPROGRESS)
                              continue;
                        if (usb_discardurb(state->usbdev, &state->du.p.txurb[i].urb))
                              lprintf(1, "error %s (%d) killing tx packet urb %u\n", strerror(errno), errno, i);
                  }
            } else if (state->mode == MODE_AUDIO) {
                  for (i = 0; i < NUMAUDIOURB; i++) {
                        if (state->du.a.inurb[i].urbstate != URBSTATE_INPROGRESS)
                              continue;
                        if (usb_discardurb(state->usbdev, &state->du.a.inurb[i].urb))
                              lprintf(1, "error %s (%d) killing audio input urb %u\n", strerror(errno), errno, i);
                  }
                  for (i = 0; i < NUMAUDIOURB; i++) {
                        if (state->du.a.outurb[i].urbstate != URBSTATE_INPROGRESS)
                              continue;
                        if (usb_discardurb(state->usbdev, &state->du.a.outurb[i].urb))
                              lprintf(1, "error %s (%d) killing audio output urb %u\n", strerror(errno), errno, i);
                  }
                  audio_close(state);
#if 0
                  if (usb_releaseinterface(state->usbdev, 3))
                        lprintf(2, "netif_close: cannot release interface 3\n");
                  if (usb_releaseinterface(state->usbdev, 2))
                        lprintf(2, "netif_close: cannot release interface 2\n");
                  if (usb_releaseinterface(state->usbdev, 1))
                        lprintf(2, "netif_close: cannot release interface 1\n");
#endif
            }
            release_trxdata_mutex(state);
            /* close network interface stuff */
            if (usb_releaseinterface(state->usbdev, 0))
                  lprintf(2, "netif_close: cannot release interface 0\n");
      }
      lprintf(30, "netif_close\n");
      state->netif_opened = 0;
}

int netif_open(struct trx_thread_state *state)
{
      unsigned char br[6];
      unsigned int u, k;
      int r;

      netif_close(state);
      /* initialize URBs */
      state->iurb.urbstate = 0;
      state->iurb.nexttime = gettimems();
      state->iurb.urb.type = USBDEVFS_URB_TYPE_BULK;
      state->iurb.urb.endpoint = 0x81;
      state->iurb.urb.flags = 0;
        state->iurb.urb.buffer = state->iurb.buf;
      state->iurb.urb.buffer_length = sizeof(state->iurb.buf);
      state->iurb.urb.signr = 0;
        state->iurb.urb.usercontext = (void *)0x20000;
      state->curb.urbstate = 0;
      state->curb.urb.type = USBDEVFS_URB_TYPE_CONTROL;
      state->curb.urb.endpoint = 0;
      state->curb.urb.flags = 0;
        state->curb.urb.buffer = &state->curb.buf;
      state->curb.urb.buffer_length = 8;
      state->curb.urb.signr = 0;
        state->curb.urb.usercontext = (void *)0x30000;
      if (state->mode == MODE_FSK || state->mode == MODE_EXTERNAL || state->mode == MODE_AFSK) {
            state->du.p.rxurbptr = 0;
            for (u = 0; u < NUMRXPACKETS; u++) {
                  state->du.p.rxurb[u].urbstate = 0;
                  state->du.p.rxurb[u].urb.type = USBDEVFS_URB_TYPE_BULK;
                  state->du.p.rxurb[u].urb.endpoint = 0x82;
                  state->du.p.rxurb[u].urb.flags = USBDEVFS_URB_QUEUE_BULK;
                  state->du.p.rxurb[u].urb.buffer = &state->du.p.rxurb[u].b.frame.frame[0];
                  state->du.p.rxurb[u].urb.buffer_length = sizeof(state->du.p.rxurb[u].b.frame.frame)+2;
                  state->du.p.rxurb[u].urb.signr = 0;
                  state->du.p.rxurb[u].urb.usercontext = (void *)(0x00000 | u);
            }
            for (u = 0; u < NUMTXPACKETS; u++) {
                  state->du.p.txurb[u].urbstate = 0;
                  state->du.p.txurb[u].urb.type = USBDEVFS_URB_TYPE_BULK;
                  state->du.p.txurb[u].urb.endpoint = 0x02;
                  state->du.p.txurb[u].urb.flags = USBDEVFS_URB_QUEUE_BULK | USBDEVFS_URB_ZERO_PACKET;
                  state->du.p.txurb[u].urb.buffer = state->du.p.txurb[u].b.buf;
                  state->du.p.txurb[u].urb.buffer_length = sizeof(state->du.p.txurb[u].b);
                  state->du.p.txurb[u].urb.signr = 0;
                  state->du.p.txurb[u].urb.usercontext = (void *)(0x10000 | u);
            }
      } else if (state->mode == MODE_AUDIO) {
            for (u = 0; u < NUMAUDIOURB; u++) {
                  state->du.a.inurb[u].urbstate = 0;
                  state->du.a.inurb[u].urb.type = USBDEVFS_URB_TYPE_ISO;
                  state->du.a.inurb[u].urb.endpoint = 0x88;
                  state->du.a.inurb[u].urb.flags = USBDEVFS_URB_ISO_ASAP;
                  state->du.a.inurb[u].urb.buffer = state->du.a.inurb[u].buf;
                  state->du.a.inurb[u].urb.buffer_length = sizeof(state->du.a.inurb[u].buf);
                  state->du.a.inurb[u].urb.number_of_packets = NUMFRAMESPERURB;
                  state->du.a.inurb[u].urb.signr = 0;
                  state->du.a.inurb[u].urb.usercontext = (void *)(0x00000 | u);
                  for (k = 0; k < NUMFRAMESPERURB; k++)
                        state->du.a.inurb[u].urb.iso_frame_desc[k].length = AUDIOSAMPLINGRATE/1000;
            }
            for (u = 0; u < NUMAUDIOURB; u++) {
                  state->du.a.outurb[u].urbstate = 0;
                  state->du.a.outurb[u].urb.type = USBDEVFS_URB_TYPE_ISO;
                  state->du.a.outurb[u].urb.endpoint = 0x08;
                  state->du.a.outurb[u].urb.flags = USBDEVFS_URB_ISO_ASAP;
                  state->du.a.outurb[u].urb.buffer = state->du.a.outurb[u].buf;
                  state->du.a.outurb[u].urb.buffer_length = sizeof(state->du.a.outurb[u].buf);
                  state->du.a.outurb[u].urb.number_of_packets = NUMFRAMESPERURB;
                  state->du.a.outurb[u].urb.signr = 0;
                  state->du.a.outurb[u].urb.usercontext = (void *)(0x10000 | u);
                  for (k = 0; k < NUMFRAMESPERURB; k++)
                        state->du.a.outurb[u].urb.iso_frame_desc[k].length = AUDIOSAMPLINGRATE/1000;
                  /* clear tx data */
                  memset(&state->du.a.outurb[u].buf, 0x80, sizeof(state->du.a.outurb[u].buf));
            }
      }
      /* claim device */
      if (usb_setconfiguration(state->usbdev, 1)) {
            lprintf(2, "netif_open: cannot set configuration 1\n");
            return -1;
      }
      /* claim interface 0 */
      if (usb_claiminterface(state->usbdev, 0)) {
            lprintf(2, "netif_open: cannot claim interface 0\n");
            return -1;
      }
      /* set interface 0 altsetting 1, to enable the bulk ep's */
      if (usb_setinterface(state->usbdev, 0, 1)) {
            lprintf(2, "netif_open: cannot set interface 0 altsetting 1\n");
            goto errsetif0;
      }
      state->bitraterx = state->bitratetx = state->txdmul = 0;
      if (state->mode == MODE_FSK || state->mode == MODE_EXTERNAL || state->mode == MODE_AFSK) {
            r = usb_control_msg(state->usbdev, 0xc0, 0xd1, 0, 0, 6, br, 100);
            if (r != 6) {
                  lprintf(1, "Error while reading adapter bitrate\n");
                  goto errsetif0;
            }
            state->bitratetx = br[0] | (br[1] << 8) | (br[2] << 16);
            state->bitraterx = br[3] | (br[4] << 8) | (br[5] << 16);
            state->txdmul = (state->bitratetx + 799) / 800;
            lprintf(5, "Adapter %s bitrate %u/%u\n",
                  state->serial, state->bitraterx, state->bitratetx);
        } else if (state->mode == MODE_AUDIO) {
#if 0
            /* claim interface 1 */
            if (usb_claiminterface(state->usbdev, 1)) {
                  lprintf(2, "netif_open: cannot claim interface 1\n");
                  goto errsetif0;
            }
            /* set interface 1 altsetting 0 */
            if (usb_setinterface(state->usbdev, 1, 0)) {
                  lprintf(2, "netif_open: cannot set interface 1 altsetting 0\n");
                  goto errsetif1;
            }
            /* claim interface 2 */
            if (usb_claiminterface(state->usbdev, 2)) {
                  lprintf(2, "netif_open: cannot claim interface 2\n");
                  goto errsetif1;
            }
            /* set interface 2 altsetting 1, to enable the ISO ep's */
            if (usb_setinterface(state->usbdev, 2, 1)) {
                  lprintf(2, "netif_open: cannot set interface 2 altsetting 1\n");
                  goto errsetif2;
            }
            /* claim interface 3 */
            if (usb_claiminterface(state->usbdev, 3)) {
                  lprintf(2, "netif_open: cannot claim interface 3\n");
                  goto errsetif2;
            }
            /* set interface 3 altsetting 1, to enable the ISO ep's */
            if (usb_setinterface(state->usbdev, 3, 1)) {
                  lprintf(2, "netif_open: cannot set interface 3 altsetting 1\n");
                  goto errsetif3;
            }
#endif
            audio_open(state);
      }
      lprintf(30, "netif_open\n");
      state->netif_opened = 1;
      return 0;

#if 0
  errsetif3:
      usb_releaseinterface(state->usbdev, 3);
  errsetif2:
      usb_releaseinterface(state->usbdev, 2);
  errsetif1:
      usb_releaseinterface(state->usbdev, 1);
#endif
  errsetif0:
      usb_releaseinterface(state->usbdev, 0);
      lprintf(30, "netif_open error\n");
      return -1;
}

/* --------------------------------------------------------------------- */

static int process(struct trx_thread_state *state, unsigned int timeout)
{
      unsigned int curtime = gettimems(), rettime = curtime + timeout;
      struct usbdevfs_urb *urb;
      signed int tdiff, tdiff1;
      unsigned int i, j;
      int r;
      DWORD wres;
      HANDLE whandle[2];

      if (!state->netif_opened) {
            if (timeout)
                  Sleep(timeout);
            return 0;
      }
      if (!timeout)
            rettime++;
      //lprintf(20, ">>> process: %d\n", timeout);
      acquire_trxdata_mutex(state);
      for (;;) {
            if (state->iurb.urbstate != URBSTATE_INPROGRESS) {
                  tdiff = curtime - state->iurb.nexttime;
                  if (tdiff >= 0) {
                        r = usb_submiturb(state->usbdev, &state->iurb.urb);
                        if (r < 0) {
                              lprintf(1, "error submitting interrupt urb\n");
                              goto submiterr;
                        }
                        state->iurb.urbstate = URBSTATE_INPROGRESS;
                        state->iurb.nexttime += INTERRUPT_INTERVAL;
                        tdiff = curtime - state->iurb.nexttime;
                        if (tdiff > 0)
                              state->iurb.nexttime = curtime;
                  }
            } else {
                  /* interrupt urb timeout processing */
                  tdiff = curtime - state->iurb.nexttime;
                  if (tdiff >= 1000) {
                        lprintf(1, "interrupt urb timeout\n");
                        if (usb_discardurb(state->usbdev, &state->iurb.urb))
                              lprintf(1, "error %s (%d) killing interrupt urb\n", strerror(errno), errno);
                        state->iurb.urbstate = URBSTATE_UNUSED;
                  }
            }
            if (state->curb.urbstate != URBSTATE_INPROGRESS) {
                  if (state->uarttxempty >= UARTTXDELAY && state->tfifo.rd != state->tfifo.wr) {
                        state->curb.buf.creq.requesttype = 0x40;
                        state->curb.buf.creq.request = 0xd3;
                        state->curb.buf.creq.value[0] = state->tfifo.buf[state->tfifo.rd];
                        state->curb.buf.creq.value[1] = 0;
                        state->curb.buf.creq.index[0] = 0;
                        state->curb.buf.creq.index[1] = 0;
                        state->curb.buf.creq.length[0] = 0;
                        state->curb.buf.creq.length[1] = 0;
                        state->curb.urb.buffer_length = 8;
                        r = usb_submiturb(state->usbdev, &state->curb.urb);
                        if (r < 0) {
                              lprintf(1, "error submitting control urb (txuart)\n");
                              goto submiterr;
                        }
                        state->curb.urbstate = URBSTATE_INPROGRESS;
                        state->curb.starttime = gettimems();
                        state->tfifo.rd = (state->tfifo.rd + 1) % sizeof(state->tfifo.buf);
                        state->uarttxempty = 0;
                  } else if (state->flags & FLG_CLRPTT) {
                        state->curb.buf.creq.requesttype = 0xc0;
                        state->curb.buf.creq.request = 0xd0;
                        state->curb.buf.creq.value[0] = 0;
                        state->curb.buf.creq.value[1] = 0;
                        state->curb.buf.creq.index[0] = 1;
                        state->curb.buf.creq.index[1] = 0;
                        state->curb.buf.creq.length[0] = 3;
                        state->curb.buf.creq.length[1] = 0;                   
                        state->curb.urb.buffer_length = 11;
                        r = usb_submiturb(state->usbdev, &state->curb.urb);
                        if (r < 0) {
                              lprintf(1, "error submitting control urb (ptt)\n");
                              goto submiterr;
                        }
                        state->curb.urbstate = URBSTATE_INPROGRESS;
                        state->curb.starttime = gettimems();
                        state->flags &= ~FLG_CLRPTT;
                  } else if (state->flags & FLG_SETPTT && !(state->flags & FLG_INHIBITSETPTT)) {
                        state->curb.buf.creq.requesttype = 0xc0;
                        state->curb.buf.creq.request = 0xd0;
                        state->curb.buf.creq.value[0] = (state->flags & FLG_MANUALPTT) ? 1 : 0;
                        state->curb.buf.creq.value[1] = 0;
                        state->curb.buf.creq.index[0] = 1;
                        state->curb.buf.creq.index[1] = 0;
                        state->curb.buf.creq.length[0] = 3;
                        state->curb.buf.creq.length[1] = 0;
                        state->curb.urb.buffer_length = 11;
                        r = usb_submiturb(state->usbdev, &state->curb.urb);
                        if (r < 0) {
                              lprintf(1, "error submitting control urb (ptt)\n");
                              goto submiterr;
                        }
                        state->curb.urbstate = URBSTATE_INPROGRESS;
                        state->curb.starttime = gettimems();
                        state->flags &= ~FLG_SETPTT;
                  } else if (state->flags & FLG_SETMDISCDIR) {
                        state->curb.buf.creq.requesttype = 0xc0;
                        state->curb.buf.creq.request = 0xd4;
                        state->curb.buf.creq.value[0] = state->cfg.mdisc.direction;
                        state->curb.buf.creq.value[1] = 0;
                        state->curb.buf.creq.index[0] = 2;
                        state->curb.buf.creq.index[1] = 0;
                        state->curb.buf.creq.length[0] = 3;
                        state->curb.buf.creq.length[1] = 0;
                        state->curb.urb.buffer_length = 11;
                        /* enable RxC, TxC or TxD outputs if special output mode is selected */
                        if (state->mode == MODE_FSK) {
                              if (state->cfg.mdisc.rxc)
                                    state->curb.buf.creq.value[0] &= ~(1 << 0);
                              if (state->cfg.mdisc.txc)
                                    state->curb.buf.creq.value[0] &= ~(1 << 1);
                              if (state->cfg.mdisc.txd)
                                    state->curb.buf.creq.value[0] &= ~(1 << 3);
                        }
                        r = usb_submiturb(state->usbdev, &state->curb.urb);
                        if (r < 0) {
                              lprintf(1, "error submitting control urb (mdiscdir)\n");
                              goto submiterr;
                        }
                        state->curb.urbstate = URBSTATE_INPROGRESS;
                        state->curb.starttime = gettimems();
                        state->flags &= ~FLG_SETMDISCDIR;
                  } else if (state->flags & FLG_SETMDISCOUT) {
                        state->curb.buf.creq.requesttype = 0xc0;
                        state->curb.buf.creq.request = 0xd4;
                        state->curb.buf.creq.value[0] = state->cfg.mdisc.output;
                        state->curb.buf.creq.value[1] = 0;
                        state->curb.buf.creq.index[0] = 1;
                        state->curb.buf.creq.index[1] = 0;
                        state->curb.buf.creq.length[0] = 3;
                        state->curb.buf.creq.length[1] = 0;
                        state->curb.urb.buffer_length = 11;
                        r = usb_submiturb(state->usbdev, &state->curb.urb);
                        if (r < 0) {
                              lprintf(1, "error submitting control urb (mdiscout)\n");
                              goto submiterr;
                        }
                        state->curb.urbstate = URBSTATE_INPROGRESS;
                        state->curb.starttime = gettimems();
                        state->flags &= ~FLG_SETMDISCOUT;
                  } else if (state->flags & FLG_SETT7FPORT) {
                        state->curb.buf.creq.requesttype = 0xc0;
                        state->curb.buf.creq.request = 0xd5;
                        state->curb.buf.creq.value[0] = state->t7fport;
                        state->curb.buf.creq.value[1] = 0;
                        state->curb.buf.creq.index[0] = 1;
                        state->curb.buf.creq.index[1] = 0;
                        state->curb.buf.creq.length[0] = 2;
                        state->curb.buf.creq.length[1] = 0;
                        state->curb.urb.buffer_length = 10;
                        r = usb_submiturb(state->usbdev, &state->curb.urb);
                        if (r < 0) {
                              lprintf(1, "error submitting control urb (t7fport)\n");
                              goto submiterr;
                        }
                        state->curb.urbstate = URBSTATE_INPROGRESS;
                        state->curb.starttime = gettimems();
                        state->flags &= ~FLG_SETT7FPORT;
                  } else if (state->flags & FLG_SETLEDS) {
                        state->curb.buf.creq.requesttype = 0x40;
                        state->curb.buf.creq.request = 0xd2;
                        state->curb.buf.creq.value[0] = state->leds & 3;
                        state->curb.buf.creq.value[1] = 0;
                        state->curb.buf.creq.index[0] = 0;
                        state->curb.buf.creq.index[1] = 0;
                        state->curb.buf.creq.length[0] = 0;
                        state->curb.buf.creq.length[1] = 0;
                        state->curb.urb.buffer_length = 8;
                        r = usb_submiturb(state->usbdev, &state->curb.urb);
                        if (r < 0) {
                              lprintf(1, "error submitting control urb (setleds)\n");
                              goto submiterr;
                        }
                        state->curb.urbstate = URBSTATE_INPROGRESS;
                        state->curb.starttime = gettimems();
                        state->flags &= ~FLG_SETLEDS;
                  }
            } else {
                  /* control URB timeout processing */
                  tdiff = curtime - state->curb.starttime;
                  if (tdiff >= 2000) {
                        lprintf(1, "control urb timeout\n");
                        if (usb_discardurb(state->usbdev, &state->curb.urb))
                              lprintf(1, "error %s (%d) killing interrupt urb\n", strerror(errno), errno);
                        state->curb.urbstate = URBSTATE_UNUSED;
                  }
            }
                if (state->mode == MODE_FSK || state->mode == MODE_EXTERNAL || state->mode == MODE_AFSK) {
                  for (;;) {
                        i = state->du.p.rxurbptr;
                        if (state->du.p.rxurb[i].urbstate == URBSTATE_INPROGRESS ||
                            state->du.p.rxurb[i].urbstate == URBSTATE_DONE ||
                            state->du.p.rxurb[i].urbstate == URBSTATE_CORBASEND)
                              break;
                        state->du.p.rxurb[i].urbstate = URBSTATE_UNUSED;
                        r = usb_submiturb(state->usbdev, &state->du.p.rxurb[i].urb);
                        if (r < 0) {
                              lprintf(1, "error submitting rx packet urb %u\n", i);
                              goto submiterr;
                        }
                        state->du.p.rxurb[i].urbstate = URBSTATE_INPROGRESS;
                        state->du.p.rxurbptr = (i + 1) % NUMRXPACKETS;
                  }
                  for (i = 0; i < NUMTXPACKETS; i++) {
                        if (state->du.p.txurb[i].urbstate != URBSTATE_FILLED)
                              continue;
                        r = usb_submiturb(state->usbdev, &state->du.p.txurb[i].urb);
                        if (r < 0) {
                              lprintf(1, "error submitting tx packet urb %u\n", i);
                              goto submiterr;
                        }
                        state->du.p.txurb[i].urbstate = URBSTATE_INPROGRESS;
#if 0
                        {
                              char buf[512];
                              snprintpkt(buf, sizeof(buf), state->du.p.txurb[i].urb.buffer+2, 
                                       state->du.p.txurb[i].urb.buffer_length-2);
                              printf("Tx(%u): %s\n", state->du.p.txurb[i].urb.buffer_length, buf);
                        }
#endif
                  }
#if 0
                  {
                        unsigned int rxu = 0, txu = 0;
                        for (i = 0; i < NUMRXPACKETS; i++)
                              if (state->du.p.rxurb[i].urbstate == URBSTATE_INPROGRESS)
                                    rxu++;
                        for (i = 0; i < NUMTXPACKETS; i++)
                              if (state->du.p.txurb[i].urbstate == URBSTATE_INPROGRESS)
                                    txu++;
                        if (rxu != NUMRXPACKETS || txu)
                              lprintf(10, "queued URBs: rx %u tx %u\n", rxu, txu);
                  }
#endif
            } else if (state->mode == MODE_AUDIO) {
                  for (i = 0; i < NUMAUDIOURB; i++) {
                        if (state->du.a.inurb[i].urbstate != URBSTATE_UNUSED)
                              continue;
                        r = usb_submiturb(state->usbdev, &state->du.a.inurb[i].urb);
                        if (r < 0) {
                              lprintf(1, "error submitting audio input urb %u\n", i);
                              goto submiterr;
                        }
                        state->du.a.inurb[i].urbstate = URBSTATE_INPROGRESS;
                  }
                  for (i = 0; i < NUMAUDIOURB; i++) {
                        if (state->du.a.outurb[i].urbstate != URBSTATE_UNUSED)
                              continue;
                        r = usb_submiturb(state->usbdev, &state->du.a.outurb[i].urb);
                        if (r < 0) {
                              lprintf(1, "error submitting audio output urb %u\n", i);
                              goto submiterr;
                        }
                        state->du.a.outurb[i].urbstate = URBSTATE_INPROGRESS;
                  }
            }
            tdiff = rettime - curtime;
            if (tdiff < 0) {
                  release_trxdata_mutex(state);
                  //lprintf(20, "<<< process\n");
                  return 0;
            }
            tdiff1 = state->iurb.nexttime - curtime;
            if (tdiff1 < 0)
                  tdiff1 = 0;
            if (tdiff1 < tdiff)
                  tdiff = tdiff1;
            release_trxdata_mutex(state);
#if 1
            //lprintf(20, ">>>WaitForMultipleObjects %d\n", tdiff);
            whandle[0] = state->hflxtxevent;
            whandle[1] = usb_getfd(state->usbdev);
            wres = WaitForMultipleObjects(2, whandle, FALSE, tdiff);
            urb = usb_reapurb(state->usbdev, 0);
            //lprintf(20, "<<<WaitForMultipleObjects %p\n", urb);
#else
            urb = usb_reapurb(state->usbdev, tdiff);
#endif
            acquire_trxdata_mutex(state);
            curtime = gettimems();
            if (!urb)
                  continue;
            switch (((unsigned int)urb->usercontext) & ~0xffff) {
            case 0x00000:
                  i = ((unsigned int)urb->usercontext) & 0xffff;
                  if (state->mode == MODE_FSK || state->mode == MODE_EXTERNAL || state->mode == MODE_AFSK) {
                        if (i > NUMRXPACKETS || urb != &state->du.p.rxurb[i].urb)
                              abort();
                        if (state->du.p.rxurb[i].urb.status || state->du.p.rxurb[i].urb.actual_length <= 2) {
                              lprintf(1, "receive transfer failed, status %u length %u\n",
                                    state->du.p.rxurb[i].urb.status, state->du.p.rxurb[i].urb.actual_length);
                              state->du.p.rxurb[i].urbstate = URBSTATE_UNUSED;
                        } else {
#if 0
                              {
                                    char buf[512];
                                    snprintpkt(buf, sizeof(buf), state->du.p.rxurb[i].urb.buffer,
                                             state->du.p.rxurb[i].urb.actual_length-2);
                                    printf("Rx(%d): %s\n", state->du.p.rxurb[i].urb.actual_length, buf);
                              }
#endif
                              state->du.p.rxurb[i].urbstate = URBSTATE_DONE;
                              SetEvent(state->hflxrxevent);
                        }
                  } else if (state->mode == MODE_AUDIO) {
                        if (i > NUMAUDIOURB || urb != &state->du.a.inurb[i].urb)
                              abort();
                        if (state->du.a.inurb[i].urb.status)
                              lprintf(1, "audio input transfer failed, status %u\n",
                                    state->du.a.inurb[i].urb.status);
                        for (j = 0; j < NUMFRAMESPERURB; j++) {
                              if (!state->du.a.inurb[i].urb.iso_frame_desc[j].status)
                                    continue;
                              lprintf(1, " audio input transfer frame %u status %u\n", 
                                    j, state->du.a.inurb[i].urb.iso_frame_desc[j].status);
                              memset(&state->du.a.inurb[i].buf[j*(AUDIOSAMPLINGRATE/1000)], 
                                     0x80, (AUDIOSAMPLINGRATE/1000));
                        }
                        audio_input(state, state->du.a.inurb[i].buf, NUMFRAMESPERURB*(AUDIOSAMPLINGRATE/1000));
                        state->du.a.inurb[i].urbstate = URBSTATE_UNUSED;
                  }
                  break;

            case 0x10000:
                  i = ((unsigned int)urb->usercontext) & 0xffff;
                  if (state->mode == MODE_FSK || state->mode == MODE_EXTERNAL || state->mode == MODE_AFSK) {
                        if (i > NUMTXPACKETS || urb != &state->du.p.txurb[i].urb)
                              abort();
                        if (state->du.p.txurb[i].urb.status)
                              lprintf(1, "transmit transfer failed, status %u length %u\n",
                                    state->du.p.txurb[i].urb.status, state->du.p.txurb[i].urb.actual_length);
                        state->du.p.txurb[i].urbstate = URBSTATE_UNUSED;
                  } else if (state->mode == MODE_AUDIO) {
                        if (i > NUMAUDIOURB || urb != &state->du.a.outurb[i].urb)
                              abort();
                        if (state->du.a.outurb[i].urb.status)
                              lprintf(1, "audio output transfer failed, status %u\n",
                                    state->du.a.outurb[i].urb.status);
                        for (j = 0; j < NUMFRAMESPERURB; j++) {
                              if (!state->du.a.outurb[i].urb.iso_frame_desc[j].status)
                                    continue;
                              lprintf(1, " audio output transfer frame %u status %u\n", 
                                    j, state->du.a.outurb[i].urb.iso_frame_desc[j].status);
                        }
                        audio_output(state, state->du.a.outurb[i].buf, NUMFRAMESPERURB*(AUDIOSAMPLINGRATE/1000));
                        state->du.a.outurb[i].urbstate = URBSTATE_UNUSED;
                  }
                  break;

            case 0x20000:
                  if (urb != &state->iurb.urb)
                        abort();
                  if (!state->iurb.urb.status && state->iurb.urb.actual_length >= 5) {
                        state->ptt = !!(state->iurb.buf[0] & 4);
                        if (state->mode != MODE_AUDIO)
                              state->dcd = !!(state->iurb.buf[0] & 8);
                        state->rssi = state->iurb.buf[3];
                        if (state->iurb.buf[0] & 32)
                              state->uarttxempty++;
                        else
                              state->uarttxempty = 0;
                        /* add UART RxChars */
                        if (state->iurb.urb.actual_length > 5)
                              addrxfifo(state, &state->iurb.buf[5], state->iurb.urb.actual_length-5);
                  } else {
                        lprintf(1, "interrupt transfer failed, status %u length %u\n",
                              state->iurb.urb.status, state->iurb.urb.actual_length);
                        goto interr;
                  }
#if 0
                  printf("ptt %d dcd %d rssi %u tempt %u slottime %u curtime %u\n", 
                         state->ptt, state->dcd, state->rssi, state->uarttxempty, state->slottime, curtime);
#endif
                  state->iurb.urbstate = URBSTATE_UNUSED;
                  break;

            case 0x30000:
                  if (urb != &state->curb.urb)
                        abort();
                  if (state->iurb.urb.status)
                        lprintf(1, "control transfer failed, status %u length %u\n",
                              state->curb.urb.status, state->curb.urb.actual_length);
                  state->curb.urbstate = URBSTATE_UNUSED;
                  break;

            default:
                  abort();
            }
      }
  submiterr:
      release_trxdata_mutex(state);
      lprintf(1, "Error submitting urb: %d/%s (%u)\n", r, strerror(errno), errno);
      return -1;

  interr:
      release_trxdata_mutex(state);
      return -1;
}

int polldevice(struct trx_thread_state *state)
{
      return process(state, 25);
}

/* --------------------------------------------------------------------- */

int getuartline(struct trx_thread_state *ctrl, unsigned int *ptr, unsigned char *buf, size_t bufsz, unsigned int timeout)
{
        unsigned int cpy = 0, reload;
      DWORD endtime;

        if (!ctrl)
                return -1;
      endtime = GetTickCount() + timeout;
        while (cpy < bufsz) {
            acquire_trxdata_mutex(ctrl);
            if (buf) {
                  while (cpy < bufsz && getrxfifo(ctrl, ptr, buf, 1) == 1) {
                        if (*buf == '\r' || *buf == '\n') {
                              cpy++;
                              *buf++ = '\n';
                              *buf = 0;
                              release_trxdata_mutex(ctrl);
                              return cpy;
                        }
                        cpy++;
                        buf++;
                  }
            }
            reload = ctrl->flags & FLG_RELOADMODEM;
            release_trxdata_mutex(ctrl);
            if (reload)
                  break;
                if ((signed)(GetTickCount()-endtime) > 0)
                        break;
            if (process(ctrl, 25))
                        return -1;
        }
      if (buf)
            *buf = 0;
        return cpy;
}

/* --------------------------------------------------------------------- */

static BOOL WINAPI signal_handler(DWORD type)
{
      switch (type) {
      case CTRL_C_EVENT:
      case CTRL_BREAK_EVENT:
            lprintf(1, "CTRL-C/BREAK pressed\n");
            quit = 1;
            return TRUE;

      case CTRL_CLOSE_EVENT:
            lprintf(1, "Console closed\n");
            return FALSE;

      case CTRL_LOGOFF_EVENT:
            lprintf(1, "Current user logging out\n");
            return FALSE;

      case CTRL_SHUTDOWN_EVENT:
            lprintf(1, "System shutdown\n");
            quit = 1;
            return TRUE;

      default:
            lprintf(1, "Unknown ConsoleCtrl type %lu\n", type);
            return FALSE;
      }
      return FALSE;
}

/* --------------------------------------------------------------------- */

static int do_init(int argc, char *argv[])
{
        static const struct option long_options[] = {
                { "drv", 1, 0, 'D' },
                { "config", 1, 0, 'C' },
                { "verbose", 1, 0, 'v' },
                { "help", 0, 0, 'h' },
            { "nommx", 0, 0, 0x400 },
            { "mmx", 0, 0, 0x401 },
                { 0, 0, 0, 0 }
        };
        int c, err = 0;
      unsigned int simd = 1;
        const char *cfgfile = NULL;

      hglobalshmem = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0,
                               PAGE_ALIGN(sizeof(struct win32_global_state)),
                               "baycomusb");
      if (!hglobalshmem) {
            lprintf(0, "Cannot create shared memory segment (error %lu)\n", GetLastError());
            return -1;
      }
      if (GetLastError() == ERROR_ALREADY_EXISTS) {
            CloseHandle(hglobalshmem);
            lprintf(0, "baycomusbserv already running\n");
            return -1;
      }
      globalstate = MapViewOfFile(hglobalshmem, FILE_MAP_ALL_ACCESS, 0, 0, 0);
      if (!globalstate) {
            lprintf(0, "Cannot map shared memory segment (error %lu)\n", GetLastError());
            return -1;
      }
      memset(globalstate, 0, sizeof(struct win32_global_state));
      strncpy(globalstate->signature, BAYUSBSIGNATURE, sizeof(globalstate->signature));
      globalstate->processid = GetCurrentProcessId();

        devlist_mutex = CreateMutex(NULL, FALSE, NULL);
      if (!devlist_mutex) {
            lprintf(0, "devlist_mutex creation error %lu\n", GetLastError());
            return -1;
      }

#if defined(ORBITIPC)
#ifdef USECRITICALSECT
      InitializeCriticalSection(&orbit_mutex);
#else
      orbit_mutex = CreateMutex(NULL, FALSE, NULL);
      if (!orbit_mutex) {
            lprintf(0, "orbit_mutex creation error %lu\n", GetLastError());
            return -1;
      }
#endif
      /* init custom IO handlers */
      IIOPAddConnectionHandler = orb_add_connection;
        IIOPRemoveConnectionHandler = orb_remove_connection;
#endif
      if (server_init1(&argc, argv))
            return -1;

      while ((c = getopt_long(argc, argv, "D:C:sv:S", long_options, NULL)) != EOF) {
                switch (c) {
                case 'D':
                        usb_setmountpoint(optarg);
                        break;

                case 'C':
                        cfgfile = optarg;
                        break;

                case 's':
                        syslogmsg = 1;
                        break;

                case 'v':
                        verboselevel = strtoul(optarg, NULL, 0);
                        break;

                case 'S':
                        break;
                        
            case 0x400:
            case 0x401:
                  simd = c & 1;
                  break;

                default:
                        err++;
                        break;
                }
        }
        if (err) {
                lprintf(1, "usage: %s [-v <vl>] [-s] [-D <drvpath>] [-C <configfile>]\n", argv[0]);
            return -1;
        }
        if (config_load(cfgfile))
            return -1;
      initsimd(simd);
        return 0;
}

/* --------------------------------------------------------------------- */

int server_entry_parse_argv(int argc, char *argv[])
{
        if (do_init(argc, argv))
                return 1;
      return 0;
}

int server_entry_run(void)
{
      if (!SetConsoleCtrlHandler(signal_handler, TRUE))
            lprintf(1, "Cannot add ConsoleCtrlHandler\n");
      if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS))
            lprintf(1, "Cannot set scheduling priority, error 0x%lx\n", GetLastError());
      audio_globalinit();
      if (server_init2())
            return 1;
      mainloop();
        config_save();
      return 0;
}

#define MAXARGV  64

void CALLBACK server_entry_cmdline(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow)
{
      unsigned int argc = 1;
      char *argv[MAXARGV];
      char *cp = lpszCmdLine;

      verboselevel = ~0;
      syslogmsg = 1;
      argv[0] = "bayusb.dll";
#if 0
      lprintf(0, "server_entry_cmdline: \"%s\"\n", lpszCmdLine);
#endif
      while (*cp) {
            while (*cp && isspace(*cp))
                  cp++;
            if (!*cp)
                  break;
            if (argc >= MAXARGV)
                  break;
            argv[argc++] = cp;
            while (*cp && !isspace(*cp))
                  cp++;
            if (!*cp)
                  break;
            *cp++ = 0;
      }
      lprintf(0, "server_entry_cmdline argc %u\n", argc);
#if 0
      {
            unsigned int i;
            for (i = 0; i < argc; i++)
                  lprintf(0, "server_entry_cmdline argv[%u] \"%s\"\n", i, argv[i]);
      }
#endif
#if 1
      if (server_entry_parse_argv(argc, argv))
            return;
      server_entry_run();
#endif
}

void server_entry_quit(void)
{
      quit = 1;
}

/* --------------------------------------------------------------------- */

static SERVICE_STATUS          MyServiceStatus; 
static SERVICE_STATUS_HANDLE   MyServiceStatusHandle; 

static void BaycomUsbServiceCtrlHandler(DWORD Opcode) 
{ 
        DWORD status; 
 
        switch(Opcode) { 
        case SERVICE_CONTROL_STOP: 
                quit = 1;
                MyServiceStatus.dwWin32ExitCode = 0; 
                MyServiceStatus.dwCurrentState  = SERVICE_STOP_PENDING; 
                MyServiceStatus.dwCheckPoint    = 0; 
                MyServiceStatus.dwWaitHint      = 0;
                if (!SetServiceStatus(MyServiceStatusHandle, &MyServiceStatus)) { 
                        status = GetLastError(); 
                        lprintf(1, "SetServiceStatus error %ld\n",status); 
                }
                lprintf(1, "Stopping baycomusbserv\n");
                return; 
 
        case SERVICE_CONTROL_INTERROGATE: 
                /* Fall through to send current status. */
                break;
 
        default:
                lprintf(1, "BaycomUsbServiceCtrlHandler: Unrecognized opcode %ld\n", Opcode); 
        }
        /* Send current status. */
        if (!SetServiceStatus(MyServiceStatusHandle, &MyServiceStatus)) { 
                status = GetLastError();
                lprintf(1, "SetServiceStatus error %ld\n",status); 
        }
}

static void BaycomUsbServiceStart(DWORD argc, LPTSTR *argv)
{ 
        DWORD status;
 
        MyServiceStatus.dwServiceType        = SERVICE_WIN32; 
        MyServiceStatus.dwCurrentState       = SERVICE_START_PENDING; 
        MyServiceStatus.dwControlsAccepted   = SERVICE_ACCEPT_STOP; 
        MyServiceStatus.dwWin32ExitCode      = 0; 
        MyServiceStatus.dwServiceSpecificExitCode = 0; 
        MyServiceStatus.dwCheckPoint         = 0; 
        MyServiceStatus.dwWaitHint           = 0; 
 
        MyServiceStatusHandle = RegisterServiceCtrlHandler(SERVICENAME, BaycomUsbServiceCtrlHandler);
        if (MyServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) {
                lprintf(1, "RegisterServiceCtrlHandler failed %ld\n", GetLastError());
                return;
        }
        if (do_init(argc, argv)) {
                MyServiceStatus.dwCurrentState       = SERVICE_STOPPED; 
                MyServiceStatus.dwCheckPoint         = 0; 
                MyServiceStatus.dwWaitHint           = 0; 
                MyServiceStatus.dwWin32ExitCode      = ERROR_ACCESS_DENIED; 
                MyServiceStatus.dwServiceSpecificExitCode = ERROR_INVALID_DATA;
                SetServiceStatus(MyServiceStatusHandle, &MyServiceStatus); 
                return; 
        }
        /* Initialization complete - report running status. */
        MyServiceStatus.dwCurrentState       = SERVICE_RUNNING; 
        MyServiceStatus.dwCheckPoint         = 0; 
        MyServiceStatus.dwWaitHint           = 0;
        if (!SetServiceStatus(MyServiceStatusHandle, &MyServiceStatus)) { 
                status = GetLastError(); 
                lprintf(1, "SetServiceStatus error %ld\n",status); 
        } 
      mainloop();
        config_save();
        MyServiceStatus.dwWin32ExitCode = 0; 
        MyServiceStatus.dwCurrentState  = SERVICE_STOPPED; 
        MyServiceStatus.dwCheckPoint    = 0; 
        MyServiceStatus.dwWaitHint      = 0;
        if (!SetServiceStatus(MyServiceStatusHandle, &MyServiceStatus)) { 
                status = GetLastError(); 
                lprintf(1, "SetServiceStatus error %ld\n",status); 
        } 
        lprintf(1, "baycomusbserv stopped\n");
}

/* --------------------------------------------------------------------- */

int main(int argc, char *argv[])
{
        SERVICE_TABLE_ENTRY DispatchTable[] = { 
                { SERVICENAME, BaycomUsbServiceStart },
                { NULL, NULL } 
        };

        printf("baycomusbserv v" VERSION " (c) 1999-2001 by Thomas Sailer, HB9JNX/AE4WA\n");
        if (argc >= 2 && !strcmp(argv[1], "-S")) {
                verboselevel = 10;
                syslogmsg = 1;
                if (!StartServiceCtrlDispatcher(DispatchTable)) {
                        lprintf(0, "Error starting service: %lu\n", GetLastError());
                        exit(1);
                }
                lprintf(0, "Starting Service\n");
                return 0;
        }
        if (server_entry_parse_argv(argc, argv))
                exit(1);
      return server_entry_run();
}

Generated by  Doxygen 1.6.0   Back to index