Π§ΠΈΡ‚Π°ΠΉΡ‚Π΅ ΠΊΠ½ΠΈΠ³ΠΈ ΠΎΠ½Π»Π°ΠΉΠ½ Π½Π° Bookidrom.ru! БСсплатныС ΠΊΠ½ΠΈΠ³ΠΈ Π² ΠΎΠ΄Π½ΠΎΠΌ ΠΊΠ»ΠΈΠΊΠ΅

Π§ΠΈΡ‚Π°Ρ‚ΡŒ ΠΎΠ½Π»Π°ΠΉΠ½ «ЭнциклопСдия Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠ° ΠΌΠΎΠ΄ΡƒΠ»Π΅ΠΉ ядра LinuxΒ». Π‘Ρ‚Ρ€Π°Π½ΠΈΡ†Π° 3

Автор ΠžΡ€ΠΈ ΠŸΠΎΠΌΠ΅Ρ€Π°Π½Ρ†

/* chardev.c

* Copyright (C) 1998-1999 by Ori Pomerantz

*

* Create a character device (read only)

*/


/* The necessary header files */

/* Standard in kernel modules */

#include <linux/kernel.h> /* We're doing kernel work */

#include <linux/module.h> /* Specifically, a module */


/* Deal with CONFIG_MODVERSIONS */

#if CONFIG_MODVERSIONS==1

#define MODVERSIONS

#include <linux/modversions.h>

#endif


/* For character devices */

#include <linux/fs.h> /* The character device definitions are here */

#include <linux/wrapper.h> /* A wrapper which does next to nothing at present, but may help for compatibility with future versions of Linux */


/* In 2.2.3 /usr/include/linux/version.h includes a macro for this, but 2.0.35 doesn't - so I add it here if necessary. */

#ifndef KERNEL_VERSION

#define KERNEL_VERSION(a,b,c)

((a)*65536+(b)*256+(c))

#endif


/* Conditional compilation. LINUX_VERSION_CODE is the code (as per KERNEL_VERSION) of this version. */

#if LINUX_VERSION_CODE > KERNEL_VERSION(2,2,0)

#include <asm/uaccess.h> /* for put_user */

#endif


#define SUCCESS 0

/* Device Declarations **************************** */

/* The name for our device, as it will appear in /proc/devices */

#define DEVICE_NAME "char_dev"


/* The maximum length of the message from the device */

#define BUF_LEN 80


/* Is the device open right now? Used to prevent concurent access into the same device */

static int Device_Open = 0;


/* The message the device will give when asked */

static char Message[BUF_LEN];


/* How far did the process reading the message get? Useful if the message is larger than the size of the buffer we get to fill in device_read. */

static char *Message_Ptr;


/* This function is called whenever a process attempts to open the device file */

static int device_open(struct inode *inode, struct file *file) {

 static int counter = 0;

#ifdef DEBUG

 printk("device_open(%p,%p)\n", inode, file);

#endif

/* This is how you get the minor device number in case you have more than one physical device using the driver. */

 printk("Device: %d.%d\n", inode->i_rdev >> 8, inode->i_rdev & 0xFF);

 /* We don't want to talk to two processes at the same time */

 if (Device_Open) return -EBUSY;

 /* If this was a process, we would have had to be

 * more careful here.

 *

 * In the case of processes, the danger would be

 * that one process might have check Device_Open

 * and then be replaced by the schedualer by another

 * process which runs this function. Then, when the

 * first process was back on the CPU, it would assume

 * the device is still not open.

 *

 * However, Linux guarantees that a process won't be

 * replaced while it is running in kernel context.

 *

 * In the case of SMP, one CPU might increment

 * Device_Open while another CPU is here, right after

 * the check. However, in version 2.0 of the

 * kernel this is not a problem because there's a lock

 * to guarantee only one CPU will be kernel module at

 * the same time. This is bad in terms of

 * performance, so version 2.2 changed it.

 * Unfortunately, I don't have access to an SMP box

 * to check how it works with SMP. */

 Device_Open++;

 /* Initialize the message. */

 sprintf(Message, "If I told you once, I told you %d times - %s", counter++, "Hello, world\n");

 /* The only reason we're allowed to do this sprintf

 * is because the maximum length of the message

 * (assuming 32 bit integers - up to 10 digits

 * with the minus sign) is less than BUF_LEN, which

 * is 80. BE CAREFUL NOT TO OVERFLOW BUFFERS,

 * ESPECIALLY IN THE KERNEL!!! */

 Message_Ptr = Message;

 /* Make sure that the module isn't removed while

 * the file is open by incrementing the usage count

 * (the number of opened references to the module, if

 * it's not zero rmmod will fail)

 */

 MOD_INC_USE_COUNT;

 return SUCCESS;

}


/* This function is called when a process closes the

* device file. It doesn't have a return value in

* version 2.0.x because it can't fail (you must ALWAYS

* be able to close a device). In version 2.2.x it is

* allowed to fail - but we won't let it. */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

static int device_release(struct inode *inode, struct file *file)

#else

static void device_release(struct inode *inode, struct file *file)

#endif

{

#ifdef DEBUG

 printk("device_release(%p,%p)\n", inode, file);

#endif

 /* We're now ready for our next caller */

 Device_Open--;

 /* Decrement the usage count, otherwise once you opened the file you'll never get rid of the module. */

 MOD_DEC_USE_COUNT;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

 return 0;

#endif

}


/* This function is called whenever a process which

* have already opened the device file attempts to

* read from it. */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

static ssize_t device_read(struct file *file,

 char *buffer, /* The buffer to fill with data */

 size_t length, /* The length of the buffer */

 loff_t *offset) /* Our offset in the file */

#else

static int device_read(struct inode *inode, struct file *file,

 char *buffer, /* The buffer to fill with the data */

 int length) /* The length of the buffer (mustn't write beyond that!) */

#endif

{

 /* Number of bytes actually written to the buffer */

 int bytes_read = 0;

 /* If we're at the end of the message, return 0 (which signifies end of file) */

 if (*Message_Ptr == 0) return 0;

 /* Actually put the data into the buffer */

 while (length && *Message_Ptr) {

  /* Because the buffer is in the user data segment,

  * not the kernel data segment, assignment wouldn't

  * work. Instead, we have to use put_user which

  * copies data from the kernel data segment to the

  * user data segment. */

  put_user(*(Message_Ptr++), buffer++);

  length--;

  bytes_read++;

 }

#ifdef DEBUG

 printk("Read %d bytes, %d left\n", bytes_read, length);

#endif

 /* Read functions are supposed to return the number of bytes actually inserted into the buffer */

 return bytes_read;

}


/* This function is called when somebody tries to write

* into our device file - unsupported in this example. */

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

static ssize_t device_write(struct file *file,

 const char *buffer, /* The buffer */

 size_t length, /* The length of the buffer */

 loff_t *offset) /* Our offset in the file */

#else

static int device_write(struct inode *inode, struct file *file, const char *buffer, int length)

#endif

{

 return -EINVAL;

}


/* Module Declarations ***************************** */

/* The major device number for the device. This is

* global (well, static, which in this context is global

* within this file) because it has to be accessible * both for registration and for release. */

static int Major;


/* This structure will hold the functions to be

* called when a process does something to the device

* we created. Since a pointer to this structure is

* kept in the devices table, it can't be local to

* init_module. NULL is for unimplemented functions. */

struct file_operations Fops = {

 NULL, /* seek */

 device_read, device_write,

 NULL, /* readdir */

 NULL, /* select */

 NULL, /* ioctl */

 NULL, /* mmap */

 device_open,

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

 NULL, /* flush */

#endif

 device_release /* a.k.a. close */

};


/* Initialize the module - Register the character device */

int init_module() {

 /* Register the character device (atleast try) */

 Major = module_register_chrdev(0, DEVICE_NAME, &Fops);

 /* Negative values signify an error */

 if (Major < 0) {

  printk("%s device failed with %d\n", "Sorry, registering the character", Major);

  return Major;

 }

 printk("%s The major device number is %d.\n", "Registeration is a success.", Major);

 printk("If you want to talk to the device driver,\n");

 printk("you'll have to create a device file. \n");

 printk("We suggest you use:\n");

 printk("mknod <name> c %d <minor>\n", Major);

 printk("You can try different minor numbers %s", "and see what happens.\n");

 return 0;

}


/* Cleanup - unregister the appropriate file from /proc */

void cleanup_module() {

 int ret;

 /* Unregister the device */

 ret = module_unregister_chrdev(Major, DEVICE_NAME);

 /* If there's an error, report it */

 if (ret < 0) printk("Error in unregister_chrdev: %d\n", ret);

}

Π˜ΡΡ…ΠΎΠ΄Π½ΠΈΠΊΠΈ для Ρ€Π°Π·Π½Ρ‹Ρ… вСрсий ядра Files

