1、编写USB设备驱动程序
usb_detect.c:
/*
* USB Detect driver
*
* This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/kref.h>
#include <linux/uaccess.h>
#include <linux/usb.h>
#include <linux/mutex.h>
/* Define these values to match your devices */
#define USB_DETECT_VENDOR_ID 0x0951
#define USB_DETECT_PRODUCT_ID 0x160b
/* table of devices that work with this driver */
static const struct usb_device_id usbdetect_table[] = {
{ USB_DEVICE(USB_DETECT_VENDOR_ID, USB_DETECT_PRODUCT_ID) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, usbdetect_table);
/* Get a minor range for your devices from the usb maintainer */
#define USB_DETECT_MINOR_BASE 192
#define WRITES_IN_FLIGHT 8
/* arbitrarily chosen */
/* Structure to hold all of our device specific stuff */
struct usb_detect {
struct usb_device *udev; /* the usb device for this device */
struct usb_interface *interface; /* the interface for this device */
struct semaphore limit_sem; /* limiting the number of writes in progress */
struct usb_anchor submitted; /* in case we need to retract our submissions */
struct urb *bulk_in_urb; /* the urb to read data with */
unsigned char *bulk_in_buffer; /* the buffer to receive data */
size_t bulk_in_size; /* the size of the receive buffer */
size_t bulk_in_filled; /* number of bytes in the buffer */
size_t bulk_in_copied; /* already copied to user space */
__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
__u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
int errors; /* the last request tanked */
bool ongoing_read; /* a read is going on */
spinlock_t err_lock; /* lock for errors */
struct kref kref;
struct mutex io_mutex; /* synchronize I/O with disconnect */
unsigned long disconnected:1;
wait_queue_head_t bulk_in_wait; /* to wait for an ongoing read */
};
#define to_detect_dev(d) container_of(d, struct usb_detect, kref)
static struct usb_driver usbdetect_driver;
static void usbdetect_delete(struct kref *kref)
{
struct usb_detect *dev = to_detect_dev(kref);
usb_free_urb(dev->bulk_in_urb);
usb_put_intf(dev->interface);
usb_put_dev(dev->udev);
kfree(dev->bulk_in_buffer);
kfree(dev);
}
static const struct file_operations usbdetect_fops = {};
/*
* usb class driver info in order to get a minor number from the usb core,
* and to have the device registered with the driver core
*/
static struct usb_class_driver usbdetect_class = {
.name = "usbdetect%d",
.fops = &usbdetect_fops,
.minor_base = USB_DETECT_MINOR_BASE,
};
static int usbdetect_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct usb_detect *dev;
struct usb_endpoint_descriptor *bulk_in, *bulk_out;
int retval;
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
kref_init(&dev->kref);
sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
mutex_init(&dev->io_mutex);
spin_lock_init(&dev->err_lock);
init_usb_anchor(&dev->submitted);
init_waitqueue_head(&dev->bulk_in_wait);
dev->udev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = usb_get_intf(interface);
/* set up the endpoint information */
/* use only the first bulk-in and bulk-out endpoints */
retval = usb_find_common_endpoints(interface->cur_altsetting,
&bulk_in, &bulk_out, NULL, NULL);
if (retval) {
dev_err(&interface->dev,
"Could not find both bulk-in and bulk-out endpoints\n");
goto error;
}
dev->bulk_in_size = usb_endpoint_maxp(bulk_in);
dev->bulk_in_endpointAddr = bulk_in->bEndpointAddress;
dev->bulk_in_buffer = kmalloc(dev->bulk_in_size, GFP_KERNEL);
if (!dev->bulk_in_buffer) {
retval = -ENOMEM;
goto error;
}
dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->bulk_in_urb) {
retval = -ENOMEM;
goto error;
}
dev->bulk_out_endpointAddr = bulk_out->bEndpointAddress;
/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);
/* we can register the device now, as it is ready */
retval = usb_register_dev(interface, &usbdetect_class);
if (retval) {
/* something prevented us from registering this driver */
dev_err(&interface->dev,
"Not able to get a minor for this device.\n");
usb_set_intfdata(interface, NULL);
goto error;
}
/* let the user know what node this device is now attached to */
dev_info(&interface->dev,
"USB detect device now attached to USBdetect-%d",
interface->minor);
return 0;
error:
/* this frees allocated memory */
kref_put(&dev->kref, usbdetect_delete);
return retval;
}
static void usbdetect_disconnect(struct usb_interface *interface)
{
struct usb_detect *dev;
int minor = interface->minor;
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
/* give back our minor */
usb_deregister_dev(interface, &usbdetect_class);
/* prevent more I/O from starting */
mutex_lock(&dev->io_mutex);
dev->disconnected = 1;
mutex_unlock(&dev->io_mutex);
usb_kill_anchored_urbs(&dev->submitted);
/* decrement our usage count */
kref_put(&dev->kref, usbdetect_delete);
dev_info(&interface->dev, "USB detect #%d now disconnected", minor);
}
static struct usb_driver usbdetect_driver = {
.name = "usbdetect",
.probe = usbdetect_probe,
.disconnect = usbdetect_disconnect,
.id_table = usbdetect_table,
.supports_autosuspend = 1,
};
MODULE_LICENSE("GPL v2");
static int __init usb_detect_init(void)
{
int result;
printk("Start usb_detect module...");
/* register this driver with the USB subsystem */
result = usb_register(&usbdetect_driver);
if (result < 0) {
printk("usb_register failed.""Error number %d", result);
return -1;
}
return 0;
}
static void __exit usb_detect_exit(void)
{
printk("Exit usb_detect module...");
/* deregister this driver with the USB subsystem */
usb_deregister(&usbdetect_driver);
}
module_init(usb_detect_init);
module_exit(usb_detect_exit);
对usb_detect.c编译运行:
模拟插入U盘:
lsusb指令查看u盘信息:
-
用法: lsusb [options]
-
功能:查看/列出USB设备
-
参数说明:
-v, --verbose 增加详细程度(显示描述符),列出所有USB的详细
-s [[bus]:][devnum] 仅显示具有指定设备和/或总线号的设备(十进制)
-d vendor:[product] 仅显示具有指定供应商和产品ID号(十六进制)的设备
-D device 选择lsusb将检查的设备
-t, --tree 将物理USB设备层次结构转储为树
-V, --version 显示程序版本
-h, --help 显示用法和帮助
查看U盘信息:
插拔一次U盘,设备号加1:
拔出U盘,查看打印信息,发现5号usb已经断开:
查看U盘信息:
卸载模块:
2、编写内核模块测试硬盘的读写速率,并与 iozone工具的测试结果比较
相关内核函数:
-
filp_open() //打开文件
-
filp_close() //关闭文件
-
kernel_read() //读文件
-
kernel_write() //写文件
使用IOZONE工具测试读写速度:
最近刚好了解到ssh远程登录,在此尝试使用windows主机cmd来登录openeuler虚拟机:
查看内存大小:
读写测试:
最小测试文件设置为512M,最大4G,并生成xls文件。
运行结果报告:
write_to_disk.c:
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/rtc.h>
#define buf_size 1024
#define write_times 524288
MODULE_LICENSE("GPL");
struct timeval tv;
static int __init write_disk_init(void)
{
struct file *fp_write;
char buf[buf_size];
int i;
int write_start_time;
int write_start_time_u;
int write_end_time;
int write_end_time_u;
int write_time;
loff_t pos;
printk("Start write_to_disk module...\n");
for(i = 0; i < buf_size; i++)
{
buf[i] = i + '0';
}
fp_write = filp_open("/home/tmp_file", O_RDWR | O_CREAT,0644);
if (IS_ERR(fp_write)) {
printk("Failed to open file...\n");
return -1;
}
pos = 0;
do_gettimeofday(&tv);
write_start_time = (int)tv.tv_sec;
write_start_time_u = (int)tv.tv_usec;
for(i = 0; i < write_times; i++) {
kernel_write(fp_write, buf, buf_size, &pos);
}
do_gettimeofday(&tv);
write_end_time = (int)tv.tv_sec;
write_end_time_u = (int)tv.tv_usec;
filp_close(fp_write, NULL);
write_time = (write_end_time - write_start_time) * 1000000 + (write_end_time_u - write_start_time_u);
printk(KERN_ALERT "Writing to file costs %d us\n", write_time);
printk("Writing speed is %d M/s\n", buf_size * write_times / write_time);
return 0;
}
static void __exit write_disk_exit(void)
{
printk("Exit write_to_disk module...\n");
}
module_init(write_disk_init);
module_exit(write_disk_exit);
测试写速度:
得出写速率为17M/s。
read_from_disk.c:
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/rtc.h>
#define buf_size 1024
#define read_times 524288
MODULE_LICENSE("GPL");
struct timeval tv;
static int __init read_disk_init(void)
{
struct file *fp_read;
char buf[buf_size];
int i;
int read_start_time;
int read_start_time_u;
int read_end_time;
int read_end_time_u;
int read_time;
loff_t pos;
printk("Start read_from_disk module...\n");
fp_read = filp_open("/home/tmp_file", O_RDONLY, 0);
if (IS_ERR(fp_read)) {
printk("Failed to open file...\n");
return -1;
}
do_gettimeofday(&tv);
read_start_time = (int)tv.tv_sec;
read_start_time_u = (int)tv.tv_usec;
pos = 0;
for(i = 0; i < read_times; i++) {
kernel_read(fp_read, buf, buf_size, &pos);
}
do_gettimeofday(&tv);
read_end_time = (int)tv.tv_sec;
read_end_time_u = (int)tv.tv_usec;
filp_close(fp_read, NULL);
read_time = (read_end_time - read_start_time) * 1000000 + (read_end_time_u - read_start_time_u);
printk(KERN_ALERT "Read file costs %d us\n", read_time);
printk("Reading speed is %d M/s\n", buf_size * read_times / read_time);
return 0;
}
static void __exit read_disk_exit(void)
{
printk("Exit read_from_disk module...\n");
}
module_init(read_disk_init);
module_exit(read_disk_exit);
测试读速度:
读速率为2932M/s。
用户态的读写速率比内核态更慢。
原因说明:
内核态:CPU可以访问内存所有数据, 包括外围设备, 例如硬盘、网卡;CPU也可以将自己从一个程序切换到另一个程序
用户态:只能受限的访问内存, 且不允许访问外围设备;占用CPU的能力被剥夺,CPU资源可以被其他程序获取。
也就是说:内核态的程序可以直接读写硬盘;而用户态的程序需要先切换至内核态,再由内核态进行系统调用来读写磁盘。因此,用户态的硬盘读写速率比内核态更耗时。