reg/tests: Test import with non-standard registry file headers.
[wine.git] / dlls / hidclass.sys / buffer.c
blob731f1e02c974cd3ab2cd46cbd51c99d9cd580073
1 /* Implementation of a ring buffer for reports
3 * Copyright 2015 CodeWeavers, Aric Stewart
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 #include "config.h"
21 #include <stdarg.h>
22 #define NONAMELESSUNION
23 #include "hid.h"
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(hid);
29 #define POINTER_UNUSED 0xffffffff
30 #define BASE_BUFFER_SIZE 32
31 #define MIN_BUFFER_SIZE 2
32 #define MAX_BUFFER_SIZE 512
34 struct ReportRingBuffer
36 UINT start, end, size;
38 UINT *pointers;
39 UINT pointer_alloc;
40 UINT buffer_size;
42 CRITICAL_SECTION lock;
44 BYTE *buffer;
47 struct ReportRingBuffer* RingBuffer_Create(UINT buffer_size)
49 struct ReportRingBuffer *ring;
50 int i;
52 TRACE("Create Ring Buffer with buffer size %i\n",buffer_size);
54 ring = HeapAlloc(GetProcessHeap(), 0, sizeof(*ring));
55 if (!ring)
56 return NULL;
57 ring->start = ring->end = 0;
58 ring->size = BASE_BUFFER_SIZE;
59 ring->buffer_size = buffer_size;
60 ring->pointer_alloc = 2;
61 ring->pointers = HeapAlloc(GetProcessHeap(), 0, sizeof(UINT) * ring->pointer_alloc);
62 if (!ring->pointers)
64 HeapFree(GetProcessHeap(), 0, ring);
65 return NULL;
67 for (i = 0; i < ring->pointer_alloc; i++)
68 ring->pointers[i] = POINTER_UNUSED;
69 ring->buffer = HeapAlloc(GetProcessHeap(), 0, buffer_size * ring->size);
70 if (!ring->buffer)
72 HeapFree(GetProcessHeap(), 0, ring->pointers);
73 HeapFree(GetProcessHeap(), 0, ring);
74 return NULL;
76 InitializeCriticalSection(&ring->lock);
77 ring->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RingBuffer.lock");
78 return ring;
81 void RingBuffer_Destroy(struct ReportRingBuffer *ring)
83 HeapFree(GetProcessHeap(), 0, ring->buffer);
84 HeapFree(GetProcessHeap(), 0, ring->pointers);
85 ring->lock.DebugInfo->Spare[0] = 0;
86 DeleteCriticalSection(&ring->lock);
87 HeapFree(GetProcessHeap(), 0, ring);
90 UINT RingBuffer_GetBufferSize(struct ReportRingBuffer *ring)
92 return ring->buffer_size;
95 UINT RingBuffer_GetSize(struct ReportRingBuffer *ring)
97 return ring->size;
100 NTSTATUS RingBuffer_SetSize(struct ReportRingBuffer *ring, UINT size)
102 BYTE* new_buffer;
103 int i;
105 if (size < MIN_BUFFER_SIZE || size > MAX_BUFFER_SIZE)
106 return STATUS_INVALID_PARAMETER;
107 if (size == ring->size)
108 return STATUS_SUCCESS;
110 EnterCriticalSection(&ring->lock);
111 ring->start = ring->end = 0;
112 for (i = 0; i < ring->pointer_alloc; i++)
114 if (ring->pointers[i] != POINTER_UNUSED)
115 ring->pointers[i] = 0;
117 new_buffer = HeapAlloc(GetProcessHeap(), 0, ring->buffer_size * size);
118 if (!new_buffer)
120 LeaveCriticalSection(&ring->lock);
121 return STATUS_NO_MEMORY;
123 HeapFree(GetProcessHeap(), 0, ring->buffer);
124 ring->buffer = new_buffer;
125 ring->size = size;
126 LeaveCriticalSection(&ring->lock);
127 return STATUS_SUCCESS;
130 void RingBuffer_ReadNew(struct ReportRingBuffer *ring, UINT index, void *output, UINT *size)
132 void *ret = NULL;
134 EnterCriticalSection(&ring->lock);
135 if (index >= ring->pointer_alloc || ring->pointers[index] == POINTER_UNUSED)
137 LeaveCriticalSection(&ring->lock);
138 *size = 0;
139 return;
141 if (ring->pointers[index] == ring->end)
143 LeaveCriticalSection(&ring->lock);
144 *size = 0;
146 else
148 ret = &ring->buffer[ring->pointers[index] * ring->buffer_size];
149 memcpy(output, ret, ring->buffer_size);
150 ring->pointers[index]++;
151 if (ring->pointers[index] == ring->size)
152 ring->pointers[index] = 0;
153 LeaveCriticalSection(&ring->lock);
154 *size = ring->buffer_size;
158 void RingBuffer_Read(struct ReportRingBuffer *ring, UINT index, void *output, UINT *size)
160 int pointer;
161 void *ret = NULL;
163 EnterCriticalSection(&ring->lock);
164 if (index >= ring->pointer_alloc || ring->pointers[index] == POINTER_UNUSED
165 || ring->end == ring->start)
167 LeaveCriticalSection(&ring->lock);
168 *size = 0;
169 return;
172 pointer = ring->pointers[index];
174 if (pointer == ring->end)
175 pointer--;
177 if (pointer < 0)
178 pointer = ring->size - 1;
180 ret = &ring->buffer[pointer * ring->buffer_size];
181 memcpy(output, ret, ring->buffer_size);
182 if (pointer == ring->pointers[index])
184 ring->pointers[index]++;
185 if (ring->pointers[index] == ring->size)
186 ring->pointers[index] = 0;
188 LeaveCriticalSection(&ring->lock);
189 *size = ring->buffer_size;
192 UINT RingBuffer_AddPointer(struct ReportRingBuffer *ring)
194 UINT idx;
195 EnterCriticalSection(&ring->lock);
196 for (idx = 0; idx < ring->pointer_alloc; idx++)
197 if (ring->pointers[idx] == POINTER_UNUSED)
198 break;
199 if (idx >= ring->pointer_alloc)
201 int count = idx = ring->pointer_alloc;
202 ring->pointer_alloc *= 2;
203 ring->pointers = HeapReAlloc(GetProcessHeap(), 0, ring->pointers, sizeof(UINT) * ring->pointer_alloc);
204 for( ;count < ring->pointer_alloc; count++)
205 ring->pointers[count] = POINTER_UNUSED;
207 ring->pointers[idx] = ring->end;
208 LeaveCriticalSection(&ring->lock);
209 return idx;
212 void RingBuffer_RemovePointer(struct ReportRingBuffer *ring, UINT index)
214 EnterCriticalSection(&ring->lock);
215 if (index < ring->pointer_alloc)
216 ring->pointers[index] = POINTER_UNUSED;
217 LeaveCriticalSection(&ring->lock);
220 void RingBuffer_Write(struct ReportRingBuffer *ring, void *data)
222 UINT i;
224 EnterCriticalSection(&ring->lock);
225 memcpy(&ring->buffer[ring->end * ring->buffer_size], data, ring->buffer_size);
226 ring->end++;
227 if (ring->end == ring->size)
228 ring->end = 0;
229 if (ring->start == ring->end)
231 ring->start++;
232 if (ring->start == ring->size)
233 ring->start = 0;
235 for (i = 0; i < ring->pointer_alloc; i++)
236 if (ring->pointers[i] == ring->end)
237 ring->pointers[i] = ring->start;
238 LeaveCriticalSection(&ring->lock);