linux device driver

The ioctl Method
Like char devices, block devices can be acted on by using the ioctl system call.
The only relevant difference between block and char ioctl implementations is that
block drivers share a number of common ioctl commands that most drivers are
expected to support.
The commands that block drivers usually handle are the following, declared in
<linux/fs.h>.
BLKGETSIZE
Retrieve the size of the current device, expressed as the number of sectors.
The value of arg passed in by the system call is a pointer to a long value
The ioctl Method
349
Chapter 12: Loading Block Drivers
and should be used to copy the size to a user-space variable. This ioctl command
is used, for instance, by mkfs to know the size of the filesystem being
created.
BLKFLSBUF
Literally, ‘‘flush buffers.’’ The implementation of this command is the same for
every device and is shown later with the sample code for the whole ioctl
method.
BLKRRPART
Reread the partition table. This command is meaningful only for partitionable
devices, introduced later in this chapter.
BLKRAGET
BLKRASET
Used to get and change the current block-level read-ahead value (the one
stored in the read_ahead array) for the device. For GET, the current value
should be written to user space as a long item using the pointer passed to
ioctl in arg; for SET, the new value is passed as an argument.
BLKFRAGET
BLKFRASET
Get and set the filesystem-level read-ahead value (the one stored in
max_readahead) for this device.
BLKROSET
BLKROGET
These commands are used to change and check the read-only flag for the
device.
BLKSECTGET
BLKSECTSET
These commands retrieve and set the maximum number of sectors per request
(as stored in max_sectors).
BLKSSZGET
Returns the sector size of this block device in the integer variable pointed to
by the caller; this size comes directly from the hardsect_size array.
BLKPG
The BLKPG command allows user-mode programs to add and delete partitions.
It is implemented by blk_ioctl (described shortly), and no drivers in the
mainline kernel provide their own implementation.
350
BLKELVGET
BLKELVSET
These commands allow some control over how the elevator request sorting
algorithm works. As with BLKPG, no driver implements them directly.
HDIO_GETGEO
Defined in <linux/hdreg.h> and used to retrieve the disk geometry. The
geometry should be written to user space in a struct hd_geometry,
which is declared in hdreg.h as well. sbull shows the general implementation
for this command.
The HDIO_GETGEO command is the most commonly used of a series of HDIO_
commands, all defined in <linux/hdreg.h>. The interested reader can look in
ide.c and hd.c for more information about these commands.
Almost all of these ioctl commands are implemented in the same way for all block
devices. The 2.4 kernel has provided a function, blk_ioctl, that may be called to
implement the common commands; it is declared in <linux/blkpg.h>. Often
the only ones that must be implemented in the driver itself are BLKGETSIZE and
HDIO_GETGEO. The driver can then safely pass any other commands to blk_ioctl
for handling.
The sbull device supports only the general commands just listed, because implementing
device-specific commands is no different from the implementation of
commands for char drivers. The ioctl implementation for sbull is as follows:
int sbull_ioctl (struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
int err;
long size;
struct hd_geometry geo;
PDEBUG("ioctl 0x%x 0x%lx/n", cmd, arg);
switch(cmd) {
case BLKGETSIZE:
/* Return the device size, expressed in sectors */
if (!arg) return -EINVAL; /* NULL pointer: not valid */
err = ! access_ok (VERIFY_WRITE, arg, sizeof(long));
if (err) return -EFAULT;
size = blksize*sbull_sizes[MINOR(inode->i_rdev)]
/ sbull_hardsects[MINOR(inode->i_rdev)];
if (copy_to_user((long *) arg, &size, sizeof (long)))
return -EFAULT;
return 0;
case BLKRRPART: /* reread partition table: can’t do it */
return -ENOTTY;
case HDIO_GETGEO:
The ioctl Method
351
Chapter 12: Loading Block Drivers
/*
* Get geometry: since we are a virtual device, we have to make
* upsomething plausible. So we claim 16 sectors, four heads,
* and calculate the corresponding number of cylinders. We set
* the start of data at sector four.
*/
err = ! access_ok(VERIFY_WRITE, arg, sizeof(geo));
if (err) return -EFAULT;
size = sbull_size * blksize / sbull_hardsect;
geo.cylinders = (size & ˜0x3f) >> 6;
geo.heads = 4;
geo.sectors = 16;
geo.start = 4;
if (copy_to_user((void *) arg, &geo, sizeof(geo)))
return -EFAULT;
return 0;
default:
/*
* For ioctls we don’t understand, let the block layer
* handle them.
*/
return blk_ioctl(inode->i_rdev, cmd, arg);
}
return -ENOTTY; /* unknown command */
}
The PDEBUG statement at the beginning of the function has been left in so that
when you compile the module, you can turn on debugging to see which ioctl
commands are invoked on the device.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值