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" 就能为面板的配置文件进行备份.

2010年9月19日星期日

在ubuntu下用thunderbird直接打开office文件的方法

一直在用thunderbird,觉得蛮好用的,就是在ubuntu下,如果收到doc或者是xls文件时,打开附件就会直接弹出文件保存对话框,没有像odt文件那样,可以选择直接打开或者保存。


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;
 acquire_console_sem();
 if (conswitchp)
  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);
 }
// 这是对控制台定时器的初始化,定时器事件函数被连接到了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");
 release_console_sem();
#ifdef CONFIG_VT_CONSOLE
 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);
}
 
可以发现vt.c开头的宏,static DECLARE_WORK(console_work, console_callback, NULL);,找到了console_callback()这个函数:
 
static void console_callback(void *ignored)
{
 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;
 }
 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,
};
熟悉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);
 
真得很神奇啊,用个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


Linux内核中64 bit division

使用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
就可以了。

small tips for text line display

tail -n +k
list lines starting with the kth first.

head -n -k
print all but last k lines

[转载]Fclk Hclk Pclk

s3c2410有两个pll,其中一个是MPLL,M即为main,用来产生三种时钟信号:Fclk(给CPU核供给时钟信号,我们所说的s3c2410的cpu主频为200MHz,就是指的这个时钟信号,相应的,1/Fclk即为cpu时钟周期)、Hclk(为AHB bus peripherals供给时钟信号,AHB为advanced high-performance bus)、Pclk(为APB bus peripherals供给时钟信号,APB为advanced peripherals bus)。

2010年9月13日星期一

[转载]: () { : | : & } ; :


我们这两天监测到一位客户的 VPS 持续维持 100% 的 CPU 利用率很长一段时间,然后昨天客户向我们报告他的 VPS 无法登录了,从我们这边来看他的 VPS 正在运行,而且网络也有反应,只不过 CPU 利用率满负荷而已,VPSee 收到客户消息的第一反应是客户的 VPS 被 CC (Challenge Collapsar) 攻击了,后来客户告诉我们他没有做网站,只是开了一些 shell 帐号供别人通过 ssh 使用,这有可能是其中某个帐号(被黑了以后)放了 fork 炸弹,这是非常简单而且很常用的一类恶意程序,原理很简单,就是通过不停的 fork 进程来达到消耗 Linux 系统所有资源的目的,使得系统无法(没有资源)运行其他程序。比如被 fork 炸了以后,就会出现:
-bash: fork: retry: Resource temporarily unavailable
下面就是一个最简单的 bash fork 炸弹:
: () { : | : & } ; :
上面几个符号看上去很复杂,其实如果写成下面这个样子就好懂了,: 是函数名,执行一个调用自己的递归并且 pipe 到自己,& 表示后台执行程序,最后的一个 : 是在函数外调用和执行 : () 这个函数的意思:
: () {
    : | : &
}; :
如何避免 fork 炸弹呢?方法很简单,只要限制每个用户可以调用的进程数就可以避免,这个可以通过修改 vi /etc/security/limits.conf 文件来设定:
# vi /etc/security/limits.conf

vpsee           hard    nproc           32
@student        hard    nproc           32
@faculty        hard    nproc           64
上面的配置文件意思是说限制 vpsee 这个用户只能 fork 32 个进程;然后限制 student 这个用户组的每个成员最多能 fork 32 个进程;限制 faculty 这个用户组的每个成员最多能 fork 64 个进程。不过要事先检查系统是否有 pam_limits.so 这个模块以及是否已经加载:
# ls /lib64/security/pam_limits.so
/lib64/security/pam_limits.so

# vi /etc/pam.d/login
session    required     pam_loginuid.so
如果自己是 Linux 普通用户,不是 root 用户不能修改 limits.conf 和重启系统的话,可以用 ulimit 来临时限制自己允许创建的进程数,ulimit 有 Hard 和 Soft 两种方法限制,用 Hard 的话可以减少最大可用的进程数,但是就不能重新增大这个限制了;用 Soft 的话可以自己自由增大和减小限制(ulimit,-H 和 -S 的详细说明可以参看 man ulimit)。不同的 Linux 版本对这个 ulimit -u 的默认值不同,在 CentOS 上默认情况下最大运行进程数是 8256,在 Fedora 上是 1024,所以这个要看不同的发行版本,不过这个无所谓,反正可以改,不过改成32后就不能再改成比32更大的了(比如64),只能再改成比32小的,ulimit 不带 -H 和 -S 参数的时候同时设置 Hard 和 Soft:
$ ulimit -u
8256
$ ulimit -u 32
$ ulimit -u 64
-bash: ulimit: max user processes: cannot modify limit: Operation not permitted

