5571e92c520fcebab78c6493d2478e34a3db15af
[linux-2.6.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         /* The next four are legacy, not per-channel. */
415         case IPMICTL_SET_MY_ADDRESS_CMD:
416         {
417                 unsigned int val;
418
419                 if (copy_from_user(&val, arg, sizeof(val))) {
420                         rv = -EFAULT;
421                         break;
422                 }
423
424                 rv = ipmi_set_my_address(priv->user, 0, val);
425                 break;
426         }
427
428         case IPMICTL_GET_MY_ADDRESS_CMD:
429         {
430                 unsigned int  val;
431                 unsigned char rval;
432
433                 rv = ipmi_get_my_address(priv->user, 0, &rval);
434                 if (rv)
435                         break;
436
437                 val = rval;
438
439                 if (copy_to_user(arg, &val, sizeof(val))) {
440                         rv = -EFAULT;
441                         break;
442                 }
443                 break;
444         }
445
446         case IPMICTL_SET_MY_LUN_CMD:
447         {
448                 unsigned int val;
449
450                 if (copy_from_user(&val, arg, sizeof(val))) {
451                         rv = -EFAULT;
452                         break;
453                 }
454
455                 rv = ipmi_set_my_LUN(priv->user, 0, val);
456                 break;
457         }
458
459         case IPMICTL_GET_MY_LUN_CMD:
460         {
461                 unsigned int  val;
462                 unsigned char rval;
463
464                 rv = ipmi_get_my_LUN(priv->user, 0, &rval);
465                 if (rv)
466                         break;
467
468                 val = rval;
469
470                 if (copy_to_user(arg, &val, sizeof(val))) {
471                         rv = -EFAULT;
472                         break;
473                 }
474                 break;
475         }
476
477         case IPMICTL_SET_MY_CHANNEL_ADDRESS_CMD:
478         {
479                 struct ipmi_channel_lun_address_set val;
480
481                 if (copy_from_user(&val, arg, sizeof(val))) {
482                         rv = -EFAULT;
483                         break;
484                 }
485
486                 return ipmi_set_my_address(priv->user, val.channel, val.value);
487                 break;
488         }
489
490         case IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD:
491         {
492                 struct ipmi_channel_lun_address_set val;
493
494                 if (copy_from_user(&val, arg, sizeof(val))) {
495                         rv = -EFAULT;
496                         break;
497                 }
498
499                 rv = ipmi_get_my_address(priv->user, val.channel, &val.value);
500                 if (rv)
501                         break;
502
503                 if (copy_to_user(arg, &val, sizeof(val))) {
504                         rv = -EFAULT;
505                         break;
506                 }
507                 break;
508         }
509
510         case IPMICTL_SET_MY_CHANNEL_LUN_CMD:
511         {
512                 struct ipmi_channel_lun_address_set val;
513
514                 if (copy_from_user(&val, arg, sizeof(val))) {
515                         rv = -EFAULT;
516                         break;
517                 }
518
519                 rv = ipmi_set_my_LUN(priv->user, val.channel, val.value);
520                 break;
521         }
522
523         case IPMICTL_GET_MY_CHANNEL_LUN_CMD:
524         {
525                 struct ipmi_channel_lun_address_set val;
526
527                 if (copy_from_user(&val, arg, sizeof(val))) {
528                         rv = -EFAULT;
529                         break;
530                 }
531
532                 rv = ipmi_get_my_LUN(priv->user, val.channel, &val.value);
533                 if (rv)
534                         break;
535
536                 if (copy_to_user(arg, &val, sizeof(val))) {
537                         rv = -EFAULT;
538                         break;
539                 }
540                 break;
541         }
542
543         case IPMICTL_SET_TIMING_PARMS_CMD:
544         {
545                 struct ipmi_timing_parms parms;
546
547                 if (copy_from_user(&parms, arg, sizeof(parms))) {
548                         rv = -EFAULT;
549                         break;
550                 }
551
552                 priv->default_retries = parms.retries;
553                 priv->default_retry_time_ms = parms.retry_time_ms;
554                 rv = 0;
555                 break;
556         }
557
558         case IPMICTL_GET_TIMING_PARMS_CMD:
559         {
560                 struct ipmi_timing_parms parms;
561
562                 parms.retries = priv->default_retries;
563                 parms.retry_time_ms = priv->default_retry_time_ms;
564
565                 if (copy_to_user(arg, &parms, sizeof(parms))) {
566                         rv = -EFAULT;
567                         break;
568                 }
569
570                 rv = 0;
571                 break;
572         }
573         }
574   
575         return rv;
576 }
577
578 #ifdef CONFIG_COMPAT
579
580 /*
581  * The following code contains code for supporting 32-bit compatible
582  * ioctls on 64-bit kernels.  This allows running 32-bit apps on the
583  * 64-bit kernel
584  */
585 #define COMPAT_IPMICTL_SEND_COMMAND     \
586         _IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req)
587 #define COMPAT_IPMICTL_SEND_COMMAND_SETTIME     \
588         _IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime)
589 #define COMPAT_IPMICTL_RECEIVE_MSG      \
590         _IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv)
591 #define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC        \
592         _IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv)
593
594 struct compat_ipmi_msg {
595         u8              netfn;
596         u8              cmd;
597         u16             data_len;
598         compat_uptr_t   data;
599 };
600
601 struct compat_ipmi_req {
602         compat_uptr_t           addr;
603         compat_uint_t           addr_len;
604         compat_long_t           msgid;
605         struct compat_ipmi_msg  msg;
606 };
607
608 struct compat_ipmi_recv {
609         compat_int_t            recv_type;
610         compat_uptr_t           addr;
611         compat_uint_t           addr_len;
612         compat_long_t           msgid;
613         struct compat_ipmi_msg  msg;
614 };
615
616 struct compat_ipmi_req_settime {
617         struct compat_ipmi_req  req;
618         compat_int_t            retries;
619         compat_uint_t           retry_time_ms;
620 };
621
622 /*
623  * Define some helper functions for copying IPMI data
624  */
625 static long get_compat_ipmi_msg(struct ipmi_msg *p64,
626                                 struct compat_ipmi_msg __user *p32)
627 {
628         compat_uptr_t tmp;
629
630         if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
631                         __get_user(p64->netfn, &p32->netfn) ||
632                         __get_user(p64->cmd, &p32->cmd) ||
633                         __get_user(p64->data_len, &p32->data_len) ||
634                         __get_user(tmp, &p32->data))
635                 return -EFAULT;
636         p64->data = compat_ptr(tmp);
637         return 0;
638 }
639
640 static long put_compat_ipmi_msg(struct ipmi_msg *p64,
641                                 struct compat_ipmi_msg __user *p32)
642 {
643         if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
644                         __put_user(p64->netfn, &p32->netfn) ||
645                         __put_user(p64->cmd, &p32->cmd) ||
646                         __put_user(p64->data_len, &p32->data_len))
647                 return -EFAULT;
648         return 0;
649 }
650
651 static long get_compat_ipmi_req(struct ipmi_req *p64,
652                                 struct compat_ipmi_req __user *p32)
653 {
654
655         compat_uptr_t   tmp;
656
657         if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
658                         __get_user(tmp, &p32->addr) ||
659                         __get_user(p64->addr_len, &p32->addr_len) ||
660                         __get_user(p64->msgid, &p32->msgid) ||
661                         get_compat_ipmi_msg(&p64->msg, &p32->msg))
662                 return -EFAULT;
663         p64->addr = compat_ptr(tmp);
664         return 0;
665 }
666
667 static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
668                 struct compat_ipmi_req_settime __user *p32)
669 {
670         if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
671                         get_compat_ipmi_req(&p64->req, &p32->req) ||
672                         __get_user(p64->retries, &p32->retries) ||
673                         __get_user(p64->retry_time_ms, &p32->retry_time_ms))
674                 return -EFAULT;
675         return 0;
676 }
677
678 static long get_compat_ipmi_recv(struct ipmi_recv *p64,
679                                  struct compat_ipmi_recv __user *p32)
680 {
681         compat_uptr_t tmp;
682
683         if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
684                         __get_user(p64->recv_type, &p32->recv_type) ||
685                         __get_user(tmp, &p32->addr) ||
686                         __get_user(p64->addr_len, &p32->addr_len) ||
687                         __get_user(p64->msgid, &p32->msgid) ||
688                         get_compat_ipmi_msg(&p64->msg, &p32->msg))
689                 return -EFAULT;
690         p64->addr = compat_ptr(tmp);
691         return 0;
692 }
693
694 static long put_compat_ipmi_recv(struct ipmi_recv *p64,
695                                  struct compat_ipmi_recv __user *p32)
696 {
697         if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
698                         __put_user(p64->recv_type, &p32->recv_type) ||
699                         __put_user(p64->addr_len, &p32->addr_len) ||
700                         __put_user(p64->msgid, &p32->msgid) ||
701                         put_compat_ipmi_msg(&p64->msg, &p32->msg))
702                 return -EFAULT;
703         return 0;
704 }
705
706 /*
707  * Handle compatibility ioctls
708  */
709 static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
710                               unsigned long arg)
711 {
712         int rc;
713         struct ipmi_file_private *priv = filep->private_data;
714
715         switch(cmd) {
716         case COMPAT_IPMICTL_SEND_COMMAND:
717         {
718                 struct ipmi_req rp;
719
720                 if (get_compat_ipmi_req(&rp, compat_ptr(arg)))
721                         return -EFAULT;
722
723                 return handle_send_req(priv->user, &rp,
724                                 priv->default_retries,
725                                 priv->default_retry_time_ms);
726         }
727         case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
728         {
729                 struct ipmi_req_settime sp;
730
731                 if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg)))
732                         return -EFAULT;
733
734                 return handle_send_req(priv->user, &sp.req,
735                                 sp.retries, sp.retry_time_ms);
736         }
737         case COMPAT_IPMICTL_RECEIVE_MSG:
738         case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
739         {
740                 struct ipmi_recv   *precv64, recv64;
741
742                 if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
743                         return -EFAULT;
744
745                 precv64 = compat_alloc_user_space(sizeof(recv64));
746                 if (copy_to_user(precv64, &recv64, sizeof(recv64)))
747                         return -EFAULT;
748
749                 rc = ipmi_ioctl(filep->f_dentry->d_inode, filep,
750                                 ((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
751                                  ? IPMICTL_RECEIVE_MSG
752                                  : IPMICTL_RECEIVE_MSG_TRUNC),
753                                 (long) precv64);
754                 if (rc != 0)
755                         return rc;
756
757                 if (copy_from_user(&recv64, precv64, sizeof(recv64)))
758                         return -EFAULT;
759
760                 if (put_compat_ipmi_recv(&recv64, compat_ptr(arg)))
761                         return -EFAULT;
762
763                 return rc;
764         }
765         default:
766                 return ipmi_ioctl(filep->f_dentry->d_inode, filep, cmd, arg);
767         }
768 }
769 #endif
770
771 static struct file_operations ipmi_fops = {
772         .owner          = THIS_MODULE,
773         .ioctl          = ipmi_ioctl,
774 #ifdef CONFIG_COMPAT
775         .compat_ioctl   = compat_ipmi_ioctl,
776 #endif
777         .open           = ipmi_open,
778         .release        = ipmi_release,
779         .fasync         = ipmi_fasync,
780         .poll           = ipmi_poll,
781 };
782
783 #define DEVICE_NAME     "ipmidev"
784
785 static int ipmi_major = 0;
786 module_param(ipmi_major, int, 0);
787 MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device.  By"
788                  " default, or if you set it to zero, it will choose the next"
789                  " available device.  Setting it to -1 will disable the"
790                  " interface.  Other values will set the major device number"
791                  " to that value.");
792
793 static struct class *ipmi_class;
794
795 static void ipmi_new_smi(int if_num)
796 {
797         dev_t dev = MKDEV(ipmi_major, if_num);
798
799         devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR,
800                       "ipmidev/%d", if_num);
801
802         class_device_create(ipmi_class, dev, NULL, "ipmi%d", if_num);
803 }
804
805 static void ipmi_smi_gone(int if_num)
806 {
807         class_device_destroy(ipmi_class, MKDEV(ipmi_major, if_num));
808         devfs_remove("ipmidev/%d", if_num);
809 }
810
811 static struct ipmi_smi_watcher smi_watcher =
812 {
813         .owner    = THIS_MODULE,
814         .new_smi  = ipmi_new_smi,
815         .smi_gone = ipmi_smi_gone,
816 };
817
818 static __init int init_ipmi_devintf(void)
819 {
820         int rv;
821
822         if (ipmi_major < 0)
823                 return -EINVAL;
824
825         printk(KERN_INFO "ipmi device interface version "
826                IPMI_DEVINTF_VERSION "\n");
827
828         ipmi_class = class_create(THIS_MODULE, "ipmi");
829         if (IS_ERR(ipmi_class)) {
830                 printk(KERN_ERR "ipmi: can't register device class\n");
831                 return PTR_ERR(ipmi_class);
832         }
833
834         rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
835         if (rv < 0) {
836                 class_destroy(ipmi_class);
837                 printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
838                 return rv;
839         }
840
841         if (ipmi_major == 0) {
842                 ipmi_major = rv;
843         }
844
845         devfs_mk_dir(DEVICE_NAME);
846
847         rv = ipmi_smi_watcher_register(&smi_watcher);
848         if (rv) {
849                 unregister_chrdev(ipmi_major, DEVICE_NAME);
850                 class_destroy(ipmi_class);
851                 printk(KERN_WARNING "ipmi: can't register smi watcher\n");
852                 return rv;
853         }
854
855         return 0;
856 }
857 module_init(init_ipmi_devintf);
858
859 static __exit void cleanup_ipmi(void)
860 {
861         class_destroy(ipmi_class);
862         ipmi_smi_watcher_unregister(&smi_watcher);
863         devfs_remove(DEVICE_NAME);
864         unregister_chrdev(ipmi_major, DEVICE_NAME);
865 }
866 module_exit(cleanup_ipmi);
867
868 MODULE_LICENSE("GPL");