上文将设备侧的端点1作为中断输入端点,来传输数据。
也可以以将端点1定义成批量端点,来传输数据。分为两个部分,设备侧和主机侧。端点的类型对设备侧编程几乎没有影响,主要是对主机侧的影响,体现在后面再说...。
设备侧只改一个地方,是端点描述符的属性,就是设备要告诉主机说我是批量端点请您做好准备,如下
主机侧要改的地方也没几个,将操作中断输入端点的洞洞改成批量端点的就行。
pipe = usb_rcvbulkpipe(dev, endpoint->bEndpointAddress); //申请批量管道
usb_fill_bulk_urb //初始化urb时使用批量管道
usb_endpoint_is_bulk_in //判断是否是批量输入端点
我觉得批量端点和中断端点的不同之处在于usb主控器驱动(or usbcore)对这两种端点类型的访问方式和大小控制---看到的不要全信,仅是个人笔记,若有错欢迎指正。
①对于中断端点,usb主控制器驱动会自动按照该端点描述符里的bInterval请求周期去发in令牌包请求数据而对批量端点则不会如此做,大概是由于中断端点一般用于hid设备,需要人机交互,实时性要求较高,而批量端点不是时刻都在传递数据,而是每次传输较多数据。这也导致了下面不同。
②对于中断端点,协议规定的可支持的最大容量远远小于批量端点。
③在具体驱动里面区别不大,访问哪种端点就申请哪种pipe就行,然后用这个pipe初始化urb再提交即可。
所以对于不需要实时传递数据的数据流就用批量端点实现。会减少主机linux的开销。
也可以以将端点1定义成批量端点,来传输数据。分为两个部分,设备侧和主机侧。端点的类型对设备侧编程几乎没有影响,主要是对主机侧的影响,体现在后面再说...。
设备侧只改一个地方,是端点描述符的属性,就是设备要告诉主机说我是批量端点请您做好准备,如下
//struct HID_DESCRIPTOR Hid_Desc;
{
0x07, // bLength
0x05, // bDescriptorType
0x81, // bEndpointAddress
0x02, // bmAttributes 02是批量端点,03中断端点
SWAP16( EP1_PACKET_SIZE ), // MaxPacketSize (LITTLE ENDIAN)
EP_INTERVAL // bInterval 如果bmAttributes=02,则此项就没用了,因为主机驱动中根本没用到这个东东
}, //end of Endpoint1Desc
主机侧要改的地方也没几个,将操作中断输入端点的洞洞改成批量端点的就行。
pipe = usb_rcvbulkpipe(dev, endpoint->bEndpointAddress); //申请批量管道
usb_fill_bulk_urb //初始化urb时使用批量管道
usb_endpoint_is_bulk_in //判断是否是批量输入端点
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* USB HIDBP test support
*/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Should you need to contact me, the author, you can do so either by
* e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb/input.h>
#include <linux/hid.h>
#include <linux/miscdevice.h>
#include <asm/uaccess.h>
/*
* Version Information
*/
#define DRIVER_VERSION "v1.0"
#define DRIVER_AUTHOR "song"
#define DRIVER_DESC "usb test"
#define DRIVER_LICENSE "GPL"
#define DEVICE_NAME "song_data_dev"
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
#define DEBUG
#ifdef DEBUG
#define DBG(...) printk(" DBG(%s, %s(), %d): ", __FILE__, __FUNCTION__, __LINE__); printk(__VA_ARGS__)
#else
#define DBG(...)
#endif
struct usb_test {
char name[128];
char phys[64];
struct usb_device *usbdev;
struct miscdevice *dev;
struct urb *irq;
unsigned char *data;
dma_addr_t data_dma;
} ;
static struct usb_test *test;
union flt_chr
{
//float flt;
unsigned int flt;
unsigned char chr[4];
}fltchr;
static struct timer_list report_timer;
static unsigned short t_interval = HZ;//delay 1 s
ssize_t read_test(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
int ret;
if (count == 0) return count;
DBG("to copy to user %d bytes\n", count);
ret = copy_to_user(buf, test->data, count);//kbuf->buf,if success,ret=0
DBG("copied %d bytes \n", count-ret);
return count-ret ; //return the bytes quantity have copied
}
static struct file_operations dev_fops = {
// .owner = THIS_MODULE,
// .open = open_test,
.read = read_test,
// .write = write_test,
// .release= release_test,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &dev_fops,
};
static void handle_timer(unsigned long data)
{ /* int i;
for(i=0;i<8;i++){
fltchr.chr[0]=test->data[i*4];
fltchr.chr[1]=test->data[i*4+1];
fltchr.chr[2]=test->data[i*4+2];
fltchr.chr[3]=test->data[i*4+3];
DBG("%d\n",fltchr.flt);
}
DBG("ok\n");
report_timer.expires = jiffies + t_interval;
add_timer(&report_timer); */
}
static void usb_test_irq(struct urb *urb)
{
struct usb_test *test = urb->context;
if (usb_submit_urb(test->irq, GFP_KERNEL))
{
DBG("err\n");
}
}
static int test_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
struct miscdevice *miscdev;
int pipe, maxp;
int error = -ENOMEM;
DBG("ok\n");
interface = intf->cur_altsetting;
if (interface->desc.bNumEndpoints != 2)
{
DBG("err\n");
return -ENODEV;
}
DBG("ok\n");
endpoint = &interface->endpoint[0].desc;
if(!usb_endpoint_is_bulk_in(endpoint))
{
DBG("err !usb_endpoint_is_bulk_in\n");
return -ENODEV;
}
/*
if (!usb_endpoint_is_bulk_in(endpoint))
{
DBG("err\n");
return -ENODEV;
}
*/
DBG("ok usb_endpoint_is_bulk_in\n");
//pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
pipe = usb_rcvbulkpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
DBG("maxp=%d\n",maxp);
test = kzalloc(sizeof(struct usb_test), GFP_KERNEL);//test
if (!test)
goto fail1;
miscdev = &misc;
test->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &test->data_dma);//test->data
if (!test->data)
goto fail2;
test->irq = usb_alloc_urb(0, GFP_KERNEL);//test->irq
if (!test->irq)
goto fail3;
test->usbdev = dev;
test->dev = miscdev;
if (dev->manufacturer)
strlcpy(test->name, dev->manufacturer, sizeof(test->name));
if (dev->product) {
if (dev->manufacturer)
strlcat(test->name, " ", sizeof(test->name));
strlcat(test->name, dev->product, sizeof(test->name));
}
/*usb_fill_int_urb(test->irq, dev, pipe, test->data,
(maxp > 8? maxp : 8 ),
usb_test_irq, test, endpoint->bInterval);*/
usb_fill_bulk_urb(test->irq,
dev,
pipe,
test->data,
maxp,
usb_test_irq,
test);
test->irq->transfer_dma = test->data_dma;
test->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
misc_register(&misc);
//usb_set_intfdata(intf, test);
DBG("ok\n");
if (usb_submit_urb(test->irq, GFP_KERNEL))
{
DBG("err\n");
return -EIO;
}
DBG("ok\n");
init_timer(&report_timer);
report_timer.expires = jiffies + t_interval;
report_timer.function = handle_timer;
add_timer(&report_timer);
DBG("ok\n");
return 0;
fail3: usb_free_urb(test->irq);
fail2: usb_buffer_free(dev, 8, test->data, test->data_dma);
fail1: kfree(test);
DBG("err\n");
return error;
}
static void test_usb_disconnect(struct usb_interface *intf)
{
del_timer(&report_timer);
misc_deregister(&misc);
printk("disconnect\n");
}
static struct usb_device_id test_usb_id_table [] = {
{USB_DEVICE(0x0606,0x0001) }, /* Terminating entry */
{}
};
MODULE_DEVICE_TABLE (usb, test_usb_id_table);
static struct usb_driver test_usb_driver = {
.name = "test_song",
.probe = test_usb_probe,
.disconnect = test_usb_disconnect,
.id_table = test_usb_id_table,
};
static int __init test_usb_init(void)
{
int retval = usb_register(&test_usb_driver);
if (retval == 0)
DBG("usb_register success!\n");
return retval;
}
static void __exit test_usb_exit(void)
{
usb_deregister(&test_usb_driver);
DBG("usb_deregister success!\n");
}
module_init(test_usb_init);
module_exit(test_usb_exit);
执行结果如下:
[root@FriendlyARM plg]# usb 1-1.1: new full speed USB device using s3c2410-ohci and address 4
usb 1-1.1: New USB device found, idVendor=0606, idProduct=0001
usb 1-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 1-1.1: Product: nRF24LU1 ADapter
usb 1-1.1: Manufacturer: Weisdigital
usb 1-1.1: SerialNumber: Ver1.0 N000
usb 1-1.1: configuration #1 chosen from 1 choice
DBG(/opt/usb/test_usb.c, test_usb_probe(), 143): ok
DBG(/opt/usb/test_usb.c, test_usb_probe(), 151): ok
DBG(/opt/usb/test_usb.c, test_usb_probe(), 169): ok usb_endpoint_is_bulk_in //是批量端点
DBG(/opt/usb/test_usb.c, test_usb_probe(), 174): maxp=32
DBG(/opt/usb/test_usb.c, test_usb_probe(), 217): ok
DBG(/opt/usb/test_usb.c, test_usb_probe(), 224): ok
DBG(/opt/usb/test_usb.c, test_usb_probe(), 230): ok
[root@FriendlyARM plg]#
[root@FriendlyARM plg]# ./read_app /dev/song_data_dev
DBG(read_app.c, main(), 26): press Ctrl-C to stop DBG(/opt/usb/test_usb.c, read_test(), 84): to copy to user 32 bytes
DBG(/opt/usb/test_usb.c, read_test(), 87): copied 32 bytes
DBG(read_app.c, main(), 34): to read : 32 bytes
DBG(read_app.c, main(), 37): return : 32 bytes
DBG(read_app.c, main(), 44): 3436 mv
DBG(read_app.c, main(), 44): 3436 mv
DBG(read_app.c, main(), 44): 1725 mv
DBG(read_app.c, main(), 44): 3436 mv
DBG(read_app.c, main(), 44): 3436 mv
DBG(read_app.c, main(), 44): 3440 mv
DBG(read_app.c, main(), 44): 3436 mv
DBG(read_app.c, main(), 44): 3436 mv
[root@FriendlyARM plg]#
我觉得批量端点和中断端点的不同之处在于usb主控器驱动(or usbcore)对这两种端点类型的访问方式和大小控制---看到的不要全信,仅是个人笔记,若有错欢迎指正。
①对于中断端点,usb主控制器驱动会自动按照该端点描述符里的bInterval请求周期去发in令牌包请求数据而对批量端点则不会如此做,大概是由于中断端点一般用于hid设备,需要人机交互,实时性要求较高,而批量端点不是时刻都在传递数据,而是每次传输较多数据。这也导致了下面不同。
②对于中断端点,协议规定的可支持的最大容量远远小于批量端点。
③在具体驱动里面区别不大,访问哪种端点就申请哪种pipe就行,然后用这个pipe初始化urb再提交即可。
所以对于不需要实时传递数据的数据流就用批量端点实现。会减少主机linux的开销。