Linux 2.6.17.7
[linux/fpc-iii.git] / drivers / s390 / char / vmlogrdr.c
blobc625b69ebd1983b7ab7216c0a68b3fe79c83cc98
1 /*
2 * drivers/s390/char/vmlogrdr.c
3 * character device driver for reading z/VM system service records
6 * Copyright (C) 2004 IBM Corporation
7 * character device driver for reading z/VM system service records,
8 * Version 1.0
9 * Author(s): Xenia Tkatschow <xenia@us.ibm.com>
10 * Stefan Weinhuber <wein@de.ibm.com>
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/errno.h>
16 #include <linux/types.h>
17 #include <linux/interrupt.h>
18 #include <linux/spinlock.h>
19 #include <asm/atomic.h>
20 #include <asm/uaccess.h>
21 #include <asm/cpcmd.h>
22 #include <asm/debug.h>
23 #include <asm/ebcdic.h>
24 #include "../net/iucv.h"
25 #include <linux/kmod.h>
26 #include <linux/cdev.h>
27 #include <linux/device.h>
28 #include <linux/string.h>
32 MODULE_AUTHOR
33 ("(C) 2004 IBM Corporation by Xenia Tkatschow (xenia@us.ibm.com)\n"
34 " Stefan Weinhuber (wein@de.ibm.com)");
35 MODULE_DESCRIPTION ("Character device driver for reading z/VM "
36 "system service records.");
37 MODULE_LICENSE("GPL");
41 * The size of the buffer for iucv data transfer is one page,
42 * but in addition to the data we read from iucv we also
43 * place an integer and some characters into that buffer,
44 * so the maximum size for record data is a little less then
45 * one page.
47 #define NET_BUFFER_SIZE (PAGE_SIZE - sizeof(int) - sizeof(FENCE))
50 * The elements that are concurrently accessed by bottom halves are
51 * connection_established, iucv_path_severed, local_interrupt_buffer
52 * and receive_ready. The first three can be protected by
53 * priv_lock. receive_ready is atomic, so it can be incremented and
54 * decremented without holding a lock.
55 * The variable dev_in_use needs to be protected by the lock, since
56 * it's a flag used by open to make sure that the device is opened only
57 * by one user at the same time.
59 struct vmlogrdr_priv_t {
60 char system_service[8];
61 char internal_name[8];
62 char recording_name[8];
63 u16 pathid;
64 int connection_established;
65 int iucv_path_severed;
66 iucv_MessagePending local_interrupt_buffer;
67 atomic_t receive_ready;
68 iucv_handle_t iucv_handle;
69 int minor_num;
70 char * buffer;
71 char * current_position;
72 int remaining;
73 ulong residual_length;
74 int buffer_free;
75 int dev_in_use; /* 1: already opened, 0: not opened*/
76 spinlock_t priv_lock;
77 struct device *device;
78 struct class_device *class_device;
79 int autorecording;
80 int autopurge;
85 * File operation structure for vmlogrdr devices
87 static int vmlogrdr_open(struct inode *, struct file *);
88 static int vmlogrdr_release(struct inode *, struct file *);
89 static ssize_t vmlogrdr_read (struct file *filp, char *data, size_t count,
90 loff_t * ppos);
92 static struct file_operations vmlogrdr_fops = {
93 .owner = THIS_MODULE,
94 .open = vmlogrdr_open,
95 .release = vmlogrdr_release,
96 .read = vmlogrdr_read,
100 static u8 iucvMagic[16] = {
101 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
102 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
106 static u8 mask[] = {
107 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
108 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
109 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
110 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
114 static u8 iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
117 static void
118 vmlogrdr_iucv_ConnectionComplete(iucv_ConnectionComplete *eib, void *pgm_data);
119 static void
120 vmlogrdr_iucv_ConnectionSevered(iucv_ConnectionSevered *eib, void *pgm_data);
121 static void
122 vmlogrdr_iucv_MessagePending(iucv_MessagePending *eib, void *pgm_data);
125 static iucv_interrupt_ops_t vmlogrdr_iucvops = {
126 .ConnectionComplete = vmlogrdr_iucv_ConnectionComplete,
127 .ConnectionSevered = vmlogrdr_iucv_ConnectionSevered,
128 .MessagePending = vmlogrdr_iucv_MessagePending,
132 DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue);
133 DECLARE_WAIT_QUEUE_HEAD(read_wait_queue);
136 * pointer to system service private structure
137 * minor number 0 --> logrec
138 * minor number 1 --> account
139 * minor number 2 --> symptom
142 static struct vmlogrdr_priv_t sys_ser[] = {
143 { .system_service = "*LOGREC ",
144 .internal_name = "logrec",
145 .recording_name = "EREP",
146 .minor_num = 0,
147 .buffer_free = 1,
148 .priv_lock = SPIN_LOCK_UNLOCKED,
149 .autorecording = 1,
150 .autopurge = 1,
152 { .system_service = "*ACCOUNT",
153 .internal_name = "account",
154 .recording_name = "ACCOUNT",
155 .minor_num = 1,
156 .buffer_free = 1,
157 .priv_lock = SPIN_LOCK_UNLOCKED,
158 .autorecording = 1,
159 .autopurge = 1,
161 { .system_service = "*SYMPTOM",
162 .internal_name = "symptom",
163 .recording_name = "SYMPTOM",
164 .minor_num = 2,
165 .buffer_free = 1,
166 .priv_lock = SPIN_LOCK_UNLOCKED,
167 .autorecording = 1,
168 .autopurge = 1,
172 #define MAXMINOR (sizeof(sys_ser)/sizeof(struct vmlogrdr_priv_t))
174 static char FENCE[] = {"EOR"};
175 static int vmlogrdr_major = 0;
176 static struct cdev *vmlogrdr_cdev = NULL;
177 static int recording_class_AB;
180 static void
181 vmlogrdr_iucv_ConnectionComplete (iucv_ConnectionComplete * eib,
182 void * pgm_data)
184 struct vmlogrdr_priv_t * logptr = pgm_data;
185 spin_lock(&logptr->priv_lock);
186 logptr->connection_established = 1;
187 spin_unlock(&logptr->priv_lock);
188 wake_up(&conn_wait_queue);
189 return;
193 static void
194 vmlogrdr_iucv_ConnectionSevered (iucv_ConnectionSevered * eib, void * pgm_data)
196 u8 reason = (u8) eib->ipuser[8];
197 struct vmlogrdr_priv_t * logptr = pgm_data;
199 printk (KERN_ERR "vmlogrdr: connection severed with"
200 " reason %i\n", reason);
202 spin_lock(&logptr->priv_lock);
203 logptr->connection_established = 0;
204 logptr->iucv_path_severed = 1;
205 spin_unlock(&logptr->priv_lock);
207 wake_up(&conn_wait_queue);
208 /* just in case we're sleeping waiting for a record */
209 wake_up_interruptible(&read_wait_queue);
213 static void
214 vmlogrdr_iucv_MessagePending (iucv_MessagePending * eib, void * pgm_data)
216 struct vmlogrdr_priv_t * logptr = pgm_data;
219 * This function is the bottom half so it should be quick.
220 * Copy the external interrupt data into our local eib and increment
221 * the usage count
223 spin_lock(&logptr->priv_lock);
224 memcpy(&(logptr->local_interrupt_buffer), eib, sizeof(*eib));
225 atomic_inc(&logptr->receive_ready);
226 spin_unlock(&logptr->priv_lock);
227 wake_up_interruptible(&read_wait_queue);
231 static int
232 vmlogrdr_get_recording_class_AB(void) {
233 char cp_command[]="QUERY COMMAND RECORDING ";
234 char cp_response[80];
235 char *tail;
236 int len,i;
238 printk (KERN_DEBUG "vmlogrdr: query command: %s\n", cp_command);
239 cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
240 printk (KERN_DEBUG "vmlogrdr: response: %s", cp_response);
241 len = strnlen(cp_response,sizeof(cp_response));
242 // now the parsing
243 tail=strnchr(cp_response,len,'=');
244 if (!tail)
245 return 0;
246 tail++;
247 if (!strncmp("ANY",tail,3))
248 return 1;
249 if (!strncmp("NONE",tail,4))
250 return 0;
252 * expect comma separated list of classes here, if one of them
253 * is A or B return 1 otherwise 0
255 for (i=tail-cp_response; i<len; i++)
256 if ( cp_response[i]=='A' || cp_response[i]=='B' )
257 return 1;
258 return 0;
262 static int
263 vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) {
265 char cp_command[80];
266 char cp_response[160];
267 char *onoff, *qid_string;
269 memset(cp_command, 0x00, sizeof(cp_command));
270 memset(cp_response, 0x00, sizeof(cp_response));
272 onoff = ((action == 1) ? "ON" : "OFF");
273 qid_string = ((recording_class_AB == 1) ? " QID * " : "");
276 * The recording commands needs to be called with option QID
277 * for guests that have previlege classes A or B.
278 * Purging has to be done as separate step, because recording
279 * can't be switched on as long as records are on the queue.
280 * Doing both at the same time doesn't work.
283 if (purge) {
284 snprintf(cp_command, sizeof(cp_command),
285 "RECORDING %s PURGE %s",
286 logptr->recording_name,
287 qid_string);
289 printk (KERN_DEBUG "vmlogrdr: recording command: %s\n",
290 cp_command);
291 cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
292 printk (KERN_DEBUG "vmlogrdr: recording response: %s",
293 cp_response);
296 memset(cp_command, 0x00, sizeof(cp_command));
297 memset(cp_response, 0x00, sizeof(cp_response));
298 snprintf(cp_command, sizeof(cp_command), "RECORDING %s %s %s",
299 logptr->recording_name,
300 onoff,
301 qid_string);
303 printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command);
304 cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
305 printk (KERN_DEBUG "vmlogrdr: recording response: %s",
306 cp_response);
307 /* The recording command will usually answer with 'Command complete'
308 * on success, but when the specific service was never connected
309 * before then there might be an additional informational message
310 * 'HCPCRC8072I Recording entry not found' before the
311 * 'Command complete'. So I use strstr rather then the strncmp.
313 if (strstr(cp_response,"Command complete"))
314 return 0;
315 else
316 return -EIO;
321 static int
322 vmlogrdr_open (struct inode *inode, struct file *filp)
324 int dev_num = 0;
325 struct vmlogrdr_priv_t * logptr = NULL;
326 int connect_rc = 0;
327 int ret;
329 dev_num = iminor(inode);
330 if (dev_num > MAXMINOR)
331 return -ENODEV;
333 logptr = &sys_ser[dev_num];
334 if (logptr == NULL)
335 return -ENODEV;
338 * only allow for blocking reads to be open
340 if (filp->f_flags & O_NONBLOCK)
341 return -ENOSYS;
343 /* Besure this device hasn't already been opened */
344 spin_lock_bh(&logptr->priv_lock);
345 if (logptr->dev_in_use) {
346 spin_unlock_bh(&logptr->priv_lock);
347 return -EBUSY;
348 } else {
349 logptr->dev_in_use = 1;
350 spin_unlock_bh(&logptr->priv_lock);
353 atomic_set(&logptr->receive_ready, 0);
354 logptr->buffer_free = 1;
356 /* set the file options */
357 filp->private_data = logptr;
358 filp->f_op = &vmlogrdr_fops;
360 /* start recording for this service*/
361 ret=0;
362 if (logptr->autorecording)
363 ret = vmlogrdr_recording(logptr,1,logptr->autopurge);
364 if (ret)
365 printk (KERN_WARNING "vmlogrdr: failed to start "
366 "recording automatically\n");
368 /* Register with iucv driver */
369 logptr->iucv_handle = iucv_register_program(iucvMagic,
370 logptr->system_service, mask, &vmlogrdr_iucvops,
371 logptr);
373 if (logptr->iucv_handle == NULL) {
374 printk (KERN_ERR "vmlogrdr: failed to register with"
375 "iucv driver\n");
376 goto not_registered;
379 /* create connection to the system service */
380 spin_lock_bh(&logptr->priv_lock);
381 logptr->connection_established = 0;
382 logptr->iucv_path_severed = 0;
383 spin_unlock_bh(&logptr->priv_lock);
385 connect_rc = iucv_connect (&(logptr->pathid), 10, iucvMagic,
386 logptr->system_service, iucv_host, 0,
387 NULL, NULL,
388 logptr->iucv_handle, NULL);
389 if (connect_rc) {
390 printk (KERN_ERR "vmlogrdr: iucv connection to %s "
391 "failed with rc %i \n", logptr->system_service,
392 connect_rc);
393 goto not_connected;
396 /* We've issued the connect and now we must wait for a
397 * ConnectionComplete or ConnectinSevered Interrupt
398 * before we can continue to process.
400 wait_event(conn_wait_queue, (logptr->connection_established)
401 || (logptr->iucv_path_severed));
402 if (logptr->iucv_path_severed) {
403 goto not_connected;
406 return nonseekable_open(inode, filp);
408 not_connected:
409 iucv_unregister_program(logptr->iucv_handle);
410 logptr->iucv_handle = NULL;
411 not_registered:
412 if (logptr->autorecording)
413 vmlogrdr_recording(logptr,0,logptr->autopurge);
414 logptr->dev_in_use = 0;
415 return -EIO;
421 static int
422 vmlogrdr_release (struct inode *inode, struct file *filp)
424 int ret;
426 struct vmlogrdr_priv_t * logptr = filp->private_data;
428 iucv_unregister_program(logptr->iucv_handle);
429 logptr->iucv_handle = NULL;
431 if (logptr->autorecording) {
432 ret = vmlogrdr_recording(logptr,0,logptr->autopurge);
433 if (ret)
434 printk (KERN_WARNING "vmlogrdr: failed to stop "
435 "recording automatically\n");
437 logptr->dev_in_use = 0;
439 return 0;
443 static int
444 vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv) {
445 int rc, *temp;
446 /* we need to keep track of two data sizes here:
447 * The number of bytes we need to receive from iucv and
448 * the total number of bytes we actually write into the buffer.
450 int user_data_count, iucv_data_count;
451 char * buffer;
453 if (atomic_read(&priv->receive_ready)) {
454 spin_lock_bh(&priv->priv_lock);
455 if (priv->residual_length){
456 /* receive second half of a record */
457 iucv_data_count = priv->residual_length;
458 user_data_count = 0;
459 buffer = priv->buffer;
460 } else {
461 /* receive a new record:
462 * We need to return the total length of the record
463 * + size of FENCE in the first 4 bytes of the buffer.
465 iucv_data_count =
466 priv->local_interrupt_buffer.ln1msg2.ipbfln1f;
467 user_data_count = sizeof(int);
468 temp = (int*)priv->buffer;
469 *temp= iucv_data_count + sizeof(FENCE);
470 buffer = priv->buffer + sizeof(int);
473 * If the record is bigger then our buffer, we receive only
474 * a part of it. We can get the rest later.
476 if (iucv_data_count > NET_BUFFER_SIZE)
477 iucv_data_count = NET_BUFFER_SIZE;
478 rc = iucv_receive(priv->pathid,
479 priv->local_interrupt_buffer.ipmsgid,
480 priv->local_interrupt_buffer.iptrgcls,
481 buffer,
482 iucv_data_count,
483 NULL,
484 NULL,
485 &priv->residual_length);
486 spin_unlock_bh(&priv->priv_lock);
487 /* An rc of 5 indicates that the record was bigger then
488 * the buffer, which is OK for us. A 9 indicates that the
489 * record was purged befor we could receive it.
491 if (rc == 5)
492 rc = 0;
493 if (rc == 9)
494 atomic_set(&priv->receive_ready, 0);
495 } else {
496 rc = 1;
498 if (!rc) {
499 priv->buffer_free = 0;
500 user_data_count += iucv_data_count;
501 priv->current_position = priv->buffer;
502 if (priv->residual_length == 0){
503 /* the whole record has been captured,
504 * now add the fence */
505 atomic_dec(&priv->receive_ready);
506 buffer = priv->buffer + user_data_count;
507 memcpy(buffer, FENCE, sizeof(FENCE));
508 user_data_count += sizeof(FENCE);
510 priv->remaining = user_data_count;
513 return rc;
517 static ssize_t
518 vmlogrdr_read (struct file *filp, char *data, size_t count, loff_t * ppos)
520 int rc;
521 struct vmlogrdr_priv_t * priv = filp->private_data;
523 while (priv->buffer_free) {
524 rc = vmlogrdr_receive_data(priv);
525 if (rc) {
526 rc = wait_event_interruptible(read_wait_queue,
527 atomic_read(&priv->receive_ready));
528 if (rc)
529 return rc;
532 /* copy only up to end of record */
533 if (count > priv->remaining)
534 count = priv->remaining;
536 if (copy_to_user(data, priv->current_position, count))
537 return -EFAULT;
539 *ppos += count;
540 priv->current_position += count;
541 priv->remaining -= count;
543 /* if all data has been transferred, set buffer free */
544 if (priv->remaining == 0)
545 priv->buffer_free = 1;
547 return count;
550 static ssize_t
551 vmlogrdr_autopurge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) {
552 struct vmlogrdr_priv_t *priv = dev->driver_data;
553 ssize_t ret = count;
555 switch (buf[0]) {
556 case '0':
557 priv->autopurge=0;
558 break;
559 case '1':
560 priv->autopurge=1;
561 break;
562 default:
563 ret = -EINVAL;
565 return ret;
569 static ssize_t
570 vmlogrdr_autopurge_show(struct device *dev, struct device_attribute *attr, char *buf) {
571 struct vmlogrdr_priv_t *priv = dev->driver_data;
572 return sprintf(buf, "%u\n", priv->autopurge);
576 static DEVICE_ATTR(autopurge, 0644, vmlogrdr_autopurge_show,
577 vmlogrdr_autopurge_store);
580 static ssize_t
581 vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) {
583 char cp_command[80];
584 char cp_response[80];
585 struct vmlogrdr_priv_t *priv = dev->driver_data;
587 if (buf[0] != '1')
588 return -EINVAL;
590 memset(cp_command, 0x00, sizeof(cp_command));
591 memset(cp_response, 0x00, sizeof(cp_response));
594 * The recording command needs to be called with option QID
595 * for guests that have previlege classes A or B.
596 * Other guests will not recognize the command and we have to
597 * issue the same command without the QID parameter.
600 if (recording_class_AB)
601 snprintf(cp_command, sizeof(cp_command),
602 "RECORDING %s PURGE QID * ",
603 priv->recording_name);
604 else
605 snprintf(cp_command, sizeof(cp_command),
606 "RECORDING %s PURGE ",
607 priv->recording_name);
609 printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command);
610 cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
611 printk (KERN_DEBUG "vmlogrdr: recording response: %s",
612 cp_response);
614 return count;
618 static DEVICE_ATTR(purge, 0200, NULL, vmlogrdr_purge_store);
621 static ssize_t
622 vmlogrdr_autorecording_store(struct device *dev, struct device_attribute *attr, const char *buf,
623 size_t count) {
624 struct vmlogrdr_priv_t *priv = dev->driver_data;
625 ssize_t ret = count;
627 switch (buf[0]) {
628 case '0':
629 priv->autorecording=0;
630 break;
631 case '1':
632 priv->autorecording=1;
633 break;
634 default:
635 ret = -EINVAL;
637 return ret;
641 static ssize_t
642 vmlogrdr_autorecording_show(struct device *dev, struct device_attribute *attr, char *buf) {
643 struct vmlogrdr_priv_t *priv = dev->driver_data;
644 return sprintf(buf, "%u\n", priv->autorecording);
648 static DEVICE_ATTR(autorecording, 0644, vmlogrdr_autorecording_show,
649 vmlogrdr_autorecording_store);
652 static ssize_t
653 vmlogrdr_recording_store(struct device * dev, struct device_attribute *attr, const char * buf, size_t count) {
655 struct vmlogrdr_priv_t *priv = dev->driver_data;
656 ssize_t ret;
658 switch (buf[0]) {
659 case '0':
660 ret = vmlogrdr_recording(priv,0,0);
661 break;
662 case '1':
663 ret = vmlogrdr_recording(priv,1,0);
664 break;
665 default:
666 ret = -EINVAL;
668 if (ret)
669 return ret;
670 else
671 return count;
676 static DEVICE_ATTR(recording, 0200, NULL, vmlogrdr_recording_store);
679 static ssize_t
680 vmlogrdr_recording_status_show(struct device_driver *driver, char *buf) {
682 char cp_command[] = "QUERY RECORDING ";
683 int len;
685 cpcmd(cp_command, buf, 4096, NULL);
686 len = strlen(buf);
687 return len;
691 static DRIVER_ATTR(recording_status, 0444, vmlogrdr_recording_status_show,
692 NULL);
694 static struct attribute *vmlogrdr_attrs[] = {
695 &dev_attr_autopurge.attr,
696 &dev_attr_purge.attr,
697 &dev_attr_autorecording.attr,
698 &dev_attr_recording.attr,
699 NULL,
702 static struct attribute_group vmlogrdr_attr_group = {
703 .attrs = vmlogrdr_attrs,
706 static struct class *vmlogrdr_class;
707 static struct device_driver vmlogrdr_driver = {
708 .name = "vmlogrdr",
709 .bus = &iucv_bus,
713 static int
714 vmlogrdr_register_driver(void) {
715 int ret;
717 ret = driver_register(&vmlogrdr_driver);
718 if (ret) {
719 printk(KERN_ERR "vmlogrdr: failed to register driver.\n");
720 return ret;
723 ret = driver_create_file(&vmlogrdr_driver,
724 &driver_attr_recording_status);
725 if (ret) {
726 printk(KERN_ERR "vmlogrdr: failed to add driver attribute.\n");
727 goto unregdriver;
730 vmlogrdr_class = class_create(THIS_MODULE, "vmlogrdr");
731 if (IS_ERR(vmlogrdr_class)) {
732 printk(KERN_ERR "vmlogrdr: failed to create class.\n");
733 ret=PTR_ERR(vmlogrdr_class);
734 vmlogrdr_class=NULL;
735 goto unregattr;
737 return 0;
739 unregattr:
740 driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status);
741 unregdriver:
742 driver_unregister(&vmlogrdr_driver);
743 return ret;
747 static void
748 vmlogrdr_unregister_driver(void) {
749 class_destroy(vmlogrdr_class);
750 vmlogrdr_class = NULL;
751 driver_remove_file(&vmlogrdr_driver, &driver_attr_recording_status);
752 driver_unregister(&vmlogrdr_driver);
753 return;
757 static int
758 vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) {
759 struct device *dev;
760 int ret;
762 dev = kzalloc(sizeof(struct device), GFP_KERNEL);
763 if (dev) {
764 snprintf(dev->bus_id, BUS_ID_SIZE, "%s",
765 priv->internal_name);
766 dev->bus = &iucv_bus;
767 dev->parent = iucv_root;
768 dev->driver = &vmlogrdr_driver;
770 * The release function could be called after the
771 * module has been unloaded. It's _only_ task is to
772 * free the struct. Therefore, we specify kfree()
773 * directly here. (Probably a little bit obfuscating
774 * but legitime ...).
776 dev->release = (void (*)(struct device *))kfree;
777 } else
778 return -ENOMEM;
779 ret = device_register(dev);
780 if (ret)
781 return ret;
783 ret = sysfs_create_group(&dev->kobj, &vmlogrdr_attr_group);
784 if (ret) {
785 device_unregister(dev);
786 return ret;
788 priv->class_device = class_device_create(
789 vmlogrdr_class,
790 NULL,
791 MKDEV(vmlogrdr_major, priv->minor_num),
792 dev,
793 "%s", dev->bus_id );
794 if (IS_ERR(priv->class_device)) {
795 ret = PTR_ERR(priv->class_device);
796 priv->class_device=NULL;
797 sysfs_remove_group(&dev->kobj, &vmlogrdr_attr_group);
798 device_unregister(dev);
799 return ret;
801 dev->driver_data = priv;
802 priv->device = dev;
803 return 0;
807 static int
808 vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv ) {
809 class_device_destroy(vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num));
810 if (priv->device != NULL) {
811 sysfs_remove_group(&priv->device->kobj, &vmlogrdr_attr_group);
812 device_unregister(priv->device);
813 priv->device=NULL;
815 return 0;
819 static int
820 vmlogrdr_register_cdev(dev_t dev) {
821 int rc = 0;
822 vmlogrdr_cdev = cdev_alloc();
823 if (!vmlogrdr_cdev) {
824 return -ENOMEM;
826 vmlogrdr_cdev->owner = THIS_MODULE;
827 vmlogrdr_cdev->ops = &vmlogrdr_fops;
828 vmlogrdr_cdev->dev = dev;
829 rc = cdev_add(vmlogrdr_cdev, vmlogrdr_cdev->dev, MAXMINOR);
830 if (!rc)
831 return 0;
833 // cleanup: cdev is not fully registered, no cdev_del here!
834 kobject_put(&vmlogrdr_cdev->kobj);
835 vmlogrdr_cdev=NULL;
836 return rc;
840 static void
841 vmlogrdr_cleanup(void) {
842 int i;
843 if (vmlogrdr_cdev) {
844 cdev_del(vmlogrdr_cdev);
845 vmlogrdr_cdev=NULL;
847 for (i=0; i < MAXMINOR; ++i ) {
848 vmlogrdr_unregister_device(&sys_ser[i]);
849 free_page((unsigned long)sys_ser[i].buffer);
851 vmlogrdr_unregister_driver();
852 if (vmlogrdr_major) {
853 unregister_chrdev_region(MKDEV(vmlogrdr_major, 0), MAXMINOR);
854 vmlogrdr_major=0;
859 static int
860 vmlogrdr_init(void)
862 int rc;
863 int i;
864 dev_t dev;
866 if (! MACHINE_IS_VM) {
867 printk (KERN_ERR "vmlogrdr: not running under VM, "
868 "driver not loaded.\n");
869 return -ENODEV;
872 recording_class_AB = vmlogrdr_get_recording_class_AB();
874 rc = alloc_chrdev_region(&dev, 0, MAXMINOR, "vmlogrdr");
875 if (rc)
876 return rc;
877 vmlogrdr_major = MAJOR(dev);
879 rc=vmlogrdr_register_driver();
880 if (rc)
881 goto cleanup;
883 for (i=0; i < MAXMINOR; ++i ) {
884 sys_ser[i].buffer = (char *) get_zeroed_page(GFP_KERNEL);
885 if (!sys_ser[i].buffer) {
886 rc = ENOMEM;
887 break;
889 sys_ser[i].current_position = sys_ser[i].buffer;
890 rc=vmlogrdr_register_device(&sys_ser[i]);
891 if (rc)
892 break;
894 if (rc)
895 goto cleanup;
897 rc = vmlogrdr_register_cdev(dev);
898 if (rc)
899 goto cleanup;
900 printk (KERN_INFO "vmlogrdr: driver loaded\n");
901 return 0;
903 cleanup:
904 vmlogrdr_cleanup();
905 printk (KERN_ERR "vmlogrdr: driver not loaded.\n");
906 return rc;
910 static void
911 vmlogrdr_exit(void)
913 vmlogrdr_cleanup();
914 printk (KERN_INFO "vmlogrdr: driver unloaded\n");
915 return;
919 module_init(vmlogrdr_init);
920 module_exit(vmlogrdr_exit);