usb.c源码:
// 参考drivers/hid/usbhid/usbmouse.c
#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/input.h"
static struct input_dev *mk_dev;
static int len;
static char *buf;
static dma_addr_t buf_phys;
static struct urb *mk_urb;
static struct usb_device_id usb_mk_id_table [] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE) },
//{USB_DEVICE(0x46d, 0xc52f)},
{ } // Terminating entry
};
// 当USB主机控制器获得鼠标数据后,
// 会调用这个函数
static void uk_callback(struct urb *urb)
{
int i;
static char pre_val;
#if 0
printk("Get datas:\n");
for (i = 0; i < len; i++)
{
printk("x ", buf[i]);
}
printk("\n");
#endif
// 鼠标数据含义:
// buf[0]: bit0-左键, 0-松开, 1-按下
// bit1-右键, 0-松开, 1-按下
// bit2-中键, 0-松开, 1-按下
// buf[1],buf[2]构成一个整数, 表示X方向的相对位移
// >0 : 右移
// <0 : 左移
// buf[3],buf[4]构成一个整数, 表示Y方向的相对位移
// >0 : 下移
// <0 : 上移
// buf[6]: 滚轮
// 确定按键值
// 上报数据
if ((pre_val & (1<<0)) != (buf[0] & (1<<0)))
{
// 左键按下或松开
input_event(mk_dev, EV_KEY, KEY_L, (buf[0] & (1<<0)) ? 1 : 0);
input_sync(mk_dev);
}
if ((pre_val & (1<<1)) != (buf[0] & (1<<1)))
{
// 右键按下或松开
input_event(mk_dev, EV_KEY, KEY_S, (buf[0] & (1<<1)) ? 1 : 0);
input_sync(mk_dev);
}
if ((pre_val & (1<<2)) != (buf[0] & (1<<2)))
{
// 中键按下或松开
input_event(mk_dev, EV_KEY, KEY_ENTER, (buf[0] & (1<<2)) ? 1 : 0);
input_sync(mk_dev);
}
pre_val = buf[0];
// 重新提交URB
usb_submit_urb(mk_urb, GFP_KERNEL);
}
static int usb_mk_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;
int pipe;
static int first = 1;
if (!first)
return -EIO;
first = 0;
// 每一个设备都有端点0
// interface->endpoint[]数组里放"除了端点0外的其他端点"
// interface->endpoint[0]表示"除端点0外的第1个端点"
// interface->endpoint[1]表示"除端点0外的第2个端点"
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
// 1. 分配inputd_dev
mk_dev = input_allocate_device();
// 2. 设置
// 2.1 能产生哪类事件
set_bit(EV_KEY, mk_dev->evbit);
set_bit(EV_REP, mk_dev->evbit);
// 2.2 能产生这类事件里的哪些事件
set_bit(KEY_L, mk_dev->keybit);
set_bit(KEY_S, mk_dev->keybit);
set_bit(KEY_ENTER, mk_dev->keybit);
// 3. 注册
input_register_device(mk_dev);
// 4. 硬件相关的操作:
// 对于GPIO按键, 是request_irq, 在中断处理函数里上报按键
// 对于USB设备, 是使用"USB主机驱动程序提供的函数"发起USB传输获得数据
// 数据传输3要素: 源, 目的, 长度
// A. 源: USB设备的某个端点
// ((PIPE_INTERRUPT << 30) | (dev->devnum << 8) | (endpoint << 15) | USB_DIR_IN)
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
// C. 长度: 这个端点描述符的wMaxPacketSize
len = endpoint->wMaxPacketSize;
// B. 目的: 分配buffer
buf = usb_buffer_alloc(dev, len, GFP_ATOMIC, &buf_phys);
// D. 怎么使用这3要素 ?
// 分配URB: USB Reqeust Block
mk_urb = usb_alloc_urb(0, GFP_KERNEL);
// 用3要素填充URB
usb_fill_int_urb(mk_urb, dev, pipe, buf, len, uk_callback, NULL, endpoint->bInterval);
mk_urb->transfer_dma = buf_phys;
mk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
// 使用URB
usb_submit_urb(mk_urb, GFP_KERNEL);
return 0;
}
static void usb_mk_disconnect(struct usb_interface *intf)
{
struct usb_device *dev = interface_to_usbdev(intf);
printk("disconnect usb mouse!!!!!\n");
usb_kill_urb(mk_urb);
usb_free_urb(mk_urb);
usb_buffer_free(dev,len, buf, buf_phys);
input_unregister_device(mk_dev);
input_free_device(mk_dev);
}
// 1. 分配usb_driver
// 2. 设置
static struct usb_driver usb_mk_driver = {
.name = "usbmk",
.probe = usb_mk_probe,
.disconnect = usb_mk_disconnect,
.id_table = usb_mk_id_table,
};
static int usb_mk_init(void)
{
// 3. 注册
usb_register(&usb_mk_driver);
return 0;
}
static void usb_mk_exit(void)
{
usb_deregister(&usb_mk_driver);
}
module_init(usb_mk_init);
module_exit(usb_mk_exit);
MODULE_LICENSE("GPL");
=====================================================================
Makefile文件:
KERN_DIR = /home/linux/linux-3.0.1
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m += usb.o
=====================================================================
测试部分参考:JZ2440的USB设备驱动程序
上一篇:OK6410块设备驱动之用内存模拟磁盘
下一篇:OK6410分层分离(总线-驱动-设备模型)
推荐阅读
史海拾趣
随着全球化趋势的加剧,飞虹高科公司意识到,要想在国际市场上取得更大的成功,必须与国际同行展开合作。因此,公司积极寻求与国际知名企业的合作机会,通过技术合作、合资建厂等方式,共同开发新产品、拓展新市场。这些合作不仅为公司带来了资金和技术支持,还帮助公司扩大了国际影响力,提高了产品的国际竞争力。
DiCon Fiberoptics Inc公司成立于1986年,当时的光纤通信技术正处于快速发展阶段。公司创始人凭借对行业的敏锐洞察和坚定信念,决定投身于这一领域。在创业初期,公司面临着资金紧张、技术壁垒高等诸多挑战。然而,通过不懈努力和持续创新,DiCon成功研发出了多款高性能的光纤通信产品,逐渐在市场上获得了认可。
随着技术的不断进步和市场的不断变化,DUBILIER公司意识到必须不断拓展市场以保持竞争力。因此,公司决定采取多元化的市场战略,进入多个不同的细分市场。通过与行业合作伙伴建立紧密的合作关系,DUBILIER公司成功地将其产品推广到了更广泛的领域。同时,公司还积极开拓国际市场,将产品出口到世界各地。这些努力不仅为公司带来了更多的商业机会,还进一步巩固了其在全球电子行业的地位。
在产品质量和技术水平得到认可后,ETAL开始积极拓展市场。公司制定了详细的市场营销策略,通过参加国际电子展会、与知名企业合作等方式提高品牌知名度。同时,ETAL还注重客户服务,建立了完善的售后服务体系,确保客户在使用产品过程中得到及时、专业的支持。这些举措使得ETAL的市场份额不断扩大,品牌影响力逐渐增强。
1957年,麻省理工学院的工程师肯尼斯·奥尔森(Kenneth Olsen)和哈伯特·安德森(Harlan Anderson)共同创立了Digital Equipment Corporation(DEC)。他们最初的目标是开发和生产创新的数字计算设备。凭借他们在数字技术领域的专业知识和独特视角,DEC推出了首批数字实验室和数字系统组件,这些产品在市场上取得了初步的成功,为DEC的发展奠定了坚实的基础。
在国内市场取得成功后,ECC开始将目光投向国际市场。公司积极参加国际展会,与海外客户建立联系。同时,ECC还在海外设立了研发中心和生产基地,以便更好地了解当地市场需求并提供定制化服务。通过不懈的努力,ECC的产品成功打入国际市场,实现了全球化布局。
当然这个对比有点不公平,那一个系列来和一款芯片对决。但是在arm中我之使用过着两种。 首先说说中断,s3的中断匪夷所思,看明白了就是调不通,再跑ucos的时候除了定时中断外没有正常工作的中断,用了1周没有任何进展,接着就放弃了 ...… 查看全部问答∨ |
|
$(\'swf_cu8\').innerHTML=AC_FL_RunContent(\'width\', \'550\', \'height\', \'400\', \'allowNetworking\', \'internal\', \'allowScriptAccess\', \'never\', \'src\', encodeURI(\'http://player.youku.com/player.php/sid/XMTE1MDUxMDcy/v.sw ...… 查看全部问答∨ |
|
用的是i.mx35自带的CAN接口,CAN时钟采用总线时钟66.5MH,需要除以分频、位时间才能得到125KHZ的波特率。现在问题是分频、位时间分别设置多少? 我算了下无论设置为多少都不能得到整数的125K? … 查看全部问答∨ |
|
有会uc/os-ii的高手吗?我要做论文 是基于uc/os-ii的串行通信的 有高手会的话 发给我好吗?我邮箱是stefa545@163.com 或者可以给我解释下源代码的也行 实在不懂啊 … 查看全部问答∨ |
设计资源 培训 开发板 精华推荐
- 好消息!返现+抽奖,双重好礼助力openmv技术学习!
- WEBENCH轻松注册,尽享精彩好礼!
- 参与有礼|欢迎来到泰克高速串行知识星球
- 阅1SP0350V SCALE-2单通道即插即用型门极驱动器,参与PI答题享好礼!
- ADI【混合动力汽车(HEV)/电动汽车(EV)】锂电池管理解决方案
- 关注 PI 最新 SCALE-iDriver IC产品系列 答题有好礼!
- ADI有奖下载活动之25:ADI汽车传感器和传感器接口解决方案
- 瑞萨电子颠覆传统理念的嵌入式开发平台 Renesas Synergy™ 评估套件震撼来袭!答题即可免费申请!
- 【芯币兑换】活动一:用社区芯币兑换51开发板PCB板!
- 艾睿照明设计工具初体验:与LED设计的亲密接触!