RT_FIFO, Device driver
Outline Introduction of RT_FIFOs Device driver RT_FIFO Example
Intro. of RT_FIFOs(1) The RT_FIFO is a mechanism, implemented as a character device, to communicate between realtime tasks and ordinary Linux processes. RT FIFO User Process RT Process RT FIFO
Intro. of RT_FIFOs(2) In the real-time task interface, read/write must be atomic and non-blocking. In Linux user processes, see RT_FIFOs as ordinary character devices
Requirements of a device driver Compile gcc –DMODULE –D__KERNEL__ -o dst src Code Setup file_opreation structure Register_chrdev / register_blkdev / misc_register in init_module
Linux file_ops structure struct file_operations { int (*seek) (struct inode *, struct file *, off_t, int); int (*read) (struct inode *, struct file *, char, int); int (*write) (struct inode *, struct file *, off_t, int); int (*readdir) (struct inode *, struct file *, struct dirent *, int); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*select) (struct inode *, struct file *, int , select_table *); int (*mmap) (struct inode *, struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*release) (struct inode *, struct file *); int (*fsync) (struct inode *, struct file *); int (*fasync) (struct inode *, struct file *, int); int (*check_media_change) (struct inode *, struct file *); int (*revalidate) (dev_t dev); }
register_chrdev int register_chrdev(unsigned int major, const char * name, struct file_operations *fops){ if (major == 0) { write_lock(&chrdevs_lock); for (major = MAX_CHRDEV-1; major > 0; major--) { if (chrdevs[major].fops == NULL) { chrdevs[major].name = name; chrdevs[major].fops = fops; write_unlock(&chrdevs_lock); return major; } return -EBUSY; if (major >= MAX_CHRDEV) return -EINVAL; ………………………………………………… return 0;
Init_module int init_module(void){ if (register_chrdev (MAJOR, “name”, &fops)){ printk (“%s: unable to get major %d\n", name, MAJOR); return -EIO; } return 0; void cleanup_module(void){ unregister_chrdev(MAJOR, “name");
RT_FIFO Install RT_FIFO module FIFO structure & file_ops Real-time part Non-real-time part
RT_FIFO init_module Flow register_chrdev == 0 yes no get_soft_irq Irq > 0 no yes rtl_register_chrdev == 0 yes no return 0 unregister_chrdev
RT_FIFO init_module int init_module(void){ int ret; ret = rtf_init(); if (ret < 0) return ret; #ifdef CONFIG_RTL_POSIX_IO if (rtl_register_chrdev (RTF_MAJOR, "rtf", &rtl_fifo_fops)) { printk ("RT-FIFO: unable to get RTLinux major %d\n", RTF_MAJOR); rtf_uninit(); return -EIO; } #endif return 0; void cleanup_module(void){ rtl_unregister_chrdev(RTF_MAJOR, "rtf"); Install non-real-time device driver Install real-time device driver
rtf_init(); int rtf_init (void){ int irq = -1, i; if (register_chrdev (RTF_MAJOR, "rtf", &rtf_fops)) { printk ("RT-FIFO: unable to get major %d\n", RTF_MAJOR); return -EIO; } irq = rtl_get_soft_irq (fifo_irq_handler, "RTLinux FIFO"); if (irq > 0) { rtl_fifo_irq = irq; } else { unregister_chrdev (RTF_MAJOR, "rtf"); printk ("Can't get an irq for rt fifos"); return 0;
RT_FIFO Install RT_FIFO module FIFO structure & file_ops Real-time part Non-real-time part
Struct rt_fifo_struct int allocated; int bidirectional; int user_open; struct task_struct *opener; char *base; int bufsize; int start; int len; spinlock_t fifo_spinlock; int (*user_handler) (unsigned int fifo); int (*rt_handler) (unsigned int fifo); int (*user_ioctl)(unsigned int fifo, unsigned int cmd, unsigned long arg); struct module *creator; struct wait_queue *wait; };
rtl_file_ops structure struct rtl_file_operations { loff_t (*llseek) (struct rtl_file *, loff_t, int); ssize_t (*read) (struct rtl_file *, char *, size_t, loff_t *); ssize_t (*write) (struct rtl_file *, const char *, size_t, loff_t *); int (*ioctl) (struct rtl_file *, unsigned int, unsigned long); int (*mmap) (struct rtl_file *, void *start, size_t length, int prot , int flags, off_t offset, caddr_t *result); int (*open) (struct rtl_file *); int (*release) (struct rtl_file *); };
Linux file_ops structure struct file_operations { int (*seek) (struct inode *, struct file *, off_t, int); int (*read) (struct inode *, struct file *, char, int); int (*write) (struct inode *, struct file *, off_t, int); int (*readdir) (struct inode *, struct file *, struct dirent *, int); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*select) (struct inode *, struct file *, int , select_table *); int (*mmap) (struct inode *, struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*release) (struct inode *, struct file *); int (*fsync) (struct inode *, struct file *); int (*fasync) (struct inode *, struct file *, int); int (*check_media_change) (struct inode *, struct file *); int (*revalidate) (dev_t dev); }
RT_FIFO Install RT_FIFO module FIFO structure & file_ops Real-time part Non-real-time part
rtl_fifo_fops cont. static struct rtl_file_operations rtl_fifo_fops = { NULL, // llseek rtl_rtf_read, // read rtl_rtf_write, // write rtl_rtf_ioctl, // ioctl NULL, // mmap rtl_rtf_open, // open rtl_rtf_release // release };
rtl_rtf_open & rtl_rtf_release static int rtl_rtf_open (struct rtl_file *filp){ if (!(filp->f_flags & O_NONBLOCK)) { return -EACCES; } if( (filp->f_flags & O_CREAT) && !RTF_ALLOCATED(filp->f_minor)){ __rtf_create(filp->f_minor, RTF_DEFAULT_SIZE, &__this_module); if(!RTF_ALLOCATED(filp->f_minor)){ return -EUNATCH; return 0; better be calling from Linux and not RT mode unless there are preallocted fifos still static int rtl_rtf_release (struct rtl_file *filp){ int minor = filp->f_minor; char *old = RTF_BASE(minor); if (RTF_ALLOCATED(minor) && old && find_prealloc(old)) { rtf_destroy(minor); } return 0;
rtl_rtf_read rtf_get int rtf_get(unsigned int minor, void *buf, int count){ int chars = 0, size = 0, read = 0; char *pipebuf; rtl_spin_lock_irqsave(&RTF_SPIN(minor), interrupt_state); while (count > 0 && (size = RTF_LEN(minor))) { ………read circular queue…… count -= chars; memcpy(buf, pipebuf, chars); buf += chars; } rtl_spin_unlock_irqrestore(&RTF_SPIN(minor), interrupt_state); if(*RTF_RT_HANDLER(minor)){ (*RTF_RT_HANDLER(minor))(minor); if (RTF_USER_OPEN(minor)) { fifo_wake_sleepers(minor); return read;
rtl_rtf_write rtf_put int rtf_put(unsigned int minor, void *buf, int count){ int chars = 0, free = 0, written = 0; char *pipebuf; rtl_spin_lock_irqsave(&RTF_SPIN(minor), interrupt_state); if (RTF_FREE(minor) < count) { rtl_spin_unlock_irqrestore(&RTF_SPIN(minor), interrupt_state); return -ENOSPC; } while (count > 0 && (free = RTF_FREE(minor))) { ………write circular queue…… memcpy(pipebuf, buf, chars); buf += chars; if((*RTF_RT_HANDLER(minor))) (*RTF_RT_HANDLER(minor))(minor); if (RTF_USER_OPEN(minor)) fifo_wake_sleepers(minor - (RTF_BI(minor) < 0)); return written;
rtl_rtf_ioctl static int rtl_rtf_ioctl (struct rtl_file *filp, unsigned int req, unsigned long arg){ int minor = RTL_MINOR_FROM_FILEPTR(filp); if (!RTF_ALLOCATED(minor)) { return -EINVAL; } if (req == RTF_SETSIZE) { if (rtf_resize(minor, arg) < 0) { } else { return 0;
RT_FIFO Install RT_FIFO module FIFO structure & file_ops Real-time part Non-real-time part
rtf_fops cont. static struct file_operations rtf_fops = { llseek: rtf_llseek, read: rtf_read, write: rtf_write, poll: rtf_poll, ioctl: rtf_ioctl, open: rtf_open, release: rtf_release, };
rtf_open& rtf_release static int rtf_open(struct inode *inode, struct file *filp){ unsigned int minor = MINOR(inode->i_rdev); RTF_OPENER(minor) = current; RTF_USER_OPEN(minor)++; if (RTF_ADDR(minor)->creator) { __MOD_INC_USE_COUNT(RTF_ADDR(minor)->creator); } return 0; static int rtf_release(struct inode *inode, struct file *file){ unsigned int minor = MINOR(inode->i_rdev); RTF_USER_OPEN(minor)--; if (RTF_ADDR(minor)->creator) { __MOD_DEC_USE_COUNT(RTF_ADDR(minor)->creator); } return 0;
rtf_read Block until data available copy fifo content to user space static ssize_t rtf_read(struct file *filp, char *buf, size_t count, loff_t* ppos){ ………………………………….. minor = minor + RTF_BI(minor); if…………… while (RTF_EMPTY(minor) ) { if (signal_pending(current)) return -ERESTARTSYS; fifo_setup_sleep(minor); interruptible_sleep_on_timeout(&RTF_WAIT(minor), RTL_FIFO_TIMEOUT); } while (count > 0 && (size = RTF_LEN(minor))) { ……read from queue…… copy_to_user(buf, pipebuf, chars); rtl_spin_lock_irqsave(&RTF_SPIN(minor), interrupt_state); RTF_START(minor) += chars; RTF_START(minor) = RTF_WRAP(minor, RTF_START(minor)); RTF_LEN(minor) -= chars; rtl_spin_unlock_irqrestore(&RTF_SPIN(minor), interrupt_state); if (read) { if((*RTF_HANDLER(minor))){ ………………………… Block until data available copy fifo content to user space
rtf_write Block until able to write if……………… copy buffer to fifo static ssize_t rtf_write(struct file *filp, const char *buf, size_t count, loff_t* ppos) { …………………… while (count > 0) { while (RTF_FREE(minor) < free) { if…………………… fifo_setup_sleep(minor); interruptible_sleep_on_timeout(&RTF_WAIT(minor), RTL_FIFO_TIMEOUT); } while (count > 0 && (free = RTF_FREE(minor))) { ………..write to queue…… rtl_spin_lock_irqsave(&RTF_SPIN(minor), interrupt_state); pipebuf = RTF_BASE(minor) + RTF_END(minor); copy_from_user(pipebuf, buf, chars); RTF_LEN(minor) += chars; rtl_spin_unlock_irqrestore(&RTF_SPIN(minor), interrupt_state); free = 1; if……………… return result; return written; Block until able to write copy buffer to fifo
Example(rt_np) pthread_t thread; void * start_routine(void *arg){ struct sched_param p; int status; p . sched_priority = 1; pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); pthread_make_periodic_np (pthread_self(), gethrtime(), 10000000); while (1){ sprintf(buf, “[%d]\n“),; status = rtf_put(0, buf, 1024); pthread_wait_np(); } return 0; int init_module(void) { rtf_create(0, 1024*1024); return pthread_create (&thread, NULL, start_routine, 0); void cleanup_module(void) { rtf_destroy(0); pthread_delete_np (thread);
Result (rt_np) [root@rtlinux rtlinux]# insmod fifo.o Run a user application [root@rtlinux root]# lsmod Module Size Used by Tainted: P fifo 2148 1 rtl_sched 30368 0 [fifo] rtl_fifo 10784 0 [fifo] rtl_posixio 8052 0 [rtl_fifo] rtl_time 7084 0 [fifo rtl_sched rtl_posixio] rtl 21200 0 [rtl_sched rtl_fifo rtl_posixio rtl_time] mbuff 8684 0 (unused)
Example(rt_posixio) int fd; pthread_t thread; void * start_routine(void *arg){ struct sched_param p; int status, i=0; p.sched_priority = 1; pthread_setschedparam (pthread_self(), SCHED_FIFO, &p); pthread_make_periodic_np (pthread_self(), gethrtime(), 10000000); while (1){ sprintf(buf, "[%d] fd = %d\n“, i++, fd); status = write(fd, buf, 1024); pthread_wait_np(); } return 0; int init_module(void) { fd = open("/dev/rtf10", O_NONBLOCK | O_CREAT ); if(fd) return -1; return pthread_create (&thread, NULL, start_routine, 0); void cleanup_module(void) { close(fd); pthread_delete_np (thread);
Result(rt_posixio) [root@rtlinux rtlinux]# insmod fifo_test.o Run a user application [root@rtlinux include]# lsmod Module Size Used by Tainted: P fifo_test 2564 0 (unused) fifo 2148 0 (unused) rtl_sched 30368 0 [fifo_test fifo] rtl_fifo 10784 2 [fifo] rtl_posixio 8052 0 [fifo_test rtl_fifo] rtl_time 7084 0 [fifo_test fifo rtl_sched rtl_posixio] rtl 21200 0 [rtl_sched rtl_fifo rtl_posixio rtl_time] mbuff 8684 0 (unused)