]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/char/ipmi/ipmi_devintf.c
Merge /spare/repo/netdev-2.6/ branch 'ieee80211'
[linux-2.6-omap-h63xx.git] / drivers / char / ipmi / ipmi_devintf.c
1 /*
2  * ipmi_devintf.c
3  *
4  * Linux device interface for the IPMI message handler.
5  *
6  * Author: MontaVista Software, Inc.
7  *         Corey Minyard <minyard@mvista.com>
8  *         source@mvista.com
9  *
10  * Copyright 2002 MontaVista Software Inc.
11  *
12  *  This program is free software; you can redistribute it and/or modify it
13  *  under the terms of the GNU General Public License as published by the
14  *  Free Software Foundation; either version 2 of the License, or (at your
15  *  option) any later version.
16  *
17  *
18  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  *  You should have received a copy of the GNU General Public License along
30  *  with this program; if not, write to the Free Software Foundation, Inc.,
31  *  675 Mass Ave, Cambridge, MA 02139, USA.
32  */
33
34 #include <linux/config.h>
35 #include <linux/module.h>
36 #include <linux/moduleparam.h>
37 #include <linux/errno.h>
38 #include <asm/system.h>
39 #include <linux/sched.h>
40 #include <linux/poll.h>
41 #include <linux/spinlock.h>
42 #include <linux/slab.h>
43 #include <linux/devfs_fs_kernel.h>
44 #include <linux/ipmi.h>
45 #include <asm/semaphore.h>
46 #include <linux/init.h>
47 #include <linux/device.h>
48 #include <linux/compat.h>
49
50 #define IPMI_DEVINTF_VERSION "v33"
51
52 struct ipmi_file_private
53 {
54         ipmi_user_t          user;
55         spinlock_t           recv_msg_lock;
56         struct list_head     recv_msgs;
57         struct file          *file;
58         struct fasync_struct *fasync_queue;
59         wait_queue_head_t    wait;
60         struct semaphore     recv_sem;
61         int                  default_retries;
62         unsigned int         default_retry_time_ms;
63 };
64
65 static void file_receive_handler(struct ipmi_recv_msg *msg,
66                                  void                 *handler_data)
67 {
68         struct ipmi_file_private *priv = handler_data;
69         int                      was_empty;
70         unsigned long            flags;
71
72         spin_lock_irqsave(&(priv->recv_msg_lock), flags);
73
74         was_empty = list_empty(&(priv->recv_msgs));
75         list_add_tail(&(msg->link), &(priv->recv_msgs));
76
77         if (was_empty) {
78                 wake_up_interruptible(&priv->wait);
79                 kill_fasync(&priv->fasync_queue, SIGIO, POLL_IN);
80         }
81
82         spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
83 }
84
85 static unsigned int ipmi_poll(struct file *file, poll_table *wait)
86 {
87         struct ipmi_file_private *priv = file->private_data;
88         unsigned int             mask = 0;
89         unsigned long            flags;
90
91         poll_wait(file, &priv->wait, wait);
92
93         spin_lock_irqsave(&priv->recv_msg_lock, flags);
94
95         if (! list_empty(&(priv->recv_msgs)))
96                 mask |= (POLLIN | POLLRDNORM);
97
98         spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
99
100         return mask;
101 }
102
103 static int ipmi_fasync(int fd, struct file *file, int on)
104 {
105         struct ipmi_file_private *priv = file->private_data;
106         int                      result;
107
108         result = fasync_helper(fd, file, on, &priv->fasync_queue);
109
110         return (result);
111 }
112
113 static struct ipmi_user_hndl ipmi_hndlrs =
114 {
115         .ipmi_recv_hndl = file_receive_handler,
116 };
117
118 static int ipmi_open(struct inode *inode, struct file *file)
119 {
120         int                      if_num = iminor(inode);
121         int                      rv;
122         struct ipmi_file_private *priv;
123
124
125         priv = kmalloc(sizeof(*priv), GFP_KERNEL);
126         if (!priv)
127                 return -ENOMEM;
128
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                 return rv;
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         sema_init(&(priv->recv_sem), 1);
147
148         /* Use the low-level defaults. */
149         priv->default_retries = -1;
150         priv->default_retry_time_ms = 0;
151
152         return 0;
153 }
154
155 static int ipmi_release(struct inode *inode, struct file *file)
156 {
157         struct ipmi_file_private *priv = file->private_data;
158         int                      rv;
159
160         rv = ipmi_destroy_user(priv->user);
161         if (rv)
162                 return rv;
163
164         ipmi_fasync (-1, file, 0);
165
166         /* FIXME - free the messages in the list. */
167         kfree(priv);
168
169         return 0;
170 }
171
172 static 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         /* From here out we cannot return, we must jump to "out" for
195            error exits to free msgdata. */
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
231 static 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                 /* We claim a semaphore because we don't want two
291                    users getting something from the queue at a time.
292                    Since we have to release the spinlock before we can
293                    copy the data to the user, it's possible another
294                    user will grab something from the queue, too.  Then
295                    the messages might get out of order if something
296                    fails and the message gets put back onto the
297                    queue.  This semaphore prevents that problem. */
298                 down(&(priv->recv_sem));
299
300                 /* Grab the message off the list. */
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                 up(&(priv->recv_sem));
358                 ipmi_free_recv_msg(msg);
359                 break;
360
361         recv_putback_on_err:
362                 /* If we got an error, put the message back onto
363                    the head of the queue. */
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                 up(&(priv->recv_sem));
368                 break;
369
370         recv_err:
371                 up(&(priv->recv_sem));
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                 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                 break;
399         }
400
401         case IPMICTL_SET_GETS_EVENTS_CMD:
402         {
403                 int val;
404
405                 if (copy_from_user(&val, arg, sizeof(val))) {
406                         rv = -EFAULT;
407                         break;
408                 }
409
410                 rv = ipmi_set_gets_events(priv->user, val);
411                 break;
412         }
413
414         case IPMICTL_SET_MY_ADDRESS_CMD:
415         {
416                 unsigned int val;
417
418                 if (copy_from_user(&val, arg, sizeof(val))) {
419                         rv = -EFAULT;
420                         break;
421                 }
422
423                 ipmi_set_my_address(priv->user, val);
424                 rv = 0;
425                 break;
426         }
427
428         case IPMICTL_GET_MY_ADDRESS_CMD:
429         {
430                 unsigned int val;
431
432                 val = ipmi_get_my_address(priv->user);
433
434                 if (copy_to_user(arg, &val, sizeof(val))) {
435                         rv = -EFAULT;
436                         break;
437                 }
438                 rv = 0;
439                 break;
440         }
441
442         case IPMICTL_SET_MY_LUN_CMD:
443         {
444                 unsigned int val;
445
446                 if (copy_from_user(&val, arg, sizeof(val))) {
447                         rv = -EFAULT;
448                         break;
449                 }
450
451                 ipmi_set_my_LUN(priv->user, val);
452                 rv = 0;
453                 break;
454         }
455
456         case IPMICTL_GET_MY_LUN_CMD:
457         {
458                 unsigned int val;
459
460                 val = ipmi_get_my_LUN(priv->user);
461
462                 if (copy_to_user(arg, &val, sizeof(val))) {
463                         rv = -EFAULT;
464                         break;
465                 }
466                 rv = 0;
467                 break;
468         }
469         case IPMICTL_SET_TIMING_PARMS_CMD:
470         {
471                 struct ipmi_timing_parms parms;
472
473                 if (copy_from_user(&parms, arg, sizeof(parms))) {
474                         rv = -EFAULT;
475                         break;
476                 }
477
478                 priv->default_retries = parms.retries;
479                 priv->default_retry_time_ms = parms.retry_time_ms;
480                 rv = 0;
481                 break;
482         }
483
484         case IPMICTL_GET_TIMING_PARMS_CMD:
485         {
486                 struct ipmi_timing_parms parms;
487
488                 parms.retries = priv->default_retries;
489                 parms.retry_time_ms = priv->default_retry_time_ms;
490
491                 if (copy_to_user(arg, &parms, sizeof(parms))) {
492                         rv = -EFAULT;
493                         break;
494                 }
495
496                 rv = 0;
497                 break;
498         }
499         }
500   
501         return rv;
502 }
503
504 #ifdef CONFIG_COMPAT
505
506 /*
507  * The following code contains code for supporting 32-bit compatible
508  * ioctls on 64-bit kernels.  This allows running 32-bit apps on the
509  * 64-bit kernel
510  */
511 #define COMPAT_IPMICTL_SEND_COMMAND     \
512         _IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req)
513 #define COMPAT_IPMICTL_SEND_COMMAND_SETTIME     \
514         _IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime)
515 #define COMPAT_IPMICTL_RECEIVE_MSG      \
516         _IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv)
517 #define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC        \
518         _IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv)
519
520 struct compat_ipmi_msg {
521         u8              netfn;
522         u8              cmd;
523         u16             data_len;
524         compat_uptr_t   data;
525 };
526
527 struct compat_ipmi_req {
528         compat_uptr_t           addr;
529         compat_uint_t           addr_len;
530         compat_long_t           msgid;
531         struct compat_ipmi_msg  msg;
532 };
533
534 struct compat_ipmi_recv {
535         compat_int_t            recv_type;
536         compat_uptr_t           addr;
537         compat_uint_t           addr_len;
538         compat_long_t           msgid;
539         struct compat_ipmi_msg  msg;
540 };
541
542 struct compat_ipmi_req_settime {
543         struct compat_ipmi_req  req;
544         compat_int_t            retries;
545         compat_uint_t           retry_time_ms;
546 };
547
548 /*
549  * Define some helper functions for copying IPMI data
550  */
551 static long get_compat_ipmi_msg(struct ipmi_msg *p64,
552                                 struct compat_ipmi_msg __user *p32)
553 {
554         compat_uptr_t tmp;
555
556         if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
557                         __get_user(p64->netfn, &p32->netfn) ||
558                         __get_user(p64->cmd, &p32->cmd) ||
559                         __get_user(p64->data_len, &p32->data_len) ||
560                         __get_user(tmp, &p32->data))
561                 return -EFAULT;
562         p64->data = compat_ptr(tmp);
563         return 0;
564 }
565
566 static long put_compat_ipmi_msg(struct ipmi_msg *p64,
567                                 struct compat_ipmi_msg __user *p32)
568 {
569         if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
570                         __put_user(p64->netfn, &p32->netfn) ||
571                         __put_user(p64->cmd, &p32->cmd) ||
572                         __put_user(p64->data_len, &p32->data_len))
573                 return -EFAULT;
574         return 0;
575 }
576
577 static long get_compat_ipmi_req(struct ipmi_req *p64,
578                                 struct compat_ipmi_req __user *p32)
579 {
580
581         compat_uptr_t   tmp;
582
583         if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
584                         __get_user(tmp, &p32->addr) ||
585                         __get_user(p64->addr_len, &p32->addr_len) ||
586                         __get_user(p64->msgid, &p32->msgid) ||
587                         get_compat_ipmi_msg(&p64->msg, &p32->msg))
588                 return -EFAULT;
589         p64->addr = compat_ptr(tmp);
590         return 0;
591 }
592
593 static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
594                 struct compat_ipmi_req_settime __user *p32)
595 {
596         if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
597                         get_compat_ipmi_req(&p64->req, &p32->req) ||
598                         __get_user(p64->retries, &p32->retries) ||
599                         __get_user(p64->retry_time_ms, &p32->retry_time_ms))
600                 return -EFAULT;
601         return 0;
602 }
603
604 static long get_compat_ipmi_recv(struct ipmi_recv *p64,
605                                  struct compat_ipmi_recv __user *p32)
606 {
607         compat_uptr_t tmp;
608
609         if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
610                         __get_user(p64->recv_type, &p32->recv_type) ||
611                         __get_user(tmp, &p32->addr) ||
612                         __get_user(p64->addr_len, &p32->addr_len) ||
613                         __get_user(p64->msgid, &p32->msgid) ||
614                         get_compat_ipmi_msg(&p64->msg, &p32->msg))
615                 return -EFAULT;
616         p64->addr = compat_ptr(tmp);
617         return 0;
618 }
619
620 static long put_compat_ipmi_recv(struct ipmi_recv *p64,
621                                  struct compat_ipmi_recv __user *p32)
622 {
623         if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
624                         __put_user(p64->recv_type, &p32->recv_type) ||
625                         __put_user(p64->addr_len, &p32->addr_len) ||
626                         __put_user(p64->msgid, &p32->msgid) ||
627                         put_compat_ipmi_msg(&p64->msg, &p32->msg))
628                 return -EFAULT;
629         return 0;
630 }
631
632 /*
633  * Handle compatibility ioctls
634  */
635 static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
636                               unsigned long arg)
637 {
638         int rc;
639         struct ipmi_file_private *priv = filep->private_data;
640
641         switch(cmd) {
642         case COMPAT_IPMICTL_SEND_COMMAND:
643         {
644                 struct ipmi_req rp;
645
646                 if (get_compat_ipmi_req(&rp, compat_ptr(arg)))
647                         return -EFAULT;
648
649                 return handle_send_req(priv->user, &rp,
650                                 priv->default_retries,
651                                 priv->default_retry_time_ms);
652         }
653         case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
654         {
655                 struct ipmi_req_settime sp;
656
657                 if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg)))
658                         return -EFAULT;
659
660                 return handle_send_req(priv->user, &sp.req,
661                                 sp.retries, sp.retry_time_ms);
662         }
663         case COMPAT_IPMICTL_RECEIVE_MSG:
664         case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
665         {
666                 struct ipmi_recv   *precv64, recv64;
667
668                 if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
669                         return -EFAULT;
670
671                 precv64 = compat_alloc_user_space(sizeof(recv64));
672                 if (copy_to_user(precv64, &recv64, sizeof(recv64)))
673                         return -EFAULT;
674
675                 rc = ipmi_ioctl(filep->f_dentry->d_inode, filep,
676                                 ((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
677                                  ? IPMICTL_RECEIVE_MSG
678                                  : IPMICTL_RECEIVE_MSG_TRUNC),
679                                 (long) precv64);
680                 if (rc != 0)
681                         return rc;
682
683                 if (copy_from_user(&recv64, precv64, sizeof(recv64)))
684                         return -EFAULT;
685
686                 if (put_compat_ipmi_recv(&recv64, compat_ptr(arg)))
687                         return -EFAULT;
688
689                 return rc;
690         }
691         default:
692                 return ipmi_ioctl(filep->f_dentry->d_inode, filep, cmd, arg);
693         }
694 }
695 #endif
696
697 static struct file_operations ipmi_fops = {
698         .owner          = THIS_MODULE,
699         .ioctl          = ipmi_ioctl,
700 #ifdef CONFIG_COMPAT
701         .compat_ioctl   = compat_ipmi_ioctl,
702 #endif
703         .open           = ipmi_open,
704         .release        = ipmi_release,
705         .fasync         = ipmi_fasync,
706         .poll           = ipmi_poll,
707 };
708
709 #define DEVICE_NAME     "ipmidev"
710
711 static int ipmi_major = 0;
712 module_param(ipmi_major, int, 0);
713 MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device.  By"
714                  " default, or if you set it to zero, it will choose the next"
715                  " available device.  Setting it to -1 will disable the"
716                  " interface.  Other values will set the major device number"
717                  " to that value.");
718
719 static struct class *ipmi_class;
720
721 static void ipmi_new_smi(int if_num)
722 {
723         dev_t dev = MKDEV(ipmi_major, if_num);
724
725         devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR,
726                       "ipmidev/%d", if_num);
727
728         class_device_create(ipmi_class, dev, NULL, "ipmi%d", if_num);
729 }
730
731 static void ipmi_smi_gone(int if_num)
732 {
733         class_device_destroy(ipmi_class, MKDEV(ipmi_major, if_num));
734         devfs_remove("ipmidev/%d", if_num);
735 }
736
737 static struct ipmi_smi_watcher smi_watcher =
738 {
739         .owner    = THIS_MODULE,
740         .new_smi  = ipmi_new_smi,
741         .smi_gone = ipmi_smi_gone,
742 };
743
744 static __init int init_ipmi_devintf(void)
745 {
746         int rv;
747
748         if (ipmi_major < 0)
749                 return -EINVAL;
750
751         printk(KERN_INFO "ipmi device interface version "
752                IPMI_DEVINTF_VERSION "\n");
753
754         ipmi_class = class_create(THIS_MODULE, "ipmi");
755         if (IS_ERR(ipmi_class)) {
756                 printk(KERN_ERR "ipmi: can't register device class\n");
757                 return PTR_ERR(ipmi_class);
758         }
759
760         rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
761         if (rv < 0) {
762                 class_destroy(ipmi_class);
763                 printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
764                 return rv;
765         }
766
767         if (ipmi_major == 0) {
768                 ipmi_major = rv;
769         }
770
771         devfs_mk_dir(DEVICE_NAME);
772
773         rv = ipmi_smi_watcher_register(&smi_watcher);
774         if (rv) {
775                 unregister_chrdev(ipmi_major, DEVICE_NAME);
776                 class_destroy(ipmi_class);
777                 printk(KERN_WARNING "ipmi: can't register smi watcher\n");
778                 return rv;
779         }
780
781         return 0;
782 }
783 module_init(init_ipmi_devintf);
784
785 static __exit void cleanup_ipmi(void)
786 {
787         class_destroy(ipmi_class);
788         ipmi_smi_watcher_unregister(&smi_watcher);
789         devfs_remove(DEVICE_NAME);
790         unregister_chrdev(ipmi_major, DEVICE_NAME);
791 }
792 module_exit(cleanup_ipmi);
793
794 MODULE_LICENSE("GPL");