⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 device.cpp

📁 HPC上的RS232 USB Driver .该软件比PL2303专用驱动强
💻 CPP
字号:
// 232usb Copyright (c) 2003 Zoroyoshi, SOFTCLUB, Japan
// See source.txt for detail

#include <windows.h>
#include "usbdi.h"
#include "common.h"
#include "file.h"
#include "device.h"

DWORD WINAPI
notifyevent(void* ev)
{
  SetEvent((HANDLE)ev);
  return 0;
};

BOOL device_extension::
evaluateevent(DWORD bit)
{
  dmesg(L"eval x%x\n", bit);
  //list-read-lock
  EnterCriticalSection(&listcs);
  if(++listread==1) WaitForSingleObject(listlock, INFINITE);
  LeaveCriticalSection(&listcs);
  file_extension *fx= list;
  while(fx) {
    DWORD setbit= fx->waitmask&bit;
    if(setbit) {
      DWORD curbit= fx->waitbit;
      for(;;) {
	if((setbit&~curbit)==0) break;
        DWORD oldbit= curbit;
        curbit= InterlockedTestExchange((long*)&fx->waitbit, curbit, curbit|setbit);
	if(oldbit==curbit) {
	  dmesg(L"set\n");
	  SetEvent(fx->waitevent);
	  break;
	};
      };
    };
    fx= fx->list;
  };
  //list-read-unlock
  EnterCriticalSection(&listcs);
  if(--listread==0) SetEvent(listlock);
  LeaveCriticalSection(&listcs);
  return TRUE;
};

BOOL device_extension::
init()
{
  dmesg(L"init\n");
  list= 0;
  listlock= CreateEvent(0, 0, 1, 0); //signaled
  InitializeCriticalSection(&listcs);
  listread= 0;

  timeout.ReadIntervalTimeout= 250;
  timeout.ReadTotalTimeoutMultiplier= 10;
  timeout.ReadTotalTimeoutConstant= 100;
  timeout.WriteTotalTimeoutMultiplier=  0;
  timeout.WriteTotalTimeoutConstant =   0;
  readevent= CreateEvent(0, 0, 0, 0);
  writeevent= CreateEvent(0, 0, 0, 0);

  //moved from open
  InitializeCriticalSection(&flowcs);
  linein= 0; //CTS/DSR/RING/CD/BREAK
  recvin= 0;
  reset();

  classpipe= uf->lpOpenPipe(uh, &classendp->Descriptor);
  recvpipe= uf->lpOpenPipe(uh, &recvendp->Descriptor);
  sendpipe= uf->lpOpenPipe(uh, &sendendp->Descriptor);

  USB_TRANSFER ut;
  USB_DEVICE_REQUEST req;
  WORD abs;

  req.bmRequestType= USB_REQUEST_HOST_TO_DEVICE|USB_REQUEST_CLASS|USB_REQUEST_FOR_INTERFACE;
  req.bRequest= 0x2; //SET_COMM_FEATURE
  req.wValue= 1; req.wIndex= classif; req.wLength= sizeof(abs);
  abs= 2; //enable multiplexing
  ut= uf->lpIssueVendorTransfer(uh, 0, 0
  , USB_SEND_TO_INTERFACE|USB_OUT_TRANSFER
  , &req, (BYTE*)&abs, 0);
  if(ut) uf->lpCloseTransfer(ut);

  ut= uf->lpClearFeature(uh, 0, 0
  , USB_SEND_TO_ENDPOINT, USB_FEATURE_ENDPOINT_STALL, classendp->Descriptor.bEndpointAddress);
  if(ut) uf->lpCloseTransfer(ut);
  ut= uf->lpClearFeature(uh, 0, 0
  , USB_SEND_TO_ENDPOINT, USB_FEATURE_ENDPOINT_STALL, recvendp->Descriptor.bEndpointAddress);
  if(ut) uf->lpCloseTransfer(ut);
  ut= uf->lpClearFeature(uh, 0, 0
  , USB_SEND_TO_ENDPOINT, USB_FEATURE_ENDPOINT_STALL, sendendp->Descriptor.bEndpointAddress);
  if(ut) uf->lpCloseTransfer(ut);

  CloseHandle(CreateThread(0, 0, classwrap, this, 0, 0));
  CloseHandle(CreateThread(0, 0, recvwrap, this, 0, 0));

  return TRUE;
};

BOOL device_extension::
deinit()
{
  dmesg(L"deinit\n");
  //no-lock
  file_extension* fx= list;
  if(fx) {
    while(fx) {
      fx->dx= 0;
      SetEvent(fx->waitevent);
      fx= fx->list;
    };
    SetEvent(readevent);
    SetEvent(writeevent);
  };
  uf->lpClosePipe(classpipe); classpipe= 0;
  uf->lpClosePipe(recvpipe); recvpipe= 0;
  uf->lpClosePipe(sendpipe); sendpipe= 0;
  Sleep(100); // threads may be already closed because pipe was closed before notify...

  CloseHandle(readevent);
  CloseHandle(writeevent);
  CloseHandle(listlock);
  return TRUE;
};

BOOL device_extension::
setlinestate(int nandcode, int xorcode)
{
  USB_TRANSFER ut;
  USB_DEVICE_REQUEST req;
  lineout= lineout&~nandcode^xorcode;
  req.bmRequestType= USB_REQUEST_HOST_TO_DEVICE|USB_REQUEST_CLASS|USB_REQUEST_FOR_INTERFACE;
  req.bRequest= 0x22; //SET_CONTROL_LINE_STATE
  req.wValue= (WORD)lineout; req.wIndex= classif; req.wLength= 0;
  ut= uf->lpIssueVendorTransfer(uh, 0, 0
  , USB_SEND_TO_INTERFACE|USB_OUT_TRANSFER
  , &req, 0, 0);
  if(ut==0) return FALSE;
  uf->lpCloseTransfer(ut);
  return TRUE;
};

BOOL device_extension::
sendbreak(int duration)
{
  USB_TRANSFER ut;
  USB_DEVICE_REQUEST req;
  req.bmRequestType= USB_REQUEST_HOST_TO_DEVICE|USB_REQUEST_CLASS|USB_REQUEST_FOR_INTERFACE;
  req.bRequest= 0x23; //SEND_BREAK;
  req.wValue= duration; req.wIndex= classif; req.wLength= 0;
  ut= uf->lpIssueVendorTransfer(uh, 0, 0
  , USB_SEND_TO_INTERFACE|USB_OUT_TRANSFER
  , &req, 0, 0);
  if(ut==0) return FALSE;
  uf->lpCloseTransfer(ut);
  return TRUE;
};

DWORD WINAPI device_extension::
classwrap(void *dx)
{
  return ((device_extension*)dx)->classthread();
};

DWORD device_extension::
classthread()
{
  dmesg(L"cci start\n");
  BYTE buf[RECVPKT];
  int pkt= classendp->Descriptor.wMaxPacketSize;
  if(pkt>RECVPKT) pkt= RECVPKT;
  for(;;) {
    USB_TRANSFER ut;
    DWORD len, rc;
    ut= uf->lpIssueInterruptTransfer(classpipe, 0, 0
    , USB_IN_TRANSFER|USB_SHORT_TRANSFER_OK
    , pkt, buf, 0);
    if(ut==0) break;
    len= 0; rc= ~0;
    uf->lpGetTransferStatus(ut, &len, &rc);
    uf->lpCloseTransfer(ut);
    dmesg(L"cci %d %d\n", len, rc);
    if(rc!=0) break;
    if(len==8&&buf[0]==0xa1&&buf[1]==0x00) {
      DWORD oldin= linein;
      DWORD newin= oldin&0xffff|buf[2]<<16|buf[3]<<24;
      linein= newin;
      dmesg(L"cci 00:%02x:%02x x%x>x%x\n", buf[2], buf[3], oldin, newin);
      //if(!(oldin&0x10080)^!(newin&0x10080)) SetEvent(writeevent), evaluateevent(EV_CTS);
    } else if(len==10&&buf[0]==0xa1&&buf[1]==0x20) {
      DWORD oldin= linein;
      DWORD newin= oldin&0xffff0000|buf[8]|buf[9]<<8;
      DWORD oldinor= lineinor;
      linein= newin; lineinor= oldinor|newin;
      dmesg(L"cci 20:%02x:%02x x%x>x%x\n", buf[8], buf[9], oldin, newin);
      DWORD ev= 0;
      if((~oldin&newin)&4) ev|= EV_BREAK;
      if((oldin^newin)&2) ev|= EV_DSR;
      if((~oldin&newin)&0x70) ev|= EV_ERR;
      if((~oldin&newin)&8) ev|= EV_RING;
      if((oldin^newin)&1) ev|= EV_RLSD;
      if(usbmode&1) {
        if((oldin^newin)&0x80) ev|= EV_CTS;
      } else if(newin&0x80) usbmode|= 1; //clear automatic detection flag
      if(ev&(EV_CTS|EV_DSR)) SetEvent(writeevent);
      if(ev) evaluateevent(ev);
    };
  };
  dmesg(L"cci end\n");
  return 0;
};

