Documente Academic
Documente Profesional
Documente Cultură
CSIE, NCKU
The information on the slides are from Linux Device Drivers, Third Edition, by Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman. Copyright 2005 OReilly Media, Inc., 0-596-00590-3.
Persistent
Data remains even when the device is closed
Char devices
Major Minor
Device name
But Linux allows multiple drivers share the same major number
count: total number of contiguous device numbers you are requesting name: the name of the device
An Example of /proc/devices
Character devices: 1 mem 2 pty 3 ttyp 4 ttyS 6 lp 7 vcs 10 misc 13 input 14 sound 21 sg 180 usb Block devices: 2 fd 8 sd 11 sr 65 sd 66 sd
File Operations
Let the accesses go to the driver
Why? .. because device FILE
The syntax is more portable across changes in the definitions of the structures
};
Others functions are not implemented by the scull driver Handled by the kernel default handler
Important fields
mode_t f_mode
read/write permission
void *private_data
For your private use Usually be used to preserve state information across system calls
Method 2
void cdev_init(struct cdev *cdev, struct file_operations *fops);
In either way,
my_cdev->owner = THIS_MODULE;
The registration may fail should check it Once the registration succeeds, kernel will call your operations prepare for that Remove a char device
void cdev_del(struct cdev *dev);
Unregistration
int unregister_chrdev(unsigned int major, const char *name);
Open Method
Initialization and preparation for later operations Usually perform the following Jobs
Check for device-specific errors Initialize the device Update the f_op pointer, if necessary Allocate and fill any data structure to be put in filp->private_data
Open Method
Which scull device is being opened?
int (*open)(struct inode *inode, struct file *filp);
Get the cdev
inode->i_cdev
scull_open()
Introduced later
scull_dev.qset
scull_dev.quantum
Scull_trim()
int scull_trim(struct scull_dev *dev) { struct scull_qset *next, *dptr; int qset = dev->qset; /* "dev" is not-null */ int i; for (dptr = dev->data; dptr; dptr = next) { /* all the list items */ if (dptr->data) { for (i = 0; i < qset; i++) kfree(dptr->data[i]); // free the quantums in a qset kfree(dptr->data); // free qsets data dptr->data = NULL; } next = dptr->next; kfree(dptr); // free the qset data structure } dev->size = 0; dev->quantum = scull_quantum; dev->qset = scull_qset; dev->data = NULL; return 0;}
Be careful
Kernel crashes Security holes
R=0
EOF
R<0
Error
Scull_read()
// EOF, return 0
Scull_read()
Scull_write()
ssize_t scull_write (struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { struct scull_dev *dev = filp->private_data; struct scull_qset *dptr; int quantum = dev->quantum, qset = dev->qset; int itemsize = quantum * qset; int item, s_pos, q_pos, rest; ssize_t retval = -ENOMEM; /* value used in "goto out" statements */ find listitem, qset index and offset in the quantum skipped dptr = scull_follow(dev, item); if (dptr = = NULL) goto out; if (!dptr->data) { dptr->data = kmalloc (qset * sizeof(char *), GFP_KERNEL); if (!dptr->data) goto out; // no free memory!!! memset (dptr->data, 0, qset * sizeof(char *)); }
Scull_write()
if (!dptr->data[s_pos]) { dptr->data[s_pos] = kmalloc (quantum, GFP_KERNEL); //allocate the quantum if (!dptr->data[s_pos]) goto out; } /* write only up to the end of this quantum */ if (count > quantum - q_pos) count = quantum - q_pos; if (copy_from_user (dptr->data[s_pos]+q_pos, buf, count)) { retval = -EFAULT; goto out; } *f_pos += count; retval = count; // f_pos should reflect the current RW head /* update the size */ if (dev->size < *f_pos) dev->size = *f_pos; out: up(&dev->sem); return retval; }
Scatter-Gather Read/Write
Read/write data from/to multiple buffers in a single operation
readv and writev
iovec structure
Used to specify the address range of a buffer
An array of iovec structures is passed to readv() or writev() A driver can implement readv() and writev() methods if it benefits from scatter-gather IO