blob: c406f03ee5519f3a97e021f0f7db290699c1d239 [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
Alexey Dobriyan97a32532020-02-03 17:37:17 -0800145static const struct proc_ops fifo_proc_ops = {
146 .proc_read = fifo_read,
147 .proc_write = fifo_write,
148 .proc_lseek = noop_llseek,
Stefani Seibold5bf2b192010-08-10 18:03:39 -0700149};
150
151static int __init example_init(void)
152{
153#ifdef DYNAMIC
154 int ret;
155
156 ret = kfifo_alloc(&test, FIFO_SIZE, GFP_KERNEL);
157 if (ret) {
158 printk(KERN_ERR "error kfifo_alloc\n");
159 return ret;
160 }
161#else
162 INIT_KFIFO(test);
163#endif
Andrea Righi2aaf2092010-08-19 14:13:29 -0700164 if (testfunc() < 0) {
165#ifdef DYNAMIC
166 kfifo_free(&test);
167#endif
168 return -EIO;
169 }
Stefani Seibold5bf2b192010-08-10 18:03:39 -0700170
Alexey Dobriyan97a32532020-02-03 17:37:17 -0800171 if (proc_create(PROC_FIFO, 0, NULL, &fifo_proc_ops) == NULL) {
Stefani Seibold5bf2b192010-08-10 18:03:39 -0700172#ifdef DYNAMIC
173 kfifo_free(&test);
174#endif
175 return -ENOMEM;
176 }
177 return 0;
178}
179
180static void __exit example_exit(void)
181{
182 remove_proc_entry(PROC_FIFO, NULL);
183#ifdef DYNAMIC
184 kfifo_free(&test);
185#endif
186}
187
188module_init(example_init);
189module_exit(example_exit);
190MODULE_LICENSE("GPL");
191MODULE_AUTHOR("Stefani Seibold <stefani@seibold.net>");