目前分類:硬體類 (16)

瀏覽方式: 標題列表 簡短摘要

1. lshw 和 lshw-GTK

 

安裝:

shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()

Nginx信號控制命令 命令 信號 功能
sbin/nginx -s stop TERM, INT
快速關閉

shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()

自從裝了ubuntu之後flash播放一直是一個問題,在用系統自帶的firefox3.0的時候根本不能播放flash,不是沒聲音,就是不能放,也有一會能放,一會又不能放,反正很是惱人,後來就索性把系統自帶的firefox給刪了,去firefox官網下了個最新的,解壓之後就用。哎!真不錯,flash總算能放了,真讓人高興,總算能看視頻了,省心不少。

 

  但好景不長,後來慢慢發現每次放完flash後再用系統自帶的Rhythmbox放音樂就不行了,死活放不出來,只能重啟之後才又能放了,但音樂能放了,flash又不能看了。暈倒...真是沒一個讓人省心的。沒辦法上網搜了一下,還真管用,問題解決了。以下是大根的解決方法:

shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()

使用ubuntu11.04 再移動硬盤copy過程中出現非正常關機,重啟後無法mount硬盤,出現以下錯誤:

 

引用「Error mounting: mount exited with exit code 13: $MFTMirr does not match $MFT (record 0).

shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()

/****************************************
 * USB主機與設備驅動
 * 主機側:由底到高:USB主機控制器硬件-->
 * USB主機控制器驅動--> USB核心層 --> USB
 * 設備驅動層
 * 設備側:UDC驅動程序、Gadget API和Gadget
 * 驅動程序
 * 邏輯組織:設備(1) <--> 配置(n)
 *           配置(1) <--> 接口(n)
 * 端點(0/n) <--> 接口(1) <--> 設置(n)
 * USB主機控制驅動:控制插入其中的USB設備
 * USB設備驅動:控制USB設備如何與主機通信
 * 標准描述符:
 * 設備描述符 usb_device_descriptor
 * 配置描述符 usb_config_descriptor
 * 接口描述符 usb_interface_descriptor
 * 端點描述符 usb_endpoint_descriptor
 * 字符串描述符 usb_string_descriptor
 * 幾個重要的數據結構:hc_driver usb_hcd 
 * ohci_hcd usb_driver urb(請求塊) 
 * urb的典型生命周期:
 * (1) 被一個USB設備驅動創建
 * (2) 初始化,被安排给一個特定USB設備的特定端點
 * (3) 被USB設備驅動提交给USB核心
 * (4) 提交與USB核心指定的USB主機控制器驅動
 * (5) 被USB主機控制器處理,進行一次到USB設備的傳送
 * (6) 當urb完成,USB主機控制器驅動通知USB設備驅動
 *
 * probe() 和 disconnect() 這兩個函數比較重要
 *         
 ********************************************/


/* 
 * USB 設備驅動實例:USB串口驅動(部分)
 *
 */
