📄 tid_driver.c
字号:
/*********************************************************************** * * (C) Copyright 2000 * Jean-Jacques Germond, Fr閐閞ic Soulier, Christian Batt; Alcatel * C/O jjg@sxb.bsf.alcatel.fr * * All rights reserved. * * This code is free software; you can redistribute it and/or * modify it under the terms of the GNU *Library* General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This code is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * *Library* General Public License for more details. * * You should have received a copy of the GNU *Library* General Public * License along with this program (see file COPYING.LIB); if not, * write to the Free Software Foundation, Inc., 675 Mass Ave, * Cambridge, MA 02139, USA. * ***********************************************************************//* The "trivial interrupt driver" main file */#include "tid_def.h"#include <asm/init.h> /* for __initfunc */#include <asm/fcntl.h>#include <asm/uaccess.h> /* for put_user *//* * Module Parameters - settable with "insmod" or "LILO" etc. * * Timer period (in us) */#define TID_DEFAULT_PERIOD 1000000 /* default: 1 second */static unsigned int period = TID_DEFAULT_PERIOD;#ifdef MODULEMODULE_PARM(period,"i");#endif /* MODULE *//* The module structure */static struct module __this_module;/* The static descriptor for the unique tid device */Tid_Dev tid_dev_struct; static loff_ttid_lseek (struct file *filp, loff_t off, int whence){ Tid_Dev *dev = &tid_dev_struct; long newpos; switch(whence) { case 0: /* SEEK_SET */ newpos = off; break; case 1: /* SEEK_CUR */ newpos = filp->f_pos + off; break; case 2: /* SEEK_END */ newpos = dev->nbChars + off; break; default: /* can't happen */ return -EINVAL; } if (newpos < 0) { return -EINVAL; } filp->f_pos = newpos; return newpos;}/* * Data management: read and write */ static ssize_ttid_read (struct file *filp, char *buf, size_t count, loff_t* ppos){ int result; /* work */ int i; /* work */ loff_t start_pos; /* f_pos upon entry */ ssize_t copyLen; /* The signed copy length */ Tid_Dev *dev = &tid_dev_struct; /* The device descriptor */ /* Can't seek (pread) on tid devices. */ if (ppos != &filp->f_pos) return -ESPIPE; /* Error if the file has been reseted by some other process */ if (dev->uniqueId != (long)filp->private_data) { return -EIO; } start_pos = filp->f_pos; if (start_pos > dev->nbChars) { return 0; /* EOF return (probably due to some far-away seek) */ } if (start_pos >= dev->maxChars) { return 0; /* EOF return (OK if == maxChars) */ } if (start_pos == dev->nbChars) { /* Put this process to wait into the tid wait queue */ result = tid_wait(start_pos); if (result < 0) { return result; /* The process was signaled or some error occured */ } } /* Truncate as appropriate (not sure how to handle negative counts */ copyLen = dev->nbChars - start_pos; /* What we can copy */ if (copyLen > count) copyLen = count; /* What we will copy */ if (copyLen < 0) { /* We should never be here. But beter be safe than sorry... */ return -EIO; } for (i = 0 ; i < copyLen; i++) { result = copy_to_user(buf++, tid_ripple(start_pos + i), 1); if (result < 0) return result; /* Copy failed */ } filp->f_pos += copyLen; return copyLen;} static ssize_ttid_write (struct file *filp, const char *buf, size_t count, loff_t* ppos) /* The semantic of write is : reset the virtual device */{ /* Can't seek (pread) on trivial devices. */ if (ppos != &filp->f_pos) return -ESPIPE; if (tid_useSimulatedTimer()) { tid_simu_timer_interrupt(count); /* Simulate count interrupts */ } filp->f_pos += count; /* Useless ??? */ return count;} static inttid_ioctl (struct inode* inode, struct file *filp, unsigned int cmd, unsigned long arg){ return 0;} static inttid_open (struct inode* inode, struct file *filp){ unsigned int flags; /* Open flags */ Tid_Dev *dev = &tid_dev_struct; /* The device descriptor */ /* Process the access flags */ filp->f_pos = 0; /* Setup the default position */ flags = (filp->f_flags) & (O_RDONLY | O_WRONLY | O_RDWR); switch (flags) { case O_RDONLY: break; case O_WRONLY: case O_RDWR: /* For our trivial cse, this is same as O_WRONLY */ if ( (filp->f_flags & O_APPEND) == 0) { dev->uniqueId += 1; /* The # of resets */ dev->nbChars = 0; /* Raz previous content if any */ /* At this point we should wake up processes that are waiting on * the 'previous instance'. But this is too complex to begin with * and we wont test this case yet. See note in trv_def.h. */ } else { filp->f_pos = dev->nbChars; /* Append at end of file */ } break; default: /* Invalid access flags */ return -EINVAL; } filp->private_data = (void*)dev->uniqueId; /* The device instance # */ MOD_INC_USE_COUNT; return 0; /* OK return */} static inttid_flush (struct file *filp){ MOD_DEC_USE_COUNT; return 0;}/* * The different file operations */struct file_operations tid_fops = { tid_lseek, tid_read, tid_write, NULL, /* tid_readdir */ NULL, /* tid_select */ tid_ioctl, NULL, /* tid_mmap */ tid_open, tid_flush, /* nothing more, fill with NULLs */};/* The driver init function: we use statically allocated Major/Minor * numbers because dynamic allocation (AR pg: 44) is too expensive * in our embedded environment. */__initfunc ( int tid_init(void) ){ int result; /* Result from kernel calls */ /* Init the tid device */ Tid_Dev* dev = &tid_dev_struct; dev->nbChars = 0; /* The # of char in the device */ dev->uniqueId = 0; /* The # of resets */ dev->maxChars = tid_rippleInit() * 20; /* Max size of the virtual device */ /* Items that are only used for debug and display in /proc */ dev->nbIntrEver = 0; /* # of interrupts since init */ dev->nbBhActiv = 0; /* # of bh activations since init */ dev->nbWakeUp = 0; /* # of wakeups for UNIX proc. */ dev->lastWakeup = -1; /* Code of last wakeup */ dev->hw = (void *)0; /* hardware specific data */ /* Register our major */ result = register_chrdev(TID_MAJOR, "tid", &tid_fops); if (result < 0) { printk(KERN_WARNING "tid: can't register %d\n", TID_MAJOR); return result; } /* Register the trivial driver into /proc */ result = tid_proc_register(); if (result) { goto registerProcFails; } /* Do the hw and foreground inits */ result = tid_connect_timer(dev, period); if (result) { printk(KERN_WARNING "tid: can't init the timer error=%d\n", result); goto connectTimerFails; } return 0; /* Succeed */connectTimerFails: tid_proc_unregister();registerProcFails: unregister_chrdev(TID_MAJOR, "tid"); return result;}/* * Provide module initialization and de-initialization when compiled as module. */#ifdef MODULEint init_module(void){ return tid_init();}void cleanup_module(void){ /* Init the tid device */ Tid_Dev* dev = &tid_dev_struct; tid_disconnect_timer (dev); unregister_chrdev(TID_MAJOR, "tid"); /* Get out of /proc */ tid_proc_unregister();}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -