sc2440_usb_ser.c
上传用户:qiulin1960
上传日期:2013-10-16
资源大小:2844k
文件大小:45k
源码类别:

Windows CE

开发平台:

Windows_Unix

  1. /*+
  2. THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  3. ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  4. THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  5. PARTICULAR PURPOSE.
  6. Copyright (c) 2001. Samsung Electronics, co. ltd  All rights reserved.
  7. Module Name:  
  8. Abstract:
  9. S3C2440 USB function(ACTIVE SYNC) device driver (Wrapper layer)
  10. rev:
  11. 2003.3.19 : updated for USB-DMA (purnnamu)
  12. 2002.5.7 : Add to s3c2410_code (Seung-han, Lim)
  13. 2002.1.22 : First release/no error recovery (kwangyoon LEE, kwangyoon@samsung.com)
  14. Notes: 
  15. */
  16. #include <windows.h>
  17. #include <types.h>
  18. #include <ceddk.h>
  19. #include <memory.h>
  20. #include <notify.h>
  21. #include <serhw.h>
  22. #include "S2440.h"
  23. #include <SC2440_usb_hw.h>
  24. #include <SC2440_usb_ser.h>
  25. #include <nkintr.h>
  26. #include <oalintr.h>
  27. #include <devload.h>
  28. #include <windev.h>
  29. #undef ZONE_INIT
  30. #include <serdbg.h>
  31. #include <celog.h> 
  32. #include <drv_glob.h> //:-)
  33. extern VOID SerialEventHandler(PVOID pHead);
  34. extern void msWait(unsigned msVal);
  35. extern volatile USBD_GLOBALS *usbdShMem; //:-)
  36. __inline static VOID
  37. SignalRemoval( PSER_INFO pHWHead )
  38. {
  39. pHWHead->ModemStatus &= ~MS_RLSD_ON;
  40. EvaluateEventFlag(pHWHead->pMddHead, EV_RLSD);
  41. }
  42. static
  43. DWORD WINAPI SerEventThread(PSER_INFO pHWHead)
  44. {
  45. ULONG WaitReturn;
  46. static HWND fgp=NULL, prev_fgp = NULL; 
  47. static HWND dialog_hwnd = NULL;
  48. static ULONG firstplug = 0, toretry = 0;
  49. static PROCESS_INFORMATION pi_usbcnect, pi_repllog;
  50. DEBUGMSG(1, (TEXT("++SerEventThreadrn")));
  51. DEBUGMSG(1, (TEXT("Spinning in dispatch thread %Xnr"), pHWHead));
  52. while (!pHWHead->pDispatchThread)
  53. Sleep(20);
  54. while (!pHWHead->KillRxThread) {
  55. DEBUGMSG (1, (TEXT("Event %X, Index %d, Int %drn"), 
  56. pHWHead->hSerialEvent,
  57. pHWHead->dwDevIndex,
  58. pHWHead->pHWObj->dwIntID ));
  59. // Ugly.  We don't get an interrupt when we are unplugged from the
  60. // bus, but we'd like to know when that happens.  So we use a timeout
  61. // on our interrupt wait.  This effectively allows me to poll the SOF
  62. // status, and if SOFs stop arriving, I'll assume we have been
  63. // disconnected from the bus.  Wait is last, allowing us to essentially
  64. // spoof one interrupt right at startup.
  65. // Only poll if we are opened and active.  Otherwise no one cares
  66. #ifdef POLL_FOR_DISCONNECT
  67. if (pHWHead->cOpenCount && pHWHead->dConfIdx)
  68. {
  69. // DEBUGMSG(1, (TEXT("waitforsingleobject in uprn")));
  70.       
  71. WaitReturn = WaitForSingleObject(pHWHead->hSerialEvent, SC2440_USB_POLL_RATE);
  72. // DEBUGMSG(1, (TEXT("waitforsingleobject inrn")));
  73. }
  74. else
  75. #endif        
  76. {
  77.    //DEBUGMSG(1, (TEXT("waitforsingleobject out uprn"))); 
  78.        WaitReturn = WaitForSingleObject(pHWHead->hSerialEvent, INFINITE);
  79. /*
  80.        DEBUGMSG(1, (TEXT("waitforsingleobject outrn")));  
  81.    if (WaitReturn == WAIT_ABANDONED)
  82.    {
  83. DEBUGMSG(1, (TEXT("WAIT_ABANDONEDrn")));
  84. }
  85. if (WaitReturn == WAIT_OBJECT_0)
  86. {
  87. DEBUGMSG(1, (TEXT("WAIT_OBJECT_0rn")));
  88. }
  89. if (WaitReturn == WAIT_TIMEOUT)
  90. {
  91. DEBUGMSG(1, (TEXT("WAIT_TIMEOUTrn")));
  92. }
  93. if (WaitReturn == WAIT_FAILED)
  94. {
  95. DEBUGMSG(1, (TEXT("WAIT_FAILEDrn")));
  96. }
  97. */
  98. }
  99. SerialEventHandler(pHWHead->pMddHead);
  100. InterruptDone(pHWHead->pHWObj->dwIntID);
  101. }
  102. DEBUGMSG (1, (TEXT("--SerEventThread %x exitingrn"), pHWHead));
  103. return (0);
  104. }
  105. static
  106. BOOL StartEventThread(PSER_INFO pHWHead)
  107. {
  108.     
  109. // Initialize the interrupt to be associated with the hSerialEvent
  110. // event. If this call fails, then another process has registered 
  111. // for the interrupt, so fail the init and set the hSerialEvent to NULL.
  112. DEBUGMSG(1, (TEXT("Initializing interrupt 0x%X, 0x%Xnr"),
  113. pHWHead->pHWObj->dwIntID, pHWHead->hSerialEvent));
  114. if (!InterruptInitialize(pHWHead->pHWObj->dwIntID, pHWHead->hSerialEvent, 0, 0)) 
  115. {
  116. DEBUGMSG(1, (TEXT("Error initializing interruptnr")));
  117. return (FALSE);
  118. }
  119. InterruptDone(pHWHead->pHWObj->dwIntID);
  120.     
  121. // Now set up the dispatch thread 
  122. pHWHead->KillRxThread = 0;
  123. DEBUGMSG(1, (TEXT("Spinning thread%Xnr"), pHWHead));
  124. pHWHead->pDispatchThread = CreateThread(NULL,0, SerEventThread,
  125. pHWHead, 0,NULL);
  126. if (pHWHead->pDispatchThread == NULL) 
  127. {
  128. DEBUGMSG(1, (TEXT("Error creating Event thread (%d)nr"), GetLastError()));
  129. return (FALSE);
  130. }
  131. DEBUGMSG (1, (TEXT("Created Event thread %Xrn"), pHWHead->pDispatchThread));
  132. DEBUGMSG (1, (TEXT("About to set priorityrn")));
  133. CeSetThreadPriority(pHWHead->pDispatchThread, DEFAULT_THREAD_PRIO);
  134.                           
  135. DEBUGMSG (1, (TEXT("Back from setting priorityrn")));
  136. return (TRUE);
  137. }
  138. /***************************************************************
  139.  @doc OEM
  140.  @func VOID | SerSetBaudRate |
  141.  * This routine sets the baud rate of the device.
  142.  *  Not exported to users, only to driver.
  143.  *
  144.  @rdesc None.
  145.  ****************************************************************/
  146. static
  147. BOOL SerSetBaudRate( PVOID pHead, // @parm PVOID returned by SerInit
  148.      ULONG BaudRate ) // @parm ULONG representing decimal baud rate.
  149. {
  150. PSER_INFO   pHWHead = (PSER_INFO)pHead;
  151. DEBUGMSG(1, (TEXT("SerSetBaudRatern")));
  152. // Baudrate is meaningless.  Just be agreeable and say we did it.
  153. return (TRUE);    
  154. }
  155. /****************************************************************
  156. @doc INTERNAL
  157. @func VOID | SerUSB_InternalMapRegisterAddresses |
  158. This routine maps the ASIC registers. 
  159. It's an artifact of this
  160. implementation.
  161. @rdesc None.
  162. ****************************************************************/
  163. static
  164. void SerUSBInternalMapRegisterAddresses( PSER_INFO   pHWHead )
  165. {
  166. PUCHAR  pVMem;
  167. BOOL    bMapReturn;
  168. ULONG   err = 0;
  169.   
  170. DEBUGMSG(1, (TEXT("++SerUSBInternalMapRegisterAddressesrn")));
  171. // Map CSR registers.
  172. pVMem = (PUCHAR)VirtualAlloc(0, PAGE_SIZE*2, MEM_RESERVE, PAGE_NOACCESS);
  173. if (pVMem) 
  174. {
  175. DEBUGMSG(1, (TEXT("VirtualAlloc Succeededrn")));
  176. bMapReturn = VirtualCopy( pVMem,
  177.   (LPVOID)pHWHead->dwIOBase,
  178.   PAGE_SIZE,
  179.   PAGE_READWRITE | PAGE_NOCACHE );
  180. if (!bMapReturn) 
  181. {
  182. err = GetLastError();
  183. DEBUGMSG(1, (TEXT("Virtual Copy: Serial SPACE FAILEDrn")));
  184. }
  185. pVMem = (BYTE *)pVMem;
  186. pHWHead->pUSBCtrlAddr=(volatile struct udcreg *)((BYTE *)pVMem + 0x140); // offset
  187. bMapReturn = VirtualCopy( pVMem+PAGE_SIZE,
  188.   (LPVOID)IOP_BASE,
  189.   PAGE_SIZE,
  190.   PAGE_READWRITE | PAGE_NOCACHE );
  191. if (!bMapReturn) 
  192. {
  193. err = GetLastError();
  194. DEBUGMSG(1, (TEXT("Virtual Copy: IOP SPACE FAILEDrn")));
  195. }
  196. pHWHead->pIrqCtrlAddr=(volatile IOPreg *)(pVMem+PAGE_SIZE);
  197. bMapReturn = VirtualCopy( pVMem+PAGE_SIZE,
  198.   (LPVOID)CLKPWR_BASE,
  199.   PAGE_SIZE,
  200.   PAGE_READWRITE | PAGE_NOCACHE );
  201. if (!bMapReturn) 
  202. {
  203. err = GetLastError();
  204. DEBUGMSG(1, (TEXT("Virtual Copy: CLKPWR SPACE FAILEDrn")));
  205. }
  206. pHWHead->pCLKPWR = (volatile CLKPWRreg *)(pVMem+PAGE_SIZE);
  207. } else {
  208.      DEBUGMSG(1, (TEXT("Virtual Alloc: FAILEDrn")));
  209. }
  210.   
  211. DEBUGMSG(1, (TEXT("VirtualCopy Succeeded, pVMem:%xrn"), pVMem));
  212. DEBUGMSG(1, (TEXT("--SerUSBInternalMapRegisterAddressesrn")));
  213. }
  214. static
  215. BOOL SerSetIRBaudRate( PSER_INFO pHWHead, ULONG baud ) // @parm baud rate - ignored
  216. {
  217. DEBUGMSG(1, (TEXT("Serial set IR Baud %drn"), baud));
  218. // We don't support IR
  219. return (FALSE);
  220. }
  221. /*******************************************************************************
  222. Routine:
  223.     Ser_GetRegistryData
  224. Description:
  225.     Take the registry path provided to COM_Init and use it to find this 
  226.     requested comm port's DeviceArrayIndex, the IOPort Base Address, and the
  227.     Interrupt number.
  228.    
  229. Arguments:
  230.     LPCTSTR regKeyPath the registry path passed in to COM_Init.
  231. Return Value:
  232.     -1 if there is an error.
  233. ******************************************************************************/
  234. static
  235. BOOL Ser_GetRegistryData(PSER_INFO pHWHead, LPCTSTR regKeyPath)
  236. {
  237. #define GCI_BUFFER_SIZE 256   
  238. LONG    regError;
  239. HKEY    hKey;
  240. TCHAR   devKeyPath[GCI_BUFFER_SIZE];
  241. DWORD   dwDataSize = GCI_BUFFER_SIZE;
  242. DEBUGMSG(1,
  243. (TEXT("Ser_GetRegistryData Try to open %srn"),regKeyPath));
  244.   // We've been handed the name of a key in the registry that was generated
  245.   // on the fly by device.exe.  We're going to open that key and pull from it
  246.   // a value that is the name of this serial port's real key.  That key
  247.   // will have the DeviceArrayIndex that we're trying to find.  
  248. regError = RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
  249. regKeyPath,
  250. 0, 
  251. KEY_ALL_ACCESS, 
  252. &hKey);
  253. if (regError != ERROR_SUCCESS) 
  254. {
  255. DEBUGMSG(1,(TEXT("Failed to open %s, Error 0x%Xrn"),regKeyPath,regError));
  256. return (FALSE);                
  257. }
  258. regError = RegQueryValueEx( hKey, 
  259.     DEVLOAD_DEVKEY_VALNAME,
  260.     NULL, 
  261.     NULL, 
  262.     (LPBYTE)devKeyPath,
  263.     &dwDataSize);
  264. // We're done with that registry key, so close it.
  265. RegCloseKey (hKey);
  266. if (regError != ERROR_SUCCESS) 
  267. {
  268. DEBUGMSG(1, (TEXT("Failed to find data at %s\%s, Error 0x%Xrn"), 
  269. regKeyPath, DEVLOAD_DEVKEY_VALNAME, regError));
  270. return (FALSE);                
  271. }
  272. DEBUGMSG(1, (TEXT("Try to open %srn"), devKeyPath));
  273. regError = RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
  274. devKeyPath, 
  275. 0,
  276. KEY_ALL_ACCESS, 
  277. &hKey);
  278. if (regError != ERROR_SUCCESS) 
  279. {
  280. DEBUGMSG(1,(TEXT("Failed to open %s, Error 0x%Xrn"), devKeyPath, regError));
  281. return (FALSE);        
  282. }
  283. // Okay, we're finally ready to try and load our registry data.
  284. dwDataSize = SC2440USB_REG_DEVINDEX_VAL_LEN;
  285. regError   = RegQueryValueEx(hKey, 
  286.      SC2440USB_REG_DEVINDEX_VAL_NAME, 
  287.      NULL, 
  288.      NULL,
  289.      (LPBYTE)(&pHWHead->dwDevIndex), 
  290.      &dwDataSize);
  291. if (regError == ERROR_SUCCESS) 
  292. {
  293. dwDataSize = SC2440USB_REG_IRQ_VAL_LEN;
  294. regError = RegQueryValueEx( hKey, 
  295.     SC2440USB_REG_IRQ_VAL_NAME, 
  296.     NULL, 
  297.     NULL,
  298.     (LPBYTE)(&pHWHead->dwIRQ), 
  299.     &dwDataSize );
  300. }
  301. if (regError == ERROR_SUCCESS) 
  302. {
  303. dwDataSize = SC2440USB_REG_IOBASE_VAL_LEN;
  304. regError = RegQueryValueEx( hKey, 
  305.     SC2440USB_REG_IOBASE_VAL_NAME, 
  306.     NULL, 
  307.     NULL,
  308.     (LPBYTE)(&pHWHead->dwIOBase), 
  309.     &dwDataSize);
  310. }
  311. if (regError == ERROR_SUCCESS) 
  312. {
  313. dwDataSize = SC2440USB_REG_IOLEN_VAL_LEN;
  314. regError = RegQueryValueEx( hKey, 
  315.     SC2440USB_REG_IOLEN_VAL_NAME, 
  316.     NULL, 
  317.     NULL,
  318.     (LPBYTE)(&pHWHead->dwIOLen), 
  319.     &dwDataSize);
  320. }
  321. RegCloseKey (hKey);
  322. if (regError != ERROR_SUCCESS) 
  323. {
  324. DEBUGMSG(1,(TEXT("Failed to get serial registry values, Error 0x%Xrn"),
  325. regError));
  326. return (FALSE);
  327. }
  328. DEBUGMSG(1,(TEXT("SerInit - Devindex %d, IRQ %d, IOB %X, IOLen %X rn"),
  329. pHWHead->dwDevIndex,
  330. pHWHead->dwIRQ,
  331. pHWHead->dwIOBase,
  332. pHWHead->dwIOLen));
  333. return (TRUE); 
  334. }
  335. /*************************************************************************
  336.  @doc OEM 
  337.  @func PVOID | SerInit | Initializes device identified by argument.
  338.  *  This routine sets information controlled by the user
  339.  *  such as Line control and baud rate. It can also initialize events and
  340.  *  interrupts, thereby indirectly managing initializing hardware buffers.
  341.  *  Exported only to driver, called only once per process.
  342.  *
  343.  @rdesc The return value is a PVOID to be passed back into the HW
  344.  dependent layer when HW functions are called.
  345.  ************************************************************************/
  346. static
  347. PVOID SerInit( ULONG   Identifier, // @parm Device identifier.
  348.                PVOID   pMddHead,   // @parm First argument to mdd callbacks.
  349.        PHWOBJ  pHWObj )    // @parm Pointer to our own HW OBJ for this device
  350. {
  351. PSER_INFO pHWHead;
  352. PHYSICAL_ADDRESS PhysicalAddress = {0,0};
  353. #ifdef DEBUG
  354. dpCurSettings.ulZoneMask = 0;
  355. #endif
  356. DEBUGMSG (1, (TEXT("++SerInit %Xrn"), pMddHead ));
  357. // Allocate for our main data structure and one of it's fields.
  358. pHWHead = (PSER_INFO)LocalAlloc( LPTR, sizeof(SER_INFO) );
  359. if ( !pHWHead )
  360. goto ALLOCFAILED;
  361. if (!Ser_GetRegistryData(pHWHead, (LPCTSTR)Identifier)) 
  362. {
  363. DEBUGMSG (1,(TEXT("SerInit - Unable to read registry data. Failing Init !!! rn")));
  364. goto ALLOCFAILED;
  365. }
  366. // Create our interrupt event.
  367. pHWHead->hSerialEvent = CreateEvent(0,FALSE,FALSE,NULL);
  368. // Initialize our critical sections
  369. InitializeCriticalSection(&(pHWHead->TransmitCritSec));
  370. InitializeCriticalSection(&(pHWHead->HwRegCritSec));
  371. SerUSBInternalMapRegisterAddresses(pHWHead);
  372. if(!InitUsbdDriverGlobals())  //:-)
  373. goto ALLOCFAILED;
  374. if(!UsbdAllocateVm())  //:-)
  375. goto ALLOCFAILED;
  376. pHWHead->pMddHead = pMddHead;
  377. pHWHead->cOpenCount = 0;
  378. pHWHead->pHWObj = pHWObj;
  379. pHWHead->wSOFStableCnt = 0; 
  380.     
  381. // Set up our Comm Properties data    
  382. pHWHead->CommProp.wPacketLength      = 0xffff;
  383. pHWHead->CommProp.wPacketVersion     = 0xffff;
  384. pHWHead->CommProp.dwServiceMask      = SP_SERIALCOMM;
  385. pHWHead->CommProp.dwReserved1        = 0;
  386. pHWHead->CommProp.dwMaxTxQueue       = 64;
  387. pHWHead->CommProp.dwMaxRxQueue       = 64;
  388. pHWHead->CommProp.dwMaxBaud          = BAUD_115200;
  389. pHWHead->CommProp.dwProvSubType      = PST_RS232;
  390. pHWHead->CommProp.dwProvCapabilities =  PCF_RLSD | 
  391. PCF_SETXCHAR |
  392. PCF_INTTIMEOUTS |
  393. PCF_SPECIALCHARS |
  394. PCF_TOTALTIMEOUTS |
  395. PCF_XONXOFF;
  396. pHWHead->CommProp.dwSettableBaud      = BAUD_075 | BAUD_110 | BAUD_150 | 
  397. BAUD_300 | BAUD_600 |
  398. BAUD_1200 | BAUD_1800 | 
  399. BAUD_2400 | BAUD_4800 |
  400. BAUD_7200 | BAUD_9600 | BAUD_14400 |
  401. BAUD_19200 | BAUD_38400 | 
  402. BAUD_56K | BAUD_128K |
  403. BAUD_115200 | BAUD_57600 | BAUD_USER;
  404. pHWHead->CommProp.dwSettableParams    = SP_BAUD | SP_RLSD ;
  405. pHWHead->CommProp.wSettableData       = DATABITS_8;
  406. pHWHead->CommProp.wSettableStopParity = STOPBITS_10 | STOPBITS_20 |
  407. PARITY_NONE | PARITY_ODD | 
  408. PARITY_EVEN | PARITY_SPACE |
  409. PARITY_MARK;
  410. pHWHead->fIRMode  = FALSE;   // Select wired by default
  411.     pHWHead->State = IDLE;
  412.     
  413. // Here is where we do any actual init for the hardware.  In the case of
  414. // USB function, we mostly just validate the hardware and then enable
  415.   // interrupts.  When we detect the presence of the bus, GetIntr will take
  416. // care of identify us to the host and kicking things off.
  417. SC2440_USB_Init(pHWHead);
  418. DEBUGMSG (1, (TEXT("--SerInit - %Xrn"), pHWHead ));
  419. return (pHWHead);
  420. ALLOCFAILED:
  421. // Unmap any memory areas that we may have mapped.
  422. if ( pHWHead->pUSBCtrlAddr)
  423. VirtualFree((PVOID)pHWHead->pUSBCtrlAddr, 0, MEM_RELEASE);
  424. if ( pHWHead->pIrqCtrlAddr)
  425. VirtualFree((PVOID)pHWHead->pIrqCtrlAddr, 0, MEM_RELEASE);
  426. if ( pHWHead->pCLKPWR)
  427. VirtualFree((PVOID)pHWHead->pCLKPWR, 0, MEM_RELEASE);
  428. LocalFree(pHWHead);
  429. // Free any critical sections we have allocated
  430. DeleteCriticalSection(&(pHWHead->TransmitCritSec));
  431. DeleteCriticalSection(&(pHWHead->HwRegCritSec));
  432. // And free the context data structure
  433. LocalFree(pHWHead);
  434. DEBUGMSG (1,(TEXT("--SerInit - %Xrn"), pHWHead ));
  435. return (NULL);
  436. }
  437. /*************************************************************************
  438.  @doc OEM 
  439.  @func PVOID | SerPostInit | Performs final hardware initialization.
  440.  ************************************************************************/
  441. static
  442. BOOL SerPostInit(PVOID   pHead)   // @parm PVOID returned by SerInit.
  443. {
  444. PSER_INFO pHWHead = (PSER_INFO)pHead;
  445. DEBUGMSG(1, (TEXT("+++SerPostInitrn")));
  446. // We use a PDD specific thread, rather than the default thread provided
  447. // by the MDD.
  448. StartEventThread( pHWHead );
  449. // Enable interrupts after thread is started - DAL
  450. // ....
  451. return TRUE;
  452. }
  453. /*************************************************************************
  454.  @doc OEM 
  455.  @func PVOID | SerDeinit | Deinitializes device identified by argument.
  456.  *  This routine frees any memory allocated by SerInit.
  457.  ************************************************************************/
  458. static
  459. BOOL SerDeinit(PVOID   pHead)   // @parm PVOID returned by SerInit.
  460. {
  461. PSER_INFO pHWHead = (PSER_INFO)pHead;
  462. DEBUGMSG(1, (TEXT("+SerDeinitrn")));
  463. // Disable interrupts
  464. // ...
  465. if ( !pHWHead )
  466. return (FALSE);
  467. // Make sure device is closed before doing DeInit
  468. if ( pHWHead->cOpenCount )
  469. SerClose( pHead );
  470. if ( pHWHead->pUSBCtrlAddr)
  471. VirtualFree((PVOID)pHWHead->pUSBCtrlAddr, 0, MEM_RELEASE);
  472. if ( pHWHead->pIrqCtrlAddr)
  473. VirtualFree((PVOID)pHWHead->pIrqCtrlAddr, 0, MEM_RELEASE);
  474. if ( pHWHead->pCLKPWR)
  475. VirtualFree((PVOID)pHWHead->pCLKPWR, 0, MEM_RELEASE);
  476. UsbdDeallocateVm(); //:-)
  477. // Free any critical sections we have allocated
  478. DeleteCriticalSection(&(pHWHead->TransmitCritSec));
  479. DeleteCriticalSection(&(pHWHead->HwRegCritSec));
  480. // Free the HWObj allocated in GetSerialObject
  481. LocalFree(pHWHead->pHWObj);
  482. LocalFree(pHWHead);
  483. DEBUGMSG(1, (TEXT("-SerDeinitrn")));
  484. return (TRUE);
  485. }
  486. /*************************************************************************
  487.  @doc OEM
  488.  @func BOOL | SerOpen | This routine is called when the port is opened.
  489.  *  Not exported to users, only to driver.
  490.  *
  491.  @rdesc Returns TRUE if successful, FALSEotherwise.
  492.  ************************************************************************/
  493. static
  494. BOOL SerOpen(PVOID   pHead) /*@parm PVOID returned by Serinit. */
  495. {
  496. PSER_INFO pHWHead = (PSER_INFO)pHead;
  497. DEBUGMSG(1,
  498. (TEXT("SerOpen+rn")));
  499. // Disallow multiple simultaneous opens
  500. if (pHWHead->cOpenCount)
  501. return (FALSE);
  502.     
  503. pHWHead->cOpenCount++;
  504. #ifdef POLL_FOR_DISCONNECT
  505. // Yuck.  We want to poll for detaches when the device is open.
  506. // But right now, the IST is in a wait infinite.  Spoof an interrupt
  507. // to let him know we have been opened and he needs to start polling.
  508. SetEvent(pHWHead->hSerialEvent);
  509. #endif
  510. return (TRUE);
  511. }
  512. /*************************************************************************
  513.  @doc OEM
  514.  @func ULONG | SerClose | This routine closes the device identified by the 
  515.  *  PVOID returned by SerInit.
  516.  *  Not exported to users, only to driver.
  517.  *
  518.  @rdesc The return value is 0.
  519.  ************************************************************************/
  520. static
  521. ULONG SerClose(PVOID   pHead)   // @parm PVOID returned by SerInit.
  522. {
  523. PSER_INFO pHWHead = (PSER_INFO)pHead;
  524. DEBUGMSG (1, (TEXT("++SerClosern")));
  525. if (pHWHead->cOpenCount) 
  526. {
  527. DEBUGMSG (1, (TEXT("SerClose, closing devicern")));
  528. pHWHead->cOpenCount--;
  529. #ifdef TODO
  530. // Do we need something similar on USB???
  531. // while we are still transmitting, sleep.
  532. uTries = 0;
  533. while ( ((pHWHead->ser16550.IER = READ_PORT_UCHAR(pHWHead->ser16550.pIER)) 
  534. & SERIAL_IER_THR) && // indicates TX in progress
  535. (uTries++ < 100) &&     // safety net
  536. // indicates FIFO not yet empty
  537. !(pHWHead->ser16550.LSR & SERIAL_LSR_TEMT)) 
  538. {
  539. DEBUGMSG(1, (TEXT("SerClose, TX in progress, IER 0x%X, LSR 0x%Xrn"),
  540. *pHWHead->ser16550.pIER, pHWHead->ser16550.LSR));
  541. Sleep(10);
  542. }
  543. #endif
  544. // TODO - When the device is closed, should power it down or somehow try to
  545. // let the desktop know that we aren't doing anything with any data that it
  546. // might be sending our way..
  547.     
  548. // Mask interrupts? - No, we wont see any more traffic - MBE.
  549. //pHWHead->pIrqCtrlAddr->icmr.sp0 = 0;
  550. }
  551. DEBUGMSG(1,(TEXT("--SerClosern")));
  552. return (0);
  553. }
  554. /*************************************************************************
  555.  @doc OEM
  556.  @func ULONG | SerRxIntr | This routine gets several characters from the 
  557. hardware receive buffer and puts them in a buffer provided via the se-
  558. cond argument. It returns the number of bytes lost to overrun.
  559.  @rdesc The return value indicates the number of overruns detected.
  560. The actual number of dropped characters may be higher.
  561. **************************************************************************/
  562. static
  563. ULONG SerRxIntr(PVOID pHead,                // @parm Pointer to hardware head
  564. PUCHAR pRxBuffer,           // @parm Pointer to receive buffer
  565. ULONG *pBufflen )           // @parm In = max bytes to read, out = bytes read
  566. {
  567. PSER_INFO   pHWHead  = (PSER_INFO)pHead;
  568. ULONG       RetVal  = 0;
  569. ULONG       TargetRoom  = *pBufflen;
  570. BOOL        fRXFlag  = FALSE;
  571. BOOL        fReplaceparityErrors = FALSE;
  572. BOOL        fNull;
  573. UCHAR       cEvtChar;
  574. PUCHAR      pRxOrig  = pRxBuffer;
  575. DEBUGMSG(1, (TEXT("++SerRxIntr %drn"), *pBufflen));
  576. cEvtChar = pHWHead->dcb.EvtChar;
  577. fNull  = pHWHead->dcb.fNull;
  578. if( pHWHead->dcb.fErrorChar && pHWHead->dcb.fParity )
  579. fReplaceparityErrors = TRUE;
  580.   
  581. // Protect the following from collision on hardware registers.
  582. // In particular, we can't let anyone else do SC2440_USB_ accesses between
  583. // time we set the read address and time we do the actual read in 
  584. // the loop below.
  585. EnterCriticalSection(&(pHWHead->HwRegCritSec));
  586. fRXFlag = SC2440_USB_RxIntHandler(pHWHead, pRxBuffer, pBufflen);
  587. LeaveCriticalSection(&(pHWHead->HwRegCritSec));
  588. // if we saw one (or more) EVT chars, then generate an event
  589. if( fRXFlag )
  590. EvaluateEventFlag( pHWHead->pMddHead, EV_RXFLAG );
  591. #ifdef DEBUG
  592. if( ZONE_RXDATA )
  593. CELOGDATA(1, CELID_RAW_UCHAR, pRxOrig, (WORD)*pBufflen, 1, CELZONE_MISC);
  594. #endif
  595. DEBUGMSG(1, (TEXT("--SerRxIntr - rx %d, drop %d.rn"),
  596. *pBufflen,
  597. pHWHead->DroppedBytes));
  598. RetVal       = pHWHead->DroppedBytes;
  599. pHWHead->DroppedBytes = 0;
  600. return RetVal;
  601. }
  602. /*************************************************************************
  603. @doc OEM
  604. @func PVOID | SerGetRxStart | This routine returns the start of the 
  605. hardware receive buffer.  See SerGetRxBufferSize.
  606.  
  607. @rdesc The return value is a pointer to the start of the device 
  608. receive buffer.
  609. *************************************************************************/ 
  610. static
  611. PVOID SerGetRxStart( PVOID   pHead ) // @parm PVOID returned by Serinit.
  612. {
  613. DEBUGMSG(1, (TEXT("SerGetRxStartrn")));   
  614. return  NULL;
  615. }
  616. /*************************************************************************
  617. @doc OEM
  618. @func ULONG | SerGetInterruptType | This function is called
  619. by the MDD whenever an interrupt occurs.  The return code
  620. is then checked by the MDD to determine which of the four
  621. interrupt handling routines are to be called.
  622. @rdesc This routine returns a bitmask indicating which interrupts
  623. are currently pending.
  624. *************************************************************************/ 
  625. static
  626. INTERRUPT_TYPE SerGetInterruptType( PVOID pHead ) // Pointer to hardware head
  627. {
  628. PSER_INFO pHWHead = (PSER_INFO)pHead;
  629. INTERRUPT_TYPE interrupts=0;
  630.     
  631. DEBUGMSG(1, (TEXT("++SerGetInterruptType 0x%Xrn"), pHead));
  632. interrupts = SC2440_USB_GetInterruptType(pHWHead);
  633. if (INTR_LINE & interrupts)
  634. {
  635. pHWHead->dConfIdx = 0;
  636. SignalRemoval(pHWHead);
  637. }
  638. #ifdef POLL_FOR_DISCONNECT
  639. //interrupts = HW_GetInterruptType(pHWHead);
  640. //RETAILMSG(1, (TEXT("interrupts = 0x%xrn"), interrupts));
  641. if (interrupts) 
  642. {
  643. pHWHead->wSOFStableCnt = 0;
  644. //RETAILMSG(1, (TEXT("pHWHead->wSOFStableCnt = 0x%xrn"), pHWHead->wSOFStableCnt));
  645. else if (pHWHead->dConfIdx && (pHWHead->wPrevSOF == pHWHead->wSOF))
  646. {
  647. if (++pHWHead->wSOFStableCnt > SOF_STABLE_MAX)
  648. {
  649. //RETAILMSG(1, (TEXT("DCD Dropped due to: wSOFStableCnt: %urn"), pHWHead->wSOFStableCnt));
  650. pHWHead->dConfIdx = 0;
  651. SignalRemoval(pHWHead);
  652. }
  653. }
  654. #endif
  655. DEBUGMSG (1, (TEXT("--SerGetInterruptType 0x%X, 0x%Xrn"),
  656. pHead, interrupts));
  657. return interrupts;
  658. }
  659. /*************************************************************************
  660. @doc OEM
  661. @func ULONG | SerModemIntr | This routine is called from the MDD
  662. whenever INTR_MODEM is returned by SerGetInterruptType.
  663. @rdesc None
  664. *************************************************************************/
  665. static
  666. VOID SerModemIntr( PVOID pHead )               // Hardware Head
  667. {
  668. PSER_INFO pHWHead = (PSER_INFO)pHead;
  669. DWORD dwModemStatus;
  670. dwModemStatus = pHWHead->ModemStatus;
  671. DEBUGMSG(1, (TEXT("+++SerModemIntrrn")));  
  672.     
  673. SC2440_USB_DoEndpoint0(pHWHead, &dwModemStatus);
  674. if ( pHWHead->dConfIdx ) 
  675. {
  676. if ( pHWHead->cOpenCount) 
  677. {
  678. // If open, notify app of any control line changes.
  679. DEBUGMSG(1, (TEXT("Modem Status %2.2X <> %2.2Xrn"),
  680. pHWHead->ModemStatus, dwModemStatus));
  681. if( (pHWHead->ModemStatus & MS_DSR_ON) != (dwModemStatus & MS_DSR_ON) )
  682. EvaluateEventFlag(pHWHead->pMddHead, EV_DSR);
  683. if( (pHWHead->ModemStatus & MS_CTS_ON) != (dwModemStatus & MS_CTS_ON) )
  684. EvaluateEventFlag(pHWHead->pMddHead, EV_CTS);
  685. if( (pHWHead->ModemStatus & MS_RLSD_ON) != (dwModemStatus & MS_RLSD_ON) )
  686. EvaluateEventFlag(pHWHead->pMddHead, EV_RLSD);
  687. } else {
  688. // If RLSD transitioned to active, we need to generate event.
  689. if( (dwModemStatus & MS_RLSD_ON) && !(pHWHead->ModemStatus & MS_RLSD_ON) ) 
  690. {
  691. if ( IsAPIReady(SH_WMGR) ) 
  692. {
  693. CeEventHasOccurred (NOTIFICATION_EVENT_RS232_DETECTED, NULL);
  694. }
  695. DEBUGMSG (0, (TEXT("Indicated RS232 Cable Eventrn")));
  696. }
  697. }
  698.    }
  699.    pHWHead->ModemStatus = dwModemStatus;
  700. DEBUGMSG(1, (TEXT("---SerModemIntrrn")));   
  701. }
  702. /*************************************************************************
  703. @doc OEM
  704. @func ULONG | SerLineIntr | This routine is called from the MDD
  705. whenever INTR_LINE is returned by SerGetInterruptType.
  706. @rdesc None
  707. *************************************************************************/
  708. static
  709. VOID SerLineIntr( PVOID pHead )               // Hardware Head
  710. {
  711. PSER_INFO pHWHead = (PSER_INFO)pHead;
  712. DEBUGMSG(1, (TEXT("SerLineIntrrn")));
  713.   // USB serial doesn't have a concept of anything like the LSR.
  714. // But since a bus reset is what we sort of equate to DCD, I use
  715. // this routine to handle USB reset conditions.
  716. // Note that by the time we get here with an SC2440_USB , we are actually
  717. //plugged back into the bus. I added some polling code to try and detect
  718. // detaches sooner
  719. SC2440_USB_LineIntHandler(pHWHead);  // Re-initialize the hardware    
  720. }
  721. /*************************************************************************
  722. @doc OEM
  723. @func ULONG | SerGetRxBufferSize | This function returns
  724. the size of the hardware buffer passed to the interrupt
  725. initialize function.  It would be used only for devices
  726. which share a buffer between the MDD/PDD and an ISR.
  727. @rdesc This routine always returns 0 for 16550 UARTS.
  728. **************************************************************************/
  729. static
  730. ULONG SerGetRxBufferSize( PVOID pHead )
  731. {
  732. DEBUGMSG(1, (TEXT("SerGetRxBufferSizern")));  
  733. return 10280;
  734. }
  735. /*************************************************************************
  736. @doc OEM
  737. @func ULONG | SerTXIntr | This routine is called from the new MDD
  738. whenever INTR_TX is returned by SerGetInterruptType.  It is 
  739. responsible for loading up the TX FIFO with next block of data.
  740. @rdesc None
  741. **************************************************************************/
  742. static
  743. VOID SerTxIntr( PVOID pHead,            // Hardware Head
  744. PUCHAR pTxBuffer,       // @parm Pointer to receive buffer
  745. ULONG *pBuffLen ) // @parm In = max bytes to transmit,
  746.             //       out = bytes transmitted
  747. {
  748. PSER_INFO pHWHead = (PSER_INFO)pHead;
  749. DEBUGMSG(1, (TEXT("SerTxIntr+rn")));
  750. pHWHead->CommErrors &= ~CE_TXFULL;
  751. SC2440_USB_TxIntHandler(pHWHead, pTxBuffer, pBuffLen);
  752. DEBUGMSG(1, (TEXT("SerTxIntr-, %d bytesrn"), *pBuffLen));  
  753. }
  754. /*************************************************************************
  755. @doc OEM
  756. @func BOOL | SerPowerOff | Called by driver to turn off power to 
  757. serial port.
  758. Not exported to users, only to driver.
  759.  
  760. @rdesc This routine returns a status.
  761.  ************************************************************************/
  762. static
  763. BOOL SerPowerOff( PVOID   pHead )      // @parm PVOID returned by SerInit.
  764. {
  765. PSER_INFO pHWHead = (PSER_INFO)pHead;
  766. pHWHead->cOpenCount = 0;
  767. //RETAILMSG(1,(TEXT("USB : SerPowerOff rn")));
  768. /*
  769. if ( pHWHead->cOpenCount )
  770. {
  771. EvaluateEventFlag( pHWHead->pMddHead, EV_RXFLAG );
  772. }
  773. return (TRUE);
  774. */
  775.     return HW_PowerOff(pHead);
  776. }
  777. /*************************************************************************
  778. @doc OEM
  779. @func BOOL | SerPowerOn | 
  780. Called by driver to turn on power to serial port.
  781. Not exported to users, only to driver.
  782.  
  783. @rdesc This routine returns a status.
  784.  ************************************************************************/
  785. static
  786. BOOL SerPowerOn( PVOID   pHead )      // @parm PVOID returned by SerInit.
  787. {
  788. PSER_INFO pHWHead = (PSER_INFO)pHead;
  789. //RETAILMSG(1,(TEXT("USB : SerPowerOn rn")));
  790.     return HW_PowerOn(pHead);
  791. }
  792. /*************************************************************************
  793. @doc OEM
  794. @func void | SerClearDtr | This routine clears DTR.
  795. @rdesc None.
  796. **************************************************************************/
  797. static
  798. VOID SerClearDTR( PVOID   pHead ) // @parm PVOID returned by HWinit.
  799. {
  800. DEBUGMSG(1, (TEXT("SerClearDTR, 0x%Xrn"), pHead));
  801. // We don't support DTR emulation.
  802. }
  803. /*************************************************************************
  804. @doc OEM
  805. @func VOID | SerSetDTR | This routine sets DTR.
  806.  
  807. @rdesc None.
  808. **************************************************************************/
  809. static
  810. VOID SerSetDTR( PVOID   pHead ) // @parm PVOID returned by HWinit.
  811. {    
  812. DEBUGMSG(1, (TEXT("SerSetDTR, 0x%Xrn"), pHead));
  813. // We don't support DTR emulation.
  814. }
  815. /*************************************************************************
  816. @doc OEM
  817. @func VOID | SerClearRTS | This routine clears RTS.
  818.  
  819. @rdesc None.
  820. **************************************************************************/
  821. static
  822. VOID SerClearRTS( PVOID   pHead ) // @parm PVOID returned by HWinit.
  823. {
  824. DEBUGMSG(1, (TEXT("SerClearRTS, 0x%Xrn"), pHead));
  825. // We don't support RTS emulation.
  826. }
  827. /*************************************************************************
  828. @doc OEM
  829. @func VOID | SerSetRTS | This routine sets RTS.
  830. @rdesc None.
  831. **************************************************************************/
  832. static
  833. VOID SerSetRTS( PVOID   pHead ) // @parm PVOID returned by HWinit.
  834. {
  835. DEBUGMSG(1, (TEXT("SerSetRTS, 0x%Xrn"), pHead));
  836. // We don't support RTS emulation.
  837. }
  838. /*************************************************************************
  839. @doc OEM
  840. @func BOOL | SerEnableIR | This routine enables ir.
  841. Not exported to users, only to driver.
  842. @rdesc Returns TRUE if successful, FALSEotherwise.
  843. **************************************************************************/
  844. static
  845. BOOL SerEnableIR( PVOID   pHead, // @parm PVOID returned by Serinit.
  846.   ULONG   BaudRate ) // @parm PVOID returned by HWinit.
  847. {
  848. PSER_INFO pHWHead = (PSER_INFO)pHead;
  849. DEBUGMSG(1, (TEXT("SerEnableIR, 0x%Xrn"), pHead));
  850. // We don't support an IR mode, so fail.
  851. return (FALSE);
  852. }
  853. /*************************************************************************
  854. @doc OEM
  855. @func BOOL | SerDisableIR | This routine disable the ir.
  856. Not exported to users, only to driver.
  857.  
  858. @rdesc Returns TRUE if successful, FALSEotherwise.
  859. **************************************************************************/
  860. static
  861. BOOL SerDisableIR( PVOID   pHead ) // @parm PVOID returned by Serinit. 
  862. {
  863. PSER_INFO pHWHead = (PSER_INFO)pHead;
  864. DEBUGMSG(1, (TEXT("SerDisableIR, 0x%Xrn"), pHead));
  865. // We don't support an IR mode.  But don't fail, in case
  866. // someone calls this redundantly to ensure that we are
  867. // in wired mode, which is what we support.
  868. return (TRUE);
  869. }
  870. /*************************************************************************
  871. @doc OEM
  872. @func VOID | SerClearBreak | This routine clears break.
  873.  
  874. @rdesc None.
  875. *************************************************************************/ 
  876. static
  877. VOID SerClearBreak( PVOID   pHead ) // @parm PVOID returned by HWinit.
  878. {
  879. DEBUGMSG(1, (TEXT("SerClearBreak, 0x%Xrn"), pHead));
  880. // We don't have a concept of break over USB serial
  881. }
  882. /*************************************************************************
  883. @doc OEM
  884. @func VOID | SerSetBreak | This routine sets break.
  885. @rdesc None.
  886. *************************************************************************/
  887. static
  888. VOID SerSetBreak( PVOID   pHead ) // @parm PVOID returned by HWinit.
  889. {
  890. DEBUGMSG(1, (TEXT("SerSetBreak, 0x%Xrn"), pHead));
  891. // We don't have a concept of break over USB serial
  892. }
  893. /*************************************************************************
  894. @doc OEM
  895. @func BOOL | SerXmitComChar | Transmit a char immediately
  896.  
  897. @rdesc TRUE if succesful
  898. *************************************************************************/
  899. static
  900. BOOL SerXmitComChar( PVOID   pHead,     // @parm PVOID returned by HWInit.
  901.      UCHAR   ComChar )  // @parm Character to transmit. 
  902. {
  903. PSER_INFO pHWHead = (PSER_INFO)pHead;
  904.     
  905. DEBUGMSG(1, (TEXT("+SerXmitComChar 0x%Xrn"), pHead));
  906. // Get critical section, then transmit when buffer empties
  907. DEBUGMSG(1, (TEXT("XmitComChar wait for CritSec %x.rn"),
  908. &(pHWHead->TransmitCritSec)));
  909. EnterCriticalSection(&(pHWHead->TransmitCritSec));
  910. DEBUGMSG(1, (TEXT("XmitComChar got CritSec %x.rn"),
  911. &(pHWHead->TransmitCritSec)));
  912. try
  913.     {
  914. // TODO - We need to wait for the current transmit to finish and
  915. // then sneak this data in ahead of whatever else is queued.
  916. #ifdef TODO
  917. while( TRUE )  // We know THR will eventually empty
  918. {
  919. // Write the character if we can
  920. ReadLSR( pHWHead );
  921. if( pHWHead->LSR & SERIAL_LSR_THRE ) 
  922. {
  923. OUTB(pHWHead, pData, ComChar);
  924. DEBUGMSG(1, (TEXT("XmitComChar wrote x%Xrn"), ComChar));
  925. break;
  926. }
  927. // If we couldn't write the data yet, then wait for a
  928. // TXINTR to come in and try it again.
  929.             
  930. // Enable xmit intr.
  931. OUTB(pHWHead, pIER, IER_NORMAL_INTS | SERIAL_IER_THR);
  932. // Wait until the txintr has signalled.
  933. DEBUGMSG(1, (TEXT("XmitComChar WaitIntr x%Xrn"),
  934. pHWHead->FlushDone));
  935. WaitForSingleObject(pHWHead->FlushDone, (ULONG)1000);
  936. }
  937. #else
  938. DEBUGMSG (0, (TEXT("!!! SerXmitComChar 0x%X not implementedrn"),
  939.    pHead));
  940. #endif        
  941. }
  942. except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
  943. EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) 
  944. {
  945. // Just exit
  946. }
  947.     
  948. LeaveCriticalSection(&(pHWHead->TransmitCritSec));
  949. DEBUGMSG(1, (TEXT("XmitComChar released CritSec %x.rn"),
  950. &(pHWHead->TransmitCritSec)));
  951.     
  952. DEBUGMSG(1, (TEXT("-SerXmitComChar 0x%Xrn"), pHead));
  953.     
  954. return TRUE;
  955. }
  956.         
  957. /*************************************************************************
  958. @doc OEM
  959. @func ULONG | SerGetStatus | This structure is called by the MDD
  960. to retrieve the contents of a COMSTAT structure.
  961. @rdesc The return is a ULONG, representing success (0) or failure (-1).
  962. *************************************************************************/
  963. static
  964. ULONG SerGetStatus( PVOID pHead, // @parm PVOID returned by HWInit.
  965. LPCOMSTAT lpStat )// Pointer to LPCOMMSTAT to hold status.
  966. {
  967. PSER_INFO pHWHead  = (PSER_INFO)pHead;
  968. ULONG RetVal  = pHWHead->CommErrors;
  969.     
  970. DEBUGMSG(1, (TEXT("++SerGetStatus 0x%Xrn"), pHead));
  971. pHWHead->CommErrors = 0; // Clear old errors each time
  972. // We don't emulate any of this, so always return a fixed result.
  973. if (lpStat) 
  974. {
  975. // TODO - Make sure we return reasonable results here.
  976. pHWHead->Status.fCtsHold = 0;
  977. pHWHead->Status.fDsrHold = 0;
  978. pHWHead->Status.cbInQue  = 0;
  979. pHWHead->Status.cbOutQue = 0;
  980. }
  981. else
  982. RetVal = (ULONG)-1;
  983. DEBUGMSG(1, (TEXT("--SerGetStatus 0x%Xrn"), pHead));
  984. return RetVal;
  985. }
  986. /*************************************************************************
  987. @doc OEM
  988. @func ULONG | SerReset | Perform any operations associated
  989. with a device reset
  990. @rdesc None.
  991. *************************************************************************/
  992. static
  993. VOID SerReset( PVOID   pHead ) // @parm PVOID returned by HWInit.
  994. {
  995. PSER_INFO pHWHead = (PSER_INFO)pHead;
  996. DEBUGMSG(1, (TEXT("++SerReset 0x%Xrn"), pHead));
  997. memset(&pHWHead->Status, 0, sizeof(COMSTAT));
  998. // TODO - Is there anything special we need to do here.
  999.     
  1000. DEBUGMSG(1, (TEXT("--SerReset 0x%Xrn"), pHead));
  1001. }
  1002. /*************************************************************************
  1003. @doc OEM
  1004. @func VOID | SerGetModemStatus | Retrieves modem status.
  1005. @rdesc None.
  1006. *************************************************************************/
  1007. static
  1008. VOID SerGetModemStatus( PVOID   pHead,        // @parm PVOID returned by HWInit.
  1009. PULONG  pModemStatus ) // @parm PULONG passed in by user.
  1010. {
  1011. PSER_INFO pHWHead = (PSER_INFO)pHead;
  1012.     
  1013. DEBUGMSG(1, (TEXT("++SerGetModemStatus 0x%Xrn"), pHead));
  1014. *pModemStatus = pHWHead->ModemStatus;
  1015. DEBUGMSG (0, (TEXT("--SerGetModemStatus 0x%X (stat x%X) rn"),
  1016. pHead,
  1017. *pModemStatus));
  1018. return;
  1019. }
  1020. /*************************************************************************
  1021. @doc OEM
  1022. @func VOID | SerGetCommProperties | Retrieves Comm Properties.
  1023.  
  1024. @rdesc None.
  1025. *************************************************************************/
  1026. static
  1027. VOID SerGetCommProperties( 
  1028. PVOID   pHead, // @parm PVOID returned by SerInit. 
  1029. LPCOMMPROP  pCommProp ) // @parm Pointer to receive COMMPROP structure. 
  1030. {
  1031. PSER_INFO pHWHead = (PSER_INFO)pHead;
  1032. DEBUGMSG(1, (TEXT("SerGetCommProperties 0x%Xrn"), pHead));
  1033. *pCommProp = pHWHead->CommProp;
  1034. return;
  1035. }
  1036. /*************************************************************************
  1037. @doc OEM
  1038. @func VOID | SerPurgeComm | Purge RX and/or TX
  1039.  
  1040. @rdesc None.
  1041. *************************************************************************/
  1042. static
  1043. VOID SerPurgeComm( PVOID   pHead,  // @parm PVOID returned by HWInit.
  1044.    DWORD   fdwAction )  // @parm Action to take. 
  1045. {
  1046. PSER_INFO pHWHead = (PSER_INFO)pHead;
  1047.     
  1048. DEBUGMSG(1, (TEXT("++SerPurgeComm 0x%Xrn"), pHead));
  1049. EnterCriticalSection(&(pHWHead->HwRegCritSec));
  1050. if ( (fdwAction & PURGE_TXCLEAR) || (fdwAction & PURGE_TXABORT) ) 
  1051. {
  1052. // Abort any pending TX data.  The MDD takes care of aborting
  1053. // data pended in the driver.  All I can do to stop an IN that
  1054. // has already been queued is to Un-Arm this endpoint, causing
  1055. // subsequent INs to get naked.  If the IN transfer has started, 
  1056. // its not clear I can stop it in progress.
  1057. // In addition to NAKing host, clearing ARM tells TxIntr that he
  1058. // can use the buffer for the next write that comes down.
  1059. #if TODO
  1060. ucECR = SC2440_USB_Read(pHWHead, EP1AControl);
  1061. ucECR &= 0xFE;   // Clear the ARM bit.
  1062. SC2440_USB_Write(pHWHead, EP1AControl, ucECR );
  1063. #endif
  1064. }
  1065. if ( (fdwAction & PURGE_RXCLEAR) || (fdwAction & PURGE_RXABORT) ) {
  1066. #if TODO
  1067. // Abort any pending RX data.
  1068. SC2440_USB_Write(pHWHead, IntStatus, 0x04 );   // Clear the EP2 interrupt
  1069. SC2440_USB_Write(pHWHead, EP2AControl, 0x03);  // Reenable the endpoint
  1070. #endif
  1071. }
  1072.     
  1073. LeaveCriticalSection(&(pHWHead->HwRegCritSec));
  1074. DEBUGMSG(1,
  1075. (TEXT("--SerPurgeComm 0x%Xrn"), pHead));
  1076. return;
  1077. }
  1078. /************************************************************************
  1079. @doc OEM
  1080. @func BOOL | SerSetDCB | Sets new values for DCB.  This
  1081. routine gets a DCB from the MDD.  It must then compare
  1082. this to the current DCB, and if any fields have changed take
  1083. appropriate action.
  1084.  
  1085. @rdesc BOOL
  1086. ************************************************************************/
  1087. static
  1088. BOOL SerSetDCB( PVOID   pHead,     // @parm PVOID returned by HWInit.
  1089. LPDCB   lpDCB )     // @parm    Pointer to DCB structure
  1090. {
  1091. PSER_INFO pHWHead = (PSER_INFO)pHead;
  1092. BOOL bRet;
  1093.     
  1094. DEBUGMSG(1, (TEXT("++SerSetDCB 0x%Xrn"), pHead));
  1095. bRet = TRUE;
  1096. // If the device is open, scan for changes and do whatever
  1097. // is needed for the changed fields.  if the device isn't
  1098. // open yet, just save the DCB for later use by the open.
  1099. if( pHWHead->OpenCount ) 
  1100. {
  1101. #ifdef TODO
  1102. // We don't really support any of this.  Ignore for now
  1103. // Note, fparity just says whether we should check
  1104. // receive parity.  And the 16550 won't let us NOT
  1105. // check parity if we generate it.  So this field
  1106. // has no effect on the hardware.
  1107.     
  1108. if ( lpDCB->BaudRate != pHWHead->dcb.BaudRate ) 
  1109. {
  1110. bRet = SerSetBaudRate( pHWHead, lpDCB->BaudRate );
  1111. }
  1112.     
  1113. if ( bRet && (lpDCB->ByteSize != pHWHead->dcb.ByteSize )) 
  1114. {
  1115. bRet = SerSetByteSize( pHWHead, lpDCB->ByteSize );
  1116. }
  1117.     
  1118. if ( bRet && (lpDCB->Parity != pHWHead->dcb.Parity )) 
  1119. {
  1120. bRet = SerSetParity( pHWHead, lpDCB->Parity );
  1121. }
  1122.     
  1123. if ( bRet && (lpDCB->StopBits != pHWHead->dcb.StopBits )) 
  1124. {
  1125. bRet = SerSetStopBits( pHWHead, lpDCB->StopBits );
  1126. }
  1127. // Don't worry about fOutxCtsFlow.  It is a flag which
  1128. // will be examined every time we load the TX buffer.
  1129. // No special action required here.
  1130. #endif         
  1131. }
  1132.     
  1133. if (bRet) 
  1134. {
  1135. // Now that we have done the right thing, store this DCB
  1136. pHWHead->dcb = *lpDCB;
  1137. }
  1138. DEBUGMSG(1, (TEXT("--SerSetDCB 0x%Xrn"), pHead));
  1139. return bRet;
  1140. }
  1141. /*************************************************************************
  1142. @doc OEM
  1143. @func BOOL | SerSetCommTimeouts | Sets new values for the
  1144. CommTimeouts structure. routine gets a DCB from the MDD.  It
  1145. must then compare this to the current DCB, and if any fields
  1146. have changed take appropriate action.
  1147. @rdesc ULONG
  1148. *************************************************************************/
  1149. static
  1150. ULONG SerSetCommTimeouts( 
  1151. PVOID   pHead,   // @parm PVOID returned by HWInit.
  1152. LPCOMMTIMEOUTS   lpCommTimeouts ) // @parm Pointer to CommTimeout structure
  1153. {
  1154. PSER_INFO pHWHead = (PSER_INFO)pHead;
  1155. ULONG retval      = 0;
  1156.     
  1157. DEBUGMSG(1, (TEXT("++SerSetCommTimeout 0x%Xrn"), pHead));
  1158. // OK, first check for any changes and act upon them
  1159. if( lpCommTimeouts->WriteTotalTimeoutMultiplier !=
  1160. pHWHead->CommTimeouts.WriteTotalTimeoutMultiplier )
  1161. {
  1162. }
  1163.     
  1164. // Now that we have done the right thing, store this DCB
  1165. pHWHead->CommTimeouts = *lpCommTimeouts;
  1166. DEBUGMSG(1, (TEXT("--SerSetCommTimeout 0x%Xrn"), pHead));
  1167. return retval;
  1168. }
  1169. /*************************************************************************
  1170.     @doc OEM
  1171.     @func    BOOL | SerIoctl | Device IO control routine.  
  1172.     @parm DWORD | dwOpenData | value returned from COM_Open call
  1173.     @parm DWORD | dwCode | io control code to be performed
  1174.     @parm PBYTE | pBufIn | input data to the device
  1175.     @parm DWORD | dwLenIn | number of bytes being passed in
  1176.     @parm PBYTE | pBufOut | output data from the device
  1177.     @parm DWORD | dwLenOut |maximum number of bytes to receive from device
  1178.     @parm PDWORD | pdwActualOut | actual number of bytes received from device
  1179.     @rdesc        Returns TRUE for success, FALSE for failure
  1180.     @remark  The MDD will pass any unrecognized IOCTLs through to this function.
  1181. *************************************************************************/
  1182. static
  1183. BOOL SerIoctl(PVOID pHead, DWORD dwCode,PBYTE pBufIn,DWORD dwLenIn,
  1184.          PBYTE pBufOut,DWORD dwLenOut,PDWORD pdwActualOut)
  1185. {
  1186. PSER_INFO pHWHead = (PSER_INFO)pHead;
  1187.   BOOL RetVal = TRUE;
  1188. DEBUGMSG(1, (TEXT("++SerIoctl 0x%Xrn"), pHead));
  1189. switch (dwCode) 
  1190. {
  1191. // Currently, no defined IOCTLs
  1192. default:
  1193. RetVal = FALSE;
  1194. DEBUGMSG(1, (TEXT(" Unsupported ioctl 0x%Xrn"), dwCode));
  1195. break;            
  1196. }
  1197. DEBUGMSG(1, (TEXT("--SerIoctl 0x%Xrn"), pHead));
  1198. return(RetVal);
  1199. }
  1200. const
  1201. HW_VTBL IoVTbl = {
  1202.     SerInit,
  1203.     SerPostInit,
  1204.     SerDeinit,
  1205.     SerOpen,
  1206.     SerClose,
  1207.     SerGetInterruptType,
  1208.     SerRxIntr,
  1209.     SerTxIntr,
  1210.     SerModemIntr,
  1211.     SerLineIntr,
  1212.     SerGetRxBufferSize,
  1213.     SerPowerOff,
  1214.     SerPowerOn,
  1215.     SerClearDTR,
  1216.     SerSetDTR,
  1217.     SerClearRTS,
  1218.     SerSetRTS,
  1219.     SerEnableIR,
  1220.     SerDisableIR,
  1221.     SerClearBreak,
  1222.     SerSetBreak,
  1223.     SerXmitComChar,
  1224.     SerGetStatus,
  1225.     SerReset,
  1226.     SerGetModemStatus,
  1227.     SerGetCommProperties,
  1228.     SerPurgeComm,
  1229.     SerSetDCB,
  1230.     SerSetCommTimeouts,
  1231.     SerIoctl};
  1232. extern const HW_VTBL SerCardIoVTbl;
  1233. PHWOBJ
  1234. GetSerialObject( DWORD DeviceArrayIndex )
  1235. {
  1236. PHWOBJ pSerObj;
  1237. // We do not have a statically allocated array of HWObjs.  Instead, we 
  1238. // allocate a new HWObj for each instance of the driver.  The MDD will 
  1239. // always call GetSerialObj/HWInit/HWDeinit in that order, so we can do 
  1240. // the alloc here and do any subsequent free in HWDeInit.
  1241.   
  1242. // Allocate space for the HWOBJ.
  1243. pSerObj = (PHWOBJ)LocalAlloc( LPTR, sizeof(HWOBJ) );
  1244. if ( !pSerObj )
  1245. return (NULL);
  1246. // Fill in the HWObj structure that we just allocated.
  1247. pSerObj->BindFlags = THREAD_IN_PDD;      // We take care of our own IST
  1248. pSerObj->dwIntID = SYSINTR_USBD;   // SysIntr 
  1249. pSerObj->pFuncTbl = (HW_VTBL *) &IoVTbl; // Return pointer to functions
  1250. // Now return this structure to the MDD.
  1251. return (pSerObj);
  1252. }