📄 device.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 + -