module_device_table(module_device_table作用)
nvidia查看license命令
nvidia linux 指令
nvidia linux 指令,Linux 如何用指令查询 Nvidia 驱动程式版本与 GPU 显示卡资讯?
程嵇邢滑
转载
关注
0点赞·180人阅读
这里介绍几种在 Linux 系统上使用指令查询 Nvidia 驱动程式版本以及 GPU 显示卡资讯的方法。
nvidia-smi 指令工具
Nvidia 所提供的 nvidia-smi(NVIDIA System Management Interface)管理工具可以直接查询驱动程式与显示卡的资讯:nvidia-smiTue Feb 14 15:43:58 2017
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 375.26 Driver Version: 375.26 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GeForce GTX 106... Off | 0000:03:00.0 Off | N/A |
| 28% 29C P0 27W / 120W | 0MiB / 6072MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
| 1 GeForce GTX 106... Off | 0000:84:00.0 Off | N/A |
| 0% 28C P0 27W / 120W | 0MiB / 6072MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| No running processes found |
+-----------------------------------------------------------------------------+
-L 参数可列出所有插在电脑上的 GPU 卡:nvidia-smi -LGPU 0: GeForce GTX 1060 6GB (UUID: GPU-aa9427cb-d5f1-429a-754b-51a3b41d6a96)
GPU 1: GeForce GTX 1060 6GB (UUID: GPU-c23faedd-2c32-b000-f6f7-0ed8a72c191c)
-q 参数可列出 GPU 卡非常详细的资讯:nvidia-smi -q==============NVSMI LOG==============
Timestamp : Tue Feb 14 16:19:18 2017
Driver Version : 375.26
Attached GPUs : 2
GPU 0000:03:00.0
Product Name : GeForce GTX 1060 6GB
Product Brand : GeForce
Display Mode : Disabled
Display Active : Disabled
Persistence Mode : Disabled
Accounting Mode : Disabled
Accounting Mode Buffer Size : 1920
Driver Model
Current : N/A
Pending : N/A
Serial Number : N/A
GPU UUID : GPU-aa9427cb-d5f1-429a-754b-51a3b41d6a96
Minor Number : 0
VBIOS Version : 86.06.0E.00.41
MultiGPU Board : No
Board ID : 0x300
GPU Part Number : N/A
Inforom Version
Image Version : G001.0000.01.03
OEM Object : 1.1
ECC Object : N/A
Power Management Object : N/A
GPU Operation Mode
Current : N/A
Pending : N/A
GPU Virtualization Mode
Virtualization mode : None
PCI
Bus : 0x03
Device : 0x00
Domain : 0x0000
Device Id : 0x1C0310DE
Bus Id : 0000:03:00.0
Sub System Id : 0x85AE1043
GPU Link Info
PCIe Generation
Max : 3
Current : 3
Link Width
Max : 16x
Current : 16x
Bridge Chip
Type : N/A
Firmware : N/A
Replays since reset : 0
Tx Throughput : 0 KB/s
Rx Throughput : 0 KB/s
Fan Speed : 28 %
Performance State : P0
Clocks Throttle Reasons
Idle : Not Active
Applications Clocks Setting : Active
SW Power Cap : Not Active
HW Slowdown : Not Active
Sync Boost : Not Active
Unknown : Not Active
FB Memory Usage
Total : 6072 MiB
Used : 0 MiB
Free : 6072 MiB
BAR1 Memory Usage
Total : 256 MiB
Used : 2 MiB
Free : 254 MiB
Compute Mode : Default
Utilization
Gpu : 0 %
Memory : 0 %
Encoder : 0 %
Decoder : 0 %
Ecc Mode
Current : N/A
Pending : N/A
ECC Errors
Volatile
Single Bit
Device Memory : N/A
Register File : N/A
L1 Cache : N/A
L2 Cache : N/A
Texture Memory : N/A
Texture Shared : N/A
Total : N/A
Double Bit
Device Memory : N/A
Register File : N/A
L1 Cache : N/A
L2 Cache : N/A
Texture Memory : N/A
Texture Shared : N/A
Total : N/A
Aggregate
Single Bit
Device Memory : N/A
Register File : N/A
L1 Cache : N/A
L2 Cache : N/A
Texture Memory : N/A
Texture Shared : N/A
Total : N/A
Double Bit
Device Memory : N/A
Register File : N/A
L1 Cache : N/A
L2 Cache : N/A
Texture Memory : N/A
Texture Shared : N/A
Total : N/A
Retired Pages
Single Bit ECC : N/A
Double Bit ECC : N/A
Pending : N/A
Temperature
GPU Current Temp : 29 C
GPU Shutdown Temp : 102 C
GPU Slowdown Temp : 99 C
Power Readings
Power Management : Supported
Power Draw : 28.66 W
Power Limit : 120.00 W
Default Power Limit : 120.00 W
Enforced Power Limit : 120.00 W
Min Power Limit : 60.00 W
Max Power Limit : 140.00 W
Clocks
Graphics : 1569 MHz
SM : 1569 MHz
Memory : 4006 MHz
Video : 1417 MHz
Applications Clocks
Graphics : N/A
Memory : N/A
Default Applications Clocks
Graphics : N/A
Memory : N/A
Max Clocks
Graphics : 1974 MHz
SM : 1974 MHz
Memory : 4004 MHz
Video : 1708 MHz
Clock Policy
Auto Boost : N/A
Auto Boost Default : N/A
Processes : None
GPU 0000:84:00.0
Product Name : GeForce GTX 1060 6GB
Product Brand : GeForce
Display Mode : Disabled
Display Active : Disabled
Persistence Mode : Disabled
Accounting Mode : Disabled
Accounting Mode Buffer Size : 1920
Driver Model
Current : N/A
Pending : N/A
Serial Number : N/A
GPU UUID : GPU-c23faedd-2c32-b000-f6f7-0ed8a72c191c
Minor Number : 1
VBIOS Version : 86.06.0E.00.41
MultiGPU Board : No
Board ID : 0x8400
GPU Part Number : N/A
Inforom Version
Image Version : G001.0000.01.03
OEM Object : 1.1
ECC Object : N/A
Power Management Object : N/A
GPU Operation Mode
Current : N/A
Pending : N/A
GPU Virtualization Mode
Virtualization mode : None
PCI
Bus : 0x84
Device : 0x00
Domain : 0x0000
Device Id : 0x1C0310DE
Bus Id : 0000:84:00.0
Sub System Id : 0x85AE1043
GPU Link Info
PCIe Generation
Max : 3
Current : 3
Link Width
Max : 16x
Current : 16x
Bridge Chip
Type : N/A
Firmware : N/A
Replays since reset : 0
Tx Throughput : 0 KB/s
Rx Throughput : 0 KB/s
Fan Speed : 28 %
Performance State : P0
Clocks Throttle Reasons
Idle : Not Active
Applications Clocks Setting : Active
SW Power Cap : Not Active
HW Slowdown : Not Active
Sync Boost : Not Active
Unknown : Not Active
FB Memory Usage
Total : 6072 MiB
Used : 0 MiB
Free : 6072 MiB
BAR1 Memory Usage
Total : 256 MiB
Used : 2 MiB
Free : 254 MiB
Compute Mode : Default
Utilization
Gpu : 2 %
Memory : 0 %
Encoder : 0 %
Decoder : 0 %
Ecc Mode
Current : N/A
Pending : N/A
ECC Errors
Volatile
Single Bit
Device Memory : N/A
Register File : N/A
L1 Cache : N/A
L2 Cache : N/A
Texture Memory : N/A
Texture Shared : N/A
Total : N/A
Double Bit
Device Memory : N/A
Register File : N/A
L1 Cache : N/A
L2 Cache : N/A
Texture Memory : N/A
Texture Shared : N/A
Total : N/A
Aggregate
Single Bit
Device Memory : N/A
Register File : N/A
L1 Cache : N/A
L2 Cache : N/A
Texture Memory : N/A
Texture Shared : N/A
Total : N/A
Double Bit
Device Memory : N/A
Register File : N/A
L1 Cache : N/A
L2 Cache : N/A
Texture Memory : N/A
Texture Shared : N/A
Total : N/A
Retired Pages
Single Bit ECC : N/A
Double Bit ECC : N/A
Pending : N/A
Temperature
GPU Current Temp : 28 C
GPU Shutdown Temp : 102 C
GPU Slowdown Temp : 99 C
Power Readings
Power Management : Supported
Power Draw : 28.50 W
Power Limit : 120.00 W
Default Power Limit : 120.00 W
Enforced Power Limit : 120.00 W
Min Power Limit : 60.00 W
Max Power Limit : 140.00 W
Clocks
Graphics : 1569 MHz
SM : 1569 MHz
Memory : 4006 MHz
Video : 1417 MHz
Applications Clocks
Graphics : N/A
Memory : N/A
Default Applications Clocks
Graphics : N/A
Memory : N/A
Max Clocks
Graphics : 1974 MHz
SM : 1974 MHz
Memory : 4004 MHz
Video : 1708 MHz
Clock Policy
Auto Boost : N/A
Auto Boost Default : N/A
Processes : None
Linux 系统指令
除了使用 Nvidia 所提供的工具之外,也可以从 kernel 组入的驱动程式来看:cat /proc/driver/nvidia/versionNVRM version: NVIDIA UNIX x86_64 Kernel Module 375.26 Thu Dec 8 18:36:43 PST 2016
GCC version: gcc version 4.8.5 20150623 (Red Hat 4.8.5-4) (GCC)
或是使用 modinfo 查看:modinfo nvidiafilename: /lib/modules/3.10.0-327.el7.x86_64/extra/nvidia.ko
alias: char-major-195-*
version: 375.26
supported: external
license: NVIDIA
rhelversion: 7.2
srcversion: 7850503DF85713C6E0D88A3
alias: pci:v000010DEd00000E00sv*sd*bc04sc80i00*
alias: pci:v000010DEd*sv*sd*bc03sc02i00*
alias: pci:v000010DEd*sv*sd*bc03sc00i00*
depends: i2c-core
vermagic: 3.10.0-327.el7.x86_64 SMP mod_unload modversions
parm: NVreg_Mobile:int
parm: NVreg_ResmanDebugLevel:int
parm: NVreg_RmLogonRC:int
parm: NVreg_ModifyDeviceFiles:int
parm: NVreg_DeviceFileUID:int
parm: NVreg_DeviceFileGID:int
parm: NVreg_DeviceFileMode:int
parm: NVreg_UpdateMemoryTypes:int
parm: NVreg_InitializeSystemMemoryAllocations:int
parm: NVreg_UsePageAttributeTable:int
parm: NVreg_MapRegistersEarly:int
parm: NVreg_RegisterForACPIEvents:int
parm: NVreg_CheckPCIConfigSpace:int
parm: NVreg_EnablePCIeGen3:int
parm: NVreg_EnableMSI:int
parm: NVreg_TCEBypassMode:int
parm: NVreg_UseThreadedInterrupts:int
parm: NVreg_MemoryPoolSize:int
parm: NVreg_RegistryDwords:charp
parm: NVreg_RmMsg:charp
parm: NVreg_AssignGpus:charp
nvidia linux 指令
一九五三年一分钱纸币现在值多少钱?
精选推荐
广告
nvidia-smi:控制您的GPU
959阅读·0评论·0点赞
2022年5月18日
nvidia命令不可用linux,如何在Linux系统上检查NVIDIA驱动程序版本
1697阅读·0评论·0点赞
2021年5月9日
linux 查看显卡信息及显卡驱动信息
1249阅读·0评论·2点赞
2022年9月7日
GPU虚拟化——NVIDIA GRID License组件工作原理介绍与故障排错实战
6102阅读·0评论·1点赞
2020年2月18日
NVIDIA GPU 常用操作
1164阅读·0评论·0点赞
2021年10月21日
英伟达命令
322阅读·0评论·0点赞
2022年7月8日
这才是我想要的播放器,你用过了么?
精选推荐
广告
linux_查看 Nvidia 驱动版本、Cuda、Cudnn 版本号
2.1W阅读·2评论·4点赞
2019年12月16日
Ubuntu下查看显卡型号及NVIDIA驱动版本
13.9W阅读·5评论·8点赞
2017年12月22日
linux查看 CUDA cudnn 版本 查看Navicat GPU版本 查看nvidia 驱动版本
1.1W阅读·0评论·2点赞
2017年12月20日
linux查看显卡版本(没有安装显卡驱动之前)
3545阅读·0评论·1点赞
2021年4月13日
linux下查看显卡和驱动版本
6351阅读·0评论·2点赞
2022年3月7日
linux代码查看N卡,LINUX下nvidia-smi命令解析
1706阅读·0评论·1点赞
2021年5月16日
ubuntu中用python获取GPU温度。push给falcon-agent。
888阅读·0评论·0点赞
2018年11月2日
Kali5.8.0-kali2-amd64安装NVIDIA GPU驱动程序
814阅读·0评论·0点赞
2020年12月27日
NVIDIA-SMI系列命令总结
10.4W阅读·5评论·64点赞
2018年7月3日
java获取linux主机中英伟达GPU状态信息(通过nvidia-smi命令)
1816阅读·0评论·4点赞
2020年11月6日
Linux服务器深度学习环境的配置
9975阅读·2评论·3点赞
2019年6月14日
Ubuntu 16.04 上安装 CUDA 9.0 详细教程
15.9W阅读·70评论·79点赞
2017年12月6日
去首页
看看更多热门内容
Uncaught ReferenceError显示“is not defined错误”怎么办?
最可能的是引用的各个js的调用顺序有误,重新调整其引用顺序。
1 .出现这个错误,最可能的是引用的各个js的调用顺序有误,重新调整其引用顺序。
2 .还有一个原因就是在你引用js时,路径出错,不是你项目中正确的文件路径。
3 .还有一个原因是你的js中有某些值是不存在的。
4 .除了以上这个具体的错误,还可能遇到类似的Uncaught ReferenceError: XXXX is not defined错误,这类错误就要多检查传值错误,或者某些值不存在。
如何编写网卡驱动程序?
实现方法和步骤如下:
1、如果网络设备(包括wireless)是PCI规范的,则先是向内核注册该PCI设备(pci_register_driver),然后由pci_driver数据结构中的probe函数指针所指向的侦测函数来初始化该PCI设备,并且同时注册和初始化该网络设备。
申明为PCI设备:
static?struct?pci_driver?tg3_driver?=?{???
????.name?=?DRV_MODULE_NAME,???
????.id_table?=?tg3_pci_tbl,?//此驱动所支持的网卡系列,vendor_id,?device_id???
????.probe?=?tg3_init_one,?//初始化网络设备的回调函数???
????.remove?=?__devexit_p(tg3_remove_one),?//注销网络设备的回调函数???
????.suspend?=?tg3_suspend,?//设备挂起函数???
????.resume?=?tg3_resume?//设备恢复函数???
};
PCI设备探测函数probe,初始化网络设备:
static?int?__devinit?tg3_init_one(struct?pci_dev?*pdev,?const?struct?pci_device_id?*ent)???
{???
???????
????//初始化设备,使I/O,memory可用,唤醒设备???
????pci_enable_device(pdev);???
???????
????//申请内存空间,配置网卡的I/O,memory资源???
????pci_request_regions(pdev,?DRV_MODULE_NAME);???
????pci_set_master(pdev);???
???????
????//设置DMA属性???
????pci_set_dma_mask(pdev,?(u64)?0xffffffffffffffff);???
???????
????//网卡?I/O,memory资源的启始地址???
????tg3reg_base?=?pci_resource_start(pdev,?0);???
???????
????//网卡I/O,memory资源的大小???
????tg3reg_len?=?pci_resource_len(pdev,?0);???
???????
????//分配并设置网络设备???
????dev?=?alloc_etherdev(sizeof(*tp));???
???????
????//申明为内核设备模块???
????SET_MODULE_OWNER(dev);???
???????
????//初始化私有结构中的各成员值???
????tp?=?dev-priv;???
????tp-pdev?=?pdev;???
????tp-dev?=?dev;???
????……???
????//锁的初始化???
????spin_lock_init(tp-lock);???
???????
????//映射I/O,memory地址到私有域中的寄存器结构???
????tp-regs?=?(unsigned?long)?ioremap(tg3reg_base,?tg3reg_len);???
????dev-irq?=?pdev-irq;???
???????
????//网络设备回调函数赋值???
????dev-open?=?tg3_open;???
????dev-stop?=?tg3_close;???
????dev-get_stats?=?tg3_get_stats;???
????dev-set_multicast_list?=?tg3_set_rx_mode;???
????dev-set_mac_address?=?tg3_set_mac_addr;???
????dev-do_ioctl?=?tg3_ioctl;???
????dev-tx_timeout?=?tg3_tx_timeout;???
????dev-hard_start_xmit=?tg3_start_xmit;???
???????
????//网卡的MAC地址赋值dev-addr???
????tg3_get_device_address(tp);???
???????
????//注册网络设备???
????register_netdev(dev);???
???????
????//把网络设备指针地址放入PCI设备中的设备指针中???
????pci_set_drvdata(pdev,?dev);???
}
打开网络设备:
/*?int?request_irq(unsigned?int?irq,?
????????????????????????void?(*handler)(int?irq,?void?*dev_id,?struct?pt_regs?*regs),??
????????????????????????unsigned?long?irqflags,?
????????????????????????const?char?*?devname,?
????????????????????????void?*dev_id);?
irq是要申请的硬件中断号。在Intel平台,范围0--15。?
handler是向系统登记的中断处理函数。?
这是一个回调函数,中断发生时,系统调用这个函数,传入的参数包括硬件中断号,device?id,寄存器值。?
dev_id就是下面的request_irq时传递给系统的参数dev_id。?
irqflags是中断处理的一些属性。比较重要的有?SA_INTERRUPT,?
标明中断处理程序是快速处理程序(设置SA_INTERRUPT)还是慢速处理程序(不设置SA_INTERRUPT)。?
快速?处理程序被调用时屏蔽所有中断。慢速处理程序不屏蔽。?
还有一个SA_SHIRQ属性,设置了以后运行多个设备共享中断。dev_id在中断共享时会用到。?
?一般设置为这个设备的device结构本身或者NULL。?
?中断处理程序可以用dev_id找到相应的控制这个中断的设备,或者用rq2dev_map找到?中断对应的设备。?
*/???
??
static?int?tg3_open(struct?net_device?*dev)???
{???
????//分配一个中断???
????request_irq(dev-irq,?tg3_interrupt,?SA_SHIRQ,?dev-name,?dev);???
???????
????//初始化硬件???
????tg3_init_hw(tp);???
???????
????//初始化收包和发包的缓冲区???
????tg3_init_rings(tp);???
???????
????//初始化定时器???
????init_timer(tp-timer);???
????tp-timer.expires?=?jiffies?+?tp-timer_offset;???
????tp-timer.data?=?(unsigned?long)?tp;???
????tp-timer.function?=?tg3_timer;?//超时回调函数???
????add_timer(tp-timer);???
???????
????//允许网卡开始传输包???
????netif_start_queue(dev);???
}
网络设备初始化主要流程是?
网卡驱动初始化
网络设备驱动加载时,内核会调用一个驱动程序注册的初始化函数。 内核提供了一个宏?module_init?来执行注册操作。
igb?模块的初始化函数长这样(请叫我程序拷贝员)。
/**
* ?igb_init_module - Driver Registration Routine
*
* ?igb_init_module is the first routine called when the driver is
* ?loaded. All it does is register with the PCI subsystem.
**/
static int __init igb_init_module(void)
{
int ret;
pr_info("%s - version %s\n",
igb_driver_string, igb_driver_version);
pr_info("%s\n", igb_copyright);
#ifdef CONFIG_IGB_DCA
dca_register_notify(dca_notifier);
#endif
ret = pci_register_driver(igb_driver);
return ret;
}
module_init(igb_init_module);
可以看到主要是有个?pci_register_driver?的函数,下面看看它干了啥。
PCI初始化
网卡一般都是PCI设备,可以用命令lspci查看。 PCI设备通过配置空间中的一系列寄存器来识别自己。 驱动会使用内核提供的宏?MODULE_DEVICE_TABLE?来导出驱动支持的PCI设备(使用设备ID标识)。 内核会用这个表决定加载特定的驱动从而控制PCI设备。
static const struct pci_device_id igb_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_BACKPLANE_1GBPS) },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_SGMII) },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I354_BACKPLANE_2_5GBPS) },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I211_COPPER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_COPPER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_FIBER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SERDES), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_SGMII), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82580_COPPER_DUAL), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SGMII), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SERDES), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_BACKPLANE), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_DH89XXCC_SFP), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS_SERDES), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_FIBER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES_QUAD), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER_ET2), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_82575GB_QUAD_COPPER), board_82575 },
/* required last entry */
{0, }
};
MODULE_DEVICE_TABLE(pci, igb_pci_tbl);
pci_register_driver?使用?igb_driver?作为参数。igb_driver?则使用?igb_pci_tbl?赋值给域?id_table。
static struct pci_driver igb_driver = {
.name ? ? = igb_driver_name,
.id_table = igb_pci_tbl,
.probe ? ?= igb_probe,
.remove ? = igb_remove,
#ifdef CONFIG_PM
.driver.pm = igb_pm_ops,
#endif
.shutdown = igb_shutdown,
.sriov_configure = igb_pci_sriov_configure,
.err_handler = igb_err_handler
};
重头戏?igb_probe
igb_driver?有个很重要的域?igb_probe。内核识别到PCI设备驱动后,就会调用pci_driver?中?probe?指向的函数。对?igb?来说,就是?igb_probe?函数。
igb_probe?会执行以下操作:
启用PCI设备。
设置DMA掩码。
请求内存区域和IO端口。
注册ethtool函数。
分配?net_device,这个结构代表一个抽象的网络设备。
注册?net_device_ops?到?net_device?的?netdev_ops?域。
设置?net_device?的features。
还有一些杂七杂八的工作都在这里完成,watchdog, 缓冲区分配等等。
struct net_device_ops?包含网络子系统操作设备的诸多函数指针。
static int igb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) {
? ?...
? ?netdev-netdev_ops = igb_netdev_ops;
? ?...
}
static const struct net_device_ops igb_netdev_ops = {
? ?.ndo_open ? ? ? = igb_open,
? ?.ndo_stop ? ? ? = igb_close,
? ?.ndo_start_xmit ? ? = igb_xmit_frame,
? ?.ndo_get_stats64 ? ?= igb_get_stats64,
? ?.ndo_set_rx_mode ? ?= igb_set_rx_mode,
? ?.ndo_set_mac_address ? ?= igb_set_mac,
? ?.ndo_change_mtu ? ? = igb_change_mtu,
? ?.ndo_do_ioctl ? ? ? = igb_ioctl,
? ?.ndo_tx_timeout ? ? = igb_tx_timeout,
? ?.ndo_validate_addr ?= eth_validate_addr,
? ?.ndo_vlan_rx_add_vid ? ?= igb_vlan_rx_add_vid,
? ?.ndo_vlan_rx_kill_vid ? = igb_vlan_rx_kill_vid,
? ?.ndo_set_vf_mac ? ? = igb_ndo_set_vf_mac,
? ?.ndo_set_vf_vlan ? ?= igb_ndo_set_vf_vlan,
? ?.ndo_set_vf_rate ? ?= igb_ndo_set_vf_bw,
? ?.ndo_set_vf_spoofchk ? ?= igb_ndo_set_vf_spoofchk,
? ?.ndo_get_vf_config ?= igb_ndo_get_vf_config,
#ifdef CONFIG_NET_POLL_CONTROLLER
? ?.ndo_poll_controller ? ?= igb_netpoll,
#endif
? ?.ndo_fix_features ? = igb_fix_features,
? ?.ndo_set_features ? = igb_set_features,
? ?.ndo_fdb_add ? ? ? ?= igb_ndo_fdb_add,
? ?.ndo_features_check = igb_features_check,
}
怎么能将linux下自动分配的usb0改为usb1
你好,方法如下:
写一个USB的驱动程序最 基本的要做四件事:
驱动程序要支持的设备、注册USB驱动程序、探测和断开、提交和控制urb(USB请求块)
驱动程序支持的设备:有一个结构体struct usb_device_id,这个结构体提供了一列不同类型的该驱动程序支持的USB设备,对于一个只控制一个特定的USB设备的驱动程序来说,struct usb_device_id表被定义为:
/* 驱动程序支持的设备列表 */
static struct usb_device_id skel_table [] = {
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
{ } /* 终止入口 */
};
MODULE_DEVICE_TABLE (usb, skel_table);
对 于PC驱动程序,MODULE_DEVICE_TABLE是必需的,而且usb必需为该宏的第一个值,而USB_SKEL_VENDOR_ID和 USB_SKEL_PRODUCT_ID就是这个特殊设备的制造商和产品的ID了,我们在程序中把定义的值改为我们这款USB的,如:
/* 定义制造商和产品的ID号 */
#define USB_SKEL_VENDOR_ID 0x1234
#define USB_SKEL_PRODUCT_ID 0x2345
这两个值可以通过命令lsusb,当然你得先把USB设备先插到主机上了。或者查看厂商的USB设备的手册也能得到,在我机器上运行lsusb是这样的结果:
Bus 004 Device 001: ID 0000:0000
Bus 003 Device 002: ID 1234:2345 Abc Corp.
Bus 002 Device 001: ID 0000:0000
Bus 001 Device 001: ID 0000:0000
得到这两个值后把它定义到程序里就可以了。
注册USB驱动程序:所 有的USB驱动程序都必须创建的结构体是struct usb_driver。这个结构体必须由USB驱动程序来填写,包括许多回调函数和变量,它们向USB核心代码描述USB驱动程序。创建一个有效的 struct usb_driver结构体,只须要初始化五个字段就可以了,在框架程序中是这样的:
static struct usb_driver skel_driver = {
.owner = THIS_MODULE,
.name = "skeleton",
.probe = skel_probe,
.disconnect = skel_disconnect,
.id_table = skel_table,
};
探测和断开:当 一个设备被安装而USB核心认为该驱动程序应该处理时,探测函数被调用,探测函数检查传递给它的设备信息,确定驱动程序是否真的适合该设备。当驱动程序因 为某种原因不应该控制设备时,断开函数被调用,它可以做一些清理工作。探测回调函数中,USB驱动程序初始化任何可能用于控制USB设备的局部结构体,它 还把所需的任何设备相关信息保存到一个局部结构体中,
提交和控制urb:当驱动程序有数据要发送到USB设备时(大多数情况是在驱动程序的写函数中),要分配一个urb来把数据传输给设备:
/* 创建一个urb,并且给它分配一个缓存*/
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
retval = -ENOMEM;
goto error;
}
当urb被成功分配后,还要创建一个DMA缓冲区来以高效的方式发送数据到设备,传递给驱动程序的数据要复制到这块缓冲中去:
buf = usb_buffer_alloc(dev-udev, count, GFP_KERNEL, urb-transfer_dma);
if (!buf) {
retval = -ENOMEM;
goto error;
}
if (copy_from_user(buf, user_buffer, count)) {
retval = -EFAULT;
goto error;
}
当数据从用户空间正确复制到局部缓冲区后,urb必须在可以被提交给USB核心之前被正确初始化:
/* 初始化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;
然后urb就可以被提交给USB核心以传输到设备了:
/* 把数据从批量OUT端口发出 */
retval = usb_submit_urb(urb, GFP_KERNEL);
if (retval) {
err("%s - failed submitting write urb, error %d", __FUNCTION__, retval);
goto error;
}
当urb被成功传输到USB设备之后,urb回调函数将被USB核心调用,在我们的例子中,我们初始化urb,使它指向skel_write_bulk_callback函数,以下就是该函数:
static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
{
struct usb_skel *dev;
dev = (struct usb_skel *)urb-context;
if (urb-status
!(urb-status == -ENOENT ||
urb-status == -ECONNRESET ||
urb-status == -ESHUTDOWN)) {
dbg("%s - nonzero write bulk status received: %d",
__FUNCTION__, urb-status);
}
/* 释放已分配的缓冲区 */
usb_buffer_free(urb-dev, urb-transfer_buffer_length,
urb-transfer_buffer, urb-transfer_dma);
}
有时候USB驱动程序只是要发送或者接收一些简单的数据,驱动程序也可以不用urb来进行数据的传输,这是里涉及到两个简单的接口函数:usb_bulk_msg和usb_control_msg ,在这个USB框架程序里读操作就是这样的一个应用:
/* 进行阻塞的批量读以从设备获取数据 */
retval = usb_bulk_msg(dev-udev,
usb_rcvbulkpipe(dev-udev, dev-bulk_in_endpointAddr),
dev-bulk_in_buffer,
min(dev-bulk_in_size, count),
count, HZ*10);
/*如果读成功,复制到用户空间 */
if (!retval) {
if (copy_to_user(buffer, dev-bulk_in_buffer, count))
retval = -EFAULT;
else
retval = count;
}
usb_bulk_msg接口函数的定义如下:
int usb_bulk_msg(struct usb_device *usb_dev,unsigned int pipe,
void *data,int len,int *actual_length,int timeout);
其参数为:
struct usb_device *usb_dev:指向批量消息所发送的目标USB设备指针。
unsigned int pipe:批量消息所发送目标USB设备的特定端点,此值是调用usb_sndbulkpipe或者usb_rcvbulkpipe来创建的。
void *data:如果是一个OUT端点,它是指向即将发送到设备的数据的指针。如果是IN端点,它是指向从设备读取的数据应该存放的位置的指针。
int len:data参数所指缓冲区的大小。
int *actual_length:指向保存实际传输字节数的位置的指针,至于是传输到设备还是从设备接收取决于端点的方向。
int timeout:以Jiffies为单位的等待的超时时间,如果该值为0,该函数一直等待消息的结束。
如果该接口函数调用成功,返回值为0,否则返回一个负的错误值。
usb_control_msg接口函数定义如下:
int usb_control_msg(struct usb_device *dev,unsigned int pipe,__u8 request,__u8requesttype,__u16 value,__u16 index,void *data,__u16 size,int timeout)
除了允许驱动程序发送和接收USB控制消息之外,usb_control_msg函数的运作和usb_bulk_msg函数类似,其参数和usb_bulk_msg的参数有几个重要区别:
struct usb_device *dev:指向控制消息所发送的目标USB设备的指针。
unsigned int pipe:控制消息所发送的目标USB设备的特定端点,该值是调用usb_sndctrlpipe或usb_rcvctrlpipe来创建的。
__u8 request:控制消息的USB请求值。
__u8 requesttype:控制消息的USB请求类型值。
__u16 value:控制消息的USB消息值。
__u16 index:控制消息的USB消息索引值。
void *data:如果是一个OUT端点,它是指身即将发送到设备的数据的指针。如果是一个IN端点,它是指向从设备读取的数据应该存放的位置的指针。
__u16 size:data参数所指缓冲区的大小。
int timeout:以Jiffies为单位的应该等待的超时时间,如果为0,该函数将一直等待消息结束。
如果该接口函数调用成功,返回传输到设备或者从设备读取的字节数;如果不成功它返回一个负的错误值。
这两个接口函数都不能在一个中断上下文中或者持有自旋锁的情况下调用,同样,该函数也不能被任何其它函数取消,使用时要谨慎。
我们要给未知的USB设备写驱动程序,只需要把这个框架程序稍做修改就可以用了,前面我们已经说过要修改制造商和产品的ID号,把0xfff0这两个值改为未知USB的ID号。
#define USB_SKEL_VENDOR_ID 0xfff0
#define USB_SKEL_PRODUCT_ID 0xfff0
还 有就是在探测函数中把需要探测的接口端点类型写好,在这个框架程序中只探测了批量(USB_ENDPOINT_XFER_BULK)IN和OUT端点,可 以在此处使用掩码(USB_ENDPOINT_XFERTYPE_MASK)让其探测其它的端点类型,驱动程序会对USB设备的每一个接口进行一次探测, 当探测成功后,驱动程序就被绑定到这个接口上。再有就是urb的初始化问题,如果你只写简单的USB驱动,这块不用多加考虑,框架程序里的东西已经够用 了,这里我们简单介绍三个初始化urb的辅助函数:
usb_fill_int_urb :它的函数原型是这样的:
void usb_fill_int_urb(struct urb *urb,struct usb_device *dev,
unsigned int pipe,void *transfer_buff,
int buffer_length,usb_complete_t complete,
void *context,int interval);
这个函数用来正确的初始化即将被发送到USB设备的中断端点的urb。
usb_fill_bulk_urb :它的函数原型是这样的:
void usb_fill_bulk_urb(struct urb *urb,struct usb_device *dev,
unsigned int pipe,void *transfer_buffer,
int buffer_length,usb_complete_t complete)
这个函数是用来正确的初始化批量urb端点的。
usb_fill_control_urb :它的函数原型是这样的:
void usb_fill_control_urb(struct urb *urb,struct usb_device *dev,unsigned int pipe,unsigned char *setup_packet,void *transfer_buffer,int buffer_length,usb_complete_t complete,void *context);
这个函数是用来正确初始化控制urb端点的。
还有一个初始化等时urb的,它现在还没有初始化函数,所以它们在被提交到USB核心前,必须在驱动程序中手工地进行初始化,可以参考内核源代码树下的/usr/src/~/drivers/usb/media下的konicawc.c文件。
MODULE_DEVICE_TABLE
这个函数的主要功能是 注册设备表
主要有以下几种类型
将其中用到的设备表注册到内核,虽然不注册也可以工作,但是注册可以将我们表加入到相关文件中,便于内核管理设备。
MODULE_DEVICE_TABLE(类型, ID表);
设备树ID表
类型:of
C写的platform_device的ID表
类型:platform
C写的i2c设备的ID表
类型:i2c
C写的USB设备的ID表
类型:usb
以我目前遇到一个I2C实例说下比较清晰点
1、注册设备表,说明支持的类型
static const struct i2c_device_id kxcjk1013_id[] = {
{"kxcjk1013", KXCJK1013},
{"kxcj91008", KXCJ91008},
{"kxtj21009", KXTJ21009},
{}
};
MODULE_DEVICE_TABLE(i2c, kxcjk1013_id);
2、假如我在dts中定义支持设备为 第二组? {"kxcj91008", KXCJ91008},
DTS 参数如下
kxcj9@1e {
status = "disabled";
compatible = "kionix,kxcj91008";
reg = 0x1e;
interrupts = 0 65 1;
interrupt-names = "kxcj_irq";
irq_type = "GPIO_IRQ_RISING";
kxcj9,irq-gpio = gpio GPIODV_6? GPIO_ACTIVE_HIGH;
};
3、那么在设备probe的时候可以获取到对应的设备 Name 和 ID
static int kxcjk1013_probe(struct i2c_client *client,
? ? ? ? ? ? ? ? ? ? ? ? ? const struct i2c_device_id *id)
....
if (id) {
data-chipset = (enum kx_chipset)(id-driver_data);
name = id-name;
dev_info(client-dev, "name:%s id:%d\n", name, data-chipset);
}
....