linux kernel programming - · pdf filelinux kernel programming by flyduck ˘ ˇˆ ˙˝ ˛...

169
Linux Kernel Programming v1.01

Upload: danganh

Post on 08-Feb-2018

237 views

Category:

Documents


1 download

TRANSCRIPT

�����

Linux Kernel Programmingv1.01

��� ��������� ��

������������ �������

�����������

�����

Linux Kernel Programmingby flyduck

����������������

�����������������

�������������� ����������������������������� ���!"#$

%&'� #�� ()*�� +,�� -.)�� #�� (/���� �� ��#$� 01 23� 4��56� 78�

9:� ���� ;��� �� ���� �� �� ��� <=:� >?@A� BCD'� �E#��� FG� ��

�'�H�I�4�#��JK��BJ#3�KL��M�N�����������!O�����PQ���R��

S6��TU�PQ���R��SVW��X��()*��YZ[�\]7�� �����\]�� ����\]^��_`�

\]���XW�a/�����b�cJd�<e�����fg� ;3��hi#;>�Qj����������c

Jd� ��� �'� >k)�� #�� ()*�� +,�� ����� �6�� l�Z�� #m/���� cJ-� no

ip�� (q7� rst)3� uv��� wx#;�� ip�� (�3� y� ��������������6$� z{'� c

|;3� �}v/���� ~�� BCd� z{�� cW� �;�� � � 78�� ���W6� (�� ���� $;�

'��JE|;>�Qj��������6�(��+,�� ���� !!��"��#$"#����!������ �������W

6���H���(/����������y��d� �������6$��E�()*��{i7�G�����@)���J

H����)*��G�������������$���H���(/���

����������� ��http://linuxkernel.to/������������ � ��http://flyduck.com/mailman/listinfo/linux-kernel

�����

��������

��� �

�������������� ���� ����������������������������� �!"�"!"��ftp://ftp.oreilly.com

#���$��������� ��������

�����%!�&!�'�(���)

��� �

*����+�����,��-��..��-�/���������,�.���01http://linuxdoc.org/LDP/lkmpg/mpg.html

#���$�*����+�����,��-��..��-�/���http://kldp.org/Translations/Kernel_Module_Programming_Guide

2��������/����0��3��4��-�05�������*�����,������ 0���� ��http://netfilter.kernelnotes.org/unreliable-guides/

�����

��

�6�������������

"6�������� � ��3�����7����

86�!������ � ��+�����9���"#���$����� ��

'6�%������ � ��+�����9���&�'�()���$����� ��

�6�*������ � ��:����+,-�.�/0

6�12������ � �����0��/034

&6��5�678

%6�-"9�:�;��<�7�=��>?�

!6�@2������ � ��-�.�A�B�C4

�(6�DEFG�H�

��6�3�I��J�

�"6�,K������ � ��+��������"#��LM����� ��

NO� �6�PQRJ� ��,;��S������ ��

NO� �6�TU� <�=

�����

�������������

! ��������VW� �

��X0��� � ��Y0$�?�#� ��.��$Z��[\3]����

��-�.�A�DE^��� ��X0��� Z_�����`�a�Jb3]�DE^��

����� ����%��c���>?��c����,;��+,-�.��*Gde������ ���f

��3�I�� ��;,2����+���7��*Gg��@h�ijklm

! ���� ��� �

��kla�no�p��1q]�r�GI�6

��s�3�I��D�klB�tu v�r�GI��D�kla�wm��1x�yv�z16

�����?�Z��{|}~��>?�Z��i3�����}���]16

������ ��a��3@�kla����� ��kla�+,H��1x�y�z16

��kla��B��P�����~�P�Z�� �����DE^��a��3@�kla�J��16

! kl��P�� �

���$�kl#�5����0�����$�����a��3���~�����~���y�z]�kl6

0�.������ ������:��������4��������.�� ��,;� :�4���>�� 0��4�� �������666

��LM�kl#����4����$�������-a���� �����3���kl�� ��� o��� B�31

#�����.���� $6�LM#��������3���+,-�.��V���y�z16

9��::���� 4��5������ 4����+��� 4��0�:��;����+��666

��*Gg�kl#�0?��4����$���*Gg����� y¡��y�z]�kl6

05��0�� ��:��:::

�����

! ���?¢#4����.����$��

������-�.�N£¤Z�[�p������¥�����y�z]�����V¦�r6

������1-�§+,3¨��-�.���N£3���~v�����,N©��ª«��y�z16

������ ����+,-�.��*Gg���¬A�f��?¢��wm�­16

! ?¢���� 9�,®�X0��� ��¯�� �

��main() °yB�±~���²�¥��-Z�³�]� 0��0�:�@������:�°yB�´µ�16

0��0�:���int init_module(void)¦b3¶� (��{�3¶���·��¸��¹º»16

�����:���void cleanup_module(void)������.������4��-��

�.������jy��°y��¼

�.�����.:��0���1½�¾Z�´µ3]� �.�����Y03]�¿

�.�����:��0���1½�¾Z��Y0��y�zvO� �.�����Jb3]�¿

�.����0������ �.���m��ÀO��B�~�z]� 0���

0�0��� ���4��-� ��§+,��3¶�� ���4�\Á��Â���16�?��ÃÄm�� � ��}��z4

Å�Z���$«��{|�B�316

����.��� ���4��-� �� �.���m�� ���4]�?¢������Å��16� �.:��0}]� �.���m��1

½�¾Z��Jb���i�Æ��16

?¢U�§+,w��3~�Ç7a�3���U� ��>�0�+,�È<�16

����9�ɵ�����?¢Z�� �:��03~�z]� �.���w��Y0��y�z16

�����

! ?¢������Z���i�YÊ� �

��9���0�5������-���?¢U���?�Z��[\3Ë��>?��o�Z�Ì���Í��ÎÏv�3���

p���?¢Z�� ÐÑ�� Zh]� -�.Z� lÒ��Ë�� >?�a�1x� Å� i�3~�� ��

°y�Ï�-Z]�®�-�ZhÓ�a�ÔY3~�Zha�H��Æ��16

��{y�ÕÖ��� ++)�Ò×U�Y0��y�±16�{y�ÕÖU��y�ÕÖp��Ì«3@�H�3

vO��16

�� ���� Y03]� �Ø� 74]� J�}�� z~� #"� :�-$�� DEFG� Ùmhv� [,�� �Ø�

Y03Ë���Ø��Ú��Y03¶�Û�16��ØZ�Ü�ÝÞ��)p¶�Û}~� #[�p���

ßàvO��1$������ �����Ú��,�����vO�i��16

�� 1½� áâã�� ~º�Æ� �16� ���]� @h� äåZ�� Y0æ� y� zpË�� 8"`G²� '

