¸ðµâÀº µî·ÏµÉ ¶§ µð¹ÙÀ̽º ¹øÈ£¸¦ µî·ÏÇϰí ÀÌ¿Í ÇÔ²² file_operations ¶ó´Â ±¸Á¶Ã¼¸¦ Ä¿³Î¿¡ ¾Ë·ÁÁØ´Ù. file_operations´Â include/linux/fs.h¿¡ Á¤ÀǵǾî ÀÖ°í ´ÙÀ½°ú °°´Ù.
/*
* NOTE:
* read, write, poll, fsync, readv, writev can be called
* without the big kernel lock held in all filesystems.
*/
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
}; |
¸ðµç µð¹ÙÀ̽º µå¶óÀ̹ö´Â »ç¿ëÀÚ°¡ file_operations¸¦ »ç¿ëÇØ µî·ÏÇØÁØ Ç¥ÁØÈµÇ¾î ÀÖ´Â ÀÎÅÍÆäÀ̽º ¸¦ »ç¿ëÇØ ÀÔ/Ãâ·Â µîÀÇ ÀÏÀ» ÇϰԵȴÙ. À¯´Ð½º¿¡¼´Â µð¹ÙÀ̽º³ª ³×Æ®¿÷À̳ª ¸ðµÎ ÇϳªÀÇ ÆÄÀÏ Ã³·³ µ¿ÀÛÇϵµ·Ï µÇ¾î Àִµ¥ ÀÌ¿¡ µû¸¥ ÇÔ¼öµéÀÌ µî·ÏµÇ¾î ÀÖ´Ù. ¿¹¸¦ µé¾î µð¹ÙÀ̽º·ÎºÎÅÍ Àб⠵¿ÀÛÀ» ¿øÇÑ´Ù¸é file_operations¿¡ µî·ÏµÈ read ÇÔ¼ö¸¦ »ç¿ëÇØ Àб⸦ ÇÑ´Ù.
file_operations´Â ¸ðµÎ ä¿ï ÇÊ¿ä´Â ¾ø´Ù. ÇÊ¿äÇϰųª Áö¿øµÇ¾ßÇÏ´Â °ÍÀ» ä¿ö ³ÖÀ¸¸é µÈ´Ù. ±×·¯³ª ¹ü¿ëÀûÀÎ µð¹ÙÀ̽º¸¦ ¸¸µç´Ù¸é µÇµµ·Ï ¸ðµç ÇÔ¼ö¸¦ ´Ù ä¿ö³Ö¾î ÁÖ´Â °ÍÀÌ ÁÁÀ» °ÍÀÌ´Ù.
±×·¯³ª file_operations¿¡ Á¸ÀçÇÏ´Â ÇÔ¼öÀÇ °³¼ö¿¡ Á¦¾àÀÌ ÀÖÀ¸¹Ç·Î µð¹ÙÀ̽º¿¡ ´ëÇØ file_operations ¿ÜÀÇ ´Ù¸¥ ±â´É ȤÀº ÇÔ¼ö¸¦ ¿øÇÏ´Â °æ¿ì¿£ ioctlÀ» »ç¿ëÇÑ´Ù. ioctlÀÇ C ¶óÀ̺귯¸® ³»ÀÇ Á¤ÀÇ´Â ´ÙÀ½°ú °°ÀÌ µÇ¾î ÀÖ´Ù.
#include <sys/ioctl.h> int ioctl(int d, int request, ...) |
ioctl ÇÔ¼ö¸¦ »ç¿ëÇÒ ¶§ request¶õ ¼ýÀÚ¸¦ Àü´ÞÇØ Áִµ¥ ÀÌ °ÍÀÌ ioctl¿¡ ÀÇÇØ ºÒ¸®´Â ÇÔ¼öÀÇ À妽º°¡ µÈ´Ù. Áï ioctl·Î ºÒ¸®´Â ÇÔ¼ö´Â switch ¹®°ú °°Àº °ÍÀ» ÀÌ¿ëÇØ request·Î Àü´ÞµÈ °ªÀ» ºñ±³ÇØ ÇØ´ç ÇÔ¼ö¸¦ ´Ù½Ã È£ÃâÇØ ÁÖ°Ô µÈ´Ù. ´ÙÀ½ ¼Ò½º´Â ÇÏµå µð½ºÅ©ÀÇ ½Ã¸®¾ó ¹øÈ£¸¦ ÀÐ¾î ³»´Â ±â´ÉÀ» ÇÏ´Â µð¹ÙÀ̽º µå¶óÀ̹ö¸¦ ¸¸µé¾î º» °ÍÀÌ´Ù.
/* hddinfo.c */
#ifndef __KERNEL__
#define __KERNEL__
#endif
#ifndef MODULE
#define MODULE
#endif
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ide.h>
#include <asm/uaccess.h>
#define HDA 0x0300
#define HARDDISK HDA
char kernel_version[] = UTS_RELEASE;
static int hddinfo_open(struct inode *node, struct file *f)
{
return 0;
}
static int hddinfo_release(struct inode *node, struct file *f)
{
return 0;
}
static ssize_t hddinfo_read(struct file *f, char *buf, size_t nbytes, loff_t *ppos)
{
return nbytes;
}
static ssize_t read_serial(char *dst)
{
ide_drive_t *drv;
drv = get_info_ptr(HARDDISK);
if (drv)
copy_to_user(dst, drv->id->serial_no, 20);
else
{
;//PDEBUG("HDDINFO : Cannot get the drive information\n");
return 0;
}
return 20;
}
int hddinfo_ioctl(struct inode *node, struct file *f, unsigned int ioctl_num, unsigned long ioctl_param)
{
switch (ioctl_num)
{
case 0 :
read_serial((char *)(ioctl_param));
break;
}
return 0;
}
struct file_operations Fops = {
NULL,
NULL,
hddinfo_read,
NULL,
NULL,
NULL,
hddinfo_ioctl,
NULL,
hddinfo_open,
NULL,
hddinfo_release
};
int init_module()
{
if (register_chrdev(212, "hddinfo", &Fops) < 0)
{
//PDEBUG("HDDINFO : Unable to register driver.\n");
return -EIO;
}
return 0;
}
void cleanup_module()
{
if (unregister_chrdev(212, "hddinfo") < 0)
;//PDEBUG("HDDINFO : Unable to unregister\n");
} |
hddinfo.c¿¡¼ Á¤ÀÇµÈ file_operations´Â read/ioctl/open/release ¸¸À» »ç¿ëÇÑ´Ù. open°ú release´Â ÀÌ µð¹ÙÀ̽º¸¦ open/closeÇÒ ¶§ ºÒ¸®¹Ç·Î µð¹ÙÀ̽º¸¦ »ç¿ëÇϱâ Àü¿¡ ÃʱâÈ ÇØ¾ßÇϰųª ȤÀº »ç¿ëÀ» ÁßÁöÇϱâ Àü¿¡ ¶Ç ÇÊ¿äÇÑ ÀÛ¾÷À» ÇØ¾ßÇÏ´Â °æ¿ì ÀÌ ÇÔ¼öµé¿¡ ÇÊ¿äÇÑ ±â´ÉÀ» ³ÖÀ¸¸é µÈ´Ù. hddinfo.c ¿¡¼´Â open/close¿¡ µû¸¥ ÀÛ¾÷À» ÇÒ Çʿ䰡 ¾ø¾î ¾Æ¹«°Íµµ ³ÖÁö ¾Ê°í ±×³É 0À» ¸®ÅÏÇÏ´Â ±â´ÉÀ» ³Ö¾î ¿¹Á¦·Î ¿Ã·È´Ù. read¸¦ »ç¿ëÇØ Çϵåµð½ºÅ©ÀÇ ½Ã¸®¾ó ¹øÈ£¸¦ Àеµ·Ï ÇØµµ µÇÁö¸¸ ¿©±â¼± ioctlÀÇ »ç¿ëÀ» º¸±âÀ§ÇØ ÀϺη¯ read¿¡¼ ÇÒ ÀÐÀ» ioctl·Î »Ì¾Æ ¸¸µé¾î ºÃ´Ù.
ÀÌ ¸ðµâÀÇ »ç¿ëÀº ¾Æ·¡¿Í °°Àº ÇÁ·Î±×·¥À¸·Î µ¿ÀÛ ½ÃŲ´Ù.
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
int fd;
char buf[256];
fd = open("/dev/hdd_info", O_RDWR);
if (fd < 0)
{
printf("Device open error.\n");
return -1;
}
ioctl(fd, 0, buf);
printf("buf : %s\n", buf);
close(fd);
return 0;
} |
test.c¸¦ µ¿ÀÛ ½Ã۱â Àü¿¡ /dev/hdd_info¸¦ ¸¸µé¾î Áà¾ßÇÑ´Ù. 'mknod c 212 0 /dev/hdd_info'·Î ¸¸µé¾î ÁØ´Ù. ÀϹÝÀûÀ¸·Î µð¹ÙÀ̽º¸¦ »ç¿ëÇϱâ À§ÇØ µð¹ÙÀ̽º ÆÄÀÏÀ» »ç¿ëÇØ µð¹ÙÀ̽º¸¦ open ÇÑ´Ù. ¿©±â¿¡¼ ¾ò¾îÁö´Â ÇÚµéÀ» »ç¿ëÇØ µð¹ÙÀ̽º¿¡ ÀÐ°í ¾²±â µ¿ÀÛ µîÀ» ÇÑ ÈÄ ´Ù »ç¿ëÇßÀ¸¸é close·Î »ç¿ëÀ» ÁßÁöÇØ ÁØ´Ù. ÀÌ ÀýÂ÷°¡ ÀüÇü ÀûÀÎ ÀýÂ÷¿¡ ÇØ´çÇÑ´Ù.
test.c¿¡¼µµ open ÈÄ ioctlÀÇ 0¹ø ÇÔ¼ö¸¦ È£ÃâÇØ hddinfo.cÀÇ read_serial()À» ºÒ·¯ Çϵåµð½ºÅ©ÀÇ ½Ã¸®¾ó ¹øÈ£¸¦ Àоî¿Â´Ù. Çϵåµð½ºÅ©ÀÇ ½Ã¸®¾ó ¹øÈ£´Â Ä¿³Î ºÎÆÃÇÒ ¶§ ÀÌ¹Ì ¾ò¾îÁø Çϵåµð½ºÅ©¿¡ ´ëÇÑ Á¤º¸¸¦ °®°í ÀÖ´Â ±¸Á¶Ã¼¿¡¼ º¹»çÇÑ´Ù.