source: mainline/uspace/drv/char/i8042/buffer.h@ c657bd7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c657bd7 was c657bd7, checked in by Jiri Svoboda <jiri@…>, 8 years ago

Less is sometimes more. Need chardev_read to be able to return less bytes than requested if less is available. Otherwise cannot read variable-sized packets except yte-by-byte.

  • Property mode set to 100644
File size: 4.7 KB
Line 
1/*
2 * Copyright (c) 2011 Jan Vesely
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/**
30 * @addtogroup kbd
31 * @{
32 */
33
34/** @file
35 * @brief Cyclic buffer structure.
36 */
37
38#ifndef BUFFER_H_
39#define BUFFER_H_
40
41#include <assert.h>
42#include <fibril_synch.h>
43
44/** Cyclic buffer that blocks on full/empty.
45 *
46 * read_head == write_head means that the buffer is empty.
47 * write_head + 1 == read_head means that the buffer is full.
48 * Attempt to insert byte into the full buffer will block until it can succeed.
49 * Attempt to read from empty buffer will block until it can succeed.
50 *
51 */
52typedef struct {
53 uint8_t *buffer; /**< Storage space. */
54 uint8_t *buffer_end; /**< End of storage place. */
55 fibril_mutex_t guard; /**< Protects buffer structures. */
56 fibril_condvar_t change; /**< Indicates change (empty/full). */
57 uint8_t *read_head; /**< Place of the next readable element. */
58 uint8_t *write_head; /**< Pointer to the next writable place. */
59} buffer_t;
60
61/** Initialize cyclic buffer using provided memory space.
62 *
63 * @param buffer Cyclic buffer structure to initialize.
64 * @param data Memory space to use.
65 * @param size Size of the memory place.
66 *
67 */
68static inline void buffer_init(buffer_t *buffer, uint8_t *data, size_t size)
69{
70 assert(buffer);
71
72 fibril_mutex_initialize(&buffer->guard);
73 fibril_condvar_initialize(&buffer->change);
74 buffer->buffer = data;
75 buffer->buffer_end = data + size;
76 buffer->read_head = buffer->buffer;
77 buffer->write_head = buffer->buffer;
78 memset(buffer->buffer, 0, size);
79}
80
81/** Write byte to cyclic buffer.
82 *
83 * @param buffer Cyclic buffer to write to.
84 * @param data Data to write.
85 *
86 */
87static inline void buffer_write(buffer_t *buffer, uint8_t data)
88{
89 fibril_mutex_lock(&buffer->guard);
90
91 /* Next position. */
92 uint8_t *new_head = buffer->write_head + 1;
93 if (new_head == buffer->buffer_end)
94 new_head = buffer->buffer;
95
96 /* Buffer full. */
97 while (new_head == buffer->read_head)
98 fibril_condvar_wait(&buffer->change, &buffer->guard);
99
100 /* Write data. */
101 *buffer->write_head = data;
102
103 /* Buffer was empty. */
104 if (buffer->write_head == buffer->read_head)
105 fibril_condvar_broadcast(&buffer->change);
106
107 /* Move head */
108 buffer->write_head = new_head;
109 fibril_mutex_unlock(&buffer->guard);
110}
111
112/** Read byte from cyclic buffer.
113 *
114 * @param buffer Cyclic buffer to read from.
115 * @param rb Place to store byte read
116 * @param wait @c True to wait until byte is available
117 *
118 * @return EOK on success, EAGAIN if @c wait is false and no data is available
119 *
120 */
121static inline int buffer_read(buffer_t *buffer, uint8_t *rb, bool wait)
122{
123 fibril_mutex_lock(&buffer->guard);
124
125 /* Buffer is empty. */
126 while (wait && buffer->write_head == buffer->read_head)
127 fibril_condvar_wait(&buffer->change, &buffer->guard);
128
129 if (buffer->write_head == buffer->read_head) {
130 fibril_mutex_unlock(&buffer->guard);
131 return EAGAIN;
132 }
133
134 /* Next position. */
135 uint8_t *new_head = buffer->read_head + 1;
136 if (new_head == buffer->buffer_end)
137 new_head = buffer->buffer;
138
139 /* Read data. */
140 const uint8_t data = *buffer->read_head;
141
142 /* Buffer was full. */
143 uint8_t *new_write_head = buffer->write_head + 1;
144 if (new_write_head == buffer->buffer_end)
145 new_write_head = buffer->buffer;
146 if (new_write_head == buffer->read_head)
147 fibril_condvar_broadcast(&buffer->change);
148
149 /* Move head */
150 buffer->read_head = new_head;
151
152 fibril_mutex_unlock(&buffer->guard);
153 *rb = data;
154 return EOK;
155}
156
157#endif
158
159/**
160 * @}
161 */
Note: See TracBrowser for help on using the repository browser.