LM3643 Initial Commit : Synchronous Boost Dual LED Flash Driver
[windows-iot-driver/drivers.git] / LM3643 / TxnwLedLm3643 / spb.c
1 /*++\r
2 The Microsoft Public License (MS-PL)\r
3 Copyright (c) 2015 Microsoft\r
4 \r
5 This license governs use of the accompanying software. If you use the software, you\r
6 accept this license. If you do not accept the license, do not use the software.\r
7 \r
8 1. Definitions\r
9 The terms "reproduce," "reproduction," "derivative works," and "distribution" have \r
10 the same meaning here as under U.S. copyright law.\r
11 A "contribution" is the original software, or any additions or changes to the software.\r
12 A "contributor" is any person that distributes its contribution under this license.\r
13 "Licensed patents" are a contributor's patent claims that read directly on its contribution.\r
14 \r
15 2. Grant of Rights\r
16 (A) Copyright Grant- Subject to the terms of this license, including the license conditions \r
17 and limitations in section 3, each contributor grants you a non-exclusive, worldwide, \r
18 royalty-free copyright license to reproduce its contribution, prepare derivative works of \r
19 its contribution, and distribute its contribution or any derivative works that you create.\r
20 (B) Patent Grant- Subject to the terms of this license, including the license conditions \r
21 and limitations in section 3, each contributor grants you a non-exclusive, worldwide, \r
22 royalty-free license under its licensed patents to make, have made, use, sell, offer for \r
23 sale, import, and/or otherwise dispose of its contribution in the software or derivative \r
24 works of the contribution in the software.\r
25 \r
26 3. Conditions and Limitations\r
27 (A) No Trademark License- This license does not grant you rights to use any contributors' \r
28 name, logo, or trademarks.\r
29 (B) If you bring a patent claim against any contributor over patents that you claim are \r
30 infringed by the software, your patent license from such contributor to the software ends \r
31 automatically.\r
32 (C) If you distribute any portion of the software, you must retain all copyright, patent, \r
33 trademark, and attribution notices that are present in the software.\r
34 (D) If you distribute any portion of the software in source code form, you may do so only \r
35 under this license by including a complete copy of this license with your distribution. \r
36 If you distribute any portion of the software in compiled or object code form, you may \r
37 only do so under a license that complies with this license.\r
38 (E) The software is licensed "as-is." You bear the risk of using it. The contributors \r
39 give no express warranties, guarantees or conditions. You may have additional consumer \r
40 rights under your local laws which this license cannot change. To the extent permitted \r
41 under your local laws, the contributors exclude the implied warranties of merchantability, \r
42 fitness for a particular purpose and non-infringement.\r
43 Sample code. Dealpoint ID #843729.\r
44 \r
45 Module Name:\r
46 \r
47 spb.c\r
48 \r
49 Abstract:\r
50 \r
51 Contains all I2C-specific functionality\r
52 \r
53 Environment:\r
54 \r
55 Kernel mode\r
56 \r
57 Revision History:\r
58     Modified for LED driver. \r
59 --*/\r
60 #include "driver.h"\r
61 #include "spb.tmh"\r
62 \r
63 #ifdef ALLOC_PRAGMA\r
64 #endif\r
65 \r
66 NTSTATUS\r
67 SpbDoWriteDataSynchronously(\r
68         IN SPB_CONTEXT *SpbContext,\r
69         IN UCHAR Address,\r
70         IN PVOID Data,\r
71         IN ULONG Length\r
72         )\r
73         /*++\r
74 \r
75         Routine Description:\r
76 \r
77         This helper routine abstracts creating and sending an I/O\r
78         request (I2C Write) to the Spb I/O target.\r
79 \r
80         Arguments:\r
81 \r
82         SpbContext - Pointer to the current device context\r
83         Address    - The I2C register address to write to\r
84         Data       - A buffer to receive the data at at the above address\r
85         Length     - The amount of data to be read from the above address\r
86 \r
87         Return Value:\r
88 \r
89         NTSTATUS Status indicating success or failure\r
90 \r
91         --*/\r
92 {\r
93         PUCHAR buffer;\r
94         ULONG length;\r
95         WDFMEMORY memory;\r
96         WDF_MEMORY_DESCRIPTOR memoryDescriptor;\r
97         NTSTATUS status;\r
98 \r
99         //\r
100         // The address pointer and data buffer must be combined\r
101         // into one contiguous buffer representing the write transaction.\r
102         //\r
103         length = Length + 1;\r
104         memory = NULL;\r
105 \r
106         if (length > DEFAULT_SPB_BUFFER_SIZE)\r
107         {\r
108                 status = WdfMemoryCreate(\r
109                         WDF_NO_OBJECT_ATTRIBUTES,\r
110                         NonPagedPool,\r
111                         LED_POOL_TAG,\r
112                         length,\r
113                         &memory,\r
114                         &buffer);\r
115 \r
116                 if (!NT_SUCCESS(status))\r
117                 {\r
118                         TraceEvents(TRACE_LEVEL_ERROR, TRACE_SPB, "Error allocating memory for Spb write - %!STATUS!", status);\r
119                         goto exit;\r
120                 }\r
121 \r
122                 WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(\r
123                         &memoryDescriptor,\r
124                         memory,\r
125                         NULL);\r
126         }\r
127         else\r
128         {\r
129                 buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->WriteMemory, NULL);\r
130 \r
131                 WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(\r
132                         &memoryDescriptor,\r
133                         (PVOID)buffer,\r
134                         length);\r
135         }\r
136 \r
137         //\r
138         // Transaction starts by specifying the address bytes\r
139         //\r
140         RtlCopyMemory(buffer, &Address, sizeof(Address));\r
141 \r
142         //\r
143         // Address is followed by the data payload\r
144         //\r
145         RtlCopyMemory((buffer + sizeof(Address)), Data, length - sizeof(Address));\r
146 \r
147         status = WdfIoTargetSendWriteSynchronously(\r
148                 SpbContext->SpbIoTarget,\r
149                 NULL,\r
150                 &memoryDescriptor,\r
151                 NULL,\r
152                 NULL,\r
153                 NULL);\r
154 \r
155         if (!NT_SUCCESS(status))\r
156         {\r
157                 TraceEvents(TRACE_LEVEL_ERROR, TRACE_SPB,"Error writing to Spb - %!STATUS!",status);\r
158                 goto exit;\r
159         }\r
160 \r
161 exit:\r
162 \r
163         if (NULL != memory)\r
164         {\r
165                 WdfObjectDelete(memory);\r
166         }\r
167 \r
168         return status;\r
169 }\r
170 \r
171 NTSTATUS\r
172 SpbWriteDataSynchronously(\r
173         IN SPB_CONTEXT *SpbContext,\r
174         IN UCHAR Address,\r
175         IN PVOID Data,\r
176         IN ULONG Length\r
177         )\r
178         /*++\r
179 \r
180         Routine Description:\r
181 \r
182         This routine abstracts creating and sending an I/O\r
183         request (I2C Write) to the Spb I/O target and utilizes\r
184         a helper routine to do work inside of locked code.\r
185 \r
186         Arguments:\r
187 \r
188         SpbContext - Pointer to the current device context\r
189         Address    - The I2C register address to write to\r
190         Data       - A buffer to receive the data at at the above address\r
191         Length     - The amount of data to be read from the above address\r
192 \r
193         Return Value:\r
194 \r
195         NTSTATUS Status indicating success or failure\r
196 \r
197         --*/\r
198 {\r
199         NTSTATUS status;\r
200 \r
201         WdfWaitLockAcquire(SpbContext->SpbLock, NULL);\r
202 \r
203         status = SpbDoWriteDataSynchronously(\r
204                 SpbContext,\r
205                 Address,\r
206                 Data,\r
207                 Length);\r
208 \r
209         WdfWaitLockRelease(SpbContext->SpbLock);\r
210 \r
211         return status;\r
212 }\r
213 \r
214 NTSTATUS\r
215 SpbReadDataSynchronously(\r
216         _In_ SPB_CONTEXT *SpbContext,\r
217         _In_ UCHAR Address,\r
218         _In_reads_bytes_(Length) PVOID Data,\r
219         _In_ ULONG Length\r
220         )\r
221         /*++\r
222 \r
223         Routine Description:\r
224 \r
225         This helper routine abstracts creating and sending an I/O\r
226         request (I2C Read) to the Spb I/O target.\r
227 \r
228         Arguments:\r
229 \r
230         SpbContext - Pointer to the current device context\r
231         Address    - The I2C register address to read from\r
232         Data       - A buffer to receive the data at at the above address\r
233         Length     - The amount of data to be read from the above address\r
234 \r
235         Return Value:\r
236 \r
237         NTSTATUS Status indicating success or failure\r
238 \r
239         --*/\r
240 {\r
241         PUCHAR buffer;\r
242         WDFMEMORY memory;\r
243         WDF_MEMORY_DESCRIPTOR memoryDescriptor;\r
244         NTSTATUS status;\r
245         ULONG_PTR bytesRead;\r
246 \r
247         WdfWaitLockAcquire(SpbContext->SpbLock, NULL);\r
248 \r
249         memory = NULL;\r
250         status = STATUS_INVALID_PARAMETER;\r
251         bytesRead = 0;\r
252 \r
253         //\r
254         // Read transactions start by writing an address pointer\r
255         //\r
256         status = SpbDoWriteDataSynchronously(\r
257                 SpbContext,\r
258                 Address,\r
259                 NULL,\r
260                 0);\r
261 \r
262         if (!NT_SUCCESS(status))\r
263         {\r
264                 //TraceEvents(TRACE_LEVEL_ERROR, TRACE_SPB,"Error setting address pointer for Spb read - %!STATUS!",status);\r
265                 goto exit;\r
266         }\r
267 \r
268         if (Length > DEFAULT_SPB_BUFFER_SIZE)\r
269         {\r
270                 status = WdfMemoryCreate(\r
271                         WDF_NO_OBJECT_ATTRIBUTES,\r
272                         NonPagedPool,\r
273                         LED_POOL_TAG,\r
274                         Length,\r
275                         &memory,\r
276                         &buffer);\r
277 \r
278                 if (!NT_SUCCESS(status))\r
279                 {\r
280                         //TraceEvents(TRACE_LEVEL_ERROR, TRACE_SPB,"Error allocating memory for Spb read - %!STATUS!",status);\r
281                         goto exit;\r
282                 }\r
283 \r
284                 WDF_MEMORY_DESCRIPTOR_INIT_HANDLE(\r
285                         &memoryDescriptor,\r
286                         memory,\r
287                         NULL);\r
288         }\r
289         else\r
290         {\r
291                 buffer = (PUCHAR)WdfMemoryGetBuffer(SpbContext->ReadMemory, NULL);\r
292 \r
293                 WDF_MEMORY_DESCRIPTOR_INIT_BUFFER(\r
294                         &memoryDescriptor,\r
295                         (PVOID)buffer,\r
296                         Length);\r
297         }\r
298 \r
299 \r
300         status = WdfIoTargetSendReadSynchronously(\r
301                 SpbContext->SpbIoTarget,\r
302                 NULL,\r
303                 &memoryDescriptor,\r
304                 NULL,\r
305                 NULL,\r
306                 &bytesRead);\r
307 \r
308         if (!NT_SUCCESS(status) ||\r
309                 bytesRead != Length)\r
310         {\r
311                 //TraceEvents(TRACE_LEVEL_ERROR, TRACE_SPB,"Error reading from Spb - %!STATUS!",status);\r
312                 goto exit;\r
313         }\r
314 \r
315         //\r
316         // Copy back to the caller's buffer\r
317         //\r
318         RtlCopyMemory(Data, buffer, Length);\r
319 \r
320 exit:\r
321         if (NULL != memory)\r
322         {\r
323                 WdfObjectDelete(memory);\r
324         }\r
325 \r
326         WdfWaitLockRelease(SpbContext->SpbLock);\r
327 \r
328         return status;\r
329 }\r
330 \r
331 VOID\r
332 SpbTargetDeinitialize(\r
333         IN WDFDEVICE FxDevice,\r
334         IN SPB_CONTEXT *SpbContext\r
335         )\r
336         /*++\r
337 \r
338         Routine Description:\r
339 \r
340         This helper routine is used to free any members added to the SPB_CONTEXT,\r
341         note the SPB I/O target is parented to the device and will be\r
342         closed and free'd when the device is removed.\r
343 \r
344         Arguments:\r
345 \r
346         FxDevice   - Handle to the framework device object\r
347         SpbContext - Pointer to the current device context\r
348 \r
349         Return Value:\r
350 \r
351         NTSTATUS Status indicating success or failure\r
352 \r
353         --*/\r
354 {\r
355         UNREFERENCED_PARAMETER(FxDevice);\r
356         UNREFERENCED_PARAMETER(SpbContext);\r
357 \r
358         //\r
359         // Free any SPB_CONTEXT allocations here\r
360         //\r
361         if (SpbContext->SpbLock != NULL)\r
362         {\r
363                 WdfObjectDelete(SpbContext->SpbLock);\r
364         }\r
365 \r
366         if (SpbContext->ReadMemory != NULL)\r
367         {\r
368                 WdfObjectDelete(SpbContext->ReadMemory);\r
369         }\r
370 \r
371         if (SpbContext->WriteMemory != NULL)\r
372         {\r
373                 WdfObjectDelete(SpbContext->WriteMemory);\r
374         }\r
375 }\r
376 \r
377 NTSTATUS\r
378 SpbTargetInitialize(\r
379         IN WDFDEVICE FxDevice,\r
380         IN SPB_CONTEXT *SpbContext\r
381         )\r
382         /*++\r
383 \r
384         Routine Description:\r
385 \r
386         This helper routine opens the Spb I/O target and\r
387         initializes a request object used for the lifetime\r
388         of communication between this driver and Spb.\r
389 \r
390         Arguments:\r
391 \r
392         FxDevice   - Handle to the framework device object\r
393         SpbContext - Pointer to the current device context\r
394 \r
395         Return Value:\r
396 \r
397         NTSTATUS Status indicating success or failure\r
398 \r
399         --*/\r
400 {\r
401         WDF_OBJECT_ATTRIBUTES objectAttributes;\r
402         WDF_IO_TARGET_OPEN_PARAMS openParams;\r
403         UNICODE_STRING spbDeviceName;\r
404         WCHAR spbDeviceNameBuffer[RESOURCE_HUB_PATH_SIZE];\r
405         NTSTATUS status;\r
406 \r
407         WDF_OBJECT_ATTRIBUTES_INIT(&objectAttributes);\r
408         objectAttributes.ParentObject = FxDevice;\r
409 \r
410         status = WdfIoTargetCreate(\r
411                 FxDevice,\r
412                 &objectAttributes,\r
413                 &SpbContext->SpbIoTarget);\r
414 \r
415         if (!NT_SUCCESS(status))\r
416         {\r
417                 TraceEvents(TRACE_LEVEL_ERROR, TRACE_SPB,"Error creating IoTarget object - %!STATUS!",status);\r
418                 WdfObjectDelete(SpbContext->SpbIoTarget);\r
419                 goto exit;\r
420         }\r
421 \r
422         RtlInitEmptyUnicodeString(\r
423                 &spbDeviceName,\r
424                 spbDeviceNameBuffer,\r
425                 sizeof(spbDeviceNameBuffer));\r
426 \r
427         status = RESOURCE_HUB_CREATE_PATH_FROM_ID(\r
428                 &spbDeviceName,\r
429                 SpbContext->I2cResHubId.LowPart,\r
430                 SpbContext->I2cResHubId.HighPart);\r
431 \r
432         if (!NT_SUCCESS(status))\r
433         {\r
434                 TraceEvents(TRACE_LEVEL_ERROR, TRACE_SPB,"Error creating Spb resource hub path string - %!STATUS!",status);\r
435                 goto exit;\r
436         }\r
437 \r
438         WDF_IO_TARGET_OPEN_PARAMS_INIT_OPEN_BY_NAME(\r
439                 &openParams,\r
440                 &spbDeviceName,\r
441                 (GENERIC_READ | GENERIC_WRITE));\r
442 \r
443         openParams.ShareAccess = 0;\r
444         openParams.CreateDisposition = FILE_OPEN;\r
445         openParams.FileAttributes = FILE_ATTRIBUTE_NORMAL;\r
446 \r
447         status = WdfIoTargetOpen(SpbContext->SpbIoTarget, &openParams);\r
448 \r
449         if (!NT_SUCCESS(status))\r
450         {\r
451                 TraceEvents(TRACE_LEVEL_ERROR, TRACE_SPB,"Error opening Spb target for communication - %!STATUS!",status);\r
452                 goto exit;\r
453         }\r
454 \r
455         //\r
456         // Allocate some fixed-size buffers from NonPagedPool for typical\r
457         // Spb transaction sizes to avoid pool fragmentation in most cases\r
458         //\r
459         status = WdfMemoryCreate(\r
460                 WDF_NO_OBJECT_ATTRIBUTES,\r
461                 NonPagedPool,\r
462                 LED_POOL_TAG,\r
463                 DEFAULT_SPB_BUFFER_SIZE,\r
464                 &SpbContext->WriteMemory,\r
465                 NULL);\r
466 \r
467         if (!NT_SUCCESS(status))\r
468         {\r
469                 TraceEvents(TRACE_LEVEL_ERROR, TRACE_SPB,"Error allocating default memory for Spb write - %!STATUS!",status);\r
470                 goto exit;\r
471         }\r
472 \r
473         status = WdfMemoryCreate(\r
474                 WDF_NO_OBJECT_ATTRIBUTES,\r
475                 NonPagedPool,\r
476                 LED_POOL_TAG,\r
477                 DEFAULT_SPB_BUFFER_SIZE,\r
478                 &SpbContext->ReadMemory,\r
479                 NULL);\r
480 \r
481         if (!NT_SUCCESS(status))\r
482         {\r
483                 TraceEvents(TRACE_LEVEL_ERROR, TRACE_SPB,"Error allocating default memory for Spb read - %!STATUS!",status);\r
484                 goto exit;\r
485         }\r
486 \r
487         //\r
488         // Allocate a waitlock to guard access to the default buffers\r
489         //\r
490         status = WdfWaitLockCreate(\r
491                 WDF_NO_OBJECT_ATTRIBUTES,\r
492                 &SpbContext->SpbLock);\r
493 \r
494         if (!NT_SUCCESS(status))\r
495         {\r
496                 TraceEvents(TRACE_LEVEL_ERROR, TRACE_SPB,"Error creating Spb Waitlock - %!STATUS!",status);\r
497                 goto exit;\r
498         }\r
499 \r
500 exit:\r
501 \r
502         if (!NT_SUCCESS(status))\r
503         {\r
504                 SpbTargetDeinitialize(FxDevice, SpbContext);\r
505         }\r
506 \r
507         return status;\r
508 }\r