360 likes | 459 Views
rtl_posixio(module). 928316 方國州 946339 陳昱廷. Outline. Introduction Code trace /dev/mem Reference. POSIX. POSIX (the ” Portable Operating System Interface ” ) is a specification which dictates how operating systems should behave.
E N D
rtl_posixio(module) 928316 方國州 946339 陳昱廷
Outline • Introduction • Code trace • /dev/mem • Reference
POSIX • POSIX (the ”Portable Operating System Interface”) is a specification which dictates how operating systems should behave. • Among other things, it specifies basic operations involving signaling and threads, making it easier for programmers to port their applications from one operating system to the other.
POSIX Interfaces • Extensions • System API Extensions • Real Time and Related API • Threads API • Real Time Extensions • Security • Additional Utilities • Protection and Control Utilities
POSIX in RTLinux • RTLinux API is based on a small system POSIX “profile” that is specified in POSIX standards 1003.13 PSE51. • This profile is for a ”minimal real-time system” environment and it looks very much like a multithreaded single POSIX process.
I/O device • Block Device • Allow random access • Fixed size of block • Ex: HD , CD-ROM , Floppy • Character Device • Do not need to support all functionality of regular files • Ex: most other devices • The device serviced by RTLinux device driver only can be a character device
rtl_posixio • rtl_posixio supports POSIX style read/write/open interface to device drivers.
rtl_posixio • Linux has difficulty on OPEN for supporting POSIXIO • Open in a file system is inherent non-real time • Opening a device file may require an unbounded time for • traversal of the namespace • following symbolic links • Resolving directories • Cross mount point
Code trace • Basic operation • rtl_register_rtldev • rtl_unregister_rtldev • Function calls • open • close • read • write • mmap / munmap • ioctl
Data Structure • struct device_struct { const char * name; struct rtl_file_operations * fops; }; • static struct device_struct rtldevs[MAX_CHRDEV] = { { NULL, NULL }, };
Data 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 *); };
Data Structure • struct rtl_file { struct rtl_file_operations *f_op; int f_minor; int f_flags; loff_t f_pos; }; • static struct rtl_file rtl_files [MAX_RTL_FILES] = { { NULL, 0 }, };
rtl_register_rtldev • int rtl_register_rtldev(unsigned int major, const char * name, struct rtl_file_operations *fops) { if (major >= MAX_CHRDEV) return -EINVAL; if (rtldevs[major].fops && rtldevs[major].fops != fops) { return -EBUSY; } rtldevs[major].name = name; rtldevs[major].fops = fops; return 0; }
rtl_unregister_rtldev • int rtl_unregister_rtldev(unsigned int major, const char * name) { if (major >= MAX_CHRDEV) return -EINVAL; if (!rtldevs[major].fops) return -EINVAL; if (strcmp(rtldevs[major].name, name)) return -EINVAL; rtldevs[major].name = NULL; rtldevs[major].fops = NULL; return 0; }
open • open() will only open files named /dev/filenameNN where filename is the name provided to the register call by the driver and NN is an optional device minor number
Open • /* we assume all RTLinux file names are of the form /dev/devicename<number> */ • int open(const char *pathname, int flags) • { • int i; • int minor; • int major; • char devname[200]; • char *p; • int ret; • if (strncmp(pathname, "/dev/", 5)) { • __set_errno(ENOENT); • return -1; /* here we can use some other name resolution scheme */ • } • i = 0; • while (i < sizeof(devname) - 1 && *(pathname + 5 + i) && !isdigit(*(pathname + 5 + i))) { • devname[i] = *(pathname + 5 + i); • i++; • } • devname[i] = 0;
Open • if (isdigit(*(pathname + 5 + i))) { • minor = simple_strtoul (pathname + 5 + i, &p, 10); • } else if (!*(pathname + 5 + i)) { • minor = 0; /* like /dev/mem */ • } else { • __set_errno(ENOENT); • return -1; • } • for (i = 0; i < MAX_CHRDEV; i ++) { • if (rtldevs[i].name && !strcmp(rtldevs[i].name, devname)) { • goto found_major; • } • } • rtl_printf("rtl_posixio: dev entry %s not found\n", pathname); • __set_errno(ENOENT); • return -1;
Open • found_major: • major = i; • for (i = 0; i < MAX_RTL_FILES; i ++) { • if (!rtl_files[i].f_op) { • goto found_free; • } • } • __set_errno(ENOMEM); • return -1;
Open • found_free: • rtl_files[i].f_op = rtldevs[major].fops; • rtl_files[i].f_minor = minor; • rtl_files[i].f_flags = flags; • ret = rtl_files[i].f_op->open(&rtl_files[i]); • if (ret < 0) { • /* if open fails free the resources - Mattias • * Sjoesvaerd <mattias@syrensoftware.se> • */ • rtl_files[i].f_op = NULL; • rtl_files[i].f_minor = 0; • rtl_files[i].f_flags = 0; • __set_errno(-ret); • return -1; • } • return i;
Close • int close(int fd) • { • CHECKFD(fd); • rtl_files[fd].f_op->release(&rtl_files[fd]); • rtl_files[fd].f_op = NULL; • return 0; • }
Write • ssize_t write(int fd, const void *buf, size_t count) • { • int ret; • CHECKFD(fd); • ret = rtl_files[fd] . f_op -> write (&rtl_files[fd], buf, count, &rtl_files[fd].f_pos); • if (ret < 0) { • __set_errno(-ret); • return -1; • } • return ret; • }
Read • ssize_t read(int fd, void *buf, size_t count) • { • int ret; • CHECKFD(fd); • ret = rtl_files[fd] . f_op -> read (&rtl_files[fd], buf, count, &rtl_files[fd].f_pos); • if (ret < 0) { • __set_errno(-ret); • return -1; • } • return ret; • }
mmap • caddr_t mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset) • { • int ret; • caddr_t result; • if ((unsigned int) (fd) >= MAX_RTL_FILES || !rtl_files[fd].f_op) { • __set_errno(EBADF); • return (caddr_t) -1; • } • if (! rtl_files[fd] . f_op -> mmap) { • __set_errno(EINVAL); • return (caddr_t) -1; • } • ret = rtl_files[fd] . f_op -> mmap (&rtl_files[fd], start, length, prot, flags, offset, &result); • if (ret != 0) { • __set_errno(-ret); • return (caddr_t) -1; • } • return result; • }
munmap • int munmap(void *start, size_t length) • { • iounmap (start); • return 0; • }
ioctl • int ioctl(int fd, int request, ...) • { • int ret; • va_list list; • unsigned long arg; • va_start (list, request); • arg = va_arg(list, unsigned long); • va_end (list); • CHECKFD(fd); • ret = rtl_files[fd] . f_op -> ioctl (&rtl_files[fd], request, arg); • if (ret < 0) { • __set_errno(-ret); • return -1; • } • return 0; • }
/dev/mem support • This driver allows real-time threads to access physical computer memory in the same way as Linux processes can do. • dev/mem support is optional. (CONFIG_RTL_DEVMEM_SUPPORT)
/dev/mem Using /dev/mem is preferable for two reasons : • doing so will allow debugging real-time threads as Linux threads. • future implementations of realtime Linux may provide optional memory protection for real-time tasks
Related functions init_module cleanup_module rtl_mem_open rtl_mem_release rtl_mem_write rtl_mem_read rtl_mem_mmap rtl_mem_llseek
Init/cleanup • int init_module(void) • { • if (rtl_register_rtldev (MEM_MAJOR, "mem", &rtl_mem_fops)) { • printk ("RTLinux /dev/mem: unable to get RTLinux major %d\n", MEM_MAJOR); • return -EIO; • } • return 0; • } • void cleanup_module(void) • { • rtl_unregister_rtldev(MEM_MAJOR, "mem"); • }
Open/release • static int rtl_mem_open (struct rtl_file *filp) • { • return 0; • } • static int rtl_mem_release (struct rtl_file *filp) • { • filp->f_pos = 0; • return 0; • }
Read/write • static ssize_t rtl_mem_write(struct rtl_file *filp, const char *buf, size_t count, loff_t* ppos) • { • memcpy_toio ((long) *ppos, buf, count); • *ppos += count; • return count; • } • static ssize_t rtl_mem_read(struct rtl_file *filp, char *buf, size_t count, loff_t* ppos) • { • memcpy_fromio (buf, (long) *ppos, count); • *ppos += count; • return count; • }
Mem_mmap • static int rtl_mem_mmap (struct rtl_file *file, void *start, size_t length, int prot , int flags, off_t offset, caddr_t *result) • { • /* TODO need to fail if MAP_FIXED was specified etc */ • if (!rtl_rt_system_is_idle()) { • return -EAGAIN; • } • *result = ioremap (offset, length); • if (!*result) { • return -EINVAL; • } • return 0; • }
Mem_llseek • static loff_t rtl_mem_llseek(struct rtl_file *file, loff_t offset, int origin) • { • if (origin != SEEK_SET) { • return -EINVAL; • } • return file->f_pos = offset; • }
Reference • 1. http://kernelnewbies.org/documents/kdoc/kernel-api/r817.html • 2. http://www.die.net/doc/linux/man/man2/mmap.2.html • 3. http://kernel.korea.ac.kr/lxr/linux-2.4.24/http/source/arch/sh64/lib/io.c#L182
Reference • 4. http://www.linuxaid.com.cn/articles/4/6/46262537.shtml • 5. http://publib.boulder.ibm.com/infocenter/pseries/index.jsp?topic=/com.ibm.aix.doc/libs/basetrf1/lseek.htm • 6. http://rtportal.upv.es/tutorial/documentacion/design.pdf