📄 trv_main.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 module" main routine. */#include "trv_def.h"#include "asm/fcntl.h"/* The module structure */static struct module __this_module;/* The max number of devices (AR uses simple code to make it dynamic * but we probably do not need this dynamicity. */int trv_nr_devs = TRV_MAX_DEVICES;/* The pointer to the table of device desciptors */Trv_Dev* trv_devices = NULL; static Trv_Dev*trv_nbr2devp(int nbr) /* Get a device pointer from a device number */{ return (nbr >= 0 && nbr < TRV_MAX_DEVICES) ? trv_devices + nbr : NULL;} static loff_ttrv_lseek (struct file *filp, loff_t off, int whence){ Trv_Dev *dev = filp->private_data; 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_ttrv_read (struct file *filp, char *buf, size_t count, loff_t* ppos){ int result; /* work */ loff_t start_pos; /* f_pos upon entry */ ssize_t copyLen; /* The signed copy length */ int devnbr = (int)filp->private_data; /* The device number */ Trv_Dev *dev = trv_nbr2devp(devnbr); /* Ptr. to the device */ if (!dev) return -EINVAL; /* Should never happen */ if (!dev->buffer) return -EINVAL; /* Not opened : Should never happen */ /* Can't seek (pread) on trivial devices. */ if (ppos != &filp->f_pos) return -ESPIPE; start_pos = filp->f_pos; if (start_pos >= dev->nbchars) { return 0; /* EOF return */ } /* Truncate as appropriate (not sure how to handle negative counts */ copyLen = dev->nbchars - start_pos; /* What we can copy */ /* Trucate as appropriate. Hope that count is unsigned and count is * always >= 0 */ if (copyLen > count) copyLen = count; /* What we will copy */ /* copyLen should always be > 0 here, but better make sure than sorry */ if ( copyLen > 0) { /* the following call may sleep with impredictable results. We should * lock the device for the copy duration. But this is just our first * driver and we plan to test it with only on process at a time. */ result = trv_copy_to_user(buf, dev->buffer + start_pos, copyLen); if (result < 0) return result; /* Copy failed */ } else { return 0; /* EOF return */ } filp->f_pos += copyLen; return copyLen;} static ssize_ttrv_write (struct file *filp, const char *buf, size_t count, loff_t* ppos) /* The semantic of write is very simple: Write the incoming buffer * (at most TRV_MAX_CHARS) from the start location of the buffer device, * erasing previous suff if any. */{ int result; /* work */ loff_t start_pos; /* f_pos upon entry */ ssize_t copyLen; /* The signed copy length */ int devnbr = (int)filp->private_data; /* The device number */ Trv_Dev *dev = trv_nbr2devp(devnbr); /* Ptr. to the device */ if (!dev) return -EINVAL; /* Should never happen */ if (!dev->buffer) return -EINVAL; /* Not opened : Should never happen */ /* Can't seek (pread) on trivial devices. */ if (ppos != &filp->f_pos) return -ESPIPE; start_pos = filp->f_pos; if (start_pos >= TRV_MAX_CHARS) { /* We are now /dev/null */ filp->f_pos += count; return count; /* OK return */ } if (start_pos > dev->nbchars) { /* Fill zero the gap when the user did seek far away */ int i; for (i = dev->nbchars; i < start_pos; i++) { dev->buffer[i] = 0; } dev->nbchars = start_pos; } /* Truncate as appropriate (not sure how to handle negative counts if * size_t is signed ???. */ copyLen = TRV_MAX_CHARS - start_pos; /* What we can copy */ /* Trucate as appropriate. Hope that count is unsigned and count is * always >= 0 */ if (copyLen > count) copyLen = count; /* What we will copy */ /* copyLen should always be > 0 here, but better make sure than sorry */ if ( copyLen > 0) { /* the following call may sleep with impredictable results. We should * lock the device for the copy duration. But this is just our first * driver and we plan to test it with only on process at a time. */ result = trv_copy_from_user(dev->buffer + start_pos, buf, copyLen); if (result < 0) return result; /* Copy failed */ dev->nbchars = start_pos + copyLen; } filp->f_pos += count; return count;} static inttrv_ioctl (struct inode* inode, struct file *filp, unsigned int cmd, unsigned long arg){ return 0;} static inttrv_open (struct inode* inode, struct file *filp){ unsigned int flags; /* Open flags */ int devnbr = NUM(inode->i_rdev); /* The device number (ivol) */ Trv_Dev *dev = trv_nbr2devp(devnbr); /* Ptr. to the device */ if (!dev) return -EINVAL; /* Should never happen */ /* Test if this device is allocated */ if (!dev->buffer) { dev->buffer = kmalloc(TRV_MAX_CHARS , GFP_KERNEL); if (!dev->buffer) { return -ENOMEM; } dev->size = TRV_MAX_CHARS; /* A cte to make thinhs simpler */ dev->nbchars = 0; /* This an attribute of the device */ } /* 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->nbchars = 0; /* Raz previous content if any */ } else { filp->f_pos = dev->nbchars; /* Append at end of file */ } break; default: /* Invalid access flags */ return -EINVAL; } /* filp->private data records the device number since it is easier * to check devnb than to check a pointer dep ptr */ filp->private_data = (void*)devnbr; MOD_INC_USE_COUNT; return 0; /* OK return */} static inttrv_flush (struct file *filp){ MOD_DEC_USE_COUNT; return 0;}/* * The different file operations */struct file_operations trv_fops = { trv_lseek, trv_read, trv_write, NULL, /* trv_readdir */ NULL, /* trv_select */ trv_ioctl, NULL, /* trv_mmap */ trv_open, trv_flush, /* nothing more, fill with NULLs */};/* The Init_module function: we use statically allocated Major/Minor * numbers because dynamic allocation (AR pg: 44) is too expensive * in our embedded environment. */ intinit_module(void){ int result; /* Result from kernel calls */ int dev_nbr; /* Device number */ /* Register our major */ result = register_chrdev(TRV_MAJOR, "trv", &trv_fops); if (result < 0) { printk(KERN_WARNING "trv: can't register %d\n", TRV_MAJOR); return result; } /* * allocate the devices */ trv_nr_devs = TRV_MAX_DEVICES; /* Do not permit insmod to modify it yet */ trv_devices = kmalloc(trv_nr_devs * sizeof (Trv_Dev), GFP_KERNEL); if (!trv_devices) { result = -ENOMEM; goto fail_malloc; } /* Init the device structures */ memset(trv_devices, 0, trv_nr_devs * sizeof (Trv_Dev)); for (dev_nbr =0; dev_nbr < trv_nr_devs; dev_nbr++) { trv_devices[dev_nbr].size = 0; trv_devices[dev_nbr].buffer = NULL; } /* Register the trivial driver into /proc */ trv_proc_register(); return 0; /* succeed */ fail_malloc: unregister_chrdev(TRV_MAJOR, "trv"); return result;}void cleanup_module(void){ int dev_nbr; unregister_chrdev(TRV_MAJOR, "trv"); /* Get out of /proc */ trv_proc_unregister(); if (!trv_devices) return; /* Loop to kmemfree everything */ for (dev_nbr = 0; dev_nbr < trv_nr_devs; dev_nbr++) { kfree(trv_devices[dev_nbr].buffer); } kfree(trv_devices);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -