d3d9: Return D3D_OK from UnlockRect() for not locked textures.
[wine.git] / dlls / hidclass.sys / buffer.c
blob0b29f97b698e28ee2c45d06816fe2521bd8d5f53
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_Read(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 UINT RingBuffer_AddPointer(struct ReportRingBuffer *ring)
160 UINT idx;
161 EnterCriticalSection(&ring->lock);
162 for (idx = 0; idx < ring->pointer_alloc; idx++)
163 if (ring->pointers[idx] == POINTER_UNUSED)
164 break;
165 if (idx >= ring->pointer_alloc)
167 int count = idx = ring->pointer_alloc;
168 ring->pointer_alloc *= 2;
169 ring->pointers = HeapReAlloc(GetProcessHeap(), 0, ring->pointers, sizeof(UINT) * ring->pointer_alloc);
170 for( ;count < ring->pointer_alloc; count++)
171 ring->pointers[count] = POINTER_UNUSED;
173 ring->pointers[idx] = ring->end;
174 LeaveCriticalSection(&ring->lock);
175 return idx;
178 void RingBuffer_RemovePointer(struct ReportRingBuffer *ring, UINT index)
180 EnterCriticalSection(&ring->lock);
181 if (index < ring->pointer_alloc)
182 ring->pointers[index] = POINTER_UNUSED;
183 LeaveCriticalSection(&ring->lock);
186 void RingBuffer_Write(struct ReportRingBuffer *ring, void *data)
188 UINT i;
190 EnterCriticalSection(&ring->lock);
191 memcpy(&ring->buffer[ring->end * ring->buffer_size], data, ring->buffer_size);
192 ring->end++;
193 if (ring->end == ring->size)
194 ring->end = 0;
195 if (ring->start == ring->end)
197 ring->start++;
198 if (ring->start == ring->size)
199 ring->start = 0;
201 for (i = 0; i < ring->pointer_alloc; i++)
202 if (ring->pointers[i] == ring->end)
203 ring->pointers[i] = ring->start;
204 LeaveCriticalSection(&ring->lock);