RT_FIFO, Device driver. Outline Introduction of RT_FIFOs Device driver RT_FIFO Example.
-
Upload
tracy-hurlock -
Category
Documents
-
view
250 -
download
3
Transcript of RT_FIFO, Device driver. Outline Introduction of RT_FIFOs Device driver RT_FIFO Example.
RT_FIFO, RT_FIFO, Device driverDevice driver
RT_FIFO, RT_FIFO, Device driverDevice driver
Outline• Introduction of RT_FIFOs• Device driver• RT_FIFO• Example
Intro. of RT_FIFOs(1)• The RT_FIFO is a mechanism, imple
mented as a character device, to communicate between realtime tasks and ordinary Linux processes.
User Process RT Process
RT FIFO
RT FIFO
Intro. of RT_FIFOs(2)• In the real-time task interface, read/w
rite 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 structurestruct 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_chrdevint 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;
}}write_unlock(&chrdevs_lock);return -EBUSY;
}if (major >= MAX_CHRDEV)
return -EINVAL;…………………………………………………
return 0;}
Init_moduleint 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 Flowregister_chrdev == 0
Irq > 0
unregister_chrdev
get_soft_irq
yes
no
no
yes
rtl_register_chrdev == 0yes
no
return 0
RT_FIFO init_moduleint 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){#ifdef CONFIG_RTL_POSIX_IO rtl_unregister_chrdev(RTF_MAJOR, "rtf");#endif rtf_uninit();}
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 -EIO; } return 0;}
RT_FIFO• Install RT_FIFO module• FIFO structure & file_ops• Real-time part• Non-real-time part
Struct rt_fifo_structstruct 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 structurestruct 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 structurestruct 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_releasestatic 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_getint 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_putint 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; } 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 - (RTF_BI(minor) < 0)); return written;}
rtl_rtf_ioctlstatic 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) { return -EINVAL; } } else { return -EINVAL; } 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_readstatic 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_writestatic 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]# lsmodModule Size Used by Tainted: Pfifo 2148 1rtl_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]# lsmodModule Size Used by Tainted: Pfifo_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)