Source code of Windows XP (NT5)
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.

558 lines
12 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. ControlBuffer[0]=(UCHAR)( Connection->Uart.BaudRate >> 24);
  207. ControlBuffer[1]=(UCHAR)( Connection->Uart.BaudRate >> 16);
  208. ControlBuffer[2]=(UCHAR)( Connection->Uart.BaudRate >> 8);
  209. ControlBuffer[3]=(UCHAR)( Connection->Uart.BaudRate >> 0);
  210. SendSynchronousControlInfo(
  211. ConnectionHandle,
  212. PI_DataRate,
  213. 4,
  214. ControlBuffer
  215. );
  216. ControlBuffer[0] = Connection->Uart.RtsState ? PV_DTESetting_RTS_High : 0;
  217. ControlBuffer[0] |= Connection->Uart.DtrState ? PV_DTESetting_DTR_High : 0;
  218. SendSynchronousControlInfo(
  219. ConnectionHandle,
  220. PI_DTESettings,
  221. 1,
  222. ControlBuffer
  223. );
  224. ReleaseConnection(ConnectionHandle);
  225. }
  226. ProcessSendAtPassive(Connection);
  227. }
  228. return;
  229. }
  230. NTSTATUS
  231. IrdaConnect(
  232. ULONG DeviceAddress,
  233. CHAR *ServiceName,
  234. BOOLEAN OutGoingConnection,
  235. IRDA_HANDLE *ConnectionHandle,
  236. RECEIVE_CALLBACK ReceiveCallBack,
  237. EVENT_CALLBACK EventCallBack,
  238. PVOID CallbackContext
  239. )
  240. {
  241. NTSTATUS Status=STATUS_SUCCESS;
  242. PIRP pIrp;
  243. KEVENT Event;
  244. IO_STATUS_BLOCK Iosb;
  245. TDI_CONNECTION_INFORMATION ConnInfo;
  246. UCHAR AddrBuf[sizeof(TRANSPORT_ADDRESS) +
  247. sizeof(TDI_ADDRESS_IRDA)];
  248. PTRANSPORT_ADDRESS pTranAddr = (PTRANSPORT_ADDRESS) AddrBuf;
  249. PTDI_ADDRESS_IRDA pIrdaAddr = (PTDI_ADDRESS_IRDA) pTranAddr->Address[0].Address;
  250. PTDI_CONNECTION Connection=NULL;
  251. *ConnectionHandle=NULL;
  252. Connection=ALLOCATE_NONPAGED_POOL(sizeof(*Connection));
  253. if (Connection == NULL) {
  254. return STATUS_INSUFFICIENT_RESOURCES;
  255. }
  256. RtlZeroMemory(Connection,sizeof(*Connection));
  257. KeInitializeSpinLock(&Connection->Send.ControlLock);
  258. ExInitializeWorkItem(
  259. &Connection->Send.WorkItem,
  260. SendWorkItemRountine,
  261. Connection
  262. );
  263. Connection->ReceiveContext=CallbackContext;
  264. Connection->ReceiveCallBack=ReceiveCallBack;
  265. Connection->EventContext=CallbackContext;
  266. Connection->EventCallBack=EventCallBack;
  267. Connection->Uart.BaudRate=115200;
  268. Connection->Uart.DtrState=1;
  269. Connection->Uart.RtsState=1;
  270. Connection->Uart.LineControl.WordLength=8;
  271. Connection->Uart.LineControl.StopBits=NO_PARITY;
  272. Connection->Uart.LineControl.Parity=STOP_BIT_1;
  273. Connection->Uart.ModemStatus=0;
  274. Connection->ReferenceCount=1;
  275. KeInitializeEvent(
  276. &Connection->CloseEvent,
  277. NotificationEvent,
  278. FALSE
  279. );
  280. *ConnectionHandle=Connection;
  281. Status=CreateTdiLink(
  282. DeviceAddress,
  283. ServiceName,
  284. OutGoingConnection, //outgoing
  285. &Connection->LinkHandle,
  286. Connection,
  287. LinkReceiveHandler,
  288. LinkStateHandler,
  289. 7,
  290. 3,
  291. 3
  292. );
  293. if (!NT_SUCCESS(Status)) {
  294. *ConnectionHandle=NULL;
  295. goto CleanUp;
  296. }
  297. return Status;
  298. CleanUp:
  299. FreeConnection(Connection);
  300. return Status;
  301. }
  302. VOID
  303. FreeConnection(
  304. IRDA_HANDLE Handle
  305. )
  306. {
  307. PTDI_CONNECTION Connection=Handle;
  308. RemoveRefereneToConnection(
  309. Connection
  310. );
  311. //
  312. // wait for recount to goto zero
  313. //
  314. KeWaitForSingleObject(
  315. &Connection->CloseEvent,
  316. Executive,
  317. KernelMode,
  318. FALSE,
  319. NULL
  320. );
  321. if (Connection->LinkHandle != NULL) {
  322. CloseTdiLink(Connection->LinkHandle);
  323. }
  324. FREE_POOL(Connection);
  325. return;
  326. }
  327. NTSTATUS
  328. ReceiveCompletion(
  329. PDEVICE_OBJECT DeviceObject,
  330. PIRP BufferIrp,
  331. PVOID Context
  332. )
  333. {
  334. PIRCOMM_BUFFER Buffer=Context;
  335. PTDI_CONNECTION Connection=Buffer->Context;
  336. D_ERROR(DbgPrint("IRCOMM: receive restart complete\n");)
  337. Buffer->FreeBuffer(Buffer);
  338. return STATUS_MORE_PROCESSING_REQUIRED;
  339. }
  340. NTSTATUS
  341. IndicateReceiveBufferSpaceAvailible(
  342. IRDA_HANDLE Handle
  343. )
  344. {
  345. PTDI_CONNECTION Connection=Handle;
  346. CONNECTION_HANDLE ConnectionHandle;
  347. //
  348. // we will send a receive irp with a zero length to irda,
  349. // this will get it to start indicating packets again
  350. //
  351. ConnectionHandle=GetCurrentConnection(Connection->LinkHandle);
  352. if (ConnectionHandle != NULL) {
  353. //
  354. // we have a good connection
  355. //
  356. PFILE_OBJECT FileObject;
  357. PIRCOMM_BUFFER Buffer;
  358. FileObject=ConnectionGetFileObject(ConnectionHandle);
  359. Buffer=ConnectionGetBuffer(ConnectionHandle,BUFFER_TYPE_RECEIVE);
  360. if (Buffer != NULL) {
  361. PDEVICE_OBJECT IrdaDeviceObject=IoGetRelatedDeviceObject(FileObject);
  362. ULONG Length=0;
  363. IoReuseIrp(Buffer->Irp,STATUS_SUCCESS);
  364. Buffer->Irp->Tail.Overlay.OriginalFileObject = FileObject;
  365. Buffer->Context=Connection;
  366. TdiBuildReceive(
  367. Buffer->Irp,
  368. IrdaDeviceObject,
  369. FileObject,
  370. ReceiveCompletion,
  371. Buffer,
  372. Buffer->Mdl,
  373. 0, // send flags
  374. Length
  375. );
  376. IoCallDriver(IrdaDeviceObject, Buffer->Irp);
  377. } else {
  378. //
  379. // we could not get a buffer, We preallocate 3 of these so this should not happen
  380. // If there are not any availibe, then they should be in use telling irda we want
  381. // packets as well
  382. //
  383. ASSERT(0);
  384. }
  385. ConnectionReleaseFileObject(ConnectionHandle,FileObject);
  386. ReleaseConnection(ConnectionHandle);
  387. }
  388. return STATUS_SUCCESS;
  389. }