Hot Plug

Hot-pluggable devices have been createdto solve a number of user needs. On laptop computers, PCMCIAdevices were designed to allow the user to swap cards while thecomputer was still running. This allowed people to change networkadaptors, memory cards and even disk drives without shutting downthe machine.

The success of this led to the creation of the USB andIEEE1394 (FireWire) buses. These designs allow for peripherals tobe attached and removed at any point. They also were created to tryto move systems away from the ISA bus to a full Plug-and-Play-typesystem.

From the operating system's point of view, there are manyproblems with hot plugging devices. In the past, the operatingsystem only had to search for the various devices connected to iton power-up, and once seen, the device would never go away. Fromthe view of the device driver, it never expects to have thehardware that it is trying to control disappear. But withhot-pluggable devices, all of this changes.

Now the operating system has to have a mechanism thatconstantly detects if a new device appears. This usually is done bya bus-specific manager. This manager handles the scanning for newdevices and recognizes this disappearance. It must be able tocreate system resources for the new device and pass control off toa specific driver. The device driver for a hot-pluggable device hasto be able to recover gracefully when the hardware is removed andbe able to bind itself to new hardware at any moment. Not only doesthe kernel need to know when devices are removed or added, but theuser also should be notified when this happens. Other kinds ofkernel events, such as the creation of network devices or theinsertion of a laptop into a docking station, also would be usefulfor the user to know about.

This article describes the new framework in the Linux kernelfor supporting USB and other hot-pluggable devices. It covers howthe past implementation of PCMCIA loaded its drivers and theproblems of that system. It presents the current method of loadingUSB and PCI drivers, and how this same framework can handle otherkinds of user configuration issues easily.

The Past

Linux has had support for PCMCIA since 1995. In order for thePCMCIA core to be able to load drivers when a new device wasinserted, it had a user-space program called cardmgr. The cardmgrprogram would receive notification from the kernel's PCMCIA corewhen a device had been inserted or removed and use that informationto load or unload the proper driver for that card. It used aconfiguration file located at /etc/pcmcia/config to determine whichdriver should be used for which card. This configuration fileneeded to be kept up to date with which driver supported whichcard, or ranges of cards, and has grown to be over 1,500 lineslong. Whenever a driver author added support for a new device, theyhad to modify two different files to enable the device to workproperly.

As the USB core code became mature, the group realized thatit also needed something like the PCMCIA system to be able to loadand unload drivers dynamically when devices were inserted andremoved. The group also noted that since USB and PCMCIA both neededthis system, and that other kernel hot-plug subsystems also woulduse such a system, a generic hot-plug core would be useful. DavidBrownell posted an initial patch to the kernel(marc.theaimsgroup.com/?l=linux-usb-devel&m=96334011602320),enabling it to call out to a user-space program called/sbin/hotplug. This patch eventually was accepted, and othersubsystems were modified to take advantage of it.

Let the Computer Do It Itself

All USB and PCI devices contain an identifier that describeseither what kind of functions they support (like a USB audio or USBmass storage device), or if they do not support a classspecification, they contain a unique vendor and product identifier.PCMCIA devices also contain these same kind of identifiers.

These identifiers are known by the PCI and USB kerneldrivers, as they need to know which kind of devices they workproperly for. The USB and PCI kernel drivers register with thekernel a list of the different types of devices that they support.This list is used to determine which driver will control whichdevices.

The kernel knows when and what kind of devices are insertedor removed from the system through the device bus core code (USB,FireWire, PCI, etc.). It can send this information to theuser.

Taking these three pieces together (devices tell the computerwhat they are, drivers know what devices they support and thekernel knows what is going on) provides us with a solution to letthe computer automatically load the proper driver whenever a newdevice is inserted.

/sbin/hotplug

The kernel hot-plug core provides a method for the kernel tonotify user space that something has happened. The CONFIG_HOTPLUGconfiguration item needs to be selected for this code to beenabled. The notification happens when the kernel calls theexecutable listed in the global variable hotplug_path. When thekernel starts, hotplug_path is set to /sbin/hotplug, but the usercan modify the value at /proc/sys/kernel/hotplug to change this.The kernel function call_usermodehelper() executes/sbin/hotplug.