БистСмныС Π²Ρ‹Π·ΠΎΠ²Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΡΠ²Π»ΡΡŽΡ‚ΡΡ Π³Π»Π°Π²Π½Ρ‹ΠΌ интСрфСйсом ядра, для процСссов выглядят ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²ΠΎ, нСзависимо ΠΎΡ‚ вСрсии. Новый систСмный Π²Ρ‹Π·ΠΎΠ² ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½, Π½ΠΎ старыС ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ Π±ΡƒΠ΄ΡƒΡ‚ вСсти сСбя Ρ‚ΠΎΡ‡Π½ΠΎ Ρ‚Π°ΠΊ, ΠΊΠ°ΠΊ ΠΈ Ρ€Π°Π½ΡŒΡˆΠ΅. Π­Ρ‚ΠΎ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ для ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠΉ совмСстимости новая вСрсия ядра, ΠΊΠ°ΠΊ прСдполагаСтся, Π½Π΅ Ρ€Π°Π·Ρ€Ρ‹Π²Π°Π΅Ρ‚ рСгулярныС процСссы. Π’ Π±ΠΎΠ»ΡŒΡˆΠΈΠ½ΡΡ‚Π²Π΅ случаСв, Ρ„Π°ΠΉΠ»Ρ‹ устройства Ρ‚Π°ΠΊΠΆΠ΅ останутся Ρ‚Π΅ΠΌΠΈ ΠΆΠ΅ самыми. Π‘ Π΄Ρ€ΡƒΠ³ΠΎΠΉ стороны, Π²Π½ΡƒΡ‚Ρ€Π΅Π½Π½ΠΈΠ΅ интСрфСйсы ядра ΠΌΠΎΠ³ΡƒΡ‚ ΠΈΠ·ΠΌΠ΅Π½ΡΡ‚ΡŒΡΡ ΠΌΠ΅ΠΆΠ΄Ρƒ вСрсиями.

ВСрсии ядра Linux Ρ€Π°Π·Π΄Π΅Π»Π΅Π½Ρ‹ ΠΌΠ΅ΠΆΠ΄Ρƒ устойчивыми вСрсиями (n.<Π§Π΅Ρ‚Π½ΠΎΠ΅ число>.m) ΠΈ вСрсии Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ (n.<НСчСтноС число>.m). ВСрсии Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Π²ΠΊΠ»ΡŽΡ‡Π°ΡŽΡ‚ всС Π½ΠΎΠ²Ρ‹Π΅ ΠΈΠ΄Π΅ΠΈ, Π²ΠΊΠ»ΡŽΡ‡Π°Ρ Ρ‚Π΅, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π±ΡƒΠ΄ΡƒΡ‚ ΡΡ‡ΠΈΡ‚Π°Ρ‚ΡŒΡΡ ошибкой ΠΈΠ»ΠΈ ΠΏΠΎΠ²Ρ‚ΠΎΡ€Π½ΠΎ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½Ρ‹ Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ вСрсии. Π’ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π΅ Π’Ρ‹ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ Π΄ΠΎΠ²Π΅Ρ€ΡΡ‚ΡŒ интСрфСйсу Π² Ρ‚ΠΎΠΌ ΠΏΠ»Π°Π½Π΅, Ρ‡Ρ‚ΠΎ ΠΎΠ½ останСтся Ρ‚Π΅ΠΌ ΠΆΠ΅ самым Π² вСрсиях Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ. Π’ устойчивых вСрсиях ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΎΠΆΠΈΠ΄Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ интСрфСйс останСтся Ρ‚Π΅ΠΌ ΠΆΠ΅ самым нСзависимо ΠΎΡ‚ вСрсии исправлСния ошибок (число m).

Π­Ρ‚Π° вСрсия MPG Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΡƒ для вСрсии 2.0.x ΠΈ вСрсии ядра Linux. Π’Π°ΠΊ ΠΊΠ°ΠΊ ΠΈΠΌΠ΅ΡŽΡ‚ΡΡ различия ΠΌΠ΅ΠΆΠ΄Ρƒ Π½ΠΈΠΌΠΈ, трСбуСтся условная трансляция Π² зависимости ΠΎΡ‚ вСрсии. Бпособ ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ это сводится ΠΊ Ρ‚ΠΎΠΌΡƒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠ°ΠΊΡ€ΠΎΠΊΠΎΠΌΠ°Π½Π΄Ρƒ LINUX_VERSION_CODE. Π’ вСрсии a.b.c ядра Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ этой ΠΌΠ°ΠΊΡ€ΠΎΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ Π±Ρ‹Π»ΠΎ Π±Ρ‹ 216a+28b+c. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡Π°Ρ‚ΡŒ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ для ΠΊΠΎΠ½ΠΊΡ€Π΅Ρ‚Π½ΠΎΠΉ вСрсии, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΌΠ°ΠΊΡ€ΠΎΠΊΠΎΠΌΠ°Π½Π΄Ρƒ KERNEL_VERSION. Π’Π°ΠΊ ΠΊΠ°ΠΊ этот макрос Π½Π΅ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ Π² 2.0.35, ΠΌΡ‹ опрСдСляСм Π΅Π³ΠΎ сами Π² случаС нСобходимости.