aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-01-28 12:02:24 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-28 12:02:24 -0500
commite770d73ceb93c235525cb9bbbf1374c9b61a0895 (patch)
treeac72b64d1978fece984c8b5a27442acbef7f172c /drivers/tty
parentbe86497152220677e3e5cb326519e19d727f8674 (diff)
parent07be0382097027cde68d9268cc628741069b5762 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 patches from Martin Schwidefsky: "A new binary interface to be able to query and modify the LPAR scheduler weight and cap settings. Some improvements for the hvc terminal over iucv and a couple of bux fixes" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: s390/hypfs: add interface for diagnose 0x304 s390: wire up sys_sched_setattr/sys_sched_getattr s390/uapi: fix struct statfs64 definition s390/uaccess: remove dead extern declarations, make functions static s390/uaccess: test if current->mm is set before walking page tables s390/zfcpdump: make zfcpdump depend on 64BIT s390/32bit: fix cmpxchg64 s390/xpram: don't modify module parameters s390/zcrypt: remove zcrypt kmsg documentation again s390/hvc_iucv: Automatically assign free HVC terminal devices s390/hvc_iucv: Display connection details through device attributes s390/hvc_iucv: fix sparse warning s390/vmur: Link parent CCW device during UR device creation
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/hvc/hvc_iucv.c103
1 files changed, 95 insertions, 8 deletions
diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
index db19a38c8c69..ea74460f3638 100644
--- a/drivers/tty/hvc/hvc_iucv.c
+++ b/drivers/tty/hvc/hvc_iucv.c
@@ -77,6 +77,7 @@ struct hvc_iucv_private {
77 struct list_head tty_outqueue; /* outgoing IUCV messages */ 77 struct list_head tty_outqueue; /* outgoing IUCV messages */
78 struct list_head tty_inqueue; /* incoming IUCV messages */ 78 struct list_head tty_inqueue; /* incoming IUCV messages */
79 struct device *dev; /* device structure */ 79 struct device *dev; /* device structure */
80 u8 info_path[16]; /* IUCV path info (dev attr) */
80}; 81};
81 82
82struct iucv_tty_buffer { 83struct iucv_tty_buffer {
@@ -126,7 +127,7 @@ static struct iucv_handler hvc_iucv_handler = {
126 * This function returns the struct hvc_iucv_private instance that corresponds 127 * This function returns the struct hvc_iucv_private instance that corresponds
127 * to the HVC virtual terminal number specified as parameter @num. 128 * to the HVC virtual terminal number specified as parameter @num.
128 */ 129 */
129struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num) 130static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num)
130{ 131{
131 if ((num < HVC_IUCV_MAGIC) || (num - HVC_IUCV_MAGIC > hvc_iucv_devices)) 132 if ((num < HVC_IUCV_MAGIC) || (num - HVC_IUCV_MAGIC > hvc_iucv_devices))
132 return NULL; 133 return NULL;
@@ -772,18 +773,37 @@ static int hvc_iucv_filter_connreq(u8 ipvmid[8])
772static int hvc_iucv_path_pending(struct iucv_path *path, 773static int hvc_iucv_path_pending(struct iucv_path *path,
773 u8 ipvmid[8], u8 ipuser[16]) 774 u8 ipvmid[8], u8 ipuser[16])
774{ 775{
775 struct hvc_iucv_private *priv; 776 struct hvc_iucv_private *priv, *tmp;
777 u8 wildcard[9] = "lnxhvc ";
778 int i, rc, find_unused;
776 u8 nuser_data[16]; 779 u8 nuser_data[16];
777 u8 vm_user_id[9]; 780 u8 vm_user_id[9];
778 int i, rc;
779 781
782 ASCEBC(wildcard, sizeof(wildcard));
783 find_unused = !memcmp(wildcard, ipuser, 8);
784
785 /* First, check if the pending path request is managed by this
786 * IUCV handler:
787 * - find a disconnected device if ipuser contains the wildcard
788 * - find the device that matches the terminal ID in ipuser
789 */
780 priv = NULL; 790 priv = NULL;
781 for (i = 0; i < hvc_iucv_devices; i++) 791 for (i = 0; i < hvc_iucv_devices; i++) {
782 if (hvc_iucv_table[i] && 792 tmp = hvc_iucv_table[i];
783 (0 == memcmp(hvc_iucv_table[i]->srv_name, ipuser, 8))) { 793 if (!tmp)
784 priv = hvc_iucv_table[i]; 794 continue;
795
796 if (find_unused) {
797 spin_lock(&tmp->lock);
798 if (tmp->iucv_state == IUCV_DISCONN)
799 priv = tmp;
800 spin_unlock(&tmp->lock);
801
802 } else if (!memcmp(tmp->srv_name, ipuser, 8))
803 priv = tmp;
804 if (priv)
785 break; 805 break;
786 } 806 }
787 if (!priv) 807 if (!priv)
788 return -ENODEV; 808 return -ENODEV;
789 809
@@ -826,6 +846,10 @@ static int hvc_iucv_path_pending(struct iucv_path *path,
826 priv->path = path; 846 priv->path = path;
827 priv->iucv_state = IUCV_CONNECTED; 847 priv->iucv_state = IUCV_CONNECTED;
828 848
849 /* store path information */
850 memcpy(priv->info_path, ipvmid, 8);
851 memcpy(priv->info_path + 8, ipuser + 8, 8);
852
829 /* flush buffered output data... */ 853 /* flush buffered output data... */
830 schedule_delayed_work(&priv->sndbuf_work, 5); 854 schedule_delayed_work(&priv->sndbuf_work, 5);
831 855
@@ -960,6 +984,49 @@ static int hvc_iucv_pm_restore_thaw(struct device *dev)
960 return 0; 984 return 0;
961} 985}
962 986
987static ssize_t hvc_iucv_dev_termid_show(struct device *dev,
988 struct device_attribute *attr,
989 char *buf)
990{
991 struct hvc_iucv_private *priv = dev_get_drvdata(dev);
992 size_t len;
993
994 len = sizeof(priv->srv_name);
995 memcpy(buf, priv->srv_name, len);
996 EBCASC(buf, len);
997 buf[len++] = '\n';
998 return len;
999}
1000
1001static ssize_t hvc_iucv_dev_state_show(struct device *dev,
1002 struct device_attribute *attr,
1003 char *buf)
1004{
1005 struct hvc_iucv_private *priv = dev_get_drvdata(dev);
1006 return sprintf(buf, "%u:%u\n", priv->iucv_state, priv->tty_state);
1007}
1008
1009static ssize_t hvc_iucv_dev_peer_show(struct device *dev,
1010 struct device_attribute *attr,
1011 char *buf)
1012{
1013 struct hvc_iucv_private *priv = dev_get_drvdata(dev);
1014 char vmid[9], ipuser[9];
1015
1016 memset(vmid, 0, sizeof(vmid));
1017 memset(ipuser, 0, sizeof(ipuser));
1018
1019 spin_lock_bh(&priv->lock);
1020 if (priv->iucv_state == IUCV_CONNECTED) {
1021 memcpy(vmid, priv->info_path, 8);
1022 memcpy(ipuser, priv->info_path + 8, 8);
1023 }
1024 spin_unlock_bh(&priv->lock);
1025 EBCASC(ipuser, 8);
1026
1027 return sprintf(buf, "%s:%s\n", vmid, ipuser);
1028}
1029
963 1030
964/* HVC operations */ 1031/* HVC operations */
965static const struct hv_ops hvc_iucv_ops = { 1032static const struct hv_ops hvc_iucv_ops = {
@@ -985,6 +1052,25 @@ static struct device_driver hvc_iucv_driver = {
985 .pm = &hvc_iucv_pm_ops, 1052 .pm = &hvc_iucv_pm_ops,
986}; 1053};
987 1054
1055/* IUCV HVC device attributes */
1056static DEVICE_ATTR(termid, 0640, hvc_iucv_dev_termid_show, NULL);
1057static DEVICE_ATTR(state, 0640, hvc_iucv_dev_state_show, NULL);
1058static DEVICE_ATTR(peer, 0640, hvc_iucv_dev_peer_show, NULL);
1059static struct attribute *hvc_iucv_dev_attrs[] = {
1060 &dev_attr_termid.attr,
1061 &dev_attr_state.attr,
1062 &dev_attr_peer.attr,
1063 NULL,
1064};
1065static struct attribute_group hvc_iucv_dev_attr_group = {
1066 .attrs = hvc_iucv_dev_attrs,
1067};
1068static const struct attribute_group *hvc_iucv_dev_attr_groups[] = {
1069 &hvc_iucv_dev_attr_group,
1070 NULL,
1071};
1072
1073
988/** 1074/**
989 * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance 1075 * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance
990 * @id: hvc_iucv_table index 1076 * @id: hvc_iucv_table index
@@ -1046,6 +1132,7 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console)
1046 priv->dev->bus = &iucv_bus; 1132 priv->dev->bus = &iucv_bus;
1047 priv->dev->parent = iucv_root; 1133 priv->dev->parent = iucv_root;
1048 priv->dev->driver = &hvc_iucv_driver; 1134 priv->dev->driver = &hvc_iucv_driver;
1135 priv->dev->groups = hvc_iucv_dev_attr_groups;
1049 priv->dev->release = (void (*)(struct device *)) kfree; 1136 priv->dev->release = (void (*)(struct device *)) kfree;
1050 rc = device_register(priv->dev); 1137 rc = device_register(priv->dev);
1051 if (rc) { 1138 if (rc) {