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#include <linux/smp_lock.h>
48
49struct ipmi_file_private
50{
51 ipmi_user_t user;
52 spinlock_t recv_msg_lock;
53 struct list_head recv_msgs;
54 struct file *file;
55 struct fasync_struct *fasync_queue;
56 wait_queue_head_t wait;
57 struct mutex recv_mutex;
58 int default_retries;
59 unsigned int default_retry_time_ms;
60};
61
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 lock_kernel();
106 result = fasync_helper(fd, file, on, &priv->fasync_queue);
107 unlock_kernel();
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 lock_kernel();
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 unlock_kernel();
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 inode *inode,
232 struct file *file,
233 unsigned int cmd,
234 unsigned long data)
235{
236 int rv = -EINVAL;
237 struct ipmi_file_private *priv = file->private_data;
238 void __user *arg = (void __user *)data;
239
240 switch (cmd)
241 {
242 case IPMICTL_SEND_COMMAND:
243 {
244 struct ipmi_req req;
245
246 if (copy_from_user(&req, arg, sizeof(req))) {
247 rv = -EFAULT;
248 break;
249 }
250
251 rv = handle_send_req(priv->user,
252 &req,
253 priv->default_retries,
254 priv->default_retry_time_ms);
255 break;
256 }
257
258 case IPMICTL_SEND_COMMAND_SETTIME:
259 {
260 struct ipmi_req_settime req;
261
262 if (copy_from_user(&req, arg, sizeof(req))) {
263 rv = -EFAULT;
264 break;
265 }
266
267 rv = handle_send_req(priv->user,
268 &req.req,
269 req.retries,
270 req.retry_time_ms);
271 break;
272 }
273
274 case IPMICTL_RECEIVE_MSG:
275 case IPMICTL_RECEIVE_MSG_TRUNC:
276 {
277 struct ipmi_recv rsp;
278 int addr_len;
279 struct list_head *entry;
280 struct ipmi_recv_msg *msg;
281 unsigned long flags;
282
283
284 rv = 0;
285 if (copy_from_user(&rsp, arg, sizeof(rsp))) {
286 rv = -EFAULT;
287 break;
288 }
289
290
291
292
293
294
295
296
297
298 mutex_lock(&priv->recv_mutex);
299
300
301 spin_lock_irqsave(&(priv->recv_msg_lock), flags);
302 if (list_empty(&(priv->recv_msgs))) {
303 spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
304 rv = -EAGAIN;
305 goto recv_err;
306 }
307 entry = priv->recv_msgs.next;
308 msg = list_entry(entry, struct ipmi_recv_msg, link);
309 list_del(entry);
310 spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
311
312 addr_len = ipmi_addr_length(msg->addr.addr_type);
313 if (rsp.addr_len < addr_len)
314 {
315 rv = -EINVAL;
316 goto recv_putback_on_err;
317 }
318
319 if (copy_to_user(rsp.addr, &(msg->addr), addr_len)) {
320 rv = -EFAULT;
321 goto recv_putback_on_err;
322 }
323 rsp.addr_len = addr_len;
324
325 rsp.recv_type = msg->recv_type;
326 rsp.msgid = msg->msgid;
327 rsp.msg.netfn = msg->msg.netfn;
328 rsp.msg.cmd = msg->msg.cmd;
329
330 if (msg->msg.data_len > 0) {
331 if (rsp.msg.data_len < msg->msg.data_len) {
332 rv = -EMSGSIZE;
333 if (cmd == IPMICTL_RECEIVE_MSG_TRUNC) {
334 msg->msg.data_len = rsp.msg.data_len;
335 } else {
336 goto recv_putback_on_err;
337 }
338 }
339
340 if (copy_to_user(rsp.msg.data,
341 msg->msg.data,
342 msg->msg.data_len))
343 {
344 rv = -EFAULT;
345 goto recv_putback_on_err;
346 }
347 rsp.msg.data_len = msg->msg.data_len;
348 } else {
349 rsp.msg.data_len = 0;
350 }
351
352 if (copy_to_user(arg, &rsp, sizeof(rsp))) {
353 rv = -EFAULT;
354 goto recv_putback_on_err;
355 }
356
357 mutex_unlock(&priv->recv_mutex);
358 ipmi_free_recv_msg(msg);
359 break;
360
361 recv_putback_on_err:
362
363
364 spin_lock_irqsave(&(priv->recv_msg_lock), flags);
365 list_add(entry, &(priv->recv_msgs));
366 spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
367 mutex_unlock(&priv->recv_mutex);
368 break;
369
370 recv_err:
371 mutex_unlock(&priv->recv_mutex);
372 break;
373 }
374
375 case IPMICTL_REGISTER_FOR_CMD:
376 {
377 struct ipmi_cmdspec val;
378
379 if (copy_from_user(&val, arg, sizeof(val))) {
380 rv = -EFAULT;
381 break;
382 }
383
384 rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
385 IPMI_CHAN_ALL);
386 break;
387 }
388
389 case IPMICTL_UNREGISTER_FOR_CMD:
390 {
391 struct ipmi_cmdspec val;
392
393 if (copy_from_user(&val, arg, sizeof(val))) {
394 rv = -EFAULT;
395 break;
396 }
397
398 rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
399 IPMI_CHAN_ALL);
400 break;
401 }
402
403 case IPMICTL_REGISTER_FOR_CMD_CHANS:
404 {
405 struct ipmi_cmdspec_chans val;
406
407 if (copy_from_user(&val, arg, sizeof(val))) {
408 rv = -EFAULT;
409 break;
410 }
411
412 rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
413 val.chans);
414 break;
415 }
416
417 case IPMICTL_UNREGISTER_FOR_CMD_CHANS:
418 {
419 struct ipmi_cmdspec_chans val;
420
421 if (copy_from_user(&val, arg, sizeof(val))) {
422 rv = -EFAULT;
423 break;
424 }
425
426 rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
427 val.chans);
428 break;
429 }
430
431 case IPMICTL_SET_GETS_EVENTS_CMD:
432 {
433 int val;
434
435 if (copy_from_user(&val, arg, sizeof(val))) {
436 rv = -EFAULT;
437 break;
438 }
439
440 rv = ipmi_set_gets_events(priv->user, val);
441 break;
442 }
443
444
445 case IPMICTL_SET_MY_ADDRESS_CMD:
446 {
447 unsigned int val;
448
449 if (copy_from_user(&val, arg, sizeof(val))) {
450 rv = -EFAULT;
451 break;
452 }
453
454 rv = ipmi_set_my_address(priv->user, 0, val);
455 break;
456 }
457
458 case IPMICTL_GET_MY_ADDRESS_CMD:
459 {
460 unsigned int val;
461 unsigned char rval;
462
463 rv = ipmi_get_my_address(priv->user, 0, &rval);
464 if (rv)
465 break;
466
467 val = rval;
468
469 if (copy_to_user(arg, &val, sizeof(val))) {
470 rv = -EFAULT;
471 break;
472 }
473 break;
474 }
475
476 case IPMICTL_SET_MY_LUN_CMD:
477 {
478 unsigned int val;
479
480 if (copy_from_user(&val, arg, sizeof(val))) {
481 rv = -EFAULT;
482 break;
483 }
484
485 rv = ipmi_set_my_LUN(priv->user, 0, val);
486 break;
487 }
488
489 case IPMICTL_GET_MY_LUN_CMD:
490 {
491 unsigned int val;
492 unsigned char rval;
493
494 rv = ipmi_get_my_LUN(priv->user, 0, &rval);
495 if (rv)
496 break;
497
498 val = rval;
499
500 if (copy_to_user(arg, &val, sizeof(val))) {
501 rv = -EFAULT;
502 break;
503 }
504 break;
505 }
506
507 case IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD:
508 {
509 struct ipmi_channel_lun_address_set val;
510
511 if (copy_from_user(&val, arg, sizeof(val))) {
512 rv = -EFAULT;
513 break;
514 }
515
516 return ipmi_set_my_address(priv->user, val.channel, val.value);
517 break;
518 }
519
520 case IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD:
521 {
522 struct ipmi_channel_lun_address_set val;
523
524 if (copy_from_user(&val, arg, sizeof(val))) {
525 rv = -EFAULT;
526 break;
527 }
528
529 rv = ipmi_get_my_address(priv->user, val.channel, &val.value);
530 if (rv)
531 break;
532
533 if (copy_to_user(arg, &val, sizeof(val))) {
534 rv = -EFAULT;
535 break;
536 }
537 break;
538 }
539
540 case IPMICTL_SET_MY_CHANNEL_LUN_CMD:
541 {
542 struct ipmi_channel_lun_address_set val;
543
544 if (copy_from_user(&val, arg, sizeof(val))) {
545 rv = -EFAULT;
546 break;
547 }
548
549 rv = ipmi_set_my_LUN(priv->user, val.channel, val.value);
550 break;
551 }
552
553 case IPMICTL_GET_MY_CHANNEL_LUN_CMD:
554 {
555 struct ipmi_channel_lun_address_set val;
556
557 if (copy_from_user(&val, arg, sizeof(val))) {
558 rv = -EFAULT;
559 break;
560 }
561
562 rv = ipmi_get_my_LUN(priv->user, val.channel, &val.value);
563 if (rv)
564 break;
565
566 if (copy_to_user(arg, &val, sizeof(val))) {
567 rv = -EFAULT;
568 break;
569 }
570 break;
571 }
572
573 case IPMICTL_SET_TIMING_PARMS_CMD:
574 {
575 struct ipmi_timing_parms parms;
576
577 if (copy_from_user(&parms, arg, sizeof(parms))) {
578 rv = -EFAULT;
579 break;
580 }
581
582 priv->default_retries = parms.retries;
583 priv->default_retry_time_ms = parms.retry_time_ms;
584 rv = 0;
585 break;
586 }
587
588 case IPMICTL_GET_TIMING_PARMS_CMD:
589 {
590 struct ipmi_timing_parms parms;
591
592 parms.retries = priv->default_retries;
593 parms.retry_time_ms = priv->default_retry_time_ms;
594
595 if (copy_to_user(arg, &parms, sizeof(parms))) {
596 rv = -EFAULT;
597 break;
598 }
599
600 rv = 0;
601 break;
602 }
603
604 case IPMICTL_GET_MAINTENANCE_MODE_CMD:
605 {
606 int mode;
607
608 mode = ipmi_get_maintenance_mode(priv->user);
609 if (copy_to_user(arg, &mode, sizeof(mode))) {
610 rv = -EFAULT;
611 break;
612 }
613 rv = 0;
614 break;
615 }
616
617 case IPMICTL_SET_MAINTENANCE_MODE_CMD:
618 {
619 int mode;
620
621 if (copy_from_user(&mode, arg, sizeof(mode))) {
622 rv = -EFAULT;
623 break;
624 }
625 rv = ipmi_set_maintenance_mode(priv->user, mode);
626 break;
627 }
628 }
629
630 return rv;
631}
632
633#ifdef CONFIG_COMPAT
634
635
636
637
638
639
640#define COMPAT_IPMICTL_SEND_COMMAND \
641 _IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req)
642#define COMPAT_IPMICTL_SEND_COMMAND_SETTIME \
643 _IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime)
644#define COMPAT_IPMICTL_RECEIVE_MSG \
645 _IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv)
646#define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC \
647 _IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv)
648
649struct compat_ipmi_msg {
650 u8 netfn;
651 u8 cmd;
652 u16 data_len;
653 compat_uptr_t data;
654};
655
656struct compat_ipmi_req {
657 compat_uptr_t addr;
658 compat_uint_t addr_len;
659 compat_long_t msgid;
660 struct compat_ipmi_msg msg;
661};
662
663struct compat_ipmi_recv {
664 compat_int_t recv_type;
665 compat_uptr_t addr;
666 compat_uint_t addr_len;
667 compat_long_t msgid;
668 struct compat_ipmi_msg msg;
669};
670
671struct compat_ipmi_req_settime {
672 struct compat_ipmi_req req;
673 compat_int_t retries;
674 compat_uint_t retry_time_ms;
675};
676
677
678
679
680static long get_compat_ipmi_msg(struct ipmi_msg *p64,
681 struct compat_ipmi_msg __user *p32)
682{
683 compat_uptr_t tmp;
684
685 if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
686 __get_user(p64->netfn, &p32->netfn) ||
687 __get_user(p64->cmd, &p32->cmd) ||
688 __get_user(p64->data_len, &p32->data_len) ||
689 __get_user(tmp, &p32->data))
690 return -EFAULT;
691 p64->data = compat_ptr(tmp);
692 return 0;
693}
694
695static long put_compat_ipmi_msg(struct ipmi_msg *p64,
696 struct compat_ipmi_msg __user *p32)
697{
698 if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
699 __put_user(p64->netfn, &p32->netfn) ||
700 __put_user(p64->cmd, &p32->cmd) ||
701 __put_user(p64->data_len, &p32->data_len))
702 return -EFAULT;
703 return 0;
704}
705
706static long get_compat_ipmi_req(struct ipmi_req *p64,
707 struct compat_ipmi_req __user *p32)
708{
709
710 compat_uptr_t tmp;
711
712 if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
713 __get_user(tmp, &p32->addr) ||
714 __get_user(p64->addr_len, &p32->addr_len) ||
715 __get_user(p64->msgid, &p32->msgid) ||
716 get_compat_ipmi_msg(&p64->msg, &p32->msg))
717 return -EFAULT;
718 p64->addr = compat_ptr(tmp);
719 return 0;
720}
721
722static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
723 struct compat_ipmi_req_settime __user *p32)
724{
725 if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
726 get_compat_ipmi_req(&p64->req, &p32->req) ||
727 __get_user(p64->retries, &p32->retries) ||
728 __get_user(p64->retry_time_ms, &p32->retry_time_ms))
729 return -EFAULT;
730 return 0;
731}
732
733static long get_compat_ipmi_recv(struct ipmi_recv *p64,
734 struct compat_ipmi_recv __user *p32)
735{
736 compat_uptr_t tmp;
737
738 if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
739 __get_user(p64->recv_type, &p32->recv_type) ||
740 __get_user(tmp, &p32->addr) ||
741 __get_user(p64->addr_len, &p32->addr_len) ||
742 __get_user(p64->msgid, &p32->msgid) ||
743 get_compat_ipmi_msg(&p64->msg, &p32->msg))
744 return -EFAULT;
745 p64->addr = compat_ptr(tmp);
746 return 0;
747}
748
749static long put_compat_ipmi_recv(struct ipmi_recv *p64,
750 struct compat_ipmi_recv __user *p32)
751{
752 if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
753 __put_user(p64->recv_type, &p32->recv_type) ||
754 __put_user(p64->addr_len, &p32->addr_len) ||
755 __put_user(p64->msgid, &p32->msgid) ||
756 put_compat_ipmi_msg(&p64->msg, &p32->msg))
757 return -EFAULT;
758 return 0;
759}
760
761
762
763
764static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
765 unsigned long arg)
766{
767 int rc;
768 struct ipmi_file_private *priv = filep->private_data;
769
770 switch(cmd) {
771 case COMPAT_IPMICTL_SEND_COMMAND:
772 {
773 struct ipmi_req rp;
774
775 if (get_compat_ipmi_req(&rp, compat_ptr(arg)))
776 return -EFAULT;
777
778 return handle_send_req(priv->user, &rp,
779 priv->default_retries,
780 priv->default_retry_time_ms);
781 }
782 case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
783 {
784 struct ipmi_req_settime sp;
785
786 if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg)))
787 return -EFAULT;
788
789 return handle_send_req(priv->user, &sp.req,
790 sp.retries, sp.retry_time_ms);
791 }
792 case COMPAT_IPMICTL_RECEIVE_MSG:
793 case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
794 {
795 struct ipmi_recv __user *precv64;
796 struct ipmi_recv recv64;
797
798 if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
799 return -EFAULT;
800
801 precv64 = compat_alloc_user_space(sizeof(recv64));
802 if (copy_to_user(precv64, &recv64, sizeof(recv64)))
803 return -EFAULT;
804
805 rc = ipmi_ioctl(filep->f_path.dentry->d_inode, filep,
806 ((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
807 ? IPMICTL_RECEIVE_MSG
808 : IPMICTL_RECEIVE_MSG_TRUNC),
809 (unsigned long) precv64);
810 if (rc != 0)
811 return rc;
812
813 if (copy_from_user(&recv64, precv64, sizeof(recv64)))
814 return -EFAULT;
815
816 if (put_compat_ipmi_recv(&recv64, compat_ptr(arg)))
817 return -EFAULT;
818
819 return rc;
820 }
821 default:
822 return ipmi_ioctl(filep->f_path.dentry->d_inode, filep, cmd, arg);
823 }
824}
825#endif
826
827static const struct file_operations ipmi_fops = {
828 .owner = THIS_MODULE,
829 .ioctl = ipmi_ioctl,
830#ifdef CONFIG_COMPAT
831 .compat_ioctl = compat_ipmi_ioctl,
832#endif
833 .open = ipmi_open,
834 .release = ipmi_release,
835 .fasync = ipmi_fasync,
836 .poll = ipmi_poll,
837};
838
839#define DEVICE_NAME "ipmidev"
840
841static int ipmi_major;
842module_param(ipmi_major, int, 0);
843MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device. By"
844 " default, or if you set it to zero, it will choose the next"
845 " available device. Setting it to -1 will disable the"
846 " interface. Other values will set the major device number"
847 " to that value.");
848
849
850struct ipmi_reg_list {
851 dev_t dev;
852 struct list_head link;
853};
854static LIST_HEAD(reg_list);
855static DEFINE_MUTEX(reg_list_mutex);
856
857static struct class *ipmi_class;
858
859static void ipmi_new_smi(int if_num, struct device *device)
860{
861 dev_t dev = MKDEV(ipmi_major, if_num);
862 struct ipmi_reg_list *entry;
863
864 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
865 if (!entry) {
866 printk(KERN_ERR "ipmi_devintf: Unable to create the"
867 " ipmi class device link\n");
868 return;
869 }
870 entry->dev = dev;
871
872 mutex_lock(®_list_mutex);
873 device_create(ipmi_class, device, dev, NULL, "ipmi%d", if_num);
874 list_add(&entry->link, ®_list);
875 mutex_unlock(®_list_mutex);
876}
877
878static void ipmi_smi_gone(int if_num)
879{
880 dev_t dev = MKDEV(ipmi_major, if_num);
881 struct ipmi_reg_list *entry;
882
883 mutex_lock(®_list_mutex);
884 list_for_each_entry(entry, ®_list, link) {
885 if (entry->dev == dev) {
886 list_del(&entry->link);
887 kfree(entry);
888 break;
889 }
890 }
891 device_destroy(ipmi_class, dev);
892 mutex_unlock(®_list_mutex);
893}
894
895static struct ipmi_smi_watcher smi_watcher =
896{
897 .owner = THIS_MODULE,
898 .new_smi = ipmi_new_smi,
899 .smi_gone = ipmi_smi_gone,
900};
901
902static __init int init_ipmi_devintf(void)
903{
904 int rv;
905
906 if (ipmi_major < 0)
907 return -EINVAL;
908
909 printk(KERN_INFO "ipmi device interface\n");
910
911 ipmi_class = class_create(THIS_MODULE, "ipmi");
912 if (IS_ERR(ipmi_class)) {
913 printk(KERN_ERR "ipmi: can't register device class\n");
914 return PTR_ERR(ipmi_class);
915 }
916
917 rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
918 if (rv < 0) {
919 class_destroy(ipmi_class);
920 printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
921 return rv;
922 }
923
924 if (ipmi_major == 0) {
925 ipmi_major = rv;
926 }
927
928 rv = ipmi_smi_watcher_register(&smi_watcher);
929 if (rv) {
930 unregister_chrdev(ipmi_major, DEVICE_NAME);
931 class_destroy(ipmi_class);
932 printk(KERN_WARNING "ipmi: can't register smi watcher\n");
933 return rv;
934 }
935
936 return 0;
937}
938module_init(init_ipmi_devintf);
939
940static __exit void cleanup_ipmi(void)
941{
942 struct ipmi_reg_list *entry, *entry2;
943 mutex_lock(®_list_mutex);
944 list_for_each_entry_safe(entry, entry2, ®_list, link) {
945 list_del(&entry->link);
946 device_destroy(ipmi_class, entry->dev);
947 kfree(entry);
948 }
949 mutex_unlock(®_list_mutex);
950 class_destroy(ipmi_class);
951 ipmi_smi_watcher_unregister(&smi_watcher);
952 unregister_chrdev(ipmi_major, DEVICE_NAME);
953}
954module_exit(cleanup_ipmi);
955
956MODULE_LICENSE("GPL");
957MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
958MODULE_DESCRIPTION("Linux device interface for the IPMI message handler.");
959MODULE_ALIAS("platform:ipmi_si");
960