Understanding Linux Device Types and Their Drivers

Understanding Linux Device Types and Their Drivers

Introduction

In Linux kernel development, various device types and their corresponding drivers form the foundation of hardware interaction. This article will explore these device types, starting from the most common to the more specialized ones, using practical examples.

1. Common Device Types and Their Drivers

1.1 Platform Devices and Drivers

Platform Device Example: UART (Serial Port)

// Platform Device Structure
struct platform_device {
    const char *name;
    int id;
    struct device dev;
    // ... other fields
};

// Platform Driver Structure
struct platform_driver {
    int (*probe)(struct platform_device *);
    void (*remove)(struct platform_device *);
    struct device_driver driver;
};
        

Example: UART Driver

static int uart_probe(struct platform_device *pdev) {
    struct uart_port *port;
    port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
    if (!port)
        return -ENOMEM;
    return uart_register_port(port);
}

static struct platform_driver uart_driver = {
    .probe = uart_probe,
    .remove = uart_remove,
    .driver = {
        .name = "uart",
    },
};
        

1.2 SPI Devices and Drivers

SPI Device Example: Temperature Sensor (LM75)

// SPI Device Structure
struct spi_device {
    struct device dev;
    struct spi_controller *controller;
    u32 max_speed_hz;
    // ... other fields
};

// SPI Driver Structure
struct spi_driver {
    int (*probe)(struct spi_device *);
    void (*remove)(struct spi_device *);
    struct device_driver driver;
};
        

Example: LM75 Temperature Sensor

static int lm75_probe(struct spi_device *spi) {
    struct lm75_data *data;
    data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL);
    if (!data)
        return -ENOMEM;
    return sysfs_create_group(&spi->dev.kobj, &lm75_attr_group);
}

static struct spi_driver lm75_driver = {
    .probe = lm75_probe,
    .remove = lm75_remove,
    .driver = {
        .name = "lm75",
    },
};
        

1.3 I2C Devices and Drivers

I2C Device Example: EEPROM (24c02)

// I2C Device Structure
struct i2c_client {
    struct device dev;
    struct i2c_adapter *adapter;
    u16 addr;
    // ... other fields
};

// I2C Driver Structure
struct i2c_driver {
    int (*probe)(struct i2c_client *);
    void (*remove)(struct i2c_client *);
    struct device_driver driver;
};
        

Example: 24c02 EEPROM

static int eeprom_probe(struct i2c_client *client) {
    struct eeprom_data *data;
    data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
    if (!data)
        return -ENOMEM;
    return sysfs_create_group(&client->dev.kobj, &eeprom_attr_group);
}

static struct i2c_driver eeprom_driver = {
    .probe = eeprom_probe,
    .remove = eeprom_remove,
    .driver = {
        .name = "24c02",
    },
};
        

1.4 USB Devices and Drivers

USB Device Example: USB Storage

// USB Device Structure
struct usb_device {
    struct device dev;
    struct usb_host *host;
    __u8 devnum;
    // ... other fields
};

// USB Driver Structure
struct usb_driver {
    int (*probe)(struct usb_interface *);
    void (*disconnect)(struct usb_interface *);
    struct device_driver driver;
};
        

Example: USB Storage

static int usb_storage_probe(struct usb_interface *intf) {
    struct usb_storage_info *info;
    info = kzalloc(sizeof(*info), GFP_KERNEL);
    if (!info)
        return -ENOMEM;
    return usb_register_dev(intf, &usb_storage_class);
}

static struct usb_driver usb_storage_driver = {
    .probe = usb_storage_probe,
    .disconnect = usb_storage_disconnect,
    .driver = {
        .name = "usb-storage",
    },
};
        

2. Less Common Device Types

2.1 MTD (Memory Technology Device)

MTD Device Example: NAND Flash

// MTD Device Structure
struct mtd_info {
    struct device dev;
    uint32_t size;
    uint32_t erasesize;
    // ... other fields
};

// MTD Driver Structure
struct mtd_driver {
    int (*probe)(struct mtd_info *);
    void (*remove)(struct mtd_info *);
    struct device_driver driver;
};
        

Example: NAND Flash

static int nand_probe(struct mtd_info *mtd) {
    struct nand_chip *chip;
    chip = devm_kzalloc(&mtd->dev, sizeof(*chip), GFP_KERNEL);
    if (!chip)
        return -ENOMEM;
    return nand_scan(chip, 1);
}
        

2.2 MDIO (Media Dependent Interface)

MDIO Device Example: Ethernet PHY

// MDIO Device Structure
struct phy_device {
    struct device dev;
    struct mii_bus *bus;
    int addr;
    // ... other fields
};

// MDIO Driver Structure
struct phy_driver {
    int (*probe)(struct phy_device *);
    void (*remove)(struct phy_device *);
    struct device_driver driver;
};
        

Example: Ethernet PHY

static int phy_probe(struct phy_device *phydev) {
    struct phy_private *priv;
    priv = devm_kzalloc(&phydev->dev, sizeof(*priv), GFP_KERNEL);
    if (!priv)
        return -ENOMEM;
    return phy_attach_direct(phydev, priv);
}

        

3. Device Driver Architecture

3.1 Platform Device Architecture

Platform Bus
  └── Platform Device
      ├── Memory Resources
      ├── IRQ Resources
      └── Device Data        

3.2 SPI Device Architecture

SPI Bus
  └── SPI Controller
      ├── SPI Devices
      ├── Chip Selects
      └── Transfer Queue        

3.3 I2C Device Architecture

I2C Bus
  └── I2C Adapter
      ├── I2C Devices
      ├── Transfer Buffer
      └── Transaction Queue        

3.4 USB Device Architecture

USB Bus
  └── USB Host
      ├── USB Devices
      ├── Endpoints
      └── Transfer Descriptors        

4. Device Driver Development Process

4.1 Driver Development Steps

  • Define Device Structure

struct uart_port {
    void __iomem *membase;
    int irq;
    // ... other fields
};        

  • Implement Driver Operations

static int uart_probe(struct platform_device *pdev) {
    // Implementation
    return 0;
}        

  • Register Driver

static struct platform_driver uart_driver = {
    .probe = uart_probe,
    .remove = uart_remove,
    .driver = {
        .name = "uart",
    },
};        

  • Module Registration

static int __init uart_init(void) {
    return platform_driver_register(&uart_driver);
}

static void __exit uart_exit(void) {
    platform_driver_unregister(&uart_driver);
}
module_init(uart_init);
module_exit(uart_exit);        

Conclusion

Linux device drivers follow well-established patterns for different hardware types. Platform drivers handle non-discoverable devices using resource management and device tree integration, while SPI/I2C drivers manage bus-connected peripherals.




要查看或添加评论,请登录

David Zhu的更多文章

社区洞察