ºìÁªLinuxÃÅ»§
Linux°ïÖú

LinuxÄں˱à³Ì(×Ö·ûÉ豸Îļþ)

·¢²¼Ê±¼ä:2006-04-04 00:25:54À´Ô´:ºìÁª×÷Õß:golshing
ÄÇô£¬ÏÖÔÚÎÒÃÇÊÇԭʼ¼¶µÄÄں˳ÌÐòÔ±£¬ÎÒÃÇÖªµÀÈçºÎд²»×öÈκÎÊÂÇéµÄÄÚºËÄ£¿é¡£ÎÒÃÇΪ×Ô¼º¶ø½¾°Á²¢ÇҸ߰ºÆðÍ·À´¡£µ«ÊDz»ÖªºÎ¹ÊÎÒÃǸоõµ½È±ÁËʲô¶«Î÷¡£»¼Óо«Éñ½ôÕÅÖ¢µÄÄ£¿é²»ÊÇÄÇôÓÐÒâÒå¡£
ÄÚºËÄ£¿éͬ½ø³Ì¶Ô»°ÓÐÁ½ÖÖÖ÷Ҫ;¾¶¡£Ò»ÖÖÊÇͨ¹ýÉ豸Îļþ£¨±ÈÈç/dev Ŀ¼ÖеÄÎļþ£©£¬ÁíÒ»ÖÖÊÇʹÓÃprocÎļþϵͳ¡£ÎÒÃÇ°ÑһЩ¶«Î÷дÈëÄں˵ÄÒ»¸öÖ÷ÒªÔ­Òò¾ÍÊÇÖ§³ÖһЩӲ¼þÉ豸£¬ËùÒÔÎÒÃÇ´ÓÉ豸Îļþ¿ªÊ¼¡£
É豸ÎļþµÄ×î³õÄ¿µÄÊÇÔÊÐí½ø³ÌͬÄÚºËÖеÄÉ豸Çý¶¯Í¨ÐÅ£¬²¢ÇÒͨ¹ýËüÃǺÍÎïÀíÉ豸ͨÐÅ£¨modem£¬Öնˣ¬µÈµÈ£©¡£ÕâÖÖ·½·¨µÄʵÏÖÈçÏ£º
ÿ¸öÉ豸Çý¶¯¶¼¶ÔÓ¦×ÅÒ»¶¨ÀàÐ͵ÄÓ²¼þÉ豸£¬²¢ÇÒ±»¸³ÓèÒ»¸öÖ÷Âë¡£É豸Çý¶¯µÄÁбíºÍËüÃǵÄÖ÷Âë¿ÉÒÔÔÚin/proc/devicesÖÐÕÒµ½¡£Ã¿¸öÉ豸Çý¶¯¹ÜÀíϵÄÎïÀíÉ豸Ҳ±»¸³ÓèÒ»¸ö´ÓÂë¡£ÎÞÂÛÕâЩÉ豸ÊÇ·ñÕæµÄ°²×°£¬ÔÚ/devĿ¼Öж¼½«ÓÐÒ»¸öÎļþ£¬³Æ×÷É豸Îļþ£¬¶ÔÓ¦×Åÿһ¸öÉ豸¡£
ÀýÈ磬Èç¹ûÄã½øÐÐls -l /dev/hd[ab] *²Ù×÷£¬Ä㽫¿´¼û¿ÉÄÜÁª½áµ½Ä³Ì¨»úÆ÷ÉϵÄËùÓеÄIDEÓ²ÅÌ·ÖÇø¡£×¢ÒâËüÃǶ¼Ê¹ÓÃÁËͬһ¸öÖ÷Â룬3£¬µ«ÊÇ´ÓÂëÈ´»¥²»Ïàͬ¡££¨ÉùÃ÷£ºÕâÊÇÔÚPC½á¹¹ÉϵÄÇé¿ö£¬ÎÒ²»ÖªµÀÔÚÆäËû½á¹¹ÉÏÔËÐеÄlinuxÊÇ·ñÈç´Ë¡££©
ÔÚϵͳ°²×°Ê±£¬ËùÓÐÉ豸ÎļþÔÚmknodÃüÁîϱ»´´½¨¡£ËüÃDZØÐë´´½¨ÔÚ/devĿ¼ÏÂûÓм¼ÊõÉϵÄÔ­Òò£¬Ö»ÊÇÒ»ÖÖʹÓÃÉϵıãÀû¡£Èç¹ûÊÇΪ²âÊÔÄ¿µÄ¶ø´´½¨µÄÉ豸Îļþ£¬±ÈÈçÎÒÃÇÕâÀïµÄÁ·Ï°£¬¿ÉÄÜ·ÅÔÚÄã±àÒëÄÚºËÄ£¿éµÄµÄĿ¼Ï¸ü¼ÓºÏÊÊ¡£
É豸¿ÉÒÔ±»·Ö³ÉÁ½Àࣺ×Ö·ûÉ豸ºÍ¿éÉ豸¡£ËüÃǵÄÇø±ðÊÇ¿éÉ豸ÓÐÒ»¸öÓÃÓÚÇëÇóµÄ»º³åÇø£¬ËùÒÔËüÃÇ¿ÉÒÔÑ¡ÔñÓÃʲôÑùµÄ˳ÐòÀ´ÏìÓ¦ËüÃÇ¡£Õâ¶ÔÓÚ´æ´¢É豸ÊǷdz£ÖØÒªµÄ£¬¶ÁÈ¡ÏàÁÚµÄÉÈÇø±È»¥ÏàÔ¶ÀëµÄ·ÖÇøËٶȻá¿ìµÃ¶à¡£ÁíÒ»¸öÇø±ðÊÇ¿éÉ豸ֻÄÜ°´¿é£¨¿é´óС¶ÔÓ¦²»Í¬É豸¶ø±ä»¯£©½ÓÊÜÊäÈëºÍ·µ»ØÊä³ö£¬¶ø×Ö·ûÉ豸ȴ°´ÕÕËüÃÇÄܽÓÊܵÄ×îÉÙ×Ö½Ú¿éÀ´½ÓÊÜÊäÈë¡£´ó²¿·ÖÉ豸ÊÇ×Ö·ûÉ豸£¬ÒòΪËüÃDz»ÐèÒªÕâÖÖÀàÐ͵Ļº³å¡£Äã¿ÉÒÔͨ¹ý¹Û¿´ls -lÃüÁîµÄÊä³öÖеĵÚÒ»¸ö×Ö·û¶øÖªµÀÒ»¸öÉ豸ÎļþÊÇ¿éÉ豸»¹ÊÇ×Ö·ûÉ豸¡£Èç¹ûÊÇb¾ÍÊÇ¿éÉ豸£¬Èç¹ûÊÇc¾ÍÊÇ×Ö·ûÉ豸¡£
Õâ¸öÄ£¿é¿ÉÒÔ±»·Ö³ÉÁ½²¿·Ö£ºÄ£¿é²¿·ÖºÍÉ豸¼°É豸Çý¶¯²¿·Ö¡£Init_moduleº¯Êýµ÷ÓÃmodule_register_chrdevÔÚÄں˵ÿéÉ豸±íÀïÔö¼ÓÉ豸Çý¶¯¡£Í¬Ê±·µ»Ø¸ÃÇý¶¯ËùʹÓõÄÖ÷Âë¡£Cleanup_moduleº¯Êý³·ÏúÉ豸µÄ×¢²á¡£
ÕâЩ²Ù×÷£¨×¢²áºÍ×¢Ïú£©ÊÇÕâÁ½¸öº¯ÊýµÄÖ÷Òª¹¦ÄÜ¡£ÄÚºËÖеĺ¯Êý²»ÊÇÏó½ø³ÌÒ»Ñù×Ô·¢ÔËÐеģ¬¶øÊÇͨ¹ýϵͳµ÷Ó㬻òÓ²¼þÖжϻòÕßÄÚºËÖеÄÆäËü²¿·Ö£¨Ö»ÒªÊǵ÷ÓþßÌåµÄº¯Êý£©±»½ø³Ìµ÷Óõġ£ËùÒÔ£¬µ±ÄãÏòÄÚºÍÖÐÔö¼Ó´úÂëʱ£¬ÄãÓ¦¸Ã°ÑËü×¢²áΪ¾ßÌåijÖÖʼþµÄ¾ä±ú£¬¶øµ±Äã°ÑËüɾ³ýµÄʱºò£¬ÄãÐèҪעÏúÕâ¸ö¾ä±ú¡£
É豸Çý¶¯ÍêÈ«ÓÉËĸöÉ豸_
ÁíÒ»µãÎÒÃÇÐèÒª¼ÇסµÄÊÇ£¬ÎÒÃDz»ÄÜÔÊÐí¹ÜÀíÔ±ËæÐÄËùÓûµÄɾ³ýÄÚºËÄ£¿é¡£ÕâÊÇÒòΪÈç¹ûÉ豸ÎļþÊDZ»½ø³Ì´ò¿ªµÄ£¬ÄÇôÎÒÃÇɾ³ýÄÚºËÄ£¿éµÄʱºò£¬ÒªÊ¹ÓÃÕâЩÎļþ¾Í»áµ¼Ö·ÃÎÊÕý³£µÄº¯Êý£¨¶Á/д£©ËùÔÚµÄÄÚ´æλÖá£Èç¹ûÐÒÔË£¬ÄÇÀï²»»áÓÐÆäËû´úÂë±»×°ÔØ£¬ÎÒÃǽ«µÃµ½Ò»¸ö¶ñÐԵĴíÎóÐÅÏ¢¡£Èç¹û²»ÐУ¬ÁíÒ»¸öÄÚºËÄ£¿é»á±»×°Ôص½Í¬Ò»¸öλÖã¬Õ⽫Òâζ×Å»áÌøÈëÄÚºËÖÐÁíÒ»¸ö³ÌÐòµÄÖм䣬½á¹û½«ÊDz»¿ÉÔ¤ÁϵĶñÁÓ¡£
ͨ³£Ä㲻ϣÍûÒ»¸öº¯Êý×öʲôÊÂÇéµÄʱºò£¬»á´ÓÄǸöº¯Êý·µ»ØÒ»¸ö´íÎóÂ루һ¸ö¸ºÊý£©¡£µ«ÕâÔÚcleanup_moduleÖÐÊDz»¿ÉÄܵģ¬ÒòΪËüÊÇÒ»¸övoidÐ͵ĺ¯Êý¡£Ò»µ©cleanup_module±»µ÷Óã¬Õâ¸öÄ£¿é¾ÍËÀµôÁË¡£È»¶øÓÐÒ»¸ö¼ÆÊýÆ÷¼Ç¼×ÅÓжàÉÙ¸öÄÚºËÄ£¿éÔÚʹÓÃÕâ¸öÄ£¿é£¬Õâ¸ö¼ÆÊýÆ÷³ÆΪË÷Òý¼ÆÊýÆ÷£¨/proc/modulesÖÐûÐеÄ×îºóÒ»¸öÊý×Ö£©¡£Èç¹ûÕâ¸öÊý×Ö²»ÊÇ0£¬É¾³ý¾Í»áʧ°Ü¡£Ä£¿éµÄË÷Òý¼ÆÊýÆ÷°üº¬ÔÚ±äÁ¿mod_use_count_ÖС£Óж¨ÒåºÃµÄ´¦ÀíÕâ¸ö±äÁ¿µÄºê£¨MOD_INC_USE_COUNTºÍMOD_DEC_USE_COUNT£©£¬ËùÒÔÎÒÃÇÒ»°ãʹÓúê¶ø²»ÊÇÖ±½ÓʹÓñäÁ¿mod_use_count_£¬ÕâÑùÔÚÒÔºóʵÏֱ仯µÄʱºò»á´øÀ´°²È«ÐÔ¡£

