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