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