xref: /netbsd-src/sys/modules/examples/readhappy/readhappy.c (revision 14e2571904077c981cf5117cb4adbc7baa12af4b)
1 /*	$NetBSD: readhappy.c,v 1.1 2015/05/13 07:07:36 pgoyette Exp $	*/
2 
3 /*-
4  * Copyright (c) 2015 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: readhappy.c,v 1.1 2015/05/13 07:07:36 pgoyette Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/conf.h>
34 #include <sys/device.h>
35 #include <sys/kernel.h>
36 #include <sys/module.h>
37 
38 /*
39  * Create a device /dev/happy from which you can read sequential
40  * happy numbers.
41  *
42  * To use this device you need to do:
43  *     mknod /dev/happy c 210 0
44  *
45  * Commentary:
46  * A happy number is a number defined by the following process: Starting with
47  * any positive integer, replace the number by the sum of the squares of its
48  * digits, and repeat the process until the number equals 1 (where it will
49  * stay), or it loops endlessly in a cycle which does not include 1. Those
50  * numbers for which this process ends in 1 are happy numbers, while those that
51  * do not end in 1 are unhappy numbers (or sad numbers).
52  *
53  * For more information on happy numbers, and the algorithms, see
54  *	http://en.wikipedia.org/wiki/Happy_number
55  *
56  * The happy number generator is here only to have something that the user
57  * can read from our device.  Any other arbitrary data generator could
58  * have been used.  The algorithm is not critical to the implementation
59  * of the module.
60  */
61 
62 
63 #define	HAPPY_NUMBER	1
64 
65 /* If n is not happy then its sequence ends in the cycle:
66  * 4, 16, 37, 58, 89, 145, 42, 20, 4, ... */
67 #define	SAD_NUMBER	4
68 
69 /* Calculate the sum of the squares of the digits of n */
70 static unsigned
dsum(unsigned n)71 dsum(unsigned n)
72 {
73 	unsigned sum, x;
74 	for (sum = 0; n; n /= 10) {
75 		x = n % 10;
76 		sum += x * x;
77 	}
78 	return sum;
79 }
80 
81 static int
check_happy(unsigned n)82 check_happy(unsigned n)
83 {
84 	for (;;) {
85 		unsigned total = dsum(n);
86 
87 		if (total == HAPPY_NUMBER)
88 			return 1;
89 		if (total == SAD_NUMBER)
90 			return 0;
91 
92 		n = total;
93 	}
94 }
95 
96 dev_type_open(happy_open);
97 dev_type_close(happy_close);
98 dev_type_read(happy_read);
99 
100 static struct cdevsw happy_cdevsw = {
101 	.d_open = happy_open,
102 	.d_close = happy_close,
103 	.d_read = happy_read,
104 	.d_write = nowrite,
105 	.d_ioctl = noioctl,
106 	.d_stop = nostop,
107 	.d_tty = notty,
108 	.d_poll = nopoll,
109 	.d_mmap = nommap,
110 	.d_kqfilter = nokqfilter,
111 	.d_discard = nodiscard,
112 	.d_flag = D_OTHER
113 };
114 
115 
116 struct happy_softc {
117 	int		refcnt;
118 	unsigned	last;
119 };
120 
121 static struct happy_softc sc;
122 
123 int
happy_open(dev_t self __unused,int flag __unused,int mode __unused,struct lwp * l __unused)124 happy_open(dev_t self __unused, int flag __unused, int mode __unused,
125            struct lwp *l __unused)
126 {
127 	if (sc.refcnt > 0)
128 		return EBUSY;
129 
130 	sc.last = 0;
131 	++sc.refcnt;
132 
133 	return 0;
134 }
135 
136 int
happy_close(dev_t self __unused,int flag __unused,int mode __unused,struct lwp * l __unused)137 happy_close(dev_t self __unused, int flag __unused, int mode __unused,
138             struct lwp *l __unused)
139 {
140 	--sc.refcnt;
141 
142 	return 0;
143 }
144 
145 int
happy_read(dev_t self __unused,struct uio * uio,int flags __unused)146 happy_read(dev_t self __unused, struct uio *uio, int flags __unused)
147 {
148 	char line[80];
149 
150 	/* Get next happy number */
151 	while (check_happy(++sc.last) == 0)
152 		continue;
153 
154 	/* Print it into line[] with trailing \n */
155 	int len = snprintf(line, sizeof(line), "%u\n", sc.last);
156 
157 	/* Is there room? */
158 	if (uio->uio_resid < len) {
159 		--sc.last; /* Step back */
160 		return EINVAL;
161 	}
162 
163 	/* Send it to User-Space */
164 	int e;
165 	if ((e = uiomove(line, len, uio)))
166 		return e;
167 
168 	return 0;
169 }
170 
171 MODULE(MODULE_CLASS_MISC, happy, NULL);
172 
173 static int
happy_modcmd(modcmd_t cmd,void * arg __unused)174 happy_modcmd(modcmd_t cmd, void *arg __unused)
175 {
176 	/* The major should be verified and changed if needed to avoid
177 	 * conflicts with other devices. */
178 	int cmajor = 210, bmajor = -1;
179 
180 	switch (cmd) {
181 	case MODULE_CMD_INIT:
182 		if (devsw_attach("happy", NULL, &bmajor, &happy_cdevsw,
183 		                 &cmajor))
184 			return ENXIO;
185 		return 0;
186 	case MODULE_CMD_FINI:
187 		if (sc.refcnt > 0)
188 			return EBUSY;
189 
190 		devsw_detach(NULL, &happy_cdevsw);
191 		return 0;
192 	default:
193 		return ENOTTY;
194 	}
195 }
196