`G�äå9� ��0� �����f��?!�~ºa��Æ�3��� ;,2Z�ç���Ó�]�}vO�è�

vO��16

! ?¢�cé���� � �

��lsmod�������?¢��ÀO��Î@»16�#/proc/modules$��insmod������?¢�����16

��rmmod������?¢��¥���16

��depmod������?¢"���´¦��ÔY�16�#/lib/modules/*/modules.dep$��modprobe���?¢��Î1�êU�y»Z��1q]���� 6

�´¦Z�� ��ë���åì�1½�?¢������¥��a��16

��kerneld������?¢��'6�X0��� ��tí����îï���,P

��Z��?¢��ë�����Å�$[p��?¢����3~��ë�±��Å�¥���16

modprobe���� ���03@�����¥��a��16

�����

! ?¢�������cé���� � �

��ksyms����:��0}��z]�ɵ����� �.����ÀO��Î@»16�#/proc/ksyms$��gcc���/�2�;���.:���

��make�����ðG�c�Z�ñ0�� /�2�.�4��0���0�

��ld���/�2����4��#�������������0������>�0�9��$��nm�����>�0�9��Z�z]� �.���m��ÀO��Î@»16

��mknod������� :�����9����w�16

����

��� �������� ����������

! À�� ��?¢����3~�¥����Å�"#��>-�a���3]�?¢���� ��J\�16

! VÉ�òó� ��?¢������Å�³�]�°yD� init_module()Z�����>-�a���3]�°

yD� printk()a� �0� A3����� 7����A� �$Þ�� ���16� ?¢�� ¥���� Å� ³�]� °yD

cleanup_module()Z�]�ÂU�òóp�� A/�����A��$Þ�����16

! 6�G�òó� ��?¢����3~�¥����Å�>-�B�JÌ����}]��ôD�16

! 9�� �

��r����

��§+,� #gcc$��?¢����3~�õ9a�ö�¤�¥��34� #insmod��lsmod��rmmod$��+�49���Y034� #make$��r�a�!�������§+,34� #gcc��ld��make$���:��0��ÃÄ�ÀO��J�34

�����

! Filename : hello.c

/*Hello, World Module Program

*/

#include <linux/kernel.h>#include <linux/module.h>

#ifdef CONFIG_MODVERSIONS#define MODVERSIONS#include <linux/modversions.h>#endif

int init_module(void){

printk("<1>Hello, World\n");

return 0;}

void cleanup_module(void){

printk("<1>Goodbye\n");}

������

! Filename : hello_init.c

#include <linux/kernel.h>#include <linux/module.h>

#ifdef CONFIG_MODVERSIONS#define MODVERSIONS#include <linux/modversions.h>#endif

int init_module(void){

printk("<1>Hello, World\n");

return 0;}

! Filename : hello_cleanup.c

#define __NO_VERSION__#include <linux/kernel.h>#include <linux/module.h>

#ifdef CONFIG_MODVERSIONS#define MODVERSIONS#include <linux/modversions.h>#endif

void cleanup_module(void){

printk("<1>Goodbye\n");}

������

! Filename : Makefile (hello.c)

CC = gccCFLAGS = -D__KERNEL__ -DMODULE -O -Wall

OBJS = hello.o

all : $(OBJS)

clean :rm -f *.o *~

! Filename : Makefile2 (hello_init.c, hello_cleanup.c)

CC = gccLD = ldCFLAGS = -D__KERNEL__ -DMODULE -O -Wall

TARGET = hello.oOBJS = hello_init.o hello_cleanup.o

all : $(TARGET)

$(TARGET) : $(OBJS)$(LD) -r $^ -o $@

clean :rm -f *.o *~

������

! ?¢�§+,34� �

gcc -c -D__KERNEL__ -DMODULE -O hello.c

! make���� ���0��§+,� �

make� %&�>?� �'�#���#A� Makefile'��J#����{

make clean %&���{��":�'�,q#>

make -f Makefile2� %&���� �'�#���#'�BJH�I�BJH� �'�#���#����W�

! ?¢�÷l� �

insmod hello.o

! ����?¢�ÀO�Î4� �

lsmod

! ?¢�J¨� �

rmmod hello

! ?¢Z������>-��Î4� �

tail /var/log/messages� %&����z;W� >

tail -f /var/log/messages� %&����z;W����� �E��rs¡��z;W� >

������

! ?¢��ø��J� �

��?�� ?¢Z]� §+,����� �ø� �ÎB� m�BÆ� 3��� �]�ɵ� {|}~� z]� ��

�ø9�,l�Æ��16

��?¢Z��ø��Î�ù°-ú4� �

#include <linux/module.h>Z��$[p��?¢��ø��Îa��B�16

?¢��øU� char kernel_version[]�jy�����16

?¢� �ø� �Î]� ø«� ?¢Z�� 3�w� z�Æ� �16� r�B� @h�D� åì� 3��

r�Z�w�?¢��ø����3~��;��r�Z�]� B�����@.����65C�+,��ù°

34�ø� #define __NO_VERSION__�����?¢��ø����3���vO��16

��?¢��ø��û�¨��?¢��ø��ÎB�±1~���Å��J��õ� �

�$�ɵ�����?¢��ø��ù°-ü�§+,��1-��1� ��Bk�ýU�òó

"$��ø��û�' v�þJ��?¢���34� ��insmod -fÌ«�� .������ �����ÂU�åì#"6"6�$��ø��û�' v�Ïä}]�åìB�Ú�

w��.������ ������û��åìZ]�Ïä}�����B�¦��ê16

D�N£��Å�Y0������ø9�?¢��§+,��Å�Y03]��ø��û��åì�!�

���ø�����i�Æ��16

! ��� ���� �.����Zh��J� �

�$�Y0��y�±]�ÃÄ��Y0��åì� �

?¢Z�]� ��Z� ��}�� z]� ?�� ÃÄ�� Y0�� y� ±p��� ��Z�� �:��0� �

i]�ÃÄw�Y0��y�z16

ÃÄ��®�-�ë���åì�����no�y�3@��ß�ÃÄ�� �:��0�-üi�Æ��16

#kernel/ksyms.c��net/netsyms.c �] � r�Z�$

������

"$� �.���mZ��ø��ÎB�ù°}��z]�åì� �

ÂU� ÃÄ� v� �ø� �Îa� ù°-�]�� @NZ� � �#;��<�/E+��FG�����$

�:��0a���Å�1�_� �16� printk()�°ya�R��m¶������ø�ÔYa�3

���p¶���� printk�� �:��0}�w���ø�ÔYa�3¶� printk��Z�?¢��

ø��ÎB��B}�� printk_xxxxxx�È<�� �:��0��16

Ó�Z��1��N©���a����i]������16#ifdef CONFIG_MODVERSIONS#define MODVERSIONS#include <linux/modversions.h>#endif

8$�������9���0�����:0�.�1��-��

������ 9���0���p����}��z]��B��°ym#R� �� get_user�� put_user�� strcpy�strcmp$U� �:0�.�1��-�� 3�� �¨�� ��� �:0�.�1��-�� 3¶� §+,-Z� �����

9���0�����tí�,®� 9���0���p��@�yv�z16��åì� ������9���0����� �0����

�.�����@4~� ���4a�-v34�Å�Z�ZhB�ÐÑ�16

§+,���Z�� ��a�®�-����Æ��16

�� � �:0�.�1��-U� ��"

��8� �:0�.�1��-U� ������ 9���0����� 9���0���p�� �� y� z4� �Z� Y0�� y

±16�#�94:�������9���0��� $

��?¢Z��Y0��y�z]�jy²�°y� �

��Z�� �:��0� �.����0������3@� �:��0��i]�ÃÄ

ɵ�����?¢Z�� �:��0��i]�ÃÄ

������9���0���p������°y

������

! �.�����:��0��J� �

���v��ÃÄ�� �:��0�@Na���3���p¶�?¢Z�� �:��0�B���?��ÃÄm# 0�0��p

����3���U�?�� -������ÃÄm$��$[p������ �.���� 0���Z��BB��1� HC

��. :���:���� �����B��16

��?¢Z��t���ÃÄv� �:��03���pº¶�r�Z�1����B�16EXPORT_NO_SYMBOLS;

���3]�ÃÄw� �:��0a�3º¶��v��ÃÄm��ÀO�����16

#define EXPORT_SYMTAB (#include <linux/module.h> �G6 ��)

EXPORT_SYMBOL(symbol1); (exportH .¢D' £¤� ��)EXPORT_SYMBOL(symbol2);

���� .��������EXPORT_SYMBOL()���v����3���U�åì�?�� �0����� �.���mU�$[

p�� �.����0���Z��B�}]���a� �.����0���Z��B3���_��16

���� .���������0����� �.�����tu' v� 4 �.��: a����?¢Z�Ì���Îa�ù°3~�z

]� ÃÄ�� $[p�� fO3]�� �a� fO3�� �]16� �� ÃÄmU� EE�� .��EI?¢�

¼JE�����È<��}��z16

������

������������ ����������������������������

! À�� ������4B�B���"#���$����� ��a�J\�16���kl]��4�4�w

��B�~�zp��� klZ�� �4a�3¶��N���Z�m��z]��4¸��¹º»16�!���

�4� î4B� B��� ��� � ��a� J\�16� @4�]� klZ� �� �0�� �N� ��Z

���!�1B��4a�3¶��a�¹º»16�%����î4a���Å��N�����0���N�3

¶� ����4��-��ÐÑ3]����� ��a�J\�16

! VÉ�òó� ���$�kl�VÉZ�ë��� 9��� �:��0���m��VÉ�16�@hB�� �:��0�����Z��@

4��ë���¿U� �:������ �������?��0�16��:������ Z�]�?¢��Y0� ya�c��16

��àU� ��Ea� �k34� ��� ~��� 74�� �È��#��������� ��99�$a� 3�� !16� ��]

ø��jy��!��[-Z��¨��[-Z�î4a���y]�±16����Z�]��N���Z�z]��

0��¹ºi~��?��0Z�]���àU��0���N���Z��k���16�?��0a���Å�����0

���N�3¶��a��"#�H��16

! 6�G� òó� �� ?¢�� J\3~� ���� ¤� mknod� Ò×p�� �ß3]� kl� çy� +,#���

:����� 9��$�� w�16� @4�]� kl�� .�>��� ��.��a� ��3�� �$p�� ��Z�� ��

»� .�>�����.��Z�� ��kl�+,��w�16�����?¢Z�]� cat�Ò×���03@�kla

����Å���Z������!��0���%]��ôD�16�!���?¢Z�]�î4a���¤��

¤Z� �4a� 3&�� Å� �øZ� �� �0�� JÌ�� �%]�� ôD�16� %��� ?¢Z�]� ��

�� 74a� '��� î4a� 3&�� Å� ����4��-�� }]�� @N²�� kla� ��m�¶� ?�4�:�

}]��ôD�16

������

! 9�� �

���4w���3]��$����� ���J\

���4@î4a�?!���3]��$����� ���J\

��î4a���Å���B�N�3¶� ����4��-��}]����� ���J\

! 6�G�9�� �

�$��4w���3]��$����� ��� �insmod minibuf.ocat /proc/devices� (%�;�¥6��]¦�PQ���R��S��§¨'�©A

mknod /dev/minibuf c major 0� (%��')�$�"��*#$��z;W�ª«�":6��©A

cat /dev/minibufrmmod minibuf

"$��4@î4a�?!���3]��$����� ��� �insmod minibuf2.ocat > /dev/minibufcat /dev/minibufrmmod minibuf2

8$�î4a���Å���B�N�3¶� ����4��-��}]����� ��insmod minibuf3.ocat minibuf3.c > /dev/minibuf� (%�*�����"+

cat /dev/minibuf (%�,'�#��

rmmod minibuf3

�����

! Filename : minibuf.c

/* Mini Buffer Device Driver*/

#include <linux/kernel.h>#include <linux/module.h>

#ifdef CONFIG_MODVERSIONS#define MODVERSIONS#include <linux/modversions.h>#endif

#include <linux/fs.h>#include <linux/kdev_t.h>#include <asm/uaccess.h>

/* * Device Definitions */

#define DEVICE_NAME "MiniBuf"#define BUFFER_LEN 1024

/* * Global Variables */

static int s_nMajor = 0;

�����

static int s_bDeviceOpen = 0;static char s_strBuf[BUFFER_LEN];static int s_nBufPos = 0, s_nBufEnd = 0;

/* * Function Prototypes */

static int device_open(struct inode *inode, struct file *filp);static int device_release(struct inode *inode, struct file *filp);static ssize_t device_read(struct file *filp, char *buffer, size_t length,

loff_t *offset);static ssize_t device_write(struct file *filp, const char *buffer, size_t length,

loff_t *offset);

static int is_buffer_empty(void);static int is_buffer_full(void);static int read_buffer_char(char *buffer);static int write_buffer_char(char *buffer);

/* * Device Operations */

struct file_operations device_fops = { NULL, /* seek */ device_read, /* read */ device_write, /* write */ NULL, /* readdir */

������

NULL, /* poll */ NULL, /* ioctl */ NULL, /* mmap */ device_open, /* open */ NULL, /* flush */ device_release /* release */};

/* * Module startup/cleanup */

int init_module(void){ printk("Loading Mini Buffer Module\n");

if ((s_nMajor = register_chrdev(0, DEVICE_NAME, &device_fops)) < 0) { printk(DEVICE_NAME " : Device registration failed (%d)\n", s_nMajor); return s_nMajor; }

printk(DEVICE_NAME " : Device registered with Major Number = %d\n", s_nMajor);

strcpy(s_strBuf, "Hello, World\n"); s_nBufEnd = strlen(s_strBuf) + 1;

return 0;}

void cleanup_module(void)

������

{ int nRetCode;

printk("Unloading Mini Buffer Module\n");

if ((nRetCode = unregister_chrdev(s_nMajor, DEVICE_NAME)) < 0) printk(DEVICE_NAME " : Device unregistration failed (%d)\n", nRetCode);}

/* * Device Operations */

int device_open(struct inode *inode, struct file *filp){ printk(DEVICE_NAME " : Device open (%d, %d)\n", MAJOR(inode->i_rdev),

MINOR(inode->i_rdev));

if (s_bDeviceOpen) { printk(DEVICE_NAME " : Device already open\n"); return -EBUSY; }

++s_bDeviceOpen;

MOD_INC_USE_COUNT;

return 0;}

������

int device_release(struct inode *inode, struct file *filp){ printk(DEVICE_NAME " : Device release (%d, %d)\n", MAJOR(inode->i_rdev),

MINOR(inode->i_rdev));

if (!s_bDeviceOpen) { printk(DEVICE_NAME " : Device has not opened\n"); return -EINVAL; }

--s_bDeviceOpen;

MOD_DEC_USE_COUNT;

return 0;}

ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset){ int count = 0;

if (is_buffer_empty()) { /* end of file */ printk(DEVICE_NAME " : Read return EOF\n"); return 0; }

while (!is_buffer_empty() && length > 1) { read_buffer_char(buffer); ++buffer; --length;

������

++count; }

put_user(0, buffer); ++count;

printk(DEVICE_NAME " : Read %d bytes\n", count);

return count;}

ssize_t device_write(struct file *filp, const char *buffer, size_t length, loff_t *offset){ return -ENOSYS; /* not implemented */}

/* * Buffer Management */

int is_buffer_empty(void){ return (s_nBufPos == s_nBufEnd) ? 1 : 0;}

int is_buffer_full(void){ int pos = s_nBufEnd + 1;

if (pos == BUFFER_LEN)

������

pos = 0;

return (pos == s_nBufPos) ? 1 : 0;}

int read_buffer_char(char *buffer){ if (is_buffer_empty()) return -1;

put_user(s_strBuf[s_nBufPos], buffer);

if (++s_nBufPos == BUFFER_LEN) s_nBufPos = 0;

return 0;}

int write_buffer_char(char *buffer){ if (is_buffer_full()) return -1;

get_user(s_strBuf[s_nBufEnd], buffer);

if (++s_nBufEnd == BUFFER_LEN) s_nBufEnd = 0;

return 0;}

������

! Filename : minibuf2.c

ssize_t device_write(struct file *filp, const char *buffer, size_t length,loff_t *offset)

{ int count = 0;

if (is_buffer_full()) { /* out of buffer */ printk(DEVICE_NAME " : Write return Out of Buffer\n"); return -ENOMEM; }

while (!is_buffer_full() && length > 0) { write_buffer_char((char *) buffer); ++buffer; --length; ++count; }

filp->f_pos += count;

printk(DEVICE_NAME " : Write %d bytes\n", count);

return count;}

������

! Filename : minibuf3.c

static int s_bDeviceReadOpen = 0;static int s_bDeviceWriteOpen = 0;static struct wait_queue *s_wq = NULL;

�"��#-��#.��#" ��

if ((filp->f_flags & O_ACCMODE) & (O_WRONLY | O_RDWR)) { if (s_bDeviceWriteOpen) { printk(DEVICE_NAME " : Device already open for writing\n"); return -EBUSY; } else ++s_bDeviceWriteOpen; } else { if (s_bDeviceReadOpen) { printk(DEVICE_NAME " : Device already open for reading\n"); return -EBUSY; } else ++s_bDeviceReadOpen; }

�"��#-��#.$#�#'/# ��

if ((filp->f_flags & O_ACCMODE) & (O_WRONLY | O_RDWR)) --s_bDeviceWriteOpen; else --s_bDeviceWriteOpen;

������

�"��#-��#.$#'� ��

while (!is_buffer_empty() && length > 1) { read_buffer_char(buffer); ++buffer; --length; ++count; wake_up_interruptible(&s_wq); }

�"��#-��#.,$��# ��

if (is_buffer_full()) { /* out of buffer */ printk(DEVICE_NAME " : Write go to sleep\n"); interruptible_sleep_on(&s_wq); printk(DEVICE_NAME " : Write wake up"); }

�����

! �$����� ����J\ó

��·N²����� ��]�+,�DE^��a�����Õõ�16

������ ��]� file_operationsa�Jb°p�(�VÉ�16

������ ��]�$¡��V�34����~ñ�� .�>�����.��a�Y0�16

! kl��fO9��J

��fO� �int register_chrdev(unsigned int major, const char *name, struct file_operations *fops)major� �¬¨H� �')�$�"��*#$��0�3�BJ#W�a��­®-6��¯@)��H°¦��

name� �\]����

fops� �\]6�±���{�²³�´�D

���J� �int unregister_chrdev(unsigned int major, const char *name)

! +�>�����.��²� +�������.��

��kla�V©3]�òóp��)���03@�ç��kla�V��16

��.�>�����.�������Z������ ��a�V©3]��Y0�16

��.�������.��������� ����Z��ë���åì�kla�V©34�����Y0�16

��*�+����� ��]�*�+� .�>�����.��a�B���16

��Documentation/devices.txtZ�?��kl�� .�>�����.��B���}��z16

��register_chrdev()��kla�fO��� .�>�����.��a����16

,ÂU� .�>�����.��B����fO}��zp¶�fO��{��16

����.���������0������major���-�.�0Z� (�ø-

�����

�Ð�9�Z�]�.��� .�>�����.��a�Y0��y�z�w�� Ýù-Z]� .�>�����.��a

�ßàtÆ��16

��mknod�Ò×p������ ��Z�o���y�z]�kl�+,�Ѧ

.4����I����9�����.J�I0�:J�I.�>��J�I.����J

��kdev_t���kl�� .�>����.�������.��a�/É3]�$0VW

MAJOR()���kdev_tZ�� .�>�����.��a�1��]�27�

MINOR()���kdev_tZ�� .�������.��a�1��]�27�

MKDEV(ma, mi)���.�>�����.����.�������.��a�B�~� kdev_ta�w�16

��cat /proc/devices Ò×p��ɵ��������� ���ÀO��Ä�y�z16

! struct file���#������@�����@9 65$���:���9����/É3]�$0VW

���:�#$�°yZ�����wm��~���;��°yZ�ø-�16

struct dentry *f_dentry;� HC�����0�����0��

struct file_operations *f_op; HC�9����:��0��� �#9���0����:���0� $

mode_t f_mode; HC�<+��GE���

loff_t f_pos; HC�ɵ�+,Z���~�î]��l

unsigned int f_flags; HC���� �.�����������4�����0���::��ÂU� 9��-

unsigned int f_uid, f_gid; HC�9����?��������-��

void *private_data; HC��:��9��31��B�D���EB�ë���Å

������

! struct file_operations���#������@�����@9 65$loff_t (*llseek) (struct file *, loff_t, int);

+,Z��ɵ��~�î]��la��[�16ssize_t (*read) (struct file *, char *, size_t, loff_t *);

klZ����Ea���mD16ssize_t (*write) (struct file *, const char *, size_t, loff_t *);

klZ���Ea�4O�16int (*readdir) (struct file *, void *, filldir_t);

klZ�]�Y03���~�4¬�Z�w�Y03]�°y�16unsigned int (*poll) (struct file *, struct poll_table_struct *);

klZ��~���y�z]����]��5�R·�6��ÐÑ7]��ÔY�16

poll()��select()�°ya�VÉ3]��Y0�16int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);

�4@î4B�tí�kl31�ë���Ò×����]��Y0�16int (*mmap) (struct file *, struct vm_area_struct *);

kl��>?�a���%���>?�²� .�::��-���16int (*open) (struct inode *, struct file *);

kla�Õ16int (*flush) (struct file *);int (*release) (struct inode *, struct file *);

kla�8]16int (*fsync) (struct file *, struct dentry *);

kla� 9�� 5��16int (*fasync) (int, struct file *, int);

������

� ���5����� ���0�9���0������:�]� 9��-D� <��K�;�9��-B�9�¿��:º»16int (*check_media_change) (kdev_t dev);

á�SÂ��Y0�v�Z� .���B�;�y�z]�LM����� ��Z��Y0�16int (*revalidate) (kdev_t dev);

J¨�B���LM�klZ�� ��99�����5a�c�34�����Y0�16int (*lock) (struct file *, int, struct file_lock *);

! �:�Z����,� �

��H�p��kla�Õ�åì�kla��4��16

��.������Ïa�ôD3~�ë���åì� f_op�ùDEa�y��16

��ë���åì�>?�a��ßàt� filp->private_dataZ��]1

��<W� y#� �-�����0$a�=B->16

! ��� Z����,� �

��<W� ya�?r->16

��filp->private_dataZ��ßàU���EB�zp¶��J�16

��3�@p�� ��� a�3]�åì�kla�P0�16

! ����� �0�������

���V�wA��U�åì� count²�ÂU�¸��¹º»16

���V��74Î1��_��U�åì� countÎ1�\U�Bya�¹º»16

��G�<#����9�9��$D�åì� (��¹º»16

��ZhB�ÐÑ3¶��ya�¹º»16

������

! ?��0���V�wA�4O��åì� count²�ÂU�¸��¹º»16

���V��74Î1��_���åì� countÎ1�\U�Bya�¹º»1

��3�v�î��C��åì� (��¹º»16���åì� write()�°y]�µ-va��16

��ZhB�ÐÑ��åì��ya�¹º»16

! ���>?�²�Y0$�>?�����E�ªä� ��#������@� .@���� 65$

�� ��� >?�²� Y0$� >?�]� ��� 1½� irb"Z� ´µ34� Å�Z� ��Z�� Y0$

>?�a���o���y�±16�� �� �����?��0�� � 0.�����H����9�X0���

Y�Z���E�ªä��ë���åì�����ir�b"p��(Ya��Æ��16

��Y0$�>?�� HC����>?�� �void get_user(to, from);void copy_from_user(to, from, n);

�����>?�� HC�Y0$�>?�� �void put_user(from, to);void copy_to_user(to, from, n);

��get_user()��put_user()���'D»�D$��74Z�� � ���"��'���0���E�(Y

��copy_from_user()��copy_to_user()���74�J��±������74wA�(Y

! ?¢��<W� y� ��?¢�Y0��¥��}]�E�ò�� #������@�����@.����65$

��?¢��1½�?¢������ Z����������Y0}~�z]�a��:F16

����� � ��a�Y03~� z�� Å� rmmodÂU� Ò×p�� ?¢��J¨}]� E�� @4

���� �:��� �� Å� <W� ya� =B-ú4~�� ��� a� 3¶� <W� ya� ?r-ü

¥���æ�y�z_��16

��?¢�<W� y�=B� ��MOD_INC_USE_COUNT

������

��?¢�<W� y�?r� ��MOD_DEC_USE_COUNT��?¢�<W�@N� ��MOD_IN_USE

! ����4��-��@��� $��� ë��� 3]��� ɵ� $��� Y0�� y� ±�� åì�� $��� Y0�� y� z�� ÅG�

41��� �:��3~��$���Y0��y�z_}¶� ?�4�:��}��\Á��HI�16

���������pº~�3]�������EB�±��Å� ����4��-6���EB�vJ3¶� ?�4�:

��?��0���îº~�3]����b"��±��Å� ����4��-��b"��Ñ4¶� ?�4�:

�� �:�°y� �void interruptible_sleep_on(struct wait_queue **q);void sleep_on(struct wait_queue **q);

��?�4�:�°y� �void wake_up_interruptible(struct wait_queue **q);void wake_up (struct wait_queue **q);

����0���:0��������4��-���,®�D� �@�Z�����ÐÑ�� ����4��-�{6��µ>!¶>������;�¥� 1��2���·¸�¬

������0���:0��������4��-������� ���0����� �0���Z��ÐÑ�� ����4��-�'+#��'���s�¹w#��P�º6����W��µ»D���¼½

����0������J� �

����4��-��ÐÑ��Ó�]�µ­���,�K�y�z16

��0�����J��õ� �

klZ�o���y�z]� y�J�34� #�:�$

-������jyB�tí� ������jy�Y034� # 0��4$

0���0�9���� :���0���0��Y0� ��Þ��+,31���E��ß

ë���åì� 4.�����#$�f��Y03@� 5�:�L���0

������

��� ���� ����� ��� � ������ ������ �����������

! À�� ������� +�����9���� ���M3@���a���p��)���~�[�p���ß��à

]� ��� � ��a� J\�16� @4�� [�p�� �ßà]� ���� 74]� 4ö�p�� 4ö

¸p��÷���74��w�� insmod���� p��?¢������Å�����74a�D$����

��yv�z16�!���� .������ÏZ�� ���4�1½�[\��3]����� ��a�J\

�16��øZ�J\��Ó�a��03@� .������ÏB� (,�ÅZ]� ����4��-��3���~�� �,�Å

Z]�î4Z�� ����4��-��3���",�ÅZ]��4Z�v� ����4��-���16

! VÉòó� �� 4´�� .�����9"6�� Ó�a�y�3@���a���p��)���~�� init_module()Z�� kmalloc()� °ya� �03@� [�p�� >?�a� �ßà]16� �� Å� insmod� ��� Z� ø

-�� D$a� ÔY3@� ���� 74a� ��3~� zp¶�� �ß3]� 74�� ��a� �ßà]16

cleanup_module()Z�]�H�Z��ßàU���a� kfree()�°ya��03@��J�16�!�

��?¢U���Z�J\�� .�����9'6��Ó�a�y�3@���4�1½�[\��3]� ���@?��0�°ya

VÉ3~���:�-Z� .������ÏZ�� � file�VW«�� 9����:��0������4�1½�°y�����

3@� .������ÏZ�� �1½�[\��3vO��16

! 6�G� òó� �� ���� ?¢U� ?¢�� ���� Å� ���� 74a� ���16� ��~� �ß�� 74

������Ea� 4O3&��Å�'����4O��}���~�>?��N��ZhB�ÐÑ3]��ö

16�!���?¢U� .������ÏB�1½�kl�+,��%�a�wm������[\��ôD�16

������

! 9�� �

����a�[�p���ßà]��$����� ���J\

��.������ÏZ�� �1½�[\��3]��$����� ���J\

! 6�G�9�� �

�$���a�[�p���ßà]��$����� ��� �insmod minibuf4.o minibuf_bufsize=10cat > /dev/minibuf� (%�S¾�º>�����¿�À��«

cat > /dev/minibuf� (%�rs���«#m'�I�6Ás�¹w#�W�©A

cat /dev/minibuf� (%�S¾�º>ÂÃÂ�y\¡Ä�W�©A

rmmod minibuf

"$�.������ÏZ�� �1½�[\��3]��$����� ��� �insmod minbuf5.omknod /dev/minibuf0 c major 0mknod /dev/minibuf1 c major 1mknod /dev/minibuf2 c major 2cat minibuf5.c > /dev/minibuf0� (%�S¾�º>ÂÃÂ��«

cat /dev/minibuf0� (%�S¾�º>ÂÃÂ�ª«

cat minibuf5.c > /dev/minibuf1� (%�*�����"+

cat /dev/minibuf1� (%�,'�#��

cat /dev/minibuf2 (%�*�����"+

cat > /dev/minibuf2� (%�,'�#��

rmmod minibuf5

������

! Filename : minibuf4.c

/* Mini Buffer Device Driver : Dynamic allocation*/

#include <linux/kernel.h>#include <linux/module.h>

#ifdef CONFIG_MODVERSIONS#define MODVERSIONS#include <linux/modversions.h>#endif

#include <linux/fs.h>#include <linux/kdev_t.h>#include <linux/slab.h>#include <asm/uaccess.h>

/* * Device Definitions */

#define DEVICE_NAME "MiniBuf"#define DEFAULT_BUFFER_LEN 1024

/* * Global Variables */

������

static int s_nMajor = 0;

static int s_bDeviceOpen = 0;static char *s_strBuf = NULL;static int s_nBufPos = 0, s_nBufEnd = 0;static int s_nBufSize = 0;

static int minibuf_bufsize = DEFAULT_BUFFER_LEN;

MODULE_PARM(minibuf_bufsize, "i");MODULE_PARM_DESC(minibuf_bufsize, "Size of buffer");

/* * Function Prototypes */

static int device_open(struct inode *inode, struct file *filp);static int device_release(struct inode *inode, struct file *filp);static ssize_t device_read(struct file *filp, char *buffer, size_t length,

loff_t *offset);static ssize_t device_write(struct file *filp, const char *buffer, size_t length,

loff_t *offset);

static int is_buffer_empty(void);static int is_buffer_full(void);static int read_buffer_char(char *buffer);static int write_buffer_char(char *buffer);

/* * Device Operations

�����

*/

struct file_operations device_fops = { NULL, /* seek */ device_read, /* read */ device_write, /* write */ NULL, /* readdir */ NULL, /* poll */ NULL, /* ioctl */ NULL, /* mmap */ device_open, /* open */ NULL, /* flush */ device_release /* release */};

/* * Module startup/cleanup */

int init_module(void){ printk("Loading Mini Buffer Module\n");

if ((s_nMajor = register_chrdev(0, DEVICE_NAME, &device_fops)) < 0) { printk(DEVICE_NAME " : Device registration failed (%d)\n", s_nMajor); return s_nMajor; }

printk(DEVICE_NAME " : Device registered with Major Number = %d\n", s_nMajor);

�����

printk(DEVICE_NAME " : Buffer allocation size = %d\n", minibuf_bufsize);

if (minibuf_bufsize <= 0) { printk(DEVICE_NAME " : invalid minibuf_bufsize argument\n"); return -EINVAL; }

if ((s_strBuf = (char *) kmalloc(minibuf_bufsize, GFP_KERNEL)) == NULL) { printk(DEVICE_NAME " : Memory allocation error\n"); return -ENOMEM; }

s_nBufSize = minibuf_bufsize;

return 0;}

void cleanup_module(void){ int nRetCode;

printk("Unloading Mini Buffer Module\n");

if ((nRetCode = unregister_chrdev(s_nMajor, DEVICE_NAME)) < 0) printk(DEVICE_NAME " : Device unregistration failed (%d)\n", nRetCode);

if (s_strBuf) { kfree(s_strBuf); s_strBuf = NULL; s_nBufSize = 0;

������

}}

/* * Device Operations */

int device_open(struct inode *inode, struct file *filp){ printk(DEVICE_NAME " : Device open (%d, %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev));

if (s_bDeviceOpen) { printk(DEVICE_NAME " : Device already open\n"); return -EBUSY; }

++s_bDeviceOpen;

MOD_INC_USE_COUNT;

return 0;}

int device_release(struct inode *inode, struct file *filp){ printk(DEVICE_NAME " : Device release (%d, %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev));

if (!s_bDeviceOpen) {

������

printk(DEVICE_NAME " : Device has not opened\n"); return -EINVAL; }

--s_bDeviceOpen;

MOD_DEC_USE_COUNT;

return 0;}

ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset){ int count = 0;

if (is_buffer_empty()) { /* end of file */ printk(DEVICE_NAME " : Read return EOF\n"); return 0; }

while (!is_buffer_empty() && length > 1) { read_buffer_char(buffer); ++buffer; --length; ++count; }

put_user(0, buffer); ++count;

������

printk(DEVICE_NAME " : Read %d bytes\n", count);

return count;}

ssize_t device_write(struct file *filp, const char *buffer, size_t length,loff_t *offset)

{ int count = 0;

if (is_buffer_full()) { /* out of buffer */ printk(DEVICE_NAME " : Write out of buffer\n"); return -ENOMEM; }

while (!is_buffer_full() && length > 0) { write_buffer_char((char *) buffer); ++buffer; --length; ++count; }

filp->f_pos += count;

printk(DEVICE_NAME " : Write %d bytes\n", count);

return count;}

/*

������

* Buffer Management */

int is_buffer_empty(void){ return (s_nBufPos == s_nBufEnd) ? 1 : 0;}

int is_buffer_full(void){ int pos = s_nBufEnd + 1;

if (pos == s_nBufSize) pos = 0;

return (pos == s_nBufPos) ? 1 : 0;}

int read_buffer_char(char *buffer){ if (is_buffer_empty()) return -1;

put_user(s_strBuf[s_nBufPos], buffer);

if (++s_nBufPos == s_nBufSize) s_nBufPos = 0;

return 0;}

������

int write_buffer_char(char *buffer){ if (is_buffer_full()) return -1;

get_user(s_strBuf[s_nBufEnd], buffer);

if (++s_nBufEnd == s_nBufSize) s_nBufEnd = 0;

return 0;}

������

! Filename : minibuf5.c

/* Mini Buffer Device Driver : Minor devices*/

#include <linux/kernel.h>#include <linux/module.h>

#ifdef CONFIG_MODVERSIONS#define MODVERSIONS#include <linux/modversions.h>#endif

#include <linux/fs.h>#include <linux/kdev_t.h>#include <linux/slab.h>#include <asm/uaccess.h>

/* * Device Definitions */

#define DEVICE_NAME "MiniBuf"#define DEFAULT_BUFFER_LEN 1024

#define DEVICE_NOBLOCK 0#define DEVICE_WRITEBLOCK 1#define DEVICE_BLOCK 2#define DEVICE_NUM 3

������

/* * Global Variables */

static int s_nMajor = 0;

static struct devicedata_t { int m_bDeviceReadOpen; int m_bDeviceWriteOpen; char *m_strBuf; int m_nBufPos, m_nBufEnd; int m_nBufSize; struct wait_queue *m_writequeue, *m_readqueue;} s_devicedata[DEVICE_NUM];

int minibuf_bufsize = DEFAULT_BUFFER_LEN;

MODULE_PARM(minibuf_bufsize, "i");MODULE_PARM_DESC(minibuf_bufsize, "Size of buffer");

/* * Function Prototypes */

static int device_open(struct inode *inode, struct file *filp);static int device_release(struct inode *inode, struct file *filp);static ssize_t device_noblock_read(struct file *filp, char *buffer, size_t length,

loff_t *offset);static ssize_t device_noblock_write(struct file *filp, const char *buffer,

������

size_t length, loff_t *offset);static ssize_t device_writeblock_read(struct file *filp, char *buffer, size_t length,

loff_t *offset);static ssize_t device_writeblock_write(struct file *filp, const char *buffer,

size_t length, loff_t *offset);static ssize_t device_block_read(struct file *filp, char *buffer, size_t length,

loff_t *offset);static ssize_t device_block_write(struct file *filp, const char *buffer,

size_t length, loff_t *offset);

static int is_buffer_empty(struct devicedata_t *pdata);static int is_buffer_full(struct devicedata_t *pdata);static int read_buffer_char(struct devicedata_t *pdata, char *buffer);static int write_buffer_char(struct devicedata_t *pdata, char *buffer);

/* * Device Operations */

struct file_operations device_noblock_fops = { open: device_open, release: device_release, read: device_noblock_read, write: device_noblock_write,};

struct file_operations device_writeblock_fops = { open: device_open, release: device_release, read: device_writeblock_read,

�����

write: device_writeblock_write,};

struct file_operations device_block_fops = { open: device_open, release: device_release, read: device_block_read, write: device_block_write,};

struct file_operations *device_fops_array[] = { &device_noblock_fops, &device_writeblock_fops, &device_block_fops};

/* * Module startup/cleanup */

int init_module(void){ int i; struct devicedata_t *pdata;

printk("Loading Mini Buffer Module\n");

if ((s_nMajor = register_chrdev(0, DEVICE_NAME, device_fops_array[0])) < 0) { printk(DEVICE_NAME " : Device registration failed (%d)\n", s_nMajor); return s_nMajor;

�����

}

printk(DEVICE_NAME " : Device registered with Major Number = %d\n", s_nMajor);

printk(DEVICE_NAME " : Buffer allocation size = %d\n", minibuf_bufsize);

if (minibuf_bufsize <= 0) { printk(DEVICE_NAME " : invalid minibuf_bufsize argument = %d\n", minibuf_bufsize); return -EINVAL; }

for (i = 0, pdata = s_devicedata; i < DEVICE_NUM; ++i, ++pdata) { if ((pdata->m_strBuf = (char *) kmalloc(minibuf_bufsize, GFP_KERNEL)) == NULL) { printk(DEVICE_NAME " : Memory allocation error\n");

while (--i >= 0) kfree(pdata->m_strBuf);

return -ENOMEM; }

pdata->m_nBufSize = minibuf_bufsize; }

return 0;}

void cleanup_module(void){

������

int i, nRetCode; struct devicedata_t *pdata;

printk("Unloading Mini Buffer Module\n");

if ((nRetCode = unregister_chrdev(s_nMajor, DEVICE_NAME)) < 0) printk(DEVICE_NAME " : Device unregistration failed (%d)\n", nRetCode);

for (i = 0, pdata = s_devicedata; i < DEVICE_NUM; ++i, ++pdata) { if (pdata->m_strBuf) { kfree(pdata->m_strBuf); pdata->m_strBuf = NULL; pdata->m_nBufSize = 0; } }}

/* * Device Operations */

int device_open(struct inode *inode, struct file *filp){ int minor = MINOR(inode->i_rdev); struct devicedata_t *pdata = &s_devicedata[minor];

printk(DEVICE_NAME " : Device open (%d, %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev));

if ((filp->f_flags & O_ACCMODE) & (O_WRONLY | O_RDWR)) {

������

if (pdata->m_bDeviceWriteOpen) { printk(DEVICE_NAME " : Device already open for writing\n"); return -EBUSY; } else ++pdata->m_bDeviceWriteOpen; } else { if (pdata->m_bDeviceReadOpen) { printk(DEVICE_NAME " : Device already open for reading\n"); return -EBUSY; } else ++pdata->m_bDeviceReadOpen; }

filp->f_op = device_fops_array[minor];

MOD_INC_USE_COUNT;

return 0;}

int device_release(struct inode *inode, struct file *filp){ int minor = MINOR(inode->i_rdev); struct devicedata_t *pdata = &s_devicedata[minor];

printk(DEVICE_NAME " : Device release (%d, %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev));

if ((filp->f_flags & O_ACCMODE) & (O_WRONLY | O_RDWR)) --pdata->m_bDeviceWriteOpen;

������

else --pdata->m_bDeviceReadOpen;

MOD_DEC_USE_COUNT;

return 0;}

/* nonblocking read/write*/

ssize_t device_noblock_read(struct file *filp, char *buffer, size_t length,loff_t *offset)

{ int count = 0; struct devicedata_t *pdata = &s_devicedata[DEVICE_NOBLOCK];

if (is_buffer_empty(pdata)) { /* end of file */ printk(DEVICE_NAME " (NOBLOCK) : Read return EOF\n"); return 0; }

while (!is_buffer_empty(pdata) && length > 1) { read_buffer_char(pdata, buffer); ++buffer; --length; ++count; }

������

put_user(0, buffer); ++count;

printk(DEVICE_NAME " (NOBLOCK) : Read %d bytes\n", count);

return count;}

ssize_t device_noblock_write(struct file *filp, const char *buffer, size_t length,loff_t *offset)

{ int count = 0; struct devicedata_t *pdata = &s_devicedata[DEVICE_NOBLOCK];

if (is_buffer_full(pdata)) { /* out of buffer */ printk(DEVICE_NAME " (NOBLOCK) : Write out of buffer\n"); return -ENOMEM; }

while (!is_buffer_full(pdata) && length > 0) { write_buffer_char(pdata, (char *) buffer); ++buffer; --length; ++count; }

filp->f_pos += count;

printk(DEVICE_NAME " (NOBLOCK) : Write %d bytes\n", count);

������

return count;}

/* blocking on write read/write*/

ssize_t device_writeblock_read(struct file *filp, char *buffer, size_t length,loff_t *offset)

{ int count = 0; struct devicedata_t *pdata = &s_devicedata[DEVICE_WRITEBLOCK];

if (is_buffer_empty(pdata)) /* end of file */ return 0;

while (!is_buffer_empty(pdata) && length > 1) { read_buffer_char(pdata, buffer); ++buffer; --length; ++count; wake_up_interruptible(&pdata->m_writequeue); }

put_user(0, buffer); ++count;

printk(DEVICE_NAME " (WRITEBLOCK) : Read %d bytes\n", count);

return count;

������

}

ssize_t device_writeblock_write(struct file *filp, const char *buffer, size_t length,loff_t *offset)

{ int count = 0; struct devicedata_t *pdata = &s_devicedata[DEVICE_WRITEBLOCK];

if (is_buffer_full(pdata)) { printk(DEVICE_NAME " (WRITEBLOCK) : Write go to sleep\n"); interruptible_sleep_on(&pdata->m_writequeue); printk(DEVICE_NAME " (WRITEBLOCK) : Write wake up\n"); }

while (!is_buffer_full(pdata) && length > 0) { write_buffer_char(pdata, (char *) buffer); ++buffer; --length; ++count; }

filp->f_pos += count;

printk(DEVICE_NAME " (WRITEBLOCK) : Write %d bytes\n", count);

return count;}

/* blocking on read read/write

������

*/

ssize_t device_block_read(struct file *filp, char *buffer, size_t length,loff_t *offset)

{ int count = 0; struct devicedata_t *pdata = &s_devicedata[DEVICE_BLOCK];

if (is_buffer_empty(pdata)) { /* end of file */ printk(DEVICE_NAME " (BLOCK) : Read go to sleep\n"); interruptible_sleep_on(&pdata->m_readqueue); printk(DEVICE_NAME " (BLOCK) : Read wake up\n"); }

while (!is_buffer_empty(pdata) && length > 1) { read_buffer_char(pdata, buffer); ++buffer; --length; ++count; wake_up_interruptible(&pdata->m_writequeue); }

put_user(0, buffer); ++count;

printk(DEVICE_NAME " : Read %d bytes\n", count);

return count;}

������

ssize_t device_block_write(struct file *filp, const char *buffer, size_t length,loff_t *offset)

{ int count = 0; struct devicedata_t *pdata = &s_devicedata[DEVICE_BLOCK];

if (is_buffer_full(pdata)) { printk(DEVICE_NAME " (BLOCK) : Write go to sleep\n"); interruptible_sleep_on(&pdata->m_writequeue); printk(DEVICE_NAME " (BLOCK) : Write wake up\n"); }

while (!is_buffer_full(pdata) && length > 0) { write_buffer_char(pdata, (char *) buffer); ++buffer; --length; ++count; wake_up_interruptible(&pdata->m_readqueue); }

filp->f_pos += count;

printk(DEVICE_NAME " (BLOCK) : Write %d bytes\n", count);

return count;}

/* * Buffer Management */

�����

int is_buffer_empty(struct devicedata_t *pdata){ return (pdata->m_nBufPos == pdata->m_nBufEnd) ? 1 : 0;}

int is_buffer_full(struct devicedata_t *pdata){ int pos = pdata->m_nBufEnd + 1;

if (pos == pdata->m_nBufSize) pos = 0;

return (pos == pdata->m_nBufPos) ? 1 : 0;}

int read_buffer_char(struct devicedata_t *pdata, char *buffer){ if (is_buffer_empty(pdata)) return -1;

put_user(pdata->m_strBuf[pdata->m_nBufPos], buffer);

if (++pdata->m_nBufPos == pdata->m_nBufSize) pdata->m_nBufPos = 0;

return 0;}

int write_buffer_char(struct devicedata_t *pdata, char *buffer)

�����

{ if (is_buffer_full(pdata)) return -1;

get_user(pdata->m_strBuf[pdata->m_nBufEnd], buffer);

if (++pdata->m_nBufEnd == pdata->m_nBufSize) pdata->m_nBufEnd = 0;

return 0;}

������

! >?���[�D��ß9��J� ��#������@�����@ ���65$void *kmalloc(size_t, int);

����74wA��>?�a��ß3@�¹º»16void kfree(const void *);

kmalloc()p���ßàU�>?�a��J�16

! ?¢Z�� :���.0��ø-34� �

��MODULE_PARM(var, type)�27��� :���.0���Y0��jya���

�����jyÒ6�-������jyB�tu�v��c��±16

0�:����$Þ�� I.��I�.��JJL��5����� M���ÈN��O]16

������0��5��� 5��0��������0���������-�� ��� 0���-

��MODULE_PARM_DESC(var, description)�27��� :���.0�Z�Ì��÷Ò���1

��:���.0����34� �

insmoda���Å� ��H����ÈNp��¸�����16

insmod���� U�?¢�������jya��ß3]�¸p��lä�16

��"6(6���øZ�]� �:��0��?��jya� :���.0�a����¸����y�z�16

! .������ÏZ�� �1½�[\��3]����� ��� �

�� �:�9� ��� � -Z� ø-}]� inode� $0VW�� i_rdev� ÊÀ�� ���� �:��� kl�

.������Ïa�:�y�z16

���:�����Å� file�$0VW�� 9����:��0����� .������ÏZ� � �� 1�_� ��°p�(�

�]� 9����:��0������,N�°ym��Pp�(�Q_�1½�[\��3vO��16

������

������������ ������� !�"�#$

! À�� �� ��� :���� +,-�.Z� ɵ� ��%��� �Îa� Î@i]� +,�� �B�16� 1�p�

.�����9Z�H��+,Z���Ea�4O3~����y�z]�+,�� :����+,-�.Z��B�16

! VÉ�òó� �� :����+,-�.�DE^��a��03@� /proc�RZ� curproc� ]�+,���B

3~�� �� +,Z�� �4a� -v3¶� �a� {|�� ��%��� ɵ� �Îa� [�p�� wm��

Î@»16� @4�]� proc_dir_entry�� read_proc� °y� ùDEa� �03@� "#3_� VÉ

�16� �� òóU� VÉ34]� Q�w� ªä�� y� z]� ��E�� 74B� PAGE_SIZEa� '�� y

±1]�#S��z16���74a�']���E�ªäU�Tø��+,�ÕÖ��VÉ3@Æ��16�!�

�]� /proc� RZ� bufproc� ]� +,�� �B3~� �� +,Z� 4O�� 3¶� 4O�� �0�� �

N� ��Z� �k�� 3~�� �� +,Z�� ��m�¶� 3�@Z� 4O�� �0�� Î@»16� @4�]

������:��0���9� 9����:��0������03@�VÉ�16�@4�]�UZ�²� ÂU� PAGE_SIZE�J���±16

! 6�G� òó� �� ���� ?¢�� ���� ¤� cat� Ò×�� �º�� ɵ� ��%��� �ÎB� �%]�

VWö16�!���?¢������¤� cat�Ò×���03@�+,Z���Ea�4O��¤��a���

m&��Å�øZ������0����}]��VWö16

! 9�� �

��:����+,-�.Z� ���:������B3~�6�G34

��:����+,-�.��4���Tø#�/0�� ���@?��0�B��� ��9:����+,�wm4

������

! 6�G�9�� �

�$����:�����cat /proc/curproc

"$���9:�����cat > /proc/bufproccat /proc/bufproc

������

! Filename : curproc.c

/* Current Process Information*/

#include <linux/kernel.h>#include <linux/module.h>

#ifdef CONFIG_MODVERSIONS#define MODVERSIONS#include <linux/modversions.h>#endif

#include <linux/proc_fs.h>

/* * Function Prototypes */

static int curproc_read_proc(char *buf, char **start, off_t offset, int count,int *eof, void *data);

/* * Proc Entry */

struct proc_dir_entry curproc_proc_entry = {0, /* low inode */7, "curproc", /* name length and name" */

������

S_IFREG | S_IRUGO, /* mode */1, 0, 0, /* nlink, uid, gid */0, /* size */NULL, /* inode operation : NULL = use default */NULL, /* get_info */NULL, /* fill_inode */NULL, NULL, NULL, /* next, parent, subdir */NULL, /* data */curproc_read_proc, /* read_proc */NULL, /* write_proc */NULL, /* readlink_proc *//* nothing more */

};

/* * Module Startup/Cleanup */

int init_module(void){

int retcode;

printk("Loading CurProc Module\n");

if ((retcode = proc_register(&proc_root, &curproc_proc_entry)) < 0)return retcode;

return 0;}

������

void cleanup_module(void){

printk("Unloading CurProc Module\n");

proc_unregister(&proc_root, curproc_proc_entry.low_ino);}

int curproc_read_proc(char *buf, char **start, off_t offset, int count, int *eof,void *data)

{static char *s_strState[] = {

"Running", "Sleep", "Disk Sleep", "Zombie", "Stop", "Swap", "Exclusive" };

int state, stateid;

count = 0;

for (stateid = 0, state = current->state; state > 0; state >>= 1, ++stateid);

count += sprintf(buf + count, "pid : %d\n", current->pid);count += sprintf(buf + count, "command : %s\n", current->comm);count += sprintf(buf + count, "state : %s\n", s_strState[stateid]);count += sprintf(buf + count, "priority : %ld\n", current->priority);count += sprintf(buf + count, "counter : %ld\n", current->counter);count += sprintf(buf + count, "processor : %d\n", current->processor);

return count;}

������

! Filename : bufproc.c

/* Read/Write Proc Filesystem*/

#include <linux/kernel.h>#include <linux/module.h>

#ifdef CONFIG_MODVERSIONS#define MODVERSIONS#include <linux/modversions.h>#endif

#include <linux/proc_fs.h>#include <asm/uaccess.h>

/* * Global Variables */

#define BUFFER_LEN 1024

static char s_strBuf[BUFFER_LEN];

/* * Function Prototypes */

static int bufproc_open(struct inode *inodep, struct file *filp);

������

static int bufproc_release(struct inode *inodep, struct file *filp);static ssize_t bufproc_read(struct file *filp, char *buf, size_t count, loff_t *ppos);static ssize_t bufproc_write(struct file *filp, const char *buf, size_t count, loff_t *ppos);

static int bufproc_permission(struct inode * inodep, int op);

/* * Proc Entry */

static struct file_operations bufproc_file_operations = { open: bufproc_open, release: bufproc_release, read: bufproc_read, write: bufproc_write,};

static struct inode_operations bufproc_inode_operations = { default_file_ops: &bufproc_file_operations, permission: bufproc_permission,};

struct proc_dir_entry bufproc_proc_entry = { 0, /* low inode */ 7, "bufproc", /* name length and name" */ S_IFREG | S_IRUGO | S_IWUSR, /* mode */ 1, 0, 0, /* nlink, uid, gid */ 0, /* size */ &bufproc_inode_operations, /* inode operation */ /* nothing more */};

�����

/* * Module Startup/Cleanup */

int init_module(void){ int retcode;

printk("Loading BufProc Module\n");

if ((retcode = proc_register(&proc_root, &bufproc_proc_entry)) < 0) return retcode;

return 0;}

void cleanup_module(void){ printk("Unloading BufProc Module\n");

proc_unregister(&proc_root, bufproc_proc_entry.low_ino);}

/* * File Operations */

int bufproc_open(struct inode *inodep, struct file *filp){ MOD_INC_USE_COUNT;

�����

return 0;}

int bufproc_release(struct inode *inodep, struct file *filp){ MOD_DEC_USE_COUNT;

return 0;}

ssize_t bufproc_read(struct file *filp, char *buf, size_t count, loff_t *ppos){ static int s_bRead = 0;

int len = strlen(s_strBuf);

if (len == 0 || s_bRead) { s_bRead = 0; return 0; }

if (len > count - 1) len = count - 1;

copy_to_user(buf, s_strBuf, len); put_user(0, &buf[len]); ++len;

s_bRead = 1;

return len;

������

}

ssize_t bufproc_write(struct file *filp, const char *buf, size_t count, loff_t *ppos){ int len = (count > BUFFER_LEN - 1) ? BUFFER_LEN - 1 : count;

if (count == 0) return 0;

copy_from_user(s_strBuf, buf, len); s_strBuf[len] = '\0';

return len;}

/* * Inode Operations */

/* op : 0 = execute, 2 = write, 4 = read return : 0 = permission ok, -EACCES = permission error*/

int bufproc_permission(struct inode * inodep, int op){ if (op == 4 || (op == 2 && current->euid == 0)) return 0;

return -EACCES;}

������

! :����+,-�.�X� �

��{J��7B�tu �>?��Z�´µ3]�+,-�.

����%�Z_��Î�ø-��Y0$Z_�-�.��$%���<�ø-34����wm�Y6

����E]�{J��4a�3]�-SZ�wm�­16

! :����+,-�.��R� �

/proc/cpuinfo���-�.Z�÷l�� ;,2Z�Ì���Îa�Î@»16

/proc/devices����������� ����ÀO��Î@»16

/proc/interrupts���ɵ�Y0�D�DEFG��ÀO��Î@»16

/proc/meminfo���>?��Y0��6��Î@»16

/proc/sys/kernel/hostname���5� 0��.��Î@i~���y�z_��16

/proc/sys/vm/freepages���.���.�.����?��5�-5�9��:�-��¸���~���y�z_��16

! :����+,-�.�fO9��Jint proc_register(struct proc_dir_entry *, struct proc_dir_entry *);int proc_unregister(struct proc_dir_entry *, int);

/proc�PÅÆ��� proc_dir_entry� �proc_root/proc/sys�PÅÆ��� proc_dir_entry� �proc_sys

������

! struct proc_dir_entryunsigned short low_ino;unsigned short namelen;const char *name;mode_t mode;nlink_t nlink;uid_t uid;gid_t gid;unsigned long size;struct inode_operations * ops;int (*get_info)(char *, char **, off_t, int, int);void (*fill_inode)(struct inode *, int);struct proc_dir_entry *next, *parent, *subdir;void *data;int (*read_proc)(char *page, char **start, off_t off, int count,

int *eof, void *data);int (*write_proc)(struct file *file, const char *buffer,

unsigned long count, void *data);int (*readlink_proc)(struct proc_dir_entry *de, char *page);unsigned int count; /* use count */int deleted; /* delete flag */

������

! struct inode_operationstruct file_operations * default_file_ops;

�� ����Z��Y0��4ö� 9��E�:��0��� int (*create) (struct inode *,struct dentry *,int);int (*readpage) (struct file *, struct page *);int (*writepage) (struct file *, struct page *);int (*permission) (struct inode *, int);

��%�B�+,Z�Ì���5�,��3º���Å�³����o��ZB�@Na�õ�

ɵ� ���²�+,��<��4:�@hB�a�B�~�õ�

! proc_dir_entryZ�fO3]� .��

��+,��I¦���:F16

��+,��P�� �

S_IFREG����-�����9��S_IFLNK������4S_IFBLK�������4����� :�����9��S_IFCHR����5����0������ :�����9��S_IFDIR�������0���S_IFFIFO�����.��:�:�#<�<�$

��� ��:�.� ������S_IRUSR��S_IWUSR��S_IXUSR�HC�S_IRWXU��-���:�:�. ������S_IRGRP��S_IWGRP��S_IXGRP�HC�S_IRWXG���05��:�.� ������S_IROTH��S_IWOTH��S_IXOTH�HC�S_RWXO

������

���%&�������� �������#$'(

! À�� ������ ��Z�� ���@?��0·��òóp��kla�J���y�z]� ���0���VÉ�16

.�����9Z�� ����� ��E²�� ��E� �a� 1~�� ��a� `ì]� ���0�� Ò×�� �B3~��

