Выбрать главу

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