花天岑 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);

iozone