As of kernel 2.4.14, the /sbin/hotplug method is being usedby the PCI, USB, IEEE1394 and Network core subsystems. As time goeson, more subsystems will be converted to use it. Patches areavailable for the PnP-BIOS (notification when a laptop is insertedand removed from a docking station), Hot-Plug CPU, SCSI and IDEkernel subsystems. These are expected to be merged into the mainkernel over time.

When /sbin/hotplug is called, different environment variablesare set, depending on what action has just occurred.

PCI

PCI devices call /sbin/hotplug with the followingarguments:

argv [0] = hotplug_path
argv [1] = "pci"
argv [2] = 0

and the system environment is set to the following:

HOME=/
PATH=/sbin:/bin:/usr/sbin:/usr/bin
PCI_CLASS=class_code
PCI_ID=vendor:device
PCI_SUBSYS_ID=subsystem_vendor:subsystem_device
PCI_SLOT_NAME=slot_name
ACTION=action
The action setting is “add” or “remove” depending on whetherthe device is being inserted or removed from the system. Theclass_code, vendor, subsystem_vendor, subsystem_device andslot_name environment settings represent the numerical values forthe PCI device's information.
USB

USB devices call /sbin/hotplug with the followingarguments:

argv [0] = hotplug_path
argv [1] = "usb"
argv [2] = 0

and the system environment is set to the following:

HOME=/
PATH=/sbin:/bin:/usr/sbin:/usr/bin
ACTION=action
PRODUCT=idVendor/idProduct/bcdDevice
TYPE=device_class/device_subclass/device_protocol
The action setting is “add” or “remove” depending on whetherthe device is being inserted or removed from the system, andidVendor, idProduct, bcdDevice, device_class, device_subclass anddevice_protocol are filled in with the information from the USBdevice's descriptors.

If the USB device's deviceClass is 0 then the environmentvariable INTERFACE is set to:

INTERFACE=class/subclass/protocol

This is because USB has a much more complex model for deviceconfiguration than PCI does.

If the USB subsystem is compiled with the usbdevfs filesystemenabled, the following environment variables also are set:

DEVFS=/proc/bus/usb
DEVICE=/proc/bus/usb/bus_number/device_number

where bus_number and device_number are set to the bus numberand device number that this specific USB device is assigned.

Network

The network core code calls /sbin/hotplug whenever a networkdevice is registered or unregistered with the network subsystem,and /sbin/hotplug is called with the following arguments whencalled from the network core:

argv [0] = hotplug_path
argv [1] = "net"
argv [2] = 0

and the system environment is set to the following:

HOME=/
PATH=/sbin:/bin:/usr/sbin:/usr/bin
INTERFACE=interface
ACTION=action
The action setting is “register” or “unregister” depending onwhat happened in the network core, and interface is the name of theinterface that just had the action applied to itself.
CPU

The Hot-Plug CPU patch (available atsourceforge.net/projects/lhcs)calls /sbin/hotplug after a CPU is removed or added to the system,and /sbin/hotplug is called with the following arguments:

argv [0] = hotplug_path
argv [1] = "cpu"
argv [2] = 0

and the system environment is set to the following:

HOME=/
PATH=/sbin:/bin:/usr/sbin:/usr/bin
CPU=cpu_number
ACTION=action
The action setting is “add” or “remove” depending on whathappened to the CPU, and cpu_number is the number of the CPU thatjust had the action applied to itself.
Examples

The /sbin/hotplug script can be a very simple script if youonly want it to control a small number of devices. For example, ifyou have a USB mouse and wish to load and unload the kernel driverwhenever the mouse is inserted or removed, the following script,located at /sbin/hotplug, would be sufficient:

#!/bin/sh
if [ "$1" = "usb" ]; then
    if [ "$INTERFACE" = "3/1/2" ]; then
        if [ "$ACTION" = "add" ]; then
            modprobe usbmouse
        else
            rmmod usbmouse
        fi
    fi
fi

Or if you want to run ColdSync(www.ooblick.com/software/coldsync)automatically when you connect your USB HandSpring Visor to thecomputer, the following script located at /sbin/hotplug would workwell:

#!/bin/sh
USER=gregkh
if [ "$1" = "usb" ]; then
    if [ "$PRODUCT" = "82d/100/0" ]; then
        if [ "$ACTION" = "add" ]; then
            modprobe visor
            su $USER - -c "/usr/bin/coldsync"
        else
            rmmod visor
        fi
    fi
fi
If you want to make sure that your network devices always come upconnected to the proper Ethernet card, the following /sbin/hotplugscript, contributed by Sukadev Bhattiprolu, can do this:
#!/bin/sh
if [ "$1" = "network" ]; then
    if [ "$ACTION" = "register" ]; then
        nameif -r $INTERFACE -c /etc/mactab
    fi
fi
Listing 1 shows a more complex example that can handleautomatically loading and unloading modules for three different USBdevices.

Listing 1. Script to Load and UnloadModules Automatically for Three Different USBDevices

Need for Automation

The previous small example shows the limitations of beingforced to enter in all of the different device IDs manually,product IDs and such in order to keep a /sbin/hotplug script up todate with all of the different devices that the kernel knows about.Instead, it would be better for the kernel itself to specify thedifferent types of devices that it supports in such a way that anyuser-space tools could read them. Thus was born a macro calledMODULE_DEVICE_TABLE() that is used by all USB and PCI drivers. Thismacro describes which devices each specific driver can support. Atcompilation time, the build process extracts this information outof the driver and builds a table. The table is calledmodules.pcimap and modules.usbmap for all PCI and USB devices,respectively, and exists in the directory/lib/modules/kernel_version/.

For example, the following code snippet fromdrivers/net/eepro100.c:

static struct pci_device_id eepro100_pci_tbl[]
__devinitdata = {
    { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557,
      PCI_ANY_ID, PCI_ANY_ID, },
    { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82562ET,
      PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL
          _82559ER, PCI_ANY_ID, PCI_ANY_ID,
},
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL
          _ID1029, PCI_ANY_ID, PCI_ANY_ID,
},
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL
          _ID1030, PCI_ANY_ID, PCI_ANY_ID,
},
        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL
          _82801BA_7, PCI_ANY_ID, PCI_ANY_ID,
},
        { 0,}
    };
    MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl);

causes these lines to be added to the modules.pcimap file:

eepro100 0x00008086 0x00001229 0xffffffff 0xffffffff
0x00000000 0x00000000 0x00000000
eepro100 0x00008086 0x00001031 0xffffffff 0xffffffff
0x00000000 0x00000000 0x00000000
eepro100 0x00008086 0x00001209 0xffffffff 0xffffffff
0x00000000 0x00000000 0x00000000
eepro100 0x00008086 0x00001029 0xffffffff 0xffffffff
0x00000000 0x00000000 0x00000000
eepro100 0x00008086 0x00001030 0xffffffff 0xffffffff
0x00000000 0x00000000 0x00000000
eepro100 0x00008086 0x00002449 0xffffffff 0xffffffff
0x00000000 0x00000000 0x00000000
As the example shows, a PCI device can be specified by any of thesame parameters that are passed to the /sbin/hotplug program.

A USB device can specify that it can accept only specificdevices such as this example from drivers/usb/mdc800.c:

static struct usb_device_id
  mdc800_table [] = {
   { USB_DEVICE(MDC800_VENDOR_ID, MDC800_PRODUCT_ID) },
   { } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, mdc800_table);

which causes the following line to be added to themodules.usbmap file:

mdc800 0x0003 0x055f 0xa800 0x0000 0x0000 0x00 0x00
0x00 0x00 0x00 0x00 0x00000000
Or it can specify that it accepts any device that matches aspecific USB class code, as in this example fromdrivers/usb/printer.c:
static struct usb_device_id usblp_ids [] = {
  { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 1) },
  { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 2) },
  { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 3) },
  { }    /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, usblp_ids);
which causes the following lines to be added to the modules.usbmapfile:
printer 0x0380 0x0000 0x0000 0x0000 0x0000 0x00 0x00
0x00 0x07 0x01 0x01 0x00000000
printer 0x0380 0x0000 0x0000 0x0000 0x0000 0x00 0x00
0x00 0x07 0x01 0x02 0x00000000
printer 0x0380 0x0000 0x0000 0x0000 0x0000 0x00 0x00
0x00 0x07 0x01 0x03 0x00000000
Again these USB examples show that the information in themodules.usbmap file matches the information provided to/sbin/hotplug by the kernel, enabling /sbin/hotplug to determinewhich driver to load without relying on a hand-generated table, asPCMCIA does.
Preprocessor Abuse