���� ��a��03]���� Z�]� ���0��Ò×���º��kla�J��16

! VÉòó� �� .�����986��r�a�y�3@�\¦�16�ìM� ���0��Ò×����3@��a�['�+,Z

�~������ ���� 9��� �:��0���Z� ���0��Ò×���B�16� ���0��Ò×��H�3]�°y]

$¡Z_�i�­�Ò×Z�� ��ß�\Á��H��16��¤����� ��a��03]�,®

;���� ��\¦3@�klZ���Ea���3~�����0��Ò×����16

! 6�G�òó� ��6�G���� �����klZ���Ea���3~� ���0��Ò×p����Ea�ôD

3~����E���a�1���¤���a�`ì~��1-���E���a�1��16�@4��õ9

B��3]����%]��VWö16

! 9�� �

�����0���H�3]����� ���J\

������ ���� ���0����03]�6�G���� �J\

! 6�G�9�� �insmod minibuf6.o./minibuf_testrmmod minibuf6

������

! Filename : minibuf.h

/* MiniBuf.h*/

#ifndef __MINIBUF_H#define __MINIBUF_H

#include <linux/ioctl.h>

#define MINIBUF_MAGICNUM 254

struct minibuf_peek_t { char *m_buf; int m_maxlen;};

#define IOCTL_MINIBUF_MAKEEMPTY _IO(MINIBUF_MAGICNUM, 0)#define IOCTL_MINIBUF_GETLENGTH _IOR(MINIBUF_MAGICNUM, 1, int *)#define IOCTL_MINIBUF_PEEK _IOR(MINIBUF_MAGICNUM, 2, struct minibuf_peek_t *)

#endif

������

! Filename : minibuf6.c

/* Mini Buffer Device Driver : ioctl*/

#include <linux/kernel.h>#include <linux/module.h>

#ifdef CONFIG_MODVERSIONS#define MODVERSIONS#include <linux/modversions.h>#endif

#include <linux/fs.h>#include <linux/kdev_t.h>#include <asm/uaccess.h>

#include "minibuf.h"

/* * Device Definitions */

#define DEVICE_NAME "MiniBuf"#define BUFFER_LEN 1024

/* * Global Variables */

������

static int s_nMajor = 0;

static int s_bDeviceReadOpen = 0;static int s_bDeviceWriteOpen = 0;static char s_strBuf[BUFFER_LEN];static int s_nBufPos = 0, s_nBufEnd = 0;

static struct wait_queue *s_wq = NULL;

/* * Function Prototypes */

static int device_open(struct inode *inode, struct file *filp);static int device_release(struct inode *inode, struct file *filp);static ssize_t device_read(struct file *filp, char *buffer, size_t length,

loff_t *offset);static ssize_t device_write(struct file *filp, const char *buffer, size_t length,

loff_t *offset);static int device_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd,

unsigned long arg);

static int peek_buffer(struct minibuf_peek_t *pdata);

static int is_buffer_empty(void);static int is_buffer_full(void);static int read_buffer_char(char *buffer);static int write_buffer_char(char *buffer);static void make_buffer_empty(void);

�����

static int get_buffer_length(void);

/* * Device Operations */

struct file_operations device_fops = { NULL, /* seek */ device_read, /* read */ device_write, /* write */ NULL, /* readdir */ NULL, /* select */ device_ioctl, /* ioctl */ NULL, /* mmap */ device_open, /* open */ NULL, /* flush */ device_release /* release */};

/* * Module startup/cleanup */

int init_module(void){ printk("Loading Mini Buffer Module\n");

if ((s_nMajor = register_chrdev(0, DEVICE_NAME, &device_fops)) < 0) { printk(DEVICE_NAME " : Device registration failed (%d)\n", s_nMajor); return s_nMajor;

�����

}

printk(DEVICE_NAME " : Device registered with Major Number = %d\n", s_nMajor);

return 0;}

void cleanup_module(void){ int nRetCode;

printk("Unloading Mini Buf Module\n");

if ((nRetCode = unregister_chrdev(s_nMajor, DEVICE_NAME)) < 0) printk(DEVICE_NAME " : Device unregistration failed (%d)\n", nRetCode);}

/* * Device Operations */

int device_open(struct inode *inode, struct file *filp){ printk(DEVICE_NAME " : Device open (%d, %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev));

if ((filp->f_flags & O_ACCMODE) & (O_WRONLY | O_RDWR)) { if (s_bDeviceWriteOpen) { printk(DEVICE_NAME " : Device already open for writing\n"); return -EBUSY;

������

} else ++s_bDeviceWriteOpen; } else { if (s_bDeviceReadOpen) { printk(DEVICE_NAME " : Device already open for reading\n"); return -EBUSY; } else ++s_bDeviceReadOpen; }

MOD_INC_USE_COUNT;

return 0;}

int device_release(struct inode *inode, struct file *filp){ printk(DEVICE_NAME " : Device release (%d, %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev));

if ((filp->f_flags & O_ACCMODE) & (O_WRONLY | O_RDWR)) --s_bDeviceWriteOpen; else --s_bDeviceReadOpen;

MOD_DEC_USE_COUNT;

return 0;}

������

ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset){ int count = 0;

if (is_buffer_empty()) /* end of file */ return 0;

while (!is_buffer_empty() && length > 1) { read_buffer_char(buffer); ++buffer; --length; ++count; wake_up_interruptible(&s_wq); }

put_user(0, buffer); ++count;

printk(DEVICE_NAME " : Read %d bytes\n", count);

return count;}

ssize_t device_write(struct file *filp, const char *buffer, size_t length,loff_t *offset)

{ int count = 0;

if (is_buffer_full()) { printk(DEVICE_NAME " : Write go to sleep\n");

������

interruptible_sleep_on(&s_wq); printk(DEVICE_NAME " : Write wake up\n"); }

while (!is_buffer_full() && length > 0) { write_buffer_char((char *) buffer); ++buffer; --length; ++count; }

filp->f_pos += count;

printk(DEVICE_NAME " : Write %d bytes\n", count);

return count;}

int device_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd,unsigned long arg)

{ int length;

printk(DEVICE_NAME " : ioctl, cmd = %x, arg = %x\n", cmd, arg);

switch (cmd) { case IOCTL_MINIBUF_MAKEEMPTY : printk(DEVICE_NAME " : ioctl : make empty\n"); make_buffer_empty(); break;

������

case IOCTL_MINIBUF_GETLENGTH : printk(DEVICE_NAME " : ioctl : get length\n"); length = get_buffer_length(); put_user(length, (int *) arg); break; case IOCTL_MINIBUF_PEEK : printk(DEVICE_NAME " : ioctl : peek\n"); return peek_buffer((struct minibuf_peek_t *) arg); default : printk(DEVICE_NAME " : ioctl : unknown\n"); return -EINVAL; }

return 0;}

/* * Higher level buffer management */

int peek_buffer(struct minibuf_peek_t *pdata){ int count = 0, nBufPos; int maxlen; char *buffer;

if (is_buffer_empty()) /* end of file */ return 0;

get_user(buffer, &pdata->m_buf);

������

get_user(maxlen, &pdata->m_maxlen);

nBufPos = s_nBufPos;

while (!is_buffer_empty() && maxlen > 1) { read_buffer_char(buffer); ++buffer; --maxlen; ++count; }

put_user(0, buffer); ++count;

s_nBufPos = nBufPos;

printk(DEVICE_NAME " : Peek %d bytes\n", count);

return count;}

/* * Buffer Management */

int is_buffer_empty(void){ return (s_nBufPos == s_nBufEnd) ? 1 : 0;}

������

int is_buffer_full(void){ int pos = s_nBufEnd + 1;

if (pos == BUFFER_LEN) pos = 0;

return (pos == s_nBufPos) ? 1 : 0;}

int read_buffer_char(char *buffer){ if (is_buffer_empty()) return -1;

put_user(s_strBuf[s_nBufPos], buffer);

if (++s_nBufPos == BUFFER_LEN) s_nBufPos = 0;

return 0;}

int write_buffer_char(char *buffer){ if (is_buffer_full()) return -1;

get_user(s_strBuf[s_nBufEnd], buffer);

������

if (++s_nBufEnd == BUFFER_LEN) s_nBufEnd = 0;

return 0;}

void make_buffer_empty(void){ s_nBufPos = s_nBufEnd = 0;}

int get_buffer_length(void){ int pos = s_nBufEnd;

if (pos < s_nBufPos) pos += BUFFER_LEN;

return pos - s_nBufPos;}

������

! Filename : minibuf_test.c

/* Mini Buffer Test : ioctl*/

#include <stdio.h>#include <fcntl.h>

#include "minibuf.h"

#define BUFFER_LEN 1024

static void minibuf_read(int fd);static void minibuf_write(int fd, char *str);static void minibuf_peek(int fd);static void minibuf_ioctl_test(int fd);

static int minibuf_ioctl_get_length(int fd);static int minibuf_ioctl_make_empty(int fd);static int minibuf_ioctl_peek(int fd, char *buffer, int length);

int main(void){ int fd;

if ((fd = open("/dev/minibuf", O_RDWR)) < 0) { printf("Error opening device file\n"); return 1; }

�����

minibuf_read(fd); minibuf_write(fd, "Hello, World"); minibuf_peek(fd); minibuf_ioctl_test(fd); minibuf_read(fd);

close(fd);

return 0;}

void minibuf_read(int fd){ int len; char str[BUFFER_LEN];

while ((len = read(fd, str, BUFFER_LEN)) > 0) printf("READ : %s (%d)\n", str, len);}

void minibuf_write(int fd, char *str){ int len;

if ((len = write(fd, str, strlen(str))) > 0) printf("WRITE : %s (%d)\n", str, len);}

void minibuf_peek(int fd)

����

{ int len; char str[BUFFER_LEN];

if ((len = minibuf_ioctl_peek(fd, str, BUFFER_LEN)) >= 0) printf("PEEK : %s (%d)\n", str, len); else printf("PEEK : Error\n");}

void minibuf_ioctl_test(int fd){ int length;

length = minibuf_ioctl_get_length(fd); printf("Buffer Length = %d\n", length); minibuf_ioctl_make_empty(fd); printf("Make buffer empty\n"); length = minibuf_ioctl_get_length(fd); printf("Buffer Length = %d\n", length);}

int minibuf_ioctl_get_length(int fd){ int length;

return (ioctl(fd, IOCTL_MINIBUF_GETLENGTH, &length) >= 0) ? length : -1;}

int minibuf_ioctl_make_empty(int fd)

�����

{ return ioctl(fd, IOCTL_MINIBUF_MAKEEMPTY, 0) >= 0 ? 0 : -1;}

int minibuf_ioctl_peek(int fd, char *buffer, int length){ struct minibuf_peek_t peek_data = { buffer, length };

return ioctl(fd, IOCTL_MINIBUF_PEEK, &peek_data);}

�����

! ���0��#��:�0���0:�0����0���$�����@?��0�·Z�kla�J���y�z]�òó

��ÌN©��kl]� ���@?��0wp��J�a�1���y]�±16

��klZ_�@hB��1B��Ò×���\�y�z]�kl�~ñ�� �0���:���0�Jb

��� ��:��-��..��-�int ioctl(int fd, int cmd, ...);

��9����:��0������0�9���int (*ioctl) (struct inode *inodep, struct file *filp, unsigned int cmd, unsigned long arg);

���.����#������@� .@���0�65$

���0���{|��Ò×�a�V©3]�¸

{y���ß�Ò×��1½����� ��Z_��ºv��JB�ÐÑ3���vO�()

��òóp��Ѧ3@��-�.�ø«Z���(}]�åìa�B���S�16

�����0���.��]$�wm4� ��_IOC(direction, type, number, size)direction�����E��ø ò^

_IOC_NONE��_IOC_READ��_IOC_WRITEtype���.�-�����.��6�B������� ��31�~��

number����� ���0��Ò×��V©��y�z]�]$

size���ø ����E��74

#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size))#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))

�����

��:��9������..�����

FIOCLEX��� 0���� �������9��-FIONCLEX����������� �������9��-FIOASYNC��� 0@� 0�� ���5����� �?��0�9���05�9��FIONBIO����������4��-��@�

filp->f_flagsZ�� �E������;*�9��-a�_16fcntl(fd, F_SETFTL, fcntl(fd, F_GETTFL) | O_NONBLOCK));

�����0��H�� �����0��5������°yZ��'��� �.��Ò×Z�� �� ?�0�5�������H�switch (cmd) {case MYDRV_IORESET :

......case MYDRV_IOCLEAR :

......default :

return -EINVAL;}

�����

�����)�*+,

! printk()a��0���5

��Bk�`a+�òóp��ë���Å�>-�a���3@�[\��ôD�16

����-����

>-���fb��÷�3@��ë���fb��>-�w���3]�¿��B�3_��16

>-��-\Z� B�C�ÂU�òóp����6

��-������3���p¶� DEFAULT_MESSAGE_LOGLEVELZ��ß�16

console_loglevelÎ1�cU� ��-�����kw����16

sys_syslog� � 0.�������� klogd -c�Ò×p�� console_loglevel��jå6

��>-�����9�� �

printk()]��N�����Z�>-�a�4O�16�#��9��?�B�$

klogd���%�]��4�p�����>-�a�àt²�� syslogdZ_�ø-�16

syslogd]� /etc/syslog.conf�+,��÷�Z�� ����>-���H��òó�õ��

16�4ö�÷�U�>-�a� /var/log/messagesZ��k3]�¿�16

klogd -f <filename>�Ò×p�����>-�a��v��+,Z��k��y�z16

���5�?�Z�w�>-�a���3_�34� �

DEBUG���B�}��z��Åw�>-����� #���G�2/��§+,$

òó� �$#ifdef DEBUGprintk(..................)#endif

�����

òó� "$#ifdef DEBUG#define dprintk(fmt, args...) printk(KERN_DEBUG " : " fmt, ##args)#else#define dprintk(fmt, args...)#endif

! ë���ÅZw��Î���34

��printk()]�ë�3���U�>-�a�Ú����3_�3���Ú��Y03¶�-�.��dº­16

