Archive for 六月, 2009

聊天记录

杨博在QQ上问我wxWidgets,下面是我的回答,乱七八糟的。整理一下。

Linux平台下的GUI开发,可以选择的图形库我知道的有gtk,gtkmm,wxWidgets,QT。
wxWidgets是我喜欢的图形库,看过gtk,看过gtkmm,最后发现我比较喜欢wxWidgets。gtk是最原生的,学习使用方法比较麻烦(个人感觉);gtkmm是对gtk的面向对象封装,按照通常的命名方法,一般应该叫做gtk++ (gtk plus plus),但是开发人员觉得叫plus plus的东西太多了,于是他们就叫gtk minus minus,所以就缩写成为gtkmm了;wxWidgets是开源的面向对象的跨平台图形库,已经有10多年的历史了,比较成熟,文档也不错(中文的几乎没有),最大的优势是跨平台,而且由于封装得不错,对各个控件的学习都还好掌握,没必要全部会,使用的时候查manual就可以了。据说wxWidgets比较像MFC,我不会MFC,尝试去学习过,但是发现学不进去,最后我觉得wxWidgets比较好懂好学。

wxWidgets有很多图形工具(GUI designer),例如wxFormbuilder,wxSmith,wxDev,wxGlade等等,各有千秋。没有必要全部掌握,选择一种学精了是不错的方法。

wxWidgets 由于层层封装,所以传说它的性能不好,这个问题我没有切身体会,但是总体的来说,wxWidgets编写的程序编译链接后的二进制文件都比原生图形库(gtk\MFC)写的程序的大。 wxWidgets在我个人看来是比较有潜力的,由于它良好的跨平台了,所以我选择它。
写一些简单的GUI,都可以用wxwidgets,很方便。当然更方便快捷的是wxPython,就是用wxwidgets的python库,国外比较火,我觉得因为他们用python的时间比较久了吧。这个东西我目前没见到过中文资料,我也不会python,所以不管他。
windows下的安装一点不难,网上有很多文章都介绍了,这里我就没必要重复了。一般问题google都能解决。另外,wxWidgets的问题就是中文参考比较少,所以最好多看英文资料。
学习wxWidgets,我的个人感觉,良好的C++基础是非常重要的。当然,只要能看懂C代码,学wxwidgets还是没问题。不过要学习透彻,要能够定制自己的控件,要理解其中的实现,都需要很好的C++知识。

跨平台的还有一个QT,我看到它的LOGO特别像镰刀帮的LOGO,所以我就没兴趣了。嘿嘿,这个是开玩笑,主要原因是wxWidgets先入为主,我就没关注QT了。但是这个东西在实际中应用是非常广的,远远超过开源的wxwidgets。QT的很多东西我不了解,不能乱说。

我是个wxWidgets菜鸟,边学边用。

Free surf

This post records how to install and config a proxy on Debian Linux.

1.install tor and privoxy

# aptitude install tor privoxy

2.modify privoxy’s configure file

# vi /etc/privoxy/config

/*
* (1)uncomment the line “#logfile logfile” (#logfile logfile  —>   logfile logfile)
* (2)add a new line at the bottom of config file “forward-socks4a/localhost:9050 .”(without quote,don’t lose the dot)
* (3)save and exit
*/

3.restart privoxy service

# /etc/init.d/privoxy restart

4.set the proxy in your browser, in iceweasel you can follow the lines below:(this works in firefox too)

Edit -> preferences -> Advanced -> Netword -> Settings

1.check the Manual proxy configuration
2.fill the “SOCKS Host” and its ports with “localhost” and “9095″(without quote)
3.fill the “No proxy for” with “localhost,127.0.0.1″(without quote)

Now click OK button.

彩虹

傍晚时分,吃饭回来看到美丽彩虹横跨天空。迅速冲回宿舍拿相机,嘿嘿。

P1 彩虹

img_2738

P2 拍摄晚霞的女生

img_2749

USB驱动学习笔记(1)

LDD 3rd 中文版实在是让我忍无可忍,USB驱动一章翻译得那是相当的晦涩,看得我云里雾里,索性扔下书来看代码,以后主要靠自己分析代码学习,多读网上前辈的笔记,这样不仅能加深对代码的理解,也看到了别人的思维角度,比抱着LDD 3rd啃强多了,开搞!

新手自学笔记,比较罗嗦,冗长,学到什么地方就写到什么地方,没有具体的层次和顺序。写这个笔记的目的,仅仅是当作备忘和一个过程的记录,如果高手看到了谬误之处,敬请斧正。

全部代码、笔记、实验都在Debian GNU/Linux 下进行,内核版本如下:

ganquan@debian:~$ uname -r

2.6.26-2-686

0.先从阅读usb-skeleton.c开始

ganquan@debian:~$ cat /usr/src/linux-source-2.6.26/drivers/usb/usb-skeleton.c | wc -l

525

还好,只有525行。不算吓人。

从驱动程序的Hello World开始看:

504    static int __init usb_skel_init(void)
 
505    {
 
506        int result;
 
507
 
508        /* register this driver with the USB subsystem */
 
509        result = usb_register(&skel_driver);
 
510        if (result)
 
511            err("usb_register failed. Error number %d", result);
 
512
 
513        return result;
 
514    }
 
515
 
516    static void __exit usb_skel_exit(void)
 
517    {
 
518        /* deregister this driver with the USB subsystem */
 
519        usb_deregister(&skel_driver);
 
520    }

显然的,504行的usb_skel_init(void)就是insmod之后被运行的初始化函数,它只干了一件事:调用usb_register函数,注册了一个叫skel_driver的东西,skel_driver是在usb-skeleton.c 文件67行定义的一个usb_driver类型的结构体。再来看看usb_driver到底是何方妖孽。

在linux-source-2.6.26/include/linux/usb.h里面,991行到1015行定义了这个结构体如下:

991 struct usb_driver {
 
992 const char *name;
 
993
 
994 int (*probe) (struct usb_interface *intf,
 
995 const struct usb_device_id *id);
 
996
 
997 void (*disconnect) (struct usb_interface *intf);
 
998
 
999 int (*ioctl) (struct usb_interface *intf, unsigned int code,
 
1000 void *buf);
 
1001
 
1002 int (*suspend) (struct usb_interface *intf, pm_message_t message);
 
1003 int (*resume) (struct usb_interface *intf);
 
1004 int (*reset_resume)(struct usb_interface *intf);
 
1005
 
1006 int (*pre_reset)(struct usb_interface *intf);
 
1007 int (*post_reset)(struct usb_interface *intf);
 
1008
 
1009 const struct usb_device_id *id_table;
 
1010
 
1011 struct usb_dynids dynids;
 
1012 struct usbdrv_wrap drvwrap;
 
1013 unsigned int no_dynamic_id:1;
 
1014 unsigned int supports_autosuspend:1;
 
1015 };

可见这个结构体包含了不少函数指针,通过名字大概猜了一下各个回调函数里面应该干啥,结构体中各个字段在内核代码中都有详细注释,不再一一叙述。总之,这个结构体现在看来,是用于标识我的USB驱动程序的。

搞清楚了传递给usb_register函数的参数,再看来看这个函数是干啥的。

还是在linux-source-2.6.26/include/linux/usb.h里面,有:

1075 static inline int usb_register(struct usb_driver *driver)
 
1076 {
 
1077 return usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
 
1078 }

这个内联函数居然又调用了另外一个函数,内核真是一个蜘蛛网,一点也不假,继续看:

usb_register_driver函数,第一个参数是用来标识USB驱动程序的usb_driver类型的结构体,第二、三个参数都是宏,但是第二个参数其实是一个module类型的结构体,第三个参数是字符指针,这两个参数暂时不分析。先放着就可以了。

接下来看一下usb_register_driver函数又干了什么。

在linux-source-2.6.26/driver/usb/core/driver.c中:

715 int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
 
716 const char *mod_name)
 
717 {
 
718 int retval = 0;
 
719
 
720 if (usb_disabled())
 
721 return -ENODEV;
 
722
 
723 new_driver->drvwrap.for_devices = 0;
 
724 new_driver->drvwrap.driver.name = (char *) new_driver->name;
 
725 new_driver->drvwrap.driver.bus = &usb_bus_type;
 
726 new_driver->drvwrap.driver.probe = usb_probe_interface;
 
727 new_driver->drvwrap.driver.remove = usb_unbind_interface;
 
728 new_driver->drvwrap.driver.owner = owner;
 
729 new_driver->drvwrap.driver.mod_name = mod_name;
 
730 spin_lock_init(&new_driver->dynids.lock);
 
731 INIT_LIST_HEAD(&new_drive->dynids.list);
 
732
 
733 retval = driver_register(&new_driver->drvwrap.driver);
 
734
 
735 if (!retval) {
 
736 pr_info("%s: registered new interface driver %s\n",
 
737 usbcore_name, new_driver->name);
 
738 usbfs_update_special();
 
739 usb_create_newid_file(new_driver);
 
740 } else {
 
741 printk(KERN_ERR "%s: error %d registering interface "
 
742 " driver %s\n",
 
743 usbcore_name, retval, new_driver->name);
 
744 }
 
745
 
746 return retval;
 
747 }

以上可见usb_register_driver函数中对usb_driver结构体的一个成员赋值,也就是对drvwrap成员。drvwrap是一个结构体,函数中对它的driver成员的各个字段进行赋值,并且usb_register_driver函数中还调用了一个driver_register函数,传入参数是drvwap的driver字段,看来这个drvwap成员分量不轻,现在去探究一下 这个usbdrv_wrap类型的drvwrap又是什么。

在linux-source-2.6.26/include/linux/usb.h中:

934 struct usbdrv_wrap {
 
935 struct device_driver driver;
 
936 int for_devices;
 
937 };

可见,usbdrv_wrap只不过是一个对device_driver的封装,继续深入看一下device_driver又是什么。

在linux-source-2.6.26/include/linux/device.h中:

120 struct device_driver {
 
121 const char *name;
 
122 struct bus_type *bus;
 
123
 
124 struct module *owner;
 
125 const char *mod_name; /* used for built-in modules */
 
126
 
127 int (*probe) (struct device *dev);
 
128 int (*remove) (struct device *dev);
 
129 void (*shutdown) (struct device *dev);
 
130 int (*suspend) (struct device *dev, pm_message_t state);
 
131 int (*resume) (struct device *dev);
 
132 struct attribute_group **groups;
 
133
 
134 struct driver_private *p;
 
135 };

注意到device_driver的定义,134行又是一个driver_private结构体指针。非常有必要弄清楚这个结构体。

在linux-source-2.6.26/driver/base/base.h中,有:

30 struct driver_private {
 
31 struct kobject kobj;
 
32 struct klist klist_devices;
 
33 struct klist_node knode_bus;
 
34 struct module_kobject *mkobj;
 
35 struct device_driver *driver;
 
36 };

继续深入看看kobject又长什么样子。

在linux-source-2.6.26/include/linux/kobject.h中:

60 struct kobject {
 
61 const char *name;
 
62 struct kref kref;
 
63 struct list_head entry;
 
64 struct kobject *parent;
 
65 struct kset *kset;
 
66 struct kobj_type *ktype;
 
67 struct sysfs_dirent *sd;
 
68 unsigned int state_initialized:1;
 
69 unsigned int state_in_sysfs:1;
 
70 unsigned int state_add_uevent_sent:1;
 
71 unsigned int state_remove_uevent_sent:1;
 
72 };

到底了,为啥到底了。去看看linux-source-2.6.26/Document/kobject.txt就知道为啥到底了。

那么kobject到底是个啥?

kobject就是组成Linux的设备模型的基本数据结构。kobject的任务有:

(1)对内核对象的计数,对应数据结构就是struct kref

(2)sysfs表述

(3)数据结构关联

(4)热插拔处理

对usb_driver一层一层的拨开,最后走到了kobject。在内核设计中也用到了面向对象的思想,kobject就可以当作基类,其他的类都是从kobject继承的,由于C语言不能像C++那样继承,所以就一次又一次的封装。

我现在搞清楚了各个struct之间的关系:

kobject—>driver_private—>device_driver—>usbdrv_wrap—>usb_driver

总结他们之间的关系如下:

kobject是Linux设备模型的基本数据结构,它被作为“基类”,其他“子类”都是“继承”了kobject。在我分析的这个例子中,driver_private就是一个“子类”,它直接“继承”了kobject。事实上,老版本的内核(2.6.10)直接把kobject放在device_driver中,新版本的内核则是用driver_private来存放kobject,然后再把driver_private封装在device_driver中。device_driver中除了包含driver_private,还有很多函数指针,也就是驱动程序需要提供的服务。接下来,usbdrv_wrap再次封装了device_driver,这次封装很简单,没有增加过多额外的字段。最后usb_driver来封装usbdrv_wrap,usb_driver中也有很多的函数指针。

这些结构体的各个字段,具体作用是什么?尤其是最接近“基类”的那些“子类”的以k开头的字段,都用来实现什么功能?

驱动程序提供的服务又是什么样子,以及USB驱动程序在总线上的挂牌过程,这些都需要弄明白,下一篇笔记看看能不能弄清楚。

无题

P1 那片云

img_2679

P2  01 或者是10

img_2708

P3 宿舍楼下的海鸥造型灯,每次晚自习回来都有一种归家的感觉

img_2711

P4 礼仪广场的水景灯

img_2721

P5 广场全景图

e5b9bfe59cba_e585a8e699afe59bbesmall

用一个新主题

原来用的主题对宽幅照片支持不好,不得不换一个主题。

把Wordpress.org的主题页面前30页都翻了一遍,就这个比较适合了。

后续的细节修改工作慢慢进行。

宽幅的力量

今天自习回来随便拍了几张,明天考数字图像。

晚上数字信号处理上机。

谁能告诉我紫色的花儿叫什么名字?

P1 阳台上的马扎

11

P2 舍友放在电视机上的洗漱工具

21

P3 我们的海棠

8

P4 B楼整齐的窗户

41

P5 忙碌

51

P6 簇拥

6

P7 绽放

7

一组交大照片

P1 交大图书馆后面的广场

5

P2 喜欢交大林荫古老的味道

4

P3 爬满爬山虎的老楼房

3

P4 交大图书馆正面

2

P5 在树下拉小提琴的同学

1

=END=

实现一个虚拟设备“自增器”,该设备把写入的数据自增1。

ganquan@debian:~/Driver/01$ cat Add.h

#ifndef _MYDRIVER_H
#define _MYDRIVER_H

#include <linux/cdev.h>       /*cdev*/
#include <linux/types.h>    /*ssize_t*/

/*设备对象*/
struct Add
{
struct cdev MyChrDevice;    /*Char device structure*/
};

/*驱动程序要实现的函数*/
ssize_t Add_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos);
ssize_t Add_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos);

#endif    /*_MYDRIVER_H*/

ganquan@debian:~/Driver/01$ cat Add.c

#include <linux/init.h>			/*包含用于声明装载模块初始化和清除函数的宏*/
#include <linux/module.h>		/*包含装载模块需要的符号和函数定义*/
#include <linux/kernel.h>		/*printk()*/
#include <linux/fs.h>			/*申请设备号函数和数据结构,file_operation*/
#include <linux/types.h>		/*dev_t*/
#include <linux/kdev_t.h>		/*包含获取主设备号和次设备号的宏*/
#include <linux/slab.h>			/*kmalloc()*/
#include <linux/cdev.h>			/*cdev,cdev_init(),cdev_add()*/
#include <asm/uaccess.h>		/*copy_to_user(),copy_from_user()*/

#include "Add.h"

static int global_var = 0;
int Add_major = 0;	/*主设备号*/
int Add_minor = 0;	/*次设备号*/

struct Add *mydev;

struct file_operations Add_fops = {
	.owner = THIS_MODULE,
	.read = Add_read,
	.write = Add_write,
};

ssize_t Add_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
	if(copy_to_user(buf,&global_var,sizeof(int)))
	{
		return -EFAULT;
	}

	return sizeof(int);
}
ssize_t Add_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
	if(copy_from_user(&global_var,buf,sizeof(int)))
	{
		return -EFAULT;
	}
	if(global_var != 0)
		global_var++;

	return sizeof(int);
}

static int MyDriver_init(void)
{
	int ret;
	int devno;
	dev_t dev;

	/*申请设备号*/
	ret = alloc_chrdev_region(&dev,0,1,"Add");
	if(ret < 0)
	{
		printk(KERN_ALERT "Can not get dev_t\n");
	}
	else
	{
		Add_major = MAJOR(dev);		/*MAJOR in <linux/kdev_t.h>*/
		Add_minor = MINOR(dev);		/*MINOR in <linux/kdev_t.h>*/
	}
	/*申请设备号结束*/

	/*分配设备内存空间*/
	mydev = kmalloc(sizeof(struct Add),GFP_KERNEL);
	if(!mydev)
	{
		printk(KERN_ALERT "kmalloc error\n");
	}
	/*分配内存空间结束*/

	/*初始化内存空间*/
	memset(mydev,0,sizeof(struct Add));

	/*注册字符设备*/
	devno = MKDEV(Add_major,Add_minor);
	cdev_init(&mydev->MyChrDevice,&Add_fops);
	mydev->MyChrDevice.owner = THIS_MODULE;
	mydev->MyChrDevice.ops = &Add_fops;
	ret = cdev_add(&mydev->MyChrDevice,devno,1);
	if(ret)
		printk(KERN_ALERT "Error %d adding Add\n",ret);
	/*注册字符设备结束*/
	return 0;
}

static void MyDriver_exit(void)
{
	dev_t devno;

    devno = MKDEV(Add_major,Add_minor);
	cdev_del(&mydev->MyChrDevice);
	unregister_chrdev_region(devno,1);
	kfree(mydev);
}

module_init(MyDriver_init);	/*声明模块加载初始化函数*/
module_exit(MyDriver_exit);	/*声明模块卸载清除函数*/

MODULE_LICENSE("GPL");		/*驱动许可证协议*/
MODULE_AUTHOR("GanQuan");	/*作者*/
MODULE_VERSION("0.0.1");	/*版本号*/

不变的Makefile:
ganquan@debian:~/Driver/01$ cat Makefile

obj-m := Add.o
	KDIR ?= /lib/modules/$(shell uname -r)/build
	PWD := $(shell pwd)
all:
	    $(MAKE) -C $(KDIR) M=$(PWD)

.PHONY:clean
clean:
	    rm -f *.mod.c *.mod.o *.ko *.o *.tmp_versions

驱动加载脚本:
ganquan@debian:~/Driver/01$ cat addload

#!/bin/bash
#author ganqan
#	imganquan@gmail.com
#load a module

module="Add"
device="Add"
mode="777"

/sbin/insmod ./${module}.ko || exit 1

major=$(awk "\$2==\"$module\" {print \$1}" /proc/devices)

mknod /dev/${module} c $major 0
chmod $mode /dev/${device}

devinfo=`ls -l /dev/${device}`

echo "insmod	:$module.ko"
echo "major	:$major"
echo "devinfo	:$devinfo"

驱动卸载脚本:
ganquan@debian:~/Driver/01$ cat addunload

#!/bin/bash
#author ganquan
#	imganquan@gmail.com
#unload a module

module="Add"
device="Add"
/sbin/rmmod $module || exit 1
rm -f /dev/${device}

很简单的测试程序:
ganquan@debian:~/Driver/01$ cat test.c

#include <sys/stat.h>
#include <stdio.h>
#include <fcntl.h>
int main()
{
	int fd,num;
	fd = open("/dev/Add", O_RDWR, S_IRUSR | S_IWUSR);
	if (fd != -1)
	{
		read(fd, &num, sizeof(int));
		printf("The MyDevice is %d\n", num);

		printf("Please input the num written to MyDevice\n");
		scanf("%d", &num);
		write(fd, &num, sizeof(int));
		read(fd, &num, sizeof(int));
		printf("The MyDevice is %d\n", num);
		close(fd);
	}
	else
		printf("Device open failure\n");
		return 0;
}

测试结果:

ganquan@debian:~/Driver/01$ sudo ./addload
insmod	:Add.ko
major	:249
devinfo	:crwxrwxrwx 1 root root 249, 0 2009-06-09 22:55 /dev/Add
ganquan@debian:~/Driver/01$ ./test
The MyDevice is 0
Please input the num written to MyDevice
7
The MyDevice is 8
ganquan@debian:~/Driver/01$ sudo ./addunload

Debian VS Ubuntu

今天又看到了关于Debian和Ubuntu的不休争论,我也说说自己的感觉。
两个发行版我都用过,结果是Debian胜出,现在我更多的感觉到Debian的优秀,不是其他发行版可以比拟的。从以下几个方面来说明我选择的理由:

一、稳定性
Debian的稳定性远远超过Ubuntu,这是经过我切身体会的结论。我是用Debian来做桌面系统,只要不使用网银,基本上就不用Windows,既然用作桌面系统,就要保证软件不要太老,所以我用Debian只用testing,然而testing的Debian一直都没有崩溃过,可是在Ubuntu的好几个版本里面都出现过突然崩溃的现象。一个操作系统,如果不能给用户以稳定的印象,势必导致用户的抛弃。

二、可定制性
Debian的可定制性非常强,爱怎么搞就怎么搞,我曾经定制了一个瘦小的Debian,很有成就感,同时运行也很快。我喜欢可以定制的东西,当然这是一种病,爱好折腾的病。使用Debian的感觉就像是自己在做一盘菜,自己怎么喜欢吃,就怎么做。但是Ubuntu却大包大揽,臃肿无比,就像在餐厅点菜吃饭,厨师怎么做,顾客就怎么吃,不管是否和口味。
Ubuntu把很多地方都隐藏或者叫做封装起来,让用户感受到易用性,这点我却不大领情。它越来越像M$ Windows,我不知道这个系统背后的东西,只知道怎么用。例如在Ubuntu上安装显卡驱动,已经完全傻瓜化了,但是却使得我不知道Linux的驱动程序机制,以及如何手动安装一个驱动。这样不利于我学习Linux,不能接触底层和后台,怎么了解这个系统。当然,这是和用户特点有关的,如果只是一个单纯想用Linux的用户,那么就觉得Ubuntu这点非常好。可定制性其实是一种自由,可以随心地对系统进行配置,我不愿意失去这样的自由。

三、心理感受
Debian最大的特色是纯,像一匹纯血宝马那样给人高贵和优秀的感觉,没有像Ubuntu那样默认装入很多有版权争议的包,这一点,说Ubuntu违法是一点也不为过,例如w32codecs那种明显是侵权的包,Ubuntu也装入其中。Debian给我更多的开源与自由软件的感受,而Ubuntu却给我感觉越来越远,不止一个人说Ubuntu从Debian这里拿走的远远超过它回报Debian的。从个人心理感受来说,我更喜欢Debian一点,低调和沉稳,就像一个身怀绝技却毫不张扬的勇士,而Ubuntu则更像一个浅薄聒噪的年轻小伙。

四、适用人群
Ubuntu花费了太多的时间在美化和易用,甚至不惜侵犯他人版权。Ubuntu没有让用户真正高效的利用Linux来工作,更多的是为用Linux来用Linux。Debian则是提供给用户一个稳定快速的系统去学习高效地使用Linux。Ubuntu的宣传工作做得非常好,这对Linux的普及是非常有帮助的,在我个人看来,Ubuntu对Linux的最大贡献目前来说就在这里。它让更多不懂Linux的人可以使用Linux,使得更多的人可以接触到Linux。我感觉,Ubuntu更适合新手或刚接触Linux的人使用,如果要学习Linux则不要使用它,Debian更加适合。因为在配置Debian的过程中,每一步都可以学到关于Linux的知识,全部走下来之后,学到的东西不是用Ubuntu用几个月就能明白的。没接触过Linux的同学问我怎么入门我都推荐Ubuntu,而不是Debian,我想,当他们用了一定时间,想知道Ubuntu背后的东西时,就是换Debian的时候了。

五、总结一下
Ubuntu出色的宣传工作是它对开源界和GNU/Linux的贡献,值得肯定。Debian的贡献不好说,因为太大。如果说GNU/Linux,开源和自由软件是一个理想,那么至今能够承载这个梦想的,只有Debian。Debian在慢慢的发展,“集市的开发方式”并不比“大教堂的开放方式”差,它会逐渐的强大起来。Ubuntu在商业支持下看起来强劲有力,希望在以后它能为开源和自由软件贡献更多,而不是只有索取。Ubuntu更加适合新手使用,Debian则适合愿意折腾的人用,我是一个喜欢折腾的家伙,所以我力荐Debian。