util.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:14k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*  devfs (Device FileSystem) utilities.
  2.     Copyright (C) 1999-2001  Richard Gooch
  3.     This library is free software; you can redistribute it and/or
  4.     modify it under the terms of the GNU Library General Public
  5.     License as published by the Free Software Foundation; either
  6.     version 2 of the License, or (at your option) any later version.
  7.     This library is distributed in the hope that it will be useful,
  8.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  10.     Library General Public License for more details.
  11.     You should have received a copy of the GNU Library General Public
  12.     License along with this library; if not, write to the Free
  13.     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14.     Richard Gooch may be reached by email at  rgooch@atnf.csiro.au
  15.     The postal address is:
  16.       Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia.
  17.     ChangeLog
  18.     19991031   Richard Gooch <rgooch@atnf.csiro.au>
  19.                Created.
  20.     19991103   Richard Gooch <rgooch@atnf.csiro.au>
  21.                Created <_devfs_convert_name> and supported SCSI and IDE CD-ROMs
  22.     20000203   Richard Gooch <rgooch@atnf.csiro.au>
  23.                Changed operations pointer type to void *.
  24.     20000621   Richard Gooch <rgooch@atnf.csiro.au>
  25.                Changed interface to <devfs_register_series>.
  26.     20000622   Richard Gooch <rgooch@atnf.csiro.au>
  27.                Took account of interface change to <devfs_mk_symlink>.
  28.                Took account of interface change to <devfs_mk_dir>.
  29.     20010519   Richard Gooch <rgooch@atnf.csiro.au>
  30.                Documentation cleanup.
  31.     20010709   Richard Gooch <rgooch@atnf.csiro.au>
  32.                Created <devfs_*alloc_major> and <devfs_*alloc_devnum>.
  33.     20010710   Richard Gooch <rgooch@atnf.csiro.au>
  34.                Created <devfs_*alloc_unique_number>.
  35.     20010730   Richard Gooch <rgooch@atnf.csiro.au>
  36.                Documentation typo fix.
  37.     20010806   Richard Gooch <rgooch@atnf.csiro.au>
  38.                Made <block_semaphore> and <char_semaphore> private.
  39.     20010813   Richard Gooch <rgooch@atnf.csiro.au>
  40.                Fixed bug in <devfs_alloc_unique_number>: limited to 128 numbers
  41.     20010818   Richard Gooch <rgooch@atnf.csiro.au>
  42.                Updated major masks up to Linus' "no new majors" proclamation.
  43.        Block: were 126 now 122 free, char: were 26 now 19 free.
  44. */
  45. #include <linux/module.h>
  46. #include <linux/init.h>
  47. #include <linux/devfs_fs_kernel.h>
  48. #include <linux/slab.h>
  49. #include <linux/vmalloc.h>
  50. #include <asm/bitops.h>
  51. /*  Private functions follow  */
  52. /**
  53.  * _devfs_convert_name - Convert from an old style location-based name to new style.
  54.  * @new: The new name will be written here.
  55.  * @old: The old name.
  56.  * @disc: If true, disc partitioning information should be processed.
  57.  */
  58. static void __init _devfs_convert_name (char *new, const char *old, int disc)
  59. {
  60.     int host, bus, target, lun;
  61.     char *ptr;
  62.     char part[8];
  63.     /*  Decode "c#b#t#u#"  */
  64.     if (old[0] != 'c') return;
  65.     host = simple_strtol (old + 1, &ptr, 10);
  66.     if (ptr[0] != 'b') return;
  67.     bus = simple_strtol (ptr + 1, &ptr, 10);
  68.     if (ptr[0] != 't') return;
  69.     target = simple_strtol (ptr + 1, &ptr, 10);
  70.     if (ptr[0] != 'u') return;
  71.     lun = simple_strtol (ptr + 1, &ptr, 10);
  72.     if (disc)
  73.     {
  74. /*  Decode "p#"  */
  75. if (ptr[0] == 'p') sprintf (part, "part%s", ptr + 1);
  76. else strcpy (part, "disc");
  77.     }
  78.     else part[0] = '';
  79.     sprintf (new, "/host%d/bus%d/target%d/lun%d/%s",
  80.      host, bus, target, lun, part);
  81. }   /*  End Function _devfs_convert_name  */
  82. /*  Public functions follow  */
  83. /**
  84.  * devfs_make_root - Create the root FS device entry if required.
  85.  * @name: The name of the root FS device, as passed by "root=".
  86.  */
  87. void __init devfs_make_root (const char *name)
  88. {
  89.     char dest[64];
  90.     if ( (strncmp (name, "sd/", 3) == 0) || (strncmp (name, "sr/", 3) == 0) )
  91.     {
  92. strcpy (dest, "../scsi");
  93. _devfs_convert_name (dest + 7, name + 3, (name[1] == 'd') ? 1 : 0);
  94.     }
  95.     else if ( (strncmp (name, "ide/hd/", 7) == 0) ||
  96.       (strncmp (name, "ide/cd/", 7) == 0) )
  97.     {
  98. strcpy (dest, "..");
  99. _devfs_convert_name (dest + 2, name + 7, (name[4] == 'h') ? 1 : 0);
  100.     }
  101.     else return;
  102.     devfs_mk_symlink (NULL, name, DEVFS_FL_DEFAULT, dest, NULL, NULL);
  103. }   /*  End Function devfs_make_root  */
  104. /**
  105.  * devfs_register_tape - Register a tape device in the "/dev/tapes" hierarchy.
  106.  * @de: Any tape device entry in the device directory.
  107.  */
  108. void devfs_register_tape (devfs_handle_t de)
  109. {
  110.     int pos;
  111.     devfs_handle_t parent, slave;
  112.     char name[16], dest[64];
  113.     static unsigned int tape_counter;
  114.     static devfs_handle_t tape_dir;
  115.     if (tape_dir == NULL) tape_dir = devfs_mk_dir (NULL, "tapes", NULL);
  116.     parent = devfs_get_parent (de);
  117.     pos = devfs_generate_path (parent, dest + 3, sizeof dest - 3);
  118.     if (pos < 0) return;
  119.     strncpy (dest + pos, "../", 3);
  120.     sprintf (name, "tape%u", tape_counter++);
  121.     devfs_mk_symlink (tape_dir, name, DEVFS_FL_DEFAULT, dest + pos,
  122.       &slave, NULL);
  123.     devfs_auto_unregister (de, slave);
  124. }   /*  End Function devfs_register_tape  */
  125. EXPORT_SYMBOL(devfs_register_tape);
  126. /**
  127.  * devfs_register_series - Register a sequence of device entries.
  128.  * @dir: The handle to the parent devfs directory entry. If this is %NULL
  129.  * the new names are relative to the root of the devfs.
  130.  * @format: The printf-style format string. A single "%u" is allowed.
  131.  * @num_entries: The number of entries to register.
  132.  * @flags: A set of bitwise-ORed flags (DEVFS_FL_*).
  133.  * @major: The major number. Not needed for regular files.
  134.  * @minor_start: The starting minor number. Not needed for regular files.
  135.  * @mode: The default file mode.
  136.  * @ops: The &file_operations or &block_device_operations structure.
  137.  * This must not be externally deallocated.
  138.  * @info: An arbitrary pointer which will be written to the private_data
  139.  * field of the &file structure passed to the device driver. You
  140.  * can set this to whatever you like, and change it once the file
  141.  * is opened (the next file opened will not see this change).
  142.  */
  143. void devfs_register_series (devfs_handle_t dir, const char *format,
  144.     unsigned int num_entries, unsigned int flags,
  145.     unsigned int major, unsigned int minor_start,
  146.     umode_t mode, void *ops, void *info)
  147. {
  148.     unsigned int count;
  149.     char devname[128];
  150.     for (count = 0; count < num_entries; ++count)
  151.     {
  152. sprintf (devname, format, count);
  153. devfs_register (dir, devname, flags, major, minor_start + count,
  154. mode, ops, info);
  155.     }
  156. }   /*  End Function devfs_register_series  */
  157. EXPORT_SYMBOL(devfs_register_series);
  158. struct major_list
  159. {
  160.     spinlock_t lock;
  161.     __u32 bits[8];
  162. };
  163. /*  Block majors already assigned:
  164.     0-3, 7-9, 11-63, 65-99, 101-113, 120-127, 199, 201, 240-255
  165.     Total free: 122
  166. */
  167. static struct major_list block_major_list =
  168. {SPIN_LOCK_UNLOCKED,
  169.     {0xfffffb8f,  /*  Majors 0   to 31   */
  170.      0xffffffff,  /*  Majors 32  to 63   */
  171.      0xfffffffe,  /*  Majors 64  to 95   */
  172.      0xff03ffef,  /*  Majors 96  to 127  */
  173.      0x00000000,  /*  Majors 128 to 159  */
  174.      0x00000000,  /*  Majors 160 to 191  */
  175.      0x00000280,  /*  Majors 192 to 223  */
  176.      0xffff0000}  /*  Majors 224 to 255  */
  177. };
  178. /*  Char majors already assigned:
  179.     0-7, 9-151, 154-158, 160-211, 216-221, 224-230, 240-255
  180.     Total free: 19
  181. */
  182. static struct major_list char_major_list =
  183. {SPIN_LOCK_UNLOCKED,
  184.     {0xfffffeff,  /*  Majors 0   to 31   */
  185.      0xffffffff,  /*  Majors 32  to 63   */
  186.      0xffffffff,  /*  Majors 64  to 95   */
  187.      0xffffffff,  /*  Majors 96  to 127  */
  188.      0x7cffffff,  /*  Majors 128 to 159  */
  189.      0xffffffff,  /*  Majors 160 to 191  */
  190.      0x3f0fffff,  /*  Majors 192 to 223  */
  191.      0xffff007f}  /*  Majors 224 to 255  */
  192. };
  193. /**
  194.  * devfs_alloc_major - Allocate a major number.
  195.  * @type: The type of the major (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK)
  196.  * Returns the allocated major, else -1 if none are available.
  197.  * This routine is thread safe and does not block.
  198.  */
  199. int devfs_alloc_major (char type)
  200. {
  201.     int major;
  202.     struct major_list *list;
  203.     list = (type == DEVFS_SPECIAL_CHR) ? &char_major_list : &block_major_list;
  204.     spin_lock (&list->lock);
  205.     major = find_first_zero_bit (list->bits, 256);
  206.     if (major < 256) __set_bit (major, list->bits);
  207.     else major = -1;
  208.     spin_unlock (&list->lock);
  209.     return major;
  210. }   /*  End Function devfs_alloc_major  */
  211. EXPORT_SYMBOL(devfs_alloc_major);
  212. /**
  213.  * devfs_dealloc_major - Deallocate a major number.
  214.  * @type: The type of the major (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK)
  215.  * @major: The major number.
  216.  * This routine is thread safe and does not block.
  217.  */
  218. void devfs_dealloc_major (char type, int major)
  219. {
  220.     int was_set;
  221.     struct major_list *list;
  222.     if (major < 0) return;
  223.     list = (type == DEVFS_SPECIAL_CHR) ? &char_major_list : &block_major_list;
  224.     spin_lock (&list->lock);
  225.     was_set = __test_and_clear_bit (major, list->bits);
  226.     spin_unlock (&list->lock);
  227.     if (!was_set)
  228. printk (KERN_ERR __FUNCTION__ "(): major %d was already freen",
  229. major);
  230. }   /*  End Function devfs_dealloc_major  */
  231. EXPORT_SYMBOL(devfs_dealloc_major);
  232. struct minor_list
  233. {
  234.     int major;
  235.     __u32 bits[8];
  236.     struct minor_list *next;
  237. };
  238. struct device_list
  239. {
  240.     struct minor_list *first, *last;
  241.     int none_free;
  242. };
  243. static DECLARE_MUTEX (block_semaphore);
  244. static struct device_list block_list;
  245. static DECLARE_MUTEX (char_semaphore);
  246. static struct device_list char_list;
  247. /**
  248.  * devfs_alloc_devnum - Allocate a device number.
  249.  * @type: The type (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK).
  250.  *
  251.  * Returns the allocated device number, else NODEV if none are available.
  252.  * This routine is thread safe and may block.
  253.  */
  254. kdev_t devfs_alloc_devnum (char type)
  255. {
  256.     int minor;
  257.     struct semaphore *semaphore;
  258.     struct device_list *list;
  259.     struct minor_list *entry;
  260.     if (type == DEVFS_SPECIAL_CHR)
  261.     {
  262. semaphore = &char_semaphore;
  263. list = &char_list;
  264.     }
  265.     else
  266.     {
  267. semaphore = &block_semaphore;
  268. list = &block_list;
  269.     }
  270.     if (list->none_free) return NODEV;  /*  Fast test  */
  271.     down (semaphore);
  272.     if (list->none_free)
  273.     {
  274. up (semaphore);
  275. return NODEV;
  276.     }
  277.     for (entry = list->first; entry != NULL; entry = entry->next)
  278.     {
  279. minor = find_first_zero_bit (entry->bits, 256);
  280. if (minor >= 256) continue;
  281. __set_bit (minor, entry->bits);
  282. up (semaphore);
  283. return MKDEV (entry->major, minor);
  284.     }
  285.     /*  Need to allocate a new major  */
  286.     if ( ( entry = kmalloc (sizeof *entry, GFP_KERNEL) ) == NULL )
  287.     {
  288. list->none_free = 1;
  289. up (semaphore);
  290. return NODEV;
  291.     }
  292.     memset (entry, 0, sizeof *entry);
  293.     if ( ( entry->major = devfs_alloc_major (type) ) < 0 )
  294.     {
  295. list->none_free = 1;
  296. up (semaphore);
  297. kfree (entry);
  298. return NODEV;
  299.     }
  300.     __set_bit (0, entry->bits);
  301.     if (list->first == NULL) list->first = entry;
  302.     else list->last->next = entry;
  303.     list->last = entry;
  304.     up (semaphore);
  305.     return MKDEV (entry->major, 0);
  306. }   /*  End Function devfs_alloc_devnum  */
  307. EXPORT_SYMBOL(devfs_alloc_devnum);
  308. /**
  309.  * devfs_dealloc_devnum - Dellocate a device number.
  310.  * @type: The type (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK).
  311.  * @devnum: The device number.
  312.  *
  313.  * This routine is thread safe and does not block.
  314.  */
  315. void devfs_dealloc_devnum (char type, kdev_t devnum)
  316. {
  317.     int major, minor;
  318.     struct semaphore *semaphore;
  319.     struct device_list *list;
  320.     struct minor_list *entry;
  321.     if (devnum == NODEV) return;
  322.     if (type == DEVFS_SPECIAL_CHR)
  323.     {
  324. semaphore = &char_semaphore;
  325. list = &char_list;
  326.     }
  327.     else
  328.     {
  329. semaphore = &block_semaphore;
  330. list = &block_list;
  331.     }
  332.     major = MAJOR (devnum);
  333.     minor = MINOR (devnum);
  334.     down (semaphore);
  335.     for (entry = list->first; entry != NULL; entry = entry->next)
  336.     {
  337. int was_set;
  338. if (entry->major != major) continue;
  339. was_set = __test_and_clear_bit (minor, entry->bits);
  340. if (was_set) list->none_free = 0;
  341. up (semaphore);
  342. if (!was_set)
  343.     printk ( KERN_ERR __FUNCTION__ "(): device %s was already freen",
  344.      kdevname (devnum) );
  345. return;
  346.     }
  347.     up (semaphore);
  348.     printk ( KERN_ERR __FUNCTION__ "(): major for %s not previously allocatedn",
  349.      kdevname (devnum) );
  350. }   /*  End Function devfs_dealloc_devnum  */
  351. EXPORT_SYMBOL(devfs_dealloc_devnum);
  352. /**
  353.  * devfs_alloc_unique_number - Allocate a unique (positive) number.
  354.  * @space: The number space to allocate from.
  355.  *
  356.  * Returns the allocated unique number, else a negative error code.
  357.  * This routine is thread safe and may block.
  358.  */
  359. int devfs_alloc_unique_number (struct unique_numspace *space)
  360. {
  361.     int number;
  362.     unsigned int length;
  363.     __u32 *bits;
  364.     /*  Get around stupid lack of semaphore initialiser  */
  365.     spin_lock (&space->init_lock);
  366.     if (!space->sem_initialised)
  367.     {
  368. sema_init (&space->semaphore, 1);
  369. space->sem_initialised = 1;
  370.     }
  371.     spin_unlock (&space->init_lock);
  372.     down (&space->semaphore);
  373.     if (space->num_free < 1)
  374.     {
  375. if (space->length < 16) length = 16;
  376. else length = space->length << 1;
  377. if ( ( bits = vmalloc (length) ) == NULL )
  378. {
  379.     up (&space->semaphore);
  380.     return -ENOMEM;
  381. }
  382. if (space->bits != NULL)
  383. {
  384.     memcpy (bits, space->bits, space->length);
  385.     vfree (space->bits);
  386. }
  387. space->num_free = (length - space->length) << 3;
  388. space->bits = bits;
  389. memset (bits + space->length, 0, length - space->length);
  390. space->length = length;
  391.     }
  392.     number = find_first_zero_bit (space->bits, space->length << 3);
  393.     --space->num_free;
  394.     __set_bit (number, space->bits);
  395.     up (&space->semaphore);
  396.     return number;
  397. }   /*  End Function devfs_alloc_unique_number  */
  398. EXPORT_SYMBOL(devfs_alloc_unique_number);
  399. /**
  400.  * devfs_dealloc_unique_number - Deallocate a unique (positive) number.
  401.  * @space: The number space to deallocate from.
  402.  * @number: The number to deallocate.
  403.  *
  404.  * This routine is thread safe and may block.
  405.  */
  406. void devfs_dealloc_unique_number (struct unique_numspace *space, int number)
  407. {
  408.     int was_set;
  409.     if (number < 0) return;
  410.     down (&space->semaphore);
  411.     was_set = __test_and_clear_bit (number, space->bits);
  412.     if (was_set) ++space->num_free;
  413.     up (&space->semaphore);
  414.     if (!was_set)
  415. printk (KERN_ERR __FUNCTION__ "(): number %d was already freen",
  416. number);
  417. }   /*  End Function devfs_dealloc_unique_number  */
  418. EXPORT_SYMBOL(devfs_dealloc_unique_number);