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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * linux/kernel/resource.c
  3.  *
  4.  * Copyright (C) 1999 Linus Torvalds
  5.  * Copyright (C) 1999 Martin Mares <mj@ucw.cz>
  6.  *
  7.  * Arbitrary resource management.
  8.  */
  9. #include <linux/sched.h>
  10. #include <linux/errno.h>
  11. #include <linux/ioport.h>
  12. #include <linux/init.h>
  13. #include <linux/slab.h>
  14. #include <linux/spinlock.h>
  15. #include <asm/io.h>
  16. struct resource ioport_resource = { "PCI IO", 0x0000, IO_SPACE_LIMIT, IORESOURCE_IO };
  17. struct resource iomem_resource = { "PCI mem", 0x00000000, 0xffffffff, IORESOURCE_MEM };
  18. static rwlock_t resource_lock = RW_LOCK_UNLOCKED;
  19. /*
  20.  * This generates reports for /proc/ioports and /proc/iomem
  21.  */
  22. static char * do_resource_list(struct resource *entry, const char *fmt, int offset, char *buf, char *end)
  23. {
  24. if (offset < 0)
  25. offset = 0;
  26. while (entry) {
  27. const char *name = entry->name;
  28. unsigned long from, to;
  29. if ((int) (end-buf) < 80)
  30. return buf;
  31. from = entry->start;
  32. to = entry->end;
  33. if (!name)
  34. name = "<BAD>";
  35. buf += sprintf(buf, fmt + offset, from, to, name);
  36. if (entry->child)
  37. buf = do_resource_list(entry->child, fmt, offset-2, buf, end);
  38. entry = entry->sibling;
  39. }
  40. return buf;
  41. }
  42. int get_resource_list(struct resource *root, char *buf, int size)
  43. {
  44. char *fmt;
  45. int retval;
  46. fmt = "        %08lx-%08lx : %sn";
  47. if (root->end < 0x10000)
  48. fmt = "        %04lx-%04lx : %sn";
  49. read_lock(&resource_lock);
  50. retval = do_resource_list(root->child, fmt, 8, buf, buf + size) - buf;
  51. read_unlock(&resource_lock);
  52. return retval;
  53. }
  54. /* Return the conflict entry if you can't request it */
  55. static struct resource * __request_resource(struct resource *root, struct resource *new)
  56. {
  57. unsigned long start = new->start;
  58. unsigned long end = new->end;
  59. struct resource *tmp, **p;
  60. if (end < start)
  61. return root;
  62. if (start < root->start)
  63. return root;
  64. if (end > root->end)
  65. return root;
  66. p = &root->child;
  67. for (;;) {
  68. tmp = *p;
  69. if (!tmp || tmp->start > end) {
  70. new->sibling = tmp;
  71. *p = new;
  72. new->parent = root;
  73. return NULL;
  74. }
  75. p = &tmp->sibling;
  76. if (tmp->end < start)
  77. continue;
  78. return tmp;
  79. }
  80. }
  81. static int __release_resource(struct resource *old)
  82. {
  83. struct resource *tmp, **p;
  84. p = &old->parent->child;
  85. for (;;) {
  86. tmp = *p;
  87. if (!tmp)
  88. break;
  89. if (tmp == old) {
  90. *p = tmp->sibling;
  91. old->parent = NULL;
  92. return 0;
  93. }
  94. p = &tmp->sibling;
  95. }
  96. return -EINVAL;
  97. }
  98. int request_resource(struct resource *root, struct resource *new)
  99. {
  100. struct resource *conflict;
  101. write_lock(&resource_lock);
  102. conflict = __request_resource(root, new);
  103. write_unlock(&resource_lock);
  104. return conflict ? -EBUSY : 0;
  105. }
  106. int release_resource(struct resource *old)
  107. {
  108. int retval;
  109. write_lock(&resource_lock);
  110. retval = __release_resource(old);
  111. write_unlock(&resource_lock);
  112. return retval;
  113. }
  114. int check_resource(struct resource *root, unsigned long start, unsigned long len)
  115. {
  116. struct resource *conflict, tmp;
  117. tmp.start = start;
  118. tmp.end = start + len - 1;
  119. write_lock(&resource_lock);
  120. conflict = __request_resource(root, &tmp);
  121. if (!conflict)
  122. __release_resource(&tmp);
  123. write_unlock(&resource_lock);
  124. return conflict ? -EBUSY : 0;
  125. }
  126. /*
  127.  * Find empty slot in the resource tree given range and alignment.
  128.  */
  129. static int find_resource(struct resource *root, struct resource *new,
  130.  unsigned long size,
  131.  unsigned long min, unsigned long max,
  132.  unsigned long align,
  133.  void (*alignf)(void *, struct resource *, unsigned long),
  134.  void *alignf_data)
  135. {
  136. struct resource *this = root->child;
  137. new->start = root->start;
  138. for(;;) {
  139. if (this)
  140. new->end = this->start;
  141. else
  142. new->end = root->end;
  143. if (new->start < min)
  144. new->start = min;
  145. if (new->end > max)
  146. new->end = max;
  147. new->start = (new->start + align - 1) & ~(align - 1);
  148. if (alignf)
  149. alignf(alignf_data, new, size);
  150. if (new->start < new->end && new->end - new->start + 1 >= size) {
  151. new->end = new->start + size - 1;
  152. return 0;
  153. }
  154. if (!this)
  155. break;
  156. new->start = this->end + 1;
  157. this = this->sibling;
  158. }
  159. return -EBUSY;
  160. }
  161. /*
  162.  * Allocate empty slot in the resource tree given range and alignment.
  163.  */
  164. int allocate_resource(struct resource *root, struct resource *new,
  165.       unsigned long size,
  166.       unsigned long min, unsigned long max,
  167.       unsigned long align,
  168.       void (*alignf)(void *, struct resource *, unsigned long),
  169.       void *alignf_data)
  170. {
  171. int err;
  172. write_lock(&resource_lock);
  173. err = find_resource(root, new, size, min, max, align, alignf, alignf_data);
  174. if (err >= 0 && __request_resource(root, new))
  175. err = -EBUSY;
  176. write_unlock(&resource_lock);
  177. return err;
  178. }
  179. /*
  180.  * This is compatibility stuff for IO resources.
  181.  *
  182.  * Note how this, unlike the above, knows about
  183.  * the IO flag meanings (busy etc).
  184.  *
  185.  * Request-region creates a new busy region.
  186.  *
  187.  * Check-region returns non-zero if the area is already busy
  188.  *
  189.  * Release-region releases a matching busy region.
  190.  */
  191. struct resource * __request_region(struct resource *parent, unsigned long start, unsigned long n, const char *name)
  192. {
  193. struct resource *res = kmalloc(sizeof(*res), GFP_KERNEL);
  194. if (res) {
  195. memset(res, 0, sizeof(*res));
  196. res->name = name;
  197. res->start = start;
  198. res->end = start + n - 1;
  199. res->flags = IORESOURCE_BUSY;
  200. write_lock(&resource_lock);
  201. for (;;) {
  202. struct resource *conflict;
  203. conflict = __request_resource(parent, res);
  204. if (!conflict)
  205. break;
  206. if (conflict != parent) {
  207. parent = conflict;
  208. if (!(conflict->flags & IORESOURCE_BUSY))
  209. continue;
  210. }
  211. /* Uhhuh, that didn't work out.. */
  212. kfree(res);
  213. res = NULL;
  214. break;
  215. }
  216. write_unlock(&resource_lock);
  217. }
  218. return res;
  219. }
  220. int __check_region(struct resource *parent, unsigned long start, unsigned long n)
  221. {
  222. struct resource * res;
  223. res = __request_region(parent, start, n, "check-region");
  224. if (!res)
  225. return -EBUSY;
  226. release_resource(res);
  227. kfree(res);
  228. return 0;
  229. }
  230. void __release_region(struct resource *parent, unsigned long start, unsigned long n)
  231. {
  232. struct resource **p;
  233. unsigned long end;
  234. p = &parent->child;
  235. end = start + n - 1;
  236. for (;;) {
  237. struct resource *res = *p;
  238. if (!res)
  239. break;
  240. if (res->start <= start && res->end >= end) {
  241. if (!(res->flags & IORESOURCE_BUSY)) {
  242. p = &res->child;
  243. continue;
  244. }
  245. if (res->start != start || res->end != end)
  246. break;
  247. *p = res->sibling;
  248. kfree(res);
  249. return;
  250. }
  251. p = &res->sibling;
  252. }
  253. printk("Trying to free nonexistent resource <%08lx-%08lx>n", start, end);
  254. }
  255. /*
  256.  * Called from init/main.c to reserve IO ports.
  257.  */
  258. #define MAXRESERVE 4
  259. static int __init reserve_setup(char *str)
  260. {
  261. static int reserved = 0;
  262. static struct resource reserve[MAXRESERVE];
  263. for (;;) {
  264. int io_start, io_num;
  265. int x = reserved;
  266. if (get_option (&str, &io_start) != 2)
  267. break;
  268. if (get_option (&str, &io_num)   == 0)
  269. break;
  270. if (x < MAXRESERVE) {
  271. struct resource *res = reserve + x;
  272. res->name = "reserved";
  273. res->start = io_start;
  274. res->end = io_start + io_num - 1;
  275. res->flags = IORESOURCE_BUSY;
  276. res->child = NULL;
  277. if (request_resource(res->start >= 0x10000 ? &iomem_resource : &ioport_resource, res) == 0)
  278. reserved = x+1;
  279. }
  280. }
  281. return 1;
  282. }
  283. __setup("reserve=", reserve_setup);