hidclass.sys: Process pending IRP queue using last read packet.
[wine.git] / dlls / hidclass.sys / buffer.c
blob59c0edf29f9f834980e33a87853fd46aab72481d
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 <stdarg.h>
21 #include <stdlib.h>
22 #include "hid.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(hid);
28 #define POINTER_UNUSED 0xffffffff
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 UINT *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 int i;
51 TRACE("Create Ring Buffer with buffer size %i\n",buffer_size);
53 ring = malloc(sizeof(*ring));
54 if (!ring)
55 return NULL;
56 ring->start = ring->end = 0;
57 ring->size = BASE_BUFFER_SIZE;
58 ring->buffer_size = buffer_size;
59 ring->pointer_alloc = 2;
60 ring->pointers = malloc(sizeof(UINT) * ring->pointer_alloc);
61 if (!ring->pointers)
63 free(ring);
64 return NULL;
66 for (i = 0; i < ring->pointer_alloc; i++)
67 ring->pointers[i] = POINTER_UNUSED;
68 ring->buffer = malloc(buffer_size * ring->size);
69 if (!ring->buffer)
71 free(ring->pointers);
72 free(ring);
73 return NULL;
75 InitializeCriticalSection(&ring->lock);
76 ring->lock.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": RingBuffer.lock");
77 return ring;
80 void RingBuffer_Destroy(struct ReportRingBuffer *ring)
82 free(ring->buffer);
83 free(ring->pointers);
84 ring->lock.DebugInfo->Spare[0] = 0;
85 DeleteCriticalSection(&ring->lock);
86 free(ring);
89 UINT RingBuffer_GetBufferSize(struct ReportRingBuffer *ring)
91 return ring->buffer_size;
94 UINT RingBuffer_GetSize(struct ReportRingBuffer *ring)
96 return ring->size;
99 NTSTATUS RingBuffer_SetSize(struct ReportRingBuffer *ring, UINT size)
101 BYTE* new_buffer;
102 int i;
104 if (size < MIN_BUFFER_SIZE || size > MAX_BUFFER_SIZE)
105 return STATUS_INVALID_PARAMETER;
106 if (size == ring->size)
107 return STATUS_SUCCESS;
109 EnterCriticalSection(&ring->lock);
110 ring->start = ring->end = 0;
111 for (i = 0; i < ring->pointer_alloc; i++)
113 if (ring->pointers[i] != POINTER_UNUSED)
114 ring->pointers[i] = 0;
116 new_buffer = malloc(ring->buffer_size * size);
117 if (!new_buffer)
119 LeaveCriticalSection(&ring->lock);
120 return STATUS_NO_MEMORY;
122 free(ring->buffer);
123 ring->buffer = new_buffer;
124 ring->size = size;
125 LeaveCriticalSection(&ring->lock);
126 return STATUS_SUCCESS;
129 void RingBuffer_ReadNew(struct ReportRingBuffer *ring, UINT index, void *output, UINT *size)
131 void *ret = NULL;
133 EnterCriticalSection(&ring->lock);
134 if (index >= ring->pointer_alloc || ring->pointers[index] == POINTER_UNUSED)
136 LeaveCriticalSection(&ring->lock);
137 *size = 0;
138 return;
140 if (ring->pointers[index] == ring->end)
142 LeaveCriticalSection(&ring->lock);
143 *size = 0;
145 else
147 ret = &ring->buffer[ring->pointers[index] * ring->buffer_size];
148 memcpy(output, ret, ring->buffer_size);
149 ring->pointers[index]++;
150 if (ring->pointers[index] == ring->size)
151 ring->pointers[index] = 0;
152 LeaveCriticalSection(&ring->lock);
153 *size = ring->buffer_size;
157 UINT RingBuffer_AddPointer(struct ReportRingBuffer *ring)
159 UINT idx;
160 EnterCriticalSection(&ring->lock);
161 for (idx = 0; idx < ring->pointer_alloc; idx++)
162 if (ring->pointers[idx] == POINTER_UNUSED)
163 break;
164 if (idx >= ring->pointer_alloc)
166 int count = idx = ring->pointer_alloc;
167 ring->pointer_alloc *= 2;
168 ring->pointers = realloc(ring->pointers, sizeof(UINT) * ring->pointer_alloc);
169 for( ;count < ring->pointer_alloc; count++)
170 ring->pointers[count] = POINTER_UNUSED;
172 ring->pointers[idx] = ring->end;
173 LeaveCriticalSection(&ring->lock);
174 return idx;
177 void RingBuffer_RemovePointer(struct ReportRingBuffer *ring, UINT index)
179 EnterCriticalSection(&ring->lock);
180 if (index < ring->pointer_alloc)
181 ring->pointers[index] = POINTER_UNUSED;
182 LeaveCriticalSection(&ring->lock);
185 void RingBuffer_Write(struct ReportRingBuffer *ring, void *data)
187 UINT i;
189 EnterCriticalSection(&ring->lock);
190 memcpy(&ring->buffer[ring->end * ring->buffer_size], data, ring->buffer_size);
191 ring->end++;
192 if (ring->end == ring->size)
193 ring->end = 0;
194 if (ring->start == ring->end)
196 ring->start++;
197 if (ring->start == ring->size)
198 ring->start = 0;
200 for (i = 0; i < ring->pointer_alloc; i++)
201 if (ring->pointers[i] == ring->end)
202 ring->pointers[i] = ring->start;
203 LeaveCriticalSection(&ring->lock);