1912d0f0bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25bf2b193SStefani Seibold /*
35bf2b193SStefani Seibold * Sample kfifo int type implementation
45bf2b193SStefani Seibold *
55bf2b193SStefani Seibold * Copyright (C) 2010 Stefani Seibold <stefani@seibold.net>
65bf2b193SStefani Seibold */
75bf2b193SStefani Seibold
85bf2b193SStefani Seibold #include <linux/init.h>
95bf2b193SStefani Seibold #include <linux/module.h>
105bf2b193SStefani Seibold #include <linux/proc_fs.h>
115bf2b193SStefani Seibold #include <linux/mutex.h>
125bf2b193SStefani Seibold #include <linux/kfifo.h>
135bf2b193SStefani Seibold
145bf2b193SStefani Seibold /*
155bf2b193SStefani Seibold * This module shows how to create a int type fifo.
165bf2b193SStefani Seibold */
175bf2b193SStefani Seibold
185bf2b193SStefani Seibold /* fifo size in elements (ints) */
195bf2b193SStefani Seibold #define FIFO_SIZE 32
205bf2b193SStefani Seibold
215bf2b193SStefani Seibold /* name of the proc entry */
225bf2b193SStefani Seibold #define PROC_FIFO "int-fifo"
235bf2b193SStefani Seibold
245bf2b193SStefani Seibold /* lock for procfs read access */
25880732aeSSebastian Andrzej Siewior static DEFINE_MUTEX(read_access);
265bf2b193SStefani Seibold
275bf2b193SStefani Seibold /* lock for procfs write access */
28880732aeSSebastian Andrzej Siewior static DEFINE_MUTEX(write_access);
295bf2b193SStefani Seibold
305bf2b193SStefani Seibold /*
315bf2b193SStefani Seibold * define DYNAMIC in this example for a dynamically allocated fifo.
325bf2b193SStefani Seibold *
335bf2b193SStefani Seibold * Otherwise the fifo storage will be a part of the fifo structure.
345bf2b193SStefani Seibold */
355bf2b193SStefani Seibold #if 0
365bf2b193SStefani Seibold #define DYNAMIC
375bf2b193SStefani Seibold #endif
385bf2b193SStefani Seibold
395bf2b193SStefani Seibold #ifdef DYNAMIC
405bf2b193SStefani Seibold static DECLARE_KFIFO_PTR(test, int);
415bf2b193SStefani Seibold #else
425bf2b193SStefani Seibold static DEFINE_KFIFO(test, int, FIFO_SIZE);
435bf2b193SStefani Seibold #endif
445bf2b193SStefani Seibold
45a25effa4SAndrea Righi static const int expected_result[FIFO_SIZE] = {
46a25effa4SAndrea Righi 3, 4, 5, 6, 7, 8, 9, 0,
47a25effa4SAndrea Righi 1, 20, 21, 22, 23, 24, 25, 26,
48a25effa4SAndrea Righi 27, 28, 29, 30, 31, 32, 33, 34,
49a25effa4SAndrea Righi 35, 36, 37, 38, 39, 40, 41, 42,
50a25effa4SAndrea Righi };
51a25effa4SAndrea Righi
testfunc(void)525bf2b193SStefani Seibold static int __init testfunc(void)
535bf2b193SStefani Seibold {
545bf2b193SStefani Seibold int buf[6];
55a25effa4SAndrea Righi int i, j;
565bf2b193SStefani Seibold unsigned int ret;
575bf2b193SStefani Seibold
585bf2b193SStefani Seibold printk(KERN_INFO "int fifo test start\n");
595bf2b193SStefani Seibold
605bf2b193SStefani Seibold /* put values into the fifo */
615bf2b193SStefani Seibold for (i = 0; i != 10; i++)
62498d319bSStefani Seibold kfifo_put(&test, i);
635bf2b193SStefani Seibold
645bf2b193SStefani Seibold /* show the number of used elements */
655bf2b193SStefani Seibold printk(KERN_INFO "fifo len: %u\n", kfifo_len(&test));
665bf2b193SStefani Seibold
675bf2b193SStefani Seibold /* get max of 2 elements from the fifo */
685bf2b193SStefani Seibold ret = kfifo_out(&test, buf, 2);
695bf2b193SStefani Seibold printk(KERN_INFO "ret: %d\n", ret);
705bf2b193SStefani Seibold /* and put it back to the end of the fifo */
715bf2b193SStefani Seibold ret = kfifo_in(&test, buf, ret);
725bf2b193SStefani Seibold printk(KERN_INFO "ret: %d\n", ret);
735bf2b193SStefani Seibold
74a25effa4SAndrea Righi /* skip first element of the fifo */
75a25effa4SAndrea Righi printk(KERN_INFO "skip 1st element\n");
76a25effa4SAndrea Righi kfifo_skip(&test);
77a25effa4SAndrea Righi
78a25effa4SAndrea Righi /* put values into the fifo until is full */
79498d319bSStefani Seibold for (i = 20; kfifo_put(&test, i); i++)
80a25effa4SAndrea Righi ;
815bf2b193SStefani Seibold
825bf2b193SStefani Seibold printk(KERN_INFO "queue len: %u\n", kfifo_len(&test));
835bf2b193SStefani Seibold
845bf2b193SStefani Seibold /* show the first value without removing from the fifo */
855bf2b193SStefani Seibold if (kfifo_peek(&test, &i))
865bf2b193SStefani Seibold printk(KERN_INFO "%d\n", i);
875bf2b193SStefani Seibold
88a25effa4SAndrea Righi /* check the correctness of all values in the fifo */
89a25effa4SAndrea Righi j = 0;
90a25effa4SAndrea Righi while (kfifo_get(&test, &i)) {
91a25effa4SAndrea Righi printk(KERN_INFO "item = %d\n", i);
92a25effa4SAndrea Righi if (i != expected_result[j++]) {
93a25effa4SAndrea Righi printk(KERN_WARNING "value mismatch: test failed\n");
94a25effa4SAndrea Righi return -EIO;
95a25effa4SAndrea Righi }
96a25effa4SAndrea Righi }
97a25effa4SAndrea Righi if (j != ARRAY_SIZE(expected_result)) {
98a25effa4SAndrea Righi printk(KERN_WARNING "size mismatch: test failed\n");
99a25effa4SAndrea Righi return -EIO;
100a25effa4SAndrea Righi }
101a25effa4SAndrea Righi printk(KERN_INFO "test passed\n");
1025bf2b193SStefani Seibold
1035bf2b193SStefani Seibold return 0;
1045bf2b193SStefani Seibold }
1055bf2b193SStefani Seibold
fifo_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)1065bf2b193SStefani Seibold static ssize_t fifo_write(struct file *file, const char __user *buf,
1075bf2b193SStefani Seibold size_t count, loff_t *ppos)
1085bf2b193SStefani Seibold {
1095bf2b193SStefani Seibold int ret;
1105bf2b193SStefani Seibold unsigned int copied;
1115bf2b193SStefani Seibold
112880732aeSSebastian Andrzej Siewior if (mutex_lock_interruptible(&write_access))
1135bf2b193SStefani Seibold return -ERESTARTSYS;
1145bf2b193SStefani Seibold
1155bf2b193SStefani Seibold ret = kfifo_from_user(&test, buf, count, &copied);
1165bf2b193SStefani Seibold
117880732aeSSebastian Andrzej Siewior mutex_unlock(&write_access);
118926ee00eSDan Carpenter if (ret)
119926ee00eSDan Carpenter return ret;
1205bf2b193SStefani Seibold
121926ee00eSDan Carpenter return copied;
1225bf2b193SStefani Seibold }
1235bf2b193SStefani Seibold
fifo_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)1245bf2b193SStefani Seibold static ssize_t fifo_read(struct file *file, char __user *buf,
1255bf2b193SStefani Seibold size_t count, loff_t *ppos)
1265bf2b193SStefani Seibold {
1275bf2b193SStefani Seibold int ret;
1285bf2b193SStefani Seibold unsigned int copied;
1295bf2b193SStefani Seibold
130880732aeSSebastian Andrzej Siewior if (mutex_lock_interruptible(&read_access))
1315bf2b193SStefani Seibold return -ERESTARTSYS;
1325bf2b193SStefani Seibold
1335bf2b193SStefani Seibold ret = kfifo_to_user(&test, buf, count, &copied);
1345bf2b193SStefani Seibold
135880732aeSSebastian Andrzej Siewior mutex_unlock(&read_access);
136926ee00eSDan Carpenter if (ret)
137926ee00eSDan Carpenter return ret;
1385bf2b193SStefani Seibold
139926ee00eSDan Carpenter return copied;
1405bf2b193SStefani Seibold }
1415bf2b193SStefani Seibold
14297a32539SAlexey Dobriyan static const struct proc_ops fifo_proc_ops = {
14397a32539SAlexey Dobriyan .proc_read = fifo_read,
14497a32539SAlexey Dobriyan .proc_write = fifo_write,
14597a32539SAlexey Dobriyan .proc_lseek = noop_llseek,
1465bf2b193SStefani Seibold };
1475bf2b193SStefani Seibold
example_init(void)1485bf2b193SStefani Seibold static int __init example_init(void)
1495bf2b193SStefani Seibold {
1505bf2b193SStefani Seibold #ifdef DYNAMIC
1515bf2b193SStefani Seibold int ret;
1525bf2b193SStefani Seibold
1535bf2b193SStefani Seibold ret = kfifo_alloc(&test, FIFO_SIZE, GFP_KERNEL);
1545bf2b193SStefani Seibold if (ret) {
1555bf2b193SStefani Seibold printk(KERN_ERR "error kfifo_alloc\n");
1565bf2b193SStefani Seibold return ret;
1575bf2b193SStefani Seibold }
1585bf2b193SStefani Seibold #endif
159a25effa4SAndrea Righi if (testfunc() < 0) {
160a25effa4SAndrea Righi #ifdef DYNAMIC
161a25effa4SAndrea Righi kfifo_free(&test);
162a25effa4SAndrea Righi #endif
163a25effa4SAndrea Righi return -EIO;
164a25effa4SAndrea Righi }
1655bf2b193SStefani Seibold
16697a32539SAlexey Dobriyan if (proc_create(PROC_FIFO, 0, NULL, &fifo_proc_ops) == NULL) {
1675bf2b193SStefani Seibold #ifdef DYNAMIC
1685bf2b193SStefani Seibold kfifo_free(&test);
1695bf2b193SStefani Seibold #endif
1705bf2b193SStefani Seibold return -ENOMEM;
1715bf2b193SStefani Seibold }
1725bf2b193SStefani Seibold return 0;
1735bf2b193SStefani Seibold }
1745bf2b193SStefani Seibold
example_exit(void)1755bf2b193SStefani Seibold static void __exit example_exit(void)
1765bf2b193SStefani Seibold {
1775bf2b193SStefani Seibold remove_proc_entry(PROC_FIFO, NULL);
1785bf2b193SStefani Seibold #ifdef DYNAMIC
1795bf2b193SStefani Seibold kfifo_free(&test);
1805bf2b193SStefani Seibold #endif
1815bf2b193SStefani Seibold }
1825bf2b193SStefani Seibold
1835bf2b193SStefani Seibold module_init(example_init);
1845bf2b193SStefani Seibold module_exit(example_exit);
185*9059044bSJeff Johnson MODULE_DESCRIPTION("Sample kfifo int type implementation");
1865bf2b193SStefani Seibold MODULE_LICENSE("GPL");
1875bf2b193SStefani Seibold MODULE_AUTHOR("Stefani Seibold <stefani@seibold.net>");
188