Monday, August 25, 2008

Linux Device Driver: Creates sysfs entry and generates uevents

Kernel APIs:

class_create — create a struct class structure
class_destroy — destroys a struct class structure
class_device_create — creates a class device and registers it with sysfs
class_device_destroy — removes a class device that was created with class_device_create

Sample Codes:

MMemory.c

/* Necessary includes for device drivers */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/proc_fs.h>
#include <linux/fcntl.h> /* O_ACCMODE */
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_from/to_user */
#include <linux/device.h> /* class_creatre */
#include <linux/cdev.h> /* cdev_init */
//---------------------------------------------------------------------------
#define DEVICE_NAME "memory"

MODULE_LICENSE("Dual BSD/GPL");

/* Declaration of memory.c functions */
int __init memory_init(void);
void __exit memory_exit(void);

int memory_open(struct inode *inode, struct file *filp);
int memory_release(struct inode *inode, struct file *filp);
ssize_t memory_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);
ssize_t memory_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos);

/* Structure that declares the usual file */
/* access functions */
struct file_operations memory_fops = {
.read = memory_read,
.write = memory_write,
.open = memory_open,
.release = memory_release
};

/* Global variables of the driver */

/* Buffer to store data */
char *memory_buffer;

struct class *memory_class = 0;
/*static*/ dev_t dev_num;
struct cdev cdev;
//---------------------------------------------------------------------------
int __init memory_init(void)
{
int result;

/* Registering device */
result = alloc_chrdev_region(&dev_num, 0, 0, DEVICE_NAME);
if (result < 0) {
printk( KERN_ALERT "memory: cannot register device\n");
return result;
}

/* Allocating memory for the buffer */
memory_buffer = kmalloc(1, GFP_KERNEL);
if (!memory_buffer) {
result = -ENOMEM;
goto fail;
}
memset(memory_buffer, 0, 1);

/* populate sysfs entry */
memory_class = class_create(THIS_MODULE, DEVICE_NAME);
/*connect the file operations with the cdev */
cdev_init(&cdev, &memory_fops);
cdev.owner = THIS_MODULE;
/* connect the major/minor number to the cdev */
if (cdev_add(&cdev, dev_num, 1)) {
printk(KERN_ALERT "Bad cdev\n");
return 1;
}

/* seend uevents to udev, so it'll create the /dev node*/
class_device_create(memory_class, NULL, dev_num, NULL, "memory%d", 1);

printk(KERN_ALERT "Inserting memory module\n");
return 0;

fail:
memory_exit();
return result;
}
//---------------------------------------------------------------------------
void __exit memory_exit(void)
{
/* remove the cdev*/
cdev_del(&cdev);

/* Freeing the major number */
unregister_chrdev_region(dev_num, 1);

class_device_destroy(memory_class, dev_num);

class_destroy(memory_class);

/* Freeing buffer memory */
if (memory_buffer) {
kfree(memory_buffer);
}

printk(KERN_ALERT "Removing memory module\n");
}
//---------------------------------------------------------------------------
int memory_open(struct inode *inode, struct file *filp)
{
/* Success */
return 0;
}
//---------------------------------------------------------------------------
int memory_release(struct inode *inode, struct file *filp)
{
/* Success */
return 0;
}
//---------------------------------------------------------------------------
ssize_t memory_read(struct file *filp, char *buf,
size_t count, loff_t *f_pos)
{
/* Transfering data to user space */
copy_to_user(buf,memory_buffer,1);

/* Changing reading position as best suits */
if (*f_pos == 0) {
*f_pos+=1;
return 1;
}
else {
return 0;
}
}
//---------------------------------------------------------------------------
ssize_t memory_write( struct file *filp, const char *buf,
size_t count, loff_t *f_pos)
{
const char *tmp;

tmp = buf + count - 1;
copy_from_user(memory_buffer, tmp, 1);

return 1;
}
//---------------------------------------------------------------------------
/* Declaration of the init and exit functions */
module_init(memory_init);
module_exit(memory_exit);

Makefile

obj-m := memory.o

KDIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

default:
$(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean

Sunday, December 23, 2007

A Tutorial on GNU gettext

“Hello world” example – hello.c

#include <stdio.h>
#include <locale.h>
#include <libintl.h>
int main()
{
setlocale(LC_ALL, "");
textdomain("hello");
bindtextdomain("hello", "locale");
printf(gettext("Hello, world !\n"));
return 0;
}

Compiling

gcc hello.c –c hello

Extracting translatable strings

xgettext -o hello.po hello.c

Translating

We will try to make a Chinese (zh_TW.UTF-8) translation

$ cat hello.po

# SOME DESCRIPTIVE TITLE.

# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER

# This file is distributed under the same license as the PACKAGE package.

# FIRST AUTHOR , YEAR.

#

#, fuzzy

msgid ""

msgstr ""

"Project-Id-Version: PACKAGE VERSION\n"

"Report-Msgid-Bugs-To: \n"

"POT-Creation-Date: 2007-12-23 13:10+0800\n"

"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"

"Last-Translator: FULL NAME \n"

"Language-Team: LANGUAGE \n"

"MIME-Version: 1.0\n"

"Content-Type: text/plain; charset=CHARSET\n"

"Content-Transfer-Encoding: 8bit\n"

#: hello.cpp:19

#, c-format

msgid "Hello, world!\n"

msgstr ""

modifies hello.po as following

# SOME DESCRIPTIVE TITLE.

# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER

# This file is distributed under the same license as the PACKAGE package.

# FIRST AUTHOR , YEAR.

#

#, fuzzy

msgid ""

msgstr ""

"Project-Id-Version: 1.0\n"

"Report-Msgid-Bugs-To: \n"

"POT-Creation-Date: 2007-12-23 13:10+0800\n"

"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"

"Last-Translator: FULL NAME \n"

"Language-Team: LANGUAGE \n"

"MIME-Version: 1.0\n"

"Content-Type: text/plain; charset=UTF-8\n"

"Content-Transfer-Encoding: 8bit\n"

#: hello.cpp:19

#, c-format

msgid "Hello, world!\n"

msgstr "大家好!\n"

builds the MO file

mkdir -p locale/zh_TW/LC_MESSAGES

msgfmt hello.po -o locale/zh_TW/LC_MESSAGES/hello.mo

Locale Environment variable

$ ./hello

Hello, world!

$ export LANG=zh_TW.UTF-8

$ ./hello

大家好!

Bibliography

1. GNU gettext

http://www.gnu.org/software/gettext/

2. A tutorial on Native Language Support using GNU gettext

http://oriya.sarovar.org/docs/gettext/

3. Gettext

http://www.haypocalc.com/wiki/Gettext

Saturday, December 22, 2007

Cygwin: list filename in chinese

edit ~/.bashrc to allow ls command to display filename in chinese
alias ls='ls -hF --show-control-chars --color=tty'

Tuesday, December 11, 2007

Using mod_python apache module on Windows

Installation (Python 2.5.1 + mod_python 3.3.1 + Apache 2.2.6)

1. Install Python 2.5.1

2. Install Apache 2.2.6

We choose to install the Apache server as a system service.

At the end of installation process, the installer will create default configuration files, the firewall software may block that action, we’d better to shutdown the firewall application before installing Apache

3. Install mod_python 3.3.1

At the end of installation process, the installer will ask you the Apache directory, then it will install mod_python.so to the APACHE_ROOT/modules directory

Configuring & Testing

We will use the default document root directory (APACHE_ROOT/htdocs)

1. Following the direction of mod_python manual, add following line to Apache configuration file (APACHE_ROOT/conf/httpd.conf)

LoadModule python_module libexec/mod_python.so

2. Add the following Apache directives,

AddHandler mod_python .py

PythonHandler mptest

PythonDebug On

3. This redirects all requests for URLs ending in .py to the mod_python handler

4. Restart Apache in order for the changes to take effect

Troubleshooting: Failed to restart apache server

Use Event Viewr to find out the problem:

In System Event say:

The Apache2.2 service terminated with service-specific error 1 (0x1).

In Application Event say:

Apache/conf/httpd.conf: Cannot load

Apache/modules/mod_python.so into server: The specified module could not be found.

From the python interpreter, we can import mod_python successfully, why? mod_python.so use python25.dll, and our user path variable already contain the Python directory; We start the Apache server as a system service, it will use the system path variable to find the import dll files; So we should add the Python directory to the system PATH variable

Edit mptest.py file in the APACHE_ROOT/htdocs directory so that is has the following lines

from mod_python import apache

def handler(req):

req.content_type = 'text/plain'

req.write("Hello World!")

return apache.OK

5. Point your browser to the URL referring to the mptest.py(for example, http://localhost/mptest.py); you should see "Hello World!".

Troubleshooting: No “Hello World!”

From APACHE_ROOT/log/error.log say:

[error] make_obcallback: could not import mod_python.apache.\n

[error] make_obcallback: Python path being used "['C:\\\\Python\\\\python25.zip', '.\\\\DLLs', '.\\\\lib', '.\\\\lib\\\\plat-win', '.\\\\lib\\\\lib-tk', 'C:\\\\Apache\\\\bin']".

[error] get_interpreter: no interpreter callback found.

[error] [client 127.0.0.1] python_handler: Can't get/create interpreter.

Apache server cann’t import mod_python.apache, we should add a PYTHONPATH system variable to contain the python modules path, for example, we can set it as following

C:\Python;C:\Python\DLLs;C:\Python\Lib;

C:\Python\Lib\lib-tk;C:\Python\Lib\site-packages

Thursday, August 9, 2007

"Ctrl+." Problem of SlickEdit 12.0.2

SlickEdit is one of the best programmer's editors, current version is v12.0.2.

There is an annoying bug of v12.0.2 while programming in C++ language
  • Some times, press "Ctrl+." (Go to Definition Of ...) on a symbol, only the corresponding header files are shown, but not the C++ source file with the function definition; this was casused by "using namespace ...;" in *.cpp/*.c source files
Solution:
  • define a using macro, set that macro in Tools > Options > Tagging Options > C Preprocessing

Thursday, April 12, 2007

pleas wait...