Release 1.9.16.
[wine.git] / dlls / hidclass.sys / buffer.c
blob23636e0eed56125cc8fbddb86185b4d07e154a28
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 BASE_BUFFER_SIZE 32
30 #define MIN_BUFFER_SIZE 2
31 #define MAX_BUFFER_SIZE 512
33 struct ReportRingBuffer
35 UINT start, end, size;
37 int *pointers;
38 UINT pointer_alloc;
39 UINT buffer_size;
41 CRITICAL_SECTION lock;
43 BYTE *buffer;
46 struct ReportRingBuffer* RingBuffer_Create(UINT buffer_size)
48 struct ReportRingBuffer *ring;
49 TRACE("Create Ring Buffer with buffer size %i\n",buffer_size);
50 ring = HeapAlloc(GetProcessHeap(), 0, sizeof(*ring));
51 if (!ring)
52 return NULL;
53 ring->start = ring->end = 0;
54 ring->size = BASE_BUFFER_SIZE;
55 ring->buffer_size = buffer_size;
56 ring->pointer_alloc = 2;
57 ring->pointers = HeapAlloc(GetProcessHeap(), 0, sizeof(int) * ring->pointer_alloc);
58 if (!ring->pointers)
60 HeapFree(GetProcessHeap(), 0, ring);
61 return NULL;
63 memset(ring->pointers, 0xff, sizeof(int) * ring->pointer_alloc);
64 ring->buffer = HeapAlloc(GetProcessHeap(), 0, buffer_size * ring->size);
65 if (!ring->buffer)
67 HeapFree(GetProcessHeap(), 0, ring->pointers);
68 HeapFree(GetProcessHeap(), 0, ring);
69 return NULL;
71 InitializeCriticalSection(&ring->lock);
72 ring->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RingBuffer.lock");
73 return ring;
76 void RingBuffer_Destroy(struct ReportRingBuffer *ring)
78 HeapFree(GetProcessHeap(), 0, ring->buffer);
79 HeapFree(GetProcessHeap(), 0, ring->pointers);
80 ring->lock.DebugInfo->Spare[0] = 0;
81 DeleteCriticalSection(&ring->lock);
82 HeapFree(GetProcessHeap(), 0, ring);
85 UINT RingBuffer_GetBufferSize(struct ReportRingBuffer *ring)
87 return ring->buffer_size;
90 UINT RingBuffer_GetSize(struct ReportRingBuffer *ring)
92 return ring->size;
95 NTSTATUS RingBuffer_SetSize(struct ReportRingBuffer *ring, UINT size)
97 BYTE* new_buffer;
98 int i;
100 if (size < MIN_BUFFER_SIZE || size > MAX_BUFFER_SIZE || size == ring->size)
101 return STATUS_INVALID_PARAMETER;
103 EnterCriticalSection(&ring->lock);
104 ring->start = ring->end = 0;
105 for (i = 0; i < ring->pointer_alloc; i++)
107 if (ring->pointers[i] != 0xffffffff)
108 ring->pointers[i] = 0;
110 new_buffer = HeapAlloc(GetProcessHeap(), 0, ring->buffer_size * size);
111 if (!new_buffer)
113 LeaveCriticalSection(&ring->lock);
114 return STATUS_NO_MEMORY;
116 HeapFree(GetProcessHeap(), 0, ring->buffer);
117 ring->buffer = new_buffer;
118 ring->size = size;
119 LeaveCriticalSection(&ring->lock);
120 return STATUS_SUCCESS;
123 void RingBuffer_Read(struct ReportRingBuffer *ring, UINT index, void *output, UINT *size)
125 void *ret = NULL;
127 EnterCriticalSection(&ring->lock);
128 if (index >= ring->pointer_alloc || ring->pointers[index] == 0xffffffff)
130 LeaveCriticalSection(&ring->lock);
131 *size = 0;
132 return;
134 if (ring->pointers[index] == ring->end)
136 LeaveCriticalSection(&ring->lock);
137 *size = 0;
139 else
141 ret = &ring->buffer[ring->pointers[index] * ring->buffer_size];
142 memcpy(output, ret, ring->buffer_size);
143 ring->pointers[index]++;
144 if (ring->pointers[index] == ring->size)
145 ring->pointers[index] = 0;
146 LeaveCriticalSection(&ring->lock);
147 *size = ring->buffer_size;
151 UINT RingBuffer_AddPointer(struct ReportRingBuffer *ring)
153 UINT idx;
154 EnterCriticalSection(&ring->lock);
155 for (idx = 0; idx < ring->pointer_alloc; idx++)
156 if (ring->pointers[idx] == -1)
157 break;
158 if (idx >= ring->pointer_alloc)
160 int count = idx = ring->pointer_alloc;
161 ring->pointer_alloc *= 2;
162 ring->pointers = HeapReAlloc(GetProcessHeap(), 0, ring->pointers, sizeof(int) * ring->pointer_alloc);
163 for( ;count < ring->pointer_alloc; count++)
164 ring->pointers[count] = -1;
166 ring->pointers[idx] = ring->start;
167 LeaveCriticalSection(&ring->lock);
168 return idx;
171 void RingBuffer_RemovePointer(struct ReportRingBuffer *ring, UINT index)
173 EnterCriticalSection(&ring->lock);
174 if (index < ring->pointer_alloc)
175 ring->pointers[index] = 0xffffffff;
176 LeaveCriticalSection(&ring->lock);
179 void RingBuffer_Write(struct ReportRingBuffer *ring, void *data)
181 UINT i;
183 EnterCriticalSection(&ring->lock);
184 memcpy(&ring->buffer[ring->end * ring->buffer_size], data, ring->buffer_size);
185 ring->end++;
186 if (ring->end == ring->size)
187 ring->end = 0;
188 if (ring->start == ring->end)
190 ring->start++;
191 if (ring->start == ring->size)
192 ring->start = 0;
194 for (i = 0; i < ring->pointer_alloc; i++)
195 if (ring->pointers[i] == ring->end)
196 ring->pointers[i] = ring->start;
197 LeaveCriticalSection(&ring->lock);