LINUX USBドライバのシステム学習を開始する(一般的なドライバフロー)
10620 ワード
USBシリアルポート駆動pl 2303を例として解析する.
まず、genericに定義された総管理usbデバイスの駆動が必要です.cのusb_device_driver;この構造はusb.cに登録する:
usb_register_device_driver(&usb_generic_driver, THIS_MODULE) -> driver_register(これはusbデバイス駆動、for_devices=1);
覚えておいてください.usbドライバアーキテクチャ全体にこのようなデバイスドライバが登録されています.
次に、具体的なデバイスのusb駆動usb_driver(PL 2303など)は、usbを使用しています.register ->usb_register_driver -> driver_registerが登録する(これはUSB interfaceドライバを登録し、for_devices=0):
これにより、driverはUSBバスに追加されます.しかし、まだデバイスはありません.これはdeivceが動的にロードを作成するためです.USBサブシステムがロードされると、カーネルスレッドが起動します.
kthread_run(hub_thread,NULL,“khubd”)は、usbデバイスのホットスワップイベントを監視し、デバイスの概略的な流れを発見する.
hub_events -> hub_port_connect_change -> usb_alloc_dev->udevを作成し、値を割り当てます.
dev->dev.bus = &usb_bus_type; dev->dev.type = &usb_device_type;//これは後でデバイスに一致します.driverの根拠dev->dev.groups=usb_device_groups;
->usb_new_device(udev) -> device_add、これにより、検出されたUSBデバイスがUSBバスusb_に追加されるbus_typeが上がった.
そしてdevice_add -> bus_probe_デバイスではbus_が使用されますfor_each_drvは、前にusbバスに登録されているドライバを巡り、このときバスにはdeviceがたくさんあります.driverですが、前のusbを呼び出します.register_device_driverが登録した汎用デバイス記述子解析駆動.
これはどのようにマッチしていますか?USBバスusb_へbus_typeのmatch関数はマッチングルールを見てわかります.
インタフェース駆動ではなくデバイス駆動が一致すると予想され、is_usb_デバイス関数の定義は、次のとおりです.
前のusb_によるとalloc_devの付与値、この条件はすでに一致している.続いてis_usb_device_driver関数の定義:
ちょうどここだdevicesの前に1を割り当て、usb_device_matchはマッチングに成功しnewを見つけたdriver->drvwrap.driverというデバイスdriver、彼のprobeメソッドを呼び出します->usb_probe_device:
簡単な判断をしてgenericを呼び出すcのusb_device_driver構造体のprobe.再度、これは汎用的な構成記述子駆動であり、上述の分割に基づいて、すべてのusb挿入装置が分析した規則に基づいてそれを見つけ、彼のprobe方法を呼び出して構成記述子を得ることを強調する.
主な仕事はusb_set_configurationでは、選択した構成記述子に基づいてデバイスに設定され、その構成下のインタフェースを有効にし、各インタフェースをdeviceとして抽象化し、device_add(&intf->dev)をUSBバスに追加します.重要なコードクリップは次のとおりです.
今回はdevice_addはまたバスのデバイスに一致しますドライブは?前のmatchの方法を見てみましょう.
この条件が成立し、usb_を呼び出すmatch_id(intf,usb_drv->id_table)とusb_match_dynamic_idマッチングとは、このように言いましょう.ここでは、USBデバイスから道徳PID、VID、ドライバで定義されたものをマッチングし、あればマッチングに成功します.我々PL 2303のid_tableは多く定義されており、新しいIDを追加する場合は、そのid_tableを追加すればいいです.
マッチングに成功したら、汎用usb_を呼び出します.probe_interface:
具体的な駆動のprobeを呼び出します.ここでPL 2303のprobeです.
usb_serial_probe、ここで面白いことを見ました.usb-serial.cのprobeもusb_を指していますserial_probe、まずusb-serialを見つけたはずだ.cのporbeは、pl 2303のprobeを見つけます.ここはusb-serialかもしれません.cは共通の関数インタフェースコードとしてPID,VIDを定義していない.しかし、USBコアのマッチングルールは、あいにくそのIDにマッチングするので、USBのアーキテクチャに合わせるためにusb serialも他に良い方法がないので、PL 2303のprobeをusb-serialに向けるしかない.cのporbeは,このprobeで端点記述子を統一的に処理する.
以上から分かるように、USBサブシステムはすでに私たちのために大部分のアーキテクチャを実現しており、私たちが駆動することはインタフェースディスクリプタ(interface descriptor)の処理を実現すればよいので、USBプロトコル規則と具体的なUSBチップマニュアルに基づいて操作する必要があります.
次の記事では、一般的なUSBプロトコルと特定のインタフェース記述子駆動を分析します.
まず、genericに定義された総管理usbデバイスの駆動が必要です.cのusb_device_driver;この構造はusb.cに登録する:
int usb_register_device_driver(struct usb_device_driver *new_udriver,
struct module *owner)
{
int retval = 0;
if (usb_disabled())
return -ENODEV;
new_udriver->drvwrap.for_devices = 1;
new_udriver->drvwrap.driver.name = (char *) new_udriver->name;
new_udriver->drvwrap.driver.bus = &usb_bus_type;
new_udriver->drvwrap.driver.probe = usb_probe_device;
new_udriver->drvwrap.driver.remove = usb_unbind_device;
new_udriver->drvwrap.driver.owner = owner;
retval = driver_register(&new_udriver->drvwrap.driver);
if (!retval) {
pr_info("%s: registered new device driver %s
",
usbcore_name, new_udriver->name);
usbfs_update_special();
} else {
printk(KERN_ERR "%s: error %d registering device "
" driver %s
",
usbcore_name, retval, new_udriver->name);
}
return retval;
}
usb_register_device_driver(&usb_generic_driver, THIS_MODULE) -> driver_register(これはusbデバイス駆動、for_devices=1);
覚えておいてください.usbドライバアーキテクチャ全体にこのようなデバイスドライバが登録されています.
次に、具体的なデバイスのusb駆動usb_driver(PL 2303など)は、usbを使用しています.register ->usb_register_driver -> driver_registerが登録する(これはUSB interfaceドライバを登録し、for_devices=0):
int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
const char *mod_name)
{
int retval = 0;
if (usb_disabled())
return -ENODEV;
new_driver->drvwrap.for_devices = 0;
new_driver->drvwrap.driver.name = (char *) new_driver->name;
new_driver->drvwrap.driver.bus = &usb_bus_type;
new_driver->drvwrap.driver.probe = usb_probe_interface;
new_driver->drvwrap.driver.remove = usb_unbind_interface;
new_driver->drvwrap.driver.owner = owner;
new_driver->drvwrap.driver.mod_name = mod_name;
spin_lock_init(&new_driver->dynids.lock);
INIT_LIST_HEAD(&new_driver->dynids.list);
retval = driver_register(&new_driver->drvwrap.driver);
if (retval)
goto out;
usbfs_update_special();
retval = usb_create_newid_file(new_driver);
if (retval)
goto out_newid;
retval = usb_create_removeid_file(new_driver);
if (retval)
goto out_removeid;
............................................................
これにより、driverはUSBバスに追加されます.しかし、まだデバイスはありません.これはdeivceが動的にロードを作成するためです.USBサブシステムがロードされると、カーネルスレッドが起動します.
kthread_run(hub_thread,NULL,“khubd”)は、usbデバイスのホットスワップイベントを監視し、デバイスの概略的な流れを発見する.
hub_events -> hub_port_connect_change -> usb_alloc_dev->udevを作成し、値を割り当てます.
dev->dev.bus = &usb_bus_type; dev->dev.type = &usb_device_type;//これは後でデバイスに一致します.driverの根拠dev->dev.groups=usb_device_groups;
->usb_new_device(udev) -> device_add、これにより、検出されたUSBデバイスがUSBバスusb_に追加されるbus_typeが上がった.
そしてdevice_add -> bus_probe_デバイスではbus_が使用されますfor_each_drvは、前にusbバスに登録されているドライバを巡り、このときバスにはdeviceがたくさんあります.driverですが、前のusbを呼び出します.register_device_driverが登録した汎用デバイス記述子解析駆動.
これはどのようにマッチしていますか?USBバスusb_へbus_typeのmatch関数はマッチングルールを見てわかります.
static int usb_device_match(struct device *dev, struct device_driver *drv)
{
/* devices and interfaces are handled separately */
if (is_usb_device(dev)) {
/* interface drivers never match devices */
if (!is_usb_device_driver(drv))
return 0;
/* TODO: Add real matching code */
return 1;
} else if (is_usb_interface(dev)) {
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id;
/* device drivers never match interfaces */
if (is_usb_device_driver(drv))
return 0;
intf = to_usb_interface(dev);
usb_drv = to_usb_driver(drv);
id = usb_match_id(intf, usb_drv->id_table);
if (id)
return 1;
id = usb_match_dynamic_id(intf, usb_drv);
if (id)
return 1;
}
return 0;
}
インタフェース駆動ではなくデバイス駆動が一致すると予想され、is_usb_デバイス関数の定義は、次のとおりです.
static inline int is_usb_device(const struct device *dev)
{
return dev->type == &usb_device_type;
}
前のusb_によるとalloc_devの付与値、この条件はすでに一致している.続いてis_usb_device_driver関数の定義:
static inline int is_usb_device_driver(struct device_driver *drv)
{
return container_of(drv, struct usbdrv_wrap, driver)->
for_devices;
}
ちょうどここだdevicesの前に1を割り当て、usb_device_matchはマッチングに成功しnewを見つけたdriver->drvwrap.driverというデバイスdriver、彼のprobeメソッドを呼び出します->usb_probe_device:
static int usb_probe_device(struct device *dev)
{
.......
error = udriver->probe(udev);
.......
}
簡単な判断をしてgenericを呼び出すcのusb_device_driver構造体のprobe.再度、これは汎用的な構成記述子駆動であり、上述の分割に基づいて、すべてのusb挿入装置が分析した規則に基づいてそれを見つけ、彼のprobe方法を呼び出して構成記述子を得ることを強調する.
static int generic_probe(struct usb_device *udev)
{
int err, c;
/* Choose and set the configuration. This registers the interfaces
* with the driver core and lets interface drivers bind to them.
*/
if (usb_device_is_owned(udev))
; /* Don't configure if the device is owned */
else if (udev->authorized == 0)
dev_err(&udev->dev, "Device is not authorized for usage
");
else {
c = usb_choose_configuration(udev);
if (c >= 0) {
err = usb_set_configuration(udev, c);
if (err) {
dev_err(&udev->dev, "can't set config #%d, error %d
",
c, err);
/* This need not be fatal. The user can try to
* set other configurations. */
}
}
}
/* USB device state == configured ... usable */
usb_notify_add_device(udev);
return 0;
}
主な仕事はusb_set_configurationでは、選択した構成記述子に基づいてデバイスに設定され、その構成下のインタフェースを有効にし、各インタフェースをdeviceとして抽象化し、device_add(&intf->dev)をUSBバスに追加します.重要なコードクリップは次のとおりです.
int usb_set_configuration(struct usb_device *dev, int configuration)
{
int i, ret;
struct usb_host_config *cp = NULL;
struct usb_interface **new_interfaces = NULL;
struct usb_hcd *hcd = bus_to_hcd(dev->bus);
int n, nintf;
。。。。。。
new_interfaces = kmalloc(nintf * sizeof(*new_interfaces),
。。。。。。
for (; n < nintf; ++n) {
new_interfaces[n] = kzalloc(
sizeof(struct usb_interface),
GFP_NOIO);
。。。。。。
usb_enable_interface(dev, intf, true);
intf->dev.parent = &dev->dev;
intf->dev.driver = NULL;
intf->dev.bus = &usb_bus_type;
intf->dev.type = &usb_if_device_type;
intf->dev.groups = usb_interface_groups;
intf->dev.dma_mask = dev->dev.dma_mask;
INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
。。。。。。
for (i = 0; i < nintf; ++i) {
struct usb_interface *intf = cp->interface[i];
dev_dbg(&dev->dev,
"adding %s (config #%d, interface %d)
",
dev_name(&intf->dev), configuration,
intf->cur_altsetting->desc.bInterfaceNumber);
device_enable_async_suspend(&intf->dev);
ret = device_add(&intf->dev);
if (ret != 0) {
dev_err(&dev->dev, "device_add(%s) --> %d
",
dev_name(&intf->dev), ret);
continue;
}
create_intf_ep_devs(intf);
。。。。。。
今回はdevice_addはまたバスのデバイスに一致しますドライブは?前のmatchの方法を見てみましょう.
static inline int is_usb_interface(const struct device *dev)
{
return dev->type == &usb_if_device_type;
}
この条件が成立し、usb_を呼び出すmatch_id(intf,usb_drv->id_table)とusb_match_dynamic_idマッチングとは、このように言いましょう.ここでは、USBデバイスから道徳PID、VID、ドライバで定義されたものをマッチングし、あればマッチングに成功します.我々PL 2303のid_tableは多く定義されており、新しいIDを追加する場合は、そのid_tableを追加すればいいです.
マッチングに成功したら、汎用usb_を呼び出します.probe_interface:
static int usb_probe_interface(struct device *dev)
{
。。。。。。
if (intf->needs_altsetting0) {
error = usb_set_interface(udev, intf->altsetting[0].
desc.bInterfaceNumber, 0);
。。。。。。
error = driver->probe(intf, id);
。。。。。。
具体的な駆動のprobeを呼び出します.ここでPL 2303のprobeです.
static struct usb_driver pl2303_driver = {
.name = "pl2303",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
.suspend = usb_serial_suspend,
.resume = usb_serial_resume,
.no_dynamic_id = 1,
.supports_autosuspend = 1,
};
usb_serial_probe、ここで面白いことを見ました.usb-serial.cのprobeもusb_を指していますserial_probe、まずusb-serialを見つけたはずだ.cのporbeは、pl 2303のprobeを見つけます.ここはusb-serialかもしれません.cは共通の関数インタフェースコードとしてPID,VIDを定義していない.しかし、USBコアのマッチングルールは、あいにくそのIDにマッチングするので、USBのアーキテクチャに合わせるためにusb serialも他に良い方法がないので、PL 2303のprobeをusb-serialに向けるしかない.cのporbeは,このprobeで端点記述子を統一的に処理する.
以上から分かるように、USBサブシステムはすでに私たちのために大部分のアーキテクチャを実現しており、私たちが駆動することはインタフェースディスクリプタ(interface descriptor)の処理を実現すればよいので、USBプロトコル規則と具体的なUSBチップマニュアルに基づいて操作する必要があります.
次の記事では、一般的なUSBプロトコルと特定のインタフェース記述子駆動を分析します.