xref: /openbmc/linux/samples/kfifo/bytestream-example.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
1912d0f0bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
25bf2b193SStefani Seibold /*
35bf2b193SStefani Seibold  * Sample kfifo byte stream 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 byte stream fifo.
165bf2b193SStefani Seibold  */
175bf2b193SStefani Seibold 
185bf2b193SStefani Seibold /* fifo size in elements (bytes) */
195bf2b193SStefani Seibold #define FIFO_SIZE	32
205bf2b193SStefani Seibold 
215bf2b193SStefani Seibold /* name of the proc entry */
225bf2b193SStefani Seibold #define	PROC_FIFO	"bytestream-fifo"
235bf2b193SStefani Seibold 
245bf2b193SStefani Seibold /* lock for procfs read access */
25*880732aeSSebastian Andrzej Siewior static DEFINE_MUTEX(read_access);
265bf2b193SStefani Seibold 
275bf2b193SStefani Seibold /* lock for procfs write access */
28*880732aeSSebastian 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 struct kfifo test;
415bf2b193SStefani Seibold #else
425bf2b193SStefani Seibold static DECLARE_KFIFO(test, unsigned char, FIFO_SIZE);
435bf2b193SStefani Seibold #endif
445bf2b193SStefani Seibold 
45a25effa4SAndrea Righi static const unsigned char expected_result[FIFO_SIZE] = {
462aaf2092SAndrea Righi 	 3,  4,  5,  6,  7,  8,  9,  0,
472aaf2092SAndrea Righi 	 1, 20, 21, 22, 23, 24, 25, 26,
482aaf2092SAndrea Righi 	27, 28, 29, 30, 31, 32, 33, 34,
492aaf2092SAndrea Righi 	35, 36, 37, 38, 39, 40, 41, 42,
502aaf2092SAndrea Righi };
512aaf2092SAndrea Righi 
testfunc(void)525bf2b193SStefani Seibold static int __init testfunc(void)
535bf2b193SStefani Seibold {
545bf2b193SStefani Seibold 	unsigned char	buf[6];
552aaf2092SAndrea Righi 	unsigned char	i, j;
565bf2b193SStefani Seibold 	unsigned int	ret;
575bf2b193SStefani Seibold 
585bf2b193SStefani Seibold 	printk(KERN_INFO "byte stream fifo test start\n");
595bf2b193SStefani Seibold 
605bf2b193SStefani Seibold 	/* put string into the fifo */
615bf2b193SStefani Seibold 	kfifo_in(&test, "hello", 5);
625bf2b193SStefani Seibold 
635bf2b193SStefani Seibold 	/* put values into the fifo */
645bf2b193SStefani Seibold 	for (i = 0; i != 10; i++)
65498d319bSStefani Seibold 		kfifo_put(&test, i);
665bf2b193SStefani Seibold 
675bf2b193SStefani Seibold 	/* show the number of used elements */
685bf2b193SStefani Seibold 	printk(KERN_INFO "fifo len: %u\n", kfifo_len(&test));
695bf2b193SStefani Seibold 
705bf2b193SStefani Seibold 	/* get max of 5 bytes from the fifo */
715bf2b193SStefani Seibold 	i = kfifo_out(&test, buf, 5);
725bf2b193SStefani Seibold 	printk(KERN_INFO "buf: %.*s\n", i, buf);
735bf2b193SStefani Seibold 
745bf2b193SStefani Seibold 	/* get max of 2 elements from the fifo */
755bf2b193SStefani Seibold 	ret = kfifo_out(&test, buf, 2);
765bf2b193SStefani Seibold 	printk(KERN_INFO "ret: %d\n", ret);
775bf2b193SStefani Seibold 	/* and put it back to the end of the fifo */
785bf2b193SStefani Seibold 	ret = kfifo_in(&test, buf, ret);
795bf2b193SStefani Seibold 	printk(KERN_INFO "ret: %d\n", ret);
805bf2b193SStefani Seibold 
815ddf8391SAndrea Righi 	/* skip first element of the fifo */
825ddf8391SAndrea Righi 	printk(KERN_INFO "skip 1st element\n");
835ddf8391SAndrea Righi 	kfifo_skip(&test);
845ddf8391SAndrea Righi 
855bf2b193SStefani Seibold 	/* put values into the fifo until is full */
86498d319bSStefani Seibold 	for (i = 20; kfifo_put(&test, i); i++)
875bf2b193SStefani Seibold 		;
885bf2b193SStefani Seibold 
895bf2b193SStefani Seibold 	printk(KERN_INFO "queue len: %u\n", kfifo_len(&test));
905bf2b193SStefani Seibold 
91a25effa4SAndrea Righi 	/* show the first value without removing from the fifo */
92a25effa4SAndrea Righi 	if (kfifo_peek(&test, &i))
93a25effa4SAndrea Righi 		printk(KERN_INFO "%d\n", i);
94a25effa4SAndrea Righi 
952aaf2092SAndrea Righi 	/* check the correctness of all values in the fifo */
962aaf2092SAndrea Righi 	j = 0;
972aaf2092SAndrea Righi 	while (kfifo_get(&test, &i)) {
98a25effa4SAndrea Righi 		printk(KERN_INFO "item = %d\n", i);
992aaf2092SAndrea Righi 		if (i != expected_result[j++]) {
1002aaf2092SAndrea Righi 			printk(KERN_WARNING "value mismatch: test failed\n");
1012aaf2092SAndrea Righi 			return -EIO;
1022aaf2092SAndrea Righi 		}
1032aaf2092SAndrea Righi 	}
1042aaf2092SAndrea Righi 	if (j != ARRAY_SIZE(expected_result)) {
1052aaf2092SAndrea Righi 		printk(KERN_WARNING "size mismatch: test failed\n");
1062aaf2092SAndrea Righi 		return -EIO;
1072aaf2092SAndrea Righi 	}
1082aaf2092SAndrea Righi 	printk(KERN_INFO "test passed\n");
1095bf2b193SStefani Seibold 
1105bf2b193SStefani Seibold 	return 0;
1115bf2b193SStefani Seibold }
1125bf2b193SStefani Seibold 
fifo_write(struct file * file,const char __user * buf,size_t count,loff_t * ppos)1135bf2b193SStefani Seibold static ssize_t fifo_write(struct file *file, const char __user *buf,
1145bf2b193SStefani Seibold 						size_t count, loff_t *ppos)
1155bf2b193SStefani Seibold {
1165bf2b193SStefani Seibold 	int ret;
1175bf2b193SStefani Seibold 	unsigned int copied;
1185bf2b193SStefani Seibold 
119*880732aeSSebastian Andrzej Siewior 	if (mutex_lock_interruptible(&write_access))
1205bf2b193SStefani Seibold 		return -ERESTARTSYS;
1215bf2b193SStefani Seibold 
1225bf2b193SStefani Seibold 	ret = kfifo_from_user(&test, buf, count, &copied);
1235bf2b193SStefani Seibold 
124*880732aeSSebastian Andrzej Siewior 	mutex_unlock(&write_access);
125926ee00eSDan Carpenter 	if (ret)
126926ee00eSDan Carpenter 		return ret;
1275bf2b193SStefani Seibold 
128926ee00eSDan Carpenter 	return copied;
1295bf2b193SStefani Seibold }
1305bf2b193SStefani Seibold 
fifo_read(struct file * file,char __user * buf,size_t count,loff_t * ppos)1315bf2b193SStefani Seibold static ssize_t fifo_read(struct file *file, char __user *buf,
1325bf2b193SStefani Seibold 						size_t count, loff_t *ppos)
1335bf2b193SStefani Seibold {
1345bf2b193SStefani Seibold 	int ret;
1355bf2b193SStefani Seibold 	unsigned int copied;
1365bf2b193SStefani Seibold 
137*880732aeSSebastian Andrzej Siewior 	if (mutex_lock_interruptible(&read_access))
1385bf2b193SStefani Seibold 		return -ERESTARTSYS;
1395bf2b193SStefani Seibold 
1405bf2b193SStefani Seibold 	ret = kfifo_to_user(&test, buf, count, &copied);
1415bf2b193SStefani Seibold 
142*880732aeSSebastian Andrzej Siewior 	mutex_unlock(&read_access);
143926ee00eSDan Carpenter 	if (ret)
144926ee00eSDan Carpenter 		return ret;
1455bf2b193SStefani Seibold 
146926ee00eSDan Carpenter 	return copied;
1475bf2b193SStefani Seibold }
1485bf2b193SStefani Seibold 
14997a32539SAlexey Dobriyan static const struct proc_ops fifo_proc_ops = {
15097a32539SAlexey Dobriyan 	.proc_read	= fifo_read,
15197a32539SAlexey Dobriyan 	.proc_write	= fifo_write,
15297a32539SAlexey Dobriyan 	.proc_lseek	= noop_llseek,
1535bf2b193SStefani Seibold };
1545bf2b193SStefani Seibold 
example_init(void)1555bf2b193SStefani Seibold static int __init example_init(void)
1565bf2b193SStefani Seibold {
1575bf2b193SStefani Seibold #ifdef DYNAMIC
1585bf2b193SStefani Seibold 	int ret;
1595bf2b193SStefani Seibold 
1605bf2b193SStefani Seibold 	ret = kfifo_alloc(&test, FIFO_SIZE, GFP_KERNEL);
1615bf2b193SStefani Seibold 	if (ret) {
1625bf2b193SStefani Seibold 		printk(KERN_ERR "error kfifo_alloc\n");
1635bf2b193SStefani Seibold 		return ret;
1645bf2b193SStefani Seibold 	}
1655bf2b193SStefani Seibold #else
1665bf2b193SStefani Seibold 	INIT_KFIFO(test);
1675bf2b193SStefani Seibold #endif
1682aaf2092SAndrea Righi 	if (testfunc() < 0) {
1692aaf2092SAndrea Righi #ifdef DYNAMIC
1702aaf2092SAndrea Righi 		kfifo_free(&test);
1712aaf2092SAndrea Righi #endif
1722aaf2092SAndrea Righi 		return -EIO;
1732aaf2092SAndrea Righi 	}
1745bf2b193SStefani Seibold 
17597a32539SAlexey Dobriyan 	if (proc_create(PROC_FIFO, 0, NULL, &fifo_proc_ops) == NULL) {
1765bf2b193SStefani Seibold #ifdef DYNAMIC
1775bf2b193SStefani Seibold 		kfifo_free(&test);
1785bf2b193SStefani Seibold #endif
1795bf2b193SStefani Seibold 		return -ENOMEM;
1805bf2b193SStefani Seibold 	}
1815bf2b193SStefani Seibold 	return 0;
1825bf2b193SStefani Seibold }
1835bf2b193SStefani Seibold 
example_exit(void)1845bf2b193SStefani Seibold static void __exit example_exit(void)
1855bf2b193SStefani Seibold {
1865bf2b193SStefani Seibold 	remove_proc_entry(PROC_FIFO, NULL);
1875bf2b193SStefani Seibold #ifdef DYNAMIC
1885bf2b193SStefani Seibold 	kfifo_free(&test);
1895bf2b193SStefani Seibold #endif
1905bf2b193SStefani Seibold }
1915bf2b193SStefani Seibold 
1925bf2b193SStefani Seibold module_init(example_init);
1935bf2b193SStefani Seibold module_exit(example_exit);
1945bf2b193SStefani Seibold MODULE_LICENSE("GPL");
1955bf2b193SStefani Seibold MODULE_AUTHOR("Stefani Seibold <stefani@seibold.net>");
196