作用:用来查看程序运行所需的共享库,常用来解决程序因缺少某个库文件而不能运行的一些问题。 1、首先ldd不是一个可执行程序,而只是一个shell脚本 2、 ldd能够显示可执行模块的dependency,其原理是通过设置一系列的环境变量,如下:LD_TRACE_LOADED_OBJECTS、 LD_WARN、LD_BIND_NOW、LD_LIBRARY_VERSION、LD_VERBOSE等。当 LD_TRACE_LOADED_OBJECTS环境变量不为空时,任何可执行程序在运行时,它都会只显示模块的dependency,而程序并不真正执 行。要不你可以在shell终端测试一下,如下: (1) export LD_TRACE_LOADED_OBJECTS=1 (2) 再执行任何的程序,如ls等,看看程序的运行结果 3、 ldd显示可执行模块的dependency的工作原理,其实质是通过ld-linux.so(elf动态库的装载器)来实现的。我们知道,ld- linux.so模块会先于executable模块程序工作,并获得控制权,因此当上述的那些环境变量被设置时,ld-linux.so选择了显示可执 行模块的dependency。 4、实际上可以直接执行ld-linux.so模块,如:/lib/ld-linux.so.2 --list program(这相当于ldd program) ldd命令使用方法(摘自ldd --help) 名称 ldd - 打印共享库的依赖关系 大纲 ldd [选项]... 文件... 描述 ldd 输出在命令行上指定的每个程序或共享库需要的共享库。 选项 --version 打印ldd的版本号 -v --verbose 打印所有信息,例如包括符号的版本信息 -d --data-relocs 执行符号重部署,并报告缺少的目标对象(只对ELF格式适用) -r --function-relocs 对目标对象和函数执行重新部署,并报告缺少的目标对象和函数(只对ELF格式适用) --help 用法信息 注意: ldd的标准版本与glibc2一起提供。Libc5与老版本以前提供,在一些系统中还存在。在libc5版本中长选项不支持。另一方面,glibc2版本不支持-V选项,只提供等价的--version选项。 如果命令行中给定的库名字包含'/',这个程序的libc5版本将使用它作为库名字;否则它将在标准位置搜索库。运行一个当前目录下的共享库,加前缀"./"。 错误: ldd不能工作在a.out格式的共享库上。 ldd不能工作在一些非常老的a.out程序上,这些程序在支持ldd的编译器发行前已经创建。如果你在这种类型的程序上使用ldd,程序将尝试argc = 0的运行方式,其结果不可预知。 !!说明:ldd程序是shell脚本,可以拷贝到其它环境、系统(arm)直接运行!! |
2010年10月6日星期三
[转载]ldd命令原理与使用
原文:http://hi.baidu.com/buptwangxin/blog/item/89542ecb655eba4ff31fe72c.html
2010年10月4日星期一
TQ2440 sound card (uda1341)
Transplant the uda1341 driver to s3c2440 (tq2440 board).
First,let's analysis the source code of uda1341 driver.
sound/soc/s3c24xx/s3c24xx_uda134x.c
242static struct s3c24xx_uda134x_platform_data *s3c24xx_uda134x_l3_pins; 290static int s3c24xx_uda134x_probe(struct platform_device *pdev) 291{ 292 int ret; 293 294 printk(KERN_INFO "S3C24XX_UDA134X SoC Audio driver\n"); 295 296 s3c24xx_uda134x_l3_pins = pdev->dev.platform_data; /*here the probe() only take the platform_data from platform_device, and the corresponding type is s3c24xx_uda134x_paltform_data, and search the source we find that it is defined in include/sound/s3c24xx_uda134x.h */ 297 if (s3c24xx_uda134x_l3_pins == NULL) { 298 printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " 299 "unable to find platform data\n"); 300 return -ENODEV; 301 } 302 s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power; 303 s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model; 304 305 if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_data, 306 "data") < 0) 307 return -EBUSY; 308 if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk, 309 "clk") < 0) { 310 gpio_free(s3c24xx_uda134x_l3_pins->l3_data); 311 return -EBUSY; 312 } 313 if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode, 314 "mode") < 0) { 315 gpio_free(s3c24xx_uda134x_l3_pins->l3_data); 316 gpio_free(s3c24xx_uda134x_l3_pins->l3_clk); 317 return -EBUSY; 318 } 319 320 s3c24xx_uda134x_snd_device = platform_device_alloc("soc-audio", -1); 321 if (!s3c24xx_uda134x_snd_device) { 322 printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: " 323 "Unable to register\n"); 324 return -ENOMEM; 325 } 326 327 platform_set_drvdata(s3c24xx_uda134x_snd_device, 328 &s3c24xx_uda134x_snd_devdata); 329 s3c24xx_uda134x_snd_devdata.dev = &s3c24xx_uda134x_snd_device->dev; 330 ret = platform_device_add(s3c24xx_uda134x_snd_device); 331 if (ret) { 332 printk(KERN_ERR "S3C24XX_UDA134X SoC Audio: Unable to add\n"); 333 platform_device_put(s3c24xx_uda134x_snd_device); 334 } 335 336 return ret; 337}
include/sound/s3c24xx_uda134x.h
1#ifndef _S3C24XX_UDA134X_H_ 2#define _S3C24XX_UDA134X_H_ 1 3 4#include <sound/uda134x.h> 5 6struct s3c24xx_uda134x_platform_data { 7 int l3_clk; 8 int l3_mode; 9 int l3_data; /*the three member above is a l3 interface, and we must register io port to them.*/ 10 void (*power) (int); 11 int model; /*the model is used to identify different types of uda134x, and the Marco is defined in include/sound/uda134x.h */ 12}; 13 14#endif
include/sound/uda134x.h
1/* 2 * uda134x.h -- UDA134x ALSA SoC Codec driver 3 * 4 * Copyright 2007 Dension Audio Systems Ltd. 5 * Author: Zoltan Devai 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12#ifndef _UDA134X_H 13#define _UDA134X_H 14 15#include <sound/l3.h> 16 17struct uda134x_platform_data { 18 struct l3_pins l3; 19 void (*power) (int); 20 int model; 21#define UDA134X_UDA1340 1 22#define UDA134X_UDA1341 2 23#define UDA134X_UDA1344 3 24#define UDA134X_UDA1345 4 25}; 26 27#endif /* _UDA134X_H */ 28
Next, initialize the platform_device in mach-s3c2440/tq2440.c (your board specified file)
/*for sound car UDA 1341*/
#include <sound/s3c24xx_uda134x.h>
/*for sound card uda1341*/
static struct s3c24xx_uda134x_platform_data tq2440_uda1341_platform_data = {
.l3_clk = S3C2410_GPB(4),
.l3_mode = S3C2410_GPB(2),
.l3_data = S3C2410_GPB(3),
.model = UDA134X_UDA1341,
};
static struct platform_device tq2440_device_uda1341 = {
.name = "s3c24xx_uda1341",/*the name must be confronted to the driver*/
.id = 0,
.dev = {
.platform_data = &tq2440_uda1341_platform_data,
}
};
static struct platform_device *tq2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&tq2440_device_dm9000, //for DM9000//
&s3c_device_usbgadget, //for s3c USB device, the struct already included in plat/devs.h
&s3c_device_ac97, //for s3c AC97
&tq2440_device_uda1341 //for soundcard uda1341
};
And don't forget to enable the uda134x driver in the kernel configure.
After compiling the the kernel, if you built it as a module, and then just run “modprobe snd-soc-s3c24xx-uda134x”.By the way, if you need oss support, for example, mplayer was built without alsa support, you can load oss module with the command “modprobe snd-pcm-oss”.
2010年9月30日星期四
恢复ubuntu默认面板的方法
打开终端,终端窗口打开之后,立即在提示符后面输入下列命令:
gconftool --recursive-unset /apps/panel
(注意:每个斜杠 “/” 后面没有空格)
接下来输入下列命令:
rm -rf ~/.gconf/apps/panel
最后还需要执行:
pkill gnome-panel
来源:http://helpforlinux.blogspot.com/2009/08/restore-ubuntu-panels-back-to-their.html
-----------------------------------------------------
这时还有可能遇到一个问题,那就是面板上的快捷方式在恢复后就不见了, 而且面板经常崩溃, 每次都这么做岂不是很麻烦, 作为一个懒人, 必须上脚本 -.-
#!/bin/bash
gconftool --recursive-unset /apps/panel
rm -rf ${HOME}/.gconf/apps/panel
gconftool --load ./Backup/panel-backup.xml
pkill gnome-panel
第4行中的 panel-backup.xml 是一个备份文件,在你面板还是好的时候,运行 "gocnftool --dump /apps/panel > ./Backup/panel-backup.xml" 就能为面板的配置文件进行备份.
-----------------------------------------------------
这时还有可能遇到一个问题,那就是面板上的快捷方式在恢复后就不见了, 而且面板经常崩溃, 每次都这么做岂不是很麻烦, 作为一个懒人, 必须上脚本 -.-
#!/bin/bash
gconftool --recursive-unset /apps/panel
rm -rf ${HOME}/.gconf/apps/panel
gconftool --load ./Backup/panel-backup.xml
pkill gnome-panel
第4行中的 panel-backup.xml 是一个备份文件,在你面板还是好的时候,运行 "gocnftool --dump /apps/panel > ./Backup/panel-backup.xml" 就能为面板的配置文件进行备份.
2010年9月19日星期日
在ubuntu下用thunderbird直接打开office文件的方法
一直在用thunderbird,觉得蛮好用的,就是在ubuntu下,如果收到doc或者是xls文件时,打开附件就会直接弹出文件保存对话框,没有像odt文件那样,可以选择直接打开或者保存。
google了一下,用中文搜,几乎没有
用英文搜索,第一个就是了 -,-
gnome open
https://addons.mozilla.org/en-US/thunderbird/addon/12523/
有了这个就可以完美解决问题了 ^_^
google了一下,用中文搜,几乎没有
用英文搜索,第一个就是了 -,-
gnome open
https://addons.mozilla.org/en-US/thunderbird/addon/12523/
有了这个就可以完美解决问题了 ^_^
2010年9月18日星期六
[转载]十分钟黑屏问题
9月13日
由一些小问题引起的东西
又是好久没有更新了,同样记录下这段时间干的事情。
来到公司报道之后我就去了工厂,呆了一个多月,熟悉公司各种产品的生产过程。当然,就是和生产线上的小MM们聊聊天,哈哈,开玩笑了。这期间我 的导师给我了个任务——一个UI的低成本实现。这个UI必须具有LCD显示、USB主机、网络等功能,要求就是低成本低成本再低成本;很自然选型选完之后 就又变成搞ARM了。买了开发板,硬件就没有什么好说的了。任务的重点落在了软件上,刚开始我和导师达成的意见是代码裸奔(省去授权费用),或者穿个自己 写的小OS。于是我花了2个星期的时间写了0.8(写了任务切换,其他没有最后写完)个类似uCOS功能的小OS,发现这种东西跑在ARM920T上实在 发挥不出920T的功能,于是我又花了2个星期写了存储管理,打算加入MMU;但是写完发现就算系统能工作,我怎么调试应用程序是个大问题,因为用了 MMU,用户进程就不能和内核一起玩了。经过和导师的商量,我再次回到了Linux;目前的打算是使用免费的内核,自己写个类似TC的图形库,或者使用 Microwindows + FLTK之类的不要钱的东西。很浪费时间啊,花了4个星期才发现原来自己写系统真的是非常困难的。但是这4个星期也没有白花,有些附属产品,例如自己写的 不需要stdlib库的malloc。其实我是第二次写这个东西了,第一次的不太成熟,用了几次就发现局限性了。现在写的这个是我啃了几天操作系统原理写 的,应该相对好用,以后有空我会贴出代码来。
然后就是我做过的Linux开发过程了,其实说起来,这次开发我发现自己Linux真的什么都不懂。过去偷懒没有花时间好好看看Linux内核,现在造成很多麻烦,今天这些问题,熟悉内核的人只需要1分钟就能搞定了,我花了1天多。写下这个笔记,以便以后查阅使用。
第一个问题:启动Linux的时候LCD会全屏花屏大约0.5秒,然后左上角出现一块不明花斑。
这个问题相对简单。因为我在Bootloader里面打开了液晶显示,缓冲区映射在某个地址上,当内核初始化MMU的时候,LCD控制寄存器里 缓冲区的位置信息就不对了,或者是Bootloader使用的缓冲区被内核的数据或代码覆盖,导致在内核初始化LCD之前,LCD花屏。
那个不明花斑其实是Linux的可爱小企鹅图片,但是可能因为缓冲区像素位宽和格式、LCD调色板设置等问题显示不出来。
花屏解决方法:在Bootloader加载系统之前关掉LCD控制器或者关掉LCD的背光,这样做比较简单。复杂的,就得改MMU映射部分代 码,在修改了MMU映射之后,立即修改LCD缓冲的位置。反正我就关掉LCD控制器了,因为内核很快就会初始化LCD,Windows启动都黑屏呢,我们 黑那么2秒钟也没有什么大不了的。
花斑解决方法:相信如果做产品的话,不需要显示什么企鹅给用户看,所以可以在内核选项里将这个企鹅logo关掉。具体位置在Device Drivers>Graphics support>Logo configuration,对应的宏相信在.config里面很容易找到。如果非要显示这个企鹅,那么可以在/drivers/video /console/fbcon.c里面找找,我也不知道怎么弄。
第二个问题:Linux启动之后,只要一段时间不动键盘(开发板上用IO扩展出来的键盘),LCD就会自动关闭(黑屏、显示慢慢消失之类),只要按下键盘就能恢复。
这个问题让我花了一天多的时间。其实如果是手持设备,这样也没有什么。但是我们公司的产品是要一直显示东西的,必须解决这个问题。我看了很多论 坛,有不少人也遇到了这个问题,但是我刚才是搜索的时候,关键词不对,总找不到正确的答案。如果你遇到了同样的问题,而且不想看我的三脚猫分析,那么就在 百度上搜索“blankinterval”、“setterm -blank 0”之类的,马上你就能找到简单的解决方案。
这个问题很容易让人想到屏幕保护和电源管理。的确,这是一种电源管理。但是,你却无法从Linux内核选项的电源管理中解决这个问题。我们一步步来。
首先,我测量到LCD的PCLK时钟消失了,这意味着内核把LCD控制器关掉了。于是,从LCD驱动程序着手。我用的是S3C2440,这是 2410的升级版,但是LCD控制器是一样的,在我拿到的开发板厂商给我做好驱动的内核里,驱动的位置在/drivers/video /s3c2410fb.c。为什么后面有个fb呢?这是Framebuffer的缩写,百度下你能找到很多关于它的解释。Framebuffer是所有 Linux下GUI程序对硬件操作的设备接口,位于/dev中,一般为fb0。在s3c2410fb.c中可以找到一个类似 s3c2410_disable_controller()这样名称的函数,我的驱动里叫pxafb_disable_controller(),可以看 出这个驱动是从pxa处理器改的,当然厂家不一样名字也叫得不一样。里面有一句类似这样写的 __raw_writel(fbi->reg.lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);,把这句话删掉LCD就不会关掉了。这是第一个层次,我也看到有人是这样做的。但是,这有问题,按键盘恢复后,原本显 示在屏幕上的东西如果你不重画会消失,就算你重画了,也会看到屏幕的某些部分先黑了下,然后恢复了。当然如果你可以接受,那么就这样吧。
然后,可以很自然的想到是谁调用了这个函数,从源头把这个问题消除掉。但是情况却不是这样的。我搜索这个函数名,找到了一个 set_ctrlr_state()的函数调用了pxafb_disable_controller(),搜索set_ctrlr_state(),发现 有个pxafb_task()调用了set_ctrlr_state(),但是到了pxafb_task()就没有办法再往上找了,因为这是提供给内核的 一个任务,以指针传递函数入口。我对内核了解太不够了,花了很多时间看了很多论坛上的文章,机缘巧合之下,我找到了/drivers/char/vt.c 这个文件。vt.c我感觉应该是2.4内核的console.c和vt.c的结合体,应为它集成了console基本上所有功能函数,就ioctl在 vt_ioctl.c这个文件里。这个文件的主要作用是负责管理控制台,如控制台的模式(图形、字符)、向控制台输出等等。其中能找到一些如 do_blank_screen(),blank_screen_t()这样的函数,就是这些函数关闭了LCD控制器,修改任意一个都可以起作用。网上的 一个解决方案是把blank_screen_t()变成空函数,但是我没有这样试过,我觉得已经来到了问题的根源附近,应该能从根本上解决。
我们先看下屏幕关闭问题的真正起因,看这个控制台初始化函数
static int __init con_init(void)
{
const char *display_desc = NULL;
struct vc_data *vc;
unsigned int currcons = 0;
{
const char *display_desc = NULL;
struct vc_data *vc;
unsigned int currcons = 0;
acquire_console_sem();
if (conswitchp)
display_desc = conswitchp->con_startup();
if (!display_desc) {
fg_console = 0;
release_console_sem();
return 0;
}
display_desc = conswitchp->con_startup();
if (!display_desc) {
fg_console = 0;
release_console_sem();
return 0;
}
init_timer(&console_timer);
console_timer.function = blank_screen_t;
if (blankinterval) {
blank_state = blank_normal_wait;
mod_timer(&console_timer, jiffies + blankinterval);
}
console_timer.function = blank_screen_t;
if (blankinterval) {
blank_state = blank_normal_wait;
mod_timer(&console_timer, jiffies + blankinterval);
}
// 这是对控制台定时器的初始化,定时器事件函数被连接到了blank_screen_t()
/*
* kmalloc is not running yet - we use the bootmem allocator.
*/
for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
vc_cons[currcons].d = vc = alloc_bootmem(sizeof(struct vc_data));
visual_init(vc, currcons, 1);
vc->vc_screenbuf = (unsigned short *)alloc_bootmem(vc->vc_screenbuf_size);
vc->vc_kmalloced = 0;
vc_init(vc, vc->vc_rows, vc->vc_cols,
currcons || !vc->vc_sw->con_save_screen);
}
currcons = fg_console = 0;
master_display_fg = vc = vc_cons[currcons].d;
set_origin(vc);
save_screen(vc);
gotoxy(vc, vc->vc_x, vc->vc_y);
csi_J(vc, 0);
update_screen(vc);
printk("Console: %s %s %dx%d",
vc->vc_can_do_color ? "colour" : "mono",
display_desc, vc->vc_cols, vc->vc_rows);
printable = 1;
printk("\n");
* kmalloc is not running yet - we use the bootmem allocator.
*/
for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
vc_cons[currcons].d = vc = alloc_bootmem(sizeof(struct vc_data));
visual_init(vc, currcons, 1);
vc->vc_screenbuf = (unsigned short *)alloc_bootmem(vc->vc_screenbuf_size);
vc->vc_kmalloced = 0;
vc_init(vc, vc->vc_rows, vc->vc_cols,
currcons || !vc->vc_sw->con_save_screen);
}
currcons = fg_console = 0;
master_display_fg = vc = vc_cons[currcons].d;
set_origin(vc);
save_screen(vc);
gotoxy(vc, vc->vc_x, vc->vc_y);
csi_J(vc, 0);
update_screen(vc);
printk("Console: %s %s %dx%d",
vc->vc_can_do_color ? "colour" : "mono",
display_desc, vc->vc_cols, vc->vc_rows);
printable = 1;
printk("\n");
release_console_sem();
#ifdef CONFIG_VT_CONSOLE
register_console(&vt_console_driver);
#endif
return 0;
}
register_console(&vt_console_driver);
#endif
return 0;
}
其中引用了一个叫blankinterval的全局变量和一个console_time,我不知道内核的定时器是具体是怎么工作,但是 这样的代码已经很明显了。这个定时器和电源管理宏PM_CONFIG没有任何关系,它是控制台的一部分。再看下blank_screen_t():
static void blank_screen_t(unsigned long dummy)
{
blank_timer_expired = 1;
schedule_work(&console_work);
}
{
blank_timer_expired = 1;
schedule_work(&console_work);
}
可以发现vt.c开头的宏,static DECLARE_WORK(console_work, console_callback, NULL);,找到了console_callback()这个函数:
static void console_callback(void *ignored)
{
acquire_console_sem();
{
acquire_console_sem();
if (want_console >= 0) {
if (want_console != fg_console &&
vc_cons_allocated(want_console)) {
hide_cursor(vc_cons[fg_console].d);
change_console(vc_cons[want_console].d);
/* we only changed when the console had already
been allocated - a new console is not created
in an interrupt routine */
}
want_console = -1;
}
if (do_poke_blanked_console) { /* do not unblank for a LED change */
do_poke_blanked_console = 0;
poke_blanked_console();
}
if (scrollback_delta) {
struct vc_data *vc = vc_cons[fg_console].d;
clear_selection();
if (vc->vc_mode == KD_TEXT)
vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
scrollback_delta = 0;
}
if (blank_timer_expired) {
do_blank_screen(0);
blank_timer_expired = 0;
}
if (want_console != fg_console &&
vc_cons_allocated(want_console)) {
hide_cursor(vc_cons[fg_console].d);
change_console(vc_cons[want_console].d);
/* we only changed when the console had already
been allocated - a new console is not created
in an interrupt routine */
}
want_console = -1;
}
if (do_poke_blanked_console) { /* do not unblank for a LED change */
do_poke_blanked_console = 0;
poke_blanked_console();
}
if (scrollback_delta) {
struct vc_data *vc = vc_cons[fg_console].d;
clear_selection();
if (vc->vc_mode == KD_TEXT)
vc->vc_sw->con_scrolldelta(vc, scrollback_delta);
scrollback_delta = 0;
}
if (blank_timer_expired) {
do_blank_screen(0);
blank_timer_expired = 0;
}
release_console_sem();
}
}
再看do_blank_screen(),随着struct vc_data中的与fops类似指针跟踪下去,就可以找到驱动里面的相应代码了。写出来太麻烦,让我偷懒把。
小总结下,其实在控制台内部就有一个定时器,它负责在一定时间之后将显示关闭,而无视是否打开了电源管理功能。那这和Framebuffer有什么关系呢?我从一个很弱智的角度解释,内核刚启动的时候有这样一句输出:
Console: colour dummy device 80x30
在初始化LCD控制器(Framebuffer)之后,有这样一句输出:
Console: switching to colour frame buffer device 80x30
我就理解:这时候,内核把控制台(也不知道是console还是tty)切换到了Framebuffer上,大虾们赶快跳出来批判我吧,呵呵。
回到正题,从代码可以发现,根本的解决之道是让blankinterval = 0,blank_state就不会是blank_off之外的值,也就不会关闭屏幕了。
但是问题到这里还是没有完全解决,如果用户程序希望改变blankinterval来实现屏保(当然在我的系统上用不着);另外,一些程序改变 了blankinterval,程序退出之后,屏幕在一段时间之后还是会关闭的。怎么才能在用户程序那头解决这个问题呢,这又耗费了我很多时间。
我在追查代码的过程中走了个弯路,认为修改控制台的模式可以不让黑屏现象出现,但是后来发现,这样可能会使控制台没有办法画图,不知道对不对。
忽略弯路,直接正解。vt.c中不是有很多操作控制台的函数么?看看是谁修改了blankinterval。于是搜索 blankinterval,发现setterm_command()修改了它,然后搜索setterm_command,找到了 do_con_trol()函数,搜索do_con_trol,找到了do_con_write()函数,搜索do_con_write,终于最终 BOSS现身了:con_write()函数。为什么说它是最终BOSS呢?看看这段:
static struct tty_operations con_ops = {
.open = con_open,
.close = con_close,
.write = con_write,
.write_room = con_write_room,
.put_char = con_put_char,
.flush_chars = con_flush_chars,
.chars_in_buffer = con_chars_in_buffer,
.ioctl = vt_ioctl,
.stop = con_stop,
.start = con_start,
.throttle = con_throttle,
.unthrottle = con_unthrottle,
};
.open = con_open,
.close = con_close,
.write = con_write,
.write_room = con_write_room,
.put_char = con_put_char,
.flush_chars = con_flush_chars,
.chars_in_buffer = con_chars_in_buffer,
.ioctl = vt_ioctl,
.stop = con_stop,
.start = con_start,
.throttle = con_throttle,
.unthrottle = con_unthrottle,
};
熟悉fops的话你就能看出来了,这是对tty设备的文件操作函数的表。也就是说,在用户程序里,通过open函数打开/dev/tty,然后 再用write函数就可以修改blankinterval了。原理是找到了,实践上有很大困难,那么多重函数调用,再看看do_con_trol()里面 的switch语句,正常人都要发晕。好在伟大的百度为我们提供了很多信息:在命令行下,可以使用setterm -blank 0指令来设置blankinterval。哈哈,救星来了,赶快看看setterm的源代码。setterm属于util-linux包,搜索一下很容易 找到。其中的perform_sequence()函数里有这样一段:
/* -blank [0-60]. */
if (opt_blank && vcterm)
printf("\033[9;%d]", opt_bl_min);
if (opt_blank && vcterm)
printf("\033[9;%d]", opt_bl_min);
真得很神奇啊,用个printf就可以在用户程序里解决这个问题,本来我是打算只说用printf解决的,看到原理我想会更舒服一些;况且,在我的系统上用printf是不行的。
但是!问题还没有完,往往在我们的系统中,LCD的虚拟控制台和控制台TTY不是同一个设备,也就是说,如果在程序里单纯的printf是不行的!这样只能修改你正在使用的TTY的blankinterval,而你用的却是文本方式的设备,不存在黑屏问题。
于是,就需要仔细比较/dev/console、/dev/tty、/dev/ttyn的设备号,在我的系统里,用户程序里/dev /console和/dev/tty都是5,说明他们是一个东西,/dev/ttyn是4,这才是FB上的虚拟控制台。但是/dev/ttyn不是正在使 用的TTY,那么怎么printf呢?只好用write函数来解决了。
写这样一段代码:
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
void some_function()
{
int f;
f = open("/dev/tty0", O_RDWR);
write(f, "\033[9;0]", 8);
close(f);
}
问题终于解决了。
总结下,第二个问题有很多种解决方法:
1.修改LCD驱动,把关闭LCD控制器的函数变为空(不推荐)
2.修改vt.c中的blank_screen_t()函数,让其为空(在系统不需要使用关闭显示功能时推荐)
3.修改vt.c中的blankinterval,让其为0(系统可能需要使用关闭显示功能,而且希望系统上电后正常状态下不会关闭显示时推荐)
4.修改用户程序,加入设置blankinterval的代码(推荐)
今天就写到这里,继续干活了。
2010年9月16日星期四
[转载]Linux内核中64位除法函数do_div
使用asm/div64.h中宏do_div
#include <asm/div64.h>
unsigned long long x,y,result;
unsigned long mod;
mod = do_div(x,y);
result = x;
64 bit division 结果保存在x中;余数保存在返回结果中。
--- End ---
2010年9月15日星期三
configure to keep ssh alive
在 .ssh/config 文件中,加入如下:
ConnectTimeout=1200
TCPKeepAlive=yes
ServerAliveInterval=45
就可以了。
订阅:
博文 (Atom)