ipmi_devintf.c revision 53f4654272df7c51064825024340554b39c9efba
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
50struct ipmi_file_private
51{
52	ipmi_user_t          user;
53	spinlock_t           recv_msg_lock;
54	struct list_head     recv_msgs;
55	struct file          *file;
56	struct fasync_struct *fasync_queue;
57	wait_queue_head_t    wait;
58	struct semaphore     recv_sem;
59	int                  default_retries;
60	unsigned int         default_retry_time_ms;
61};
62
63static void file_receive_handler(struct ipmi_recv_msg *msg,
64				 void                 *handler_data)
65{
66	struct ipmi_file_private *priv = handler_data;
67	int                      was_empty;
68	unsigned long            flags;
69
70	spin_lock_irqsave(&(priv->recv_msg_lock), flags);
71
72	was_empty = list_empty(&(priv->recv_msgs));
73	list_add_tail(&(msg->link), &(priv->recv_msgs));
74
75	if (was_empty) {
76		wake_up_interruptible(&priv->wait);
77		kill_fasync(&priv->fasync_queue, SIGIO, POLL_IN);
78	}
79
80	spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
81}
82
83static unsigned int ipmi_poll(struct file *file, poll_table *wait)
84{
85	struct ipmi_file_private *priv = file->private_data;
86	unsigned int             mask = 0;
87	unsigned long            flags;
88
89	poll_wait(file, &priv->wait, wait);
90
91	spin_lock_irqsave(&priv->recv_msg_lock, flags);
92
93	if (! list_empty(&(priv->recv_msgs)))
94		mask |= (POLLIN | POLLRDNORM);
95
96	spin_unlock_irqrestore(&priv->recv_msg_lock, flags);
97
98	return mask;
99}
100
101static int ipmi_fasync(int fd, struct file *file, int on)
102{
103	struct ipmi_file_private *priv = file->private_data;
104	int                      result;
105
106	result = fasync_helper(fd, file, on, &priv->fasync_queue);
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	priv->file = file;
128
129	rv = ipmi_create_user(if_num,
130			      &ipmi_hndlrs,
131			      priv,
132			      &(priv->user));
133	if (rv) {
134		kfree(priv);
135		return rv;
136	}
137
138	file->private_data = priv;
139
140	spin_lock_init(&(priv->recv_msg_lock));
141	INIT_LIST_HEAD(&(priv->recv_msgs));
142	init_waitqueue_head(&priv->wait);
143	priv->fasync_queue = NULL;
144	sema_init(&(priv->recv_sem), 1);
145
146	/* Use the low-level defaults. */
147	priv->default_retries = -1;
148	priv->default_retry_time_ms = 0;
149
150	return 0;
151}
152
153static int ipmi_release(struct inode *inode, struct file *file)
154{
155	struct ipmi_file_private *priv = file->private_data;
156	int                      rv;
157
158	rv = ipmi_destroy_user(priv->user);
159	if (rv)
160		return rv;
161
162	ipmi_fasync (-1, file, 0);
163
164	/* FIXME - free the messages in the list. */
165	kfree(priv);
166
167	return 0;
168}
169
170static int handle_send_req(ipmi_user_t     user,
171			   struct ipmi_req *req,
172			   int             retries,
173			   unsigned int    retry_time_ms)
174{
175	int              rv;
176	struct ipmi_addr addr;
177	struct kernel_ipmi_msg msg;
178
179	if (req->addr_len > sizeof(struct ipmi_addr))
180		return -EINVAL;
181
182	if (copy_from_user(&addr, req->addr, req->addr_len))
183		return -EFAULT;
184
185	msg.netfn = req->msg.netfn;
186	msg.cmd = req->msg.cmd;
187	msg.data_len = req->msg.data_len;
188	msg.data = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
189	if (!msg.data)
190		return -ENOMEM;
191
192	/* From here out we cannot return, we must jump to "out" for
193	   error exits to free msgdata. */
194
195	rv = ipmi_validate_addr(&addr, req->addr_len);
196	if (rv)
197		goto out;
198
199	if (req->msg.data != NULL) {
200		if (req->msg.data_len > IPMI_MAX_MSG_LENGTH) {
201			rv = -EMSGSIZE;
202			goto out;
203		}
204
205		if (copy_from_user(msg.data,
206				   req->msg.data,
207				   req->msg.data_len))
208		{
209			rv = -EFAULT;
210			goto out;
211		}
212	} else {
213		msg.data_len = 0;
214	}
215
216	rv = ipmi_request_settime(user,
217				  &addr,
218				  req->msgid,
219				  &msg,
220				  NULL,
221				  0,
222				  retries,
223				  retry_time_ms);
224 out:
225	kfree(msg.data);
226	return rv;
227}
228
229static int ipmi_ioctl(struct inode  *inode,
230		      struct file   *file,
231		      unsigned int  cmd,
232		      unsigned long data)
233{
234	int                      rv = -EINVAL;
235	struct ipmi_file_private *priv = file->private_data;
236	void __user *arg = (void __user *)data;
237
238	switch (cmd)
239	{
240	case IPMICTL_SEND_COMMAND:
241	{
242		struct ipmi_req req;
243
244		if (copy_from_user(&req, arg, sizeof(req))) {
245			rv = -EFAULT;
246			break;
247		}
248
249		rv = handle_send_req(priv->user,
250				     &req,
251				     priv->default_retries,
252				     priv->default_retry_time_ms);
253		break;
254	}
255
256	case IPMICTL_SEND_COMMAND_SETTIME:
257	{
258		struct ipmi_req_settime req;
259
260		if (copy_from_user(&req, arg, sizeof(req))) {
261			rv = -EFAULT;
262			break;
263		}
264
265		rv = handle_send_req(priv->user,
266				     &req.req,
267				     req.retries,
268				     req.retry_time_ms);
269		break;
270	}
271
272	case IPMICTL_RECEIVE_MSG:
273	case IPMICTL_RECEIVE_MSG_TRUNC:
274	{
275		struct ipmi_recv      rsp;
276		int              addr_len;
277		struct list_head *entry;
278		struct ipmi_recv_msg  *msg;
279		unsigned long    flags;
280
281
282		rv = 0;
283		if (copy_from_user(&rsp, arg, sizeof(rsp))) {
284			rv = -EFAULT;
285			break;
286		}
287
288		/* We claim a semaphore because we don't want two
289                   users getting something from the queue at a time.
290                   Since we have to release the spinlock before we can
291                   copy the data to the user, it's possible another
292                   user will grab something from the queue, too.  Then
293                   the messages might get out of order if something
294                   fails and the message gets put back onto the
295                   queue.  This semaphore prevents that problem. */
296		down(&(priv->recv_sem));
297
298		/* Grab the message off the list. */
299		spin_lock_irqsave(&(priv->recv_msg_lock), flags);
300		if (list_empty(&(priv->recv_msgs))) {
301			spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
302			rv = -EAGAIN;
303			goto recv_err;
304		}
305		entry = priv->recv_msgs.next;
306		msg = list_entry(entry, struct ipmi_recv_msg, link);
307		list_del(entry);
308		spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
309
310		addr_len = ipmi_addr_length(msg->addr.addr_type);
311		if (rsp.addr_len < addr_len)
312		{
313			rv = -EINVAL;
314			goto recv_putback_on_err;
315		}
316
317		if (copy_to_user(rsp.addr, &(msg->addr), addr_len)) {
318			rv = -EFAULT;
319			goto recv_putback_on_err;
320		}
321		rsp.addr_len = addr_len;
322
323		rsp.recv_type = msg->recv_type;
324		rsp.msgid = msg->msgid;
325		rsp.msg.netfn = msg->msg.netfn;
326		rsp.msg.cmd = msg->msg.cmd;
327
328		if (msg->msg.data_len > 0) {
329			if (rsp.msg.data_len < msg->msg.data_len) {
330				rv = -EMSGSIZE;
331				if (cmd == IPMICTL_RECEIVE_MSG_TRUNC) {
332					msg->msg.data_len = rsp.msg.data_len;
333				} else {
334					goto recv_putback_on_err;
335				}
336			}
337
338			if (copy_to_user(rsp.msg.data,
339					 msg->msg.data,
340					 msg->msg.data_len))
341			{
342				rv = -EFAULT;
343				goto recv_putback_on_err;
344			}
345			rsp.msg.data_len = msg->msg.data_len;
346		} else {
347			rsp.msg.data_len = 0;
348		}
349
350		if (copy_to_user(arg, &rsp, sizeof(rsp))) {
351			rv = -EFAULT;
352			goto recv_putback_on_err;
353		}
354
355		up(&(priv->recv_sem));
356		ipmi_free_recv_msg(msg);
357		break;
358
359	recv_putback_on_err:
360		/* If we got an error, put the message back onto
361		   the head of the queue. */
362		spin_lock_irqsave(&(priv->recv_msg_lock), flags);
363		list_add(entry, &(priv->recv_msgs));
364		spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
365		up(&(priv->recv_sem));
366		break;
367
368	recv_err:
369		up(&(priv->recv_sem));
370		break;
371	}
372
373	case IPMICTL_REGISTER_FOR_CMD:
374	{
375		struct ipmi_cmdspec val;
376
377		if (copy_from_user(&val, arg, sizeof(val))) {
378			rv = -EFAULT;
379			break;
380		}
381
382		rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd);
383		break;
384	}
385
386	case IPMICTL_UNREGISTER_FOR_CMD:
387	{
388		struct ipmi_cmdspec   val;
389
390		if (copy_from_user(&val, arg, sizeof(val))) {
391			rv = -EFAULT;
392			break;
393		}
394
395		rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd);
396		break;
397	}
398
399	case IPMICTL_SET_GETS_EVENTS_CMD:
400	{
401		int val;
402
403		if (copy_from_user(&val, arg, sizeof(val))) {
404			rv = -EFAULT;
405			break;
406		}
407
408		rv = ipmi_set_gets_events(priv->user, val);
409		break;
410	}
411
412	/* The next four are legacy, not per-channel. */
413	case IPMICTL_SET_MY_ADDRESS_CMD:
414	{
415		unsigned int val;
416
417		if (copy_from_user(&val, arg, sizeof(val))) {
418			rv = -EFAULT;
419			break;
420		}
421
422		rv = ipmi_set_my_address(priv->user, 0, val);
423		break;
424	}
425
426	case IPMICTL_GET_MY_ADDRESS_CMD:
427	{
428		unsigned int  val;
429		unsigned char rval;
430
431		rv = ipmi_get_my_address(priv->user, 0, &rval);
432		if (rv)
433			break;
434
435		val = rval;
436
437		if (copy_to_user(arg, &val, sizeof(val))) {
438			rv = -EFAULT;
439			break;
440		}
441		break;
442	}
443
444	case IPMICTL_SET_MY_LUN_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_LUN(priv->user, 0, val);
454		break;
455	}
456
457	case IPMICTL_GET_MY_LUN_CMD:
458	{
459		unsigned int  val;
460		unsigned char rval;
461
462		rv = ipmi_get_my_LUN(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_CHANNEL_ADDRESS_CMD:
476	{
477		struct ipmi_channel_lun_address_set val;
478
479		if (copy_from_user(&val, arg, sizeof(val))) {
480			rv = -EFAULT;
481			break;
482		}
483
484		return ipmi_set_my_address(priv->user, val.channel, val.value);
485		break;
486	}
487
488	case IPMICTL_GET_MY_CHANNEL_ADDRESS_CMD:
489	{
490		struct ipmi_channel_lun_address_set val;
491
492		if (copy_from_user(&val, arg, sizeof(val))) {
493			rv = -EFAULT;
494			break;
495		}
496
497		rv = ipmi_get_my_address(priv->user, val.channel, &val.value);
498		if (rv)
499			break;
500
501		if (copy_to_user(arg, &val, sizeof(val))) {
502			rv = -EFAULT;
503			break;
504		}
505		break;
506	}
507
508	case IPMICTL_SET_MY_CHANNEL_LUN_CMD:
509	{
510		struct ipmi_channel_lun_address_set val;
511
512		if (copy_from_user(&val, arg, sizeof(val))) {
513			rv = -EFAULT;
514			break;
515		}
516
517		rv = ipmi_set_my_LUN(priv->user, val.channel, val.value);
518		break;
519	}
520
521	case IPMICTL_GET_MY_CHANNEL_LUN_CMD:
522	{
523		struct ipmi_channel_lun_address_set val;
524
525		if (copy_from_user(&val, arg, sizeof(val))) {
526			rv = -EFAULT;
527			break;
528		}
529
530		rv = ipmi_get_my_LUN(priv->user, val.channel, &val.value);
531		if (rv)
532			break;
533
534		if (copy_to_user(arg, &val, sizeof(val))) {
535			rv = -EFAULT;
536			break;
537		}
538		break;
539	}
540
541	case IPMICTL_SET_TIMING_PARMS_CMD:
542	{
543		struct ipmi_timing_parms parms;
544
545		if (copy_from_user(&parms, arg, sizeof(parms))) {
546			rv = -EFAULT;
547			break;
548		}
549
550		priv->default_retries = parms.retries;
551		priv->default_retry_time_ms = parms.retry_time_ms;
552		rv = 0;
553		break;
554	}
555
556	case IPMICTL_GET_TIMING_PARMS_CMD:
557	{
558		struct ipmi_timing_parms parms;
559
560		parms.retries = priv->default_retries;
561		parms.retry_time_ms = priv->default_retry_time_ms;
562
563		if (copy_to_user(arg, &parms, sizeof(parms))) {
564			rv = -EFAULT;
565			break;
566		}
567
568		rv = 0;
569		break;
570	}
571	}
572
573	return rv;
574}
575
576#ifdef CONFIG_COMPAT
577
578/*
579 * The following code contains code for supporting 32-bit compatible
580 * ioctls on 64-bit kernels.  This allows running 32-bit apps on the
581 * 64-bit kernel
582 */
583#define COMPAT_IPMICTL_SEND_COMMAND	\
584	_IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req)
585#define COMPAT_IPMICTL_SEND_COMMAND_SETTIME	\
586	_IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime)
587#define COMPAT_IPMICTL_RECEIVE_MSG	\
588	_IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv)
589#define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC	\
590	_IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv)
591
592struct compat_ipmi_msg {
593	u8		netfn;
594	u8		cmd;
595	u16		data_len;
596	compat_uptr_t	data;
597};
598
599struct compat_ipmi_req {
600	compat_uptr_t		addr;
601	compat_uint_t		addr_len;
602	compat_long_t		msgid;
603	struct compat_ipmi_msg	msg;
604};
605
606struct compat_ipmi_recv {
607	compat_int_t		recv_type;
608	compat_uptr_t		addr;
609	compat_uint_t		addr_len;
610	compat_long_t		msgid;
611	struct compat_ipmi_msg	msg;
612};
613
614struct compat_ipmi_req_settime {
615	struct compat_ipmi_req	req;
616	compat_int_t		retries;
617	compat_uint_t		retry_time_ms;
618};
619
620/*
621 * Define some helper functions for copying IPMI data
622 */
623static long get_compat_ipmi_msg(struct ipmi_msg *p64,
624				struct compat_ipmi_msg __user *p32)
625{
626	compat_uptr_t tmp;
627
628	if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
629			__get_user(p64->netfn, &p32->netfn) ||
630			__get_user(p64->cmd, &p32->cmd) ||
631			__get_user(p64->data_len, &p32->data_len) ||
632			__get_user(tmp, &p32->data))
633		return -EFAULT;
634	p64->data = compat_ptr(tmp);
635	return 0;
636}
637
638static long put_compat_ipmi_msg(struct ipmi_msg *p64,
639				struct compat_ipmi_msg __user *p32)
640{
641	if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
642			__put_user(p64->netfn, &p32->netfn) ||
643			__put_user(p64->cmd, &p32->cmd) ||
644			__put_user(p64->data_len, &p32->data_len))
645		return -EFAULT;
646	return 0;
647}
648
649static long get_compat_ipmi_req(struct ipmi_req *p64,
650				struct compat_ipmi_req __user *p32)
651{
652
653	compat_uptr_t	tmp;
654
655	if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
656			__get_user(tmp, &p32->addr) ||
657			__get_user(p64->addr_len, &p32->addr_len) ||
658			__get_user(p64->msgid, &p32->msgid) ||
659			get_compat_ipmi_msg(&p64->msg, &p32->msg))
660		return -EFAULT;
661	p64->addr = compat_ptr(tmp);
662	return 0;
663}
664
665static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
666		struct compat_ipmi_req_settime __user *p32)
667{
668	if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
669			get_compat_ipmi_req(&p64->req, &p32->req) ||
670			__get_user(p64->retries, &p32->retries) ||
671			__get_user(p64->retry_time_ms, &p32->retry_time_ms))
672		return -EFAULT;
673	return 0;
674}
675
676static long get_compat_ipmi_recv(struct ipmi_recv *p64,
677				 struct compat_ipmi_recv __user *p32)
678{
679	compat_uptr_t tmp;
680
681	if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
682			__get_user(p64->recv_type, &p32->recv_type) ||
683			__get_user(tmp, &p32->addr) ||
684			__get_user(p64->addr_len, &p32->addr_len) ||
685			__get_user(p64->msgid, &p32->msgid) ||
686			get_compat_ipmi_msg(&p64->msg, &p32->msg))
687		return -EFAULT;
688	p64->addr = compat_ptr(tmp);
689	return 0;
690}
691
692static long put_compat_ipmi_recv(struct ipmi_recv *p64,
693				 struct compat_ipmi_recv __user *p32)
694{
695	if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
696			__put_user(p64->recv_type, &p32->recv_type) ||
697			__put_user(p64->addr_len, &p32->addr_len) ||
698			__put_user(p64->msgid, &p32->msgid) ||
699			put_compat_ipmi_msg(&p64->msg, &p32->msg))
700		return -EFAULT;
701	return 0;
702}
703
704/*
705 * Handle compatibility ioctls
706 */
707static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
708			      unsigned long arg)
709{
710	int rc;
711	struct ipmi_file_private *priv = filep->private_data;
712
713	switch(cmd) {
714	case COMPAT_IPMICTL_SEND_COMMAND:
715	{
716		struct ipmi_req	rp;
717
718		if (get_compat_ipmi_req(&rp, compat_ptr(arg)))
719			return -EFAULT;
720
721		return handle_send_req(priv->user, &rp,
722				priv->default_retries,
723				priv->default_retry_time_ms);
724	}
725	case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
726	{
727		struct ipmi_req_settime	sp;
728
729		if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg)))
730			return -EFAULT;
731
732		return handle_send_req(priv->user, &sp.req,
733				sp.retries, sp.retry_time_ms);
734	}
735	case COMPAT_IPMICTL_RECEIVE_MSG:
736	case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
737	{
738		struct ipmi_recv   __user *precv64;
739		struct ipmi_recv   recv64;
740
741		if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
742			return -EFAULT;
743
744		precv64 = compat_alloc_user_space(sizeof(recv64));
745		if (copy_to_user(precv64, &recv64, sizeof(recv64)))
746			return -EFAULT;
747
748		rc = ipmi_ioctl(filep->f_dentry->d_inode, filep,
749				((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
750				 ? IPMICTL_RECEIVE_MSG
751				 : IPMICTL_RECEIVE_MSG_TRUNC),
752				(unsigned long) precv64);
753		if (rc != 0)
754			return rc;
755
756		if (copy_from_user(&recv64, precv64, sizeof(recv64)))
757			return -EFAULT;
758
759		if (put_compat_ipmi_recv(&recv64, compat_ptr(arg)))
760			return -EFAULT;
761
762		return rc;
763	}
764	default:
765		return ipmi_ioctl(filep->f_dentry->d_inode, filep, cmd, arg);
766	}
767}
768#endif
769
770static struct file_operations ipmi_fops = {
771	.owner		= THIS_MODULE,
772	.ioctl		= ipmi_ioctl,
773#ifdef CONFIG_COMPAT
774	.compat_ioctl   = compat_ipmi_ioctl,
775#endif
776	.open		= ipmi_open,
777	.release	= ipmi_release,
778	.fasync		= ipmi_fasync,
779	.poll		= ipmi_poll,
780};
781
782#define DEVICE_NAME     "ipmidev"
783
784static int ipmi_major = 0;
785module_param(ipmi_major, int, 0);
786MODULE_PARM_DESC(ipmi_major, "Sets the major number of the IPMI device.  By"
787		 " default, or if you set it to zero, it will choose the next"
788		 " available device.  Setting it to -1 will disable the"
789		 " interface.  Other values will set the major device number"
790		 " to that value.");
791
792static struct class *ipmi_class;
793
794static void ipmi_new_smi(int if_num)
795{
796	dev_t dev = MKDEV(ipmi_major, if_num);
797
798	devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR,
799		      "ipmidev/%d", if_num);
800
801	class_device_create(ipmi_class, NULL, dev, NULL, "ipmi%d", if_num);
802}
803
804static void ipmi_smi_gone(int if_num)
805{
806	class_device_destroy(ipmi_class, MKDEV(ipmi_major, if_num));
807	devfs_remove("ipmidev/%d", if_num);
808}
809
810static struct ipmi_smi_watcher smi_watcher =
811{
812	.owner    = THIS_MODULE,
813	.new_smi  = ipmi_new_smi,
814	.smi_gone = ipmi_smi_gone,
815};
816
817static __init int init_ipmi_devintf(void)
818{
819	int rv;
820
821	if (ipmi_major < 0)
822		return -EINVAL;
823
824	printk(KERN_INFO "ipmi device interface\n");
825
826	ipmi_class = class_create(THIS_MODULE, "ipmi");
827	if (IS_ERR(ipmi_class)) {
828		printk(KERN_ERR "ipmi: can't register device class\n");
829		return PTR_ERR(ipmi_class);
830	}
831
832	rv = register_chrdev(ipmi_major, DEVICE_NAME, &ipmi_fops);
833	if (rv < 0) {
834		class_destroy(ipmi_class);
835		printk(KERN_ERR "ipmi: can't get major %d\n", ipmi_major);
836		return rv;
837	}
838
839	if (ipmi_major == 0) {
840		ipmi_major = rv;
841	}
842
843	devfs_mk_dir(DEVICE_NAME);
844
845	rv = ipmi_smi_watcher_register(&smi_watcher);
846	if (rv) {
847		unregister_chrdev(ipmi_major, DEVICE_NAME);
848		class_destroy(ipmi_class);
849		printk(KERN_WARNING "ipmi: can't register smi watcher\n");
850		return rv;
851	}
852
853	return 0;
854}
855module_init(init_ipmi_devintf);
856
857static __exit void cleanup_ipmi(void)
858{
859	class_destroy(ipmi_class);
860	ipmi_smi_watcher_unregister(&smi_watcher);
861	devfs_remove(DEVICE_NAME);
862	unregister_chrdev(ipmi_major, DEVICE_NAME);
863}
864module_exit(cleanup_ipmi);
865
866MODULE_LICENSE("GPL");
867MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
868MODULE_DESCRIPTION("Linux device interface for the IPMI message handler.");
869