DWORD WINAPI device_extension::
recvwrap(void* dx)
{
  return ((device_extension*)dx)->recvthread();
};

DWORD device_extension::
recvthread()
{
  dmesg(L"dci start\n");
  int pkt= recvendp->Descriptor.wMaxPacketSize;
  if(pkt>RECVPKT) pkt= RECVPKT;
  for(;;) {
    USB_TRANSFER ut;
    DWORD rc;
    int len;
    
    int ip= recvin;
    int sz= recvout-ip-1;
    if(sz>=0) {
      if(sz<pkt) ip= RECVSIZE; //transfer to additional area
    } else {
      sz+= RECVSIZE;
    };
    len= pkt;

    ut= uf->lpIssueBulkTransfer(recvpipe, 0, 0
    , USB_IN_TRANSFER|USB_SHORT_TRANSFER_OK
    , len, recvbuf+ip, 0);
    if(ut==0) break;
    len= 0; rc= ~0;
    uf->lpGetTransferStatus(ut, (DWORD*)&len, &rc);
    uf->lpCloseTransfer(ut);
    dmesg(L"dci %d %d %d\n", len, rc, sz);
    if(rc!=0) break;
    if(list==0) continue; //closed..just ignore received bytes
    if(dcb.fOutX) { //search xoff/xon char
      BYTE *p= recvbuf+ip;
      BYTE *q= p;
      for(int n= 0; n<len; n++) {
        BYTE c= *p++;
	if(c==dcb.XoffChar) {
	  sendxoff= 1; SetEvent(writeevent);
	} else if(c==dcb.XonChar) {
	  sendxoff= 0; SetEvent(writeevent);
	} else *q++= c;
      };
      len= q-(recvbuf+ip);
    };
    if(len==0) continue;
    if(len>sz) { //overrun
      errors|= CE_RXOVER;
      len= sz; //treat as received data even if sz==0
    };
    //copy, update rin
    if(ip!=recvin) {
      memcpy(recvbuf+recvin, recvbuf+ip, len);
      recvin+= len;
    } else {
      ip= recvin+len-RECVSIZE;
      if(ip>=0) { //uuoo!!
        memcpy(recvbuf, recvbuf+RECVSIZE, ip);
        recvin= ip;
      } else {
        recvin+= len;
      };
    };
    SetEvent(readevent);
    evaluateevent(EV_RXCHAR);
    sz-= len;
    if(recvflow==0&&sz<RECVSIZE/4) { //flow control
      int code= 0;
      if(dcb.fRtsControl==RTS_CONTROL_HANDSHAKE) code|= 2;
      if(dcb.fDtrControl==DTR_CONTROL_HANDSHAKE) code|= 1;
      if(code) setlinestate(code, 0);
      if(dcb.fInX) {
        EnterCriticalSection(&flowcs);
        USB_TRANSFER ut= uf->lpIssueBulkTransfer(sendpipe, 0, 0
        , USB_OUT_TRANSFER, 1, &dcb.XoffChar, 0);
        if(ut) uf->lpCloseTransfer(ut);
        recvflow= 1;
        LeaveCriticalSection(&flowcs);
      } else recvflow= 1;
    };
  };
  dmesg(L"dci end\n");
  return 0;
};