$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 8256
max locked memory       (kbytes, -l) 32
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 32
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

2010年9月12日星期日

Build Mplayer for arm Linux


Build Mplayer for arm(s3c2440) Linux:


1.download the source file and uncompress it to the sysapps directory:

2.run the configure:
./configure \
--prefix=${PRJROOT}/rootfs/usr \
--target=arm-unknown-linux \
--cc=arm-linux-gcc \
--host-cc=gcc \
--as=arm-linux-as \
--enable-fbdev \
--disable-largefiles \
--disable-md5sum \
--disable-pnm \
--disable-tga \
--disable-vcd \
--disable-bluray \
--disable-dvdnav \
--disable-dvdread \
--disable-dvdread-internal \
--disable-libdvdcss-internal \
--enable-menu \
--disable-libmpeg2 \
--disable-libmpeg2-internal \
--disable-liba52 \
--disable-ftp \
--disable-tv \
--disable-networking \
--disable-inet6 \
--disable-mmx \
--disable-mmxext \
--disable-3dnow \
--disable-3dnowext \
--disable-sse \
--disable-sse2 \
--disable-ssse3 \
--disable-shm \
--disable-altivec \
--disable-armv5te \
--disable-armv6 \
--disable-iwmmxt \
--disable-fastmemcpy \
--disable-dynamic-plugins \
--language=en \
--enable-static

#for more information, you can type the “./configure –help”
#accoarding to the configure above, the mplay will install in the directory rootfs/usr
#since in my arm-linux-gcc configure, I don't enable large file support, so –disable-largefiles option must be used.
#option –disable-libmpeg2-internal must be add, because s3c2410 cpu does not support arm pld instruction.
#the end of the –prefix must not have “/”, else install will fail.

3, run make and make install