ex chardev.c

/* chardev.c
* Copyright (C) 1998-1999 by Ori Pomerantz
*
* Create a character device (read only)
*/

/* The necessary header files */

/* Standard in kernel modules */
#include /* Were doing kernel work */
#include /* Specifically, a module */

/* Deal with CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include
#endif

/* For character devices */
#include /* The character device
* definitions are here */
#include /* A wrapper which does
* next to nothing at
* 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 doesnt - 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 /* 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 dont 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 wont
* 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 theres 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 dont 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 were 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 isnt removed while
* the file is open by incrementing the usage count
* (the number of opened references to the module, if
* its not zero rmmod will fail)
*/
MOD_INC_USE_COUNT;

return SUCCESS;
}


/* This function is called when a process closes the
* device file. It doesnt have a return value in
* version 2.0.x because it cant fail (you must ALWAYS
* be able to close a device). In version 2.2.x it is
* allowed to fail - but we wont 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

/* Were now ready for our next caller */
Device_Open --;

/* Decrement the usage count, otherwise once you
* opened the file youll 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
* (mustnt write beyond that!) */
#endif
{
/* Number of bytes actually written to the buffer */
int bytes_read = 0;

/* If were 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 wouldnt
* 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 cant 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 ("youll have to create a device file. \n");
printk ("We suggest you use:\n");
printk ("mknod c %d \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 theres an error, report it */
if (ret < 0)
printk("Error in unregister_chrdev: %d\n", ret);
}
2£®1¶àÄں˰汾ԴÎļþ
ϵͳµ÷ÓÃÊÇÄں˳öʾ¸ø½ø³ÌµÄÖ÷Òª½Ó¿Ú£¬ÔÚ²»Í¬°æ±¾ÖÐÒ»°ãÊÇÏàͬµÄ¡£¿ÉÄÜ»áÔö¼ÓеÄϵͳ£¬µ«ÊǾɵÄϵͳµÄÐÐΪÊDz»±äµÄ¡£Ïòºó¼æÈÝÊDZØÒªµÄ----еÄÄں˰汾²»ÄÜ´òÆÆÕý³£µÄ½ø³Ì¹æÂÉ¡£ÔÚ´ó¶àÊýÇé¿öÏ£¬É豸ÎļþÊDz»±äµÄ¡£È»¶ø£¬ÄÚºËÖеÄÄÚ²¿½Ó¿ÚÊÇ¿ÉÒÔÔÚ²»Í¬°æ±¾¼ä¸Ä±äµÄ¡£
LinuxÄں˵İ汾·ÖΪÎȶ¨°æ£¨n.<żÊý>.m£©ºÍ·¢Õ¹°æ£¨n.<ÆæÊý>.m£©¡£·¢Õ¹°æ°üº¬ÁËËùÓÐÐÂÆæµÄ˼Ï룬°üÀ¨ÄÇЩÔÚÏÂÒ»°æÖб»ÈÏΪÊÇ´íµÄ£¬»òÕß±»ÖØÐÂʵÏֵġ£ËùÒÔ£¬Äã²»ÄÜÏàÐÅÔÚÄÇЩ°æ±¾ÖÐÕâЩ½Ó¿ÚÊDZ£³Ö²»±äµÄ£¨Õâ¾ÍÊÇΪʲôÎÒÔÚ±¾ÊéÖв»ÑáÆä·³µÄÖ§³Ö²»Í¬½Ó¿Ú¡£ÕâÊǺܴóÁ¿µÄ¹¤×÷µ«ÊÇÂíÉϾͻá¹ýʱ£©¡£µ«ÊÇÔÚÎȶ¨°æÖÐÎÒÃǾͿÉÒÔÈÏΪ½Ó¿ÚÊÇÏàͬµÄ£¬¼´Ê¹ÔÚÐÞÕý°æÖУ¨Êý×ÖmËùÖ¸µÄ£©¡£
MPG°æ±¾°üÀ¨Á˶ÔÄÚºË2.0.xºÍ2.2.xµÄÖ§³Ö¡£ÕâÁ½ÖÖÄÚºËÈÔÓв»Í¬Ö®´¦£¬ËùÒÔ±àÒëʱҪȡ¾öÓÚÄں˰汾¶ø¾ö¶¨¡£·½·¨ÊÇʹÓúêLINUX_VERSION_CODE¡£ÔÚa.b.c°æÖУ¬Õâ¸öºêµÄÖµÊÇ216a+28b+c¡£Èç¹ûÏ£ÍûµÃµ½¾ßÌåÄں˰汾ºÅ£¬ÎÒÃÇ¿ÉÒÔʹÓúêKERNEL_VERSION¡£ÔÚ2.0.35°æÖÐûÓж¨ÒåÕâ¸öºê£¬ÔÚÐèҪʱÎÒÃÇ¿ÉÒÔ×Ô¼º¶¨Òå¡£
ÎÄÕÂÆÀÂÛ

¹²ÓÐ 0 ÌõÆÀÂÛ