/*- * Copyright (c) 2006-2007 Jean-Sébastien Pédron * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #define PERDU_MINOR 0 #define PERDU_FILENAME "perdu" #define UNLOCK_CODE "Le code est beau !" #define CYCLE_DURATION 25 /* 2 minutes */ #define CYCLE_UPDATE_PERIOD 5 /* 5 seconds */ #define CYCLE_ALARM1 15 /* 15 seconds */ #define CYCLE_ALARM2 10 /* 10 seconds */ #define CYCLE_ALARM3 5 /* 5 seconds */ #define CYCLE_ALARM_UPDATE_PERIOD 1 /* 1 seconds */ #define DEVD_SYS "PERDU" #define DEVD_SUBSYS "ALARM" static d_write_t perdu_write; int cycle_start(void); void cycle_system_failure(void); static void cycle_update(void *args); static void cycle_update_alarm(void *args); void cycle_beep1(void); void cycle_beep2(void); void cycle_beep3(void); static struct cdevsw perdu_cdevsw = { .d_name = "perdu", .d_version = D_VERSION, .d_write = perdu_write }; /* For use with make_dev(9)/destroy_dev(9). */ static struct cdev *perdu_dev; /* For use with callout(9). */ static struct callout perdu_callout; /* Remaining time. */ static int remaining; int cycle_start() { remaining = CYCLE_DURATION; return (callout_reset(&perdu_callout, CYCLE_UPDATE_PERIOD * hz, cycle_update, NULL)); } void cycle_system_failure() { panic("SYSTEM FAILURE\n"); } static void cycle_update(void *args) { remaining -= CYCLE_UPDATE_PERIOD; if (remaining <= 0) { cycle_system_failure(); return; } else if (remaining <= CYCLE_ALARM1) { cycle_beep1(); callout_reset(&perdu_callout, CYCLE_ALARM_UPDATE_PERIOD * hz, cycle_update_alarm, NULL); } else { callout_reset(&perdu_callout, CYCLE_UPDATE_PERIOD * hz, cycle_update, NULL); } } static void cycle_update_alarm(void *args) { remaining -= CYCLE_ALARM_UPDATE_PERIOD; if (remaining <= 0) { cycle_system_failure(); return; } else if (remaining <= CYCLE_ALARM3) { cycle_beep3(); } else if (remaining <= CYCLE_ALARM2) { cycle_beep2(); } else { cycle_beep1(); } callout_reset(&perdu_callout, CYCLE_ALARM_UPDATE_PERIOD * hz, cycle_update_alarm, NULL); } void cycle_beep1() { if (remaining % 2 == 0) { devctl_notify(DEVD_SYS, DEVD_SUBSYS, "1", NULL); } } void cycle_beep2() { if (remaining % 2 == 0) { devctl_notify(DEVD_SYS, DEVD_SUBSYS, "2", NULL); } } void cycle_beep3() { devctl_notify(DEVD_SYS, DEVD_SUBSYS, "3", NULL); } static int perdu_write(struct cdev *dev, struct uio *uio, int flag) { int error; size_t len, pos, data_available; char *buf; len = 0; error = 0; buf = malloc(PAGE_SIZE, M_TEMP, M_WAITOK | M_ZERO); pos = 0; while (uio->uio_resid > 0) { data_available = PAGE_SIZE - pos; if (data_available > 0) { len = MIN(uio->uio_resid, PAGE_SIZE); error = uiomove(buf, len, uio); if (error) goto OUT; pos += len; } else break; } if (!error && remaining <= CYCLE_ALARM1 && (strcmp(buf, UNLOCK_CODE) == 0 || strcmp(buf, UNLOCK_CODE "\n") == 0)) { devctl_notify(DEVD_SYS, DEVD_SUBSYS, "aborted", NULL); cycle_start(); } OUT: free(buf, M_TEMP); return (error); } static int perdu_modevent(module_t mod, int type, void *data) { int error; error = 0; switch (type) { case MOD_LOAD: callout_init(&perdu_callout, 0); perdu_dev = make_dev(&perdu_cdevsw, PERDU_MINOR, UID_ROOT, GID_WHEEL, 0666, PERDU_FILENAME); cycle_start(); break; case MOD_UNLOAD: callout_stop(&perdu_callout); destroy_dev(perdu_dev); break; case MOD_SHUTDOWN: break; default: error = EOPNOTSUPP; break; } return (error); } DEV_MODULE(perdu, perdu_modevent, NULL); MODULE_VERSION(perdu, 1);