error:
make[1]: Entering directory `/home/oneyoung/project/sysapps/mplayer-export-2010-09-11/libavcodec'
CC 4xm.o
{standard input}: Assembler messages:
{standard input}:478: Error: no such instruction: `eor %edx,%eax,%eax,ror'
{standard input}:479: Error: no such instruction: `bic %edx,%edx,'
{standard input}:480: Error: suffix or operands invalid for `mov'
{standard input}:481: Error: no such instruction: `eor %eax,%eax,%edx,lsr'
{standard input}:1670: Error: no such instruction: `eor %eax,%ebx,%ebx,ror'
{standard input}:1671: Error: no such instruction: `bic %eax,%eax,'
{standard input}:1672: Error: suffix or operands invalid for `mov'
{standard input}:1673: Error: no such instruction: `eor %ebx,%ebx,%eax,lsr'
{standard input}:1685: Error: no such instruction: `eor %edx,%eax,%eax,ror'
{standard input}:1686: Error: no such instruction: `bic %edx,%edx,'
{standard input}:1687: Error: suffix or operands invalid for `mov'
{standard input}:1688: Error: no such instruction: `eor %eax,%eax,%edx,lsr'
{standard input}:2110: Error: no such instruction: `eor %eax,%ebx,%ebx,ror'
{standard input}:2111: Error: no such instruction: `bic %eax,%eax,'
{standard input}:2112: Error: suffix or operands invalid for `mov'
{standard input}:2113: Error: no such instruction: `eor %ebx,%ebx,%eax,lsr'
{standard input}:2125: Error: no such instruction: `eor %edx,%eax,%eax,ror'
{standard input}:2126: Error: no such instruction: `bic %edx,%edx,'
{standard input}:2127: Error: suffix or operands invalid for `mov'
{standard input}:2128: Error: no such instruction: `eor %eax,%eax,%edx,lsr'
{standard input}:2200: Error: no such instruction: `eor %eax,%ebx,%ebx,ror'
{standard input}:2201: Error: no such instruction: `bic %eax,%eax,'
{standard input}:2202: Error: suffix or operands invalid for `mov'
{standard input}:2203: Error: no such instruction: `eor %ebx,%ebx,%eax,lsr'
{standard input}:2215: Error: no such instruction: `eor %edx,%eax,%eax,ror'
{standard input}:2216: Error: no such instruction: `bic %edx,%edx,'
{standard input}:2217: Error: suffix or operands invalid for `mov'
{standard input}:2218: Error: no such instruction: `eor %eax,%eax,%edx,lsr'
{standard input}:2280: Error: no such instruction: `eor %edx,%eax,%eax,ror'
{standard input}:2281: Error: no such instruction: `bic %edx,%edx,'
{standard input}:2282: Error: suffix or operands invalid for `mov'
{standard input}:2283: Error: no such instruction: `eor %eax,%eax,%edx,lsr'
{standard input}:2318: Error: no such instruction: `eor %edx,%eax,%eax,ror'
{standard input}:2319: Error: no such instruction: `bic %edx,%edx,'
{standard input}:2320: Error: suffix or operands invalid for `mov'
{standard input}:2321: Error: no such instruction: `eor %eax,%eax,%edx,lsr'
{standard input}:2364: Error: no such instruction: `eor %edx,%eax,%eax,ror'
{standard input}:2365: Error: no such instruction: `bic %edx,%edx,'
{standard input}:2366: Error: suffix or operands invalid for `mov'
{standard input}:2367: Error: no such instruction: `eor %eax,%eax,%edx,lsr'
{standard input}:2428: Error: no such instruction: `eor %edx,%eax,%eax,ror'
{standard input}:2429: Error: no such instruction: `bic %edx,%edx,'
{standard input}:2430: Error: suffix or operands invalid for `mov'
{standard input}:2431: Error: no such instruction: `eor %eax,%eax,%edx,lsr'
{standard input}:2494: Error: no such instruction: `eor %edx,%eax,%eax,ror'
{standard input}:2495: Error: no such instruction: `bic %edx,%edx,'
{standard input}:2496: Error: suffix or operands invalid for `mov'
{standard input}:2497: Error: no such instruction: `eor %eax,%eax,%edx,lsr'
{standard input}:2532: Error: no such instruction: `eor %edx,%eax,%eax,ror'
{standard input}:2533: Error: no such instruction: `bic %edx,%edx,'
{standard input}:2534: Error: suffix or operands invalid for `mov'
{standard input}:2535: Error: no such instruction: `eor %eax,%eax,%edx,lsr'
{standard input}:2578: Error: no such instruction: `eor %edx,%eax,%eax,ror'
{standard input}:2579: Error: no such instruction: `bic %edx,%edx,'
{standard input}:2580: Error: suffix or operands invalid for `mov'
{standard input}:2581: Error: no such instruction: `eor %eax,%eax,%edx,lsr'
{standard input}:2638: Error: no such instruction: `eor %edx,%eax,%eax,ror'
{standard input}:2639: Error: no such instruction: `bic %edx,%edx,'
{standard input}:2640: Error: suffix or operands invalid for `mov'
{standard input}:2641: Error: no such instruction: `eor %eax,%eax,%edx,lsr'
{standard input}:2898: Error: no such instruction: `eor %edx,%eax,%eax,ror'
{standard input}:2899: Error: no such instruction: `bic %edx,%edx,'
{standard input}:2900: Error: suffix or operands invalid for `mov'
{standard input}:2901: Error: no such instruction: `eor %eax,%eax,%edx,lsr'
{standard input}:2936: Error: no such instruction: `eor %edx,%eax,%eax,ror'
{standard input}:2937: Error: no such instruction: `bic %edx,%edx,'
{standard input}:2938: Error: suffix or operands invalid for `mov'
{standard input}:2939: Error: no such instruction: `eor %eax,%eax,%edx,lsr'
{standard input}:2982: Error: no such instruction: `eor %edx,%eax,%eax,ror'
{standard input}:2983: Error: no such instruction: `bic %edx,%edx,'
{standard input}:2984: Error: suffix or operands invalid for `mov'
{standard input}:2985: Error: no such instruction: `eor %eax,%eax,%edx,lsr'
make[1]: *** [4xm.o] Error 1
make[1]: Leaving directory `/home/oneyoung/project/sysapps/mplayer-export-2010-09-11/libavcodec'
make: *** [libavcodec/libavcodec.a] 错误 2

--it seems that something wrong with cpu type config, so re comfigure with the opton –target=arm-unknown-linux
--target=arm-armv4l-linux这个参数要注意的是一个分三部分,第一部分的arm是指arch,这里设定为arm;第二部分的armv4l是指具体的版本,这个要注意了,一定要跟libavcodec目录下的平台目录名一致,否则为这个平台的优化代码没办法编译进去(据我观察是这样的^_@ );第三部分是系统平台。
--this way doesn't work , try another option –disable-mencoder
disable MEncoder (A/V encoder) compilation
also does not work alright.

