main.c
上传用户:wudi5211
上传日期:2010-01-21
资源大小:607k
文件大小:21k
源码类别:

嵌入式Linux

开发平台:

C/C++

  1. /*
  2.  * main.c -- the bare scull char module
  3.  *
  4.  * Copyright (C) 2001 Alessandro Rubini and Jonathan Corbet
  5.  * Copyright (C) 2001 O'Reilly & Associates
  6.  *
  7.  * The source code in this file can be freely used, adapted,
  8.  * and redistributed in source or binary form, so long as an
  9.  * acknowledgment appears in derived source files.  The citation
  10.  * should list that the code comes from the book "Linux Device
  11.  * Drivers" by Alessandro Rubini and Jonathan Corbet, published
  12.  * by O'Reilly & Associates.   No warranty is attached;
  13.  * we cannot take responsibility for errors or fitness for use.
  14.  *
  15.  */
  16. #ifndef __KERNEL__
  17. #  define __KERNEL__
  18. #endif
  19. #ifndef MODULE
  20. #  define MODULE
  21. #endif
  22. #include <linux/config.h>
  23. #include <linux/module.h>
  24. #include <linux/kernel.h>   /* printk() */
  25. #include <linux/malloc.h>   /* kmalloc() */
  26. #include <linux/fs.h>       /* everything... */
  27. #include <linux/errno.h>    /* error codes */
  28. #include <linux/types.h>    /* size_t */
  29. #include <linux/proc_fs.h>
  30. #include <linux/fcntl.h>    /* O_ACCMODE */
  31. #include <asm/system.h>     /* cli(), *_flags */
  32. #include "scull.h"          /* local definitions */
  33. /*
  34.  * I don't use static symbols here, because we export no symbols
  35.  */
  36. int scull_major =   SCULL_MAJOR;
  37. int scull_nr_devs = SCULL_NR_DEVS;    /* number of bare scull devices */
  38. int scull_quantum = SCULL_QUANTUM;
  39. int scull_qset =    SCULL_QSET;
  40. MODULE_PARM(scull_major,"i");
  41. MODULE_PARM(scull_nr_devs,"i");
  42. MODULE_PARM(scull_quantum,"i");
  43. MODULE_PARM(scull_qset,"i");
  44. MODULE_AUTHOR("Alessandro Rubini");
  45. Scull_Dev *scull_devices; /* allocated in scull_init_module */
  46. /*
  47.  * Different minors behave differently, so let's use multiple fops
  48.  */
  49. struct file_operations *scull_fop_array[]={
  50.     &scull_fops,      /* type 0 */
  51.     &scull_priv_fops, /* type 1 */
  52.     &scull_pipe_fops, /* type 2 */
  53.     &scull_sngl_fops, /* type 3 */
  54.     &scull_user_fops, /* type 4 */
  55.     &scull_wusr_fops  /* type 5 */
  56. };
  57. #define SCULL_MAX_TYPE 5
  58. int scull_trim(Scull_Dev *dev)
  59. {
  60.     Scull_Dev *next, *dptr;
  61.     int qset = dev->qset;   /* "dev" is not-null */
  62.     int i;
  63.     for (dptr = dev; dptr; dptr = next) { /* all the list items */
  64.         if (dptr->data) {
  65.             for (i = 0; i < qset; i++)
  66.                 if (dptr->data[i])
  67.                     kfree(dptr->data[i]);
  68.             kfree(dptr->data);
  69.             dptr->data=NULL;
  70.         }
  71.         next=dptr->next;
  72.         if (dptr != dev) kfree(dptr); /* all of them but the first */
  73.     }
  74.     dev->size = 0;
  75.     dev->quantum = scull_quantum;
  76.     dev->qset = scull_qset;
  77.     dev->next = NULL;
  78.     return 0;
  79. }
  80. #ifdef SCULL_DEBUG /* use proc only if debugging */
  81. /*
  82.  * The proc filesystem: function to read and entry
  83.  */
  84. int scull_read_procmem(char *buf, char **start, off_t offset,
  85.                    int count, int *eof, void *data)
  86. {
  87.     int i, j, len = 0;
  88.     int limit = count - 80; /* Don't print more than this */
  89.     for (i = 0; i < scull_nr_devs && len <= limit; i++) {
  90.         Scull_Dev *d = &scull_devices[i];
  91.         if (down_interruptible(&d->sem))
  92.                 return -ERESTARTSYS;
  93.         len += sprintf(buf+len,"nDevice %i: qset %i, q %i, sz %lin",
  94.                        i, d->qset, d->quantum, d->size);
  95.         for (; d && len <= limit; d = d->next) { /* scan the list */
  96.             len += sprintf(buf+len, "  item at %p, qset at %pn", d, d->data);
  97.             if (d->data && !d->next) /* dump only the last item - save space */
  98.                 for (j = 0; j < d->qset; j++) {
  99.                     if (d->data[j])
  100.                         len += sprintf(buf+len,"    % 4i: %8pn",j,d->data[j]);
  101.                 }
  102.         }
  103.         up(&scull_devices[i].sem);
  104.     }
  105.     *eof = 1;
  106.     return len;
  107. }
  108. #ifdef USE_PROC_REGISTER
  109. static int scull_get_info(char *buf, char **start, off_t offset,
  110.                 int len, int unused)
  111. {
  112.     int eof = 0;
  113.     return scull_read_procmem (buf, start, offset, len, &eof, NULL);
  114. }
  115. struct proc_dir_entry scull_proc_entry = {
  116.         namelen:    8,
  117.         name:       "scullmem",
  118.         mode:       S_IFREG | S_IRUGO,
  119.         nlink:      1,
  120.         get_info:   scull_get_info,
  121. };
  122. static void scull_create_proc()
  123. {
  124.     proc_register_dynamic(&proc_root, &scull_proc_entry);
  125. }
  126. static void scull_remove_proc()
  127. {
  128.     proc_unregister(&proc_root, scull_proc_entry.low_ino);
  129. }
  130. #else  /* no USE_PROC_REGISTER - modern world */
  131. static void scull_create_proc()
  132. {
  133.     create_proc_read_entry("scullmem", 0 /* default mode */,
  134.                            NULL /* parent dir */, scull_read_procmem,
  135.                            NULL /* client data */);
  136. }
  137. static void scull_remove_proc()
  138. {
  139.     /* no problem if it was not registered */
  140.     remove_proc_entry("scullmem", NULL /* parent dir */);
  141. }
  142. #endif /* USE_PROC_REGISTER */
  143. #endif /* SCULL_DEBUG */
  144. /*
  145.  * Open and close
  146.  */
  147. /* In scull_open, the fop_array is used according to TYPE(dev) */
  148. int scull_open(struct inode *inode, struct file *filp)
  149. {
  150.     Scull_Dev *dev; /* device information */
  151.     int num = NUM(inode->i_rdev);
  152.     int type = TYPE(inode->i_rdev);
  153.     /*
  154.      * the type and num values are only valid if we are not using devfs.
  155.      * However, since we use them to retrieve the device pointer, we
  156.      * don't need them with devfs as filp->private_data is already
  157.      * initialized
  158.      */
  159.     /*
  160.      * If private data is not valid, we are not using devfs
  161.      * so use the type (from minor nr.) to select a new f_op
  162.      */
  163.     if (!filp->private_data && type) {
  164.         if (type > SCULL_MAX_TYPE) return -ENODEV;
  165.         filp->f_op = scull_fop_array[type];
  166.         return filp->f_op->open(inode, filp); /* dispatch to specific open */
  167.     }
  168.     /* type 0, check the device number (unless private_data valid) */
  169.     dev = (Scull_Dev *)filp->private_data;
  170.     if (!dev) {
  171.         if (num >= scull_nr_devs) return -ENODEV;
  172.         dev = &scull_devices[num];
  173.         filp->private_data = dev; /* for other methods */
  174.     }
  175.     MOD_INC_USE_COUNT;  /* Before we maybe sleep */
  176.     /* now trim to 0 the length of the device if open was write-only */
  177.     if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) {
  178.         if (down_interruptible(&dev->sem)) {
  179.             MOD_DEC_USE_COUNT;
  180.             return -ERESTARTSYS;
  181.         }
  182.         scull_trim(dev); /* ignore errors */
  183.         up(&dev->sem);
  184.     }
  185.     return 0;          /* success */
  186. }
  187. int scull_release(struct inode *inode, struct file *filp)
  188. {
  189.     MOD_DEC_USE_COUNT;
  190.     return 0;
  191. }
  192. /*
  193.  * Follow the list 
  194.  */
  195. Scull_Dev *scull_follow(Scull_Dev *dev, int n)
  196. {
  197.     while (n--) {
  198.         if (!dev->next) {
  199.             dev->next = kmalloc(sizeof(Scull_Dev), GFP_KERNEL);
  200.             memset(dev->next, 0, sizeof(Scull_Dev));
  201.         }
  202.         dev = dev->next;
  203.         continue;
  204.     }
  205.     return dev;
  206. }
  207. /*
  208.  * Data management: read and write
  209.  */
  210. ssize_t scull_read(struct file *filp, char *buf, size_t count,
  211.                 loff_t *f_pos)
  212. {
  213.     Scull_Dev *dev = filp->private_data; /* the first listitem */
  214.     Scull_Dev *dptr;
  215.     int quantum = dev->quantum;
  216.     int qset = dev->qset;
  217.     int itemsize = quantum * qset; /* how many bytes in the listitem */
  218.     int item, s_pos, q_pos, rest;
  219.     ssize_t ret = 0;
  220.     if (down_interruptible(&dev->sem))
  221.             return -ERESTARTSYS;
  222.     if (*f_pos >= dev->size)
  223.         goto out;
  224.     if (*f_pos + count > dev->size)
  225.         count = dev->size - *f_pos;
  226.     /* find listitem, qset index, and offset in the quantum */
  227.     item = (long)*f_pos / itemsize;
  228.     rest = (long)*f_pos % itemsize;
  229.     s_pos = rest / quantum; q_pos = rest % quantum;
  230.     /* follow the list up to the right position (defined elsewhere) */
  231.     dptr = scull_follow(dev, item);
  232.     if (!dptr->data)
  233.         goto out; /* don't fill holes */
  234.     if (!dptr->data[s_pos])
  235.         goto out;
  236.     /* read only up to the end of this quantum */
  237.     if (count > quantum - q_pos)
  238.         count = quantum - q_pos;
  239.     if (copy_to_user(buf, dptr->data[s_pos]+q_pos, count)) {
  240.         ret = -EFAULT;
  241. goto out;
  242.     }
  243.     *f_pos += count;
  244.     ret = count;
  245.  out:
  246.     up(&dev->sem);
  247.     return ret;
  248. }
  249. ssize_t scull_write(struct file *filp, const char *buf, size_t count,
  250.                 loff_t *f_pos)
  251. {
  252.     Scull_Dev *dev = filp->private_data;
  253.     Scull_Dev *dptr;
  254.     int quantum = dev->quantum;
  255.     int qset = dev->qset;
  256.     int itemsize = quantum * qset;
  257.     int item, s_pos, q_pos, rest;
  258.     ssize_t ret = -ENOMEM; /* value used in "goto out" statements */
  259.     if (down_interruptible(&dev->sem))
  260.             return -ERESTARTSYS;
  261.     /* find listitem, qset index and offset in the quantum */
  262.     item = (long)*f_pos / itemsize;
  263.     rest = (long)*f_pos % itemsize;
  264.     s_pos = rest / quantum; q_pos = rest % quantum;
  265.     /* follow the list up to the right position */
  266.     dptr = scull_follow(dev, item);
  267.     if (!dptr->data) {
  268.         dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL);
  269.         if (!dptr->data)
  270.             goto out;
  271.         memset(dptr->data, 0, qset * sizeof(char *));
  272.     }
  273.     if (!dptr->data[s_pos]) {
  274.         dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);
  275.         if (!dptr->data[s_pos])
  276.             goto out;
  277.     }
  278.     /* write only up to the end of this quantum */
  279.     if (count > quantum - q_pos)
  280.         count = quantum - q_pos;
  281.     if (copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) {
  282.         ret = -EFAULT;
  283. goto out;
  284.     }
  285.     *f_pos += count;
  286.     ret = count;
  287.     /* update the size */
  288.     if (dev->size < *f_pos)
  289.         dev-> size = *f_pos;
  290.   out:
  291.     up(&dev->sem);
  292.     return ret;
  293. }
  294. /*
  295.  * The ioctl() implementation
  296.  *
  297.  * This is done twice, once the 2.2 way, followed by the 2.0 way.  One
  298.  * would not normally do things in this manner, but we wanted to illustrate
  299.  * both ways...
  300.  */
  301. #ifndef LINUX_20
  302. int scull_ioctl(struct inode *inode, struct file *filp,
  303.                  unsigned int cmd, unsigned long arg)
  304. {
  305.     int err = 0, tmp;
  306.     int ret = 0;
  307.     
  308.     /*
  309.      * extract the type and number bitfields, and don't decode
  310.      * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok()
  311.      */
  312.     if (_IOC_TYPE(cmd) != SCULL_IOC_MAGIC) return -ENOTTY;
  313.     if (_IOC_NR(cmd) > SCULL_IOC_MAXNR) return -ENOTTY;
  314.     /*
  315.      * the direction is a bitmask, and VERIFY_WRITE catches R/W
  316.      * transfers. `Type' is user-oriented, while
  317.      * access_ok is kernel-oriented, so the concept of "read" and
  318.      * "write" is reversed
  319.      */
  320.     if (_IOC_DIR(cmd) & _IOC_READ)
  321.         err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
  322.     else if (_IOC_DIR(cmd) & _IOC_WRITE)
  323.         err =  !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
  324.     if (err) return -EFAULT;
  325.     switch(cmd) {
  326. #ifdef SCULL_DEBUG
  327.       case SCULL_IOCHARDRESET:
  328.          /*
  329.           * reset the counter to 1, to allow unloading in case
  330.           * of problems. Use 1, not 0, because the invoking
  331.           * process has the device open.
  332.           */
  333.          while (MOD_IN_USE)
  334.              MOD_DEC_USE_COUNT;
  335.          MOD_INC_USE_COUNT;
  336.          /* don't break: fall through and reset things */
  337. #endif /* SCULL_DEBUG */
  338.       case SCULL_IOCRESET:
  339.         scull_quantum = SCULL_QUANTUM;
  340.         scull_qset = SCULL_QSET;
  341.         break;
  342.         
  343.       case SCULL_IOCSQUANTUM: /* Set: arg points to the value */
  344.         if (! capable (CAP_SYS_ADMIN))
  345.             return -EPERM;
  346.         ret = __get_user(scull_quantum, (int *)arg);
  347.         break;
  348.       case SCULL_IOCTQUANTUM: /* Tell: arg is the value */
  349.         if (! capable (CAP_SYS_ADMIN))
  350.             return -EPERM;
  351.         scull_quantum = arg;
  352.         break;
  353.       case SCULL_IOCGQUANTUM: /* Get: arg is pointer to result */
  354.         ret = __put_user(scull_quantum, (int *)arg);
  355.         break;
  356.       case SCULL_IOCQQUANTUM: /* Query: return it (it's positive) */
  357.         return scull_quantum;
  358.       case SCULL_IOCXQUANTUM: /* eXchange: use arg as pointer */
  359.         if (! capable (CAP_SYS_ADMIN))
  360.             return -EPERM;
  361.         tmp = scull_quantum;
  362.         ret = __get_user(scull_quantum, (int *)arg);
  363.         if (ret == 0)
  364.             ret = __put_user(tmp, (int *)arg);
  365.         break;
  366.       case SCULL_IOCHQUANTUM: /* sHift: like Tell + Query */
  367.         if (! capable (CAP_SYS_ADMIN))
  368.             return -EPERM;
  369.         tmp = scull_quantum;
  370.         scull_quantum = arg;
  371.         return tmp;
  372.         
  373.       case SCULL_IOCSQSET:
  374.         if (! capable (CAP_SYS_ADMIN))
  375.             return -EPERM;
  376.         ret = __get_user(scull_qset, (int *)arg);
  377.         break;
  378.       case SCULL_IOCTQSET:
  379.         if (! capable (CAP_SYS_ADMIN))
  380.             return -EPERM;
  381.         scull_qset = arg;
  382.         break;
  383.       case SCULL_IOCGQSET:
  384.         ret = __put_user(scull_qset, (int *)arg);
  385.         break;
  386.       case SCULL_IOCQQSET:
  387.         return scull_qset;
  388.       case SCULL_IOCXQSET:
  389.         if (! capable (CAP_SYS_ADMIN))
  390.             return -EPERM;
  391.         tmp = scull_qset;
  392.         ret = __get_user(scull_qset, (int *)arg);
  393.         if (ret == 0)
  394.             ret = put_user(tmp, (int *)arg);
  395.         break;
  396.       case SCULL_IOCHQSET:
  397.         if (! capable (CAP_SYS_ADMIN))
  398.             return -EPERM;
  399.         tmp = scull_qset;
  400.         scull_qset = arg;
  401.         return tmp;
  402.         /*
  403.          * The following two change the buffer size for scullpipe.
  404.          * The scullpipe device uses this same ioctl method, just to
  405.          * write less code. Actually, it's the same driver, isn't it?
  406.          */
  407.       case SCULL_P_IOCTSIZE:
  408.         scull_p_buffer = arg;
  409.         break;
  410.       case SCULL_P_IOCQSIZE:
  411.         return scull_p_buffer;
  412.       default:  /* redundant, as cmd was checked against MAXNR */
  413.         return -ENOTTY;
  414.     }
  415.     return ret;
  416. }
  417. #else  /* LINUX_20 */
  418. int scull_ioctl(struct inode *inode, struct file *filp,
  419.                  unsigned int cmd, unsigned long arg)
  420. {
  421.     int err = 0, tmp;
  422.     
  423.     /*
  424.      * extract the type and number bitfields, and don't decode
  425.      * wrong cmds: return ENOTTY before verify_area()
  426.      */
  427.     if (_IOC_TYPE(cmd) != SCULL_IOC_MAGIC) return -ENOTTY;
  428.     if (_IOC_NR(cmd) > SCULL_IOC_MAXNR) return -ENOTTY;
  429.     /*
  430.      * the direction is a bitmask, and VERIFY_WRITE catches R/W
  431.      * transfers. `Type' is user-oriented, while
  432.      * verify_area is kernel-oriented, so the concept of "read" and
  433.      * "write" is reversed
  434.      */
  435.     if (_IOC_DIR(cmd) & _IOC_READ)
  436.         err = verify_area(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));
  437.     else if (_IOC_DIR(cmd) & _IOC_WRITE)
  438.         err =  verify_area(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
  439.     if (err) return err;
  440.     switch(cmd) {
  441.       case SCULL_IOCRESET:
  442.         scull_quantum = SCULL_QUANTUM;
  443.         scull_qset = SCULL_QSET;
  444.         break;
  445.         
  446.       case SCULL_IOCSQUANTUM: /* Set: arg points to the value */
  447.         scull_quantum = get_user((int *)arg);
  448.         break;
  449.       case SCULL_IOCTQUANTUM: /* Tell: arg is the value */
  450.         scull_quantum = arg;
  451.         break;
  452.       case SCULL_IOCGQUANTUM: /* Get: arg is pointer to result */
  453.         put_user(scull_quantum, (int *)arg);
  454.         break;
  455.       case SCULL_IOCQQUANTUM: /* Query: return it (it's positive) */
  456.         return scull_quantum;
  457.       case SCULL_IOCXQUANTUM: /* eXchange: use arg as pointer */
  458.         tmp = scull_quantum;
  459.         scull_quantum = get_user((int *)arg);
  460.         put_user(tmp, (int *)arg);
  461.         break;
  462.       case SCULL_IOCHQUANTUM: /* sHift: like Tell + Query */
  463.         tmp = scull_quantum;
  464.         scull_quantum = arg;
  465.         return tmp;
  466.         
  467.       case SCULL_IOCSQSET:
  468.         scull_qset = get_user((int *)arg);
  469.         break;
  470.       case SCULL_IOCTQSET:
  471.         scull_qset = arg;
  472.         break;
  473.       case SCULL_IOCGQSET:
  474.         put_user(scull_qset, (int *)arg);
  475.         break;
  476.       case SCULL_IOCQQSET:
  477.         return scull_qset;
  478.       case SCULL_IOCXQSET:
  479.         tmp = scull_qset;
  480.         scull_qset = get_user((int *)arg);
  481.         put_user(tmp, (int *)arg);
  482.         break;
  483.       case SCULL_IOCHQSET:
  484.         tmp = scull_qset;
  485.         scull_quantum = arg;
  486.         return tmp;
  487.         /*
  488.          * The following two change the buffer size for scullpipe.
  489.          * The scullpipe device uses this same ioctl method, just to
  490.          * write less code. Actually, it's the same driver, isn't it?
  491.          */
  492.       case SCULL_P_IOCTSIZE:
  493.         scull_p_buffer = arg;
  494.         break;
  495.       case SCULL_P_IOCQSIZE:
  496.         return scull_p_buffer;
  497.       default:  /* redundant, as cmd was checked against MAXNR */
  498.         return -ENOTTY;
  499.     }
  500.     return 0;
  501. }
  502. #endif /* LINUX_20 */
  503. /*
  504.  * The "extended" operations -- only seek
  505.  */
  506. loff_t scull_llseek(struct file *filp, loff_t off, int whence)
  507. {
  508.     Scull_Dev *dev = filp->private_data;
  509.     loff_t newpos;
  510.     switch(whence) {
  511.       case 0: /* SEEK_SET */
  512.         newpos = off;
  513.         break;
  514.       case 1: /* SEEK_CUR */
  515.         newpos = filp->f_pos + off;
  516.         break;
  517.       case 2: /* SEEK_END */
  518.         newpos = dev->size + off;
  519.         break;
  520.       default: /* can't happen */
  521.         return -EINVAL;
  522.     }
  523.     if (newpos<0) return -EINVAL;
  524.     filp->f_pos = newpos;
  525.     return newpos;
  526. }
  527. /*
  528.  * The following wrappers are meant to make things work with 2.0 kernels
  529.  */
  530. #ifdef LINUX_20
  531. int scull_lseek_20(struct inode *ino, struct file *f,
  532.                 off_t offset, int whence)
  533. {
  534.     return (int)scull_llseek(f, offset, whence);
  535. }
  536. int scull_read_20(struct inode *ino, struct file *f, char *buf, int count)
  537. {
  538.     return (int)scull_read(f, buf, count, &f->f_pos);
  539. }
  540. int scull_write_20(struct inode *ino, struct file *f, const char *b, int c)
  541. {
  542.     return (int)scull_write(f, b, c, &f->f_pos);
  543. }
  544. void scull_release_20(struct inode *ino, struct file *f)
  545. {
  546.     scull_release(ino, f);
  547. }
  548. /* Redefine "real" names to the 2.0 ones */
  549. #define scull_llseek scull_lseek_20
  550. #define scull_read scull_read_20
  551. #define scull_write scull_write_20
  552. #define scull_release scull_release_20
  553. #define llseek lseek
  554. #endif  /* LINUX_20 */
  555. struct file_operations scull_fops = {
  556.     llseek:     scull_llseek,
  557.     read:       scull_read,
  558.     write:      scull_write,
  559.     ioctl:      scull_ioctl,
  560.     open:       scull_open,
  561.     release:    scull_release,
  562. };
  563. /*
  564.  * Finally, the module stuff
  565.  */
  566. #ifdef CONFIG_DEVFS_FS
  567. devfs_handle_t scull_devfs_dir;
  568. static char devname[4];
  569. #endif
  570. /*
  571.  * The cleanup function is used to handle initialization failures as well.
  572.  * Thefore, it must be careful to work correctly even if some of the items
  573.  * have not been initialized
  574.  */
  575. void scull_cleanup_module(void)
  576. {
  577.     int i;
  578. #ifndef CONFIG_DEVFS_FS
  579.     /* cleanup_module is never called if registering failed */
  580.     unregister_chrdev(scull_major, "scull");
  581. #endif
  582. #ifdef SCULL_DEBUG /* use proc only if debugging */
  583.     scull_remove_proc();
  584. #endif
  585.     if (scull_devices) {
  586.         for (i=0; i<scull_nr_devs; i++) {
  587.             scull_trim(scull_devices+i);
  588.             /* the following line is only used for devfs */
  589.             devfs_unregister(scull_devices[i].handle);
  590.         }
  591.         kfree(scull_devices);
  592.     }
  593.     /* and call the cleanup functions for friend devices */
  594.     scull_p_cleanup();
  595.     scull_access_cleanup();
  596.     /* once again, only for devfs */
  597.     devfs_unregister(scull_devfs_dir);
  598. }
  599. int scull_init_module(void)
  600. {
  601.     int result, i;
  602.     SET_MODULE_OWNER(&scull_fops);
  603. #ifdef CONFIG_DEVFS_FS
  604.     /* If we have devfs, create /dev/scull to put files in there */
  605.     scull_devfs_dir = devfs_mk_dir(NULL, "scull", NULL);
  606.     if (!scull_devfs_dir) return -EBUSY; /* problem */
  607. #else /* no devfs, do it the "classic" way  */    
  608.     /*
  609.      * Register your major, and accept a dynamic number. This is the
  610.      * first thing to do, in order to avoid releasing other module's
  611.      * fops in scull_cleanup_module()
  612.      */
  613.     result = register_chrdev(scull_major, "scull", &scull_fops);
  614.     if (result < 0) {
  615.         printk(KERN_WARNING "scull: can't get major %dn",scull_major);
  616.         return result;
  617.     }
  618.     if (scull_major == 0) scull_major = result; /* dynamic */
  619. #endif /* CONFIG_DEVFS_FS */
  620.     /* 
  621.      * allocate the devices -- we can't have them static, as the number
  622.      * can be specified at load time
  623.      */
  624.     scull_devices = kmalloc(scull_nr_devs * sizeof(Scull_Dev), GFP_KERNEL);
  625.     if (!scull_devices) {
  626.         result = -ENOMEM;
  627.         goto fail;
  628.     }
  629.     memset(scull_devices, 0, scull_nr_devs * sizeof(Scull_Dev));
  630.     for (i=0; i < scull_nr_devs; i++) {
  631.         scull_devices[i].quantum = scull_quantum;
  632.         scull_devices[i].qset = scull_qset;
  633.         sema_init(&scull_devices[i].sem, 1);
  634. #ifdef CONFIG_DEVFS_FS
  635.         sprintf(devname, "%i", i);
  636.         devfs_register(scull_devfs_dir, devname,
  637.                        DEVFS_FL_AUTO_DEVNUM,
  638.                        0, 0, S_IFCHR | S_IRUGO | S_IWUGO,
  639.                        &scull_fops,
  640.                        scull_devices+i);
  641. #endif  
  642.     }
  643.     /* At this point call the init function for any friend device */
  644.     if ( (result = scull_p_init()) )
  645.         goto fail;
  646.     if ( (result = scull_access_init()) )
  647.         goto fail;
  648.     /* ... */
  649. #ifndef SCULL_DEBUG
  650.     EXPORT_NO_SYMBOLS; /* otherwise, leave global symbols visible */
  651. #endif
  652. #ifdef SCULL_DEBUG /* only when debugging */
  653.     scull_create_proc();
  654. #endif
  655.     return 0; /* succeed */
  656.   fail:
  657.     scull_cleanup_module();
  658.     return result;
  659. }
  660. module_init(scull_init_module);
  661. module_exit(scull_cleanup_module);