/* Driver structure we register with the USB core */
static struct usb_driver usb_serial_driver = {
        .name = "usbserial",
        .probe = usb_serial_probe,
        .disconnect = usb_serial_disconnect,
        .suspend = usb_serial_suspend,
        .resume = usb_serial_resume,
        .no_dynamic_id = 1,
}
/* USB串口設備驅動的模塊加載函數 */
static int __init usb_serial_init(void)
{
        int i;
        int result;


        /* 分配tty_driver */
        usb_serial_tty_driver = alloc_tty_driver(SERIAL_TTY_MINORS);
        if(usb_serial_tty_driver)
        {
                return -ENOMEM;
        }
        /* 初始化全局變量 */
        for(i = 0; i < SERIAL_TTY_MINORS; ++i)
                serial_table[i] = NULL;


        /* 注冊總線 */
        result = bus_register(&usb_serial_bus_type);
        if(result)
        {
                printk(KERN_ERR "usb-serial: %s - registering bus driver failed\n", __func__);
                goto exit_bus;
        }
        /* 初始化tty_driver */
        usb_serial_tty_driver->owner = THIS_MODULE;
        usb_serial_tty_driver->driver_name = "usbserial";
        usb_serial_tty_driver->name =        "ttyUSB";
        usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
        usb_serial_tty_driver->minor_start = 0;
        usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
        usb_serial_tty_driver->subtype = SERIAL_TYPE_NORMAL;
        usb_serial_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        usb_serial_tty_driver->init_termios = tty_std_termios;
        usb_serial_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD 
                                                          | HUPCL | CLOCAL;
        usb_serial_tty_driver->init_termios.c_ispeed = 9600;
        usb_serial_tty_driver->init_termios.c_ospeed = 9600;
        
        tty_set_operations(usb_serial_tty_driver, &serial_ops);
        /*  注冊tty_driver */
        result = tty_register_driver(usb_serial_tty_driver);
        if (result) 
        {
                printk(KERN_ERR "usb-serial: %s - tty_register_driver failed\n",
                                                       __func__);
                goto exit_reg_driver;
        }
        /* 注冊USB驅動 */
        result = usb_register(&usb_serial_driver);
        if (result < 0) 
        {
                printk(KERN_ERR "usb-serial: %s - usb_register failed\n",
                                                                       __func__);
                goto exit_tty;
        }
        /* register the generic driver, if we should */
        result = usb_serial_generic_register(debug);
        if (result < 0) 
        {
                printk(KERN_ERR "usb-serial: %s - registering generic "
                                                               "driver failed\n", __func__);
                goto exit_generic;
        }


        printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");


        return result;


exit_generic:
        usb_deregister(&usb_serial_driver);


exit_tty:
        tty_unregister_driver(usb_serial_tty_driver);


exit_reg_driver:
        bus_unregister(&usb_serial_bus_type);


exit_bus:
        printk(KERN_ERR "usb-serial: %s - returning with error %d\n",
                                                                       __func__, result);
        put_tty_driver(usb_serial_tty_driver);
        return result;
}


static void __exit usb_serial_exit(void)
{
        usb_serial_console_exit();


        usb_serial_generic_deregister();


        usb_deregister(&usb_serial_driver); //注銷usb_driver
        tty_unregister_driver(usb_serial_tty_driver); // 注銷tty_driver
        put_tty_driver(usb_serial_tty_driver); // 減少引用計數
        bus_unregister(&usb_serial_bus_type); // 注銷bus
}


/*
 * 在usb_driver的探測成員函數usb_serial_probe()中,將初始化USB端點
 * 等信息,並通過usb_set_intfdata()設置接口私有數據,它也將初始化urb。
 *
 */
static const struct tty_operations serial_ops = {
        .open =                 serial_open,
        .close =                serial_close,
        .write =                serial_write,
        .hangup =               serial_hangup,
        .write_room =   serial_write_room,
        .ioctl =                serial_ioctl,
        .set_termios =  serial_set_termios,
        .throttle =             serial_throttle,
        .unthrottle =   serial_unthrottle,
        .break_ctl =    serial_break,
        .chars_in_buffer =      serial_chars_in_buffer,
        .tiocmget =             serial_tiocmget,
        .tiocmset =             serial_tiocmset,
        .get_icount =   serial_get_icount,
        .cleanup =              serial_cleanup,
        .install =              serial_install,
        .proc_fops =    &serial_proc_fops,
};
///////////////////////////////////////////
/* 
 * USB 設備驅動實例:USB鍵盤驅動(部分)
 * 主要包含兩部分:
 *     usb_driver的成員函數
 *     輸入設備的打開、關閉、中斷處理等函數
 *
 */
////////////////////////////////////////////
/* 
 * 在USB鍵盤設備驅動的模塊加載和卸載函數中
 * ,將分別注冊和注銷對於USB鍵盤的usb_driver
 * 結構體usb_kbd_driver
 */


