1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#include <linux/module.h>
35#include <linux/moduleparam.h>
36#include <linux/errno.h>
37#include <asm/system.h>
38#include <linux/poll.h>
39#include <linux/sched.h>
40#include <linux/spinlock.h>
41#include <linux/slab.h>
42#include <linux/ipmi.h>
43#include <linux/mutex.h>
44#include <linux/init.h>
45#include <linux/device.h>
46#include <linux/compat.h>
47
48struct ipmi_file_private
49{
50 ipmi_user_t user;
51 spinlock_t recv_msg_lock;
52 struct list_head recv_msgs;
53 struct file *file;
54 struct fasync_struct *fasync_queue;
55 wait_queue_head_t wait;
56 struct mutex recv_mutex;
57 int default_retries;
58 unsigned int default_retry_time_ms;
59};
60
61static DEFINE_MUTEX(ipmi_mutex);
62static void file_receive_handler(struct ipmi_recv_msg *msg,
63 void *handler_data)
64{
65 struct ipmi_file_private *priv = handler_data;
66 int was_empty;
67 unsigned long flags;
68
69 spin_lock_irqsave(&(priv->recv_msg_lock), flags);
70
71 was_empty = list_empty(&(priv->recv_msgs));
72 list_add_tail(&(msg->link), &(priv->recv_msgs));
73
74 if (was_empty) {
75 wake_up_interruptible(&priv->wait);
76 kill_fasync(&priv->fasync_queue, SIGIO, POLL_IN);
77 }
78
79 spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
80}
81
82static unsigned int ipmi_poll(struct file *file, poll_table *wait)
83{
84 struct ipmi_file_private *priv = file->private_data;
85 unsigned int mask = 0;
86 unsigned long flags;
87
88 poll_wait(file, &priv->wait, wait);
89
90 spin_lock_irqsave(&priv->recv_msg_lock, flags);
91
92 if (!list_empty(&(priv->recv_msgs)))
93 mask |= (POLLIN | POLLRDNORM);
94
95 spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
96
97 return mask;
98}
99
100static int ipmi_fasync(int fd, struct file *file, int on)
101{
102 struct ipmi_file_private *priv = file->private_data;
103 int result;
104
105 mutex_lock(&ipmi_mutex);
106 result = fasync_helper(fd, file, on, &priv->fasync_queue);
107 mutex_unlock(&ipmi_mutex);
108
109 return (result);
110}
111
112static struct ipmi_user_hndl ipmi_hndlrs =
113{
114 .ipmi_recv_hndl = file_receive_handler,
115};
116
117static int ipmi_open(struct inode *inode, struct file *file)
118{
119 int if_num = iminor(inode);
120 int rv;
121 struct ipmi_file_private *priv;
122
123
124 priv = kmalloc(sizeof(*priv), GFP_KERNEL);
125 if (!priv)
126 return -ENOMEM;
127
128 mutex_lock(&ipmi_mutex);
129 priv->file = file;
130
131 rv = ipmi_create_user(if_num,
132 &ipmi_hndlrs,
133 priv,
134 &(priv->user));
135 if (rv) {
136 kfree(priv);
137 goto out;
138 }
139
140 file->private_data = priv;
141
142 spin_lock_init(&(priv->recv_msg_lock));
143 INIT_LIST_HEAD(&(priv->recv_msgs));
144 init_waitqueue_head(&priv->wait);
145 priv->fasync_queue = NULL;
146 mutex_init(&priv->recv_mutex);
147
148
149 priv->default_retries = -1;
150 priv->default_retry_time_ms = 0;
151
152out:
153 mutex_unlock(&ipmi_mutex);
154 return rv;
155}
156
157static int ipmi_release(struct inode *inode, struct file *file)
158{
159 struct ipmi_file_private *priv = file->private_data;
160 int rv;
161
162 rv = ipmi_destroy_user(priv->user);
163 if (rv)
164 return rv;
165
166
167 kfree(priv);
168
169 return 0;
170}
171
172static int handle_send_req(ipmi_user_t user,
173 struct ipmi_req *req,
174 int retries,
175 unsigned int retry_time_ms)
176{
177 int rv;
178 struct ipmi_addr addr;
179 struct kernel_ipmi_msg msg;
180
181 if (req->addr_len > sizeof(struct ipmi_addr))
182 return -EINVAL;
183
184 if (copy_from_user(&addr, req->addr, req->addr_len))
185 return -EFAULT;
186
187 msg.netfn = req->msg.netfn;
188 msg.cmd = req->msg.cmd;
189 msg.data_len = req->msg.data_len;
190 msg.data = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
191 if (!msg.data)
192 return -ENOMEM;
193
194
195
196
197 rv = ipmi_validate_addr(&addr, req->addr_len);
198 if (rv)
199 goto out;
200
201 if (req->msg.data != NULL) {
202 if (req->msg.data_len > IPMI_MAX_MSG_LENGTH) {
203 rv = -EMSGSIZE;
204 goto out;
205 }
206
207 if (copy_from_user(msg.data,
208 req->msg.data,
209 req->msg.data_len))
210 {
211 rv = -EFAULT;
212 goto out;
213 }
214 } else {
215 msg.data_len = 0;
216 }
217
218 rv = ipmi_request_settime(user,
219 &addr,
220 req->msgid,
221 &msg,
222 NULL,
223 0,
224 retries,
225 retry_time_ms);
226 out:
227 kfree(msg.data);
228 return rv;
229}
230
231static int ipmi_ioctl(struct file *file,
232 unsigned int cmd,
233 unsigned long data)
234{
235 int rv = -EINVAL;
236 struct ipmi_file_private *priv = file->private_data;
237 void __user *arg = (void __user *)data;
238
239 switch (cmd)
240 {
241 case IPMICTL_SEND_COMMAND:
242 {
243 struct ipmi_req req;
244
245 if (copy_from_user(&req, arg, sizeof(req))) {
246 rv = -EFAULT;
247 break;
248 }
249
250 rv = handle_send_req(priv->user,
251 &req,
252 priv->default_retries,
253 priv->default_retry_time_ms);
254 break;
255 }
256
257 case IPMICTL_SEND_COMMAND_SETTIME:
258 {
259 struct ipmi_req_settime req;
260
261 if (copy_from_user(&req, arg, sizeof(req))) {
262 rv = -EFAULT;
263 break;
264 }
265
266 rv = handle_send_req(priv->user,
267 &req.req,
268 req.retries,
269 req.retry_time_ms);
270 break;
271 }
272
273 case IPMICTL_RECEIVE_MSG:
274 case IPMICTL_RECEIVE_MSG_TRUNC:
275 {
276 struct ipmi_recv rsp;
277 int addr_len;
278 struct list_head *entry;
279 struct ipmi_recv_msg *msg;
280 unsigned long flags;
281
282
283 rv = 0;
284 if (copy_from_user(&rsp, arg, sizeof(rsp))) {
285 rv = -EFAULT;
286 break;
287 }
288
289
290
291
292
293
294
295
296
297 mutex_lock(&priv->recv_mutex);
298
299
300 spin_lock_irqsave(&(priv->recv_msg_lock), flags);
301 if (list_empty(&(priv->recv_msgs))) {
302 spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
303 rv = -EAGAIN;
304 goto recv_err;
305 }
306 entry = priv->recv_msgs.next;
307 msg = list_entry(entry, struct ipmi_recv_msg, link);
308 list_del(entry);
309 spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
310
311 addr_len = ipmi_addr_length(msg->addr.addr_type);
312 if (rsp.addr_len < addr_len)
313 {
314 rv = -EINVAL;
315 goto recv_putback_on_err;
316 }
317
318 if (copy_to_user(rsp.addr, &(msg->addr), addr_len)) {
319 rv = -EFAULT;
320 goto recv_putback_on_err;
321 }
322 rsp.addr_len = addr_len;
323
324 rsp.recv_type = msg->recv_type;
325 rsp.msgid = msg->msgid;
326 rsp.msg.netfn = msg->msg.netfn;
327 rsp.msg.cmd = msg->msg.cmd;
328
329 if (msg->msg.data_len > 0) {
330 if (rsp.msg.data_len < msg->msg.data_len) {
331 rv = -EMSGSIZE;
332 if (cmd == IPMICTL_RECEIVE_MSG_TRUNC) {
333 msg->msg.data_len = rsp.msg.data_len;
334 } else {
335 goto recv_putback_on_err;
336 }
337 }
338
339 if (copy_to_user(rsp.msg.data,
340 msg->msg.data,
341 msg->msg.data_len))
342 {
343 rv = -EFAULT;
344 goto recv_putback_on_err;
345 }
346 rsp.msg.data_len = msg->msg.data_len;
347 } else {
348 rsp.msg.data_len = 0;
349 }
350
351 if (copy_to_user(arg, &rsp, sizeof(rsp))) {
352 rv = -EFAULT;
353 goto recv_putback_on_err;
354 }
355
356 mutex_unlock(&priv->recv_mutex);
357 ipmi_free_recv_msg(msg);
358 break;
359
360 recv_putback_on_err:
361
362
363 spin_lock_irqsave(&(priv->recv_msg_lock), flags);
364 list_add(entry, &(priv->recv_msgs));
365 spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
366 mutex_unlock(&priv->recv_mutex);
367 break;
368
369 recv_err:
370 mutex_unlock(&priv->recv_mutex);
371 break;
372 }
373
374 case IPMICTL_REGISTER_FOR_CMD:
375 {
376 struct ipmi_cmdspec val;
377
378 if (copy_from_user(&val, arg, sizeof(val))) {
379 rv = -EFAULT;
380 break;
381 }
382
383 rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
384 IPMI_CHAN_ALL);
385 break;
386 }
387
388 case IPMICTL_UNREGISTER_FOR_CMD:
389 {
390 struct ipmi_cmdspec val;
391
392 if (copy_from_user(&val, arg, sizeof(val))) {
393 rv = -EFAULT;
394 break;
395 }
396
397 rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
398 IPMI_CHAN_ALL);
399 break;
400 }
401
402 case IPMICTL_REGISTER_FOR_CMD_CHANS:
403 {
404 struct ipmi_cmdspec_chans val;
405
406 if (copy_from_user(&val, arg, sizeof(val))) {
407 rv = -EFAULT;
408 break;
409 }
410
411 rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
412 val.chans);
413 break;
414 }
415
416 case IPMICTL_UNREGISTER_FOR_CMD_CHANS:
417 {
418 struct ipmi_cmdspec_chans val;
419
420 if (copy_from_user(&val, arg, sizeof(val))) {
421 rv = -EFAULT;
422 break;
423 }
424
425 rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
426 val.chans);
427 break;
428 }
429
430 case IPMICTL_SET_GETS_EVENTS_CMD:
431 {
432 int val;
433
434 if (copy_from_user(&val, arg, sizeof(val))) {
435 rv = -EFAULT;
436 break;
437 }
438
439 rv = ipmi_set_gets_events(priv->user, val);
440 break;
441 }
442
443
444 case IPMICTL_SET_MY_ADDRESS_CMD:
445 {
446 unsigned int val;
447
448 if (copy_from_user(&val, arg, sizeof(val))) {
449 rv = -EFAULT;
450 break;
451 }
452
453 rv = ipmi_set_my_address(priv->user, 0, val);
454 break;
455 }
456
457 case IPMICTL_GET_MY_ADDRESS_CMD:
458 {
459 unsigned int val;
460 unsigned char rval;
461
462 rv = ipmi_get_my_address(priv->user, 0, &rval);
463 if (rv)
464 break;
465
466 val = rval;
467
468 if (copy_to_user(arg, &val, sizeof(val))) {
469 rv = -EFAULT;
470 break;
471 }
472 break;
473 }
474
475 case IPMICTL_SET_MY_LUN_CMD:
476 {
477 unsigned int val;
478
479 if (copy_from_user(&val, arg, sizeof(val))) {
480 rv = -EFAULT;
481 break;
482 }
483
484 rv = ipmi_set_my_LUN(priv->user, 0, val);
485 break;
486 }
487
488 case IPMICTL_GET_MY_LUN_CMD:
489 {
490 unsigned int val;
491 unsigned char rval;
492
493 rv = ipmi_get_my_LUN(priv->user, 0, &rval);
494 if (rv)
495 break;
496
497 val = rval;
498
499 if (copy_to_user(arg, &val, sizeof(val))) {
500 rv = -EFAULT;
501 break;
502 }
503 break;
504 }
505
506 case IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD:
507 {
508 struct ipmi_channel_lun_address_set val;
509
510 if (copy_from_user(&val, arg, sizeof(val))) {
511 rv = -EFAULT;
512 break;
513 }
514
515 return ipmi_set_my_address(priv->user, val.channel, val.value);
516 break;
517 }
518
519 case IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD:
520 {
521 struct ipmi_channel_lun_address_set val;
522
523 if (copy_from_user(&val, arg, sizeof(val))) {
524 rv = -EFAULT;
525 break;
526 }
527
528 rv = ipmi_get_my_address(priv->user, val.channel, &val.value);
529 if (rv)
530 break;
531
532 if (copy_to_user(arg, &val, sizeof(val))) {
533 rv = -EFAULT;
534 break;
535 }
536 break;
537 }
538
539 case IPMICTL_SET_MY_CHANNEL_LUN_CMD:
540 {
541 struct ipmi_channel_lun_address_set val;
542
543 if (copy_from_user(&val, arg, sizeof(val))) {
544 rv = -EFAULT;
545 break;
546 }
547
548 rv = ipmi_set_my_LUN(priv->user, val.channel, val.value);
549 break;
550 }
551
552 case IPMICTL_GET_MY_CHANNEL_LUN_CMD:
553 {
554 struct ipmi_channel_lun_address_set val;
555
556 if (copy_from_user(&val, arg, sizeof(val))) {
557 rv = -EFAULT;
558 break;
559 }
560
561 rv = ipmi_get_my_LUN(priv->user, val.channel, &val.value);
562 if (rv)
563 break;
564
565 if (copy_to_user(arg, &val, sizeof(val))) {
566 rv = -EFAULT;
567 break;
568 }
569 break;
570 }
571
572 case IPMICTL_SET_TIMING_PARMS_CMD:
573 {
574 struct ipmi_timing_parms parms;
575
576 if (copy_from_user(&parms, arg, sizeof(parms))) {
577 rv = -EFAULT;
578 break;
579 }
580
581 priv->default_retries = parms.retries;
582 priv->default_retry_time_ms = parms.retry_time_ms;
583 rv = 0;
584 break;
585 }
586
587 case IPMICTL_GET_TIMING_PARMS_CMD:
588 {
589 struct ipmi_timing_parms parms;
590
591 parms.retries = priv->default_retries;
592 parms.retry_time_ms = priv->default_retry_time_ms;
593
594 if (copy_to_user(arg, &parms, sizeof(parms))) {
595 rv = -EFAULT;
596 break;
597 }
598
599 rv = 0;
600 break;
601 }
602
603 case IPMICTL_GET_MAINTENANCE_MODE_CMD:
604 {
605 int mode;
606
607 mode = ipmi_get_maintenance_mode(priv->user);
608 if (copy_to_user(arg, &mode, sizeof(mode))) {
609 rv = -EFAULT;
610 break;
611 }
612 rv = 0;
613 break;
614 }
615
616 case IPMICTL_SET_MAINTENANCE_MODE_CMD:
617 {
618 int mode;
619
620 if (copy_from_user(&mode, arg, sizeof(mode))) {
621 rv = -EFAULT;
622 break;
623 }
624 rv = ipmi_set_maintenance_mode(priv->user, mode);
625 break;
626 }
627 }
628
629 return rv;
630}
631
632
633
634
635
636static long ipmi_unlocked_ioctl(struct file *file,
637 unsigned int cmd,
638 unsigned long data)
639{
640 int ret;
641
642 mutex_lock(&ipmi_mutex);
643 ret = ipmi_ioctl(file, cmd, data);
644 mutex_unlock(&ipmi_mutex);
645
646 return ret;
647}
648
649#ifdef CONFIG_COMPAT
650
651
652
653
654
655
656#define COMPAT_IPMICTL_SEND_COMMAND \
657 _IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req)
658#define COMPAT_IPMICTL_SEND_COMMAND_SETTIME \
659 _IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime)
660#define COMPAT_IPMICTL_RECEIVE_MSG \
661 _IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv)
662#define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC \
663 _IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv)
664
665struct compat_ipmi_msg {
666 u8 netfn;
667 u8 cmd;
668 u16 data_len;
669 compat_uptr_t data;
670};
671
672struct compat_ipmi_req {
673 compat_uptr_t addr;
674 compat_uint_t addr_len;
675 compat_long_t msgid;
676 struct compat_ipmi_msg msg;
677};
678
679struct compat_ipmi_recv {
680 compat_int_t recv_type;
681 compat_uptr_t addr;
682 compat_uint_t addr_len;
683 compat_long_t msgid;
684 struct compat_ipmi_msg msg;
685};
686
687struct compat_ipmi_req_settime {
688 struct compat_ipmi_req req;
689 compat_int_t retries;
690 compat_uint_t retry_time_ms;
691};
692
693
694
695
696static long get_compat_ipmi_msg(struct ipmi_msg *p64,
697 struct compat_ipmi_msg __user *p32)
698{
699 compat_uptr_t tmp;
700
701 if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
702 __get_user(p64->netfn, &p32->netfn) ||
703 __get_user(p64->cmd, &p32->cmd) ||
704 __get_user(p64->data_len, &p32->data_len) ||
705 __get_user(tmp, &p32->data))
706 return -EFAULT;
707 p64->data = compat_ptr(tmp);
708 return 0;
709}
710
711static long put_compat_ipmi_msg(struct ipmi_msg *p64,
712 struct compat_ipmi_msg __user *p32)
713{
714 if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
715 __put_user(p64->netfn, &p32->netfn) ||
716 __put_user(p64->cmd, &p32->cmd) ||
717 __put_user(p64->data_len, &p32->data_len))
718 return -EFAULT;
719 return 0;
720}
721
722static long get_compat_ipmi_req(struct ipmi_req *p64,
723 struct compat_ipmi_req __user *p32)
724{
725
726 compat_uptr_t tmp;
727
728 if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
729 __get_user(tmp, &p32->addr) ||
730 __get_user(p64->addr_len, &p32->addr_len) ||
731 __get_user(p64->msgid, &p32->msgid) ||
732 get_compat_ipmi_msg(&p64->msg, &p32->msg))
733 return -EFAULT;
734 p64->addr = compat_ptr(tmp);
735 return 0;
736}
737
738static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
739 struct compat_ipmi_req_settime __user *p32)
740{
741 if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
742 get_compat_ipmi_req(&p64->req, &p32->req) ||
743 __get_user(p64->retries, &p32->retries) ||
744 __get_user(p64->retry_time_ms, &p32->retry_time_ms))
745 return -EFAULT;
746 return 0;
747}
748
749static long get_compat_ipmi_recv(struct ipmi_recv *p64,
750 struct compat_ipmi_recv __user *p32)
751{
752 compat_uptr_t tmp;
753
754 if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
755 __get_user(p64->recv_type, &p32->recv_type) ||
756 __get_user(tmp, &p32->addr) ||
757 __get_user(p64->addr_len, &p32->addr_len) ||
758 __get_user(p64->msgid, &p32->msgid) ||
759 get_compat_ipmi_msg(&p64->msg, &p32->msg))
760 return -EFAULT;
761 p64->addr = compat_ptr(tmp);
762 return 0;
763}
764
765static long put_compat_ipmi_recv(struct ipmi_recv *p64,
766 struct compat_ipmi_recv __user *p32)
767{
768 if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
769 __put_user(p64->recv_type, &p32->recv_type) ||
770 __put_user(p64->addr_len, &p32->addr_len) ||
771 __put_user(p64->msgid, &p32->msgid) ||
772 put_compat_ipmi_msg(&p64->msg, &p32->msg))
773 return -EFAULT;
774 return 0;
775}
776
777
778
779
780static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
781 unsigned long arg)
782{
783 int rc;
784 struct ipmi_file_private *priv = filep->private_data;
785
786 switch(cmd) {
787 case COMPAT_IPMICTL_SEND_COMMAND:
788 {
789 struct ipmi_req rp;
790
791 if (get_compat_ipmi_req(&rp, compat_ptr(arg)))
792 return -EFAULT;
793
794 return handle_send_req(priv->user, &rp,
795 priv->default_retries,
796 priv->default_retry_time_ms);
797 }
798 case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
799 {
800 struct ipmi_req_settime sp;
801
802 if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg)))
803 return -EFAULT;
804
805 return handle_send_req(priv->user, &sp.req,
806 sp.retries, sp.retry_time_ms);
807 }
808 case COMPAT_IPMICTL_RECEIVE_MSG:
809 case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
810 {
811 struct ipmi_recv __user *precv64;
812 struct ipmi_recv recv64;
813
814 if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
815 return -EFAULT;
816
817 precv64 = compat_alloc_user_space(sizeof(recv64));
818 if (copy_to_user(precv64, &recv64, sizeof(recv64)))
819 return -EFAULT;
820
821 rc = ipmi_ioctl(filep,
822 ((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
823 ? IPMICTL_RECEIVE_MSG
824 : IPMICTL_RECEIVE_MSG_TRUNC),
825 (unsigned long) precv64);
826 if (rc != 0)
827 return rc;
828
829 if (copy_from_user(&recv64, precv64, sizeof(recv64)))
830 return -EFAULT;
831
832 if (put_compat_ipmi_recv(&recv64, compat_ptr(arg)))
833 return -EFAULT;
834
835 return rc;
836 }
837 default:
838 return ipmi_ioctl(filep, cmd, arg);
839 }
840}
841#endif
842
843static const struct file_operations ipmi_fops = {
844 .owner = THIS_MODULE,
845 .unlocked_ioctl = ipmi_unlocked_ioctl,
846#ifdef CONFIG_COMPAT
847 .compat_ioctl = compat_ipmi_ioctl,
848#endif
849 .open = ipmi_open,
850 .release = ipmi_release,
851 .fasync = ipmi_fasync,
852 .poll = ipmi_poll,
853 .llseek = noop_llseek,
854};
855
856#define DEVICE_NAME "ipmidev"
857
858static int ipmi_major;
859module_param(ipmi_major, int, 0);
860MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device. By"
861 " default, or if you set it to zero, it will choose the next"
862 " available device. Setting it to -1 will disable the"
863 " interface. Other values will set the major device number"
864 " to that value.");
865
866
867struct ipmi_reg_list {
868 dev_t dev;
869 struct list_head link;
870};
871static LIST_HEAD(reg_list);
872static DEFINE_MUTEX(reg_list_mutex);
873
874static struct class *ipmi_class;
875
876static void ipmi_new_smi(int if_num, struct device *device)
877{
878 dev_t dev = MKDEV(ipmi_major, if_num);
879 struct ipmi_reg_list *entry;
880
881 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
882 if (!entry) {
883 printk(KERN_ERR "ipmi_devintf: Unable to create the"
884 " ipmi class device link\n");
885 return;
886 }
887 entry->dev = dev;
888
889 mutex_lock(®_list_mutex);
890 device_create(ipmi_class, device, dev, NULL, "ipmi%d", if_num);
891 list_add(&entry->link, ®_list);
892 mutex_unlock(®_list_mutex);
893}
894
895static void ipmi_smi_gone(int if_num)
896{
897 dev_t dev = MKDEV(ipmi_major, if_num);
898 struct ipmi_reg_list *entry;
899
900 mutex_lock(®_list_mutex);
901 list_for_each_entry(entry, ®_list, link) {
902 if (entry->dev == dev) {
903 list_del(&entry->link);
904 kfree(entry);
905 break;
906 }
907 }
908 device_destroy(ipmi_class, dev);
909 mutex_unlock(®_list_mutex);
910}
911
912static struct ipmi_smi_watcher smi_watcher =
913{
914 .owner = THIS_MODULE,
915 .new_smi = ipmi_new_smi,
916 .smi_gone = ipmi_smi_gone,
917};
918
919static int __init init_ipmi_devintf(void)
920{
921 int rv;
922
923 if (ipmi_major < 0)
924 return -EINVAL;
925
926 printk(KERN_INFO "ipmi device interface\n");
927
928 ipmi_class = class_create(THIS_MODULE, "ipmi");
929 if (IS_ERR(ipmi_class)) {
930 printk(KERN_ERR "ipmi: can't register device class\n");
931 return PTR_ERR(ipmi_class);
932 }
933
934 rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
935 if (rv < 0) {
936 class_destroy(ipmi_class);
937 printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
938 return rv;
939 }
940
941 if (ipmi_major == 0) {
942 ipmi_major = rv;
943 }
944
945 rv = ipmi_smi_watcher_register(&smi_watcher);
946 if (rv) {
947 unregister_chrdev(ipmi_major, DEVICE_NAME);
948 class_destroy(ipmi_class);
949 printk(KERN_WARNING "ipmi: can't register smi watcher\n");
950 return rv;
951 }
952
953 return 0;
954}
955module_init(init_ipmi_devintf);
956
957static void __exit cleanup_ipmi(void)
958{
959 struct ipmi_reg_list *entry, *entry2;
960 mutex_lock(®_list_mutex);
961 list_for_each_entry_safe(entry, entry2, ®_list, link) {
962 list_del(&entry->link);
963 device_destroy(ipmi_class, entry->dev);
964 kfree(entry);
965 }
966 mutex_unlock(®_list_mutex);
967 class_destroy(ipmi_class);
968 ipmi_smi_watcher_unregister(&smi_watcher);
969 unregister_chrdev(ipmi_major, DEVICE_NAME);
970}
971module_exit(cleanup_ipmi);
972
973MODULE_LICENSE("GPL");
974MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
975MODULE_DESCRIPTION("Linux device interface for the IPMI message handler.");
976MODULE_ALIAS("platform:ipmi_si");
977