After I google the `eor %edx,%eax,%eax,ror', I found that it was x86 insruction.
So … FUCK ! I forget to export arm-linux-gcc path. What a shame!

Error:
mp_fifo.o: could not read symbols: File in wrong format
--recompile mp_fifo.o
make –new-file=fifo.c
--another file has the same error. Maybe it was because I recompile with make -o Makefile, and after I change configure, some file do not re-compile again. So run make clean and then run make, this problem solved. :)

error:
libmpdemux/mp_taglists.o:(.rodata+0x0): undefined reference to `ff_codec_wav_tags'
libmpdemux/mp_taglists.o:(.rodata+0x14): undefined reference to `ff_codec_bmp_tags'
collect2: ld returned 1 exit status
--open the file libmpdemux/mp_taglists.c and remove the “ff_” prefix from both reference.
I try this way, but it does not work.

--take a close look at the error. I seems that ff_codec_wav_tags and ff_codec_bmp_tags have not been defined. I search the google, and find that the two structure are defined in libavformat/riff.c
, but during the configure, we just disable it. So we remove the option --disable-libavformat_a --disable-libavformat_so .

Error:
when running make install, the error below occurs.

strip: Unable to recognise the format of the input file `/home/oneyoung/project/rootfs/usr/bin/mencoder'

--the error occurs. Because that the file mencoder we compile is arm format, but the make script use install -s to accomplish strip task, install is a x86 version program, and can't not operate on arm execute file.
So we have some trick:
(1)first we “run make install -n” to get the command while make will run. And mine looks like below:
install -d /home/oneyoung/project/rootfs/usr/bin /home/oneyoung/project/rootfs/usr/etc/mplayer /home/oneyoung/project/rootfs/usr/lib
install -m 755 -s mencoder /home/oneyoung/project/rootfs/usr/bin
install -d /home/oneyoung/project/rootfs/usr/share/man/zh_CN/man1
install -m 644 DOCS/man/zh_CN/mplayer.1 /home/oneyoung/project/rootfs/usr/share/man/zh_CN/man1/
cd /home/oneyoung/project/rootfs/usr/share/man/zh_CN/man1 && ln -sf mplayer.1 mencoder.1
install -m 755 -s mplayer /home/oneyoung/project/rootfs/usr/bin

here we delete the install's “-s” option and add arm-linux-strip like below:
install -d /home/oneyoung/project/rootfs/usr/bin /home/oneyoung/project/rootfs/usr/etc/mplayer /home/oneyoung/project/rootfs/usr/lib
install -m 755 mencoder /home/oneyoung/project/rootfs/usr/bin
arm-linux-strip /home/oneyoung/project/rootfs/usr/bin/mencoder
install -d /home/oneyoung/project/rootfs/usr/share/man/zh_CN/man1
install -m 644 DOCS/man/zh_CN/mplayer.1 /home/oneyoung/project/rootfs/usr/share/man/zh_CN/man1/
cd /home/oneyoung/project/rootfs/usr/share/man/zh_CN/man1 && ln -sf mplayer.1 mencoder.1
cd -
install -m 755 mplayer /home/oneyoung/project/rootfs/usr/bin
arm-linux-strip mplayer /home/oneyoung/project/rootfs/usr/bin/mplayer

and past it to the terminal, and the install will be complete.


Test the mplayer:

fetch a movie and try to run “mplayer -nosound 1.avi”

and error occurs:
[swscaler @ 0x8d1fb0]No accelerated colorspace conversion found from yuv420p to.
[swscaler @ 0x8d1fb0]using unscaled yuv420p -> bgra special converter
VO: [fbdev] 320x240 => 320x240 BGRA
Can't put VSCREENINFO: Invalid argument

search the VSCREENINFO in the kernel source, and find that ioctl is define in the drivers/video/fbmem.c
1052        case FBIOPUT_VSCREENINFO:
1053                if (copy_from_user(&var, argp, sizeof(var)))
1054                        return -EFAULT;
1055                if (!lock_fb_info(info))
1056                        return -ENODEV;
1057                acquire_console_sem();
1058                info->flags |= FBINFO_MISC_USEREVENT;
1059                ret = fb_set_var(info, &var);
1060                info->flags &= ~FBINFO_MISC_USEREVENT;
1061                release_console_sem();
1062                unlock_fb_info(info);
1063                if (!ret && copy_to_user(argp, &var, sizeof(var)))
1064                        ret = -EFAULT;
1065                break;
maybe the problem laid in the frame buffer console, since I don't take care of fbcon, and just initialize the s3c2410fb.

--this is not working, since my fbcon works well.

After that, I have tried many methods, but still does not work. And one day, I refer to the mplayer manual, and find that there is another option -vo fbdev2 instead of -vo fbdev. Eventually it works!!!
just run “mplayer -nosound -vo fbdev2 4.avi”

2010年9月11日星期六

ubuntu 鼠标暂时失灵

今天直接在nautilus里直接拖拽影片到totem时,突然totem卡住了,
然后鼠标也悲剧了,只能移动,点击都没用,图标也变成拖拽是的指针。