��:����+,-�.�/034� �

Y0$B��V��-SZ��Îa�wm���Y0$Z_�Î@»16

ɵ�?¢���<���N���Ea�Î@è�y�z���5��0�3_��16

�����0��/034� �

���0�Z��5�����Ò×�m���B�16

�5��ÎB��ß� ���0��Ò×��t]�Ye��tu¶�f�}���]16

:����+,-�.Î1�IvB�g���Y0òóZ�Jh��±16

! Y0$���� ��Y03]�9�Z���J�ôD34� �

���¨��Y0$���� �����16

��-�.�A���� ��a�Y03]�N©Z� printf()�p���Îa����16

��strace���� ���03@�-�.�°yB�³�]�¿��ÔY�16

-�.�AZ�ø-��D$9���õ9a�Î@»16strace cat /dev/minibuf

�����

! ��: ����Z��JB�ÐÑ3@�����i��Å� #R�������:���0����� $���: �>-�a����16

����: �>-�]�ZhB�ÐÑ��ir²�ï��E��<�� 0��4��<�f�w�����16

��ksymoops���� ���03@� ��: �>-�a��j����JB�ÐÑ��¾��:yz16ksymoops /boot/System.map < oops

��#��Zh���lw�Ìþ�k��y�z��l���ô��Ó����la�:º¶��mL��Ó�a

���Æ�3~��ß-��>?���<�f��Î@i���p���-�.���p���JB�ÐÑ

7��Å��¶Z� ��: �>-�a���3��C3¨���n��ÚU� ��: �>-�a���3@�>

-�B���B�\�yv�z16

��System.map���:��0��ÃÄlw�tu ���Z�m��z]�?��ÃÄmZ�Ì���Îa�B�~�z16

����§+,��Å�wm�­16

����9�?¢��ù°��ÃÄ�ÀO�wm4� �

System.mapZ]�����?¢��ÃÄ��m�z���p��� /proc/ksymsZ]�?¢�

ÃÄ��m�z�w���Z�� �:��0}��ÛU�ÃÄmZ�Ì���ÎB�±16

��0�@:���@4 �. �@���0@�� 0.6.�:�N� ��� @�6�@�@��N��?4��L:���0�O���APA��O"M��N� ��0����C� �.��� 6.�:

! *������.:�

��4. -��.:�������i��Å� ������>-�²� ��: �>-�a�á�SZ��k�16

�� .���� ������i�������#���$a�o�3@� ��+Z��k��3~�����>?�Z��

�}�� zp� *�+� ��� ����� ����0a� �16� ����0¤Z� �øZ� ��+Z� �k�

���a��B�� � 0.��������03@�o���q~��7Z��k��y�z16

��kS� �

�����

��0���:0����0�0Z�v�Y0��y�z16

��+Z��k��34��Z�g�16

��#S� �

÷lB��r16

����0-Z�>?���0���d��]��16

���*;�� #������*����;�����.:�$� ���;����7��4��� /03@����� i�� � ���a

?�:� :��0�0���Z��k���16� �;��� �������J�Å�Z� ��0���:0�sZ��ZhB�ÐÑ�

åì�Y0��y�±16

! 4������Z� ���4�� 4�������--�

��;,2Z�� 9���0B�ÐÑ3¨���,�2�G�úa���¨��� �������� ��������Ï��16

��4���������0���:0�� �������0���:0�ÛZ��H��16

�� ��-�� 0:�����4:���0a��0���5��B�

������ �.����lw�tu � .������ �.���v�:~�z��?¢��5v�B�316

�� 0��4Z�� 9��.�:���0�a��03@� 0��4�0���a���yv�z16

! 4-�����.�0�-������ ����������|[��J��16

�� !� Ì�� 4Ha� ������ Õõ3~� �s� 4HZ� �5�� ���� 1½� 4HZ�� -��a� ¹

�16

�� ���� ���--��-� �.����� ù°3@� §+,3~� 9��.� :���0�a� �03vO� §+,3@

G�<������w�16

�����

�� ��-�� 0:�����4:���0a��0���5�B�6

���5����Å�1½�4HB�ë�3~��÷lB��ºì���?¢��ira�ôD3��C�16

! +�-����� �Q�*�

��ɵ��<a�Î@i]�ú� �

�5�90R��������� 5�?�..���;0��R��������� 5�?� 0�0��0�R���������� 5�?��-� 0�

��çy��ú�WQ������çy��[\��3vO���y�z16

�����÷�����Å� +�-����� �Q�����ü��§+,�Æ��16

Y0ó� ����0R�� �QRB��..���C

��..������#����.�0�0���@ � �Q60�0$� ���� ��������.���0��9�� � 0.������ 5�0��99�.������.:������0�..���

����

���!�-�.�/�0�+�1�234

! ��Z���-"� �

���P;�#����P�.�;���4$���-�.Z��ɵ�-"��c�3]�kl

�� ��U� 0�.�� ��0���:0B� ÐÑ�� Å31� �N�� -"�� c�3]� ��Ea� =B-ü� ɵ

-"��c��16

��HZ�����Z� 0�.����0���:0B�ÐÑ3]� y6�#������@�����@:���.65$

��jiffies���+L«JB�N£��¤�ÐÑ��tM� 0��4�� y6���>�99� �H��@3S��

��0�.����0���:0��ÐÑ�"u�W�� �

HZ�¸�=B� ��Iv]�dº��w�®X�Iv]�v ­16

HZ�¸�?r� ��Iv]�v ��w�®X�Iv]�dº­16

! ɵ�-"� �

��do_gettimeofday()�°ya����� ������.���� �����#���-"��1��y�z16

���N�p��ɵ�-"��B�~�z]� struct timeval xtime�X�jyB�z�w����

���N�$0VWa�no�o�3]�¿U�en3���16

��ɵ�-"�14� �struct timeval {

time_t tv_sec;suseconds_t tv_usec;

}

#include <linux/time.h>void do_gettimeofday(struct timeval *tv);

�����

! ���-�������òó� ������ ��?��0��-

41�]�[ÛZ����?�Z�HI�z�Æ�3���1½�\Á��{|��y�±�6

unsigned long j = jiffies + delay * HZ;

while (jiffies < j);

��òó� "��

1½�{|����%�B�±p¶�HI�$¡��MØ}��{|w6

while (jiffies < j)schedule();

��òó� 8��

0�.��0���03@��3]�-"[� ����4��-��}��Bk�xy��16

@4�� 0�.��0U��Õ��-"� #>�99� �R�αB�tu $

struct wait_queue *wq = NULL;

interruptible_sleep_on_timeout(&wait, timeout);

! �5��0�������������#$�#������@� .@����65$

��:��0�0�:���void udelay(unsigned long usecs);��>�99� �Î1�'�TU�-"�� ����a�����Y0�16

�� N£�� Å� HÖ�� ��-�+�: a� zp�� loops_per_secondsa� HÖ3~�� �a� zp

������

���3]�-"[�� ����a����r�GI��p�� ���:a�{16

���� ��?��0��-���� �����H��(((�.��� ��������.��� �����H��(((�.���� ����

! ���:�;

���5�ç��\Á��{|��-"����3@�,��-"��å9��¤Z�{|3_��16

��:�;�=Z�m�"�\ÁU���w�{|�16

��|K�òN��:�;� ��~���}y��:�;a�Jb�16struct timer_struct {

unsigned long expires;void (*fn)(void);

};

unsigned long timer_active;struct timer_struct timer_table[32];

��*�+�òN��:�;� �����4���� 0�òNp��}yZ�J���±16struct timer_list {

struct timer_list *next; /* MUST be first element */struct timer_list *prev;unsigned long expires;unsigned long data;void (*function)(unsigned long);

};

void init_timer(struct timer_list * timer)void add_timer(struct timer_list * timer);int del_timer(struct timer_list * timer);

������

! Filename : mytimer.c

/* Timer Handling*/

#include <linux/kernel.h>#include <linux/module.h>

#ifdef CONFIG_MODVERSIONS#define MODVERSIONS#include <linux/modversions.h>#endif

#include <linux/sched.h>#include <linux/timer.h>

/* * type definitions */

struct mytimer_data { int m_times; int m_endtimes;};

/* * global variables */

������

static struct timer_list s_mytimer;static struct mytimer_data s_mytimer_data;

/* * function prototypes */

static void mytimer_proc(unsigned long ptr);static void add_mytimer(void);static void del_mytimer(void);

/* * Module startup/cleanup */

int init_module(void){ printk("Loading Timer\n");

s_mytimer_data.m_times = 0; s_mytimer_data.m_endtimes = 5;

add_mytimer();

return 0;}

void cleanup_module(void){ del_mytimer();

������

printk("Unloading Timer\n");}

void mytimer_proc(unsigned long ptr){ struct mytimer_data *pdata = (struct mytimer_data *) ptr;

++pdata->m_times;

printk("Timer called %d/%d\n", pdata->m_times, pdata->m_endtimes);

if (pdata->m_times < pdata->m_endtimes) add_mytimer();}

void add_mytimer(void){ init_timer(&s_mytimer);

s_mytimer.function = mytimer_proc; s_mytimer.data = (unsigned long) &s_mytimer_data; s_mytimer.expires = jiffies + HZ * 5; /* 5 seconds */

add_timer(&s_mytimer);}

void del_mytimer(void){ del_timer(&s_mytimer);}

������

! ;��0�0��� �����0�0��� � 0.�������0��:�H��ɵ�����[\��ɵ���%�3~�cé��z��Å6

����4��-��B�316

schedule()�°ya�³h��1½���%�B�{|}_���y�z16

����0���:0����0�0���DEFG�ÙmhZ��DEFGa�H�3~�z]�����]�ɵ���%�²

�c3_�.���-SZ�{|}]�DEFG²�ñY���66

��5���?�����0���:0����0�0���DEFG�ÙmhB�H�}~�z�� Å���ß� DEFGB�~

����<Z��{|}���åìZ�� �1½�DEFGB�~�}4v��16

�� �90?�����0���:0����0�0���DEFGB�Z0���<Z��{|}�����00�.�5��9��0�.���ç�

0� 4�Q��H��.���-SZ�{|�16

����0���:0����0�0Z����y�±]�,� �

�����0�:��� 3~�cé}]�,� �������0�:��� B���B�±16

�����0�:��� B�±pË�� � �� :��²���E�ªä����y�±16

�5�����-��� �5���#$�°ya�N�¨���"o�p��Na�y�z]�°ym6

?�:��ÐÑ��y�z]�,� ��>?���ßÂ�� �0�.����:��0�����tí�¿m6

� ��..���Z�� :�-�9���0B�ÐÑ��y�z]�,� ����:�E0�E� �#$Â��Y0$�>?

�a�o�3]�°ym6

! P� 4�=����ç��\Á���d�v�-"����¤Z�{|3]�òó����3��16

��:�����-��H�3¨���3�I�a���3_�J���Å�Y0�16

�� ��00�.� 5��9H�� ��0���:0a�H���Å� ��0���:0� 5�����a�H���¤Z��U�\Á��H��

Åv�Y0�16

������

��0� 4�Q���$0VW� �����4���� 0�È<struct tq_struct {

struct tq_struct *next; /* linked list of active bh's */unsigned long sync; /* must be initialized to zero */void (*routine)(void *); /* function to call */void *data; /* argument to function */

};

��0� 4�Q���°y#define DECLARE_TASK_QUEUE(q)

*�+�<�7�=a����16void queue_task(struct tq_struct *bh_pointer, task_queue *bh_list);

<�7�=Z�<�7a��B�16void run_task_queue(task_queue *list);

=Z�z]�?��\Á��{|�16

��:��9����0� 4�Q�� ���-�.�[\�������������U� 0� 4�Q��m6

tq_timer���:�;�DEFGB�ÐÑ3&��Å�H�}]�=� #��0���:0�0�.$

tq_immediate���B����g½�-"�Z�H�}]�=� #��0���:0�0�.$

tq_scheduler������hB�{|æ�Å�H�}]�=� #��0���0���:0�0�.$

! >?���� ����4.�������49��#������@�����@ ���65$void *kmalloc(size_t size, int priority);

malloc()H� ����74wA��>?�a���16void kfree(const void *ptr);

free()H� malloc()p� �ßàU >?�a��J�16

��:�����0����>?���ß�òN�����16

������

GFP_KERNEL : (__GFP_MED | __GFP_WAIT | __GFP_IO),®�p��Y03]� :�����0��� ����4��-��,�K�y�z16

>?�B�N�3¶� ?�:�f������>?��b"��w�16GFP_USER : (__GFP_LOW | __GFP_WAIT | __GFP_IO)GFP_NFS : (__GFP_HIGH | __GFP_WAIT | __GFP_IO)

�<��+,-�.Z��}vO�v��>?�a��ßà��Å�Y0�16GFP_ATOMIC : (__GFP_HIGH)

��0���:0�0�.Z��Y0� # �5�����-��,���]�Û}]�åì$

__min_free_pages²��c3_�B���?��>?��Y0�16GFP_DMA : (__GFP_DMA)

�+��>?����16

���p�� � +���3��L�Z�ÕI��>?�a��ß�16

�� �1��

��Z�]� :�-�:������03@�^��a�c��16

:�-�����0��������0��������+��Bk�ñÕ3_�Y0��y�z]�òó

������������0������������Â�� :�-�����0��òNZ�]�c�34��r16

PAGE_SIZE�D�"T�Î1�W~�\U�74��>?���ß��Bk�xy��16

74J���z1� ���"%*�

! >?���� ��:�-�#������@�����@..65$unsigned long get_free_page(int gfp_mask);

��^��a��ß��¤� :�-a��+16unsigned long __get_free_page(int gfp_mask);

