Чтение онлайн

ЖАНРЫ

Энциклопедия разработчика модулей ядра Linux

Померанц Ори

Шрифт:

#define DEVICE_NAME "char_dev"

/* The maximum length of the message for 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) {

#ifdef DEBUG

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

#endif

 /* 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, because one process might have

 * checked Device_Open right before the other one

 * tried to increment it. However, we're in the

 * kernel, so we're protected against context switches.

 *

 * This is NOT the right attitude to take, because we

 * might be running on an SMP box, but we'll deal with

 * SMP in a later chapter. */

 Device_Open++;

 /* Initialize the message */

 Message_Ptr = Message;

 MOD_INC_USE_COUNT;

 return SUCCESS;

}

/* This function is called when a process closes the

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

* it cannot fail. Regardless of what else happens, you

* should always be able to close a device (in 2.0, a 2.2

* device file could be impossible to close). */

#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--;

 MOD_DEC_USE_COUNT;

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

 return 0;

#endif

}

/* This function is called whenever a process which

* has 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 the data */

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

 loff_t *offset) /* offset to 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;

#ifdef DEBUG

 printk("device_read(%p,%p,%d)\n", file, buffer, length);

#endif

 /* 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. */

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

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

#else

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

Поделиться с друзьями: