Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

571 lines
13 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. tdi.c
  5. Abstract:
  6. This module contains the code that is very specific to initialization
  7. and unload operations in the irenum driver
  8. Author:
  9. Brian Lieuallen, 7-13-2000
  10. Environment:
  11. Kernel mode
  12. Revision History :
  13. --*/
  14. #include "internal.h"
  15. VOID
  16. RemoveRefereneToConnection(
  17. PTDI_CONNECTION Connection
  18. )
  19. {
  20. LONG Count;
  21. Count=InterlockedDecrement(&Connection->ReferenceCount);
  22. if (Count == 0) {
  23. KeSetEvent(
  24. &Connection->CloseEvent,
  25. IO_NO_INCREMENT,
  26. FALSE
  27. );
  28. }
  29. return;
  30. }
  31. VOID
  32. HandleControlInformation(
  33. PTDI_CONNECTION Connection,
  34. PUCHAR Buffer,
  35. ULONG Length
  36. )
  37. {
  38. PUCHAR Current=Buffer;
  39. while (Current < Buffer+Length) {
  40. UCHAR PI=*Current;
  41. UCHAR PL=*(Current+1);
  42. D_TRACE1(
  43. DbgPrint("IRCOMM: Receive Control, PI=%x, PL=%d, PV= ",PI,PL);
  44. DumpBuffer(Current+2,PL);
  45. DbgPrint("\n");
  46. )
  47. if ((Connection->EventCallBack != NULL)
  48. &&
  49. ((PI == PI_DTESettings) || (PI == PI_DCESettings))) {
  50. UCHAR PV=*(Current+2);
  51. UCHAR NewPV;
  52. ULONG LineDelta=0;
  53. if (PI == PI_DTESettings) {
  54. //
  55. // the other machine is a DTE as well. mundge the control lines
  56. //
  57. PI=PI_DCESettings;
  58. NewPV = PV & PV_DTESetting_Delta_DTR ? PV_DCESetting_Delta_DSR : 0;
  59. NewPV |= PV & PV_DTESetting_Delta_RTS ? PV_DCESetting_Delta_CTS : 0;
  60. NewPV |= PV & PV_DTESetting_DTR_High ? PV_DCESetting_DSR_State : 0;
  61. NewPV |= PV & PV_DTESetting_RTS_High ? PV_DCESetting_CTS_State : 0;
  62. } else {
  63. //
  64. // the other device is a DCE, just report the value straight back
  65. //
  66. NewPV=PV;
  67. }
  68. //
  69. // save the current state of the control line here
  70. //
  71. Connection->Uart.ModemStatus=NewPV & 0xf0;
  72. if (NewPV & PV_DCESetting_Delta_CTS ) {
  73. LineDelta |= SERIAL_EV_CTS;
  74. }
  75. if (NewPV & PV_DCESetting_Delta_DSR ) {
  76. LineDelta |= SERIAL_EV_DSR;
  77. }
  78. if (NewPV & PV_DCESetting_Delta_RI ) {
  79. LineDelta |= SERIAL_EV_RING;
  80. }
  81. if (NewPV & PV_DCESetting_Delta_CD ) {
  82. LineDelta |= SERIAL_EV_RLSD;
  83. }
  84. (*Connection->EventCallBack)(
  85. Connection->EventContext,
  86. LineDelta
  87. );
  88. }
  89. Current+=2+PL;
  90. }
  91. return;
  92. }
  93. NTSTATUS
  94. LinkReceiveHandler(
  95. PVOID Context,
  96. ULONG ReceiveFlags,
  97. IN ULONG BytesIndicated,
  98. IN ULONG BytesAvailable,
  99. OUT ULONG *BytesTaken,
  100. IN PVOID Tsdu,
  101. OUT PIRP *IoRequestPacket
  102. )
  103. {
  104. PTDI_CONNECTION Connection=Context;
  105. PUCHAR Data=Tsdu;
  106. NTSTATUS Status;
  107. ULONG ClientDataUsed;
  108. *IoRequestPacket=NULL;
  109. *BytesTaken=BytesAvailable;
  110. D_TRACE(DbgPrint("IRCOMM: receive event, ind=%d, Avail=%d\n",BytesIndicated,BytesAvailable);)
  111. if (BytesIndicated < 1) {
  112. //
  113. // ircomm frames should at least have the control length byte
  114. //
  115. D_ERROR(DbgPrint("IRCOMM: ClientEventRecieve: less than one byte indicated\n");)
  116. return STATUS_SUCCESS;
  117. }
  118. if ((ULONG)((*Data) + 1) > BytesIndicated) {
  119. //
  120. // The control information is larger than the whole frame
  121. //
  122. D_ERROR(DbgPrint("IRCOMM: ClientEventRecieve: control length more than frame length, %d > %d\n",(ULONG)((*Data) + 1) , BytesIndicated);)
  123. return STATUS_SUCCESS;
  124. }
  125. if ((*Data > 0) && (*Data < 3)) {
  126. //
  127. // There is control data, but it is less than a minimal PI,PL, and a one byte PV
  128. //
  129. D_ERROR(DbgPrint("IRCOMM: ClientEventRecieve: Control data is less than 3 bytes\n");)
  130. return STATUS_SUCCESS;
  131. }
  132. if (Connection->ReceiveCallBack != NULL) {
  133. //
  134. // indicate the packet to the client
  135. //
  136. ULONG ClientDataLength=(BytesIndicated-*Data)-1;
  137. if (ClientDataLength > 0) {
  138. Status=(*Connection->ReceiveCallBack)(
  139. Connection->ReceiveContext,
  140. Data+1+*Data,
  141. ClientDataLength,
  142. &ClientDataUsed
  143. );
  144. if (Status == STATUS_DATA_NOT_ACCEPTED) {
  145. //
  146. // the clients buffer is full, let the tdi driver buffer the data
  147. //
  148. *BytesTaken=0;
  149. //
  150. // return now, before processing any control info so it will only be done once
  151. // when the client request more data
  152. //
  153. return Status;
  154. }
  155. ASSERT(Status == STATUS_SUCCESS);
  156. }
  157. }
  158. //
  159. // process the control data now
  160. //
  161. HandleControlInformation(Connection,Data+1,*Data);
  162. return STATUS_SUCCESS;
  163. }
  164. VOID
  165. LinkStateHandler(
  166. PVOID Context,
  167. BOOLEAN LinkUp,
  168. ULONG MaxSendPdu
  169. )
  170. {
  171. PTDI_CONNECTION Connection=Context;
  172. D_ERROR(DbgPrint("IRCOMM: LinkState %d\n",LinkUp);)
  173. Connection->LinkUp=LinkUp;
  174. if (!LinkUp) {
  175. //
  176. // link down
  177. //
  178. if (Connection->EventCallBack != NULL) {
  179. //
  180. // indicate that CTS, DSR, and CD are now low.
  181. //
  182. ULONG LineDelta;
  183. Connection->Uart.ModemStatus=0;
  184. LineDelta = SERIAL_EV_CTS;
  185. LineDelta |= SERIAL_EV_DSR;
  186. LineDelta |= SERIAL_EV_RING;
  187. LineDelta |= SERIAL_EV_RLSD;
  188. (*Connection->EventCallBack)(
  189. Connection->EventContext,
  190. LineDelta
  191. );
  192. }
  193. } else {
  194. UCHAR ControlBuffer[4];
  195. CONNECTION_HANDLE ConnectionHandle;
  196. Connection->MaxSendPdu=MaxSendPdu;
  197. ConnectionHandle=GetCurrentConnection(Connection->LinkHandle);
  198. if (ConnectionHandle != NULL) {
  199. ControlBuffer[0]=PV_ServiceType_9_Wire;
  200. SendSynchronousControlInfo(
  201. ConnectionHandle,
  202. PI_ServiceType,
  203. 1,
  204. ControlBuffer
  205. );
  206. //
  207. // request the current settings
  208. //
  209. SendSynchronousControlInfo(
  210. ConnectionHandle,
  211. PI_Poll,
  212. 0,
  213. NULL
  214. );
  215. ControlBuffer[0]=(UCHAR)( Connection->Uart.BaudRate >> 24);
  216. ControlBuffer[1]=(UCHAR)( Connection->Uart.BaudRate >> 16);
  217. ControlBuffer[2]=(UCHAR)( Connection->Uart.BaudRate >> 8);
  218. ControlBuffer[3]=(UCHAR)( Connection->Uart.BaudRate >> 0);
  219. SendSynchronousControlInfo(
  220. ConnectionHandle,
  221. PI_DataRate,
  222. 4,
  223. ControlBuffer
  224. );
  225. ControlBuffer[0] = Connection->Uart.RtsState ? PV_DTESetting_RTS_High : 0;
  226. ControlBuffer[0] |= Connection->Uart.DtrState ? PV_DTESetting_DTR_High : 0;
  227. SendSynchronousControlInfo(
  228. ConnectionHandle,
  229. PI_DTESettings,
  230. 1,
  231. ControlBuffer
  232. );
  233. ReleaseConnection(ConnectionHandle);
  234. }
  235. ProcessSendAtPassive(Connection);
  236. }
  237. return;
  238. }
  239. NTSTATUS
  240. IrdaConnect(
  241. TDI_OBJECT_HANDLE TdiObjectHandle,
  242. ULONG DeviceAddress,
  243. CHAR *ServiceName,
  244. BOOLEAN OutGoingConnection,
  245. IRDA_HANDLE *ConnectionHandle,
  246. RECEIVE_CALLBACK ReceiveCallBack,
  247. EVENT_CALLBACK EventCallBack,
  248. PVOID CallbackContext
  249. )
  250. {
  251. NTSTATUS Status=STATUS_SUCCESS;
  252. PIRP pIrp;
  253. KEVENT Event;
  254. IO_STATUS_BLOCK Iosb;
  255. TDI_CONNECTION_INFORMATION ConnInfo;
  256. UCHAR AddrBuf[sizeof(TRANSPORT_ADDRESS) +
  257. sizeof(TDI_ADDRESS_IRDA)];
  258. PTRANSPORT_ADDRESS pTranAddr = (PTRANSPORT_ADDRESS) AddrBuf;
  259. PTDI_ADDRESS_IRDA pIrdaAddr = (PTDI_ADDRESS_IRDA) pTranAddr->Address[0].Address;
  260. PTDI_CONNECTION Connection=NULL;
  261. *ConnectionHandle=NULL;
  262. Connection=ALLOCATE_NONPAGED_POOL(sizeof(*Connection));
  263. if (Connection == NULL) {
  264. return STATUS_INSUFFICIENT_RESOURCES;
  265. }
  266. RtlZeroMemory(Connection,sizeof(*Connection));
  267. KeInitializeSpinLock(&Connection->Send.ControlLock);
  268. ExInitializeWorkItem(
  269. &Connection->Send.WorkItem,
  270. SendWorkItemRountine,
  271. Connection
  272. );
  273. Connection->ReceiveContext=CallbackContext;
  274. Connection->ReceiveCallBack=ReceiveCallBack;
  275. Connection->EventContext=CallbackContext;
  276. Connection->EventCallBack=EventCallBack;
  277. Connection->Uart.BaudRate=115200;
  278. Connection->Uart.DtrState=1;
  279. Connection->Uart.RtsState=1;
  280. Connection->Uart.LineControl.WordLength=8;
  281. Connection->Uart.LineControl.StopBits=NO_PARITY;
  282. Connection->Uart.LineControl.Parity=STOP_BIT_1;
  283. Connection->Uart.ModemStatus=0;
  284. Connection->ReferenceCount=1;
  285. KeInitializeEvent(
  286. &Connection->CloseEvent,
  287. NotificationEvent,
  288. FALSE
  289. );
  290. *ConnectionHandle=Connection;
  291. Status=CreateTdiLink(
  292. TdiObjectHandle,
  293. DeviceAddress,
  294. ServiceName,
  295. OutGoingConnection, //outgoing
  296. &Connection->LinkHandle,
  297. Connection,
  298. LinkReceiveHandler,
  299. LinkStateHandler,
  300. 7,
  301. 3,
  302. 3
  303. );
  304. if (!NT_SUCCESS(Status)) {
  305. *ConnectionHandle=NULL;
  306. goto CleanUp;
  307. }
  308. return Status;
  309. CleanUp:
  310. FreeConnection(Connection);
  311. return Status;
  312. }
  313. VOID
  314. FreeConnection(
  315. IRDA_HANDLE Handle
  316. )
  317. {
  318. PTDI_CONNECTION Connection=Handle;
  319. RemoveRefereneToConnection(
  320. Connection
  321. );
  322. //
  323. // wait for recount to goto zero
  324. //
  325. KeWaitForSingleObject(
  326. &Connection->CloseEvent,
  327. Executive,
  328. KernelMode,
  329. FALSE,
  330. NULL
  331. );
  332. if (Connection->LinkHandle != NULL) {
  333. CloseTdiLink(Connection->LinkHandle);
  334. }
  335. FREE_POOL(Connection);
  336. return;
  337. }
  338. NTSTATUS
  339. ReceiveCompletion(
  340. PDEVICE_OBJECT DeviceObject,
  341. PIRP BufferIrp,
  342. PVOID Context
  343. )
  344. {
  345. PIRCOMM_BUFFER Buffer=Context;
  346. PTDI_CONNECTION Connection=Buffer->Context;
  347. D_ERROR(DbgPrint("IRCOMM: receive restart complete\n");)
  348. Buffer->FreeBuffer(Buffer);
  349. return STATUS_MORE_PROCESSING_REQUIRED;
  350. }
  351. NTSTATUS
  352. IndicateReceiveBufferSpaceAvailible(
  353. IRDA_HANDLE Handle
  354. )
  355. {
  356. PTDI_CONNECTION Connection=Handle;
  357. CONNECTION_HANDLE ConnectionHandle;
  358. //
  359. // we will send a receive irp with a zero length to irda,
  360. // this will get it to start indicating packets again
  361. //
  362. ConnectionHandle=GetCurrentConnection(Connection->LinkHandle);
  363. if (ConnectionHandle != NULL) {
  364. //
  365. // we have a good connection
  366. //
  367. PFILE_OBJECT FileObject;
  368. PIRCOMM_BUFFER Buffer;
  369. FileObject=ConnectionGetFileObject(ConnectionHandle);
  370. Buffer=ConnectionGetBuffer(ConnectionHandle,BUFFER_TYPE_RECEIVE);
  371. if (Buffer != NULL) {
  372. PDEVICE_OBJECT IrdaDeviceObject=IoGetRelatedDeviceObject(FileObject);
  373. ULONG Length=0;
  374. IoReuseIrp(Buffer->Irp,STATUS_SUCCESS);
  375. Buffer->Irp->Tail.Overlay.OriginalFileObject = FileObject;
  376. Buffer->Context=Connection;
  377. TdiBuildReceive(
  378. Buffer->Irp,
  379. IrdaDeviceObject,
  380. FileObject,
  381. ReceiveCompletion,
  382. Buffer,
  383. Buffer->Mdl,
  384. 0, // send flags
  385. Length
  386. );
  387. IoCallDriver(IrdaDeviceObject, Buffer->Irp);
  388. } else {
  389. //
  390. // we could not get a buffer, We preallocate 3 of these so this should not happen
  391. // If there are not any availibe, then they should be in use telling irda we want
  392. // packets as well
  393. //
  394. ASSERT(0);
  395. }
  396. ConnectionReleaseFileObject(ConnectionHandle,FileObject);
  397. ReleaseConnection(ConnectionHandle);
  398. }
  399. return STATUS_SUCCESS;
  400. }