/* $Id: fpclone.c,v 1.13 2008/05/09 12:12:39 kostik Exp kostik $ */ #include #include #include #include #include #include #include static d_open_t fpclone_open; static d_close_t fpclone_close; static d_read_t fpclone_read; static struct cdevsw fpclone_cdevsw = { .d_open = fpclone_open, .d_close = fpclone_close, .d_read = fpclone_read, .d_name = "fpclone", .d_version = D_VERSION, .d_flags = D_TRACKCLOSE }; MALLOC_DEFINE(M_FPCLONESC, "fpclone memory", "fpclone memory"); struct fpclone_sc { int pos; }; static struct cdev *fpclone_dev; static struct mtx me; static void fpclone_cdevpriv_dtr(void *data) { free(data, M_FPCLONESC); } static int fpclone_open(struct cdev *dev, int oflags, int devtype, d_thread_t *td) { struct fpclone_sc *sc; int error; sc = malloc(sizeof(struct fpclone_sc), M_FPCLONESC, M_WAITOK | M_ZERO); error = devfs_set_cdevpriv(sc, fpclone_cdevpriv_dtr); if (error) fpclone_cdevpriv_dtr(sc); return (error); } static int fpclone_close(struct cdev *dev, int fflag, int devtype, d_thread_t *td) { devfs_clear_cdevpriv(); return (0); } static char rdata[] = "fpclone sample data string\n"; static int fpclone_read(struct cdev *dev, struct uio *uio, int ioflag) { struct fpclone_sc *sc; int rv, amnt, svpos, error; error = devfs_get_cdevpriv((void **)&sc); if (error) return (error); rv = 0; while (uio->uio_resid > 0) { svpos = sc->pos; amnt = MIN(uio->uio_resid, sizeof(rdata) - svpos); rv = uiomove(rdata + svpos, amnt, uio); if (rv != 0) break; mtx_lock(&me); sc->pos += amnt; sc->pos %= sizeof(rdata); mtx_unlock(&me); } return (rv); } static int fpclone_modevent(module_t mod, int what, void *arg) { switch (what) { case MOD_LOAD: mtx_init(&me, "fp_ref", NULL, MTX_DEF); fpclone_dev = make_dev(&fpclone_cdevsw, 0, 0, 0, 0666, "fpclone"); return(0); case MOD_UNLOAD: destroy_dev(fpclone_dev); mtx_destroy(&me); return (0); default: break; } return (0); } moduledata_t fpclone_mdata = { "fpclone", fpclone_modevent, NULL }; DECLARE_MODULE(fpclone, fpclone_mdata, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); MODULE_VERSION(fpclone, 1);