总线系统(下)

简介: 总线系统(下)

注册设备驱动程序

注册设备驱动程序:在进行一些检查和初始化工作之后,driver_register调用bus_add_driver将一个新驱动程序添加到一个总线来。驱动程序要有名字,然后注册到通用数据结构框架。

bus_add_driver

//注册设备驱动程序
int bus_add_driver(struct device_driver *drv)
{
  struct bus_type *bus;
  struct driver_private *priv;
  int error = 0;
  bus = bus_get(drv->bus);
  if (!bus)
    return -EINVAL;
  pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);
  priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  if (!priv) {
    error = -ENOMEM;
    goto out_put_bus;
  }
  klist_init(&priv->klist_devices, NULL, NULL);
  priv->driver = drv;
  drv->p = priv;
  priv->kobj.kset = bus->p->drivers_kset;
  error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,
             "%s", drv->name);
  if (error)
    goto out_unregister;
  klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
  if (drv->bus->p->drivers_autoprobe) {
    error = driver_attach(drv);
    if (error)
      goto out_unregister;
  }
  module_add_driver(drv->owner, drv);
  error = driver_create_file(drv, &driver_attr_uevent);
  if (error) {
    printk(KERN_ERR "%s: uevent attr (%s) failed\n",
      __func__, drv->name);
  }
  error = driver_add_groups(drv, bus->drv_groups);
  if (error) {
    /* How the hell do we get out of this pickle? Give up */
    printk(KERN_ERR "%s: driver_create_groups(%s) failed\n",
      __func__, drv->name);
  }
  if (!drv->suppress_bind_attrs) {
    error = add_bind_files(drv);
    if (error) {
      /* Ditto */
      printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
        __func__, drv->name);
    }
  }
  return 0;
out_unregister:
  kobject_put(&priv->kobj);
  kfree(drv->p);
  drv->p = NULL;
out_put_bus:
  bus_put(bus);
  return error;
}

如果总线支持自动探测,调用driver_attach,该函数迭代总线上所有设备,使用驱动程序的match函数进行检测,确定是否有某些设备可使用该驱动程序管理。最后将该驱动程序添加到总线上注册的所有驱动程序的链表中(klist_add_tail)。

PCI总线

PCI是peripheral component interconnect的缩写,是英持尔公司开发的一种标准总线,它迅速在系统组件和体系结构厂商中间确立了自身的地位,成为一种非常流行的总线。其原因不在于市场策略方面的技巧,而是因为其技术水平。

PCl总线设计目标:

  • 支持高传输带宽,以适合具有大数据流的多媒体应用;
  • 简单且易于自动化配置外设;
  • 平台独立性,即不绑定到特定的处理器类型或系统平台。

PCI系统布局

  • 设备标识:系统某个PCI总线上的每个设备,都由一组3个编号标识;
  • 总线编号:设备所有总线的编号,编号从0开始,PCI规范准许每个系统最多255个总线;
  • 插槽编号:总线内核的一个唯一标识编号,一个总线最多能够附接32个设备
  • 功能编号:用于在一个扩展卡上,实现包括多个扩展设备的设备。

PCI地址空间

有3个地址空间支持与PCI设备的通信。

  • I/O空间通过32个比特描述。对用于与设备通信端口地址,提供了最大4GB空间。
  • 取决于处理器类型,数据空间由32或64个比特位描述。
  • 配置空间包含各个设备的类型和特征的详细信息。

内核提供几个数据结构类型来管理系统的PCI结构:

总线的表示

在内存中,每个PCI总线都通过pci_bus數据结构的一个实例表示,该结构定义如下:

pci_bus

struct pci_bus {
  struct list_head node;  //总线链表中的节点
  /* node in list of buses */
  struct pci_bus  *parent;//桥接器所在的父总线
  /* parent bus this bridge is on */
  struct list_head children;  //子总线链表
  /* list of child buses */
  struct list_head devices;//总线上设备的链表
  /* list of devices on this bus */
  struct pci_dev  *self;  //父总线所看到的桥接器设备
  /* bridge device as seen by parent */
  struct list_head slots;   /* list of slots on this bus */
  struct resource *resource[PCI_BRIDGE_RESOURCE_NUM];//导向到该总线的地址空间
  struct list_head resources; /* address space routed to this bus */
  struct resource busn_res; /* bus numbers routed to this bus */
  struct pci_ops  *ops; //访问配置信息的各函数  
  /* configuration access functions */
  struct msi_controller *msi; /* MSI controller */
  void    *sysdata; //挂钩,用于特定硬件的拓展
  /* hook for sys-specific extension */
  struct proc_dir_entry *procdir; /* directory entry in /proc/bus/pci */
  unsigned char number; //总线号 
  /* bus number */
  unsigned char primary;//主桥接器编号
  /* number of primary bridge */
  unsigned char max_bus_speed;  //次桥接器编号
  /* enum pci_bus_speed */
  unsigned char cur_bus_speed;  /* enum pci_bus_speed */
#ifdef CONFIG_PCI_DOMAINS_GENERIC
  int   domain_nr;
#endif
  char    name[48];
  unsigned short  bridge_ctl; /* manage NO_ISA/FBB/et al behaviors */
  pci_bus_flags_t bus_flags;  /* inherited by child buses */
  struct device   *bridge;
  struct device   dev;
  struct bin_attribute  *legacy_io; /* legacy I/O for this bus */
  struct bin_attribute  *legacy_mem; /* legacy mem */
  unsigned int    is_added:1;
};

设备管理

struct pci_dev是一个关键的数据结构,用于表示系统中的各个PCI设备。

struct pci_dev {
  struct list_head bus_list;
  /* node in per-bus list */
  struct pci_bus  *bus; 
  /* bus this device is on */
  struct pci_bus  *subordinate;
  /* bus this device bridges to */
  void    *sysdata; /* hook for sys-specific extension */
  struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */
  struct pci_slot *slot;    /* Physical slot this device is in */
  unsigned int  devfn;    /* encoded device & function index */
  unsigned short  vendor;
  unsigned short  device;
  unsigned short  subsystem_vendor;
  unsigned short  subsystem_device;
  unsigned int  class;    /* 3 bytes: (base,sub,prog-if) */
  u8    revision; /* PCI revision, low byte of class word */
  u8    hdr_type; /* PCI header type (`multi' flag masked out) */
  u8    pcie_cap; /* PCIe capability offset */
  u8    msi_cap;  /* MSI capability offset */
  u8    msix_cap; /* MSI-X capability offset */
  u8    pcie_mpss:3;  /* PCIe Max Payload Size Supported */
  u8    rom_base_reg; /* which config register controls the ROM */
  u8    pin;    /* which interrupt pin this device uses */
  u16   pcie_flags_reg; /* cached PCIe Capabilities Register */
  u8    dma_alias_devfn;/* devfn of DMA alias, if any */
  struct pci_driver *driver;  /* which driver has allocated this device */
  u64   dma_mask; /* Mask of the bits of bus address this
             device implements.  Normally this is
             0xffffffff.  You only need to change
             this if your device has broken DMA
             or supports 64-bit transfers.  */
  struct device_dma_parameters dma_parms;
  pci_power_t     current_state;  /* Current operating state. In ACPI-speak,
             this is D0-D3, D0 being fully functional,
             and D3 being off. */
  u8    pm_cap;   /* PM capability offset */
  unsigned int  pme_support:5;  /* Bitmask of states from which PME#
             can be generated */
  unsigned int  pme_interrupt:1;
  unsigned int  pme_poll:1; /* Poll device's PME status bit */
  unsigned int  d1_support:1; /* Low power state D1 is supported */
  unsigned int  d2_support:1; /* Low power state D2 is supported */
  unsigned int  no_d1d2:1;  /* D1 and D2 are forbidden */
  unsigned int  no_d3cold:1;  /* D3cold is forbidden */
  unsigned int  d3cold_allowed:1; /* D3cold is allowed by user */
  unsigned int  mmio_always_on:1; /* disallow turning off io/mem
               decoding during bar sizing */
  unsigned int  wakeup_prepared:1;
  unsigned int  runtime_d3cold:1; /* whether go through runtime
               D3cold, not set for devices
               powered on/off by the
               corresponding bridge */
  unsigned int  ignore_hotplug:1; /* Ignore hotplug events */
  unsigned int  d3_delay; /* D3->D0 transition time in ms */
  unsigned int  d3cold_delay; /* D3cold->D0 transition time in ms */
#ifdef CONFIG_PCIEASPM
  struct pcie_link_state  *link_state;  /* ASPM link state */
#endif
  pci_channel_state_t error_state;  /* current connectivity state */
  struct  device  dev;    /* Generic device interface */
  int   cfg_size; /* Size of configuration space */
  /*
   * Instead of touching interrupt line and base address registers
   * directly, use the values stored here. They might be different!
   */
  unsigned int  irq;
  struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
  bool match_driver;    /* Skip attaching driver */
  /* These fields are used by common fixups */
  unsigned int  transparent:1;  /* Subtractive decode PCI bridge */
  unsigned int  multifunction:1;/* Part of multi-function device */
  /* keep track of device state */
  unsigned int  is_added:1;
  unsigned int  is_busmaster:1; /* device is busmaster */
  unsigned int  no_msi:1; /* device may not use msi */
  unsigned int  no_64bit_msi:1; /* device may only use 32-bit MSIs */
  unsigned int  block_cfg_access:1; /* config space access is blocked */
  unsigned int  broken_parity_status:1; /* Device generates false positive parity */
  unsigned int  irq_reroute_variant:2;  /* device needs IRQ rerouting variant */
  unsigned int  msi_enabled:1;
  unsigned int  msix_enabled:1;
  unsigned int  ari_enabled:1;  /* ARI forwarding */
  unsigned int  is_managed:1;
  unsigned int    needs_freset:1; /* Dev requires fundamental reset */
  unsigned int  state_saved:1;
  unsigned int  is_physfn:1;
  unsigned int  is_virtfn:1;
  unsigned int  reset_fn:1;
  unsigned int    is_hotplug_bridge:1;
  unsigned int    __aer_firmware_first_valid:1;
  unsigned int  __aer_firmware_first:1;
  unsigned int  broken_intx_masking:1;
  unsigned int  io_window_1k:1; /* Intel P2P bridge 1K I/O windows */
  unsigned int  irq_managed:1;
  pci_dev_flags_t dev_flags;
  atomic_t  enable_cnt; /* pci_enable_device has been called */
  u32   saved_config_space[16]; /* config space saved at suspend time */
  struct hlist_head saved_cap_space;
  struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */
  int rom_attr_enabled;   /* has display of the rom attribute been enabled? */
  struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */
  struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */
#ifdef CONFIG_PCI_MSI
  struct list_head msi_list;
  const struct attribute_group **msi_irq_groups;
#endif
  struct pci_vpd *vpd;
#ifdef CONFIG_PCI_ATS
  union {
    struct pci_sriov *sriov;  /* SR-IOV capability related */
    struct pci_dev *physfn; /* the PF this VF is associated with */
  };
  struct pci_ats  *ats; /* Address Translation Service */
#endif
  phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */
  size_t romlen; /* Length of ROM if it's not from the BAR */
  char *driver_override; /* Driver name to force a match */
};

设备驱动程序

struct module;
struct pci_driver {
  struct list_head node;
  const char *name;
  const struct pci_device_id *id_table; /* must be non-NULL for probe to be called */
  int  (*probe)  (struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */
  void (*remove) (struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */
  int  (*suspend) (struct pci_dev *dev, pm_message_t state);  /* Device suspended */
  int  (*suspend_late) (struct pci_dev *dev, pm_message_t state);
  int  (*resume_early) (struct pci_dev *dev);
  int  (*resume) (struct pci_dev *dev);                 /* Device woken up */
  void (*shutdown) (struct pci_dev *dev);
  int (*sriov_configure) (struct pci_dev *dev, int num_vfs); /* PF pdev */
  const struct pci_error_handlers *err_handler;
  struct device_driver  driver;
  struct pci_dynids dynids;
};

PCI驱动程序通过pci_register_driver注册:

#define pci_register_driver(driver)   \
  __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
int __pci_register_driver(struct pci_driver *drv, struct module *owner,
        const char *mod_name)
{
  /* initialize common driver fields */
  drv->driver.name = drv->name;
  drv->driver.bus = &pci_bus_type;
  drv->driver.owner = owner;
  drv->driver.mod_name = mod_name;
  spin_lock_init(&drv->dynids.lock);
  INIT_LIST_HEAD(&drv->dynids.list);
  /* register with core */
  return driver_register(&drv->driver);
}

USB

USB(Universal Serial Bus,通用串行总线)开发于上世纪90年代末。它是一种外部总线,用于满足不断发展的PC的需求,并用于建立针对新类型计机的解决方案,如手持设备、PDA等。作为一种通用的外部总线,在用于连接中低数据传输速率的设备时(如鼠标、网络摄像头、键盘),USB很有优势。但带宽要求更高的设备如外部硬盘、光驱、CD刻录机也可以通过USB总线运行。USB1.1的最大传输速率限于12兆比特/秒,该标准的2.0版本最高速率提升到480兆比特/杪。

所有USB设备都划分到不同类型当中,在内核源代码中,我们可以看到这样划分,各个驱动程序源代码按照所属类型归纳到不同的目录。

USB标准定义4种不同传输模式:控制传输、块传输、中断传输及同步传输。

USB子系统有4种主要任务:

  • 注册和管理现存的设备驱动程序;
  • 为USB设备查找适当的驱动程序,以及初始化和配置;
  • 在内核内存中表示设备树;
  • 与设备通信(交换数据)

USB设备

struct usb_device {
  int   devnum;
  char    devpath[16];
  u32   route;
  enum usb_device_state state;
  enum usb_device_speed speed;
  struct usb_tt *tt;
  int   ttport;
  unsigned int toggle[2];
  struct usb_device *parent;
  struct usb_bus *bus;
  struct usb_host_endpoint ep0;
  struct device dev;
  struct usb_device_descriptor descriptor;
  struct usb_host_bos *bos;
  struct usb_host_config *config;
  struct usb_host_config *actconfig;
  struct usb_host_endpoint *ep_in[16];
  struct usb_host_endpoint *ep_out[16];
  char **rawdescriptors;
  unsigned short bus_mA;
  u8 portnum;
  u8 level;
  unsigned can_submit:1;
  unsigned persist_enabled:1;
  unsigned have_langid:1;
  unsigned authorized:1;
  unsigned authenticated:1;
  unsigned wusb:1;
  unsigned lpm_capable:1;
  unsigned usb2_hw_lpm_capable:1;
  unsigned usb2_hw_lpm_besl_capable:1;
  unsigned usb2_hw_lpm_enabled:1;
  unsigned usb2_hw_lpm_allowed:1;
  unsigned usb3_lpm_enabled:1;
  int string_langid;
  /* static strings from the device */
  char *product;
  char *manufacturer;
  char *serial;
  struct list_head filelist;
  int maxchild;
  u32 quirks;
  atomic_t urbnum;
  unsigned long active_duration;
#ifdef CONFIG_PM
  unsigned long connect_time;
  unsigned do_remote_wakeup:1;
  unsigned reset_resume:1;
  unsigned port_is_suspended:1;
#endif
  struct wusb_dev *wusb_dev;
  int slot_id;
  enum usb_device_removable removable;
  struct usb2_lpm_parameters l1_params;
  struct usb3_lpm_parameters u1_params;
  struct usb3_lpm_parameters u2_params;
  unsigned lpm_disable_count;
};

USB驱动

struct usb_driver {
  const char *name;
  int (*probe) (struct usb_interface *intf,
          const struct usb_device_id *id);
  void (*disconnect) (struct usb_interface *intf);
  int (*unlocked_ioctl) (struct usb_interface *intf, unsigned int code,
      void *buf);
  int (*suspend) (struct usb_interface *intf, pm_message_t message);
  int (*resume) (struct usb_interface *intf);
  int (*reset_resume)(struct usb_interface *intf);
  int (*pre_reset)(struct usb_interface *intf);
  int (*post_reset)(struct usb_interface *intf);
  const struct usb_device_id *id_table;
  struct usb_dynids dynids;
  struct usbdrv_wrap drvwrap;
  unsigned int no_dynamic_id:1;
  unsigned int supports_autosuspend:1;
  unsigned int disable_hub_initiated_lpm:1;
  unsigned int soft_unbind:1;
};

USB设备驱动

struct usb_device_driver {
  const char *name;
  int (*probe) (struct usb_device *udev);
  void (*disconnect) (struct usb_device *udev);
  int (*suspend) (struct usb_device *udev, pm_message_t message);
  int (*resume) (struct usb_device *udev, pm_message_t message);
  struct usbdrv_wrap drvwrap;
  unsigned int supports_autosuspend:1;
};
目录
相关文章
|
8月前
|
安全 芯片 C++
浅谈总线通信机制(通信基础+串口+I2C)
浅谈总线通信机制(通信基础+串口+I2C)
77 0
|
9月前
IIC总线的硬件解析
IIC总线的硬件解析
104 0
|
9月前
|
存储 芯片 异构计算
LocalBus总线介绍及FPGA总线编程
LocalBus总线介绍及FPGA总线编程
523 0
LocalBus总线介绍及FPGA总线编程
|
10月前
|
Linux
总线系统(上)
总线系统
52 0
|
11月前
|
算法 网络架构 iOS开发
详解CAN总线:什么是CAN总线?
CAN总线协议(Controller Area Network),控制器局域网总线,是德国BOSCH(博世)公司研发的一种串行通讯协议总线,它可以使用双绞线来传输信号,是世界上应用最广泛的现场总线之一。
详解CAN总线:高速CAN总线和低速CAN总线的特性
在ISO 11898-2和ISO 11898-3中分别规定了两种CAN总线结构(在BOSCH CAN2.0规范中,并没有关于总线拓扑结构的说明):高速CAN总线和低速CAN总线,本篇博文将详细介绍两者的特性和区别。
详解CAN总线:CAN总线通信优先级机制
在详解CAN总线:CAN总线报文格式—数据帧文章中,讲解到仲裁段。仲裁段用于写明需要发送到目的CAN节点的地址、确定发送的帧类型(当前发送的是数据帧还是遥控帧),并确定发送的帧格式是标准帧还是扩展帧。 本篇文章将讲解仲裁段的另一个重要功能:通信优先级。
详解CAN总线:CAN总线故障界定与管理
CAN总线故障界定的目标是实现数据传输系统即使在节点发生故障的情况下也能维持很高的可用性。 因此故障界定策略必须证明在以下2个方面是可靠的: 区分短期故障和永久性故障; 找到并断开故障节点。
RK3399平台开发系列讲解(高速设备驱动篇)6.51、PCI总线信号定义
RK3399平台开发系列讲解(高速设备驱动篇)6.51、PCI总线信号定义
107 0
RK3399平台开发系列讲解(高速设备驱动篇)6.51、PCI总线信号定义
|
存储 算法
二、总线控制
二、总线控制
136 0
二、总线控制