?? rtl_posixio.c
字號:
/* * (C) Finite State Machine Labs Inc. 1999-2001 <business@fsmlabs.com> * * Released under the terms of GPL 2. * Open RTLinux makes use of a patented process described in * US Patent 5,995,745. Use of this process is governed * by the Open RTLinux Patent License which can be obtained from * www.fsmlabs.com/PATENT or by sending email to * licensequestions@fsmlabs.com * *//* * Originally derived from the Linux VFS code * Copyright (C) 1991-1993 Linus Torvalds *//* CangeLog * Feb 11 2003 Mattias Sjoesvaerd <mattias@syrensoftware.se> * fix for resource releas if open via f_op fails. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/version.h>#include <linux/config.h>#include <linux/fs.h>#include <linux/major.h>#include <linux/string.h>#include <linux/sched.h>#include <linux/stat.h>#include <linux/fcntl.h>#include <linux/errno.h>#include <linux/ctype.h>#include <asm/io.h>#include <rtl_posixio.h>#include <sys/mman.h>#include <errno.h>#include <unistd.h>#include <rtl.h>#include <rtl_core.h>MODULE_LICENSE("GPL v2");MODULE_AUTHOR("FSMLabs Inc.");MODULE_DESCRIPTION("POSIX API support for RTLinux");#define MAX_RTL_FILES 128static struct rtl_file rtl_files [MAX_RTL_FILES] /* TODO __attribute__ ((aligned (64))) */ = { { NULL, 0 },};struct device_struct { const char * name; struct rtl_file_operations * fops;};static struct device_struct rtldevs[MAX_CHRDEV] = { { NULL, NULL },};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;}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;}/* 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; 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;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;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;}#define CHECKFD(fd) \ if ((unsigned int) (fd) >= MAX_RTL_FILES || !rtl_files[fd].f_op) { \ __set_errno(EBADF); \ return -1; \ }extern int rtl_get_minor(int fd){ CHECKFD(fd); return RTL_MINOR_FROM_FILEPTR(&rtl_files[fd]);}int close(int fd){ CHECKFD(fd); rtl_files[fd].f_op->release(&rtl_files[fd]); rtl_files[fd].f_op = NULL; return 0;}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;}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;}/* TODO lseek */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;}int munmap(void *start, size_t length){ iounmap (start); return 0;}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;}#ifndef CONFIG_RTL_DEVMEM_SUPPORTint init_module(void) {return 0;}void cleanup_module(void){return; }#else #include <asm/io.h>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;}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;}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;}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;}static struct rtl_file_operations rtl_mem_fops = { rtl_mem_llseek, rtl_mem_read, rtl_mem_write, NULL, rtl_mem_mmap, rtl_mem_open, rtl_mem_release};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");}#endif
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -