星期六, 九月 29, 2007

转贴:嵌入式系统中LCD驱动的实现原理

结合三星公司ARM9系列嵌入式处理器S3C2410,讲解如何进行LCD驱动程序模块化编程及如何将驱动程序静态加载进系统内核。

 

LCD (液晶显示)模块满足了嵌入式系统日益提高的要求,它可以显示汉字、字符和图形,同时还具有低压、低功耗、体积小、重量轻和超薄等很多优点。随着嵌入式系 统的应用越来越广泛,功能也越来越强大,对系统中的人机界面的要求也越来越高,在应用需求的驱使下,许多工作在Linux下的图形界面软件包的开发和移植 工作中都涉及到底层LCD驱动的开发问题。因此在嵌入式系统中开发LCD驱动得以广泛运用。

 

本文以三星公司ARM9内核芯片S3C2410的LCD接口为基础,介绍了在Linux平台上开发嵌入式LCD驱动程序的一般方法。

 

本文硬件采用三星公司的S3C2410芯片的开发板,软件采用Linux 2.4.19平台,编译器为arm-linux-gcc的交叉编译器,使用640×480分辨率的TFT彩色LCD,通过对其Linux驱动程序进行改写和调试,成功地实现了对该种屏的驱动和显示。



嵌入式驱动的概念

 

设 备驱动程序是操作系统内核和机器硬件之间的接口,设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以 像操作普通文件一样对硬件设备进行操作。设备驱动程序是内核的一部分,它主要完成的功能有:对设备进行初始化和释放;把数据从内核传送到硬件和从硬件读取 数据;读取应用程序传送给设备文件的数据、回送应用程序请求的数据以及检测和处理设备出现的错误。

 

Linux 将设备分为最基本的两大类:一类是字符设备,另一类是块设备。字符设备和块设备的主要区别是:在对字符设备发出读/写请求时,实际的硬件I/O一般就紧接 着发生了。字符设备以单个字节为单位进行顺序读写操作,通常不使用缓冲技术;块设备则是以固定大小的数据块进行存储和读写的,如硬盘、软盘等,并利用一块 系统内存作为缓冲区。为提高效率,系统对于块设备的读写提供了缓存机制,由于涉及缓冲区管理、调度和同步等问题,实现起来比字符设备复杂得多。LCD是以 字符设备方式加以访问和管理的,Linux把显示驱动看做字符设备,把要显示的数据一字节一字节地送往LCD驱动器。

 

Linux 的设备管理是和文件系统紧密结合的,各种设备都以文件的形式存放在/dev目录下,称为设备文件。应用程序可以打开、关闭和读写这些设备文件,完成对设备 的操作,就像操作普通的数据文件一样。为了管理这些设备,系统为设备编了号,每个设备号又分为主设备号和次设备号。主设备号用来区分不同种类的设备,而次 设备号用来区分同一类型的多个设备。对于常用设备,Linux有约定俗成的编号,如硬盘的主设备号是3。Linux为所有的设备文件都提供了统一的操作函 数接口,方法是使用数据结构struct file_operations。这个数据结构中包括许多操作函数的指针,如open()、close()、read()和write()等,但由于外设 的种类较多,操作方式各不相同。Struct file_operations结构体中的成员为一系列的接口函数,如用于读/写的read/write函数和用于控制的ioctl等。打开一个文件就是 调用这个文件file_operations中的open操作。不同类型的文件有不同的file_operations成员函数,如普通的磁盘数据文件, 接口函数完成磁盘数据块读写操作;而对于各种设备文件,则最终调用各自驱动程序中的I/O函数进行具体设备的操作。这样,应用程序根本不必考虑操作的是设 备还是普通文件,可一律当作文件处理,具有非常清晰统一的I/O接口。所以file_operations是文件层次的I/O接口。

 

LCD控制器

 

LCD 控制器的功能是显示驱动信号,进而驱动LCD。用户只需要通过读写一系列的寄存器,完成配置和显示驱动。在驱动LCD设计的过程中首要的是配置LCD控制 器,而在配置LCD控制器中最重要的一步则是帧缓冲区(FrameBuffer)的指定。用户所要显示的内容皆是从缓冲区中读出,从而显示到屏幕上的。帧 缓冲区的大小由屏幕的分辨率和显示色彩数决定。驱动帧缓冲的实现是整个驱动开发过程的重点。S3C2410中的LCD控制器可支持STN和TFT两种液 晶。对于STN 液晶平板,该LCD控制器可支持4位双扫描、4位单扫描和8位单扫描三种显示类型,支持4级和16级灰度级单色显示模式,支持256色和4096色显示, 可接多种分辨率的LCD,例如640×480、320×240和160×160等,在256色显示模式时,最大可支持4096×1024、2048× 2048和1024×4096显示。TFT液晶平板可支持1-2-4-8bpp(bits per pixel)调色板显示模式和16bpp非调色板真彩显示。

 

帧缓冲区是出现在Linux 2.2.xx及以后版本内核当中的一种驱动程序接口,这种接口将显示设备抽象为帧缓冲区设备区。帧缓冲区为图像硬件设备提供了一种抽象化处理,它代表了一 些视频硬件设备,允许应用软件通过定义明确的界面来访问图像硬件设备。这样软件无须了解任何涉及硬件底层驱动的东西(如硬件寄存器)。它允许上层应用程序 在图形模式下直接对显示缓冲区进行读写和I/O控制等操作。通过专门的设备节点可对该设备进行访问,如/dev/fb*。用户可以将它看成是显示内存的一 个映像,将其映射到进程地址空间之后,就可以进行读写操作,而读写操作可以反映到LCD。

 

帧缓冲设备对应的设备文件是/dev/fb*。如果系统有多个显卡,Linux还支持多个帧缓冲设备,最多可达32个,即/dev/fb0~/dev/fb31。而/dev/fb则指向当前的帧缓冲设备,通常情况下,默认的帧缓冲设备为/dev/fb0。

 

帧缓冲设备也属于字符设备,采用“文件层-驱动层”的接口方式。在文件层为之定义了以下数据结构。

 

Static struct file_operations fb_fops={

ower: THIS_MODULE,

read: fb_read, /*读操作*/

write: fb_write, /*写操作*/

ioct1: fb_ioct1, /*I/O操作*/

mmap: fb_mmap, /*映射操作*/

open: fb_open, /*打开操作*/

release: fb_release,  /*关闭操作*/

}

 

其成员函数都在linux/driver/video/fbmem.c中定义,其中的函数对具体的硬件进行操作,对寄存器进行设置,对显示缓冲进行映射。主要结构体还有以下几个。

 

Struct fb_fix_screeninfo:记录了帧缓冲设备和指定显示模式的不可修改信息。它包含了屏幕缓冲区的物理地址和长度。

Struct fb_var_screeninfo:记录了帧缓冲设备和指定显示模式的可修改信息。它包括显示屏幕的分辨率、每个像素的比特数和一些时序变量。其中变量 xres定义了屏幕一行所占的像素数,yres定义了屏幕一列所占的像素数,bits_per_pixel定义了每个像素用多少个位来表示。

Struct fb_info:Linux为帧缓冲设备定义的驱动层接口。它不仅包含了底层函数,而且还有记录设备状态的数据。每个帧缓冲设备都与一个fb_info结 构相对应。其中成员变量modename为设备名称,fontname为显示字体,fbops为指向底层操作的函数的指针。

 

LCD驱动开发的主要工作

 

1 编写初始化函数

 

初始化函数首先初始化LCD 控制器,通过写寄存器设置显示模式和颜色数,然后分配LCD显示缓冲区。在Linux中可以用kmalloc()函数分配一段连续的空间。缓冲区大小为: 点阵行数×点阵列数×用于表示一个像素的比特数/8。缓冲区通常分配在大容量的片外SDRAM中,起始地址保存在LCD控制寄存器中。本文采用的LCD显 示方式为640×480,16位彩色,则需要分配的显示缓冲区为640×480×2=600kb。最后是初始化一个fb_info结构,填充其中的成员变 量,并调用register_framebuffer(&fb_info),将fb_info登记入内核。

 

2 编写成员函数

 

编写结构fb_info中函数指针fb_ops对应的成员函数,对于嵌入式系统的简单实现,只需要下列三个函数就可以了。

struct fb_ops{

……

int (*fb_get_fix)(struct fb_fix_screeninfo *fix, int con, struct fb_info *info);

int (*fb_get_var)(struct fb_var_screeninfo *var, int con, struct fb_info *info);

int (*fb_set_var)(struct fb_var_screeninfo *var, int con, struct fb_info *info);

……

}

Struct fb_ops在include/linux/fb.h中定义。这些函数都是用来设置/获取fb_info结构中的成员变量的。当应用程序对设备文件进行 ioctl操作时候会调用它们。对于fb_get_fix(),应用程序传入的是fb_fix_screeninfo结构,在函数中对其成员变量赋值,主 要是smem_start(缓冲区起始地址)和smem_len(缓冲区长度),最终返回给应用程序。而fb_set_var()函数的传入参数是 fb_var_screeninfo,函数中需要对xres、yres和bits_per_pixel赋值。

对于/dev/fb,对显示设备的操作主要有以下几种。

 

● 读/写(read/write)/dev/fb:相当于读/写屏幕缓冲区。

● 映射(map) 操作:由于Linux工作在保护模式,每个应用程序都有自己的虚拟地址空间,在应用程序中是不能直接访问物理缓冲区地址的。为此,Linux在文件操作 file_operations结构中提供了mmap函数,可将文件的内容映射到用户空间。对于帧缓冲设备,则可通过映射操作,可将屏幕缓冲区的物理地址 映射到用户空间的一段虚拟地址中,之后用户就可以通过读写这段虚拟地址访问屏幕缓冲区,在屏幕上绘图了。

I/O控制:对于帧缓冲设备,对设备文件的ioctl操作可读取/设置显示设备及屏幕的参数,如分辨率、显示颜色数和屏幕大小等。ioctl的操作是由底 层的驱动程序来完成的。在应用程序中,操作/dev/fb的一般步骤如下:打开/dev/fb设备文件;用ioctrl操作取得当前显示屏幕的参数,如屏 幕分辨率和每个像素的比特数,根据屏幕参数可计算屏幕缓冲区的大小;将屏幕缓冲区映射到用户空间;映射后即可直接读写屏幕缓冲区,进行绘图和图片显示了。

 

LCD模块化驱动

 

在对S3C2410 的LCD编写模块化驱动程序时,首先要从内核中去除LCD驱动。这里需要做一些改动,系统调用被加在以下文件中,需去除: /root/usr/src/arm/linux/kernel/sys.c;/root/usr/src/arm/linux/include/arm -arm下的unistd.h和lcd.h;/root/usr/src/arm/linux/arch/arm/kernel下的calls.s。

编写模块化驱动程序,有以下几个关键的函数。

lcd_kernel_init(void)/当模块被载入时执行

lcd_kernel_exit(void)/当模块被移出内核空间时被执行

lcd_kernel1_ioctl(struct*inode, struct*file, unsigned int cmd, unsigned longarg) /其他功能

每当装配设备驱动程序时,系统自动调用初始化模块lcd_kernel_init(void)。

另一个必须提供的函数是lcd_kernel_exit(void),它在模块被卸载时调用,负责进行设备驱动程序的工作。

执行insmod lcd.o命令即可将LCD驱动添加到内核中,执行rmmod lcd命令即可从内核中删除LCD驱动。

 

静态加载LCD驱动

 

将写好的lcd 驱动程序lcd.c放到arm/linux/drivers/char目录下,修改arm/linux/drivers/char/config.in文 件,加上一行:Bool"LCD driver support"CONFIG_LCD;修改arm/linux/drivers/char/Makefile文件,加上一行:obj-$ (CONFIG_LCD)+=lcd.o。

 

这样,当再进行make xconfig时,就会选择是否将LCD驱动编译进内核。同样的办法也可用在其他设备上。

Read More...

星期五, 九月 28, 2007

高手博客

章鱼的窝 打开链接 2007-09-16 14:29
ly44770的博客 打开链接 2007-09-13 21:12
NOR Flash - FLASH - 飞翔,嵌入式linux 打开链接 2007-08-07 17:38
todaygood的博客 打开链接 2007-08-21 13:43
WeiBing blog 打开链接 2007-08-19 08:50
嵌入式中国 打开链接 2007-08-19 08:55
On The Way 打开链接 2007-09-13 21:14
Bekars涡轮增压的Blog ^_^ 打开链接 2007-08-21 11:57
EE小站 打开链接 2007-08-23 10:21
无猫的个人空间 打开链接 2007-08-28 15:15
skywalker_nick的技术专栏 打开链接 2007-08-29 14:56
luofuchong的博客 打开链接 2007-08-30 11:48
Linux&ARM驱动之家 打开链接 2007-08-30 14:01
tr73-armlinux 打开链接 2007-09-01 09:32
hongjiujing的专栏 打开链接 2007-09-09 15:20
刘淼的博客 打开链接 2007-09-10 22:10
zcx3000的专栏 打开链接 2007-09-11 09:31
Super 打开链接 2007-09-19 08:46
JordonWu's Blog 打开链接 2007-09-15 17:58
所罗门的宝藏 打开链接 2007-09-15 23:20
zouzheng 嵌入式 zz 打开链接 2007-09-16 10:45
enchen的博客 打开链接 2007-09-19 13:39
WORKING&FEELING Blos's 打开链接 2007-09-22 09:00
zht_sir的博客 打开链接 2007-09-24 23:23

Read More...

转:linux 2.6 输入子系统 键盘驱动的实现

好久没来了!写点东西.关于linux 2.6下面的键盘驱动的实现. 2.6内核采用"input sub system" 的概念.将输入驱动分成三块: driver,input core和Event handler. "一个输入事件,如鼠标移动,键盘按键按下,joystick的移动等等通过 Driver -> InputCore -> Eventhandler -> userspace 的顺序到达用户空间传给应用程序。" 关于输入子系统详细的文章有一个老兄写了一篇: http://blog.csdn.net/colorant/archive/2007/04/12/1561837.aspx 在这里我肤浅得讲一下如何实现一个驱动.todo 正文

2.6输入子系统使得用户空间可以通过字符设备接口毫无遗漏的获得原始的输入消息。比如说有些智能鼠标,除了坐标滚球,三键,滚轮之外还有其他的输入装置,,比如控制系统音量的按钮. 如何注册设备

/*

*Input interface, not finished yet

*/

int key,code;

button_dev = input_allocate_device(); /*static struct input_dev *button_dev defined outside*/

init_input_dev(button_dev);

set_bit(EV_KEY,button_dev->evbit);


//@set_bit(EV_REP,button_dev->evbit); //repeat

for(key=0;key<16;key++)

set_bit(keypad_keycode[key],button_dev->keybit);

button_dev->name = PCA9554_DRV_NAME;

button_dev->id.bustype = BUS_HOST;

input_register_device(button_dev);

如上述代码所示,首先分配一个输入设备,之后对其进行初始化,然后配置参数. “set_bit(EV_KEY,button_dev->evbit);”将该输入设备定义为键盘输入,这样input core在分发消息的时候会将其发送到keyboard event handler. 接着就是初始化键盘定义,这里keybit是由若干个long型变量组成的数组,我所用的kernel直至最大按键数目为0x1ff.
for(key=0;key<16;key++)

set_bit(keypad_keycode[key],button_dev->keybit);

我的开发板上有16个按键,因为项目是播放器,所以我对其作了定义:
int keypad_keycode[] = {
KEY_UP, KEY_DOWN, KEY_A, KEY_B, // 1 - 4
KEY_LEFT, KEY_RIGHT, KEY_C, KEY_D, // 5 - 8
KEY_PLAYPAUSE,KEY_PLAY,KEY_NEXTSONG,KEY_VOLUMEUP, // 9- 12
KEY_CANCEL,KEY_OK,KEY_PREVIOUSSONG,KEY_VOLUMEDOWN, // 13 - 16
KEY_UNKNOWN,
}

键盘定义示意图

在input.c的input_event函数中会对keybit进行判断,确定某个按键对应的位是否被打开,否则不予上传键值.
case EV_KEY:

printk("haigang;:%s: code:%d,value=%d\n",__FUNCTION__,code,value);

if (code > KEY_MAX || !test_bit(code, dev->keybit) || !!test_bit(code, dev->key) == value){

printk("haigang:%s: code too big\n",__FUNCTION__,code);

return;

}

if (value == 2)

break;

change_bit(code, dev->key);

if (test_bit(EV_REP, dev->evbit) &&
dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
dev->timer.data && value) {


dev->repeat_key = code;

mod_timer(&dev->timer, jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));

}

break

input_event部分代码

如何传送输入键值比较简单,只需要使用 函数void input_event即可,该函数定义
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)

在include/linux/input.h中对该函数作了封装
static inline void input_report_key(struct input_dev *dev, unsigned int code, int value)

{

input_event(dev, EV_KEY, code, !!value);

}

这里code是键值,value应该是键盘状态,按下或者释放(仅是猜测,有待考证) 我的驱动中的建值传输代码,当键值是0x16时候,表示松开键盘事件 unsigned char key; static unsigned char oldKey=0x16; key = pca9554_readKey(); //@printk("KEY:%d\n",key); if(key!=0x16){ input_report_key(button_dev,keypad_keycode[key],1); input_sync(button_dev); }
else{
input_report_key(button_dev,keypad_keycode[oldKey],0); input_sync(button_dev); } set_irq_type(IRQ_KEYPAD,IRQT_FALLING); s3c_gpio_cfgpin(S3C_GPF4,S3C_GPF4_EINT4);/*reconfigure the GPF4 as EINT4*/ oldKey=key;

Read More...

OS Roadmap

Read More...

转:输入子系统分析

1 输入子系统架构Overview

输入子系统(Input Subsystem)的架构如下图所示

输入子系统由 输入子系统核心层( Input Core ),驱动层和事件处理层(Event Handler)三部份组成。一个输入事件,如鼠标移动,键盘按键按下,joystick的移动等等通过 Driver -> InputCore -> Eventhandler -> userspace 的顺序到达用户空间传给应用程序。
其中Input Core 即 Input Layer 由 driver/input/input.c及相关头文件实现。对下提供了设备驱动的接口,对上提供了Event Handler层的编程接口。


1.1 主要数据结构

表 1 Input Subsystem main data structure

数据结构

用途

定义位置

具体数据结构的分配和初始化

Struct input_dev

驱动层物理Input设备的基本数据结构

Input.h

通常在具体的设备驱动中分配和填充具体的设备结构

Struct Evdev

Struct Mousedev

Struct Keybdev…

Event Handler层逻辑Input设备的数据结构

Evdev.c

Mousedev.c

Keybdev.c

Evdev.c/Mouedev.c …中分配

Struct Input_handler

Event Handler的结构

Input.h

Event Handler层,定义一个具体的Event Handler

Struct Input_handle

用来创建驱动层DevHandler链表的链表项结构

Input.h

Event Handler层中分配,包含在Evdev/Mousedev…中。

1.2 输入子系统架构示例图

图2 输入子系统架构示例图


2 输入链路的创建过程

由于input子系统通过分层将一个输入设备的输入过程分隔为独立的两部份:驱动到Input Core,Input Core到Event Handler。所以整个链路的这两部分的接口的创建是独立的。

2.1 硬件设备的注册

驱动层负责和底层的硬件设备打交道,将底层硬件对用户输入的响应转换为标准的输入事件以后再向上发送给Input Core。
驱动层通过调用Input_register_device函数和Input_unregister_device函数来向输入子系统中注册和注销输入设备。
这两个函数调用的参数是一个Input_dev结构,这个结构在driver/input/input.h中定义。驱动层在调用Input_register_device之前需要填充该结构中的部分字段

#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>

MODULE_LICENSE("GPL");

struct input_dev ex1_dev;

static int __init ex1_init(void)
{
/* extra safe initialization */
memset(&ex1_dev, 0, sizeof(struct input_dev));
init_input_dev(&ex1_dev);

/* set up descriptive labels */
ex1_dev.name = "Example 1 device";
/* phys is unique on a running system */
ex1_dev.phys = "A/Fake/Path";
ex1_dev.id.bustype = BUS_HOST;
ex1_dev.id.vendor = 0x0001;
ex1_dev.id.product = 0x0001;
ex1_dev.id.version = 0x0100;

/* this device has two keys (A and B) */
set_bit(EV_KEY, ex1_dev.evbit);
set_bit(KEY_B, ex1_dev.keybit);
set_bit(KEY_A, ex1_dev.keybit);

/* and finally register with the input core */
input_register_device(&ex1_dev);

return 0;
}

其中比较重要的是evbit字段用来定义该输入设备可以支持的(产生和响应)的事件的类型。
包括:

Ø EV_RST 0x00 Reset
Ø EV_KEY 0x01 按键
Ø EV_REL 0x02 相对坐标
Ø EV_ABS 0x03 绝对坐标
Ø EV_MSC 0x04 其它
Ø EV_LED 0x11 LED
Ø EV_SND 0x12 声音
Ø EV_REP 0x14 Repeat
Ø EV_FF 0x15 力反馈

一个设备可以支持一个或多个事件类型。每个事件类型下面还需要设置具体的触发事件,比如EV_KEY事件,支持哪些按键等。

2.2 Event Handler层

2.2.1 注册Input Handler

驱动层只是把输入设备注册到输入子系统中,在驱动层的代码中本身并不创建设备结点。应用程序用来与设备打交道的设备结点的创建由Event Handler层调用Input core中的函数来实现。而在创建具体的设备节点之前,Event Handler层需要先注册一类设备的输入事件处理函数及相关接口
以MouseDev Handler为例:

static struct input_handler mousedev_handler = {
event: mousedev_event,
connect: mousedev_connect,
disconnect: mousedev_disconnect,
fops: &mousedev_fops,
minor: MOUSEDEV_MINOR_BASE,
};

static int __init mousedev_init(void)
{
input_register_handler(&mousedev_handler);

memset(&mousedev_mix, 0, sizeof(struct mousedev));z
init_waitqueue_head(&mousedev_mix.wait);
mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
mousedev_mix.exist = 1;
mousedev_mix.minor = MOUSEDEV_MIX;
mousedev_mix.devfs = input_register_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE);

printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");

return 0;
}

在Mousedev_init中调用input.c中定义的input_register_handler来注册一个鼠标类型的Handler. 这里的Handler不是具体的用户可以操作的设备,而是鼠标类设备的统一的处理函数接口。

2.2.2 设备节点的创建

接下来,mousedev_init函数调用input_register_minor注册一个通用mice设备,这才是与用户相关联的具体的设备接口。 然而这里在init函数中创建一个通用的Mice设备只是鼠标类Event Handler层的特例。在其它类型的EventHandler层中,并不一定会创建一个通用的设备。
标准的流程见是硬件驱动向Input子系统注册一个硬件设备后,在input_register_device中调用已经注册的所有类型的Input Handler的connect函数,每一个具体的Connect函数会根据注册设备所支持的事件类型判断是否与自己相关,如果相关就调用 input_register_minor创建一个具体的设备节点。

void input_register_device(struct input_dev *dev)
{
……
while (handler) {
if ((handle = handler->connect(handler, dev)))
input_link_handle(handle);
handler = handler->next;
}
}

此外如果已经注册了一些硬件设备,此后再注册一类新的Input Handler,则同样会对所有已注册的Device调用新的Input Handler的Connect函数已确定是否需要创建新的设备节点:

void input_register_handler(struct input_handler *handler)
{
……
while (dev) {
if ((handle = handler->connect(handler, dev)))
input_link_handle(handle);
dev = dev->next;
}
}

从上面的分析中可以看到一类Input Handler可以和多个硬件设备相关联,创建多个设备节点。而一个设备也可能与多个Input Handler相关联,创建多个设备节点。
直观起见,物理设备,Input Handler,逻辑设备之间的多对多关系可见下图:

图3 物理设备,Input Handler,逻辑设备关系图

3 设备的打开和读写

用户程序通过Input Handler层创建的设备节点的Open,read,write等函数打开和读写输入设备。

3.1 Open

设备节点的Open函数,首先会调用一类具体的Input Handler的Open函数,处理一些和该类型设备相关的通用事务,比如初始化事件缓冲区等。然后通过Input.c中的 input_open_device函数调用驱动层中具体硬件设备的Open函数。

3.2 Read

大多数Input Handler的Read函数等待在Event Layer层逻辑设备的wait队列上。当设备驱动程序通过调用Input_event函数将输入以事件的形式通知给输入子系统的时候,相关的Input Handler的event函数被调用,该event函数填充事件缓冲区后将等待队列唤醒。
在驱动层中,读取设备输入的一种可能的实现机制是扫描输入的函数睡眠在驱动设备的等待队列上,在设备驱动的中断函数中唤醒等待队列,而后扫描输入函数将设备输入包装成事件的形式通知给输入子系统。

3.3 Write

2.4内核中没有固定的模式,根据具体的Input Handler,可能不实现,也可能通过调用Input_event将写入的数据以事件的形式再次通知给输入子系统,或者调用设备驱动的Write函数等等。
2.6内核的代码中,通过调用Input_event将写入的数据以事件的形式再次通知给输入子系统,而后在Input.c中根据事件的类型,将需要反馈给物理设备的事件通过调用物理设备的Event函数传给设备驱动处理,如EV_LED事件:

void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
......
case EV_LED:
if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value)
return;

change_bit(code, dev->led);
if (dev->event) dev->event(dev, type, code, value);
break;
......
}

4 其它

本文中对Input子系统架构的分析主要是基于2.4.20内核,在2.6内核中对Input子系统做了很大的扩充增加了对许多设备的支持(如触摸屏,键盘等)。不过整体的框架还是一致的。

另,参考了linux journal上的两篇文章:

The Linux USB Input Subsystem, Part I | Linux Journal
Using the Input Subsystem, Part II | Linux Journal


Read More...

Email-To-Blogger Test

不经意间,GCC已发展到了4.0的版本,尽管在软件开发社区之外乏人闻问,但因为 GCC在几乎所有开源软件和自由软件中都会用到,因此它的编译性能的涨落会直接影响到Linux 、Firefox 乃至于OpenOffice.org和Apache等几千个项目的开发。因此,把GCC摆在开源软件的核心地位是一点也不为过。另一方面,GCC4.0的 出现,正在牵引着广大程序员们的心。如果我们非要用一个词来说明GCC与程序员之间的关系,那无疑是"心随心动"。

历史篇
作为自由软件的旗舰项目,Richard Stallman 在十多年前刚开始写作 GCC 的时候,还只是把它当作仅仅一个 C 程序语言的编译器;GCC 的意思也只是 GNU C Compiler 而已。经过了这么多年的发展,GCC 已经不仅仅能支持 C 语言;它现在还支持 Ada 语言、C++ 语言、Java 语言、Objective C 语言、Pascal 语言、COBOL语言,以及支持函数式编程和逻辑编程的 Mercury 语言,等等。而 GCC 也不再单只是 GNU C 语言编译器的意思了,而是变成了 GNU Compiler Collection 也即是 GNU 编译器家族的意思了。另一方面,说到 GCC 对于各种硬件平台的支持,概括起来就是一句话:无所不在。几乎所有有点实际用途的硬件平台,甚至包括有些不那么有实际用途的硬件平台。

Gcc 简介
Linux系统下的gcc(GNU C Compiler)是GNU推出的功能强大、性能优越的多平台编译器,是GNU的代表作品之一。Gcc是可以在多种硬体平台上编译出可执行程序的超级编译器,其执行效率与一般的编译器相比平均效率要高20%~30%。

GCC 3.0印象记
从1999年4月开始,GCC的含义从GNU C Compiler变成了GNU Compiler Collection,支持C、C++、Objective C、Chill、Fortan和Java等语言。其中C++编译器G++当然是我们关注的焦点。从GCC网站的介绍中可以看出,G++作了不少改进,更好 地支持C++标准。我们将选出相关的内容逐一评论。我们对GCC 3.0的总体印象是,有不少改进,但"革命尚未成功",还得加把劲儿。
技术篇
GCC是整个协作软件开发理念的基础,时至今日,GCC的使用范围已不仅仅限于Linux平台,而是扩展到了包括Windows在内的很多平台。这样,GCC性能的高低,还关系到许多专有软件的核心竞争力。

Linux上安装GCC编译器过程

在cygwin下安装gcc4.0

GCC--一切从这里开始
要想读懂本文,你需要对C语言有基本的了解,本文将介绍如何使用gcc编译器。首先,我们介绍如何在命令行方式下使用编译器编译简单的C源代码。然后,我们简要介绍一下编译器究竟作了那些工作,以及如何控制编译过程。我们也简要介绍了调试器的使用方法。

GCC 中文手册

GCC中SIMD指令的应用方法
X86架构上的多媒体应用开发,如果能够使用SIMD指令进行优化, 性能将大大提高。目前,IA-32的SIMD指令包括MMX,SSE,SSE2等几级。 在GCC的开发环境中,有几种使用SIMD指令的方式……

GCC常用命令描述

Gcc使用的内嵌汇编语法格式小教程
本文对内嵌汇编语法,从基本语法、内嵌汇编的格式介绍、和扩展的内嵌汇编格式进行了详细说明,需要说明的是gcc采用的是at&t的汇编格式。
现状篇
GCC4.0的发展道路并不平坦。GCC 4.0发布不久就因为无法编译Linux图形界面KDE,而遭到参与开发KDE的程序员们的放弃。但是,一方面,GCC4.0编译性能的提高,是有目共睹 的。另一方面,开源软件的一大优势,就在于它能在开发者的不断改进中变得完善。

开源开发工具GCC将大翻修 性能有望全面提升
改良GCC 并非易事,从GCC 3.3 版升级到3.4 版,在性能上虽然有进步,但却造成回溯兼容性的问题。GCC4.0在这方面又做得如何呢?

开源利器GCC 4.0性能改进工作火热进行
GCC 4.0发布不久就遇到问题,Linux图形界面KDE无法用GCC编译,参与开发KDE的程序员们随即放弃了GCC 4.0。这些问题又如何解决呢?

Read More...

VOCAL 1.5.0 won't compile with gcc 3.4.1

Description: Opened: 2004-11-17 21:45

VOCAL 1.5.0 won't compile with gcc 3.4.1 due to changes in how gcc handles
namespace type limitations.... apparently is stricter now, more in conformance
with standards... also other problems.
First problem:
util/Timer.h -- added #include <iostream> to make compilation work

Second problem:
util/mstring.hxx -- added string:: prefix to npos for friend declarations using npos

Third problem: gcc reports:
../build/../util/Fifo.cc:90: error: `myMutex' undeclared (first use this function)
This appears to be some sort of namespacing problems (undoubtedly prefixing
with something:: will fix it) but at this point i'm giving up...

i'm going to try installing an older version of gcc.

Oh yes, what i did to begin with:
wget http://www.vovida.org/downloads/vocal/1.5.0/vocal-1.5.0.tar.gz
cd vocal
make OPTIMIZE=1 all


-Ted
------- Additional Comment #1 From Sam Jiang 2005-01-12 18:45 -------
The Third Problem is fixed in CVS HEAD version -- prefixing myMutex with this->
to let g++ find members of a dependent base

the following note is from url: http://gcc.gnu.org/gcc-3.4/changes.html#3.4.3

In a template definition, unqualified names will no longer find members of a
dependent base (as specified by [temp.dep]/3 in the C++ standard).
For example,

template <typename T> struct B {
int m;
int n;
int f ();
int g ();
};
int n;
int g ();
template <typename T> struct C : B<T> {
void h ()
{
m = 0; // error
f (); // error
n = 0; // ::n is modified
g (); // ::g is called
}
};

You must make the names dependent, e.g. by prefixing them with this->. Here is
the corrected definition of C<T>::h,

template <typename T> void C<T>::h ()
{
this->m = 0;
this->f ();
this->n = 0
this->g ();
}

As an alternative solution, you may use using declarations instead of this->:

template <typename T> struct C : B<T> {
using B<T>::m;
using B<T>::f;
using B<T>::n;
using B<T>::g;
void h ()
{
m = 0;
f ();
n = 0;
g ();
}
};

Read More...

解决问题 “error: `cout' was not declared in this scope”

code is:

#include <iostream>

int main(int argc, char *argv[])
{
cout << "hello world" << endl;
}

when compile the erro info is below:

test@kenshinxf ~/sutdy $ g++ scat.cpp -o scat

scat.cpp: In function `int main(int, char**)':
scat.cpp:12: error: `cout' was not declared in this scope
scat.cpp:12: error: `endl' was not declared in this scope

the reason is :

This is becuase C++ 1998 requires cout and endl be called
'std::cout' and 'std::endl', or that a proper using directives such as
'using namespace std;' be used.

#include <iostream>

int main(int argc, char *argv[])
{
std::cout << "hello world" << std::endl;
}

or

#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
cout << "hello world" << endl;
}


Read More...

星期四, 九月 27, 2007

防止编译因未指定动态链接库而出错

1 当一个程序使用动态函数时,编译该程序时就必须指定含所用动态函数的动态链接库,否则编译将会出错退出.如本文示例程序ady.c的编译(未明确引用动态链接库libmy.so):

# cc -o ady ady.c
/tmp/ccL4FsJp.o: In function `main':
/tmp/ccL4FsJp.o(.text+0x43): undefined reference to `gettime'
collect2: ld returned 1 exit status
#
注: 因为ady.c所含的动态函数getdate,gettime不在系统函数库中,所以连接时出错.
2 编译时引用动态链接库的几种方式
(1)当所用的动态链接库在系统目录(/lib,/usr/lib)下时,可用编译选项-l来引用.即:
# cc -lmy -o ady ady.c
#
注:编译时用-l选项引用动态链接库时,库名须使用其缩写形式.本例的my,表示引用libmy.so库.若引用光标库libncurses.so,须用-lncurses.注意,-l选项与参数之间不能有空格,否则会出错.
(2)当所用的动态链接库在系统目录(/lib,/usr/lib)以外的目录时,须用编译选项-L来指定动态链接库所在的目录(供编译器查找用),同时用-l选项指定缩写的动态链接库名.即:
# cc -L/usr/zzz/lib -lmy -o ady ady.c
#
(3)直接引用所需的动态链接库.即:
# cc -o ady ady.c libmy.so
#
# cc -o ady ady.c /lib/libmy.so
#
等等.其中,动态链接库的库名可以采用相对路径形式(文件名不以/开头),也可采用绝对路径形式(文件名以/开头).

Read More...

转贴:快速設計 CSS 版型 的 YUI CSS Grid Builder

一般要設計頁面版型, 如欄位數, 側邊欄等, 多少要運用CSS 語法或是使用 html table的方式. 如果不熟悉CSS, 就考慮 Yahoo 提供的 CSS Grid 工具來設計介面吧!

只要調整欄位數, 欄寬, 就可以自動產生語法.





YUI:CSS Grid Builder 提供一個線上快速產生版型語法的介面, 即使不懂 CSS 語法, 也可以操作.

在Body Columns, 有幾種選項 可以選擇, 如左邊側邊欄, 右邊側邊欄.


輸入header, footer的文字及顯示位置


利用 "add another row"的方式, 可創建出多欄的樣式.


設定好之後, 按 show code, 就可以顯示程式碼了!


另外, Body的寬度, 也可以自訂哦!


YUI CSS Grid Builder : http://developer.yahoo.com/yui/grids/builder/

Read More...

越狱第三季来了

终于又等来新一季的越狱,17日在美国正式开播,不过据说新一季收视率却让所有人大跌眼镜,首播收视率下滑高达24%,收看观众比第二季首播减少了200万人。不过即便如此,我依然是挺期待的。
要等待。
剧情介绍:


《越狱》的编剧和执行制片人保罗·朔伊林表示,第三季会将更多的细节联系到一起,让观众体会它的不可思议。保罗同时说,两大绝对主角文特沃斯·米勒
饰演的弟弟迈克尔和多米尼克·珀塞尔扮演的哥哥林肯,其中有一个可能不会活到第三季结束。”他们会再度失散,所以他们的故事也将独自展开。”保罗对《好莱
坞报道》的记者说,”他们未来会再度相聚到一起,他们的冲突和交融也将到来,但他们中的一个可能活不到全季终结。”


  第三季可能会再度回到监狱拍摄,但这次不再是美国的狐狸河监狱,而是南美洲国家的监狱。保罗同时透露,商谈和签约等事项将在5月前敲定,大部分角色都将保留,该剧还计划增加至少四个新角色,两男两女,且都不是美国人。


新剧揭秘


  米帅麻烦一大堆


  2005年8月,《越狱》第一季在美国首播,短短时间内就在全球掀起了收视狂潮。但《越狱》第二季的运气明显没有那么好,剧情对各主演分散的安
排,让很多越狱迷们逐渐失去了耐性,该剧在美国的收视率排名甚至一度跌出前10。不过这次观众可以放心了,据FOX官网透露,第三季将安排迈克兄弟联合敌
人马洪再度逃狱,本季的越狱之旅,将和第一季一样充满变数,迈克也将遭遇更多麻烦。


  麻烦一:索纳监狱有进无出


  在目前曝光的第一集前17分钟片段中,观众可以明显感觉到这一季的《越狱》更阴暗、更刺激:迈克被关进了巴拿马的索纳监狱。用剧中官员的话
说:”那可是全世界最可怕的监狱,所有穷凶极恶的罪犯都聚集在那里
—成千上万的小偷、强奸犯和杀人犯。一年前他们发动了一场野蛮暴动,守卫都撤出来了,让他们在里面自生自灭。那里是单行道—只进,不出,除非你死了。”


  在片花中,一向冷静睿智的迈克这次有些惊慌失措,看着这个监狱中犯人之间斗殴残杀却没有狱警制止的情况,只能躲在角落里发抖。


  麻烦二:爱人莎拉不会现身


  据网上”剧透”一族的消息,第三季在情节上,林肯重走迈克在第一季的道路,他文身后潜入监狱要将弟弟救出这个人间地狱。在人物上,除了在前两季中对迈克和林肯穷追不舍的探员马洪,倒霉的狱警巴利克、极度变态的T-Bag都会出现。


  至于之前盛传女主角莎拉虽然怀孕,但还是会排除万难回来和迈克谈情的消息,美国知名电视杂志《TVGUIDE》日前给予了否定,并透露莎拉这一季不会现身。


  让粉丝更加难过的是,主角迈克和他的哥哥林肯将会在这季死去一个。此外本季还将有不少新增人物粉墨登场。


  麻烦三:兄弟感情出现摩擦


  《越狱》编剧Scheuring介绍说:”第三季本质上是新的一章,通过前两季,每个角色已经彼此独立地发展故事了,但在第三季中他们将再次走到一起。”看来导演已经意识到第2季中,让每个人的故事情节彼此独立绝对是个错误。只有让人物之间充满斗争和相互配合,才是明智的安排。


  不过,在《TVGUIDE》杂志的人物采访中,林肯的扮演者多明尼克.伯萨尔透露,迈克与林肯兄弟感情会出现摩擦,”迈克觉得哥哥背叛了他,然后他们就分道扬镳了,所以就有林肯他自己一个人去侦察的故事发生。”


Read More...

【图】15个超漂亮科幻相关壁纸下载站点集装

如果您正在寻找一些很炫很科幻的壁纸,再或者你找不到合适你屏幕大小的壁纸,这篇文章是为你而写的。这些壁纸的漂亮程度绝对超乎你的想象,强烈推荐你下载使用。

1、先来个Desktopography的,它上面有超过40个科幻的主题壁纸,都是一些专业人士设计的,而且网站的设计相当漂亮,华丽的界面和震撼的音乐。
2、Vista Wallpaper ,放心,这不是只提供vista壁纸下载的网站。这个网站的壁纸能让你有回归大自然的感觉(德文网站) 可能吧 www.kenengba.com 3、c’t Wallpapers 上面有很多关于企鹅的壁纸,不知道是否和linux有关呢 可能吧 www.kenengba.com 4、ArtLebedev Wallpapers and Posters ,不要被下面的单张壁纸迷惑倒,它不是提供apple壁纸的网站。 5、Social Wallpapering ,web2.0相关的壁纸。壁纸是又匿名用户上传的。 6、Wallpapers Flickr Pool,超过20000张漂亮的壁纸供你下载。 7、Mexivista ,每个季度都有新的壁纸推出,可惜的是有些壁纸尺寸太小。 8、Gallery of Art ,提供的壁纸大多都是黑色背景的。需要注意的是你可能需要关闭“阻止弹出窗口”。 可能吧 www.kenengba.com 9、Adobe CS3 Wallpaper,这个的确和Adobe有点关系。 10、Design Is… Pool,壁纸由用户上传,来自Flickr。需要翻墙查看。 11、Wallpaperstock.net,有回家的感觉吗? 可能吧 www.kenengba.com 12、13 Fantastic Free Wallpaper Images,够科幻吗? 13、Gamers Wallpapers Gallery,提供游戏壁纸下载,尤其是赛车游戏。壁纸超过8千张。而且像素都是非常高的。 14、Mike Bonnell’s Wallpaper,很有艺术感吧?里面还有更多。 15、Four,这个下载站点的名字比较有趣。站点里面的壁纸可能比较适合女生。 可能吧 www.kenengba.com

Read More...

星期一, 九月 24, 2007

转贴:无线网卡驱动RT73的移植

1.下载最新版的RT73无线网卡驱动:
# wget http://rt2x00.serialmonkey.com/rt73-cvs-daily.tar.gz
解压:# tar zxvf rt73-cvs-daily.tar.gz

2.在内核中创建新文件夹drivers/usb/net/rt73,
# mkdir drivers/usb/net/rt73
将解压出来的文件夹Module下的文件拷贝到刚才新建的rt73文件夹中:
# cp rt73-(time)/Module/* /home/oem/trunk/cirrus-1-0-0-4/linux-2.6.8.1/drivers/usb/net/rt73


3.修改Qwerk板内核源代码,加入RT73驱动的配置信息,以使在make menuconfig 中能添加RT73驱动的选项。

?修改drivers/usb/net/Kconfig文件,加入RT73的驱动模块的配置项:
# gedit drivers/usb/net/Kconfig &
加入以下内容:
config RT73
tristate “support for rt73 wireless usb device”
depends on USB && NET && USB_USBNET

?修改drivers/usb/net/Makefile, 加入rt73的编译项:
# gedit drivers/usb/net/Makefile &
添加一下内容:
obj-$(CONFIG_RT73)+= rt73/

4.修改RT73的Makefile,设置内核位置和编译选项:

?删除以前的modules选项,并将arm编译项改成modules,这样编译的时候才是for ARM版本的驱动模块;

?修改KERNDIR为Qwerk内核位置:
KERNDIR=/home/oem/trunk/cirrus-1-0-0-4/linux-2.6.8.1

5.配置内核:

?将Qwerk默认配置拷贝到内核根目录下:
# cp ../edb9302/linux.config .config

?用make menuconfig界面配置编译选项,选上RT73无线网卡编译选项:
在USB devices à network à support for rt73 wireless usb device,按空格键选为M,将其编译成模块。

6.编译内核模块:
# make modules
成功编译后,会在drivers/usb/net/rt73目录下生成rt73.ko驱动文件,将其拷贝到FTP目录下,以便于下载到Qwerk板上:
# cp drivers/usb/net/rt73/rt73.ko /home/ftp/

7.下载rt73驱动到Qwerk上,并修改一些脚本文件使其开机加载驱动并启用网卡:
假设Qwerk板已经可以启动起来(烧写系统可以参考QwerkDevelopmentGuide),启动Qwerk板,从minicom命令行操作:
# cd /opt/driver/
# wget ftp://192.168.1.201/rt73.ko
编写开机加载rt73.ko驱动、启用网卡脚本,将其放入/opt/scripts/目录下:
# cd ../scripts/
# vi wifi-up
加入如下内容:
(去公司后Copy到这儿)
修改/opt/scripts/robot.init脚本文件,在最后添加wifi-up脚本:
# vi robot.init
加入:
/opt/scripts/wifi-up
保存推出。

8.至此为止,无线网卡驱动移植和配置工作已经完成,重启Qwerk,无线网卡就能工作了。

说明:

1.如果按照modules编译的rt73.ko不能工作的话,可以选用armdebug编译。

附一个老外的指导:

put the contents of the Module directory into my arm 2.6.15 kernel tree under drivers/usb/net/rt73, then did the following to make it part of the kernel build:
- I added to the /drivers/usb/net/Kconfig to add an option to enable the rt73 module,
- Then edited the Makefile in /drivers/usb/net to have it build the subdir rt73 when the option above is active.
Then I ran the kernel menuconfig to actually enable that option.

Finally I edited the Makefile for the rt73 driver itself:
- put the right paths in KERNEL_SOURCE and MODULE_ROOT
- removed the calls to /sbin/depmod since we're not on the target system
- deleted the module and debug rules
- renamed arm rule to module and armdebug rule to debug

At this point doing make modules && make modules_install from the kernel root did the trick.
I'm not sure if this will be enough on your system. It worked for me.


Read More...

转帖:[嵌入式中国 http://www.armchina.cn/]既是老师又是师兄的临别箴言

以下是 嵌入式中国 http://www.armchina.cn/ 网站上的文章,看后感触颇深!

他在评阅我们毕设论文时候就经常为计算机学生现状感到痛心疾首,在最后一次论文的
修订中收到老师最长的一封邮件,洋洋洒洒三千字有余。一口气读完,感慨颇多,特别是
读到96级和03级对比之处惊讶之余,心中生出感动的情绪来。在这个时候得到老师宝贵
的“批评”,我想我是幸运的,因为之后的路更长。

在此,我再次谢谢老师,谢谢这段时间在实验室遇到的其它老师和学长,各种教诲和帮
助铭记于心。经过老师同意后转贴于此,希望使更多人获益。


----------------------------------我是分割线--------------------------------

在这次论文评审中我要求比较严格,对一些同学批评比较严厉,用词激切,可能会使一
些同学的自尊心受伤,这并非我初衷,但却是我无可奈何之下的最后选择——我就是要
刺痛你们的神经,使你们知耻而后勇,奋发而图强。我是北邮96计算机的,本硕博连读
最后留校当老师,按说也是你们的大师兄,你们所经历的考研、找工作、毕业设计、毕
业狂欢等等我以前都经历过,你们所没有经历的读研、工作、招聘面试、审查指导论文
等等我也经历过,我也曾喜欢玩游戏,打篮球,看电影,网络聊天,……,所以我很清
楚你们目前的状态,但我更加清楚今后你们将面对的社会的残酷无情。

我慨叹于现在北邮的学风日下、人心浮躁、放任自流、法不责众——这不仅是培养方法
问题,这是学风校风问题!

我痛心于现在学生的基础薄弱、懒散颓废、不负责任、没有追求——这不仅是生活方式
问题,这是素质人品问题!

我震惊于论文满篇的错字病句、抄袭剽窃、文理不通、逻辑混乱——这不仅是写作态度
问题,这是基本能力问题!

我哀其不悟,怒其不争,捶胸顿足,痛心疾首。
我温言软语,循循善诱,横眉立目,唇枪舌剑。
我叮嘱提醒,罗嗦唠叨,婆婆妈妈,唐僧作风。
但众人全当身外事,皆做耳旁风,我又奈何?

各位落得潇洒快活,不拘小节,我却成了神经质、强迫症。

最后我想告诉你们一些我们的年代的事实,可以向任何96 级的人证实:

96年,北邮高考招生的分数线在全国20多个省是前三名(清华、北大、北邮),其中在
5个省(?)是第一名。我高考614 分,是新疆第15名,但在我们宿舍8 个人中仅排第5
名。当时北邮的学生对北航、北理、交大、师大等学校不屑一顾,认为都是二流学校
(我们自然是一流),“不以其为竞争对手”,颇有些轻狂傲慢。

当时每天晚上7: 00~11:00宿舍楼都没有人,大家都去自习了,楼道里空荡荡的,说
话都有回声。 11:00 熄灯后大家陆续回来,11:00~1 :00楼道里和楼门口等有灯的
地方挤满了背英语的同学( 50%),挡住了道路,使洗漱的同学行走困难,背诵声使其
他同学(50%)睡不着觉,也只好起来读书。这一点可向宿舍楼管理员查证。

每天都很难找到自习的地方,各处教室都人满为患,最大的理想就是有一个固定的自习
位置。考试期间同学们强烈要求增加通宵教室的数量。

我大学期间学习很努力,小班排名才10~15(全班 30人),但考研考了全班第一,这是
我大学期间考得最好的一次。

从大二起,宿舍里已经有电脑了,只是没有联网,大部分同学都用它来编程,做课程设
计。

作为计算机系的(不良)传统,Pascal是唯一教授的编程语言,但从大三起几乎所有同
学都自学使用 C/C++来编程完成课程设计,因为大家都认为Pascal 很弱智,用它会被
人鄙视。毕业设计时从来就没有什么C++、 Java、面向对象的培训,就像不用培训你怎
么吃饭一样,这是常识,谁都知道。

课程设计几乎人人动手,女生也不例外。不会编程的男生被女生瞧不起。

考试很难,就算认真听课,按时完成作业也不能保证通过考试,还必须努力复习,很多
人都从高教书店买了《高等数学习题集》、《电子电路习题集》这样的厚书,随着讲课
的进度一章一章做完。尽管这样,每次还有不少人不及格,而不及格是莫大的耻辱,在
同学前都抬不起头,从此没有地位,名誉扫地。我大学时有两次特别害怕考不及格,痛
苦忧虑,后悔复习不够,最后还是涉险过关。

当时北邮规定大学四年内累计有1门课不及格则不准留京工作, 3门课不及格即不发学
位证,7、 8门不及格则要退学。严格执行,铁面无私。

我们宿舍共8人,有 1人在大三退学(因玩游戏),2人没有获得学位(因玩游戏),还
有一个平时成绩第一名的同学大学物理实验挂了(运气不好,碰到分光镜了),被取消
留京资格。

没有听说过作弊,连快要被退学的学生都没想过(作弊比退学都丢人),学校从来没有
公布过对作弊学生的处理结果——因为没人作弊。大家都认为作弊的人是垃圾。

2000年毕业时北邮毕业生人数与用人单位需求人数之比为1 :8,我本人被三家单位录
取(华为北研所、大唐微电子、西门子),与华为签约(注明考不上研才去,考上研合
约就自动失效),月薪5.4k,华为请吃饭并赠送礼品(我的第一个钱包,以前钱都是直
接揣在兜里的),办理了北京户口,最后我还是上研了,让华为很不爽。

北邮毕业生质量过硬,声誉极佳,各地运营商基本上只认北邮学生,只到北邮专场招
聘。华为等国内外著名企业主要招收北邮学生,我曾目睹师大计算机系学生去华为投"
霸王"简历,被华为HR 嘲笑"师大还有计算机系?"。水木BBS上清华学生抱怨找工作不
如北邮,进不了运营商。

除了考试不及格的人,想留北京就能留,户口没问题。某公司曾放言,只要是北邮96级
的来多少要多少,不用面试笔试。

除了北京、上海、广东,其他地方的单位基本上没有人去。曾经看到找工作接近尾声时
某省移动公司羞答答地在一棵路边的杨树上贴出告示,愿意接收任何还没有找到工作的
同学到他们单位,被大家爆笑一番。

没人想当公务员,请都不去。

当时最好的电脑是奔腾1、 2代,流行的游戏是真侍魂、三国、FIFA、红色警戒、星际
争霸、 MUD(文字版网络游戏),80% 的男生都曾玩过游戏,但大部分都是偶尔玩,不
耽误学习。玩MUD的人最多,最狂热,最颓废。我大学期间没玩游戏,但编了 2个可支
持人机对弈的游戏——大一用Pascal编了翻转棋,大二用 C编了五子棋,获得2次北邮
的星火杯编程大赛三等奖。我大三获得康柏杯编程大赛一等奖,研一时作为北邮代表队
成员参加了在香港举行的ACM国际大学生编程大赛,这是北邮首次参赛。其实,我上大
学前都没有见过计算机,纯粹是凭着热爱,凭着兴趣。

以游戏玩得好出名的人赢得的都是负面的声誉,受人嘲弄,除非他还具备后面所说的素
质。我们的时代学习尖子、编程高手、体育主力、文艺骨干、文学才俊才是真正的风云
人物,受人尊崇仰慕,我的一个同学朋友同时占据前三项桂冠,而且思想成熟深邃,眼
光长远独到,被我佩服得无以复加。我慨叹人世间竟然竟然有这样的人才,苍天不公!
与优秀的人为伍,成为优秀的人,这是我们时代的座右铭。不服,就是不服,精英才
俊,宁有种乎?!你强,我要比你更强!每个人都有自己要超越的目标人物,大家都铆
着一股颈,明里竞争,暗自加油。韬光养晦,卧薪尝胆,针锋相对,锋芒毕露!纸香墨
飞,词赋满江,才华横溢,汪洋恣肆!这首我大学时写的《诗言志》,最能够反映我们
那个时代的精神风貌:

少年轻名利,剑气冲斗牛,半生浮四海,独步纵九州,头颅谢知己,杯酒傲王侯,愿为
擎天柱,大笔快春秋。

当时的本科毕设难度大致相当于现在的硕士毕设难度。当时毕设时曾两个人合用一台电
脑,一个座位。

我现在回想,各个学习阶段的辛苦程度(主要是心理压力程度)排序为(最辛苦到最轻
松):博士、本科、高中、硕士。

时代变了,我们的时代是雅典时代,斯巴达时代,罗马时代,盛唐时代,而现在呢,我
想是巴比伦时代。

痛说了革命传统,你们的状况我就不多讲了,各位最清楚。我再说一下现在你们面临的
社会形势:

扩招造成现在研究生人数大于当时的本科生人数。

工作很难找,竞争很激烈,毕业生薪酬看降,硕士本科化。

留京很困难,本科户口原则上不给。

欲求各地移动公司工作而不可得。当年那个省移动公司现在牛的很。

房价飞涨了三四倍,买房要多奋斗10年。

北邮的牌子不再过硬,运营商、厂商认为北邮只是众多大学之一,可能还不如北航、北
理,招聘时无甚差别。

大锅饭单位越来越少,各用人单位更加看重基本素质、能力、责任心,对不合格的人开
除没商量。

游戏更加好玩了。。。

事实如此,对比一下,思考一下,想想自己该干什么。毕业设计是大学教育的最后一个阶段,马上就要结束了,希望你们能够有所收获(不光是毕业证)。大家好自为之吧。

Read More...

星期四, 九月 20, 2007

又一套linux girl

Read More...