blob: 9ca3e4400c98f3a799f0cd112fb3e8ad5fb78833 [file] [log] [blame]
Thomas Gleixner912d0f0b2019-06-04 10:10:58 +02001// SPDX-License-Identifier: GPL-2.0-only
Stefani Seibold5bf2b192010-08-10 18:03:39 -07002/*
3 * Sample kfifo byte stream implementation
4 *
5 * Copyright (C) 2010 Stefani Seibold <stefani@seibold.net>
Stefani Seibold5bf2b192010-08-10 18:03:39 -07006 */
7
8#include <linux/init.h>
9#include <linux/module.h>
10#include <linux/proc_fs.h>
11#include <linux/mutex.h>
12#include <linux/kfifo.h>
13
14/*
15 * This module shows how to create a byte stream fifo.
16 */
17
18/* fifo size in elements (bytes) */
19#define FIFO_SIZE 32
20
21/* name of the proc entry */
22#define PROC_FIFO "bytestream-fifo"
23
24/* lock for procfs read access */
25static DEFINE_MUTEX(read_lock);
26
27/* lock for procfs write access */
28static DEFINE_MUTEX(write_lock);
29
30/*
31 * define DYNAMIC in this example for a dynamically allocated fifo.
32 *
33 * Otherwise the fifo storage will be a part of the fifo structure.
34 */
35#if 0
36#define DYNAMIC
37#endif
38
39#ifdef DYNAMIC
40static struct kfifo test;
41#else
42static DECLARE_KFIFO(test, unsigned char, FIFO_SIZE);
43#endif
44
Andrea Righia25effa2010-08-19 14:13:30 -070045static const unsigned char expected_result[FIFO_SIZE] = {
Andrea Righi2aaf2092010-08-19 14:13:29 -070046 3, 4, 5, 6, 7, 8, 9, 0,
47 1, 20, 21, 22, 23, 24, 25, 26,
48 27, 28, 29, 30, 31, 32, 33, 34,
49 35, 36, 37, 38, 39, 40, 41, 42,
50};
51
Stefani Seibold5bf2b192010-08-10 18:03:39 -070052static int __init testfunc(void)
53{
54 unsigned char buf[6];
Andrea Righi2aaf2092010-08-19 14:13:29 -070055 unsigned char i, j;
Stefani Seibold5bf2b192010-08-10 18:03:39 -070056 unsigned int ret;
57
58 printk(KERN_INFO "byte stream fifo test start\n");
59
60 /* put string into the fifo */
61 kfifo_in(&test, "hello", 5);
62
63 /* put values into the fifo */
64 for (i = 0; i != 10; i++)
Stefani Seibold498d3192013-11-14 14:32:17 -080065 kfifo_put(&test, i);
Stefani Seibold5bf2b192010-08-10 18:03:39 -070066
67 /* show the number of used elements */
68 printk(KERN_INFO "fifo len: %u\n", kfifo_len(&test));
69
70 /* get max of 5 bytes from the fifo */
71 i = kfifo_out(&test, buf, 5);
72 printk(KERN_INFO "buf: %.*s\n", i, buf);
73
74 /* get max of 2 elements from the fifo */
75 ret = kfifo_out(&test, buf, 2);
76 printk(KERN_INFO "ret: %d\n", ret);
77 /* and put it back to the end of the fifo */
78 ret = kfifo_in(&test, buf, ret);
79 printk(KERN_INFO "ret: %d\n", ret);
80
Andrea Righi5ddf8392010-08-19 14:13:28 -070081 /* skip first element of the fifo */
82 printk(KERN_INFO "skip 1st element\n");
83 kfifo_skip(&test);
84
Stefani Seibold5bf2b192010-08-10 18:03:39 -070085 /* put values into the fifo until is full */
Stefani Seibold498d3192013-11-14 14:32:17 -080086 for (i = 20; kfifo_put(&test, i); i++)
Stefani Seibold5bf2b192010-08-10 18:03:39 -070087 ;
88
89 printk(KERN_INFO "queue len: %u\n", kfifo_len(&test));
90
Andrea Righia25effa2010-08-19 14:13:30 -070091 /* show the first value without removing from the fifo */
92 if (kfifo_peek(&test, &i))
93 printk(KERN_INFO "%d\n", i);
94
Andrea Righi2aaf2092010-08-19 14:13:29 -070095 /* check the correctness of all values in the fifo */
96 j = 0;
97 while (kfifo_get(&test, &i)) {
Andrea Righia25effa2010-08-19 14:13:30 -070098 printk(KERN_INFO "item = %d\n", i);
Andrea Righi2aaf2092010-08-19 14:13:29 -070099 if (i != expected_result[j++]) {
100 printk(KERN_WARNING "value mismatch: test failed\n");
101 return -EIO;
102 }
103 }
104 if (j != ARRAY_SIZE(expected_result)) {
105 printk(KERN_WARNING "size mismatch: test failed\n");
106 return -EIO;
107 }
108 printk(KERN_INFO "test passed\n");
Stefani Seibold5bf2b192010-08-10 18:03:39 -0700109
110 return 0;
111}
112
113static ssize_t fifo_write(struct file *file, const char __user *buf,
114 size_t count, loff_t *ppos)
115{
116 int ret;
117 unsigned int copied;
118
119 if (mutex_lock_interruptible(&write_lock))
120 return -ERESTARTSYS;
121
122 ret = kfifo_from_user(&test, buf, count, &copied);
123
124 mutex_unlock(&write_lock);
125
126 return ret ? ret : copied;
127}
128
129static ssize_t fifo_read(struct file *file, char __user *buf,
130 size_t count, loff_t *ppos)
131{
132 int ret;
133 unsigned int copied;
134
135 if (mutex_lock_interruptible(&read_lock))
136 return -ERESTARTSYS;
137
138 ret = kfifo_to_user(&test, buf, count, &copied);
139
140 mutex_unlock(&read_lock);
141
142 return ret ? ret : copied;
143}
144
145static const struct file_operations fifo_fops = {
146 .owner = THIS_MODULE,
147 .read = fifo_read,
148 .write = fifo_write,
Arnd Bergmann6038f372010-08-15 18:52:59 +0200149 .llseek = noop_llseek,
Stefani Seibold5bf2b192010-08-10 18:03:39 -0700150};
151
152static int __init example_init(void)
153{
154#ifdef DYNAMIC
155 int ret;
156
157 ret = kfifo_alloc(&test, FIFO_SIZE, GFP_KERNEL);
158 if (ret) {
159 printk(KERN_ERR "error kfifo_alloc\n");
160 return ret;
161 }
162#else
163 INIT_KFIFO(test);
164#endif
Andrea Righi2aaf2092010-08-19 14:13:29 -0700165 if (testfunc() < 0) {
166#ifdef DYNAMIC
167 kfifo_free(&test);
168#endif
169 return -EIO;
170 }
Stefani Seibold5bf2b192010-08-10 18:03:39 -0700171
172 if (proc_create(PROC_FIFO, 0, NULL, &fifo_fops) == NULL) {
173#ifdef DYNAMIC
174 kfifo_free(&test);
175#endif
176 return -ENOMEM;
177 }
178 return 0;
179}
180
181static void __exit example_exit(void)
182{
183 remove_proc_entry(PROC_FIFO, NULL);
184#ifdef DYNAMIC
185 kfifo_free(&test);
186#endif
187}
188
189module_init(example_init);
190module_exit(example_exit);
191MODULE_LICENSE("GPL");
192MODULE_AUTHOR("Stefani Seibold <stefani@seibold.net>");