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

📄 ldd ——scull(main.c).txt

📁 详细介绍的scull字符设备驱动程序的实现!
💻 TXT
📖 第 1 页 / 共 2 页
字号:
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 
 17 /* 
 18 #include <linux/config.h>
 19 */
 20 #include <linux/module.h>
 21 #include <linux/moduleparam.h>
 22 #include <linux/init.h>
 23 
 24 #include <linux/kernel.h>       /* printk() */
 25 #include <linux/slab.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 <linux/seq_file.h>
 32 #include <linux/cdev.h>
 33 
 34 #include <asm/system.h>         /* cli(), *_flags */
 35 #include <asm/uaccess.h>        /* copy_*_user */
 36 
 37 #include "scull.h"              /* local definitions */
 38 
 39 /*
 40  * Our parameters which can be set at load time.
 41  */
 42 
 43 int scull_major =   SCULL_MAJOR;
 44 int scull_minor =   0;
 45 int scull_nr_devs = SCULL_NR_DEVS;      /* number of bare scull devices */
 46 int scull_quantum = SCULL_QUANTUM;
 47 int scull_qset =    SCULL_QSET;
 48 
 49 module_param(scull_major, int, S_IRUGO);
 50 module_param(scull_minor, int, S_IRUGO);
 51 module_param(scull_nr_devs, int, S_IRUGO);
 52 module_param(scull_quantum, int, S_IRUGO);
 53 module_param(scull_qset, int, S_IRUGO);
 54 
 55 MODULE_AUTHOR("Alessandro Rubini, Jonathan Corbet");
 56 MODULE_LICENSE("Dual BSD/GPL");
 57 
 58 struct scull_dev *scull_devices;        /* allocated in scull_init_module */
 59 
 60 
 61 /*
 62  * Empty out the scull device; must be called with the device
 63  * semaphore held.
 64  */
 65 int scull_trim(struct scull_dev *dev)
 66 {
 67         struct scull_qset *next, *dptr;
 68         int qset = dev->qset;   /* "dev" is not-null */
 69         int i;
 70 
 71         for (dptr = dev->data; dptr; dptr = next) { /* all the list items */
 72                 if (dptr->data) {
 73                         for (i = 0; i < qset; i++)
 74                                 kfree(dptr->data[i]);
 75                         kfree(dptr->data);
 76                         dptr->data = NULL;
 77                 }
 78                 next = dptr->next;
 79                 kfree(dptr);
 80         }
 81         dev->size = 0;
 82         dev->quantum = scull_quantum;
 83         dev->qset = scull_qset;
 84         dev->data = NULL;
 85         return 0;
 86 }
 87 #ifdef SCULL_DEBUG /* use proc only if debugging */
 88 /*
 89  * The proc filesystem: function to read and entry
 90  */
 91 
 92 int scull_read_procmem(char *buf, char **start, off_t offset,
 93                    int count, int *eof, void *data)
 94 {
 95         int i, j, len = 0;
 96         int limit = count - 80; /* Don't print more than this */
 97 
 98         for (i = 0; i < scull_nr_devs && len <= limit; i++) {
 99                 struct scull_dev *d = &scull_devices[i];
100                 struct scull_qset *qs = d->data;
101                 if (down_interruptible(&d->sem))
102                         return -ERESTARTSYS;
103                 len += sprintf(buf+len,"\nDevice %i: qset %i, q %i, sz %li\n",
104                                 i, d->qset, d->quantum, d->size);
105                 for (; qs && len <= limit; qs = qs->next) { /* scan the list */
106                         len += sprintf(buf + len, "  item at %p, qset at %p\n",
107                                         qs, qs->data);
108                         if (qs->data && !qs->next) /* dump only the last item */
109                                 for (j = 0; j < d->qset; j++) {
110                                         if (qs->data[j])
111                                                 len += sprintf(buf + len,
112                                                                 "    % 4i: %8p\n",
113                                                                 j, qs->data[j]);
114                                 }
115                 }
116                 up(&scull_devices[i].sem);
117         }
118         *eof = 1;
119         return len;
120 }
121 
122 
123 /*
124  * For now, the seq_file implementation will exist in parallel.  The
125  * older read_procmem function should maybe go away, though.
126  */
127 
128 /*
129  * Here are our sequence iteration methods.  Our "position" is
130  * simply the device number.
131  */
132 static void *scull_seq_start(struct seq_file *s, loff_t *pos)
133 {
134         if (*pos >= scull_nr_devs)
135                 return NULL;   /* No more to read */
136         return scull_devices + *pos;
137 }
138 
139 static void *scull_seq_next(struct seq_file *s, void *v, loff_t *pos)
140 {
141         (*pos)++;
142         if (*pos >= scull_nr_devs)
143                 return NULL;
144         return scull_devices + *pos;
145 }
146 
147 static void scull_seq_stop(struct seq_file *s, void *v)
148 {
149         /* Actually, there's nothing to do here */
150 }
151 
152 static int scull_seq_show(struct seq_file *s, void *v)
153 {
154         struct scull_dev *dev = (struct scull_dev *) v;
155         struct scull_qset *d;
156         int i;
157 
158         if (down_interruptible(&dev->sem))
159                 return -ERESTARTSYS;
160         seq_printf(s, "\nDevice %i: qset %i, q %i, sz %li\n",
161                         (int) (dev - scull_devices), dev->qset,
162                         dev->quantum, dev->size);
163         for (d = dev->data; d; d = d->next) { /* scan the list */
164                 seq_printf(s, "  item at %p, qset at %p\n", d, d->data);
165                 if (d->data && !d->next) /* dump only the last item */
166                         for (i = 0; i < dev->qset; i++) {
167                                 if (d->data[i])
168                                         seq_printf(s, "    % 4i: %8p\n",
169                                                         i, d->data[i]);
170                         }
171         }
172         up(&dev->sem);
173         return 0;
174 }
175         
176 /*
177  * Tie the sequence operators up.
178  */
179 static struct seq_operations scull_seq_ops = {
180         .start = scull_seq_start,
181         .next  = scull_seq_next,
182         .stop  = scull_seq_stop,
183         .show  = scull_seq_show
184 };
185 
186 /*
187  * Now to implement the /proc file we need only make an open
188  * method which sets up the sequence operators.
189  */
190 static int scull_proc_open(struct inode *inode, struct file *file)
191 {
192         return seq_open(file, &scull_seq_ops);
193 }
194 
195 /*
196  * Create a set of file operations for our proc file.
197  */
198 static struct file_operations scull_proc_ops = {
199         .owner   = THIS_MODULE,
200         .open    = scull_proc_open,
201         .read    = seq_read,
202         .llseek  = seq_lseek,
203         .release = seq_release
204 };
205         
206 
207 /*
208  * Actually create (and remove) the /proc file(s).
209  */
210 
211 static void scull_create_proc(void)
212 {
213         struct proc_dir_entry *entry;
214         create_proc_read_entry("scullmem", 0 /* default mode */,
215                         NULL /* parent dir */, scull_read_procmem,
216                         NULL /* client data */);
217         entry = create_proc_entry("scullseq", 0, NULL);
218         if (entry)
219                 entry->proc_fops = &scull_proc_ops;
220 }
221 
222 static void scull_remove_proc(void)
223 {
224         /* no problem if it was not registered */
225         remove_proc_entry("scullmem", NULL /* parent dir */);
226         remove_proc_entry("scullseq", NULL);
227 }
228 
229 
230 #endif /* SCULL_DEBUG */
231 
232 
233 
234 
235 
236 /*
237  * Open and close
238  */
239 
240 int scull_open(struct inode *inode, struct file *filp)
241 {
242         struct scull_dev *dev; /* device information */
243 
244         dev = container_of(inode->i_cdev, struct scull_dev, cdev);
245         filp->private_data = dev; /* for other methods */
246 
247         /* now trim to 0 the length of the device if open was write-only */
248         if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) {
249                 if (down_interruptible(&dev->sem))
250                         return -ERESTARTSYS;
251                 scull_trim(dev); /* ignore errors */
252                 up(&dev->sem);
253         }
254         return 0;          /* success */
255 }
256 
257 int scull_release(struct inode *inode, struct file *filp)
258 {
259         return 0;
260 }
261 /*
262  * Follow the list
263  */
264 struct scull_qset *scull_follow(struct scull_dev *dev, int n)
265 {
266         struct scull_qset *qs = dev->data;
267 
268         /* Allocate first qset explicitly if need be */
269         if (! qs) {
270                 qs = dev->data = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
271                 if (qs == NULL)
272                         return NULL;  /* Never mind */
273                 memset(qs, 0, sizeof(struct scull_qset));
274         }
275 
276         /* Then follow the list */
277         while (n--) {
278                 if (!qs->next) {
279                         qs->next = kmalloc(sizeof(struct scull_qset), GFP_KERNEL);
280                         if (qs->next == NULL)
281                                 return NULL;  /* Never mind */
282                         memset(qs->next, 0, sizeof(struct scull_qset));
283                 }
284                 qs = qs->next;
285                 continue;
286         }
287         return qs;
288 }
289 
290 /*
291  * Data management: read and write
292  */
293 
294 ssize_t scull_read(struct file *filp, char __user *buf, size_t count,
295                 loff_t *f_pos)
296 {
297         struct scull_dev *dev = filp->private_data; 
298         struct scull_qset *dptr;        /* the first listitem */
299         int quantum = dev->quantum, qset = dev->qset;
300         int itemsize = quantum * qset; /* how many bytes in the listitem */
301         int item, s_pos, q_pos, rest;
302         ssize_t retval = 0;
303 
304         if (down_interruptible(&dev->sem))
305                 return -ERESTARTSYS;
306         if (*f_pos >= dev->size)
307                 goto out;
308         if (*f_pos + count > dev->size)
309                 count = dev->size - *f_pos;
310 
311         /* find listitem, qset index, and offset in the quantum */
312         item = (long)*f_pos / itemsize;
313         rest = (long)*f_pos % itemsize;
314         s_pos = rest / quantum; q_pos = rest % quantum;
315 
316         /* follow the list up to the right position (defined elsewhere) */
317         dptr = scull_follow(dev, item);
318 
319         if (dptr == NULL || !dptr->data || ! dptr->data[s_pos])
320                 goto out; /* don't fill holes */
321 
322         /* read only up to the end of this quantum */
323         if (count > quantum - q_pos)
324                 count = quantum - q_pos;
325 
326         if (copy_to_user(buf, dptr->data[s_pos] + q_pos, count)) {
327                 retval = -EFAULT;
328                 goto out;
329         }
330         *f_pos += count;
331         retval = count;
332 
333   out:
334         up(&dev->sem);
335         return retval;
336 }
337 
338 ssize_t scull_write(struct file *filp, const char __user *buf, size_t count,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -