xref: /linux/drivers/char/ipmi/ipmi_devintf.c (revision d67b569f5f620c0fb95d5212642746b7ba9d29e4)
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");
795