BOOL device_extension::
reset()
{
  lineout= 0; //RTS/DTR
  lineinor= 0;
  readuse= 0;
  writeuse= 0;
  sendxoff= 0;
  recvflow= 0;
  errors= 0;
  recvout= recvin;
  memset(&dcb, 0, sizeof(dcb));
  dcb.DCBlength= sizeof(dcb);
  dcb.BaudRate= 9600;
  dcb.ByteSize= 8; dcb.Parity= NOPARITY; dcb.StopBits= ONESTOPBIT;
  dcb.fDtrControl= DTR_CONTROL_DISABLE;
  dcb.fRtsControl= RTS_CONTROL_DISABLE;
  dcb.fBinary= 1; dcb.XonChar= 0x11; dcb.XoffChar= 0x13;
  return TRUE;
};

BOOL device_extension::
open()
{
  dmesg(L"open\n");
  reset();
  dcb.fDtrControl= DTR_CONTROL_ENABLE;
  dcb.fRtsControl= DTR_CONTROL_ENABLE;

  applydcb();
  return TRUE;
};

ULONG device_extension::
close()
{
  dmesg(L"close\n");
  setlinestate(~0, 0);
  return 0;
};

DWORD device_extension::
comstat(COMSTAT *ce)
{
  DWORD rc= InterlockedExchange((long*)&errors, 0);
  DWORD inor= InterlockedExchange((long*)&lineinor, 0);
  if(inor&16) rc|= CE_FRAME;
  if(inor&32) rc|= CE_RXPARITY;
  if(inor&64) rc|= CE_OVERRUN;
  if((inor|linein)&4) rc|= CE_BREAK; //once and continues

  memset(ce, 0, sizeof(COMSTAT));
  if(dcb.fOutxCtsFlow&&!((usbmode&1)==0||(linein&0x80))) ce->fCtsHold= 1;
  if(dcb.fOutxDsrFlow&&!(linein&2)) ce->fDsrHold= 1;
  //fRlsdHold= 0;
  if(dcb.fOutX&&sendxoff) ce->fXoffHold= 1;
  if(recvflow) {
    if(dcb.fInX&&!dcb.fTXContinueOnXoff) ce->fXoffSent= 1;
  };
  //fEof= 0;
  //fTxim= 0?
  int sz= recvin-recvout;
  if(sz<0) sz+= RECVSIZE;
  ce->cbInQue= sz;
  ce->cbOutQue= 0;
  return rc;
};

BOOL device_extension::
applydcb()
{
  if(dcb.fOutX==0) sendxoff= 0;
  int mode;
  if(dcb.fDtrControl==DTR_CONTROL_ENABLE) mode|= 1;
  else if(dcb.fDtrControl==DTR_CONTROL_HANDSHAKE&&recvflow==0) mode|= 1;
  if(dcb.fRtsControl==RTS_CONTROL_ENABLE) mode|= 2;
  else if(dcb.fRtsControl==RTS_CONTROL_HANDSHAKE&&recvflow==0) mode|= 2;
  setlinestate(~0, mode);

  USB_TRANSFER ut;
  USB_DEVICE_REQUEST req;
  BYTE buf[7];
  req.bmRequestType= USB_REQUEST_HOST_TO_DEVICE|USB_REQUEST_CLASS|USB_REQUEST_FOR_INTERFACE;
  req.bRequest= 0x20; //SET_LINE_CODING
  req.wValue= 0; req.wIndex= classif; req.wLength= 7;
  *(DWORD*)buf= dcb.BaudRate;
  buf[4]= dcb.StopBits;
  buf[5]= dcb.Parity;
  buf[6]= dcb.ByteSize;
  ut= uf->lpIssueVendorTransfer(uh, 0, 0
  , USB_SEND_TO_INTERFACE|USB_OUT_TRANSFER
  , &req, buf, 0);
  if(ut) uf->lpCloseTransfer(ut);
  return TRUE;
};

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -