Linux USB 详解_usbdev_do_ioctl-程序员宅基地

技术标签: struct  linux  descriptor  buffer  interface  5# Linux驱动实例  structure  

To understand all the Linux-USB framework, you'll use these resources:
    * This source code.
       "make pdfdocs",
       "usb.pdf" for host side
             "gadget.pdf" for peripheral side
    * The USB 2.0 specification (from www.usb.org).
    * Chip specifications for USB controllers. host controllers (on PCs, servers, and more);
       peripheral controllers (in devices with Linux firmware, like printers or cell phones);
       hard-wired peripherals like Ethernet adapters.
    * Specifications for other protocols implemented by USB peripheral functions. 
       Some are vendor-specific;
       others are vendor-neutral but just standardized outside of the www.usb.org team.

Here is a list of what each subdirectory here is, and what is contained in them.

core/  - This is for the core USB host code, including the usbfs files and the hub class driver ("khubd").

host/  - This is for USB host controller drivers.  This includes UHCI, OHCI, EHCI, and others that might
    be used with more specialized "embedded" systems.

gadget/ - This is for USB peripheral controller drivers and the various gadget drivers which talk to them.


Individual USB driver directories.  A new driver should be added to the first subdirectory in the list below that it fits into.

image/ - This is for still image drivers, like scanners or digital cameras.
input/ - This is for any driver that uses the input subsystem,like keyboard, mice, touchscreens, tablets, etc.
media/ - This is for multimedia drivers, like video cameras,radios, and any other drivers that talk to the v4l subsystem.
net/  - This is for network drivers.
serial/ - This is for USB to serial drivers.
storage/ - This is for USB mass-storage drivers.
atm/  - Automatic
mon/  - Monitor
class/ - This is for all USB device drivers that do not fit into any of the above categories, and work for a range
    of USB Class specified devices.
misc/  - This is for all USB device drivers that do not fit into any of the above categories.

驱动结构:
 USB 设备驱动 : USB设备和主机通讯      Gadget 驱动 :具体USB设备功能的实现,使设备表现出"网络连接"
             "打印机""USB Mass Storage"的特性

 USB Core : 定义一些数据结构,宏和功能函数.提供上下层的API   Gadget API : Callback API 的简单包装
      通过全局变量维护系统的USB信息,HotPlug控制,总线数据传输 

 USB 主机驱动 : 控制插入的USB设备      UDC 驱动 :控制USB设备和HOST的底层通讯,向上提供Callback API

 USB控制器硬件OHCI/EHCI/UHCI    <<-->> USB Bus <<-->>  USB控制器硬件OHCI/EHCI/UHCI

数据结构的定义: in /kernel/include/linux/usb_ch9.h
/*
 * This file holds USB constants and structures that are needed for USB
 * device APIs.  These are used by the USB device model, which is defined
 * in chapter 9 of the USB 2.0 specification.  Linux has several APIs in C
 * that need these:
 *
 * - the master/host side Linux-USB kernel driver API;
 * - the "usbfs" user space API; and
 * - the Linux "gadget" slave/device/peripheral side driver API.
 *
 * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems
 * act either as a USB master/host or as a USB slave/device.  That means
 * the master and slave side APIs benefit from working well together.
 *
 * There's also "Wireless USB", using low power short range radios for
 * peripheral interconnection but otherwise building on the USB framework.
 */
/* USB_DT_DEVICE: Device descriptor */
 struct usb_device_descriptor {   设备描述符    如USB扬声器
  __u8  bLength;    描述符的长度
  __u8  bDescriptorType;   描述符类型的编号

  __le16 bcdUSB;    USB版本号
  __u8  bDeviceClass;    USB的设备类code
  __u8  bDeviceSubClass;   USB的子类code
  __u8  bDeviceProtocol;   USB的协议code
  __u8  bMaxPacketSize0;   默认端口端口0的最大包大小
  __le16 idVendor;    厂商编号
  __le16 idProduct;    产品编号
  __le16 bcdDevice;    设备出厂的编号
  __u8  iManufacturer;    描述厂商的字符串的索引
  __u8  iProduct;    描述产品的字符串的索引
  __u8  iSerialNumber;    描述设备序列号的字符串的索引
  __u8  bNumConfigurations;   可能的配置数量
 } __attribute__ ((packed));
 struct usb_config_descriptor {   多个配置描述符    
  __u8  bLength;    描述符的长度
  __u8  bDescriptorType;   描述符类型的编号

  __le16 wTotalLength;    配置 所返回的所有数据的大小
  __u8  bNumInterfaces;   配置 所支持的interface数
  __u8  bConfigurationValue;   Set_Configuration命令需要的参数值
  __u8  iConfiguration;   描述该配置的字符串的索引值
  __u8  bmAttributes;    供电模式的选择
  __u8  bMaxPower;    设备从总线提取的最大电流
 } __attribute__ ((packed));
 /* USB_DT_INTERFACE: Interface descriptor */
 struct usb_interface_descriptor {  多个接口描述符    如音频接口,旋钮和按钮接口
  __u8  bLength;    描述符的长度
  __u8  bDescriptorType;   描述符类型的编号

  __u8  bInterfaceNumber;   接口的编号
  __u8  bAlternateSetting;   备用的接口描述符编号,提供不同质量的服务参数.
  __u8  bNumEndpoints;    该接口所使用的端口数,不包括端口0
  __u8  bInterfaceClass;   接口类型 
  __u8  bInterfaceSubClass;   接口子类型
  __u8  bInterfaceProtocol;   接口所遵循的协议
  __u8  iInterface;    描述该接口的字符串索引值
 } __attribute__ ((packed)
 /* USB_DT_ENDPOINT: Endpoint descriptor */
 struct usb_endpoint_descriptor {  多个端口描述符
  __u8  bLength;    描述符长度
  __u8  bDescriptorType;   描述符的类型

  __u8  bEndpointAddress;   端点号:0-3是端口点,第7位是方向(0-OUT,1-IN)
  __u8  bmAttributes;    端口属性:bit[0:1] 00:控制端点 01:同步传输端点 02:批量传输端点 03:中断端点
  __le16 wMaxPacketSize;   数据包的最大容量
  __u8  bInterval;    轮询数据传送端点的时间间隔,即中断传送时轮询间隔,此域为1-255
        批量和控制传送时,此域忽略
        同步传送时,为1
        
  /* NOTE:  these two are _only_ in audio endpoints. */
  /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
  __u8  bRefresh;    
  __u8  bSynchAddress;
 } __attribute__ ((packed));
 /* USB_DT_STRING: String descriptor */
 struct usb_string_descriptor {   字符串描述符
  __u8  bLength;    描述符长度
  __u8  bDescriptorType;   描述符类型

  __le16 wData[1];    /* UTF-16LE encoded */
 } __attribute__ ((packed));

1,USB主机驱动:  OHCI: Open Host Controller Interface,None PC or SiS/ALi chip PC USB
   UHCI: Universal,Used by PC USB
   EHCI: Enhanced usb2.0
   一,数据结构: in /kernel/drivers/usb/core/hcd.h
 /*-------------------------------------------------------------------------*/
 /*
  * USB Host Controller Driver (usb_hcd) framework
  *
  * Since "struct usb_bus" is so thin, you can't share much code in it.
  * This framework is a layer over that, and should be more sharable.
  */
 /*-------------------------------------------------------------------------*/

 1,struct usb_hcd { /* usb_bus.hcpriv points to this */  描述USB的Host Controller Driver
  /*
   *  housekeeping   家务管理
  */
  struct usb_bus self;  /* hcd is-a bus */   所代表的USB Bus

  const char *product_desc; /* product/vendor string */  产品字符串
  char irq_descr[24];  /* driver + bus # */   驱动+总线

  struct timer_list rh_timer; /* drives root-hub polling */ 根hub轮询
  struct urb *status_urb; /* the current status urb */ 目前的状态urb
  /*
   * hardware info/state  硬件资源/状态
   */
  const struct hc_driver *driver; /* hw-specific hooks */ 硬件特定的钩子函数,操作HC硬件
  unsigned saw_irq : 1;      
  unsigned can_wakeup:1; /* hw supports wakeup? */
  unsigned remote_wakeup:1; /* sw should use wakeup? */
  unsigned rh_registered:1; /* is root hub registered? */

  /* The next flag is a stopgap"权益之计", to be removed when all the HCDs
   * support the new root-hub polling mechanism. */
  unsigned uses_new_polling:1;     支持新的根hub轮询?
  unsigned poll_rh:1;  /* poll for rh status? */  轮询根hub状态?
  unsigned poll_pending:1; /* status has changed? */  状态已改变?

  int irq;   /* irq allocated */   被分配的irq
  void __iomem *regs;  /* device memory/io */  设备的IO内存
  u64 rsrc_start;  /* memory/io resource start */ IO内存起始地址
  u64 rsrc_len;   /* memory/io resource length */ IO内存长度
  unsigned power_budget; /* in mA, 0 = no limit */  最大电流

  #define HCD_BUFFER_POOLS 4
  struct dma_pool *pool [HCD_BUFFER_POOLS];    

  int state;  状态
  #define __ACTIVE 0x01
  #define __SUSPEND 0x04
  #define __TRANSIENT 0x80

  #define HC_STATE_HALT 0
  #define HC_STATE_RUNNING (__ACTIVE)
  #define HC_STATE_QUIESCING (__SUSPEND|__TRANSIENT|__ACTIVE)
  #define HC_STATE_RESUMING (__SUSPEND|__TRANSIENT)
  #define HC_STATE_SUSPENDED (__SUSPEND)

  #define HC_IS_RUNNING(state) ((state) & __ACTIVE)  宏
  #define HC_IS_SUSPENDED(state) ((state) & __SUSPEND)

  /* more shared queuing code would be good; it should support
   * smarter scheduling, handle transaction translators, etc;
   * input size of periodic table to an interrupt scheduler.
   * (ohci 32, uhci 1024, ehci 256/512/1024).
   */
  /* The HC driver's private data is stored at the end of
   * this structure. 私有数据
   */
  unsigned long hcd_priv[0]
   __attribute__ ((aligned (sizeof(unsigned long))));
 };

 2,struct hc_driver {
  const char *description;  /* "ehci-hcd" etc */  ehci-hcd等 
  const char *product_desc; /* product/vendor string */ 产品字符串
  size_t  hcd_priv_size; /* size of private data */ 私有数据的size

  /* irq handler */
  irqreturn_t (*irq) (struct usb_hcd *hcd, struct pt_regs *regs);中断处理函数

  int flags;
  #define HCD_MEMORY 0x0001  /* HC regs use memory (else I/O) */ HC的寄存器使用的内存或I/O
  #define HCD_USB11 0x0010  /* USB 1.1 */   
  #define HCD_USB2 0x0020  /* USB 2.0 */

  /* called to init HCD and root hub */
  int (*reset) (struct usb_hcd *hcd);    初始化HCD
  int (*start) (struct usb_hcd *hcd);    初始化根Hub 

  /* NOTE:  these suspend/resume calls relate to the HC as
   * a whole, not just the root hub; they're for bus glue.
   */
  /* called after all devices were suspended */
  int (*suspend) (struct usb_hcd *hcd, pm_message_t message);挂起Hub,进入D3(etc)前调用 

  /* called before any devices get resumed */   
  int (*resume) (struct usb_hcd *hcd);    进入D0(etc)后,恢复Hub

  /* cleanly make HCD stop writing memory and doing I/O */ 
  void (*stop) (struct usb_hcd *hcd);    HCD停止MM和IO

  /* return current frame number */
  int (*get_frame_number) (struct usb_hcd *hcd);  返回目前帧数

  /* manage i/o requests, device state */
  int (*urb_enqueue) (struct usb_hcd *hcd,   插入和退出urb队列
     struct usb_host_endpoint *ep,
     struct urb *urb,
     unsigned mem_flags);
  int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);

  /* hw synch, freeing endpoint resources that urb_dequeue can't */
  void  (*endpoint_disable)(struct usb_hcd *hcd,   释放endpoint资源
    struct usb_host_endpoint *ep);

  /* root hub support */      根Hub操作
  int (*hub_status_data) (struct usb_hcd *hcd, char *buf); 
  int (*hub_control) (struct usb_hcd *hcd,
     u16 typeReq, u16 wValue, u16 wIndex,
     char *buf, u16 wLength);
  int (*hub_suspend)(struct usb_hcd *);
  int (*hub_resume)(struct usb_hcd *);
  int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
  void (*hub_irq_enable)(struct usb_hcd *);
  /* Needed only if port-change IRQs are level-triggered */
 };

 /**
  * usb_create_hcd - create and initialize an HCD structure
  * @driver: HC driver that will use this hcd
  * @dev: device for this HC, stored in hcd->self.controller
  * @bus_name: value to store in hcd->self.bus_name
  * Context: !in_interrupt()
  *
  * Allocate a struct usb_hcd, with extra space at the end for the
  * HC driver's private data.  Initialize the generic members of the
  * hcd structure.
  *
  * If memory is unavailable, returns NULL.
  */
 3,struct usb_hcd *usb_create_hcd (const struct hc_driver *driver, struct device *dev, char *bus_name)
 
 /**
   * usb_add_hcd - finish generic HCD structure initialization and register
  * @hcd: the usb_hcd structure to initialize
  * @irqnum: Interrupt line to allocate
  * @irqflags: Interrupt type flags
  *
  * Finish the remaining parts of generic HCD initialization: allocate the
  * buffers of consistent memory, register the bus, request the IRQ line,
  * and call the driver's reset() and start() routines.
  */
 4,int usb_add_hcd(struct usb_hcd *hcd, unsigned int irqnum, unsigned long irqflags)

 /**
  * usb_remove_hcd - shutdown processing for generic HCDs
  * @hcd: the usb_hcd structure to remove
  * Context: !in_interrupt()
  *
  * Disconnects the root hub, then reverses the effects of usb_add_hcd(),
  * invoking the HCD's stop() method.
  */
 5,void usb_remove_hcd(struct usb_hcd *hcd);

 /*
  * This is the full ohci controller description
  *
  * Note how the "proper" USB information is just
  * a subset of what the full implementation needs. (Linus)
  */

 6,struct ohci_hcd {      作为usb_hcd结构体的hcd_priv
  spinlock_t  lock;
  /*
   * I/O memory used to communicate with the HC (dma-consistent)
   */
  struct ohci_regs __iomem *regs;    与主机控制器通信的IO内存(DMA 一致)

  /*
   * main memory used to communicate with the HC (dma-consistent).
   * hcd adds to schedule for a live hc any time, but removals finish
   * only at the start of the next frame.
   */
  struct ohci_hcca *hcca;     与主机控制器通信的主存(DMA 一致)
  dma_addr_t  hcca_dma;       

  struct ed  *ed_rm_list;  /* to be removed */ 将移除的OHCI Endpoint Descriptor (ED)

  struct ed  *ed_bulktail;  /* last in bulk list */ 批量队列尾
  struct ed  *ed_controltail; /* last in ctrl list */ 控制队列尾
   struct ed  *periodic [NUM_INTS];/* shadow int_table */ ??

  /*
   * OTG controllers and transceivers need software interaction;
   * other external transceivers should be software-transparent
   */
  struct otg_transceiver *transceiver;   OTG控制器和收发器需要软件交互,其他的外部收发器应该是软件透明的.

  /*
   * memory management for queue data structures  队列数据的内存管理
   */
  struct dma_pool *td_cache;
  struct dma_pool *ed_cache;
  struct td  *td_hash [TD_HASH_SIZE];
  struct list_head pending;

  /*
   * driver state      状态
   */
  int   load [NUM_INTS];
  u32    hc_control;  /* copy of hc control reg */ 主机控制器控制寄存器的复制
  unsigned long  next_statechange; /* suspend/resume */ 
  u32   fminterval;  /* saved register */ 被保存的寄存器

  struct work_struct rh_resume;
  struct notifier_block reboot_notifier;

  unsigned long flags;      /* for HC bugs */
  #define OHCI_QUIRK_AMD756 0x01   /* erratum #4 */
  #define OHCI_QUIRK_SUPERIO 0x02   /* natsemi */
  #define OHCI_QUIRK_INITRESET 0x04   /* SiS, OPTi, ... */
  #define OHCI_BIG_ENDIAN 0x08   /* big endian HC */
  #define OHCI_QUIRK_ZFMICRO 0x10   /* Compaq ZFMicro chipset*/
  // there are also chip quirks/bugs in init logic
 };

 7,struct ohci_hcd *hcd_to_ohci(struct usb_hcd *hcd);  内联函数usb_hcd与ohci_hcd的转换,得到私有数据
   struct usb_hcd  *ohci_to_hcd(const struct ohci_hcd *ohci); 通过conainer_of()从结构体成员获得所在结构体指针

 8,static int ohci_init (struct ohci_hcd *ohci);  初始化
   static int ohci_run (struct ohci_hcd *ohci)   开启
   static void ohci_stop (struct usb_hcd *hcd);   停止
   static void ohci_usb_reset (struct ohci_hcd *ohci)  复位 

   二,S3c2410主机驱动实例:
 S3c2410的集成的USB主机控制器兼容并实现OCHI1.0,USB1.1协议层.
 0x4900 0000 OHCI HcRevision
    HcControl
    HcCommonStatus
    HcInterruptStatus
    HcInterruptDisable
    HcHCCA
    HcPeriodCuttentED
    HcControlHeadED
    HcControlCurrentED
    HcBulkHeadED
    HcBulkCurrentED
    HcDoneHead
    HcRmInterval
    HcFmRemaining
    HcFmNumber
    HcPeriodicStart
    HcLSThreshold
    HcRhDescriptorA
    HcRhDescriptorB
    HcRhStatus
    HcRhportStatus1
    HcRhPortStatus2

  定义:static const struct hc_driver ohci_s3c2410_hc_driver = {
  .description = hcd_name,
  .product_desc = "S3C24XX OHCI",
  .hcd_priv_size = sizeof(struct ohci_hcd),
  /*
   * generic hardware linkage   通用硬件连接
   */
  .irq =   ohci_irq,
  .flags =  HCD_USB11 | HCD_MEMORY,
  /*
   * basic lifecycle operations  基本生命周期操作
   */
  .start =  ohci_s3c2410_start,
  .stop =  ohci_stop,
  /*
   * managing i/o requests and associated device resources I/O操作
   */
  .urb_enqueue = ohci_urb_enqueue,
  .urb_dequeue = ohci_urb_dequeue,
  .endpoint_disable = ohci_endpoint_disable,
  /*
   * scheduling support   调度
   */
  .get_frame_number = ohci_get_frame,
  /*
   * root hub support    根Hub操作
   */
  .hub_status_data = ohci_s3c2410_hub_status_data,
  .hub_control = ohci_s3c2410_hub_control,

  #if defined(CONFIG_USB_SUSPEND) && 0 挂起和恢复
  .hub_suspend = ohci_hub_suspend,
  .hub_resume =  ohci_hub_resume,
  #endif
 };
  实现函数: 
 static int ohci_s3c2410_start (struct usb_hcd *hcd)
 {
  struct ohci_hcd *ohci = hcd_to_ohci (hcd);
  int ret;

  if ((ret = ohci_init(ohci)) < 0)
   return ret;

  if ((ret = ohci_run (ohci)) < 0) {
   err ("can't start %s", hcd->self.bus_name);
   ohci_stop (hcd);
   return ret;
  }
  return 0;
 }

2,Linux的USB设备驱动
 USB设备文件 usbdevfs,usbfs 是动态产生的 /dev/ttyUSBn (串口Major188)
 挂载:  在/etc/fstab 加入 none /proc/bus/usb usbfs defaults
  或输入: mount -t usbfs none /proc/bus/usb
 显示:  cat /proc/bus/usb/devices
  拓扑,带宽,产品ID,Device Des,Config Des,Interface Des,Endpoint Des,Char Des.
 sysfs:/sys/bus/usb ->devices
    ->drivers -> hub
        -> usb
        -> usbfs 
  /sys/devices
  /sys/drivers
 
usb_driver:USB设备驱动描述
 /**
  * struct usb_driver - identifies USB driver to usbcore
  * @owner: Pointer to the module owner of this driver; initialize
  * it using THIS_MODULE.
  * @name: The driver name should be unique among USB drivers,
  * and should normally be the same as the module name.
  * @probe: Called to see if the driver is willing to manage a particular
  * interface on a device.  If it is, probe returns zero and uses
  * dev_set_drvdata() to associate driver-specific data with the
  * interface.  It may also use usb_set_interface() to specify the
  * appropriate altsetting.  If unwilling to manage the interface,
  * return a negative errno value.
  * @disconnect: Called when the interface is no longer accessible, usually
  * because its device has been (or is being) disconnected or the
  * driver module is being unloaded.
  * @ioctl: Used for drivers that want to talk to userspace through
  * the "usbfs" filesystem.  This lets devices provide ways to
  * expose information to user space regardless of where they
  * do (or don't) show up otherwise in the filesystem.
  * @suspend: Called when the device is going to be suspended by the system.
  * @resume: Called when the device is being resumed by the system.
  * @id_table: USB drivers use ID table to support hotplugging.
  * Export this with MODULE_DEVICE_TABLE(usb,...).  This must be set
  * or your driver's probe function will never get called.
  * @driver: the driver model core driver structure.
  *
  * USB drivers must provide a name, probe() and disconnect() methods,
  * and an id_table.  Other driver fields are optional.
  *
  * The id_table is used in hotplugging.  It holds a set of descriptors,
  * and specialized data may be associated with each entry.  That table
  * is used by both user and kernel mode hotplugging support.
  *
  * The probe() and disconnect() methods are called in a context where
  * they can sleep, but they should avoid abusing the privilege.  Most
  * work to connect to a device should be done when the device is opened,
  * and undone at the last close.  The disconnect code needs to address
  * concurrency issues with respect to open() and close() methods, as
  * well as forcing all pending I/O requests to complete (by unlinking
  * them as necessary, and blocking until the unlinks complete).
  */
 struct usb_driver { USB Core 总线部分
  struct module *owner;        内核模块
  const char *name;         唯一的USB设备名

  int (*probe) (struct usb_interface *intf, const struct usb_device_id *id); 探测函数
  void (*disconnect) (struct usb_interface *intf);    断开函数
  int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf); IO控制函数
  int (*suspend) (struct usb_interface *intf, pm_message_t message);  挂起
  int (*resume) (struct usb_interface *intf);     恢复
  const struct usb_device_id *id_table;      hotplugging探测设备表

  struct device_driver driver;       驱动模块core
 };
  
 usb_device
 usb_interface
 usb_host_interface
 usb_host_endpoint

linux下usb驱动编写(内核2.4)——2.6与此接口有区别
我们知道了在Linux下如何去使用一些最常见的USB设备。但对于做系统设计的程序员来说,我们还需要具有驱动程序的阅读、修改和开发能力。

USB骨架程序(usb-skeleton),是USB驱动架构。/driver/usb/usb-skeleton.c

那些linux下不支持的USB设备几乎都是生产厂商特定的产品。他们需要特定的驱动程序。有些生产厂商根本不公开他们的USB协议。因为每一个不同的协议都会产生一个新的驱动程序,所以就有了这个通用的USB驱动骨架程序,它是以pci 骨架为模板的。

如果你准备写一个linux驱动程序,首先要熟悉USB协议规范。还要有USB urbs的概念。

Linux USB 骨架驱动程序:
1,Init,并在USB Core子系统里注册,将这个驱动程序支持那种设备,当被支持的设备从系统插入或拔出时,会有哪些动作等信息都传送到USB Core子系统中.
   module_init (usb_skel_init);   初始化包括usb_register
 usb_register(&skel_driver);
 static struct usb_driver skel_driver = {
  name: "skeleton",     对驱动程序进行描述
  probe: skel_probe,     函数指针,当设备与在id_table 中变量信息匹配时,此函数被调用。
  disconnect: skel_disconnect,   函数指针
  fops: &skel_fops,
  minor: USB_SKEL_MINOR_BASE,
  id_table: skel_table,
 };
 fops和minor变量是可选的。
   大多usb驱动程序钩住另外一个驱动系统,例如SCSI,网络或者tty子系统。这些驱动程序在其他驱动系统中注册,同时任何用户空间的交互操作通  过那些接口提供,比如我们把SCSI设备驱动作为我们USB驱动所钩住的另外一个驱动系统,那么我们此USB设备的read、write等操作,就相应按SCSI设备的  read、write函数进行访问。
  但是对于扫描仪等驱动程序来说,并没有一个匹配的驱动系统可以使用,那我们就要自己处理与用户空间的read、write等交互函数。
  Usb子系统提供一种方法去注册一个次设备号和file_operations函数指针,这样就可以与用户空间实现方便地交互。

2,probe当usb设备插入时,为了使linux-hotplug(PCI、USB等设备热插拔支持)系统自动装载驱动程序,你需要创建一个MODULE_DEVICE_TABLE。代码如下(这个模块仅支持某一特定设备):
 /* table of devices that work with this driver */
 static struct usb_device_id skel_table [] = {
  { USB_DEVICE(USB_SKEL_VENDOR_ID,   USB_DEVICE宏利用厂商ID和产品ID提供了一个设备的唯一标识。
       USB_SKEL_PRODUCT_ID) },
    { } /* Terminating entry */
  };
 MODULE_DEVICE_TABLE (usb, skel_table);

 当插入一个ID匹配的USB设备到USB总线时,驱动会在USB core中注册。驱动程序中probe 函数也就会被调用。
 static int skel_probe( struct usb_interface *interface,   接口指针
     const struct usb_device_id *id)  接口ID
 {
  struct usb_skel *dev = NULL;    设备资源
  struct usb_host_interface *iface_desc;
  struct usb_endpoint_descriptor *endpoint;
  size_t buffer_size;
  int i;
  int retval = -ENOMEM;

  /* allocate memory for our device state and initialize it */
  dev = kmalloc(sizeof(*dev), GFP_KERNEL);   申请资源
  if (dev == NULL) {
   err("Out of memory");
   goto error;
  }
  memset(dev, 0x00, sizeof(*dev));    初始化资源
  kref_init(&dev->kref);     引用计数初始化
  dev->udev = usb_get_dev(interface_to_usbdev(interface));usb_device
  dev->interface = interface;     usb_interface

  /* set up the endpoint information */   设置端点信息
  /* use only the first bulk-in and bulk-out endpoints */只使用第一个批量IN和批量OUT端点
  iface_desc = interface->cur_altsetting;
  for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
   endpoint = &iface_desc->endpoint[i].desc;
   if ( !dev->bulk_in_endpointAddr &&
    ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&
        ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) ) {
    /* we found a bulk in endpoint */  找到一个批量IN端点
    buffer_size = le16_to_cpu( endpoint->wMaxPacketSize );
    dev->bulk_in_size = buffer_size;
    dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
    dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
    if ( !dev->bulk_in_buffer ) {
     err("Could not allocate bulk_in_buffer");
     goto error;
    }
   }

   if (!dev->bulk_out_endpointAddr &&
       ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) &&
       ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) {
    /* we found a bulk out endpoint */   找到一个批量OUT端点
    dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
   }
  }
  if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {
   err("Could not find both bulk-in and bulk-out endpoints");
   goto error;
  }

  /* save our data pointer in this interface device */  把usb_skel保存到interface
  usb_set_intfdata(interface, dev);    

  /* we can register the device now, as it is ready */
  retval = usb_register_dev(interface, &skel_class); 注册设备到USB Core,
          1,ask for a minor number.
          2,creates the devfs file for the usb device,devfs_mk_cdev().
                  class_device_create()
          3,creates a usb class device in the sysfs tree.
  if (retval) {
   /* something prevented us from registering this driver */
   err("Not able to get a minor for this device.");
   usb_set_intfdata(interface, NULL);
   goto error;
  }

  /* let the user know what node this device is now attached to */
  info("USB Skeleton device now attached to USBSkel-%d", interface->minor);
  return 0;

 error:
  if (dev)
   kref_put(&dev->kref, skel_delete);
  return retval;
 }
 /* Structure to hold all of our device specific stuff */
 struct usb_skel {      自定义的数据结构usb_skel
  struct usb_device *udev;    /* the usb device for this device */
  struct usb_interface *interface;   /* the interface for this device */
  unsigned char *bulk_in_buffer;   /* the buffer to receive data */
  size_t  bulk_in_size;    /* the size of the receive buffer */
  __u8  bulk_in_endpointAddr;  /* the address of the bulk in endpoint */
  __u8  bulk_out_endpointAddr;  /* the address of the bulk out endpoint */
  struct kref kref;
 };
 /*
  * usb class driver info in order to get a minor number from the usb core,
  * and to have the device registered with devfs and the driver core
  */
 static struct usb_class_driver skel_class = {
  .name = "usb/skel%d",
  .fops = &skel_fops,
  .mode = S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
  .minor_base = USB_SKEL_MINOR_BASE,
 };
 static struct file_operations skel_fops = {
  .owner = THIS_MODULE,
  .read =  skel_read,
  .write = skel_write,
  .open =  skel_open,
  .release = skel_release,
 };
 驱动程序需要确认插入的设备是否可以被接受,如果不接受,或者在初始化的过程中发生任何错误,probe函数返回一个NULL值。否则返回一个含有设备驱动程序状 态的指针。通过这个指针,就可以访问所有结构中的回调函数。

3, 如果设备从usb总线拔掉,设备指针会调用disconnect函数。驱动程序就需要清除那些被分配了的所有私有数据、关闭urbs,并且释放设备文件devfs句柄。
 usb_set_intfdata(interface, NULL);
 usb_deregister_dev(interface, &skel_class);
 kref_put(&dev->kref, skel_delete);

4,注销,当要从系统卸载驱动程序时,需要注销usb子系统。即需要usb_unregister函数处理:
 module_exit(usb_skel_exit);
 static void __exit usb_skel_exit(void)
 {
  /* deregister this driver with the USB subsystem */
  usb_deregister(&skel_driver);
 }
5,skeleton驱动就已经和设备绑定上了,任何用户态程序要操作此设备都可以通过file_operations结构所定义的函数进行了。
 static struct file_operations skel_fops = {
 .owner = THIS_MODULE,
 .read =  skel_read,
 .write = skel_write,
 .open = skel_open,
 .release = skel_release,
 };
 1,static int skel_open(struct inode *inode, struct file *file)
  struct usb_skel *dev;
  dev = usb_get_intfdata(interface);
  /* increment our usage count for the device */
  kref_get(&dev->kref);
  /* save our object in the file's private structure */  
  file->private_data = dev;

 2,static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
  dev = (struct usb_skel *)file->private_data;
  /* do a blocking bulk read to get data from the device */
  retval = usb_bulk_msg(dev->udev,     对usb设备进行一次读或写,这个函数能够不需要创建urbs和操作urb函数
            usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
            dev->bulk_in_buffer,
            min(dev->bulk_in_size, count),
            &bytes_read, 10000);
 3,static ssize_t skel_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos) 利用urbs批量写
  /* 建立一个urb及其buffer,复制user_buffer到urb */
  urb = usb_alloc_urb(0, GFP_KERNEL);
  buf = usb_buffer_alloc(dev->udev, count, GFP_KERNEL, &urb->transfer_dma);
  if (copy_from_user(buf, user_buffer, count)) {
   retval = -EFAULT;
   goto error;
  }
  /* 设定urb */
  usb_fill_bulk_urb(urb, dev->udev,
       usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
       buf, count, skel_write_bulk_callback, dev);
  urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
  /* send the data out the bulk port */
  retval = usb_submit_urb(urb, GFP_KERNEL);
  /* release our reference to this urb, the USB core will eventually free it entirely */
  usb_free_urb(urb);
 exit:
  return count;

 4,static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
  skel_write_bulk的回调函数

 5,static void skel_delete(struct kref *kref)
 6,static int skel_release(struct inode *inode, struct file *file)

 
 7,USB请求块 urbs

数据结构分析:
 /usb/core
  config.c
   void usb_release_interface_cache(struct kref *ref)
   int usb_get_configuration(struct usb_device *dev)
   void usb_destroy_configuration(struct usb_device *dev)
  buffer.c
   int hcd_buffer_create ( struct usb_hcd *hcd )
   void *hcd_buffer_alloc ( struct usb_bus *bus, size_t size, unsigned mem_flags, dma_addr_t *dma )
   void hcd_buffer_free ( struct usb_bus *bus,size_t size, void *addr,dma_addr_t dma )
   void hcd_buffer_destroy ( struct usb_hcd *hcd )
  devices.c
   void usbfs_conn_disc_event(void)
   struct file_operations usbfs_devices_fops = {
    .llseek = usb_device_lseek,
    .read = usb_device_read,
    .poll = usb_device_poll,
    .open = usb_device_open,
    .release = usb_device_release,
   };
  devio.c
   struct file_operations usbfs_device_file_operations = {
    .llseek = usbdev_lseek,
    .read = usbdev_read,
    .poll = usbdev_poll,
    .ioctl = usbdev_ioctl,
    .open = usbdev_open,
    .release = usbdev_release,
   };
  file.c
   int usb_major_init(void)
   void usb_major_cleanup(void)
   int usb_register_dev(struct usb_interface *intf, struct usb_class_driver *class_driver)
   void usb_deregister_dev(struct usb_interface *intf, struct usb_class_driver *class_driver)
  inode.c
   void usbfs_update_special (void)
   void usbfs_add_bus(struct usb_bus *bus)
   void usbfs_remove_bus(struct usb_bus *bus)
   void usbfs_add_device(struct usb_device *dev)
   void usbfs_remove_device(struct usb_device *dev)
   int __init usbfs_init(void)
   void usbfs_cleanup(void)
  sysfs.c
   void usb_create_sysfs_dev_files (struct usb_device *udev)
   void usb_remove_sysfs_dev_files (struct usb_device *udev)
   void usb_create_sysfs_intf_files (struct usb_interface *intf)
   void usb_remove_sysfs_intf_files (struct usb_interface *intf)
  message.c
   int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
      __u16 value, __u16 index, void *data, __u16 size, int timeout)
   int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
      void *data, int len, int *actual_length, int timeout)
   int usb_sg_init (
    struct usb_sg_request *io,
    struct usb_device *dev,
    unsigned  pipe,
    unsigned  period,
    struct scatterlist *sg,
    int   nents,
    size_t   length,
    unsigned  mem_flags
   )
   void usb_sg_wait (struct usb_sg_request *io)
   void usb_sg_cancel (struct usb_sg_request *io)
   int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
   int usb_get_string(struct usb_device *dev, unsigned short langid,
      unsigned char index, void *buf, int size)
   int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
   int usb_get_device_descriptor(struct usb_device *dev, unsigned int size)
   int usb_get_status(struct usb_device *dev, int type, int target, void *data)
   int usb_clear_halt(struct usb_device *dev, int pipe)
   void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
   void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf)
   void usb_disable_device(struct usb_device *dev, int skip_ep0)
   int usb_set_interface(struct usb_device *dev, int interface, int alternate)
   int usb_reset_configuration(struct usb_device *dev)
   int usb_set_configuration(struct usb_device *dev, int configuration)
  urb.c
   void usb_init_urb(struct urb *urb)
   void usb_free_urb(struct urb *urb)
   int usb_submit_urb(struct urb *urb, unsigned mem_flags)
   int usb_unlink_urb(struct urb *urb)
   void usb_kill_urb(struct urb *urb)
  usb.c
   int usb_register(struct usb_driver *new_driver)
   void usb_deregister(struct usb_driver *driver)
   struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
   struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf,unsigned int altnum)
   int usb_driver_claim_interface(struct usb_driver *driver,struct usb_interface *iface, void* priv)
   void usb_driver_release_interface(struct usb_driver *driver,struct usb_interface *iface)
   const struct usb_device_id *usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
   struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
   struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
   struct usb_device *usb_get_dev(struct usb_device *dev)
   void usb_put_dev(struct usb_device *dev)
   void usb_put_intf(struct usb_interface *intf)
   void usb_lock_device(struct usb_device *udev)
   int usb_trylock_device(struct usb_device *udev)
   int usb_lock_device_for_reset(struct usb_device *udev,
   void usb_unlock_device(struct usb_device *udev)
   void usb_lock_all_devices(void)
   void usb_unlock_all_devices(void)
   struct usb_device *usb_find_device(u16 vendor_id, u16 product_id)
   int usb_get_current_frame_number(struct usb_device *dev)
   int __usb_get_extra_descriptor(char *buffer, unsigned size, unsigned char type, void **ptr)
   void *usb_buffer_alloc (struct usb_device *dev, size_t size,unsigned mem_flags,dma_addr_t *dma )
   void usb_buffer_free (
    struct usb_device *dev,
    size_t size,
    void *addr,
    dma_addr_t dma
   )
   int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,struct scatterlist *sg, int nents)
   void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,struct scatterlist *sg, int n_hw_ents)
   struct bus_type usb_bus_type = {
    .name = "usb",
    .match = usb_device_match,
    .hotplug = usb_hotplug,
    .suspend = usb_generic_suspend,
    .resume = usb_generic_resume,
   };
   int usb_disabled(void)
  hub.c
   void usb_hub_tt_clear_buffer (struct usb_device *udev, int pipe)
   void usb_set_device_state(struct usb_device *udev,enum usb_device_state new_state)
   void usb_disconnect(struct usb_device **pdev)
   int usb_new_device(struct usb_device *udev)
   int usb_suspend_device(struct usb_device *udev, pm_message_t state)
   int usb_resume_device(struct usb_device *udev)
   void usb_resume_root_hub(struct usb_device *hdev)
   int usb_suspend_device(struct usb_device *udev, pm_message_t state)
   int usb_hub_init(void)
   void usb_hub_cleanup(void)
   int usb_reset_device(struct usb_device *udev)
  hcd.c
   struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,struct device *dev, char *bus_name)
    创建一个usb_hcd结构体并初始化.
    usb_hcd,usb_bus,hc_driver,timer_list,device
    usb_devmap,usb_operations,usb_device,dentry,class_device,mon_bus
   int usb_add_hcd(struct usb_hcd *hcd,unsigned int irqnum, unsigned long irqflags)
    复位    retval = hcd->driver->reset(hcd) 
    定位一段usb DMA,   retval = hcd_buffer_create(hcd)
    register the bus,   usb_register_bus(&hcd->self)
    request the IRQ line, request_irq(irqnum, &usb_hcd_irq, irqflags,hcd->irq_descr, hcd))
    start().   rhdev = usb_alloc_dev(NULL, &hcd->self, 0) hcd->driver->start(hcd)
    usb_device
   void usb_remove_hcd(struct usb_hcd *hcd)
        usb_disconnect(&hcd->self.root_hub);
        free_irq(hcd->irq, hcd);
        usb_deregister_bus(&hcd->self);
        hcd_buffer_destroy(hcd);
   void usb_hcd_poll_rh_status(struct usb_hcd *hcd)  Root hub中断后的定时传输函数
    static void rh_timer_func (unsigned long _hcd)
    {
     usb_hcd_poll_rh_status((struct usb_hcd *) _hcd);
    }

   struct usb_bus *usb_bus_get(struct usb_bus *bus)
   void usb_bus_put(struct usb_bus *bus)
   int usb_host_init(void)
   void usb_enable_root_hub_irq (struct usb_bus *bus)
   long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
   int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
   void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)
   void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc)
   void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
   int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num)
   void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
   irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
   void usb_hc_died (struct usb_hcd *hcd)
   void usb_put_hcd (struct usb_hcd *hcd)

   int usb_mon_register (struct usb_mon_operations *ops)
   void usb_mon_deregister (void)
  hcd-api.c
   int usb_hcd_pci_probe (struct pci_dev *dev, const struct pci_device_id *id)
   void usb_hcd_pci_remove (struct pci_dev *dev)
   int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
   int usb_hcd_pci_resume (struct pci_dev *dev)
 /usb/host
  
 /usb/gadget

 

3,USB固件驱动
 UDC
 Gadger API
 Gadget

 

 

 

 

 

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/tomlingyu/article/details/4479664

智能推荐

什么是内部类?成员内部类、静态内部类、局部内部类和匿名内部类的区别及作用?_成员内部类和局部内部类的区别-程序员宅基地

文章浏览阅读3.4k次,点赞8次,收藏42次。一、什么是内部类?or 内部类的概念内部类是定义在另一个类中的类;下面类TestB是类TestA的内部类。即内部类对象引用了实例化该内部对象的外围类对象。public class TestA{ class TestB {}}二、 为什么需要内部类?or 内部类有什么作用?1、 内部类方法可以访问该类定义所在的作用域中的数据,包括私有数据。2、内部类可以对同一个包中的其他类隐藏起来。3、 当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。三、 内部类的分类成员内部_成员内部类和局部内部类的区别

分布式系统_分布式系统运维工具-程序员宅基地

文章浏览阅读118次。分布式系统要求拆分分布式思想的实质搭配要求分布式系统要求按照某些特定的规则将项目进行拆分。如果将一个项目的所有模板功能都写到一起,当某个模块出现问题时将直接导致整个服务器出现问题。拆分按照业务拆分为不同的服务器,有效的降低系统架构的耦合性在业务拆分的基础上可按照代码层级进行拆分(view、controller、service、pojo)分布式思想的实质分布式思想的实质是为了系统的..._分布式系统运维工具

用Exce分析l数据极简入门_exce l趋势分析数据量-程序员宅基地

文章浏览阅读174次。1.数据源准备2.数据处理step1:数据表处理应用函数:①VLOOKUP函数; ② CONCATENATE函数终表:step2:数据透视表统计分析(1) 透视表汇总不同渠道用户数, 金额(2)透视表汇总不同日期购买用户数,金额(3)透视表汇总不同用户购买订单数,金额step3:讲第二步结果可视化, 比如, 柱形图(1)不同渠道用户数, 金额(2)不同日期..._exce l趋势分析数据量

宁盾堡垒机双因素认证方案_horizon宁盾双因素配置-程序员宅基地

文章浏览阅读3.3k次。堡垒机可以为企业实现服务器、网络设备、数据库、安全设备等的集中管控和安全可靠运行,帮助IT运维人员提高工作效率。通俗来说,就是用来控制哪些人可以登录哪些资产(事先防范和事中控制),以及录像记录登录资产后做了什么事情(事后溯源)。由于堡垒机内部保存着企业所有的设备资产和权限关系,是企业内部信息安全的重要一环。但目前出现的以下问题产生了很大安全隐患:密码设置过于简单,容易被暴力破解;为方便记忆,设置统一的密码,一旦单点被破,极易引发全面危机。在单一的静态密码验证机制下,登录密码是堡垒机安全的唯一_horizon宁盾双因素配置

谷歌浏览器安装(Win、Linux、离线安装)_chrome linux debian离线安装依赖-程序员宅基地

文章浏览阅读7.7k次,点赞4次,收藏16次。Chrome作为一款挺不错的浏览器,其有着诸多的优良特性,并且支持跨平台。其支持(Windows、Linux、Mac OS X、BSD、Android),在绝大多数情况下,其的安装都很简单,但有时会由于网络原因,无法安装,所以在这里总结下Chrome的安装。Windows下的安装:在线安装:离线安装:Linux下的安装:在线安装:离线安装:..._chrome linux debian离线安装依赖

烤仔TVの尚书房 | 逃离北上广?不如押宝越南“北上广”-程序员宅基地

文章浏览阅读153次。中国发达城市榜单每天都在刷新,但无非是北上广轮流坐庄。北京拥有最顶尖的文化资源,上海是“摩登”的国际化大都市,广州是活力四射的千年商都。GDP和发展潜力是衡量城市的数字指...

随便推点

java spark的使用和配置_使用java调用spark注册进去的程序-程序员宅基地

文章浏览阅读3.3k次。前言spark在java使用比较少,多是scala的用法,我这里介绍一下我在项目中使用的代码配置详细算法的使用请点击我主页列表查看版本jar版本说明spark3.0.1scala2.12这个版本注意和spark版本对应,只是为了引jar包springboot版本2.3.2.RELEASEmaven<!-- spark --> <dependency> <gro_使用java调用spark注册进去的程序

汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用_uds协议栈 源代码-程序员宅基地

文章浏览阅读4.8k次。汽车零部件开发工具巨头V公司全套bootloader中UDS协议栈源代码,自己完成底层外设驱动开发后,集成即可使用,代码精简高效,大厂出品有量产保证。:139800617636213023darcy169_uds协议栈 源代码

AUTOSAR基础篇之OS(下)_autosar 定义了 5 种多核支持类型-程序员宅基地

文章浏览阅读4.6k次,点赞20次,收藏148次。AUTOSAR基础篇之OS(下)前言首先,请问大家几个小小的问题,你清楚:你知道多核OS在什么场景下使用吗?多核系统OS又是如何协同启动或者关闭的呢?AUTOSAR OS存在哪些功能安全等方面的要求呢?多核OS之间的启动关闭与单核相比又存在哪些异同呢?。。。。。。今天,我们来一起探索并回答这些问题。为了便于大家理解,以下是本文的主题大纲:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JCXrdI0k-1636287756923)(https://gite_autosar 定义了 5 种多核支持类型

VS报错无法打开自己写的头文件_vs2013打不开自己定义的头文件-程序员宅基地

文章浏览阅读2.2k次,点赞6次,收藏14次。原因:自己写的头文件没有被加入到方案的包含目录中去,无法被检索到,也就无法打开。将自己写的头文件都放入header files。然后在VS界面上,右键方案名,点击属性。将自己头文件夹的目录添加进去。_vs2013打不开自己定义的头文件

【Redis】Redis基础命令集详解_redis命令-程序员宅基地

文章浏览阅读3.3w次,点赞80次,收藏342次。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。此时,可以将系统中所有用户的 Session 数据全部保存到 Redis 中,用户在提交新的请求后,系统先从Redis 中查找相应的Session 数据,如果存在,则再进行相关操作,否则跳转到登录页面。当数据量很大时,count 的数量的指定可能会不起作用,Redis 会自动调整每次的遍历数目。_redis命令

URP渲染管线简介-程序员宅基地

文章浏览阅读449次,点赞3次,收藏3次。URP的设计目标是在保持高性能的同时,提供更多的渲染功能和自定义选项。与普通项目相比,会多出Presets文件夹,里面包含着一些设置,包括本色,声音,法线,贴图等设置。全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,主光源和附加光源在一次Pass中可以一起着色。URP:全局只有主光源和附加光源,主光源只支持平行光,附加光源数量有限制,一次Pass可以计算多个光源。可编程渲染管线:渲染策略是可以供程序员定制的,可以定制的有:光照计算和光源,深度测试,摄像机光照烘焙,后期处理策略等等。_urp渲染管线

推荐文章

热门文章

相关标签