The macro MODULE_DEVICE_TABLE automatically creates twovariables. For the example: MODULE_DEVICE_TABLE (usb, usblp_ids);the variables __module_usb_device_size and__module_usb_device_table are created and placed into the read-onlydata section and the initialized data section of the module,respectively. The variable __module_usb_device_size contains thevalue of the size of the struct usb_id structure, and__module_usb_device_table points to the usblp_ids structure. Theusblp_ids variable is an array of usb_id structures with aterminating NULL structure at the end of the list.

When the depmod program is run, as part of the kernelinstallation process, it goes through every module looking for thesymbol __module_usb_device_size to be present in the compiledmodule. If it finds it, it copies the data pointed to by the__module_usb_device_table symbol into a structure, extracts all ofthe information and writes it out to the modules.usbmap file, whichis located in the module root directory. It does the same thingwhile looking for the __module_pci_device_size in creating themodules.pcimap file.

With the kernel module information exported to the filesmodules.usbmap and modules.pcimap, our version of /sbin/hotplug canlook like Listing 2 [available atftp.linuxjournal.com/pub/lj/listings/issue96/5604.tgz].This example only tests for a match of the USB product ID andvendor IDs. The Linux-Hotplug Project has created a set of scriptsthat covers all of the different subsystems that can call/sbin/hotplug. This enables drivers to be loaded automatically whennew devices are inserted into the systems. It also starts upnetwork services when network devices are seen. These scripts arereleased under the GPL and are available atlinux-hotplug.sourceforge.net.Almost all major Linux distributions are currently shipping thispackage, so it is probably already on your machine.

The Future

The current /sbin/hotplug subsystem needs to be incorporatedinto other kernel systems, as they develop hot-plug capability.SCSI, IDE and other systems all have hot-plug patches available forkernel support but need to have script support, kernel macrosupport and modutils depmod support added in order to provide theuser with a consistent experience.

As the kernel boots, and discovers new devices, it tries tospawn /sbin/hotplug, but since user space has not been initializedyet, it cannot run. This means that any USB or PCI devices that areneeded at boot time need to be compiled into the kernel or exist inan initrd RAM disk image as a module. Sometime during the 2.5development process, the initrd RAM disk image will be converted tocontain an entire small user-space tree. This will allow/sbin/hotplug to be run during the boot process and load modulesdynamically. Some links describing this disk image idea are:lwn.net/2001/0712/kernel.php3 --marc.theaimsgroup.com/?l=acpi4linux&m=99705696732868 --marc.theaimsgroup.com/?l=linux-kernel&m=99436439232254andmarc.theaimsgroup.com/?l=linux-kernel&m=99436253707952.

Because of the small space requirements of this RAM diskimage, the dietHotplug program has been written. It is animplementation of the Linux-Hotplug bash scripts in C and does notrequire modules.*map files when the program runs. The executablesize of the entire dietHotplug program is one-fifth of the size ofthe original modules.*map files themselves. The small size is dueto the use of dietLibc (found atwww.fefe.de/dietlibc)and other space-saving techniques.dietHotplug will undergo moredevelopment as the 2.5 kernel requirements are more fully known.dietHotplug can be downloaded fromthe Linux-Hotplug site.

Acknowledgements

I would like to thank David Brownell who wrote the original/sbin/hotplug kernel patch and most of the Linux Hotplug scripts.Without his persistence, Linux would not have this user-friendlyfeature. I also would like to acknowledge the entire Linux USBdevelopment team, who have provided a solid kernel subsystem in arelatively short amount of time.

Keith Owens wrote the supporting code in the depmod utilityand has endured constant changes to the format of theMODULE_DEVICE_TABLE() USB structure.

The other developers on the linux-hotplug-devel mailing listwho have helped with their patches and feedback on the hot-plugscripts also deserve recognition, along with the wonderful Linuxdistribution-specific support that Debian, Red Hat and Mandrakehave provided.

This article was based upon a paper and presentation that Igave at the 2001 Ottawa Linux Symposium.

Greg Kroah-Hartman is currently the Linux USB and PCI Hotplug kernel maintainer. He works for IBM, doing various LInux kernel-related things and can be reached at greg@kroah.com.

原文:http://www.linuxjournal.com/node/5604/print

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值