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