📄 sc2440_usb_ser.c
字号:
/*+
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 2001. Samsung Electronics, co. ltd All rights reserved.
Module Name:
Abstract:
S3C2440 USB function(ACTIVE SYNC) device driver (Wrapper layer)
rev:
2003.3.19 : updated for USB-DMA (purnnamu)
2002.5.7 : Add to s3c2410_code (Seung-han, Lim)
2002.1.22 : First release/no error recovery (kwangyoon LEE, kwangyoon@samsung.com)
Notes:
*/
#include <windows.h>
#include <types.h>
#include <ceddk.h>
#include <memory.h>
#include <notify.h>
#include <serhw.h>
#include "S2440.h"
#include <SC2440_usb_hw.h>
#include <SC2440_usb_ser.h>
#include <nkintr.h>
#include <oalintr.h>
#include <devload.h>
#include <windev.h>
#undef ZONE_INIT
#include <serdbg.h>
#include <celog.h>
#include <drv_glob.h> //:-)
extern VOID SerialEventHandler(PVOID pHead);
extern void msWait(unsigned msVal);
extern volatile USBD_GLOBALS *usbdShMem; //:-)
__inline static VOID
SignalRemoval( PSER_INFO pHWHead )
{
pHWHead->ModemStatus &= ~MS_RLSD_ON;
EvaluateEventFlag(pHWHead->pMddHead, EV_RLSD);
}
static
DWORD WINAPI SerEventThread(PSER_INFO pHWHead)
{
ULONG WaitReturn;
static HWND fgp=NULL, prev_fgp = NULL;
static HWND dialog_hwnd = NULL;
static ULONG firstplug = 0, toretry = 0;
static PROCESS_INFORMATION pi_usbcnect, pi_repllog;
DEBUGMSG(1, (TEXT("++SerEventThread\r\n")));
DEBUGMSG(1, (TEXT("Spinning in dispatch thread %X\n\r"), pHWHead));
while (!pHWHead->pDispatchThread)
Sleep(20);
while (!pHWHead->KillRxThread) {
DEBUGMSG (1, (TEXT("Event %X, Index %d, Int %d\r\n"),
pHWHead->hSerialEvent,
pHWHead->dwDevIndex,
pHWHead->pHWObj->dwIntID ));
// Ugly. We don't get an interrupt when we are unplugged from the
// bus, but we'd like to know when that happens. So we use a timeout
// on our interrupt wait. This effectively allows me to poll the SOF
// status, and if SOFs stop arriving, I'll assume we have been
// disconnected from the bus. Wait is last, allowing us to essentially
// spoof one interrupt right at startup.
// Only poll if we are opened and active. Otherwise no one cares
#ifdef POLL_FOR_DISCONNECT
if (pHWHead->cOpenCount && pHWHead->dConfIdx)
{
// DEBUGMSG(1, (TEXT("waitforsingleobject in up\r\n")));
WaitReturn = WaitForSingleObject(pHWHead->hSerialEvent, SC2440_USB_POLL_RATE);
// DEBUGMSG(1, (TEXT("waitforsingleobject in\r\n")));
}
else
#endif
{
//DEBUGMSG(1, (TEXT("waitforsingleobject out up\r\n")));
WaitReturn = WaitForSingleObject(pHWHead->hSerialEvent, INFINITE);
/*
DEBUGMSG(1, (TEXT("waitforsingleobject out\r\n")));
if (WaitReturn == WAIT_ABANDONED)
{
DEBUGMSG(1, (TEXT("WAIT_ABANDONED\r\n")));
}
if (WaitReturn == WAIT_OBJECT_0)
{
DEBUGMSG(1, (TEXT("WAIT_OBJECT_0\r\n")));
}
if (WaitReturn == WAIT_TIMEOUT)
{
DEBUGMSG(1, (TEXT("WAIT_TIMEOUT\r\n")));
}
if (WaitReturn == WAIT_FAILED)
{
DEBUGMSG(1, (TEXT("WAIT_FAILED\r\n")));
}
*/
}
SerialEventHandler(pHWHead->pMddHead);
InterruptDone(pHWHead->pHWObj->dwIntID);
}
DEBUGMSG (1, (TEXT("--SerEventThread %x exiting\r\n"), pHWHead));
return (0);
}
static
BOOL StartEventThread(PSER_INFO pHWHead)
{
// Initialize the interrupt to be associated with the hSerialEvent
// event. If this call fails, then another process has registered
// for the interrupt, so fail the init and set the hSerialEvent to NULL.
DEBUGMSG(1, (TEXT("Initializing interrupt 0x%X, 0x%X\n\r"),
pHWHead->pHWObj->dwIntID, pHWHead->hSerialEvent));
if (!InterruptInitialize(pHWHead->pHWObj->dwIntID, pHWHead->hSerialEvent, 0, 0))
{
DEBUGMSG(1, (TEXT("Error initializing interrupt\n\r")));
return (FALSE);
}
InterruptDone(pHWHead->pHWObj->dwIntID);
// Now set up the dispatch thread
pHWHead->KillRxThread = 0;
DEBUGMSG(1, (TEXT("Spinning thread%X\n\r"), pHWHead));
pHWHead->pDispatchThread = CreateThread(NULL,0, SerEventThread,
pHWHead, 0,NULL);
if (pHWHead->pDispatchThread == NULL)
{
DEBUGMSG(1, (TEXT("Error creating Event thread (%d)\n\r"), GetLastError()));
return (FALSE);
}
DEBUGMSG (1, (TEXT("Created Event thread %X\r\n"), pHWHead->pDispatchThread));
DEBUGMSG (1, (TEXT("About to set priority\r\n")));
CeSetThreadPriority(pHWHead->pDispatchThread, DEFAULT_THREAD_PRIO);
DEBUGMSG (1, (TEXT("Back from setting priority\r\n")));
return (TRUE);
}
/***************************************************************
@doc OEM
@func VOID | SerSetBaudRate |
* This routine sets the baud rate of the device.
* Not exported to users, only to driver.
*
@rdesc None.
****************************************************************/
static
BOOL SerSetBaudRate( PVOID pHead, // @parm PVOID returned by SerInit
ULONG BaudRate ) // @parm ULONG representing decimal baud rate.
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
DEBUGMSG(1, (TEXT("SerSetBaudRate\r\n")));
// Baudrate is meaningless. Just be agreeable and say we did it.
return (TRUE);
}
/****************************************************************
@doc INTERNAL
@func VOID | SerUSB_InternalMapRegisterAddresses |
This routine maps the ASIC registers.
It's an artifact of this
implementation.
@rdesc None.
****************************************************************/
static
void SerUSBInternalMapRegisterAddresses( PSER_INFO pHWHead )
{
PUCHAR pVMem;
BOOL bMapReturn;
ULONG err = 0;
DEBUGMSG(1, (TEXT("++SerUSBInternalMapRegisterAddresses\r\n")));
// Map CSR registers.
pVMem = (PUCHAR)VirtualAlloc(0, PAGE_SIZE*2, MEM_RESERVE, PAGE_NOACCESS);
if (pVMem)
{
DEBUGMSG(1, (TEXT("VirtualAlloc Succeeded\r\n")));
bMapReturn = VirtualCopy( pVMem,
(LPVOID)pHWHead->dwIOBase,
PAGE_SIZE,
PAGE_READWRITE | PAGE_NOCACHE );
if (!bMapReturn)
{
err = GetLastError();
DEBUGMSG(1, (TEXT("Virtual Copy: Serial SPACE FAILED\r\n")));
}
pVMem = (BYTE *)pVMem;
pHWHead->pUSBCtrlAddr=(volatile struct udcreg *)((BYTE *)pVMem + 0x140); // offset
bMapReturn = VirtualCopy( pVMem+PAGE_SIZE,
(LPVOID)IOP_BASE,
PAGE_SIZE,
PAGE_READWRITE | PAGE_NOCACHE );
if (!bMapReturn)
{
err = GetLastError();
DEBUGMSG(1, (TEXT("Virtual Copy: IOP SPACE FAILED\r\n")));
}
pHWHead->pIrqCtrlAddr=(volatile IOPreg *)(pVMem+PAGE_SIZE);
bMapReturn = VirtualCopy( pVMem+PAGE_SIZE,
(LPVOID)CLKPWR_BASE,
PAGE_SIZE,
PAGE_READWRITE | PAGE_NOCACHE );
if (!bMapReturn)
{
err = GetLastError();
DEBUGMSG(1, (TEXT("Virtual Copy: CLKPWR SPACE FAILED\r\n")));
}
pHWHead->pCLKPWR = (volatile CLKPWRreg *)(pVMem+PAGE_SIZE);
} else {
DEBUGMSG(1, (TEXT("Virtual Alloc: FAILED\r\n")));
}
DEBUGMSG(1, (TEXT("VirtualCopy Succeeded, pVMem:%x\r\n"), pVMem));
DEBUGMSG(1, (TEXT("--SerUSBInternalMapRegisterAddresses\r\n")));
}
static
BOOL SerSetIRBaudRate( PSER_INFO pHWHead, ULONG baud ) // @parm baud rate - ignored
{
DEBUGMSG(1, (TEXT("Serial set IR Baud %d\r\n"), baud));
// We don't support IR
return (FALSE);
}
/*******************************************************************************
Routine:
Ser_GetRegistryData
Description:
Take the registry path provided to COM_Init and use it to find this
requested comm port's DeviceArrayIndex, the IOPort Base Address, and the
Interrupt number.
Arguments:
LPCTSTR regKeyPath the registry path passed in to COM_Init.
Return Value:
-1 if there is an error.
******************************************************************************/
static
BOOL Ser_GetRegistryData(PSER_INFO pHWHead, LPCTSTR regKeyPath)
{
#define GCI_BUFFER_SIZE 256
LONG regError;
HKEY hKey;
TCHAR devKeyPath[GCI_BUFFER_SIZE];
DWORD dwDataSize = GCI_BUFFER_SIZE;
DEBUGMSG(1,
(TEXT("Ser_GetRegistryData Try to open %s\r\n"),regKeyPath));
// We've been handed the name of a key in the registry that was generated
// on the fly by device.exe. We're going to open that key and pull from it
// a value that is the name of this serial port's real key. That key
// will have the DeviceArrayIndex that we're trying to find.
regError = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
regKeyPath,
0,
KEY_ALL_ACCESS,
&hKey);
if (regError != ERROR_SUCCESS)
{
DEBUGMSG(1,(TEXT("Failed to open %s, Error 0x%X\r\n"),regKeyPath,regError));
return (FALSE);
}
regError = RegQueryValueEx( hKey,
DEVLOAD_DEVKEY_VALNAME,
NULL,
NULL,
(LPBYTE)devKeyPath,
&dwDataSize);
// We're done with that registry key, so close it.
RegCloseKey (hKey);
if (regError != ERROR_SUCCESS)
{
DEBUGMSG(1, (TEXT("Failed to find data at %s\\%s, Error 0x%X\r\n"),
regKeyPath, DEVLOAD_DEVKEY_VALNAME, regError));
return (FALSE);
}
DEBUGMSG(1, (TEXT("Try to open %s\r\n"), devKeyPath));
regError = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
devKeyPath,
0,
KEY_ALL_ACCESS,
&hKey);
if (regError != ERROR_SUCCESS)
{
DEBUGMSG(1,(TEXT("Failed to open %s, Error 0x%X\r\n"), devKeyPath, regError));
return (FALSE);
}
// Okay, we're finally ready to try and load our registry data.
dwDataSize = SC2440USB_REG_DEVINDEX_VAL_LEN;
regError = RegQueryValueEx(hKey,
SC2440USB_REG_DEVINDEX_VAL_NAME,
NULL,
NULL,
(LPBYTE)(&pHWHead->dwDevIndex),
&dwDataSize);
if (regError == ERROR_SUCCESS)
{
dwDataSize = SC2440USB_REG_IRQ_VAL_LEN;
regError = RegQueryValueEx( hKey,
SC2440USB_REG_IRQ_VAL_NAME,
NULL,
NULL,
(LPBYTE)(&pHWHead->dwIRQ),
&dwDataSize );
}
if (regError == ERROR_SUCCESS)
{
dwDataSize = SC2440USB_REG_IOBASE_VAL_LEN;
regError = RegQueryValueEx( hKey,
SC2440USB_REG_IOBASE_VAL_NAME,
NULL,
NULL,
(LPBYTE)(&pHWHead->dwIOBase),
&dwDataSize);
}
if (regError == ERROR_SUCCESS)
{
dwDataSize = SC2440USB_REG_IOLEN_VAL_LEN;
regError = RegQueryValueEx( hKey,
SC2440USB_REG_IOLEN_VAL_NAME,
NULL,
NULL,
(LPBYTE)(&pHWHead->dwIOLen),
&dwDataSize);
}
RegCloseKey (hKey);
if (regError != ERROR_SUCCESS)
{
DEBUGMSG(1,(TEXT("Failed to get serial registry values, Error 0x%X\r\n"),
regError));
return (FALSE);
}
DEBUGMSG(1,(TEXT("SerInit - Devindex %d, IRQ %d, IOB %X, IOLen %X \r\n"),
pHWHead->dwDevIndex,
pHWHead->dwIRQ,
pHWHead->dwIOBase,
pHWHead->dwIOLen));
return (TRUE);
}
/*************************************************************************
@doc OEM
@func PVOID | SerInit | Initializes device identified by argument.
* This routine sets information controlled by the user
* such as Line control and baud rate. It can also initialize events and
* interrupts, thereby indirectly managing initializing hardware buffers.
* Exported only to driver, called only once per process.
*
@rdesc The return value is a PVOID to be passed back into the HW
dependent layer when HW functions are called.
************************************************************************/
static
PVOID SerInit( ULONG Identifier, // @parm Device identifier.
PVOID pMddHead, // @parm First argument to mdd callbacks.
PHWOBJ pHWObj ) // @parm Pointer to our own HW OBJ for this device
{
PSER_INFO pHWHead;
PHYSICAL_ADDRESS PhysicalAddress = {0,0};
#ifdef DEBUG
dpCurSettings.ulZoneMask = 0;
#endif
DEBUGMSG (1, (TEXT("++SerInit %X\r\n"), pMddHead ));
// Allocate for our main data structure and one of it's fields.
pHWHead = (PSER_INFO)LocalAlloc( LPTR, sizeof(SER_INFO) );
if ( !pHWHead )
goto ALLOCFAILED;
if (!Ser_GetRegistryData(pHWHead, (LPCTSTR)Identifier))
{
DEBUGMSG (1,(TEXT("SerInit - Unable to read registry data. Failing Init !!! \r\n")));
goto ALLOCFAILED;
}
// Create our interrupt event.
pHWHead->hSerialEvent = CreateEvent(0,FALSE,FALSE,NULL);
// Initialize our critical sections
InitializeCriticalSection(&(pHWHead->TransmitCritSec));
InitializeCriticalSection(&(pHWHead->HwRegCritSec));
SerUSBInternalMapRegisterAddresses(pHWHead);
if(!InitUsbdDriverGlobals()) //:-)
goto ALLOCFAILED;
if(!UsbdAllocateVm()) //:-)
goto ALLOCFAILED;
pHWHead->pMddHead = pMddHead;
pHWHead->cOpenCount = 0;
pHWHead->pHWObj = pHWObj;
pHWHead->wSOFStableCnt = 0;
// Set up our Comm Properties data
pHWHead->CommProp.wPacketLength = 0xffff;
pHWHead->CommProp.wPacketVersion = 0xffff;
pHWHead->CommProp.dwServiceMask = SP_SERIALCOMM;
pHWHead->CommProp.dwReserved1 = 0;
pHWHead->CommProp.dwMaxTxQueue = 64;
pHWHead->CommProp.dwMaxRxQueue = 64;
pHWHead->CommProp.dwMaxBaud = BAUD_115200;
pHWHead->CommProp.dwProvSubType = PST_RS232;
pHWHead->CommProp.dwProvCapabilities = PCF_RLSD |
PCF_SETXCHAR |
PCF_INTTIMEOUTS |
PCF_SPECIALCHARS |
PCF_TOTALTIMEOUTS |
PCF_XONXOFF;
pHWHead->CommProp.dwSettableBaud = BAUD_075 | BAUD_110 | BAUD_150 |
BAUD_300 | BAUD_600 |
BAUD_1200 | BAUD_1800 |
BAUD_2400 | BAUD_4800 |
BAUD_7200 | BAUD_9600 | BAUD_14400 |
BAUD_19200 | BAUD_38400 |
BAUD_56K | BAUD_128K |
BAUD_115200 | BAUD_57600 | BAUD_USER;
pHWHead->CommProp.dwSettableParams = SP_BAUD | SP_RLSD ;
pHWHead->CommProp.wSettableData = DATABITS_8;
pHWHead->CommProp.wSettableStopParity = STOPBITS_10 | STOPBITS_20 |
PARITY_NONE | PARITY_ODD |
PARITY_EVEN | PARITY_SPACE |
PARITY_MARK;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -