Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
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