/* * clone_open: - open a clone device node * @inode: the external filesystem inode * @file: the external filesystem file pointer * * clone_open() is only used to open a clone device from a character device node in an external * filesystem. This is never called for direct opens of a specfs device node (for direct opens see * spec_dev_open() in strspecfs.c). The character device number from the inode is used to * determine the shadow special filesystem (internal) inode and chain the open call. * * This is the separation point where we convert the external device number to an internal device * number. The external device number is contained in inode->i_rdev. */ STATIC int clone_open(struct inode *inode, struct file *file) { int err; struct cdevsw *cdev; major_t major; minor_t minor; modID_t modid, instance; #if defined HAVE_KFUNC_TO_KDEV_T minor = MINOR(kdev_t_to_nr(inode->i_rdev)); major = MAJOR(kdev_t_to_nr(inode->i_rdev)); #else minor = MINOR(inode->i_rdev); major = MAJOR(inode->i_rdev); #endif minor = cdev_minor(&clone_cdev, major, minor); major = clone_cdev.d_major; modid = clone_cdev.d_modid; err = -ENXIO; if (!(cdev = sdev_get(minor))) { goto exit; } instance = cdev->d_modid; err = spec_open(file, cdev, makedevice(modid, instance), CLONEOPEN); sdev_put(cdev); exit: return (err); }
/** * cdev_open: - open a character special device node * @inode: the character device inode * @file: the user file pointer * * cdev_open() is only used to open a stream from a character device node in an external * filesystem. This is never called for direct opens of a specfs device node (for direct opens see * spec_dev_open() in strspecfs.c). It is also not used for direct opens of fifos, pipes or * sockets. Those devices provide their own file operations to the main operating system. The * character device number from the inode is used to determine the shadow special file system * (internal) inode and chain the open call. * * This is the separation point where we convert the external device number to an internal device * number. The external device number is contained in inode->i_rdev. * * @inode is the inode in the external filesystem. * * @file->f_op is the external file operations (character device, fifo) and must be replaced with * our file operations. * * @file->f_dentry is the external filesystem dentry for the device node. * @file->f_vfsmnt is the external filesystem vfsmnt for the device node. * @file exists on the file->f_dentry->d_inode->i_sb->s_files list. * * What we should be doing here is get a fresh new dentry. Find our inode from the device number, * add it to the dentry. Set the dentry->d_sb to the specfs super block, set dentry->d_parent = * dget(file->f_dentry->d_parent), but do not add the dentry to the child list on the parent * directory, nor do we hash the dentry. Next we do a dentry open on the on the dentry and a file * pointer swap on return. * * Instead of farting around with dentries and such, just lookup the inode in the specfs replace * the file->f_ops and chain the open with the specfs inode passed to the new open procedure. For * FIFOs we pass the external filesystem inode instead. */ STATIC int cdev_open(struct inode *inode, struct file *file) { int err; struct cdevsw *cdev; struct devnode *cmin; major_t major; minor_t minor; modID_t modid; dev_t dev; int sflag; #if defined HAVE_KFUNC_TO_KDEV_T minor = MINOR(kdev_t_to_nr(inode->i_rdev)); major = MAJOR(kdev_t_to_nr(inode->i_rdev)); #else minor = MINOR(inode->i_rdev); major = MAJOR(inode->i_rdev); #endif if (!(cdev = sdev_get(major))) { return (-ENXIO); } minor = cdev_minor(cdev, major, minor); major = cdev->d_major; modid = cdev->d_modid; dev = makedevice(modid, minor); sflag = DRVOPEN; if (cdev->d_flag & D_CLONE) sflag = CLONEOPEN; else if ((cmin = cmin_get(cdev, minor)) && cmin->n_flag & D_CLONE) sflag = CLONEOPEN; err = spec_open(file, cdev, dev, sflag); sdev_put(cdev); return (err); }
/** * cloneopen: - open a clone special device * @inode: shadow special filesystem inode * @file: shadow special filesystem file pointer * * cloneopen() is called only from within the shadow special filesystem. This can occur by * chaining from the external filesystem (e.g. openining a character device with clone major) or by * direct open of the inode within the mounted shadow special filesystem. Either way, the inode * number has our extended device numbering as a inode number and we chain the call within the * shadow special filesystem. */ static int cloneopen(struct inode *inode, struct file *file) { struct cdevsw *cdev; dev_t dev = inode->i_ino; if (file->private_data) /* Darn. Somebody passed us a FIFO inode. */ return (-EIO); if ((cdev = sdev_get(getminor(dev)))) { int err; dev = makedevice(cdev->d_modid, 0); err = spec_open(file, cdev, dev, CLONEOPEN); sdev_put(cdev); return (err); } return (-ENOENT); }
static int spec_fdelay_create(fdelay_device_t *dev, int bus, int dev_fn) { uint32_t base; dev->priv_io = spec_open(bus, dev_fn); if(!dev->priv_io) { fprintf(stderr,"Can't map the SPEC @ %x:%x\n", bus, dev_fn); return -1; } dev->writel = fd_spec_writel; dev->readl = fd_spec_readl; dev->base_addr = base; //spec_vuart_init(dev->priv_io, 0xe0500); /* for communication with WRCore during DMTD calibration */ return 0; }
int ptyfs_open(void *v) { struct vop_open_args /* { struct vnode *a_vp; int a_mode; kauth_cred_t a_cred; } */ *ap = v; struct vnode *vp = ap->a_vp; struct ptyfsnode *ptyfs = VTOPTYFS(vp); switch (ptyfs->ptyfs_type) { case PTYFSpts: case PTYFSptc: return spec_open(v); case PTYFSroot: return 0; default: return EINVAL; } }
STATIC int nsdev_open(struct inode *inode, struct file *file) { int err; struct cdevsw *cdev; struct dentry *dentry; major_t major; minor_t minor; modID_t modid, instance; dev_t dev; #if defined HAVE_KFUNC_TO_KDEV_T minor = MINOR(kdev_t_to_nr(inode->i_rdev)); major = MAJOR(kdev_t_to_nr(inode->i_rdev)); #else minor = MINOR(inode->i_rdev); major = MAJOR(inode->i_rdev); #endif minor = cdev_minor(&nsdev_cdev, major, minor); major = nsdev_cdev.d_major; modid = nsdev_cdev.d_modid; #ifdef HAVE_KMEMB_STRUCT_FILE_F_VFSMNT dentry = file->f_dentry; #else dentry = file->f_path.dentry; #endif err = -ENXIO; if (!(cdev = cdev_match((char *) dentry->d_name.name))) goto exit; err = -ENXIO; if (cdev == &nsdev_cdev) goto cdev_put_exit; /* would loop */ instance = cdev->d_modid; dev = makedevice(modid, instance); err = spec_open(file, cdev, dev, CLONEOPEN); cdev_put_exit: sdev_put(cdev); exit: return (err); }
/** * nsdevopen: - open the named streams device * @inode: shadow special filesystem inode to open * @file: shadow special filesystem file pointer to open * * This is rather simple. We are going to do a redirected open on the a new device with the major * device number mapped according to name. We do this by nesting another spec_open() inside the * first one with an adjusted device number. It helps that the orginal file pointer is stored with * the args passed as private_data attached to the current file pointer. We use this to find the * original file pointer and dentry and get the name of the opened file. * * If we don't find a reasonable match and kmod is equipped, we try to load the module with * 'streams-' prefixed to the name and run through the list again. We could also generate the * request from the path to the original dentry. */ static int nsdevopen(struct inode *inode, struct file *file) { struct cdevsw *cdev; struct dentry *dentry; int err; #ifdef HAVE_KMEMB_STRUCT_FILE_F_VFSMNT dentry = file->f_dentry; #else dentry = file->f_path.dentry; #endif if ((cdev = cdev_match((char *) dentry->d_name.name))) { major_t major = cdev->d_modid; minor_t minor = getminor(inode->i_ino); dev_t dev = makedevice(major, minor); int sflag = (file->f_flags & O_CLONE) ? CLONEOPEN : DRVOPEN; err = spec_open(file, cdev, dev, sflag); sdev_put(cdev); } else err = -ENOENT; return (err); }
/* based on minimal daemon code from the daemon-HOWTO */ int main(void) { /* Our process ID and Session ID */ pid_t pid, sid; /* Fork off the parent process */ pid = fork(); if (pid < 0) { exit(EXIT_FAILURE); } /* If we got a good PID, then we can exit the parent process. */ if (pid > 0) { exit(EXIT_SUCCESS); } /* Change the file mode mask */ umask(0); /* Create a new SID for the child process */ sid = setsid(); if (sid < 0) { //syslog(LOG_ERR,"setsid() error. EXIT."); exit(EXIT_FAILURE); } /* Change the current working directory */ if ((chdir("/")) < 0) { /* Log the failure */ //syslog(LOG_ERR,"chdir() error. EXIT."); exit(EXIT_FAILURE); } /* Close out the standard file descriptors */ close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); /* Daemon-specific initialization goes here */ /* use syslog */ setlogmask (LOG_UPTO (LOG_NOTICE)); openlog ("spec_ptp2ntpd", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); syslog (LOG_NOTICE, "Program started by User %d", getuid()); // Attach to SPEC shared memory int bar = BASE_BAR0; int bus = -1, dev_fn = -1; void *card; void *map_base; card = spec_open(bus, dev_fn); if(!card) { syslog(LOG_ERR, "Can't detect a SPEC card under the given " "adress. Make sure a SPEC card is present in your PC, " "the driver is loaded and you run the program as root. EXIT.\n"); exit(1); } syslog(LOG_NOTICE,"Found SPEC at %x \n",(uint)card); map_base = spec_get_base(card, bar); if(!map_base || map_base == (void *) -1) { syslog(LOG_ERR,"mmap(/dev/mem): %s. EXIT.\n", strerror(errno)); syslog(LOG_ERR, "map_base = %x \n",(uint)map_base); exit(1); } syslog(LOG_NOTICE,"map_base = %u \n",(uint)map_base); syslog (LOG_NOTICE, "Attached to SPEC SHM at %x", (uint)map_base); // attach to NTP shared memory T = getShmTime(0); if (T==0) { /* error */ syslog(LOG_ERR,"getShmTime() error"); syslog(LOG_ERR,"EXITING."); exit(EXIT_FAILURE); } else { syslog (LOG_NOTICE, "Attached to NTP SHM at %x", (uint)T); } // initialize T->mode=1; // does it matter? set here or by NTP? T->leap=0; // ? T->precision=-10; //? T->nsamples=10; // ? shmdt(T); //detach struct timeval tv; uint32_t nsec_cycles, s_lsb, usecs; double cycle = 1/125e6; uint32_t nsecs; /* The Big Loop */ while (1) { T = getShmTime(0); // attach to shared memory gettimeofday(&tv,NULL); // system time-stamp // WR time nsec_cycles = read_mem(map_base, 4 ); // read nanoseconds, in number of 62.5MHz ref cycles nsecs = (uint32_t) (cycle*nsec_cycles*1e9); usecs = (uint32_t) (cycle*nsec_cycles*1e6); s_lsb = read_mem(map_base, 8 ); // read utc lsb //s_msb = read_mem(map_base, 12 ); // read utc msb // clock time T->clockTimeStampSec = s_lsb; T->clockTimeStampUSec = usecs; // offset 4 msec, just for fun T->clockTimeStampNSec = nsecs; // time stamp T->receiveTimeStampSec = tv.tv_sec; T->receiveTimeStampUSec = tv.tv_usec; T->receiveTimeStampNSec = tv.tv_usec*1000; T->valid = 1; T->count += 1; shmdt(T); // detach, required here? syslog (LOG_NOTICE, "WR time is %d.%09d ", (int)s_lsb,(int)nsecs); syslog (LOG_NOTICE, "system time is %d.%06d ", (int)tv.tv_sec,(int)tv.tv_usec); sleep(8); // minpoll is 4, so NTP reads every 16s } spec_close(card); closelog(); exit(EXIT_SUCCESS); }