Tuesday, April 28, 2009

Drivers en linux (II)

Ahora crearemos un dispositivo de caracteres en /dev/algo, para esto debemos definir cuatro nuevas funciones: para abrir y cerrar el dispositivo, y para leer y escribirlo. Hay mas operaciones, pero con esas es suficiente por ahora (http://www.linuxtopia.org/online_books/linux_kernel/linux_kernel_module_programming_2.6/x569.html).

El archivo test.h queda asi:

#ifndef _TEST_SPI_H_
#define _TEST_SPI_H_

#define DEVICE_NAME "test-spi"

MODULE_AUTHOR("Jorge Eduardo Cardona <jorgeecardona@gmail.com>");
MODULE_DESCRIPTION("SPI test driver.");
MODULE_LICENSE("GPL");

// Character device functions.
static int this_open(struct inode *inode, struct file *file);
static int this_release(struct inode *inode, struct file *file);
static ssize_t this_read(struct file *file, char __user *buffer, size_t len, loff_t *offset);
static ssize_t this_write(struct file *file, const char __user *buffer, size_t len, loff_t *offset);

// File Operations structure.
struct file_operations this_fops = {
.open = this_open,
.release = this_release,
.read = this_read,
.write = this_write
};

// Linux module functions.
static int __init this_init(void);
static void __exit this_exit(void);
module_init(this_init);
module_exit(this_exit);

#endif



Para crear el dispositivo de caracteres debemos llamar a la funcion: register_chrdev (http://kerneltrap.org/man/linux/man9/register_chrdev.9)(http://www.silicontao.com/ProgrammingGuide/GNU_function_list/register_chrdev.html)

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/err.h>


#include "test.h"

// Global data
static int this_major;


// Function that is called every time we try to open a device.
static int this_open(struct inode *inode, struct file *file)
{
printk(DEVICE_NAME": Open device.\n");
return 0;
}

// Function that is called when we close a device.
static int this_release(struct inode *inode, struct file *file)
{
printk(DEVICE_NAME": Close device.\n");
return 0;
}

// Function that is called when we read from a device.
static ssize_t this_read(struct file *file, char __user *buffer, size_t len, loff_t *offset)
{
printk(DEVICE_NAME": Read device.\n");
return 0;
}

// Function that is called when we write to a device.
static ssize_t this_write(struct file *file, const char __user *buffer, size_t len, loff_t *offset)
{
printk(DEVICE_NAME": Write device.\n");
return 0;
}

// Function that is called when we load the module.
static int __init this_init(void)
{
int ret;

printk(DEVICE_NAME ": Init.\n");

// Register char device: 0 for dynamically allocation of the major number.
ret = register_chrdev(0, DEVICE_NAME, &this_fops);
if (~IS_ERR_VALUE(ret))
{
printk(DEVICE_NAME ": Character device registered, with major=%d.\n",ret);
this_major = ret;

return 0;
}

unregister_chrdev(this_major, DEVICE_NAME);
printk(DEVICE_NAME ": Character device unregistered.\n");

return ret;
}

// Function that is called when we remove the module.
static void __exit this_exit(void)
{
unregister_chrdev(this_major, DEVICE_NAME);
printk(DEVICE_NAME ": Character device unregistered.\n");
printk(DEVICE_NAME ": Exit.\n");
}

(http://tomoyo.sourceforge.jp/cgi-bin/lxr/ident?i=IS_ERR_VALUE)

Bueno, igual que antes, configuramos, compilamos y tenemos:

root@gumstix-custom-connex:~$ modprobe test
root@gumstix-custom-connex:~$ dmesg | grep "test-spi"
<4>test-spi: Init.
<4>test-spi: Character device registered, with major=254.
root@gumstix-custom-connex:~$ mknod /dev/test c 254 0
root@gumstix-custom-connex:~$ cat /dev/test
root@gumstix-custom-connex:~$ dd bs=1 count=0 if=/dev/zero of=/dev/test
0+0 records in
0+0 records out
root@gumstix-custom-connex:~$ echo "ja" > /dev/test

root@gumstix-custom-connex:~$ rmmod test
root@gumstix-custom-connex:~$ dmesg | grep "test-spi"
<4>test-spi: Init.
<4>test-spi: Character device registered, with major=254.
<4>test-spi: Open device.
<4>test-spi: Read device.
<4>test-spi: Close device.
<4>test-spi: Open device.
<4>test-spi: Close device.
<4>test-spi: Open device.
<4>test-spi: Write device.
<4>test-spi: Write device.
<4>test-spi: Write device.
<4>test-spi: Write device.
<4>test-spi: Write device.
<4>test-spi: Write device.
<4>test-spi: Write device.
<4>test-spi: Write device.
<4>test-spi: Write device.
<4>test-spi: Write device.
<4>test-spi: Close device.
<4>test-spi: Character device unregistered.
<4>test-spi: Exit.
root@gumstix-custom-connex:~$


Los varios mensajes de Write se deben a que retornamos 0 esto quiere decir que no escribimos ningun caracter y la funcion es llamada hasta que vacie el buffer, pero aqui toca matarla con un Ctrl-C.

Bueno, un paso mas.

Drivers en linux (I)

Bueno iba a hacer esto en un solo post pero por partes es mejor, primero lo básico, cargar y bajar el modulo. En mi caso necesito un modulo para SPI, entonces lo ubico en drivers/spi/test.c

Comenzando con lo basico, entrar y bajar el modulo.

test.c

#include <linux/module.h>
#include "test.h"

static int __init this_init(void)
{
// Initialize module.

printk(DEVICE_NAME ": Init.\n");
}

static void __exit this_exit(void)
{
// Exit module.

printk(DEVICE_NAME ": Exit.\n");
}


test.h

#ifndef _TEST_SPI_H_
#define _TEST_SPI_H_

#define DEVICE_NAME "test-spi"

MODULE_AUTHOR("Jorge Eduardo Cardona <jorgeecardona@gmail.com>");
MODULE_DESCRIPTION("SPI test driver.");
MODULE_LICENSE("GPL");

// Linux module functions.
static int __init this_init(void);
static void __exit this_exit(void);
module_init(this_init);
module_exit(this_exit);

#endif


Tenemos que manipular dos archivos mas: Kconfig y Makefile, ambos en la misma carpeta:

Kconfig

.
.
.
config SPI_TEST
tristate "Test SPI driver."
depends on SPI_MASTER && EXPERIMENTAL
help
Test SPI driver.
.
.
.


Makefile

.
.
.
obj-$(CONFIG_SPI_TEST) += test.o
.
.
.


Al configurar el kernel nos saldra la opcion, la seleccionamos y podremos hacer esto:

root@gumstix-custom-connex:~$ modprobe test
root@gumstix-custom-connex:~$ dmesg | tail -n1
<4>; test-spi: Init.
root@gumstix-custom-connex:~$ rmmod test
root@gumstix-custom-connex:~$ dmesg | tail -n1
<4> test-spi: Exit.
root@gumstix-custom-connex:~$


Primer paso listo.

Wednesday, April 15, 2009

Contando racionales.

Un numero racional es todo aquel que puede ser escrito de la forma:

racional = a/b : siendo a y b numeros enteros.

Usando el metodo como Georg Ferdinand Ludwig Philipp Cantor demostro que los racionales son contables podemos crear un pequeñito programa para sacar el i-esimo racional de la tabla de cantor:


from math import sqrt

def rational(i):
b = int((sqrt(1+8*i)-1)/2)
n = i - (b**2 + b)/2 + 1
d = b + 2 - n

return (n,d)


for i in xrange(100):
(n,d) = rational(i)

print "(%d) %d/%d \t= %f"%(i,n,d,float(n)/float(d))



Bueno, La tabla de Cantor es sencilla, el numerador aumenta columna a columna desde 1 hasta aleph_0 y el denumenador fila a fila de 1 a aleph_0, de esta forma todos los nuemros racionales son cubiertos por la tabla, y por tanto son contables, se les puede asociar uno a uno un elemento de los enteros.

La tabla:

1/1 2/1 3/1 4/1 5/1 6/1 7/1 8/1 9/1 ...
1/2 2/2 3/2 4/2 5/2 6/2 7/2 8/2 9/2 ...
1/3 2/3 3/3 4/3 5/3 6/3 7/3 8/3 9/3 ...
1/4 2/4 3/4 4/4 5/4 6/4 7/4 8/4 9/4 ...
1/5 2/5 3/5 4/5 5/5 6/5 7/5 8/5 9/5 ...
1/6 2/6 3/6 4/6 5/6 6/6 7/6 8/6 9/6 ...
1/7 2/7 3/7 4/7 5/7 6/7 7/7 8/7 9/7 ...
1/8 2/8 3/8 4/8 5/8 6/8 7/8 8/8 9/8 ...
1/9 2/9 3/9 4/9 5/9 6/9 7/9 8/9 9/9 ...


Y el conteo:

0 2 5 9 14 20 27 35 44 ...
1 4 8 13 19 26 34 43 53 ...
3 7 12 18 25 33 42 52 ...
6 11 17 24 32 41 51 ...
10 16 23 31 40 50 ...
15 22 30 39 49 ...
21 29 38 48 ...
28 37 47 ...
36 46 ...
45 ...
...


Resultado de la ejecucion del codigo:

(0) 1/1 = 1.000000
(1) 1/2 = 0.500000
(2) 2/1 = 2.000000
(3) 1/3 = 0.333333
(4) 2/2 = 1.000000
(5) 3/1 = 3.000000
(6) 1/4 = 0.250000
(7) 2/3 = 0.666667
(8) 3/2 = 1.500000
(9) 4/1 = 4.000000
(10) 1/5 = 0.200000
(11) 2/4 = 0.500000
(12) 3/3 = 1.000000
(13) 4/2 = 2.000000
(14) 5/1 = 5.000000
(15) 1/6 = 0.166667
(16) 2/5 = 0.400000
(17) 3/4 = 0.750000
(18) 4/3 = 1.333333
(19) 5/2 = 2.500000
(20) 6/1 = 6.000000
(21) 1/7 = 0.142857
(22) 2/6 = 0.333333
(23) 3/5 = 0.600000
(24) 4/4 = 1.000000
(25) 5/3 = 1.666667
(26) 6/2 = 3.000000
(27) 7/1 = 7.000000
(28) 1/8 = 0.125000
(29) 2/7 = 0.285714
(30) 3/6 = 0.500000
(31) 4/5 = 0.800000
(32) 5/4 = 1.250000
(33) 6/3 = 2.000000
(34) 7/2 = 3.500000
(35) 8/1 = 8.000000
(36) 1/9 = 0.111111
(37) 2/8 = 0.250000
(38) 3/7 = 0.428571
(39) 4/6 = 0.666667
(40) 5/5 = 1.000000
(41) 6/4 = 1.500000
(42) 7/3 = 2.333333
(43) 8/2 = 4.000000
(44) 9/1 = 9.000000
(45) 1/10 = 0.100000
(46) 2/9 = 0.222222
(47) 3/8 = 0.375000
(48) 4/7 = 0.571429
(49) 5/6 = 0.833333
(50) 6/5 = 1.200000
(51) 7/4 = 1.750000
(52) 8/3 = 2.666667
(53) 9/2 = 4.500000
(54) 10/1 = 10.000000
(55) 1/11 = 0.090909
(56) 2/10 = 0.200000
(57) 3/9 = 0.333333
(58) 4/8 = 0.500000
(59) 5/7 = 0.714286
(60) 6/6 = 1.000000
(61) 7/5 = 1.400000
(62) 8/4 = 2.000000
(63) 9/3 = 3.000000
(64) 10/2 = 5.000000
(65) 11/1 = 11.000000
(66) 1/12 = 0.083333
(67) 2/11 = 0.181818
(68) 3/10 = 0.300000
(69) 4/9 = 0.444444
(70) 5/8 = 0.625000
(71) 6/7 = 0.857143
(72) 7/6 = 1.166667
(73) 8/5 = 1.600000
(74) 9/4 = 2.250000
(75) 10/3 = 3.333333
(76) 11/2 = 5.500000
(77) 12/1 = 12.000000
(78) 1/13 = 0.076923
(79) 2/12 = 0.166667
(80) 3/11 = 0.272727
(81) 4/10 = 0.400000
(82) 5/9 = 0.555556
(83) 6/8 = 0.750000
(84) 7/7 = 1.000000
(85) 8/6 = 1.333333
(86) 9/5 = 1.800000
(87) 10/4 = 2.500000
(88) 11/3 = 3.666667
(89) 12/2 = 6.000000
(90) 13/1 = 13.000000
(91) 1/14 = 0.071429
(92) 2/13 = 0.153846
(93) 3/12 = 0.250000
(94) 4/11 = 0.363636
(95) 5/10 = 0.500000
(96) 6/9 = 0.666667
(97) 7/8 = 0.875000
(98) 8/7 = 1.142857
(99) 9/6 = 1.500000