static int __init usb_kbd_init(void)
{
        int result = usb_register(&usb_kbd_driver);  //注冊USB設備驅動
        if (result == 0)
                printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
                                                                DRIVER_DESC "\n");
        return result;
}


static void __exit usb_kbd_exit(void)
{
        usb_deregister(&usb_kbd_driver);
}


static struct usb_driver usb_kbd_driver = {
        .name =         "usbkbd",
        .probe =        usb_kbd_probe,
        .disconnect =   usb_kbd_disconnect,
        .id_table =     usb_kbd_id_table,
};


// 支持的設備列表
static struct usb_device_id usb_kbd_id_table [] = {
        { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
                                USB_INTERFACE_PROTOCOL_KEYBOARD) },
        { }                                             /* Terminating entry */
};


MODULE_DEVICE_TABLE (usb, usb_kbd_id_table);


/* 
 * 在usb_driver的探測函數中,將進行input設備的初始化和注冊。
 * usb鍵盤要使用的中斷urb和控制urb的初始化,並設置接口的私有數據。
 */
static int usb_kbd_probe(struct usb_interface *iface,
                                         const struct usb_device_id *id)
{
        ...
}
/* 設置接口私有數據为NULL、終止已提交的urb並注銷輸入設備。*/
static void usb_kbd_disconnect(struct usb_interface *intf)
{
        ...
}
/*
 * 鍵盤中斷處理函數中,也就是urb的完成函數中,將會通過input_report_key()
 * 報告按鍵事件,通過input_sync()報告同步事件,並發起一次新的控制urb傳輸。
 */


static void usb_kbd_irq(struct urb *urb)
{
        struct usb_kbd *kbd = urb->context;
        int i;


        switch (urb->status) 
        {
                case 0:                 /* success */
                        break;
                case -ECONNRESET:       /* unlink */
                case -ENOENT:
                case -ESHUTDOWN:
                        return;
                /* -EPIPE:  should clear the halt */
                default:                /* error */
                        goto resubmit;
        }


        for (i = 0; i < 8; i++)
        {
                input_report_key(kbd->dev, usb_kbd_keycode[i + 224], 
                (kbd->new[0] >> i) & 1);
        }


        for (i = 2; i < 8; i++) 
        {
                if (kbd->old[i] > 3 && 
                memscan(kbd->new + 2, kbd->old[i], 6) == kbd->new + 8) 
                {
                        if (usb_kbd_keycode[kbd->old[i]])
                        {
                                input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
                        }
                        else
                        {
                                dev_info(&urb->dev->dev,
                                                "Unknown key (scancode %#x) released.\n", kbd->old[i]);
                        }
                }


                if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) 
                {
                        if (usb_kbd_keycode[kbd->new[i]])
                                input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
                        else
                                dev_info(&urb->dev->dev,
                                                "Unknown key (scancode %#x) released.\n", kbd->new[i]);
                }
        }


        input_sync(kbd->dev);


        memcpy(kbd->old, kbd->new, 8);


resubmit:
        i = usb_submit_urb (urb, GFP_ATOMIC);
        if (i)
        {
                err_hid ("can't resubmit intr, %s-%s/input0, status %d",
                                kbd->usbdev->bus->bus_name,
                                kbd->usbdev->devpath, i);
        }
}

 

小結:

          這個只能了解usb設備驅動的大概,要真正深刻理解USB驅動,需要對USB源碼進行分析和對相關協議的理解。這裏稍微總結一下:

shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()

對於框架,我覺得就是在一定規範的形式下去實現你要的功能。這裏就涉及到一個變與不變的地方。你所要實現的功能會是千差萬別的---這就是變的地方,而所謂既定的規範,包括建立目錄和屬性檔這是Linux系統已經為我們做好了的,我們只需要直接拿來引用就OK了。

 

那麼今天,我們就來看看hwmon框架是怎麼樣的。

shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()

刪除nvidia的驅動。
sudo apt-get --purge remove nvidia-*
sudo apt-get --purge remove xserver-xorg-video-nouveau



弄完這以後,可能還要把一個文件给刪除

shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()

kudzu --probe --class=network

shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()

sync
echo 1 > /proc/sys/vm/drop_caches;
echo 2 > /proc/sys/vm/drop_caches;

shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()

1、查看CPU資訊

cat /proc/cpuinfo

shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>

shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()

参考2.6.14版本中的driver/usb/input/usbmouse.c。鼠标驱动可分为几个部分:驱动加载部分、probe部分、open部分、urb回调函数处理部分。
下文阴影部分为注解。
一、    驱动加载部分
static int __init usb_mouse_init(void)

int retval = usb_register(&usb_mouse_driver);//注册鼠标驱动
if (retval == 0)
info(DRIVER_VERSION ":" DRIVER_DESC);
return retval;
}
其中usb_mouse_driver的定义为:
static struct usb_driver usb_mouse_driver = {
.owner        = THIS_MODULE,
.name        = "usbmouse",
.probe        = usb_mouse_probe,
.disconnect    = usb_mouse_disconnect,
.id_table    = usb_mouse_id_table,
};
如果注册成功的话,将会调用usb_mouse_probe。那么什么时候才算注册成功呢?
和其它驱动注册过程一样,只有在其对应的“总线”上发现匹配的“设备”才会调用probe。总线匹配的方法和具体总线相关,如:platform_bus_type中是判断驱动名称和平台设备名称是否相同;那如何确认usb总线的匹配方法呢?
Usb设备是注册在usb_bus_type总线下的。查看usb_bus_type的匹配方法。
struct bus_type usb_bus_type = {
.name =        "usb",
.match =    usb_device_match,
.hotplug =    usb_hotplug,
.suspend =    usb_generic_suspend,
.resume =    usb_generic_resume,
};
其中usb_device_match定义了匹配方法
static int usb_device_match (struct device *dev, struct device_driver *drv)
{
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id;
/* check for generic driver, which we don't match any device with */
if (drv == &usb_generic_driver)
return 0;
intf = to_usb_interface(dev);
usb_drv = to_usb_driver(drv);
id = usb_match_id (intf, usb_drv->id_table);
if (id)
return 1;
return 0;
}
可 以看出usb的匹配方法是usb_match_id (intf, usb_drv->id_table),也就是说通过比对“dev中intf信息”和“usb_drv->id_table信息”,如果匹配 则说明驱动所对应的设备已经添加到总线上了,所以接下了就会调用drv中的probe方法注册usb设备驱动。
usb_mouse_id_table的定义为:
static struct usb_device_id usb_mouse_id_table[] = {
{ USB_INTERFACE_INFO(3, 1, 2) },
{ }                        /* Terminating entry */
};
#define USB_INTERFACE_INFO(cl,sc,pr) \
.match_flags = USB_DEVICE_ID_MATCH_INT_INFO, \
.bInterfaceClass = (cl), \
.bInterfaceSubClass = (sc), \
.bInterfaceProtocol = (pr)
鼠标设备遵循USB人机接口设备(HID),在HID规范中规定鼠标接口类码为:
接口类:0x03
接口子类:0x01
接口协议:0x02
这样分类的好处是设备厂商可以直接利用标准的驱动程序。除了HID类以外还有Mass storage、printer、audio等
#define USB_DEVICE_ID_MATCH_INT_INFO \
(USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_INT_PROTOCOL)
匹配的过程为:
usb_match_id(struct usb_interface *interface, const struct usb_device_id *id)
{
struct usb_host_interface *intf;
struct usb_device *dev;

/* proc_connectinfo in devio.c may call us with id == NULL. */
if (id == NULL)
return NULL;

intf = interface->cur_altsetting;
dev = interface_to_usbdev(interface);

/* It is important to check that id->driver_info is nonzero,
since an entry that is all zeroes except for a nonzero
id->driver_info is the way to create an entry that
indicates that the driver want to examine every
device and interface. */
for (; id->idVendor || id->bDeviceClass || id->bInterfaceClass ||
id->driver_info; id++) {

if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
continue;

if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
continue;

/* No need to test id->bcdDevice_lo != 0, since 0 is never
greater than any unsigned number. */
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
(id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
continue;

if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
(id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
continue;

if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
(id->bDeviceClass != dev->descriptor.bDeviceClass))
continue;

if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
(id->bDeviceSubClass!= dev->descriptor.bDeviceSubClass))
continue;

if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
continue;

//接口类
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
(id->bInterfaceClass != intf->desc.bInterfaceClass))
continue;
//接口子类
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
(id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))
continue;
//遵循的协议
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
(id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
continue;

return id;
}
return NULL;
}
从中可以看出,只有当设备的接口类、接口子类、接口协议匹配鼠标驱动时鼠标驱动才会调用probe方法。
二、probe部分
static int usb_mouse_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 usb_mouse *mouse;
int pipe, maxp;
char path[64];

interface = intf->cur_altsetting;
/* 以下是网络的一段对cur_altsettin的解释,下面就借花献佛。usb 设备有一个configuration 的概念,表示配置,一个设备可以有多个配置,但只能同时激活一个,如:一些设备可以下载固件,或可以设置不同的全局模式,就像手机可以被设定为静音模式或 响铃模式一样。而这里又有一个setting,咋一看有些奇怪,这两个词不是一回事吗.还是拿我们最熟悉的手机来打比方,configuration 不说了,setting,一个手机可能各种配置都确定了,是振动还是铃声已经确定了,各种功能都确定了,但是声音的大小还可以变吧,通常手机的音量是一格 一格的变动,大概也就5,6 格,那么这个可以算一个setting 吧.这里cur_altsetting 就是表示的当前的这个setting,或者说设置。可以查看原码中usb_interface 结构定义的说明部分。从说明中可以看到一个接口可以有多种setting*/

if (interface->desc.bNumEndpoints != 1)        
return -ENODEV;
/* 根据HID规则,期望鼠标只有一个端点即中断端点bNumEndpoints 就是接口描述符中的成员,表示这个接口有多少个端点,不过这其中不包括0 号端点,0号端点是任何一个usb 设备都必须是提供的,这个端点专门用于进行控制传输,即它是一个控制端点.正因为如此,所以即使一个设备没有进行任何设置,usb 主机也可以开始跟它进行一些通信,因为即使不知道其它的端点,但至少知道它一定有一个0号端点,或者说一个控制端点。
*/
endpoint = &interface->endpoint[0].desc;//端点0描述符,此处的0表示中断端点
if (!(endpoint->bEndpointAddress & 0x80))
return -ENODEV;
/* 先看bEndpointAddress,这个struct usb_endpoint_descriptor 中的一个成员,是8个bit,或者说1 个byte,其中bit7 表示的是这个端点的方向,0 表示OUT,1 表示IN,OUT 与IN 是对主机而言。OUT 就是从主机到设备,IN 就是从设备到主机。而宏*USB_DIR_IN 来自
*include/linux/usb_ch9.h
* USB directions
* This bit flag is used in endpoint descriptors' bEndpointAddress field.
* It's also one of three fields in control requests bRequestType.
*#define USB_DIR_OUT 0 /* to device */
*#define USB_DIR_IN 0x80 /* to host */
*/
if ((endpoint->bmAttributes & 3) != 3)  //判断是否是中断类型
return -ENODEV;
/* bmAttributes 表示属性,总共8位,其中bit1和bit0 共同称为Transfer Type,即传输类型,即00 表示控制,01 表示等时,10 表示批量,11 表示中断*/

pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);//构造中断端点的输入pipe

maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
/*跟踪usb_maxpacket
usb_maxpacket(struct usb_device *udev, int pipe, int is_out)
{
struct usb_host_endpoint    *ep;
unsigned            epnum = usb_pipeendpoint(pipe);
/*
得到的自然就是原来pipe 里边的15 至18 位.一个pipe 的15 位至18 位是endpoint 号,(一共16 个endpoint,)所以很显然,这里就是得到endpoint 号
*/
if (is_out) {
WARN_ON(usb_pipein(pipe));
ep = udev->ep_out[epnum];
} else {
WARN_ON(usb_pipeout(pipe));
ep = udev->ep_in[epnum];
}
if (!ep)
return 0;
/* NOTE:  only 0x07ff bits are for packet size... */
return le16_to_cpu(ep->desc.wMaxPacketSize);
}
*/
//返回对应端点能够传输的最大的数据包,鼠标的返回的最大数据包为4个字节,
第0个字节:bit 0、1、2、3、4分别代表左、右、中、SIDE、EXTRA键的按下情况
第1个字节:表示鼠标的水平位移
第2个字节:表示鼠标的垂直位移
第3个字节:REL_WHEEL位移

if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL)))
return -ENOMEM;
memset(mouse, 0, sizeof(struct usb_mouse));
mouse->data = usb_buffer_alloc(dev, 8, SLAB_ATOMIC, &mouse->data_dma);
/*
申请用于urb用于数据传输的内存,注意:这里将返回“mouse->data”和“mouse->data_dma”
mouse->data:记录了用于普通传输用的内存指针
mouse->data_dma:记录了用于DMA传输的内存指针
如果是DMA 方式的传输,那么usb core 就应该使用mouse->data_dma
*/
if (!mouse->data) {
kfree(mouse);
return -ENOMEM;
}
mouse->irq = usb_alloc_urb(0, GFP_KERNEL);
if (!mouse->irq) {
usb_buffer_free(dev, 8, mouse->data, mouse->data_dma);
kfree(mouse);
return -ENODEV;
}
mouse->usbdev = dev;
mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
//设置input系统响应按键和REL(相对结果)事件
mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
mouse->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
mouse->dev.relbit[0] |= BIT(REL_WHEEL);
//设置input系统响应的码表及rel表
mouse->dev.private = mouse;
mouse->dev.open = usb_mouse_open;
mouse->dev.close = usb_mouse_close;

usb_make_path(dev, path, 64);
sprintf(mouse->phys, "%s/input0", path);

mouse->dev.name = mouse->name;
mouse->dev.phys = mouse->phys;
usb_to_input_id(dev, &mouse->dev.id);
/*
usb_to_input_id(const struct usb_device *dev, struct input_id *id)
{
id->bustype = BUS_USB;
id->vendor = le16_to_cpu(dev->descriptor.idVendor);
id->product = le16_to_cpu(dev->descriptor.idProduct);
id->version = le16_to_cpu(dev->descriptor.bcdDevice);
}
struct usb_device 中有一个成员struct usb_device_descriptor,而struct usb_device_descriptor 中的成员__u16 bcdDevice,表示的是制造商指定的产品的版本号,制造商id 和产品id 来标志一个设备.bcdDevice 一共16 位,是以bcd码的方式保存的信息,也就是说,每4 位代表一个十进制的数,比如0011 0110 1001 0111 就代表的3697.
业内为每家公司编一个号,这样便于管理,比 如三星的编号就是0x0839,那么三星的产品中就会在其设备描述符中idVendor 的烙上0x0839.而三星自己的每种产品也会有个编号,和Digimax 410 对应的编号就是0x000a,而bcdDevice_lo 和bcdDevice_hi 共同组成一个具体设备的编号(device release
number),bcd 就意味着这个编号是二进制的格式.
*/
mouse->dev.dev = &intf->dev;

if (dev->manufacturer)
strcat(mouse->name, dev->manufacturer);
if (dev->product)
sprintf(mouse->name, "%s %s", mouse->name, dev->product);

if (!strlen(mouse->name))
sprintf(mouse->name, "USB HIDBP Mouse %04x:%04x",
mouse->dev.id.vendor, mouse->dev.id.product);

usb_fill_int_urb(mouse->irq, dev, pipe, mouse->data,
(maxp > 8 ? 8 : maxp),
usb_mouse_irq, mouse, endpoint->bInterval);

/*
static inline void usb_fill_int_urb (struct urb *urb,
struct usb_device *dev,
unsigned int pipe,
void *transfer_buffer,
int buffer_length,
usb_complete_t complete,
void *context,
int interval)
{
spin_lock_init(&urb->lock);
urb->dev = dev;
urb->pipe = pipe;
urb->transfer_buffer = transfer_buffer;//如果不使用DMA传输方式,则使用这个缓冲指针。如何用DMA则使用transfer_DMA,这个值会在后面单独给URB赋

urb->transfer_buffer_length = buffer_length;
urb->complete = complete;
urb->context = context;
if (dev->speed == USB_SPEED_HIGH)
urb->interval = 1 << (interval - 1);
else
urb->interval = interval;
urb->start_frame = -1;

}
此处只是构建好一个urb,在open方法中会实现向usb core递交urb
*/
mouse->irq->transfer_dma = mouse->data_dma;
mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
/*
#define URB_NO_TRANSFER_DMA_MAP    0x0004    //urb->transfer_dma valid on submit 
#define URB_NO_SETUP_DMA_MAP    0x0008    //urb->setup_dma valid on submit 
,这里是两个DMA 相关的flag,一个是URB_NO_SETUP_DMA_MAP,而另一个是
URB_NO_TRANSFER_DMA_MAP.注意这两个是不一样的,前一个是专门为控制传输准备的,因为只有控制传输需要有这么一个setup 阶段需要准备一个setup packet。
transfer_buffer 是给各种传输方式中真正用来数据传输的,而setup_packet 仅仅是在控制传输中发送setup 的包,控制传输除了setup 阶段之外,也会有数据传输阶段,这一阶段要传输数据还是得靠transfer_buffer,而如果使用dma 方式,那么就是使用transfer_dma.
因为这里使用了 mouse->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP,所以应该给urb的transfer_dma赋值。所以用 了:mouse->irq->transfer_dma = mouse->data_dma;
*/


input_register_device(&mouse->dev);
//向input系统注册input设备
printk(KERN_INFO "input: %s on %s\n", mouse->name, path);

usb_set_intfdata(intf, mouse);

/*
usb_set_intfdata().的结果就是使得
%intf->dev->driver_data= mouse,而其它函数中会调用usb_get_intfdata(intf)的作用就是把mouse从中取出来
*/
return 0;
}
三、    open部分
当应用层打开鼠标设备时,usb_mouse_open将被调用

static int usb_mouse_open(struct input_dev *dev)
{
struct usb_mouse *mouse = dev->private;

mouse->irq->dev = mouse->usbdev;
if (usb_submit_urb(mouse->irq, GFP_KERNEL))
return -EIO;
//向usb core递交了在probe中构建好的中断urb,注意:此处是成功递交给usb core以后就返回,而不是等到从设备取得鼠标数据。
return 0;
}

四、    urb回调函数处理部分
当出现传输错误或获取到鼠标数据后,urb回调函数将被执行
static void usb_mouse_irq(struct urb *urb, struct pt_regs *regs)
{
struct usb_mouse *mouse = urb->context;
//在usb_fill_int_urb中有对urb->context赋值
signed char *data = mouse->data;
struct input_dev *dev = &mouse->dev;
int status;
switch (urb->status) {
case 0:                /* success */
break;
case -ECONNRESET:    /* unlink */
case -ENOENT:
case -ESHUTDOWN:
return;
/* -EPIPE:  should clear the halt */
default:        /* error */
goto resubmit;
}

input_regs(dev, regs);

input_report_key(dev, BTN_LEFT,   data[0] & 0x01);
input_report_key(dev, BTN_RIGHT,  data[0] & 0x02);
input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);
input_report_key(dev, BTN_SIDE,   data[0] & 0x08);
input_report_key(dev, BTN_EXTRA,  data[0] & 0x10);
//向input系统报告key事件,分别是鼠标LEFT、RIGHT、MIDDLE、SIDE、EXTRA键,
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)中的value非0时表示按下,0表示释放
input_report_rel(dev, REL_X,     data[1]);
input_report_rel(dev, REL_Y,     data[2]);
input_report_rel(dev, REL_WHEEL, data[3]);
//向input系统报告rel事件,分别是x方向位移、y方向位移、wheel值
input_sync(dev);
//最后需要向事件接受者发送一个完整的报告。这是input系统的要求。
resubmit:
status = usb_submit_urb (urb, SLAB_ATOMIC);
//重新递交urb
if (status)
err ("can't resubmit intr, %s-%s/input0, status %d",
mouse->usbdev->bus->bus_name,
mouse->usbdev->devpath, status);
}

五、    应用层测试代码编写
在应用层编写测试鼠标的测试程序,在我的系统中,鼠标设备为/dev/input/event3.
测试代码如下:
/*
* usb_mouse_test.c
*by lht
*/

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/input.h>

int main (void) 
{
int fd,i,count;
struct input_event ev_mouse[2];
fd = open ("/dev/input/event3",O_RDWR);
if (fd < 0) {
printf ("fd open failed\n");
exit(0);
}
printf ("\nmouse opened, fd=%d\n",fd);
while(1)
{
printf("...............................................\n");
count=read(fd, ev_mouse, sizeof(struct input_event));
for(i=0;i<(int)count/sizeof(struct input_event);i++)
{
printf("type=%d\n",ev_mouse[i].type);
if(EV_REL==ev_mouse[i].type)
{
printf("time:%ld.%d",ev_mouse[i].time.tv_sec,ev_mouse[i].time.tv_usec);
printf(" type:%d code:%d value:%d\n",ev_mouse[i].type,ev_mouse[i].code,ev_mouse[i].value);
}
if(EV_KEY==ev_mouse[i].type)
{
printf("time:%ld.%d",ev_mouse[i].time.tv_sec,ev_mouse[i].time.tv_usec);
printf(" type:%d code:%d value:%d\n",ev_mouse[i].type,ev_mouse[i].code,ev_mouse[i].value);
}


}
}
close (fd);
return 0;
}

运行结果如下:

根据type、code、value的值,可以判断出鼠标的状态,具体值参考include/linux/input.h

 


shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()

Android中使用inotify來偵測input設備的添加和刪除。在EventHub.cpp中

 

#include <sys/inotify.h>

shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()

一直奇怪kernel用dev_name列印出的usb設備名中各數位的意義,如:
[ 7.715397] usb 1-1.3: new high speed USB device using pxau2h-ehci and address 5
[ 7.832798] option 1-1.3:1.0: GSM modem (1-port) converter detected

shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()

If you need to store large files on a temporary basis and don’t have enough room in your quota for them, you might consider using /var/tmp and /tmp on the shell hosts. These directories are available to you and the data stored there does not count against your quota.

Here’s what you need to know about /var/tmp and /tmp:

* /var/tmp and /tmp are shared space, and are used by numerous commands as a matter of course. It is your responsibility to make sure that your use of the space does not interfere with others’ responsible use of the system.

shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()

 

1.在终端機執行 lsusb

出現類似以下結果:

Bus 001 Device 008: ID 0bb4:0c02 High Tech Computer Corp. 

這時键入

shadow 發表在 痞客邦 PIXNET 留言(0) 人氣()