花天岑 231830117
usb_detect
makefile
ifdef KERNELRELEASE
obj-m := usb_detect.o
else
KERNELDIR ?= /usr/lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
.PHONY:clean
clean:
-rm *.mod.c *.o *.order *.symvers *.ko
usb_detect.c
/*
* USB Detect driver
*
* This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
*/
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/usb.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);
模块加载
插入u盘
拔出u盘
卸载模块
硬盘读写速度
wirte
Makefile
ifneq ($(KERNELRELEASE),)
obj-m := write_to_disk.o
else
KERNELDIR ?= /usr/lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
.PHONY:clean
clean:
-rm *.mod.c *.o *.order *.symvers *.ko
write_to_disk.c
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timekeeping.h>
#define buf_size 1024
#define write_times 524288
MODULE_LICENSE("GPL");
static struct timespec64 ts_start, ts_end;
static int __init write_disk_init(void) {
struct file *fp_write;
char buf[buf_size];
int i;
loff_t pos;
time64_t start_sec, end_sec;
long start_nsec, end_nsec;
long write_time_us;
printk("Start write_to_disk module...\n");
// 初始化缓冲区
for (i = 0; i < buf_size; i++) {
buf[i] = i + '0';
}
// 打开文件
fp_write = filp_open("/tmp/test_file", O_RDWR | O_CREAT, 0644);
if (IS_ERR(fp_write)) {
printk("Failed to open file...\n");
return -1;
}
pos = 0;
// 获取开始时间
ktime_get_real_ts64(&ts_start);
start_sec = ts_start.tv_sec;
start_nsec = ts_start.tv_nsec;
// 执行写操作
for (i = 0; i < write_times; i++) {
ssize_t ret = kernel_write(fp_write, buf, buf_size, &pos);
}
// 获取结束时间
ktime_get_real_ts64(&ts_end);
end_sec = ts_end.tv_sec;
end_nsec = ts_end.tv_nsec;
// 计算耗时(微秒)
write_time_us = (end_sec - start_sec) * 1000000 + (end_nsec - start_nsec) / 1000;
// 输出结果
printk(KERN_INFO "Writing cost: %ld us\n", write_time_us);
printk(KERN_INFO "Write speed: %lld MB/s\n", (buf_size * (long long)write_times) / write_time_us);
filp_close(fp_write, NULL);
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);
read
Makefile
ifneq ($(KERNELRELEASE),)
obj-m := read_from_disk.o
else
KERNELDIR ?= /usr/lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif
.PHONY:clean
clean:
-rm *.mod.c *.o *.order *.symvers *.ko
read_from_disk.c
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/timekeeping.h>
#define buf_size 1024
#define read_times 524288
MODULE_LICENSE("GPL");
// 使用内核标准时间结构体
static struct timespec64 ts_start, ts_end;
static int __init read_disk_init(void) {
struct file *fp_read;
char *buf;
int i;
loff_t pos;
time64_t time_diff;
long nsec_diff;
long total_us;
ssize_t ret;
printk("Start read_from_disk module...\n");
buf = kmalloc(buf_size, GFP_KERNEL);
fp_read = filp_open("/tmp/test_file", O_RDONLY, 0);
if (IS_ERR(fp_read)) {
printk("Failed to open file...\n");
kfree(buf);
return -1;
}
pos = 0;
// 记录开始时间
ktime_get_real_ts64(&ts_start);
for (i = 0; i < read_times; i++) {
ret = kernel_read(fp_read, buf, buf_size, &pos);
}
// 记录结束时间
ktime_get_real_ts64(&ts_end);
// 计算时间差(微秒)
time_diff = ts_end.tv_sec - ts_start.tv_sec;
nsec_diff = ts_end.tv_nsec - ts_start.tv_nsec;
total_us = time_diff * 1000000 + nsec_diff / 1000;
// 计算速度(MB/s)
unsigned long long total_bytes = (unsigned long long)buf_size * read_times;
unsigned long speed = total_bytes / total_us;
printk("Read file costs: %ld us\n", total_us);
printk("Reading speed is: %lu MB/s\n", speed);
filp_close(fp_read, NULL);
kfree(buf);
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);