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/spinlock.h>
40#include <linux/slab.h>
41#include <linux/ipmi.h>
42#include <linux/mutex.h>
43#include <linux/init.h>
44#include <linux/device.h>
45#include <linux/compat.h>
46#include <linux/smp_lock.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 void file_receive_handler(struct ipmi_recv_msg *msg,
62 void *handler_data)
63{
64 struct ipmi_file_private *priv = handler_data;
65 int was_empty;
66 unsigned long flags;
67
68 spin_lock_irqsave(&(priv->recv_msg_lock), flags);
69
70 was_empty = list_empty(&(priv->recv_msgs));
71 list_add_tail(&(msg->link), &(priv->recv_msgs));
72
73 if (was_empty) {
74 wake_up_interruptible(&priv->wait);
75 kill_fasync(&priv->fasync_queue, SIGIO, POLL_IN);
76 }
77
78 spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
79}
80
81static unsigned int ipmi_poll(struct file *file, poll_table *wait)
82{
83 struct ipmi_file_private *priv = file->private_data;
84 unsigned int mask = 0;
85 unsigned long flags;
86
87 poll_wait(file, &priv->wait, wait);
88
89 spin_lock_irqsave(&priv->recv_msg_lock, flags);
90
91 if (!list_empty(&(priv->recv_msgs)))
92 mask |= (POLLIN | POLLRDNORM);
93
94 spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
95
96 return mask;
97}
98
99static int ipmi_fasync(int fd, struct file *file, int on)
100{
101 struct ipmi_file_private *priv = file->private_data;
102 int result;
103
104 lock_kernel();
105 result = fasync_helper(fd, file, on, &priv->fasync_queue);
106 unlock_kernel();
107
108 return (result);
109}
110
111static struct ipmi_user_hndl ipmi_hndlrs =
112{
113 .ipmi_recv_hndl = file_receive_handler,
114};
115
116static int ipmi_open(struct inode *inode, struct file *file)
117{
118 int if_num = iminor(inode);
119 int rv;
120 struct ipmi_file_private *priv;
121
122
123 priv = kmalloc(sizeof(*priv), GFP_KERNEL);
124 if (!priv)
125 return -ENOMEM;
126
127 lock_kernel();
128 priv->file = file;
129
130 rv = ipmi_create_user(if_num,
131 &ipmi_hndlrs,
132 priv,
133 &(priv->user));
134 if (rv) {
135 kfree(priv);
136 goto out;
137 }
138
139 file->private_data = priv;
140
141 spin_lock_init(&(priv->recv_msg_lock));
142 INIT_LIST_HEAD(&(priv->recv_msgs));
143 init_waitqueue_head(&priv->wait);
144 priv->fasync_queue = NULL;
145 mutex_init(&priv->recv_mutex);
146
147
148 priv->default_retries = -1;
149 priv->default_retry_time_ms = 0;
150
151out:
152 unlock_kernel();
153 return rv;
154}
155
156static int ipmi_release(struct inode *inode, struct file *file)
157{
158 struct ipmi_file_private *priv = file->private_data;
159 int rv;
160
161 rv = ipmi_destroy_user(priv->user);
162 if (rv)
163 return rv;
164
165
166 kfree(priv);
167
168 return 0;
169}
170
171static int handle_send_req(ipmi_user_t user,
172 struct ipmi_req *req,
173 int retries,
174 unsigned int retry_time_ms)
175{
176 int rv;
177 struct ipmi_addr addr;
178 struct kernel_ipmi_msg msg;
179
180 if (req->addr_len > sizeof(struct ipmi_addr))
181 return -EINVAL;
182
183 if (copy_from_user(&addr, req->addr, req->addr_len))
184 return -EFAULT;
185
186 msg.netfn = req->msg.netfn;
187 msg.cmd = req->msg.cmd;
188 msg.data_len = req->msg.data_len;
189 msg.data = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
190 if (!msg.data)
191 return -ENOMEM;
192
193
194
195
196 rv = ipmi_validate_addr(&addr, req->addr_len);
197 if (rv)
198 goto out;
199
200 if (req->msg.data != NULL) {
201 if (req->msg.data_len > IPMI_MAX_MSG_LENGTH) {
202 rv = -EMSGSIZE;
203 goto out;
204 }
205
206 if (copy_from_user(msg.data,
207 req->msg.data,
208 req->msg.data_len))
209 {
210 rv = -EFAULT;
211 goto out;
212 }
213 } else {
214 msg.data_len = 0;
215 }
216
217 rv = ipmi_request_settime(user,
218 &addr,
219 req->msgid,
220 &msg,
221 NULL,
222 0,
223 retries,
224 retry_time_ms);
225 out:
226 kfree(msg.data);
227 return rv;
228}
229
230static int ipmi_ioctl(struct inode *inode,
231 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#ifdef CONFIG_COMPAT
633
634
635
636
637
638
639#define COMPAT_IPMICTL_SEND_COMMAND \
640 _IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req)
641#define COMPAT_IPMICTL_SEND_COMMAND_SETTIME \
642 _IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime)
643#define COMPAT_IPMICTL_RECEIVE_MSG \
644 _IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv)
645#define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC \
646 _IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv)
647
648struct compat_ipmi_msg {
649 u8 netfn;
650 u8 cmd;
651 u16 data_len;
652 compat_uptr_t data;
653};
654
655struct compat_ipmi_req {
656 compat_uptr_t addr;
657 compat_uint_t addr_len;
658 compat_long_t msgid;
659 struct compat_ipmi_msg msg;
660};
661
662struct compat_ipmi_recv {
663 compat_int_t recv_type;
664 compat_uptr_t addr;
665 compat_uint_t addr_len;
666 compat_long_t msgid;
667 struct compat_ipmi_msg msg;
668};
669
670struct compat_ipmi_req_settime {
671 struct compat_ipmi_req req;
672 compat_int_t retries;
673 compat_uint_t retry_time_ms;
674};
675
676
677
678
679static long get_compat_ipmi_msg(struct ipmi_msg *p64,
680 struct compat_ipmi_msg __user *p32)
681{
682 compat_uptr_t tmp;
683
684 if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
685 __get_user(p64->netfn, &p32->netfn) ||
686 __get_user(p64->cmd, &p32->cmd) ||
687 __get_user(p64->data_len, &p32->data_len) ||
688 __get_user(tmp, &p32->data))
689 return -EFAULT;
690 p64->data = compat_ptr(tmp);
691 return 0;
692}
693
694static long put_compat_ipmi_msg(struct ipmi_msg *p64,
695 struct compat_ipmi_msg __user *p32)
696{
697 if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
698 __put_user(p64->netfn, &p32->netfn) ||
699 __put_user(p64->cmd, &p32->cmd) ||
700 __put_user(p64->data_len, &p32->data_len))
701 return -EFAULT;
702 return 0;
703}
704
705static long get_compat_ipmi_req(struct ipmi_req *p64,
706 struct compat_ipmi_req __user *p32)
707{
708
709 compat_uptr_t tmp;
710
711 if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
712 __get_user(tmp, &p32->addr) ||
713 __get_user(p64->addr_len, &p32->addr_len) ||
714 __get_user(p64->msgid, &p32->msgid) ||
715 get_compat_ipmi_msg(&p64->msg, &p32->msg))
716 return -EFAULT;
717 p64->addr = compat_ptr(tmp);
718 return 0;
719}
720
721static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
722 struct compat_ipmi_req_settime __user *p32)
723{
724 if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
725 get_compat_ipmi_req(&p64->req, &p32->req) ||
726 __get_user(p64->retries, &p32->retries) ||
727 __get_user(p64->retry_time_ms, &p32->retry_time_ms))
728 return -EFAULT;
729 return 0;
730}
731
732static long get_compat_ipmi_recv(struct ipmi_recv *p64,
733 struct compat_ipmi_recv __user *p32)
734{
735 compat_uptr_t tmp;
736
737 if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
738 __get_user(p64->recv_type, &p32->recv_type) ||
739 __get_user(tmp, &p32->addr) ||
740 __get_user(p64->addr_len, &p32->addr_len) ||
741 __get_user(p64->msgid, &p32->msgid) ||
742 get_compat_ipmi_msg(&p64->msg, &p32->msg))
743 return -EFAULT;
744 p64->addr = compat_ptr(tmp);
745 return 0;
746}
747
748static long put_compat_ipmi_recv(struct ipmi_recv *p64,
749 struct compat_ipmi_recv __user *p32)
750{
751 if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
752 __put_user(p64->recv_type, &p32->recv_type) ||
753 __put_user(p64->addr_len, &p32->addr_len) ||
754 __put_user(p64->msgid, &p32->msgid) ||
755 put_compat_ipmi_msg(&p64->msg, &p32->msg))
756 return -EFAULT;
757 return 0;
758}
759
760
761
762
763static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
764 unsigned long arg)
765{
766 int rc;
767 struct ipmi_file_private *priv = filep->private_data;
768
769 switch(cmd) {
770 case COMPAT_IPMICTL_SEND_COMMAND:
771 {
772 struct ipmi_req rp;
773
774 if (get_compat_ipmi_req(&rp, compat_ptr(arg)))
775 return -EFAULT;
776
777 return handle_send_req(priv->user, &rp,
778 priv->default_retries,
779 priv->default_retry_time_ms);
780 }
781 case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
782 {
783 struct ipmi_req_settime sp;
784
785 if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg)))
786 return -EFAULT;
787
788 return handle_send_req(priv->user, &sp.req,
789 sp.retries, sp.retry_time_ms);
790 }
791 case COMPAT_IPMICTL_RECEIVE_MSG:
792 case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
793 {
794 struct ipmi_recv __user *precv64;
795 struct ipmi_recv recv64;
796
797 if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
798 return -EFAULT;
799
800 precv64 = compat_alloc_user_space(sizeof(recv64));
801 if (copy_to_user(precv64, &recv64, sizeof(recv64)))
802 return -EFAULT;
803
804 rc = ipmi_ioctl(filep->f_path.dentry->d_inode, filep,
805 ((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
806 ? IPMICTL_RECEIVE_MSG
807 : IPMICTL_RECEIVE_MSG_TRUNC),
808 (unsigned long) precv64);
809 if (rc != 0)
810 return rc;
811
812 if (copy_from_user(&recv64, precv64, sizeof(recv64)))
813 return -EFAULT;
814
815 if (put_compat_ipmi_recv(&recv64, compat_ptr(arg)))
816 return -EFAULT;
817
818 return rc;
819 }
820 default:
821 return ipmi_ioctl(filep->f_path.dentry->d_inode, filep, cmd, arg);
822 }
823}
824#endif
825
826static const struct file_operations ipmi_fops = {
827 .owner = THIS_MODULE,
828 .ioctl = ipmi_ioctl,
829#ifdef CONFIG_COMPAT
830 .compat_ioctl = compat_ipmi_ioctl,
831#endif
832 .open = ipmi_open,
833 .release = ipmi_release,
834 .fasync = ipmi_fasync,
835 .poll = ipmi_poll,
836};
837
838#define DEVICE_NAME "ipmidev"
839
840static int ipmi_major;
841module_param(ipmi_major, int, 0);
842MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device. By"
843 " default, or if you set it to zero, it will choose the next"
844 " available device. Setting it to -1 will disable the"
845 " interface. Other values will set the major device number"
846 " to that value.");
847
848
849struct ipmi_reg_list {
850 dev_t dev;
851 struct list_head link;
852};
853static LIST_HEAD(reg_list);
854static DEFINE_MUTEX(reg_list_mutex);
855
856static struct class *ipmi_class;
857
858static void ipmi_new_smi(int if_num, struct device *device)
859{
860 dev_t dev = MKDEV(ipmi_major, if_num);
861 struct ipmi_reg_list *entry;
862
863 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
864 if (!entry) {
865 printk(KERN_ERR "ipmi_devintf: Unable to create the"
866 " ipmi class device link\n");
867 return;
868 }
869 entry->dev = dev;
870
871 mutex_lock(®_list_mutex);
872 device_create(ipmi_class, device, dev, NULL, "ipmi%d", if_num);
873 list_add(&entry->link, ®_list);
874 mutex_unlock(®_list_mutex);
875}
876
877static void ipmi_smi_gone(int if_num)
878{
879 dev_t dev = MKDEV(ipmi_major, if_num);
880 struct ipmi_reg_list *entry;
881
882 mutex_lock(®_list_mutex);
883 list_for_each_entry(entry, ®_list, link) {
884 if (entry->dev == dev) {
885 list_del(&entry->link);
886 kfree(entry);
887 break;
888 }
889 }
890 device_destroy(ipmi_class, dev);
891 mutex_unlock(®_list_mutex);
892}
893
894static struct ipmi_smi_watcher smi_watcher =
895{
896 .owner = THIS_MODULE,
897 .new_smi = ipmi_new_smi,
898 .smi_gone = ipmi_smi_gone,
899};
900
901static __init int init_ipmi_devintf(void)
902{
903 int rv;
904
905 if (ipmi_major < 0)
906 return -EINVAL;
907
908 printk(KERN_INFO "ipmi device interface\n");
909
910 ipmi_class = class_create(THIS_MODULE, "ipmi");
911 if (IS_ERR(ipmi_class)) {
912 printk(KERN_ERR "ipmi: can't register device class\n");
913 return PTR_ERR(ipmi_class);
914 }
915
916 rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
917 if (rv < 0) {
918 class_destroy(ipmi_class);
919 printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
920 return rv;
921 }
922
923 if (ipmi_major == 0) {
924 ipmi_major = rv;
925 }
926
927 rv = ipmi_smi_watcher_register(&smi_watcher);
928 if (rv) {
929 unregister_chrdev(ipmi_major, DEVICE_NAME);
930 class_destroy(ipmi_class);
931 printk(KERN_WARNING "ipmi: can't register smi watcher\n");
932 return rv;
933 }
934
935 return 0;
936}
937module_init(init_ipmi_devintf);
938
939static __exit void cleanup_ipmi(void)
940{
941 struct ipmi_reg_list *entry, *entry2;
942 mutex_lock(®_list_mutex);
943 list_for_each_entry_safe(entry, entry2, ®_list, link) {
944 list_del(&entry->link);
945 device_destroy(ipmi_class, entry->dev);
946 kfree(entry);
947 }
948 mutex_unlock(®_list_mutex);
949 class_destroy(ipmi_class);
950 ipmi_smi_watcher_unregister(&smi_watcher);
951 unregister_chrdev(ipmi_major, DEVICE_NAME);
952}
953module_exit(cleanup_ipmi);
954
955MODULE_LICENSE("GPL");
956MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
957MODULE_DESCRIPTION("Linux device interface for the IPMI message handler.");
958MODULE_ALIAS("platform:ipmi_si");
959