Run-Time Configuration

A user might occasionally want to change the interface configuration at run time. If, for example, the IRQ number can’t be probed for, the only way to have it properly configured is through a trial-and-error technique. A user-space program can retrieve the device’s current configuration or set a new configuration by invoking ioctl on an open socket. The ifconfig application, for instance, uses ioctl to set the I/O port for an interface.

We saw earlier how one of the methods defined for network interface is set_config. The method is used to set or change some interface features at run time.

When a program asks for the current configuration, the kernel extracts the information from struct device without notifying the driver; on the other hand, when a new configuration is passed to the interface, the set_config method is called so the driver can check the values being passed and take appropriate action. The driver method responds to the following prototype:

int (*set_config)(struct device *dev, struct ifmap *map);

The map argument points to a copy of the structure passed by the user program; the copy is already in kernel space, so the driver doesn’t need to call memcpy_from_fs.

The fields of struct ifmap are:

unsigned long mem_start; , unsigned long mem_end; , unsigned short base_addr; , unsigned char irq; , unsigned char dma;

These fields correspond to the fields in struct device.

unsigned char port;

This field corresponds to if_port, as found in dev. The meaning of map->port is device-specific.

The set_config device method is called when a process issues ioctl(SIOCSIFMAP) (Socket I/O Control Set InterFace MAP) for the device. The process should issue ioctl(SIOCGIFMAP) (Socket I/O Control Get InterFace MAP) before trying to force new values on, so the driver will just look for mismatches between struct dev and struct ifmap. Any fields in map that are not used by the driver can be skipped. For instance, a network device not using DMA ignores map->dma.

The snull implementation is designed to show how the driver can behave with respect to configuration changes. None of the fields has any physical sense for the snull driver. But for the sake of illustration, the code prohibits changes to the I/O address, allows changes to the IRQ number, and ignores other options in order to show how the changes are acknowledged, refused, or ignored.

int snull_config(struct device *dev, struct ifmap *map)
{
    if (dev->flags & IFF_UP) /* can't act on a running interface */
        return -EBUSY;

    /* Don't allow changing the I/O address */
    if (map->base_addr != dev->base_addr) {
        printk(KERN_WARNING "snull: Can't change I/O address
");
        return -EOPNOTSUPP;
    }

    /* Allow changing the IRQ */
    if (map->irq != dev->irq) {
        dev->irq = map->irq;
        /* request_irq() is delayed to open-time */
    }

    /* ignore other fields */
    return 0;
}

The return value of the method is used as the return value for the outstanding ioctl system call, and -EOPNOTSUPP is returned for drivers that don’t implement set_config.

If you are curious about how the interface configuration is accessed from user space, look in misc-progs/netifconfig.c, which can be used to play with set_config. Here is the output from a sample run:

morgana.root# ./netifconfig sn0
sn0: mem=0x0-0x0, io=0x0, irq=0, dma=0, port=0
morgana.root# ./netifconfig sn0 irq=4
./netifconfig: ioctl(SIOCSIFMAP): Device or resource busy
morgana.root# ifconfig sn0 down
morgana.root# ./netifconfig sn0 irq=4 tell
sn0: mem=0x0-0x0, io=0x0, irq=4, dma=0, port=0
morgana.root# ./netifconfig eth0
eth0: mem=0x0-0x0, io=0x300, irq=5, dma=0, port=0
morgana.root# ./netifconfig eth0 io=0x400
./netifconfig: ioctl(SIOCSIFMAP): Operation not supported on transport
endpoint
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.202.167