aoechr.c
上传用户:ajay2009
上传日期:2009-05-22
资源大小:495k
文件大小:5k
源码类别:

驱动编程

开发平台:

Unix_Linux

  1. /* Copyright (c) 2004 Coraid, Inc.  See COPYING for GPL terms. */
  2. /*
  3.  * aoechr.c
  4.  * AoE character device driver
  5.  */
  6. #include <linux/hdreg.h>
  7. #include <linux/blkdev.h>
  8. #include "aoe.h"
  9. enum {
  10. //MINOR_STAT = 1, (moved to sysfs)
  11. MINOR_ERR = 2,
  12. MINOR_DISCOVER,
  13. MINOR_INTERFACES,
  14. MSGSZ = 2048,
  15. NARGS = 10,
  16. NMSG = 100, /* message backlog to retain */
  17. };
  18. struct aoe_chardev {
  19. ulong minor;
  20. char name[32];
  21. };
  22. enum { EMFL_VALID = 1 };
  23. struct ErrMsg {
  24. short flags;
  25. short len;
  26. char *msg;
  27. };
  28. static struct ErrMsg emsgs[NMSG];
  29. static int emsgs_head_idx, emsgs_tail_idx;
  30. static struct semaphore emsgs_sema;
  31. static spinlock_t emsgs_lock;
  32. static int nblocked_emsgs_readers;
  33. static struct class *aoe_class;
  34. static struct aoe_chardev chardevs[] = {
  35. { MINOR_ERR, "err" },
  36. { MINOR_DISCOVER, "discover" },
  37. { MINOR_INTERFACES, "interfaces" },
  38. };
  39. static int
  40. discover(void)
  41. {
  42. aoecmd_cfg(0xffff, 0xff);
  43. return 0;
  44. }
  45. static int
  46. interfaces(const char __user *str, size_t size)
  47. {
  48. if (set_aoe_iflist(str, size)) {
  49. printk(KERN_CRIT
  50.        "%s: could not set interface list: %sn",
  51.        __FUNCTION__, "too many interfaces");
  52. return -EINVAL;
  53. }
  54. return 0;
  55. }
  56. void
  57. aoechr_error(char *msg)
  58. {
  59. struct ErrMsg *em;
  60. char *mp;
  61. ulong flags, n;
  62. n = strlen(msg);
  63. spin_lock_irqsave(&emsgs_lock, flags);
  64. em = emsgs + emsgs_tail_idx;
  65. if ((em->flags & EMFL_VALID)) {
  66. bail: spin_unlock_irqrestore(&emsgs_lock, flags);
  67. return;
  68. }
  69. mp = kmalloc(n, GFP_ATOMIC);
  70. if (mp == NULL) {
  71. printk(KERN_CRIT "aoe: aoechr_error: allocation failure, len=%ldn", n);
  72. goto bail;
  73. }
  74. memcpy(mp, msg, n);
  75. em->msg = mp;
  76. em->flags |= EMFL_VALID;
  77. em->len = n;
  78. emsgs_tail_idx++;
  79. emsgs_tail_idx %= ARRAY_SIZE(emsgs);
  80. spin_unlock_irqrestore(&emsgs_lock, flags);
  81. if (nblocked_emsgs_readers)
  82. up(&emsgs_sema);
  83. }
  84. static ssize_t
  85. aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp)
  86. {
  87. int ret = -EINVAL;
  88. switch ((unsigned long) filp->private_data) {
  89. default:
  90. printk(KERN_INFO "aoe: aoechr_write: can't write to that file.n");
  91. break;
  92. case MINOR_DISCOVER:
  93. ret = discover();
  94. break;
  95. case MINOR_INTERFACES:
  96. ret = interfaces(buf, cnt);
  97. break;
  98. }
  99. if (ret == 0)
  100. ret = cnt;
  101. return ret;
  102. }
  103. static int
  104. aoechr_open(struct inode *inode, struct file *filp)
  105. {
  106. int n, i;
  107. n = MINOR(inode->i_rdev);
  108. filp->private_data = (void *) (unsigned long) n;
  109. for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
  110. if (chardevs[i].minor == n)
  111. return 0;
  112. return -EINVAL;
  113. }
  114. static int
  115. aoechr_rel(struct inode *inode, struct file *filp)
  116. {
  117. return 0;
  118. }
  119. static ssize_t
  120. aoechr_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
  121. {
  122. unsigned long n;
  123. char *mp;
  124. struct ErrMsg *em;
  125. ssize_t len;
  126. ulong flags;
  127. n = (unsigned long) filp->private_data;
  128. switch (n) {
  129. case MINOR_ERR:
  130. spin_lock_irqsave(&emsgs_lock, flags);
  131. loop:
  132. em = emsgs + emsgs_head_idx;
  133. if ((em->flags & EMFL_VALID) == 0) {
  134. if (filp->f_flags & O_NDELAY) {
  135. spin_unlock_irqrestore(&emsgs_lock, flags);
  136. return -EAGAIN;
  137. }
  138. nblocked_emsgs_readers++;
  139. spin_unlock_irqrestore(&emsgs_lock, flags);
  140. n = down_interruptible(&emsgs_sema);
  141. spin_lock_irqsave(&emsgs_lock, flags);
  142. nblocked_emsgs_readers--;
  143. if (n) {
  144. spin_unlock_irqrestore(&emsgs_lock, flags);
  145. return -ERESTARTSYS;
  146. }
  147. goto loop;
  148. }
  149. if (em->len > cnt) {
  150. spin_unlock_irqrestore(&emsgs_lock, flags);
  151. return -EAGAIN;
  152. }
  153. mp = em->msg;
  154. len = em->len;
  155. em->msg = NULL;
  156. em->flags &= ~EMFL_VALID;
  157. emsgs_head_idx++;
  158. emsgs_head_idx %= ARRAY_SIZE(emsgs);
  159. spin_unlock_irqrestore(&emsgs_lock, flags);
  160. n = copy_to_user(buf, mp, len);
  161. kfree(mp);
  162. return n == 0 ? len : -EFAULT;
  163. default:
  164. return -EFAULT;
  165. }
  166. }
  167. static struct file_operations aoe_fops = {
  168. .write = aoechr_write,
  169. .read = aoechr_read,
  170. .open = aoechr_open,
  171. .release = aoechr_rel,
  172. .owner = THIS_MODULE,
  173. };
  174. int __init
  175. aoechr_init(void)
  176. {
  177. int n, i;
  178. n = register_chrdev(AOE_MAJOR, "aoechr", &aoe_fops);
  179. if (n < 0) { 
  180. printk(KERN_ERR "aoe: aoechr_init: can't register char devicen");
  181. return n;
  182. }
  183. sema_init(&emsgs_sema, 0);
  184. spin_lock_init(&emsgs_lock);
  185. aoe_class = class_create(THIS_MODULE, "aoe");
  186. if (IS_ERR(aoe_class)) {
  187. unregister_chrdev(AOE_MAJOR, "aoechr");
  188. return PTR_ERR(aoe_class);
  189. }
  190. for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
  191. class_device_create(aoe_class,
  192. MKDEV(AOE_MAJOR, chardevs[i].minor),
  193. NULL, chardevs[i].name);
  194. return 0;
  195. }
  196. void
  197. aoechr_exit(void)
  198. {
  199. int i;
  200. for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
  201. class_device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor));
  202. class_destroy(aoe_class);
  203. unregister_chrdev(AOE_MAJOR, "aoechr");
  204. }