⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 trv_main.c

📁 mpc8xx driver(led), based on tqm8
💻 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 + -