Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Deliver z/VM CP special messages (SMSG) as uevents.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * The driver registers for z/VM CP special messages with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  * "APP" prefix. Incoming messages are delivered to user space
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * as uevents.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * Copyright IBM Corp. 2010
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #define KMSG_COMPONENT		"smsgiucv_app"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #define pr_fmt(fmt)		KMSG_COMPONENT ": " fmt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include <linux/ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) #include <linux/list.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) #include <linux/kobject.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) #include <linux/spinlock.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #include <linux/workqueue.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #include <net/iucv/iucv.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #include "smsgiucv.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) /* prefix used for SMSG registration */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) #define SMSG_PREFIX		"APP"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) /* SMSG related uevent environment variables */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) #define ENV_SENDER_STR		"SMSG_SENDER="
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) #define ENV_SENDER_LEN		(strlen(ENV_SENDER_STR) + 8 + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) #define ENV_PREFIX_STR		"SMSG_ID="
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) #define ENV_PREFIX_LEN		(strlen(ENV_PREFIX_STR) + \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 				 strlen(SMSG_PREFIX) + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) #define ENV_TEXT_STR		"SMSG_TEXT="
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) #define ENV_TEXT_LEN(msg)	(strlen(ENV_TEXT_STR) + strlen((msg)) + 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) /* z/VM user ID which is permitted to send SMSGs
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41)  * If the value is undefined or empty (""), special messages are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42)  * accepted from any z/VM user ID. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) static char *sender;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) module_param(sender, charp, 0400);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) MODULE_PARM_DESC(sender, "z/VM user ID from which CP SMSGs are accepted");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) /* SMSG device representation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) static struct device *smsg_app_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) /* list element for queuing received messages for delivery */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) struct smsg_app_event {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	struct list_head list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	char *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 	char *envp[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) /* queue for outgoing uevents */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) static LIST_HEAD(smsg_event_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) static DEFINE_SPINLOCK(smsg_event_queue_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) static void smsg_app_event_free(struct smsg_app_event *ev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	kfree(ev->buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	kfree(ev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) static struct smsg_app_event *smsg_app_event_alloc(const char *from,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 						   const char *msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	struct smsg_app_event *ev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 	ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	if (!ev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	ev->buf = kzalloc(ENV_SENDER_LEN + ENV_PREFIX_LEN +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 			  ENV_TEXT_LEN(msg), GFP_ATOMIC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 	if (!ev->buf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 		kfree(ev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 	/* setting up environment pointers into buf */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 	ev->envp[0] = ev->buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	ev->envp[1] = ev->envp[0] + ENV_SENDER_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	ev->envp[2] = ev->envp[1] + ENV_PREFIX_LEN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 	ev->envp[3] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	/* setting up environment: sender, prefix name, and message text */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	snprintf(ev->envp[0], ENV_SENDER_LEN, ENV_SENDER_STR "%s", from);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	snprintf(ev->envp[1], ENV_PREFIX_LEN, ENV_PREFIX_STR "%s", SMSG_PREFIX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	snprintf(ev->envp[2], ENV_TEXT_LEN(msg), ENV_TEXT_STR "%s", msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	return ev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) static void smsg_event_work_fn(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	LIST_HEAD(event_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	struct smsg_app_event *p, *n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	dev = get_device(smsg_app_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	if (!dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	spin_lock_bh(&smsg_event_queue_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	list_splice_init(&smsg_event_queue, &event_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	spin_unlock_bh(&smsg_event_queue_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	list_for_each_entry_safe(p, n, &event_queue, list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 		list_del(&p->list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 		kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, p->envp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 		smsg_app_event_free(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	put_device(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) static DECLARE_WORK(smsg_event_work, smsg_event_work_fn);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) static void smsg_app_callback(const char *from, char *msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	struct smsg_app_event *se;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	/* check if the originating z/VM user ID matches
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	 * the configured sender. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	if (sender && strlen(sender) > 0 && strcmp(from, sender) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	/* get start of message text (skip prefix and leading blanks) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	msg += strlen(SMSG_PREFIX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 	while (*msg && isspace(*msg))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 		msg++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	if (*msg == '\0')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	/* allocate event list element and its environment */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	se = smsg_app_event_alloc(from, msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	if (!se)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 		return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	/* queue event and schedule work function */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	spin_lock(&smsg_event_queue_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	list_add_tail(&se->list, &smsg_event_queue);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 	spin_unlock(&smsg_event_queue_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	schedule_work(&smsg_event_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) static int __init smsgiucv_app_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	struct device_driver *smsgiucv_drv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	int rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	if (!MACHINE_IS_VM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	smsg_app_dev = kzalloc(sizeof(*smsg_app_dev), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	if (!smsg_app_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	smsgiucv_drv = driver_find(SMSGIUCV_DRV_NAME, &iucv_bus);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	if (!smsgiucv_drv) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 		kfree(smsg_app_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	rc = dev_set_name(smsg_app_dev, KMSG_COMPONENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 		kfree(smsg_app_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 		goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 	smsg_app_dev->bus = &iucv_bus;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 	smsg_app_dev->parent = iucv_root;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 	smsg_app_dev->release = (void (*)(struct device *)) kfree;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 	smsg_app_dev->driver = smsgiucv_drv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	rc = device_register(smsg_app_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 		put_device(smsg_app_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 		goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	/* convert sender to uppercase characters */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 	if (sender) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 		int len = strlen(sender);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 		while (len--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 			sender[len] = toupper(sender[len]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	/* register with the smsgiucv device driver */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	if (rc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 		device_unregister(smsg_app_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 		goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) 	rc = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 	return rc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) module_init(smsgiucv_app_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) static void __exit smsgiucv_app_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 	/* unregister callback */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 	smsg_unregister_callback(SMSG_PREFIX, smsg_app_callback);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 	/* cancel pending work and flush any queued event work */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 	cancel_work_sync(&smsg_event_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 	smsg_event_work_fn(&smsg_event_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	device_unregister(smsg_app_dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) module_exit(smsgiucv_app_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) MODULE_LICENSE("GPL v2");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) MODULE_DESCRIPTION("Deliver z/VM CP SMSG as uevents");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) MODULE_AUTHOR("Hendrik Brueckner <brueckner@linux.vnet.ibm.com>");