通常这种情况重启一下就行了,当时freerapid正在下东西,这时重启肯定悲剧了 T.T
那就死马当活马医,还好这时键盘还可以用,用快捷健开个terminal

先把totem挂掉再说,sudo killall totem
之后鼠标还是不能点击,
一不做二不休,干脆也把nautilus也挂掉
之后就恢复正常了 ^_^

2010年9月10日星期五

[转载]嵌入式系统入门书籍推荐

-C编程语言
Kernighan&  Ritchie 著.《C程序设计语言》(第二版)
-计算机综述
Bryant&  O’Hallaron 著.《深入理解计算机系统》
-Shell编程
David Tansley著.《LINUX与UNIX shell编程指南》
-Unix编程
W.Richard Stevens 等著,《Unix 环境高级编程 》(第二版)
-计算机网络及编程
Andrew S.Tanenbaum,Vrije Universiteit,Amsterdam,The Netherlands, 计算机网络
(第4版)
W.Richard Stevens 等著,《Unix 网络编程》(第三版)
-Linux内核
Daniel P.Bovet,Marco Cesati,深入理解Linux内核(第三版)
ROBERT LOVE, LINUX内核设计与实现(第2版)
-Linux设备驱动
Jonathan Corbet, Alessandro Rubini, Greg Kroan-Hartman.Linux设备驱动(第三版
).
Sreekrishnan Venkateswaran,精通Linux 设备驱动程序开发
-嵌入式Linux
Christopher Hallinan. Embedded Linux Primer: A Practical, Real-World Approach
-图像与视频
Gonzalez 等著,数字图像处理(第二版)
Yao Wang 等著,视频处理与通信 

s3c2410 touchscreen 驱动分析

 linux/drivers/input/touchscreen/s3c2410_ts.c
大体工作过程:
在probe中通过platform_get_irq 将touchscreen的中断源注册好,并和stylus_irq绑定
当触摸版被按下是,触法中断,调用stylus_irq --> s3c_adc_start 激活采样队列
adc采样完成后,会引发s3c_adc_irq 中断
s3c_adc_irq -->s3c24xx_ts_select --> select =1 -->continue
=0 -->mod_timer -->touch_timer --> touch_timer_fire
  26#include <linux/errno.h>
  27#include <linux/kernel.h>
  28#include <linux/module.h>
  29#include <linux/gpio.h>
  30#include <linux/input.h>
  31#include <linux/init.h>
  32#include <linux/delay.h>
  33#include <linux/interrupt.h>
  34#include <linux/platform_device.h>
  35#include <linux/clk.h>
  36#include <linux/io.h>
  37
  38#include <plat/adc.h>
  39#include <plat/regs-adc.h>
  40#include <plat/ts.h>
  41
  42#define TSC_SLEEP  (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0))
  43
  44#define INT_DOWN        (0)
  45#define INT_UP          (1 << 8)
  46
  47#define WAIT4INT        (S3C2410_ADCTSC_YM_SEN | \
  48                         S3C2410_ADCTSC_YP_SEN | \
  49                         S3C2410_ADCTSC_XP_SEN | \
  50                         S3C2410_ADCTSC_XY_PST(3))
  51
  52#define AUTOPST         (S3C2410_ADCTSC_YM_SEN | \
  53                         S3C2410_ADCTSC_YP_SEN | \
  54                         S3C2410_ADCTSC_XP_SEN | \
  55                         S3C2410_ADCTSC_AUTO_PST | \
  56                         S3C2410_ADCTSC_XY_PST(0))
  57
  58#define FEAT_PEN_IRQ    (1 << 0)        /* HAS ADCCLRINTPNDNUP */
  59
struct s3c2410ts  ---触摸板核心数据结构
  60/* Per-touchscreen data. */
  61
  62/**
  63 * struct s3c2410ts - driver touchscreen state.
  64 * @client: The ADC client we registered with the core driver.
  65 * @dev: The device we are bound to.
  66 * @input: The input device we registered with the input subsystem.
  67 * @clock: The clock for the adc.
  68 * @io: Pointer to the IO base.
  69 * @xp: The accumulated X position data.
  70 * @yp: The accumulated Y position data.
  71 * @irq_tc: The interrupt number for pen up/down interrupt
  72 * @count: The number of samples collected.
  73 * @shift: The log2 of the maximum count to read in one go.
  74 * @features: The features supported by the TSADC MOdule.
  75 */
  76struct s3c2410ts {
  77        struct s3c_adc_client *client;
  78        struct device *dev;
  79        struct input_dev *input;
  80        struct clk *clock;
  81        void __iomem *io;
  82        unsigned long xp;
  83        unsigned long yp;
  84        int irq_tc;
  85        int count;
  86        int shift;
  87        int features;
  88};
  89
  90static struct s3c2410ts ts;
  91
  92/**
  93 * get_down - return the down state of the pen
  94 * @data0: The data read from ADCDAT0 register.
  95 * @data1: The data read from ADCDAT1 register.
  96 *
  97 * Return non-zero if both readings show that the pen is down.
  98 */
判断触摸板是否被按下
  99static inline bool get_down(unsigned long data0, unsigned long data1)
 100{
 101        /* returns true if both data values show stylus down */
 102        return (!(data0 & S3C2410_ADCDAT0_UPDOWN) &&
 103                !(data1 & S3C2410_ADCDAT0_UPDOWN)); //s3c2410 的ADCDATA0和ADCDATA1的第8位是判断是否有被按下的寄存器
 104}
 105
 106static void touch_timer_fire(unsigned long data)
 107{
 108        unsigned long data0;
 109        unsigned long data1;
 110        bool down;
 111
 112        data0 = readl(ts.io + S3C2410_ADCDAT0);
 113        data1 = readl(ts.io + S3C2410_ADCDAT1);
 114
 115        down = get_down(data0, data1);
 116
 117        if (down) {
 118                if (ts.count == (1 << ts.shift)) { //再次判断是否完全转化完
 119                     
用移位的方法求平均值 
ts.xp >>= ts.shift;
 120                        ts.yp >>= ts.shift;
 121
 122                        dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n",
 123                                __func__, ts.xp, ts.yp, ts.count);
 124                       向input core报告
 125                        input_report_abs(ts.input, ABS_X, ts.xp);
 126                        input_report_abs(ts.input, ABS_Y, ts.yp);
 127
 128                        input_report_key(ts.input, BTN_TOUCH, 1);
 129                        input_sync(ts.input);
 130
 131                        ts.xp = 0;
 132                        ts.yp = 0;
 133                        ts.count = 0;
 134                }
 135               因为触摸板还是被按着的,继续安排采样
 136                s3c_adc_start(ts.client, 0, 1 << ts.shift);
 137        } else {
   down=0是表示触摸板已被释放
 138                ts.xp = 0;
 139                ts.yp = 0;
 140                ts.count = 0;
 141
 142                input_report_key(ts.input, BTN_TOUCH, 0);
 143                input_sync(ts.input);
 144
 145                writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
 146        }
 147}
 148
初始化一个定时器,toch_timer_fire绑定,在后面会用到
 149static DEFINE_TIMER(touch_timer, touch_timer_fire, 0, 0);
 150
 151/**
 152 * stylus_irq - touchscreen stylus event interrupt
 153 * @irq: The interrupt number
 154 * @dev_id: The device ID.
 155 *
 156 * Called when the IRQ_TC is fired for a pen up or down event.
 157 */
       interrupt handler,为input system的中断用
 158static irqreturn_t stylus_irq(int irq, void *dev_id)
 159{
 160        unsigned long data0;
 161        unsigned long data1;
 162        bool down;
 163
 164        data0 = readl(ts.io + S3C2410_ADCDAT0);
 165        data1 = readl(ts.io + S3C2410_ADCDAT1);
 166
 167        down = get_down(data0, data1);
 168
 169        /* TODO we should never get an interrupt with down set while
 170         * the timer is running, but maybe we ought to verify that the
 171         * timer isn't running anyways. */
 172
             s3c_adc_start -- 加入adc采样队列,开始采样
              采用的是多次采样的方法,采样次数为2的ts.shift次方
 173        if (down)
 174                s3c_adc_start(ts.client, 0, 1 << ts.shift);
 175        else
 176                dev_dbg(ts.dev, "%s: count=%d\n", __func__, ts.count);
 177
 178        if (ts.features & FEAT_PEN_IRQ) {
 179                /* Clear pen down/up interrupt */
 180                writel(0x0, ts.io + S3C64XX_ADCCLRINTPNDNUP);
 181        }
 182
 183        return IRQ_HANDLED;
 184}
 185
    
以下2个函数: s3c24xx_ts_conversion 和 s3c24xx_ts_select是为注册adc要用到的
 186/**
 187 * s3c24xx_ts_conversion - ADC conversion callback
 188 * @client: The client that was registered with the ADC core.
 189 * @data0: The reading from ADCDAT0.
 190 * @data1: The reading from ADCDAT1.
 191 * @left: The number of samples left.
 192 *
 193 * Called when a conversion has finished.
 194 */
 195static void s3c24xx_ts_conversion(struct s3c_adc_client *client,
 196                                  unsigned data0, unsigned data1,
 197                                  unsigned *left)
 198{
 199        dev_dbg(ts.dev, "%s: %d,%d\n", __func__, data0, data1);
 200
       驱动采用的是多次采样,然后求平均的方法来获取ADC 转换的数据,因此,每次转换完后先把数据累加起来
 201        ts.xp += data0;
 202        ts.yp += data1;
 203
 204        ts.count++;
 205
 206        /* From tests, it seems that it is unlikely to get a pen-up
 207         * event during the conversion process which means we can
 208         * ignore any pen-up events with less than the requisite
 209         * count done.
 210         *
 211         * In several thousand conversions, no pen-ups where detected
 212         * before count completed.
 213         */
 214}
 215
 216/**
 217 * s3c24xx_ts_select - ADC selection callback.
 218 * @client: The client that was registered with the ADC core.
 219 * @select: The reason for select.
 220 *
 221 * Called when the ADC core selects (or deslects) us as a client.
 222 */
 223static void s3c24xx_ts_select(struct s3c_adc_client *client, unsigned select)
 224{
当select为1时,继续采样;当select为0时,完成采样,并通过定时器调用touch_timer_fire()
 225        if (select) {
 226                writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
 227                       ts.io + S3C2410_ADCTSC);
 228        } else {
 229                mod_timer(&touch_timer, jiffies+1); //通过定时器的方法,jiffies+1实际上是立即安排定时器执行,调用touch_timer_fire 函数
 230                writel(WAIT4INT | INT_UP, ts.io + S3C2410_ADCTSC);
 231        }
 232}
 233
 234/**
 235 * s3c2410ts_probe - device core probe entry point
 236 * @pdev: The device we are being bound to.
 237 *
 238 * Initialise, find and allocate any resources we need to run and then
 239 * register with the ADC and input systems.
 240 */
 241static int __devinit s3c2410ts_probe(struct platform_device *pdev)
 242{
 243        struct s3c2410_ts_mach_info *info;
 244        struct device *dev = &pdev->dev;
 245        struct input_dev *input_dev;
 246        struct resource *res;
 247        int ret = -EINVAL;
 248
 249        /* Initialise input stuff */
 250        memset(&ts, 0, sizeof(struct s3c2410ts));
 251
 252        ts.dev = dev;
 253
 254        info = pdev->dev.platform_data;
 255        if (!info) {
 256                dev_err(dev, "no platform data, cannot attach\n");
 257                return -EINVAL;
 258        }
 259
 260        dev_dbg(dev, "initialising touchscreen\n");
 261
 262        ts.clock = clk_get(dev, "adc");
 263        if (IS_ERR(ts.clock)) {
 264                dev_err(dev, "cannot get adc clock source\n");
 265                return -ENOENT;
 266        }
 267
 268        clk_enable(ts.clock);
 269        dev_dbg(dev, "got and enabled clocks\n");
 270
             platform_get_irq --> platform_get_resource 通过这个调用,从device的struct resource中获得中断源
 271        ts.irq_tc = ret = platform_get_irq(pdev, 0);
 272        if (ret < 0) {
 273                dev_err(dev, "no resource for interrupt\n");
 274                goto err_clk;
 275        }
 276
 277        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 278        if (!res) {
 279                dev_err(dev, "no resource for registers\n");
 280                ret = -ENOENT;
 281                goto err_clk;
 282        }
 283
 284        ts.io = ioremap(res->start, resource_size(res));
 285        if (ts.io == NULL) {
 286                dev_err(dev, "cannot map registers\n");
 287                ret = -ENOMEM;
 288                goto err_clk;
 289        }
 290
 291        /* inititalise the gpio */
 292        if (info->cfg_gpio)
 293                info->cfg_gpio(to_platform_device(ts.dev));
 294
 295        ts.client = s3c_adc_register(pdev, s3c24xx_ts_select,
 296                                     s3c24xx_ts_conversion, 1);
 297        if (IS_ERR(ts.client)) {
 298                dev_err(dev, "failed to register adc client\n");
 299                ret = PTR_ERR(ts.client);
 300                goto err_iomap;
 301        }
 302
 303        /* Initialise registers */
 304        if ((info->delay & 0xffff) > 0)
 305                writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY);
 306
 307        writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
 308
 309        input_dev = input_allocate_device();
 310        if (!input_dev) {
 311                dev_err(dev, "Unable to allocate the input device !!\n");
 312                ret = -ENOMEM;
 313                goto err_iomap;
 314        }
 315
 316        ts.input = input_dev;
 317        ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 318        ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
 319        input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0);
 320        input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0);
 321
 322        ts.input->name = "S3C24XX TouchScreen";
 323        ts.input->id.bustype = BUS_HOST;
 324        ts.input->id.vendor = 0xDEAD;
 325        ts.input->id.product = 0xBEEF;
 326        ts.input->id.version = 0x0102;
 327
 328        ts.shift = info->oversampling_shift;
 329        ts.features = platform_get_device_id(pdev)->driver_data;
 330
 331        ret = request_irq(ts.irq_tc, stylus_irq, IRQF_DISABLED,
 332                          "s3c2410_ts_pen", ts.input);
 333        if (ret) {
 334                dev_err(dev, "cannot get TC interrupt\n");
 335                goto err_inputdev;
 336        }
 337
 338        dev_info(dev, "driver attached, registering input device\n");
 339
 340        /* All went ok, so register to the input system */
 341        ret = input_register_device(ts.input);
 342        if (ret < 0) {
 343                dev_err(dev, "failed to register input device\n");
 344                ret = -EIO;
 345                goto err_tcirq;
 346        }
 347
 348        return 0;
 349
 350 err_tcirq:
 351        free_irq(ts.irq_tc, ts.input);
 352 err_inputdev:
 353        input_unregister_device(ts.input);
 354 err_iomap:
 355        iounmap(ts.io);
 356 err_clk:
 357        del_timer_sync(&touch_timer);
 358        clk_put(ts.clock);
 359        return ret;
 360}
 361
 362/**
 363 * s3c2410ts_remove - device core removal entry point
 364 * @pdev: The device we are being removed from.
 365 *
 366 * Free up our state ready to be removed.
 367 */
 368static int __devexit s3c2410ts_remove(struct platform_device *pdev)
 369{
 370        free_irq(ts.irq_tc, ts.input);
 371        del_timer_sync(&touch_timer);
 372
 373        clk_disable(ts.clock);
 374        clk_put(ts.clock);
 375
 376        input_unregister_device(ts.input);
 377        iounmap(ts.io);
 378
 379        return 0;
 380}
 381
 382#ifdef CONFIG_PM
 383static int s3c2410ts_suspend(struct device *dev)
 384{
 385        writel(TSC_SLEEP, ts.io + S3C2410_ADCTSC);
 386        disable_irq(ts.irq_tc);
 387        clk_disable(ts.clock);
 388
 389        return 0;
 390}
 391
 392static int s3c2410ts_resume(struct device *dev)
 393{
 394        struct platform_device *pdev = to_platform_device(dev);
 395        struct s3c2410_ts_mach_info *info = pdev->dev.platform_data;
 396
 397        clk_enable(ts.clock);
 398        enable_irq(ts.irq_tc);
 399
 400        /* Initialise registers */
 401        if ((info->delay & 0xffff) > 0)
 402                writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY);
 403
 404        writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
 405
 406        return 0;
 407}
 408
 409static struct dev_pm_ops s3c_ts_pmops = {
 410        .suspend        = s3c2410ts_suspend,
 411        .resume         = s3c2410ts_resume,
 412};
 413#endif
 414
 415static struct platform_device_id s3cts_driver_ids[] = {
 416        { "s3c2410-ts", 0 },
 417        { "s3c2440-ts", 0 },
 418        { "s3c64xx-ts", FEAT_PEN_IRQ },
 419        { }
 420};
 421MODULE_DEVICE_TABLE(platform, s3cts_driver_ids);
 422
 423static struct platform_driver s3c_ts_driver = {
 424        .driver         = {
 425                .name   = "samsung-ts",
 426                .owner  = THIS_MODULE,
 427#ifdef CONFIG_PM
 428                .pm     = &s3c_ts_pmops,
 429#endif
 430        },
 431        .id_table       = s3cts_driver_ids,
 432        .probe          = s3c2410ts_probe,
 433        .remove         = __devexit_p(s3c2410ts_remove),
 434};
 435
 436static int __init s3c2410ts_init(void)
 437{
 438        return platform_driver_register(&s3c_ts_driver);
 439}
 440
 441static void __exit s3c2410ts_exit(void)
 442{
 443        platform_driver_unregister(&s3c_ts_driver);
 444}
 445
 446module_init(s3c2410ts_init);
 447module_exit(s3c2410ts_exit);
 448
 449MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, "
 450              "Ben Dooks <ben@simtec.co.uk>, "
 451              "Simtec Electronics <linux@simtec.co.uk>");
 452MODULE_DESCRIPTION("S3C24XX Touchscreen driver");
 453MODULE_LICENSE("GPL v2");
 454