这里bInterval是主机轮询时间1表示125us

修改struct usb_descriptor_header *hidg_hs_descriptors[]加上刚刚增加的endpoint

static struct usb_descriptor_header *hidg_hs_descriptors[] = {

(struct usb_descriptor_header *)&hidg_interface_desc,

(struct usb_descriptor_header *)&hidg_desc,

(struct usb_descriptor_header *)&hidg_hs_in_ep_desc,

#ifdef CONFIG_INTOUT

(struct usb_descriptor_header *)&hidg_hs_out_ep_desc,

#endif

NULL,

};

hs也相应的加上中断out端点

#ifdef CONFIG_INTOUT

static struct usb_endpoint_descriptor hidg_fs_out_ep_desc = {

.bLength  = USB_DT_ENDPOINT_SIZE,

.bDescriptorType = USB_DT_ENDPOINT,

.bEndpointAddress = USB_DIR_OUT,

.bmAttributes  = USB_ENDPOINT_XFER_INT,

/*.wMaxPacketSize = DYNAMIC */

.bInterval  = 1, /* FIXME: Add this field in the

* HID gadget configuration?

* (struct hidg_func_descriptor)

*/

};

#endif

static struct usb_descriptor_header *hidg_fs_descriptors[] = {

(struct usb_descriptor_header *)&hidg_interface_desc,

(struct usb_descriptor_header *)&hidg_desc,

(struct usb_descriptor_header *)&hidg_fs_in_ep_desc,

#ifdef CONFIG_INTOUT

(struct usb_descriptor_header *)&hidg_fs_out_ep_desc,

#endif

NULL,

};

修改hidg_bind函数 增加对中端OUT的一些初始化

static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)

{

struct usb_ep        *ep;

struct f_hidg        *hidg = func_to_hidg(f);

int            status;

dev_t            dev;

/* allocate instance-specific interface IDs, and patch descriptors */

status = usb_interface_id(c, f);

if (status < 0)

goto fail;

hidg_interface_desc.bInterfaceNumber = status;

/* allocate instance-specific endpoints */

status = -ENODEV;

ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_in_ep_desc);

if (!ep)

goto fail;

ep->driver_data = c->cdev;    /* claim */

hidg->in_ep = ep;

#ifdef CONFIG_INTOUT

status = -ENODEV;

ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_out_ep_desc);

if (!ep)

goto fail;

ep->driver_data = c->cdev;    /* claim */

hidg->out_ep = ep;

/* preallocate request and buffer */

status = -ENOMEM;

hidg->rx_req = usb_ep_alloc_request(hidg->out_ep, GFP_KERNEL);

if (!hidg->rx_req)

goto fail;

hidg->rx_req->buf = kmalloc(hidg->report_length, GFP_KERNEL);

if (!hidg->rx_req->buf)

goto fail;

hidg->rx_req->length = hidg->report_length;

hidg->rx_length = hidg->report_length;

hidg->rx_req->status   = 0;

hidg->rx_req->zero     = 0;

hidg->rx_req->context  = hidg;

hidg->rx_req->complete = hidg_read_complete;

#endif

/* preallocate request and buffer */

status = -ENOMEM;

hidg->req = usb_ep_alloc_request(hidg->in_ep, GFP_KERNEL);

if (!hidg->req)

goto fail;

hidg->req->buf = kmalloc(hidg->report_length, GFP_KERNEL);

if (!hidg->req->buf)

goto fail;

/* set descriptor dynamic values */

hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass;

hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol;

hidg_hs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);

hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(64);

#ifdef CONFIG_INTOUT

hidg_hs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);

hidg_fs_out_ep_desc.wMaxPacketSize = cpu_to_le16(64);

#endif

hidg_desc.desc[0].bDescriptorType = HID_DT_REPORT;

hidg_desc.desc[0].wDescriptorLength =

cpu_to_le16(hidg->report_desc_length);

hidg->set_report_buff = NULL;

/* copy descriptors */

f->descriptors = usb_copy_descriptors(hidg_fs_descriptors);

if (!f->descriptors)

goto fail;

if (gadget_is_dualspeed(c->cdev->gadget)) {

hidg_hs_in_ep_desc.bEndpointAddress =

hidg_fs_in_ep_desc.bEndpointAddress;

#ifdef CONFIG_INTOUT

hidg_hs_out_ep_desc.bEndpointAddress =

hidg_fs_out_ep_desc.bEndpointAddress;

#endif

f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);

if (!f->hs_descriptors)

goto fail;

}

mutex_init(&hidg->lock);

spin_lock_init(&hidg->spinlock);

init_waitqueue_head(&hidg->write_queue);

init_waitqueue_head(&hidg->read_queue);

#ifdef CONFIG_INTOUT

init_waitqueue_head(&hidg->read_wq);

#endif

/* create char device */

cdev_init(&hidg->cdev, &f_hidg_fops);

dev = MKDEV(major, hidg->minor);

status = cdev_add(&hidg->cdev, dev, 1);

if (status)

goto fail;

device_create(hidg_class, NULL, dev, NULL, "%s%d", "hidg", hidg->minor);

#ifdef USE_FIFO

//add by hclydao

status = kfifo_alloc(&recv_fifo, RECV_LEN, GFP_KERNEL);

if (status) {

printk(KERN_ERR "+++++++++++ error kfifo_alloc\n");

goto fail;

}

#endif

return 0;

fail:

ERROR(f->config->cdev, "hidg_bind FAILED\n");

if (hidg->req != NULL) {

kfree(hidg->req->buf);

if (hidg->in_ep != NULL)

usb_ep_free_request(hidg->in_ep, hidg->req);

}

usb_free_descriptors(f->hs_descriptors);

usb_free_descriptors(f->descriptors);

return status;

}

然后修改hidg_set_alt增加中断OUT的使能

static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)

{

struct usb_composite_dev  *cdev = f->config->cdev;

struct f_hidg    *hidg = func_to_hidg(f);

int status = 0;

VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);

if (hidg->in_ep != NULL) {

/* restart endpoint */

if (hidg->in_ep->driver_data != NULL)

usb_ep_disable(hidg->in_ep);

status = config_ep_by_speed(f->config->cdev->gadget, f,

hidg->in_ep);

if (status) {

ERROR(cdev, "config_ep_by_speed FAILED!\n");

goto fail;

}

status = usb_ep_enable(hidg->in_ep);

if (status < 0) {

ERROR(cdev, "Enable endpoint FAILED!\n");

goto fail;

}

hidg->in_ep->driver_data = hidg;

}

#ifdef CONFIG_INTOUT

if (hidg->out_ep != NULL) {

/* restart endpoint */

if (hidg->out_ep->driver_data != NULL)

usb_ep_disable(hidg->out_ep);

status = config_ep_by_speed(f->config->cdev->gadget, f,

hidg->out_ep);

if (status) {

ERROR(cdev, "config_ep_by_speed FAILED!\n");

goto fail;

}

status = usb_ep_enable(hidg->out_ep);

if (status < 0) {

ERROR(cdev, "Enable endpoint FAILED!\n");

goto fail;

}

hidg->out_ep->driver_data = hidg;

}

#endif

fail:

return status;

}

我们先把

hidg->rx_req->complete = hidg_read_complete;

注释掉

一般到这里 编译完成下载就可以看到中断out端点了 此时如果使用bushond通过中断端点发送数据不同的平台就会有不同的现象 在这纠结了很久 4418如果到这里用bushond

通过中断OUT发送数据 发送不成功 可以通过USBlyzer监控 这时一直阻塞着 如果是2416第一次可以发送成功 但是第二次就成了阻塞状态了 最后找到原来是没有调用usb_ep_queue把out端点的相关处理加到队列中去

打开刚刚的注释 下面两个函数同时修改hidg_poll

#ifdef CONFIG_INTOUT

static ssize_t hidg_read(struct file *file, char __user *buffer,

size_t count, loff_t *ptr)

{

struct f_hidg *hidg     = file->private_data;

char  *tmp_buff = NULL;

unsigned long flags;

unsigned int copied;

if (!count)

return 0;

if (!access_ok(VERIFY_WRITE, buffer, count))

return -EFAULT;

spin_lock_irqsave(&hidg->spinlock, flags);

#ifndef USE_FIFO

#define READ_COND (hidg->set_report_buff != NULL)

#else

#define READ_COND (!kfifo_is_empty(&recv_fifo))

#endif

while (!READ_COND) {

spin_unlock_irqrestore(&hidg->spinlock, flags);

if (file->f_flags & O_NONBLOCK)

return -EAGAIN;

if (wait_event_interruptible(hidg->read_wq, READ_COND))

return -ERESTARTSYS;

spin_lock_irqsave(&hidg->spinlock, flags);

}

count = min_t(unsigned, count, hidg->rx_length);

tmp_buff = hidg->set_report_buff;

hidg->set_report_buff = NULL;

spin_unlock_irqrestore(&hidg->spinlock, flags);

if (tmp_buff != NULL) {

/* copy to user outside spinlock */

count -= copy_to_user(buffer, tmp_buff, count);

kfree(tmp_buff);

} else

count = -ENOMEM;

#ifdef USE_FIFO

//add by hclydao

count = kfifo_to_user(&recv_fifo,buffer,hidg->rx_length,&copied);

return copied;

#else

return count;

#endif

}

static void hidg_read_complete(struct usb_ep *ep, struct usb_request *req)

{

struct f_hidg *hidg = (struct f_hidg *)req->context;

int ret;

if (req->status != 0 || req->buf == NULL || req->actual == 0) {

ERROR(hidg->func.config->cdev,"%s FAILED\n", __func__);

return;

}

spin_lock(&hidg->spinlock);

//hclydao

kfifo_in(&recv_fifo, req->buf, req->actual);

spin_unlock(&hidg->spinlock);

wake_up(&hidg->read_wq);

hidg->rx_req->zero = 0;

hidg->rx_req->length = hidg->rx_length;

ret = usb_ep_queue(hidg->out_ep, hidg->rx_req, GFP_ATOMIC);

if (ret < 0)

ERROR(hidg->func.config->cdev, "usb_ep_queue error on ep0 %d\n", ret);

}

#endif

static unsigned int f_hidg_poll(struct file *file, poll_table *wait)

{

struct f_hidg *hidg  = file->private_data;

unsigned int ret = 0;

#ifdef CONFIG_INTOUT

poll_wait(file, &hidg->read_wq, wait);

#else

poll_wait(file, &hidg->read_queue, wait);

#endif

poll_wait(file, &hidg->write_queue, wait);

if (WRITE_COND)

ret |= POLLOUT | POLLWRNORM;

if (READ_COND)

ret |= POLLIN | POLLRDNORM;

return ret;

}

同时还需要修改hidg_setup函数

case HID_DT_REPORT:

VDBG(cdev, "USB_REQ_GET_DESCRIPTOR: REPORT\n");

length = min_t(unsigned short, length,

hidg->report_desc_length);

memcpy(req->buf, hidg->report_desc, length);

if (usb_ep_queue(hidg->out_ep, hidg->rx_req, GFP_ATOMIC) < 0) {

printk("+++usb_ep_queue error on ep out\n");

return -1;

}

goto respond;

break;

当hidg设备被识别后 需要queue一次out端点 才能正常发送数据 也可以在hidg_open中增加queue函数 但是热插拔就会出问题 所以加到这里.这样基本上就可以了 最后修改hid.c中的你自己的struct hidg_func_descriptor中

.report_length  = 1024,

同时修改.report_desc中的报告大小

0x75, 0x40,

Report Size 64位以及

0x95, 0x80,

所有的REPORT_COUNT (128) 由于PC端的测试程序最后是读取这个里面的参数确定每次发送的数据大小 这样最后就是64x128=1024B

经测试速度可以达到900KB/s

hid在linux上的轮训时间,linux 自定义hid速度优化相关推荐

  1. hid在linux上的轮训时间,LINUX下USB1.1设备学习小记(6)_hid与input子系统(1)

    现在终于开始匹配设备的接口驱动了 目标当然是hid,当然在了解驱动初始化过程之前,让我们先看看一下hid协议 我对hid协议的理解是建立在鼠标上的,所以如果有理解不当的地方,请务必请大家指出 我们先来 ...

  2. linux上安装telnet服务器:linux vmvare虚拟机 安装telnet redhat9

    linux上安装telnet服务器:linux vmvare虚拟机 安装telnet redhat9 参考:http://blog.sina.com.cn/s/blog_5688414b0100bhr ...

  3. linux自动登出时间,Linux 上让一段时间不活动的用户自动登出方法介绍

    让我们想象这么一个场景.你有一台服务器经常被网络中各系统的很多个用户访问.有可能出现某些用户忘记登出会话让会话保持会话处于连接状态.我们都知道留下一个处于连接状态的用户会话是一件多么危险的事情.有些用 ...

  4. linux 上自动执行caffe,linux下caffe的命令运行脚本

    参考:https://www.cnblogs.com/denny402/p/5076285.html 首先编译: make -j8 make pycaffe 注:下面的--solver=.... 等价 ...

  5. linux ps查看完整时间,Linux ps 命令查看进程启动及运行时间

    引言 同事问我怎样看一个进程的启动时间和运行时间,我第一反应当然是说用 ps 命令啦. ps aux或ps -ef不就可以看时间吗? ps aux选项及输出说明 我们来重新复习下ps aux的选项,这 ...

  6. linux 禁止文件修改时间,linux 修改文件的时间属性

    二.修改文件时间 创建文件我们可以通过touch来创建.同样,我们也可以使用touch来修改文件时间.touch的相关参数如下: -a : 仅修改access time. -c : 仅修改时间,而不建 ...

  7. linux上用户管理,掌握Linux上的用户管理

    您是Linux管理员吗?您是否在Linux命令行中创建/删除用户?如果是,那么本文适合您!阅读以下内容后,您将能够在Linux系统中操纵用户和组权限.在下面的示例中,sai是用户名. 用户模组 use ...

  8. 查看linux内核的编译时间,linux内核编译步骤

    linux内核编译步骤 对于linux新手来说,编译内核相对有一些难度,甚至不知道如何入手,我通过在网上收集这方面的资料,最终编译成功.现在我归纳了一下,写出这一篇还算比较详细的步骤,希望能对各位新手 ...

  9. linux修改硬件系统时间,Linux修改日期、时间,系统与硬件时间

    Linux的时间分为两种,硬件时间和系统时间两种: 一.查看与修改系统时间 查看系统时间:date # date Fri Nov 26 15:20:18 CST 1999 用指定的格式显示系统时间:  ...

最新文章

  1. [裴礼文数学分析中的典型问题与方法习题参考解答]4.3.15
  2. 在处理向该请求提供服务所需的配置文件时出错。请检查下面的特定错误详细信息并适当地修改配置文件。...
  3. 2021年第十二届蓝桥杯 - 省赛 - C/C++大学A组 - D.路径
  4. java 序列化保存_保存到二进制/序列化Java
  5. 【微服务架构】SpringCloud组件和概念介绍(一)
  6. 华为手机海拔测试软件,华为手机海拔高度测量仪
  7. java 股票数据接口_股票数据查询接口
  8. CTFSHOW 愚人节欢乐赛WP
  9. 计算机的开机键在哪里设置,笔记本电脑怎么开机 笔记本电脑开机键在哪
  10. mysql自定义函数的分号_MySQL 第八篇:自定义函数、存储过程、游标-阿里云开发者社区...
  11. HOE-32020,23554-99-6用于染色DNA的蓝色荧光染料
  12. 你真的会在阳光下拍照片么?
  13. 利用PHPExcel将数据导出到xls格式的excel文件
  14. rust怎么拆除墙壁指令_腐蚀RUST基本指令及服务器指令大全
  15. ASO马甲包:马甲包上架注意事项
  16. 3D卷积和去(反)卷积
  17. 用ssh方法scp,从本地传输文件到服务器
  18. 【转】SCI论文写作全攻略
  19. Python批量处理大量excel数据(含完整代码)
  20. Java刷算法:收藏大法

热门文章

  1. 单件模式与业务逻辑服务层封装
  2. 利用 S3-tests 测试 S3 接口兼容性
  3. java new一个线程执行完后会自动销毁吗_Java基础总结,超级全的面试题
  4. 深入理解K8S网络原理下
  5. Flink流式处理百万数据量CSV文件
  6. Spark源码打包编译的过程
  7. mysql 创建索引 终止_技术分享 | 常见索引问题处理
  8. CentOS下rpm命令详解
  9. Python入门7_抽象进阶
  10. mysql线上问题之Lock wait timeout exceeded; try restarting transaction