��^��a���16

������

unsigned long __get_dma_pages(int gfp_mask, order)�+�0�>?��^��a���16

unsigned long __get_free_pages(int gfp_mask, unsigned long gfp_order);����74wA��^��a���16

void free_page(unsigned long addr);��^��a��J�16

void free_pages(unsigned long addr, unsigned long order);@h�^��a��J�16

! >?���� ��.�������9��#������@�����@.�����65$void * vmalloc(unsigned long size);

B��ir�b"Z��>?�a���16void vfree(void * addr);

vmalloc()p���ßàU�>?�a��J�16

��B��ir�b"#��0�������� � :��$Z��ÕI��>?��L����ß�16

kmalloc()U�����ir�b"Z��>?�a���16

���p��ÕI}���U�>?�v�B��ir�b"Z�]�ÕI�p��Ä�y�z16

:�-�0������03@�����ir��jä�16

�����>?��b"Z�w��]�L��16

�����D�b"Z�w�ÕI}�����l���ßàU�>?�]�,Â��Y0��y�zp���ÌN

©��åì��ß�U�>?�B����p��ÕI}�Æ���ë�]�±16

�� r�GI��p�w� Y03]� Ü� ��a� �ßà�� Å� Y0�1� #74� J��� kmalloc()Î1�71$

�����

���5&�������� ��!�"�6�7�8(

! À�� �� �5� ç��� -�.� A�� ³��� Å� �a� B�C�� 1½� ,�� 3vO� �16� @4�]

sys_open()9� sys_close()� -�.� A�� B�C��� -�.�� Û�¦�� ���� -�.� A�

³�]�w�ôD3~������-�.�A�H��°ya��Ì��³h»16

! VÉòó� ��ø«�-�.�A�Ùmh��ÀO��B�~�z]� sys_call_table��E���0��n

o�y�3@�� �:��� ��� �-�.�A��Ùmha��k3~����� ��Z�*��J\��Ùmh�

Ìl�16�Ìl��ÙmhZ�]�'���D$��¸����3~������-�.�A�Ùmha�³h

��\Á��H���¤�õ9¸��Î@»16

! 6�G�òó� ��?¢������¤� �:��� ��� �-�.�A��³\�Å31�>-�B���}]��ô

D�16

! 9�� �

���:������ �-�.�A��B�C4

��1½�-�.�A��B�C4

! 6�G�9�� �insmod syscall.olsrmmod syscall

������

! Filename : syscall.c

/* System Call Spy*/

#include <linux/kernel.h>#include <linux/module.h>

#ifdef CONFIG_MODVERSIONS#define MODVERSIONS#include <linux/modversions.h>#endif

#include <sys/syscall.h>#include <asm/uaccess.h>

/* * Global Variable */

extern void *sys_call_table[];

static asmlinkage int (*orig_sys_open)(const char *filename, int flags, int mode);static asmlinkage int (*orig_sys_close)(unsigned int fd);

/* * Function Prototypes */

�������

static asmlinkage int my_sys_open(const char *filename, int flags, int mode);static asmlinkage int my_sys_close(unsigned int fd);

/* * Module startup/cleanup */

int init_module(void){ printk("Loading System Call Spy Module\n");

orig_sys_open = sys_call_table[__NR_open]; sys_call_table[__NR_open] = my_sys_open;

orig_sys_close = sys_call_table[__NR_close]; sys_call_table[__NR_close] = my_sys_close;

return 0;}

void cleanup_module(void){ printk("Unloading System Call Spy Module\n");

if (sys_call_table[__NR_open] != my_sys_open || sys_call_table[__NR_close] != my_sys_close) { printk("Error : other program changed the system call handler\n"); }

sys_call_table[__NR_open] = orig_sys_open;

�������

sys_call_table[__NR_close] = orig_sys_close;}

/* * System Call handler */

int my_sys_open(const char *filename, int flags, int mode){ int retcode; char fname[1024], *cpsrc = (char *) filename, *cpdes = fname;

for (;;) { get_user(*cpdes, cpsrc); if (*cpdes == 0) break; ++cpdes; ++cpsrc; }

printk("sys_open : pid = %d, filename = %s, flags = %x, mode = %x\n", current->pid, fname, flags, mode); retcode = orig_sys_open(filename, flags, mode); printk("sys_open : result = %d\n", retcode);

return retcode;}

int my_sys_close(unsigned int fd){

�������

int retcode;

printk("sys_close : pid = %d, fd = %d\n", current->pid, fd); retcode = orig_sys_close(fd); printk("sys_close : result = %d\n", retcode);

return retcode;}

�������

! -�.�A� �

��Y0$�?�Z�z]�X0��� ������4���Y0��y�zvO�3]�¿

��-�.�A��N�¶�Y0$�?�Z�����?���916

����Z��-�.�A��H�3¶����?�Z��Y0$�?������\Á��HI�16

��-�.�A��P�� �

include/asm/unistd.hZ���}��z16

! -�.�A��H�9�� �

�����8"Z�� � 0.�����U� (�%(�DEFGa��3@�H��16

��Y0$���� Z�� � 0.�������N�¶�DEFGB�ÐÑ�16

��(�%(�DEFG�Ùmh]� system_call�#���5@�8% @4���@�0��6�$�16

�� system_call� °y]� 'D»� � 0.� ����� �Ï#U��$Z� � � sys_call_table[]Z� z]

°ya�Ï��16

����-�.�A�H��°y]��ß�Ò×��{|3~�õ9a�¹º»16

��ret_from_sys_call�°ya���� � 0.�������3l~�Y0$�?���(��16

�������

����9:;<�=4

! DEFG��klB� ;,2Z_� �0B�ÐÑ7���:ºi]�òó

��� ���5����� ��0��:�����-@��0���:0

:�����-���kl��j�a�i4�p��?-����<��j�a�:t�16

��0���:0���klZ�¡åî���~�\Á��31B��<�j�B�z��Å�klB�:º»16

���+�]�DEFG²�ÕH���Y0�16

! DEFG�Ùmh��fO9���� ��#������@�����@ �5�65$int request_irq(unsigned int irq,

void (*handler)(int, void *, struct pt_regs *),unsigned long flags,const char *device,void *dev_id);

irq���DEFG��Ï6

handler���DEFGa�H���Ùmh�°y

flags���DEFG�c�²�cé�� 9��-

SA_INTERRUPT���9� 0���0���:0@ ��?���0���:0a�V�34����Y06

SA_SHIRQ���DEFGa�bñ��y�z1]�¿���:F16

SA_SAMPLE_RANDOM� �� �����.�¸��w�]��4@�16�kl��DEFGB�`�

4�p��ÐÑ3]�åì� �����.�¸��w�]��v����16

device���DEFG�rñ$a�/-��Å��:���$Þ

�������

dev_id���DEFGa�bñ��Å�$¡��V�34�����Y03]�ñ,��¸6

ÙmhZ_���Ea�ø-3]�À�p�v�Y0��y�z16void free_irq(unsigned int irq, void *dev_id);

DEFGa�®��16�fO��Å����� ��Q�²� �E��a��Ì�����16

��DEFGa�fO@����-S� �

���0E.�������?¢��Y03���' v�DEFGa�Sñ3]��JB�ÐÑ

�:����DEFGa�1½���� ��Y03~�zp¶�Sñ3��C��yv�z16

fO� ��H�p��kla� �:���ÅZ�DEFGa�fO

��� ��3�@p�� ��� a����DEFGa���

��@:���@��0���:0

ɵ�Sñ3~�z]�DEFG��ÀO��Î@»16

! ��=���:t�4

��÷�B��� ��=���,;�Z�]� ��=B�-�.Z������ß�16

kl��ÎZ��k��DEFG�÷�����²��Y0�16

��~��� ��=������Z�]� ��=B�3�I��p��~�}��z16

/»�D�òóp�� ��=a�:t��yB�±16

�$�?¢������Å� ��=���@��ira�D$��ø-�16

"$�kl�� �@��L���¸��Z� ��=��ÎB�z]�åì��a����16

8$�kl�ç¦���03@� ��=��Ïa� :�����-�16

����=�:�����-���#������@�����@��0���:065$unsigned long probe_irq_on(void);

ɵ��ß}���U�DEFG�� ��0.� 4a�¹º»16

{�3¶� (��¹º»16

�������

int probe_irq_off(unsigned long);:���E���¤Z�ÐÑ��DEFG��Ïa�¹º»16

DEFGB�ÐÑ3���p¶� (��¹º»16

@h���DEFGB�ÐÑ3¶� #�.��-��� ��0�0���$��ya�¹º»16

:����34ø� ��probe_irq_on()��N½16

kl��ç¦���03@�3�I��p��DEFGa�ÐÑ->16

:���a�3l~� ��probe_irq_off()a�N½16

! DEFG�Ùmh�VÉ� �void handler(int irq, void *dev_id, struct pt_regs *regs);��DEFG�Ùmh]� 5���?�����0���:0����0�0Z��{|�16

��DEFG�H��-"�� r����16

DEFG�ÙmhZ�]��ß�DEFGB�~����<Z��{|�16

9� 0���0���:0��åì�?��DEFGB�~����<Z��{|�16

-�.���/��\Á�����]�DEFG�H��-"��T��yO�ý16

DEFG�H�Z�-"��Ú��ë���åì�DEFG�H�a�DEFG�ÙmhZ��H�

�Æ�3]�N©9������tv�}]� N©p������� ��N©U� ��00�.�5��9�� 0� 4

Q��a��03@�H��16

! DEFG�Z09�~�� ��#������@� .@��Q65$void disable_irq(unsigned int);

��DEFGa�~��16void enable_irq(unsigned int);

DEFGa�Z0�16

�������

��?��DEFG�Ùmh]�ɵ�H��D�DEFGB�~����<Z��H��16

��DEFG�Z0@~�]�DEFG�ÙmhZ��Y0��y�±16

��9� 0���0���:0@ ��?���0���:0

9� 0� ��0���:0� �� ?�� DEFGB� ~��� �<Z�� DEFGa� H��16� DEFG� H�

v�Z� 1½� DEFG]� ÐÑ3�� �]16� v�� H��Æ3]� DEFG� H�-Z

Y0�16

��?���0���:0���1½�DEFGB�Z0���<Z��DEFGa�H��16

! ��00�.�3��9

����0���:0�5�����Z��H��Æ�3]�\Á��ÚU�åì��®�-� ��0���:0�5�����Z��H�3�

�tv�}]�,�� ��0���:0�5�����a�g����¤�{|��y�zvO��16

��0�:�5��9�@���00�.�5��9

0�:�5��9Z�]�kl����Ea��v����Z��k3~� ��00�.�5��9a�/-�16

��00�.�5��9]�vJ����Ea���%�Z_�ø-�16

����00�.�5��9�H��v�Z]�?��DEFGB�Z0�16

����00�.�5��9�V� ��#������@�����@��0���:065$

9���0����:���0���ÝÞ9�Y0@N²�H�@Na��:�]� ��0.� 4��wm�­16volatile unsigned char bh_running;atomic_t bh_mask_count[32];unsigned long bh_active;unsigned long bh_mask;void (*bh_base[32])(void);

����00�.�5��9�c�y� ��#������@� .@ �90��Q65$void init_bh(int nr, void (*routine)(void))

��00�.�5��9a�fO�16

������

void remove_bh(int nr)��00�.�5��9a����16

void mark_bh(int nr)��00�.�5��9a�H��Æ�3]�åì�³h»16

void disable_bh(int nr)� ��00�.�5��9�H�a�~��16

void enable_bh(int nr)� ��00�.�5��9�H�a�Z0�16

void do_bottom_half(void)��00�.�5��9�H��°y6��0���E9��.E � E����#$Z��³�16

����00�.�5��9��� �

��00�.�5��9��}y]���}��z16

ÌN©�ç������ ��Z_��ß}��z16

����Z��Y03]� ��00�.�5��9��

IMMEDIATE_BH���0QE�..���0a�H��16

TQUEUE_BH���0QE0�.�a�H��16

NET_BH����0?��4�����Z��Y0�16

CONSOLE_BH���00�� ?�0�5��-TIMER_BH���0�.����0���:0�H��¤�Ï�}���4����0�.�a�H��16

! DEFG�bñ� �

��DEFGa�Sñ��Å�DEFG�bñ�@Na�÷��16

�� ���� ��DEFG�bñZ�Ì�������¿U�±�w��3�I��p��DEFG�bñB�³B

�3�]� �16� 3�I��p�� klZ� DEFGB� ÐÑ7]�� @Na� ôD�� y� z]

������

òó��z1¶�r�GI��D�òóp���õ��B�316

��,;�����hZ��4ö�p��DEFG�bñB�B�3vO�÷H}��z16

����0���:0�5�����

DEFGB�ÐÑ3¶�DEFGa�bñ3]�?��ÙmhB�³�16

DEFG�ÙmhB�³���Å�®�-�$¡��DEFGB�ÐÑ��¿U�tu16

3�I�a�ÔY3@�DEFGB�$¡��klZ��ÐÑ��åìZw�DEFGa�H�

! ���������0�������Ó�B�DN3��C��Y�Z�$¡��1q]���EB� ��0���:0�0�.Z��~���ß�Ó�]

��Ea�j�a�DN3��C3~�H�a�HI3]�åì6

������������0�.����:��0���9�1½�Ó��Y�Z���B����H�3��åi6

�����������0�����ÐÑ3]�åì� �

°y��Z�� �5�����-��ÐÑ� ��n@"o�p�� �5���#$�°yB�³��åì6

����4��-��:��0���

DEFG�Ùmh²�-�.�A��1½�Ó�²���Ea�bñ3]�åì

�����������0�����õ� �

b�Ea�Y03���~�����a�Y0�16

b�Ea�y������[�DEFGa�~�->16

��Ea�o���� ���4��Y0��� �0�.����:��0���p��w�16

�������

����'�>?�@?

! 3�I��J�Z�Y03]�$�� �

���@��,��0�����@��+.���������0���:0���+�

! �@��,��0�J�� ��#������@� .@��65��������@�����@��:��065$

���@��:��0�L���� �

�@��L���Y034�øZ��ß�L���1½�� ��B�Y03]��ÔY�16

{J�� �ß�� à�� �$1~� ��� �ß� L��� o��� y� ±]� ¿U� tu�w�� ��

v� kl� Y��� �¹�� @4� ���� L��� ÔY3~�� Y0�D� åì� Zha� ÐÑ

3]�¿��ý16int check_region(unsigned long from, unsigned long extent);

�ß� �@��:��0�L���`�z]��ÔY�16void request_region(unsigned long from, unsigned long extent, const char *name);

�@��:��0�L����ßà]16void release_region(unsigned long from, unsigned long extent);

�@��:��0�L���Y0��3l~�$���®��16

��3�����E� �@�unsigned int inb(unsigned int port);void outb(unsigned char data, unsigned int port);

�������

%���0���E� �@�unsigned int inw(unsigned int port);void outw(unsigned short data, unsigned int port);

� ���0���E� �@�unsigned int inl(unsigned int port);void outl(unsigned int data, unsigned int port);

8"���0���E� �@�

��3��� :��0��ÕI����E� �@�unsigned int insb(unsigned int port, void *addr, unsigned long count);void outsb(unsigned int port, void *addr, unsigned long count);

%���0���E� �@�unsigned int insw(unsigned int port, void *addr, unsigned long count);void outsw(unsigned int port, void *addr, unsigned long count);

� ���0���E� �@�unsigned int insl(unsigned int port, void *addr, unsigned long count);void outsl(unsigned int port, void *addr, unsigned long count);

8"���0���E� �@�

��:�� ��-��@�

;,2��Iv]� �@���� ��IvÎ1�g�16

|K�3�I���Z]�Iv¯��Å�Z� :��0��@�Z����Ea��l]�åìB�z16

inb_p()��outb_p()�ÂU�°ya��03@� �@��Y�Z� ����a�èyz16

! �@��+.����J�� ��#������@� .@��65$

���@��..����L���� �

��0���:0�� �@��:��0Z�²�ÂU�L���ß�>�u�U�±16

���@��..�����@�

�������

unsigned int readb(void *addr);void writeb(unsigned int data, void *addr);

%���0���E� �@�unsigned int readw(void *addr);void writew(unsigned int data, void *addr);

� ���0���E� �@�unsigned int readl(void *addr);void writel(unsigned int data, void *addr);

8"���0���E� �@�void memset_io(void *addr, unsigned int data, int count);

����74wA�������E��÷�void memcpy_fromio(void *dest, void *src, int count);

�@��>?�Z�� ��+p����E�ø void memcpy_toio(void *dst, void *src, int count);

��+Z�� �@��>?�����E�ø 

���@��..����.�::��-

,;��klÂU�¾Z�]� ..����.�:������ �@��>?�a�o��16void * ioremap (unsigned long offset, unsigned long size)

�@��>?�a�B��>?��ir�� .�::��-���16void iounmap(void *addr);

.�::��-��>?�a��J�16

! �+��J�� ��#������@� .@�.�65$

���+��L���� �int request_dma(unsigned int dmanr, const char * device_id);

�+���5�������V�16��5����U� (�&G��B�316

�������

void free_dma(unsigned int dmanr);

�+���5������®��16

���+������� �kmalloc(size, GFP_DMA);get_dma_pages(mask, pages);

���+��Y034� �void enable_dma(unsigned int dmanr);

�+���5����Z�ñx����EB�z1~�/-�16void disable_dma(unsigned int dmanr);

�+���5������ �� ����->16void set_dma_mode(unsigned int dmanr, char mode);

�+�a��3@���Ea��������a����16void set_dma_addr(unsigned int dmanr, unsigned int a);

�+������ira����16void set_dma_page(unsigned int dmanr, char pagenr);

ø ��ir�� :�-��-� 0�w��÷��16void set_dma_count(unsigned int dmanr, unsigned int count);

ø ����E��74a����16int get_dma_residue(unsigned int dmanr);

�+�a�����ø ����E��Z���U�]$a�:º»16

�+��Ò×��¦b�@Na�:º»16void clear_dma_ff(unsigned int dmanr);

�������

���� A�������� ���������������BC����������

! À�� ��"#��LM� ��a�w�16�@4�]�{J�LM�kla�Y03���~�� ��+��Z

,N�>?�a��7H��/03]�"#�� ��+��7a�w�16

! VÉòó� �� �$� ��� � ��²� 3�B��� +,� ÕÖ�� ��3~� �a� fO�16� �Å

+,�ÕÖ��Z�� ���@?��0]�,®�D�LM� ���@?��0�°ya��0�16���~�LM���

� ���VÉZ�ë��� �Q� 0�°y²�LM�74���E�74��kl�74�f�����16�?¢�

����Å� ��+��7a����>?�a��ß�16� ��+��7��74]�?¢Z�~�}��z

p��� ?¢�� �������� Å� �ßàU� >?�a� �J�16� �Q� 0� °yZ�]� ���-�� ��²

�ßàU�>?��Y�Z� ���@?��0a�y|�16

! 6�G�òó� ��?¢������¤�LM����� ��a�B�ú]�kl�+,��w�16�@4

�]� �GF�;GE�2+� }ywA�� .����� ��.��a� Z034� �Z� @h��� kl� +,�� wm

y� z16� .4"9 � Ò×p�� kl� +,�Z� +,-�.�� w�� ¤� .���0a� ��� +,-�.H�

Y0���16

! 9�� �

��"#�� ��+��7�LM����� ���J\

����+��7��Z�+,-�.�V����6�G

�������

! 6�G�9�� �insmod minird.o minird_size=1024mknod /dev/minird0 b [major] 0dd if=/dev/zero of=/dev/minird0 bs=1024 count=1024mke2fs /dev/minird0 1024mkdir /mnt/othermount /dev/minird0 /mnt/othercp /bin/ls /mnt/otherls /mnt/otherumount /mnt/othermount /dev/minird0 /mnt/otherls /mnt/otherumount /mnt/otherrmmod minird

�������

! Filename : minird.c

/* Mini RAM Disk Driver*/

#include <linux/kernel.h>#include <linux/module.h>

#include <linux/vmalloc.h>#include <asm/uaccess.h>

#define MINIRD_MAJOR 0 /* major number : dynamic allocation */#define DEVICE_NAME "MiniRD" /* device name */#define DEVICE_NUM 2 /* minor device number */

#define MINIRD_DEF_SIZE 1024 /* default device size in KB */#define MINIRD_BLOCKSIZE 1024 /* sizeof block */#define MINIRD_SECTSIZE 512 /* sizeof sector */

extern int s_nMajor;

#define MAJOR_NR (s_nMajor)#define DEVICE_REQUEST minird_request#define DEVICE_NR(device) (MINOR(device))#define DEVICE_ON(device) /* do nothing */#define DEVICE_OFF(device) /* do nothing */#define DEVICE_NO_RANDOM

#include <linux/blk.h>

�������

/* * Globak Variables */

static int s_nMajor = 0;static int minird_size = MINIRD_DEF_SIZE;

static int s_kbsize[DEVICE_NUM]; /* size in blocks of 1024 bytes */static int s_blocksize[DEVICE_NUM]; /* size of 1024 byte block */static int s_hardsect[DEVICE_NUM]; /* sizeof real block in bytes */static int s_length[DEVICE_NUM]; /* size of disks in bytes */static char *s_data[DEVICE_NUM];

MODULE_PARM(minird_size, "i");MODULE_PARM_DESC(minird_size, "RAM Disk size in KB");

/* * Function Prototypes */

static int minird_open(struct inode *inodep, struct file *filp);static int minird_release(struct inode *inodep, struct file *filp);static int minird_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd,

unsigned long arg);

static void minird_request(void);

/* * Device Operations

������

*/

static struct file_operations minird_fops = { open : minird_open, release : minird_release, read : block_read, write : block_write, ioctl : minird_ioctl, fsync : block_fsync,};

/* * Module startup/cleanup */

int init_module(void){ int i, j;

printk("Loading Mini RAM Disk Module\n");

for (i = 0; i < DEVICE_NUM; ++i) { s_kbsize[i] = minird_size; s_blocksize[i] = MINIRD_BLOCKSIZE; s_hardsect[i] = MINIRD_SECTSIZE; s_length[i] = (minird_size << BLOCK_SIZE_BITS);

if ((s_data[i] = vmalloc(s_length[i])) == NULL) { for (j = 0; j < i; ++j) vfree(s_data[j]);

������

return -ENOMEM; } }

if ((s_nMajor = register_blkdev(MINIRD_MAJOR, DEVICE_NAME, &minird_fops)) < 0) { printk(DEVICE_NAME " : Device registration failed (%d)\n", s_nMajor); return s_nMajor; }

printk(DEVICE_NAME " : Device registered with Major Number = %d\n", MAJOR_NR);

blk_dev[MAJOR_NR].request_fn = &minird_request;

blk_size[MAJOR_NR] = s_kbsize; blksize_size[MAJOR_NR] = s_blocksize; hardsect_size[MAJOR_NR] = s_hardsect;

return 0;}

void cleanup_module(void){ int i;

printk("Unloading Mini RAM Disk Module\n");

for (i = 0; i < DEVICE_NUM; ++i) destroy_buffers(MKDEV(MAJOR_NR, i)); /* flush the devices */

for (i = 0; i < DEVICE_NUM; ++i)

�������

vfree(s_data[i]);

unregister_blkdev(MAJOR_NR, DEVICE_NAME);

blk_dev[MAJOR_NR].request_fn = NULL;

blk_size[MAJOR_NR] = NULL; blksize_size[MAJOR_NR] = NULL; hardsect_size[MAJOR_NR] = NULL;}

/* * Device Operations */

int minird_open(struct inode *inodep, struct file *filp){ if (DEVICE_NR(inodep->i_rdev) >= DEVICE_NUM) return -ENXIO;

MOD_INC_USE_COUNT;

return 0;}

int minird_release(struct inode *inodep, struct file *filp){ MOD_DEC_USE_COUNT;

return 0;

�������

}

int minird_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd,unsigned long arg)

{ int minor = DEVICE_NR(inodep->i_rdev); long devsize;

switch (cmd) { case BLKGETSIZE : /* return device size */ devsize = s_length[minor] / s_hardsect[minor]; return put_user(devsize, (long *) arg);

case BLKSSZGET : /* block size of media */ return put_user(s_blocksize[minor], (int *) arg);

case BLKFLSBUF : /* flush */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; destroy_buffers(inodep->i_rdev); break;

RO_IOCTLS(inodep->i_rdev, arg); /* default ioctl for BLKROSET, BLKROGET */

default : return -EINVAL; }

return 0;}

�������

/* * Request Processing */

void minird_request(void){ char *ptr; int size, minor;

while (1) { INIT_REQUEST;

if ((minor = DEVICE_NR(CURRENT_DEV)) > DEVICE_NUM) { printk(DEVICE_NAME " : Unknown Minor Device\n"); end_request(0); continue; }

ptr = s_data[minor] + CURRENT->sector * s_hardsect[minor]; size = CURRENT->current_nr_sectors * s_hardsect[minor];

if (ptr + size > s_data[minor] + s_length[minor]) { printk(DEVICE_NAME " : Request past end of device\n"); end_request(0); continue; }

switch (CURRENT->cmd) { case READ :

�������

memcpy(CURRENT->buffer, ptr, size); break; case WRITE : memcpy(ptr, CURRENT->buffer, size); break; default : end_request(0); continue; }

end_request(1); }}

�������

! LM����� ����J\ó

���$����� ��²�3�B��� ·N²]� +,�DE^���� Õõ}��+,�ÕÖm

#9��E�:��0��� $��Jb�16

������ ��]� .�>�����.����V�}���$����� ��²]�����c�}

Ë���$����� ��²� .�>�����.��B���v��c±16

��+,�-�.U� ��99�� ���5a�����LM���a�o��16�����-a����\ÁU

,®� ���@?��0²]� û�4� Å�Z� +,� ÕÖ�� ���@?��0²� �v�� ��� �-a� ��

���@?��0a�34�����v��DE^��B�´µ�1� ���Q� 0

����� �Q� 0�°ya�VÉ�Æ�3~����°yZ��{��D� ���@?��0�\Á���16����L

M��74���E��74��ø«�74�f�����LM�kla�c�3]�ø��jyZ�÷��

��16

! kl��fO9��J

��fO� �int register_blkdev(unsigned int major, const char *name, struct file_operations *fops);

�$klZ�²�3�B��� .�>����ÏZ� (����3@�[�p���ßà��y�z16

���J� �int unregister_blkdev(unsigned int major, const char * name);

! +,�ÕÖ#9��E�:��0��� $

��LM����� ����+,�ÕÖU��$����� ��²�W~�¯�B�z16

�� ���@?��0@9 ���� °y]� ��� VÉ�� ë�B� ±p��� ,®�p�� block_read()�block_write()��block_fsync()�°ya��Ì��Y0�16

�������

���:������ ����$����� ��Z�²�3�B���VÉ�16

�� ���0�� ��LM����� ��Z]�b��p��Y03]�@hB�� ���0��Ò×��zp����

m��ÌN©U�®�-������i�Æ��16

BLKGETSIZE���kl��74a��E��}y��¹º»16

BLKFLSBUF�����a� 9�� 5�16

BLKRAGET��BLKRASET����3�����4#�����5��$a���¿D��1�%~�÷��16

BLKROSET��BLKROGET���kl�� ���������9��-a�1�%~�jå�16����VÉ3���~

,®�p�� RO_IOCTLS(dev, where)�27�a����VÉ�16

BLKRRPART���+���6�L��1-����16�#+����z]�klZ�$

HDIO_GETGEO���3��7��VWa����16�#3���7$

���5�4E.���E�5��-���.���a���y�z]�kl��åì� .���B���]��:t�4���

��Y0�16�.���B�9�åì� ��������U�åì� (��¹ºi¶��16

�� ������0� �� .���B�9�åìZ�³�]�°y�16�*�+� .���a�H�34�����N��

Îa�y�3]�\Á��3¶��16

! V�������B�����@��465C��øZ�����y�z]�¿@���Æ���¿

��MAJOR_NR���kl�� .�>����Ï

��DEVICE_NAME���kl���¼

��DEVICE_NR(kdev_t device)���{J�kl��Ïa�14����27�6�Î�U�MINOR(device)��DEVICE_ON(kdev_t device)����DEVICE_OFF(kdev_t device)���end_request()B�\Á��3l~�N�]�°y

��DEVICE_NO_RANDOM��������.���.��a�w�]��4@3����

�������

! LM����� ���cé�$0VWstruct blk_dev_struct {

request_fn_proc *request_fn; => request Ç� ́ �

queue_proc *queue;void *data;struct request *current_request; => ÈÉ Ç�H requeststruct request plug;struct tq_struct plug_tq;

};

extern struct blk_dev_struct blk_dev[MAX_BLKDEV];

?��LM����� �Q� 0Z�cé���Îa�B�~�z]�ÝÞextern int * blk_size[MAX_BLKDEV];

.�>�����.����.�������.��Z��ß3]�kl��74a� *��#����:F16extern int * blksize_size[MAX_BLKDEV];

.�>�����.����.�������.��Z��ß3]�kl��LM��74a� ��0�#����:F16extern int * hardsect_size[MAX_BLKDEV];

.�>��� ��.���� .����� ��.��Z� �ß3]� kl�� �E�� 74a� ��0#��� �:F16

#�9���0H��"$extern struct sec_size * blk_sec[MAX_BLKDEV];extern int * max_readahead[MAX_BLKDEV];extern int * max_sectors[MAX_BLKDEV];extern int * max_segments[MAX_BLKDEV];

��LM����� ��]�LM���a�fO��¤� ��4E�I.�>��J6�Q� 0E9���`�3@

klZ�Ì��@hB���Îa�÷��Æ��16

��{��D���E�ø U� ��4E�I.�>��J6�Q� 0E9��°ya������q�­16

�������

��ɵ�àU�� U� ��4E�I.�>��J6�����0E�Q� 0��"##� ;2��G�P

struct request {volatile int rq_status;kdev_t rq_dev; => Ç�H \] (major/minor)int cmd; /* READ or WRITE */ => Ç�H �Ê : READ/WRITEint errors;unsigned long sector; => %Ë� I/O� Ì­Í ÎÀunsigned long nr_sectors; => clustered request� BJH I Ag� ÎÀ� Ï�unsigned long nr_segments;unsigned long current_nr_sectors; => %Ë� I/O� ÎÀ� Ï�char * buffer; => ¿�À� µq7 Ð S¾ (S¾ Ñ;6 (� S¾)struct semaphore * sem;struct buffer_head * bh; => Ì­Í S¾6 ±� � struct buffer_head * bhtail; => �WÒ S¾6 ±� � struct request * next; => �Ó request6 ±� ²" ��Z

};

�� �Q� 0E9�#$��VÉ� �� ;2��G�PZ�� � �@�a�y|�16� �.�B� �G���¶������k3

~��7��PG�¶�kl���k�16��@�a�-\���l]� �0����74]� �����0E��E �0�� Z

m��zp�� �Q� 0a�H���Å31� ��E�Q� 0#$�°ya�N½16

� �

������

DE� ��FGH@� ��!"��I�����������

! À�� �� �$� ��� � ��a� {J�� \¦�16� @4�]� ,;� �S�� ��� � ��a

\¦3@��a��03@�Y+�a����16

! VÉòó� �� ,;� �S��� Y+�a� ��3]� ¿U� %��� �@�� ùGa� J�°p�(� B�316

(�'"��(�'8��(� ��ùGZ��"��¸����i¶����� i+y��r�B� ÐÑ3_� ��y�zp��

r�B�����_v���y�z16�@4Z�¡¢@����:�;a��03@�����-"[Û�r�

B� �vO� �16� @h��� ��� ��àU� åì� �a� �N�� =Z� £t!~� :�;a� ®(�p

���03@�r�B��vO��16

! �¤� �

�������������-"[� ,;��S�������y�z16

��klZ�,®�D� write()�Ò×���º������y�z16���Å�ø-}]���E��ÈN

U�r���ê�²��a�Â��B�~�z]� struct playnote_t��ÝÞ�16

�� ioctl()�Ò×������Y+�a�����y�z16���Å�ø-}]���E��ÈNU�ø«

��� }y²� .ù²� struct playnote_t�� ÝÞ�� B�ú]� ùDEa� B�~� z]

struct playdata_t�16

��1B�� ioctl()�Ò×������?¢��J���y�z16

��2���������i+y��������16

��2����PG�������������16

����2�����r�B�����_��16

,��K����¥��Õi�16�ɵ���}~�z]���EB�zp¶�=��¦Z��B�16

������

�P�,� �� ?�� Õia� �#�16� =Z� z]� ?�� �0U� §J�16� @4�� ¨��� z]

��%�w��§JB�B�316

�GPPG+,����write()����3]���E��4ö�.ùa����16

;3��/GPG+,����ɵ�Õi}]��¥��.ùa�_16

/GP;�2�P���ɵ��U����}ya�:º»16

��klZ� Ì����U� `[4�p�� ��y� z16�©� ,®�D� åìZ]���� � �� ��E

a�?!�����¤Z������%���¹tB�w��`[4�D�åìZ]�=Zw��U�¤

��¹t"16

��kl]�[-Z�3������ w����y�z16

! 6�G�òó� ������4���JÌ��[\3]��ôD�16����0���VÉ�� �����@��� �����@�:����@

0�:�f��[\��\[��ôD3~� ?��0#$��4O��¥ÎÌ��Õi}]��ôD�16� � ���5�����

?��0a�÷���¤�JÌ��[\3]��ôD�16

! 9�� �

������ ���J\

��6�G���� �J\

! 6�G�9�� �insmod pcplay.omknod /dev/pcplay c [major] 0./pcplay_testrmmod pcplay

�������

! Filename : pcplay.h

/* * PC Speaker Play */

#ifndef __PCPLAY_H#define __PCPLAY_H

#include <linux/ioctl.h>

#define PCPLAY_MAGICNUM 0x37

#define PCPLAY_DEFAULTTEMPO 120

enum OCTAVE_NONE, OCTAVE_1, OCTAVE_2, OCTAVE_3, OCTAVE_4, OCTAVE_5, OCTAVE_6, OCTAVE_7, OCTAVE_8, OCTAVE_NUM};

enum NOTE_C,

�������

NOTE_CSHARP, NOTE_DFLAT = NOTE_CSHARP, NOTE_D, NOTE_DSHARP, NOTE_EFLAT = NOTE_DSHARP, NOTE_E, NOTE_F, NOTE_FSHARP, NOTE_GFLAT = NOTE_FSHARP, NOTE_G, NOTE_GSHARP, NOTE_AFLAT = NOTE_GSHARP, NOTE_A, NOTE_ASHARP, NOTE_BFLAT = NOTE_ASHARP, NOTE_B, NOTE_NUM};

#define NOTE_NOSOUND 0#define NOTE_REST 0 #define PCPLAY_MAKEINOTE(octave, note) ((octave) * NOTE_NUM + note)#define PCPLAY_GETOCTAVE(inote) ((inote) / NOTE_NUM)#define PCPLAY_GETNOTE(inote) ((inote) % NOTE_NUM)

enum DURATION_64, DURATION_32, DURATION_16, DURATION_8, DURATION_4, DURATION_2, DURATION_1, DURATION_2X,

�������

DURATION_4X, DURATION_8X, DURATION_16X, DURATION_32X, DURATION_64X, DURATION_START = DURATION_64, DURATION_END = DURATION_64X, DURATION_0 = 0xff};

enum DURATION_POINT = 0x10, DURATION_POINT2X = 0x20, DURATION_POINT3X = 0x30,};

#define PCPLAY_GETDURATIONLENGTH(duration) ((duration) & 0x0f)#define PCPLAY_GETDURATIONPOINT(duration) ((duration) & 0xf0)#define PCPLAY_MAKEDURATION(duration, point) ((duration) | (point))

struct playnote_t { unsigned char m_note; unsigned char m_duration;};

struct playdata_t { int m_length; int m_tempo; struct playnote_t *m_pdata;};

�������

#define IOCTL_PCPLAY_SOUND _IOW(PCPLAY_MAGICNUM, 0, int)#define IOCTL_PCPLAY_SOUNDNOTE _IOW(PCPLAY_MAGICNUM, 1, int)#define IOCTL_PCPLAY_NOSOUND _IO(PCPLAY_MAGICNUM, 2)#define IOCTL_PCPLAY_PLAY _IOW(PCPLAY_MAGICNUM, 10, struct playdata_t *)#define IOCTL_PCPLAY_STOP _IO(PCPLAY_MAGICNUM, 11)#define IOCTL_PCPLAY_SETTEMPO _IOW(PCPLAY_MAGICNUM, 20, int)#define IOCTL_PCPLAY_CHANGETEMPO _IOW(PCPLAY_MAGICNUM, 21, int)#define IOCTL_PCPLAY_GETCOUNT _IOR(PCPLAY_MAGICNUM, 22, int *)

#endif

�������

! Filename : pcplay.c

/* PC Speaker Play Module*/

#include <linux/kernel.h>#include <linux/module.h>

#ifdef CONFIG_MODVERSIONS#define MODVERSIONS#include <linux/modversions.h>#endif

#include <linux/sched.h>#include <linux/slab.h>#include <linux/timer.h>#include <asm/uaccess.h>#include <asm/io.h>

#include "pcplay.h"

/* * Device Definitions */

#define DEVICE_NAME "PCPlay"

/* * type definitions

�������

*/

struct playqueue_t { struct playqueue_t *m_next; pid_t m_pid; uid_t m_uid, m_euid; gid_t m_gid, m_egid; int m_curpos; struct playdata_t *m_pdata; struct wait_queue *m_wq;};

/* * sound data definitions */

static int s_notefreq[OCTAVE_NUM][NOTE_NUM] = { { 16, 17, 18, 19, 21, 22, 23, 24, 26, 27, 29, 31 }, { 33, 35, 37, 39, 41, 44, 46, 49, 52, 55, 58, 62 }, { 65, 69, 73, 78, 82, 87, 92, 98, 104, 110, 116, 123 }, { 131, 139, 147, 155, 165, 175, 185, 196, 208, 220, 233, 245 }, { 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494 }, { 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988 }, { 1046, 1109, 1175, 1244, 1328, 1397, 1480, 1568, 1661, 1760, 1865, 1975 }, { 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951 }};

/* * function prototypes */

�������

static int device_open(struct inode *inode, struct file *filp);static int device_release(struct inode *inode, struct file *filp);static ssize_t device_read(struct file *filp, char *buffer, size_t length,

loff_t *offset);static ssize_t device_write(struct file *filp, const char *buffer, size_t length,

loff_t *offset);static int device_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd,

unsigned long arg);

static void mytimer_proc(unsigned long ptr);static void add_mytimer(int clocks);static void del_mytimer(void);

static int play_curnote(void);

static int add_playdata_notes(char *pdata, int length);static int add_playdata(struct playdata_t *pdata);static void process_wait(struct file *filp);

static int enqueue_playdata(struct playdata_t *pdata);static int dequeue_playdata(void);static void dequeueall_playdata(void);static int check_delperm(void);static int settempo(int tempo);static int changetempo_playdata(int tempo);static int get_playqueue_count(void);

static void soundnote(int inote);static void sound(int freq);

�������

static void nosound(void);

/* * Device Operations */

struct file_operations device_fops = { open: device_open, release: device_release, read: device_read, write: device_write, ioctl: device_ioctl,};

/* * global variables */

static int s_nMajor = 0;static int s_bDeviceReadOpen = 0, s_bDeviceWriteOpen = 0;

static struct playqueue_t *s_queue = NULL;static int s_bInPlay = 0;static int s_nTempo = 120;

static struct timer_list s_mytimer;

/* * Module startup/cleanup */

������

int init_module(void){ printk("Loading PC Speaker Play Module\n");

if ((s_nMajor = register_chrdev(0, DEVICE_NAME, &device_fops)) < 0) { printk(DEVICE_NAME " : Device registration failed (%d)\n", s_nMajor); return s_nMajor; }

printk(DEVICE_NAME " : Device registered with Major Number = %d\n", s_nMajor);

return 0;}

void cleanup_module(void){ int nRetCode;

printk("Unloading PC Speaker Play Module\n"); nosound(); dequeueall_playdata();

if ((nRetCode = unregister_chrdev(s_nMajor, DEVICE_NAME)) < 0) printk(DEVICE_NAME " : Device unregistration failed (%d)\n", nRetCode);}

/* * Device Operations

������

*/

int device_open(struct inode *inode, struct file *filp){ printk(DEVICE_NAME " : Device open (%d, %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev));

if ((filp->f_flags & O_ACCMODE) & (O_WRONLY | O_RDWR)) { if (s_bDeviceWriteOpen) { printk(DEVICE_NAME " : Device already open for writing\n"); return -EBUSY; } else ++s_bDeviceWriteOpen; } else ++s_bDeviceReadOpen;

MOD_INC_USE_COUNT;

return 0;}

int device_release(struct inode *inode, struct file *filp){ printk(DEVICE_NAME " : Device release (%d, %d)\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev));

if ((filp->f_flags & O_ACCMODE) & (O_WRONLY | O_RDWR)) --s_bDeviceWriteOpen; else --s_bDeviceReadOpen;

�������

MOD_DEC_USE_COUNT;

return 0;}

ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset){ return 0;}

ssize_t device_write(struct file *filp, const char *buffer, size_t length,loff_t *offset)

{ int count = add_playdata_notes((char *) buffer, length); if (count > 0) filp->f_pos += count; process_wait(filp); return count;}

int device_ioctl(struct inode *inodep, struct file *filp, unsigned int cmd,unsigned long arg)

{ int length, retcode = 0;

printk(DEVICE_NAME " : ioctl, cmd = %x, arg = %x\n", cmd, (int) arg);

�������

switch (cmd) { case IOCTL_PCPLAY_SOUND : sound((int) arg); break; case IOCTL_PCPLAY_SOUNDNOTE : soundnote((int) arg); break; case IOCTL_PCPLAY_NOSOUND : nosound(); break;

case IOCTL_PCPLAY_PLAY : retcode = add_playdata((struct playdata_t *) arg); process_wait(filp); break; case IOCTL_PCPLAY_STOP : nosound(); dequeueall_playdata(); break;

case IOCTL_PCPLAY_SETTEMPO : settempo((int) arg); break; case IOCTL_PCPLAY_CHANGETEMPO : changetempo_playdata((int) arg);

�������

break; case IOCTL_PCPLAY_GETCOUNT : length = get_playqueue_count(); put_user(length, (int *) arg); break;

default : printk(DEVICE_NAME " : ioctl : unknown\n"); retcode = -EINVAL; }

return retcode;}

/* Timer Management*/

void mytimer_proc(unsigned long ptr){ play_curnote();}

void add_mytimer(int clock){ init_timer(&s_mytimer);

s_mytimer.function = mytimer_proc; s_mytimer.expires = jiffies + clock;

�������

add_timer(&s_mytimer);}

void del_mytimer(void){ del_timer(&s_mytimer);}

#define DURATION_FACTOR 1000

int play_curnote(void){ int duration, point, clocks; struct playnote_t *pnote;

if (s_queue) { if (s_queue->m_curpos == s_queue->m_pdata->m_length) { nosound(); dequeue_playdata(); s_bInPlay = 0; play_curnote(); } else { pnote = s_queue->m_pdata->m_pdata + s_queue->m_curpos; duration = PCPLAY_GETDURATIONLENGTH(pnote->m_duration); point = PCPLAY_GETDURATIONPOINT(pnote->m_duration);

clocks = HZ * DURATION_FACTOR; if (duration >= DURATION_4 && duration <= DURATION_END)

�������

clocks <<= (duration - DURATION_4); else if (duration >= DURATION_START && duration < DURATION_4) clocks >>= (DURATION_4 - duration); else clocks = 0;

while (point-- > 0) clocks = clocks * 3 / 2; clocks = clocks * 60 / s_queue->m_pdata->m_tempo; clocks /= DURATION_FACTOR; soundnote(pnote->m_note); add_mytimer(clocks); ++s_queue->m_curpos; s_bInPlay = 1; } return 0; } else return -ENODATA;}

/* User space / Queue*/

int add_playdata_notes(char *pdata, int length){

�������

struct playdata_t *newdata; int itemnum, buflen, retcode; itemnum = length / sizeof(struct playnote_t); buflen = sizeof(struct playdata_t) + (itemnum - 1) * sizeof(struct playnote_t); if ((newdata = kmalloc(buflen, GFP_KERNEL)) == NULL) return -ENOMEM; newdata->m_length = itemnum; newdata->m_tempo = s_nTempo; copy_from_user(newdata->m_pdata, pdata, itemnum * sizeof(struct playnote_t)); if ((retcode = enqueue_playdata(newdata)) < 0) { kfree(newdata); return retcode; } if (!s_bInPlay) play_curnote();

return length;}

int add_playdata(struct playdata_t *pdata){ int length, buflen, retcode; struct playdata_t *newdata; struct playnote_t *pnotes;

�������

get_user(length, &pdata->m_length); get_user(pnotes, &pdata->m_pdata);

buflen = sizeof(struct playdata_t) + sizeof(struct playnote_t) * length - sizeof pdata->m_pdata; if ((newdata = kmalloc(buflen, GFP_KERNEL)) == NULL) return -ENOMEM; copy_from_user(newdata, pdata, sizeof(struct playdata_t)); copy_from_user(newdata->m_pdata, pnotes, sizeof(struct playnote_t) * length); if ((retcode = enqueue_playdata(newdata)) < 0) { kfree(newdata); return retcode; } if (!s_bInPlay) play_curnote(); return 0;}

void process_wait(struct file *filp){ if ((filp->f_flags & FASYNC) == 0) interruptible_sleep_on(&s_queue->m_wq);}

/*

�������

Queue Management*/

int enqueue_playdata(struct playdata_t *pdata){ struct playqueue_t *endqueue, *newqueue; if ((newqueue = (struct playqueue_t *) kmalloc(sizeof(struct playqueue_t), GFP_KERNEL)) != NULL) { newqueue->m_next = NULL; newqueue->m_pid = current->pid; newqueue->m_uid = current->uid; newqueue->m_euid = current->euid; newqueue->m_gid = current->gid; newqueue->m_egid = current->egid; newqueue->m_curpos = 0; newqueue->m_pdata = pdata; newqueue->m_wq = NULL; if (s_queue == NULL) s_queue = newqueue; else { for (endqueue = s_queue; endqueue->m_next != NULL; endqueue = endqueue->m_next) ; endqueue->m_next = newqueue; } return 0; } else return -ENOMEM;

������

}

int dequeue_playdata(void){ int retcode; struct playqueue_t *curqueue; if ((retcode = check_delperm()) < 0) return retcode; if (s_queue) { curqueue = s_queue; s_queue = s_queue->m_next; wake_up_interruptible(&curqueue->m_wq); kfree(curqueue->m_pdata); kfree(curqueue); return 0; } else return -ENODATA;}

void dequeueall_playdata(void){ while (dequeue_playdata() == 0) ;}

int check_delperm(void)

������

{ if (s_queue) { if (current->uid == s_queue->m_uid || current->euid == s_queue->m_uid || current->euid == s_queue->m_euid) return 0; else return -EPERM; } else return -ENODATA;}

int settempo(int tempo){ s_nTempo = tempo; return 0;}

int changetempo_playdata(int tempo){ if (s_queue) { s_queue->m_pdata->m_tempo = tempo; return 0; } else return -ENODATA;}

int get_playqueue_count(void){

�������

int count; struct playqueue_t *queue; for (count = 0, queue = s_queue; queue != NULL; queue = queue->m_next) count += queue->m_pdata->m_length - queue->m_curpos; return count;}

/* PC Speaker Sound Primitive*/

void soundnote(int inote){ if (inote == NOTE_REST) nosound(); else sound(s_notefreq[PCPLAY_GETOCTAVE(inote) - 1][PCPLAY_GETNOTE(inote)]);}

void sound(int freq){ unsigned int value = inb(0x61); freq = 1193181 / freq; if ((value & 3) == 0) { outb(value | 3, 0x61); outb(0xb6, 0x43);

�������

} outb(freq & 0xff, 0x42); outb((freq >> 8) & 0xff, 0x42); printk("freq = %x\n", freq);}

void nosound(void){ unsigned int value = inb(0x61); value &= 0xfc; outb(value, 0x61);}

�������

! Filename : pcplay_test.c

/* PC Speaker Play Module Test*/

#include <stdio.h>#include <fcntl.h>

#include "pcplay.h"

/* * global data */

static struct playdata_t s_playdata;

static struct playnote_t s_notes[] = { { PCPLAY_MAKEINOTE(OCTAVE_4, NOTE_C), DURATION_4 }, { PCPLAY_MAKEINOTE(OCTAVE_4, NOTE_D), DURATION_4 }, { PCPLAY_MAKEINOTE(OCTAVE_4, NOTE_E), DURATION_4 }, { PCPLAY_MAKEINOTE(OCTAVE_4, NOTE_F), DURATION_4 }, { PCPLAY_MAKEINOTE(OCTAVE_4, NOTE_G), DURATION_4 }, { PCPLAY_MAKEINOTE(OCTAVE_4, NOTE_A), DURATION_4 }, { PCPLAY_MAKEINOTE(OCTAVE_4, NOTE_B), DURATION_4 }, { PCPLAY_MAKEINOTE(OCTAVE_5, NOTE_C), DURATION_4 },};

#define s_notesnum (sizeof s_notes / sizeof s_notes[0])

�������

/* * function prototypes */

static int pcplay_ioctl_sound(int fd, int freq);static int pcplay_ioctl_soundnote(int fd, int octave, int note);static int pcplay_ioctl_nosound(int fd);static int pcplay_ioctl_play(int fd, struct playdata_t *pdata);static int pcplay_ioctl_stop(int fd);static int pcplay_ioctl_settempo(int fd, int tempo);static int pcplay_ioctl_changetempo(int fd, int tempo);static int pcplay_ioctl_getcount(int fd);

/* * main of the program */

int main(void){ int i, fd;

if ((fd = open("/dev/pcplay", O_RDWR)) < 0) { printf("Error opening device file\n"); return 1; } printf("SOUND : octave 4, C for 1 second\n"); pcplay_ioctl_soundnote(fd, OCTAVE_4, NOTE_C); sleep(1); printf("NOSOUND : for 1 second\n");

�������

pcplay_ioctl_nosound(fd); sleep(1); s_playdata.m_length = s_notesnum; s_playdata.m_tempo = PCPLAY_DEFAULTTEMPO; printf("PLAY 1 : using IOCTL\n"); pcplay_ioctl_play(fd, &s_playdata); printf("PLAY 2 : using WRITE\n"); write(fd, s_notes, sizeof s_notes); printf("PLAY 3 : asynchronous play & stop\n"); fcntl(fd, F_SETFL, fcntl(0, F_GETFL) | FASYNC); write(fd, s_notes, sizeof s_notes); sleep(3); pcplay_ioctl_stop(fd); printf("PLAY end\n");

close(fd);

return 0;}

/* * ioctls */

int pcplay_ioctl_sound(int fd, int freq){ return ioctl(fd, IOCTL_PCPLAY_SOUND, freq);}

�������

int pcplay_ioctl_soundnote(int fd, int octave, int note){ return ioctl(fd, IOCTL_PCPLAY_SOUNDNOTE, PCPLAY_MAKEINOTE(octave, note));}

int pcplay_ioctl_nosound(int fd){ return ioctl(fd, IOCTL_PCPLAY_NOSOUND, 0);}

int pcplay_ioctl_play(int fd, struct playdata_t *pdata){ return ioctl(fd, IOCTL_PCPLAY_PLAY, pdata);}

int pcplay_ioctl_stop(int fd){ return ioctl(fd, IOCTL_PCPLAY_STOP, 0);}

int pcplay_ioctl_settempo(int fd, int tempo){ return ioctl(fd, IOCTL_PCPLAY_SETTEMPO, tempo);}

int pcplay_ioctl_changetempo(int fd, int tempo){ return ioctl(fd, IOCTL_PCPLAY_CHANGETEMPO, tempo);}

�������

int pcplay_ioctl_getcount(int fd){ int count, retcode; return ((retcode = ioctl(fd, IOCTL_PCPLAY_GETCOUNT, &count)) < 0) ? retcode : count;}

�������

DE� ���JK� # $

=������>-�a�κ¶W

�� ��ɵ�Î~�z]��¶�� ��� ��� ¶�@4Z��� ���>-�a� ���16�)�7����?���

¶� E��� ª�� 3�� '� «ì~� tail -f /var/log/messages ]� Ò×�� {|��� ��}]

>-�a�HI�ôD3¶��������3]�¿��ý16

=����� .�����..���f����� ��{|��}���]�W

�� ��?¢������¥��a�3]���� U� �:�� �w����y�z16� �:�� ����Ò×��{|

��3~��:�05B�)¬z���1¶� @ ���@�� .���Np��4¬�a����16

=���?¢����3º]���ø������]1]�ZhB�ÐÑ�16

�� ��ɵ�Y03]��ø9�?¢��§+,3]��Y0������ø��,l->16�$%��òóU� "

k�� B?¢��ø��JCa�<~�16

=���?¢����3º]��<W3]�ÃÄ��±1]�ZhB�ÐÑ�16

����"k�� B��� ���� �.����Zh��JCa�<~3@��D��kt����õ�16

=���?¢9�Y0$�?�����%�²���Ea�ªä��Å�­�(Ya��Æ3�W

������?�Z��Y03]���E�%��G�b"9�Y0$?�Z��Y03]���E�%��G�b

"��û�4�Å�Z���Z�]�Y0$�>?�a�no�o���y�±16�� ����Ea�i~à�

�(Ya����16

������

=���?¢Z�� sys_��-\3]�-�.�A��H�3]�°ya�Na�y�z]BW

�� ��-�.�A��H�3]�°y]�D$��'���ùDE]�Y0$?���irb"Z�z]���E

~� B��� �16� � �� D$�� ��?��� irb"Z� z]� ��E�� ùDEa� 'Di�Æ� 3

]�åì�-�.�A��H�3]�°ya�no�Na�y�±16

=���1½��ø����Z��§+,��3]��ZhB�ÐÑ3¶W

����?¢������3]�òóU�Ì«��`®3�w��%%�� Ó�Z�]��ø31�¯�B� z16��

øZ�� �°y��$0VWB�;�yv�z~���B��DE^����j�B�z��y�z16����ø

����VW��r�a�~���16