Revert to Fedora kernel-2.6.17-1.2187_FC5 patched with vs2.0.2.1; there are too many...
[linux-2.6.git] / drivers / s390 / net / ctcmain.c
index 3257c22..fe986af 100644 (file)
@@ -6,7 +6,7 @@
  * Fixes by : Jochen Röhrig (roehrig@de.ibm.com)
  *            Arnaldo Carvalho de Melo <acme@conectiva.com.br>
              Peter Tiedemann (ptiedem@de.ibm.com)
- * Driver Model stuff by : Cornelia Huck <cornelia.huck@de.ibm.com>
+ * Driver Model stuff by : Cornelia Huck <huckc@de.ibm.com>
  *
  * Documentation used:
  *  - Principles of Operation (IBM doc#: SA22-7201-06)
@@ -65,6 +65,7 @@
 
 #include <asm/idals.h>
 
+#include "ctctty.h"
 #include "fsm.h"
 #include "cu3088.h"
 
@@ -478,7 +479,10 @@ ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
                skb->dev = pskb->dev;
                skb->protocol = pskb->protocol;
                pskb->ip_summed = CHECKSUM_UNNECESSARY;
-               netif_rx_ni(skb);
+               if (ch->protocol == CTC_PROTO_LINUX_TTY)
+                       ctc_tty_netif_rx(skb);
+               else
+                       netif_rx_ni(skb);
                /**
                 * Successful rx; reset logflags
                 */
@@ -553,7 +557,8 @@ ccw_unit_check(struct channel *ch, unsigned char sense)
        DBF_TEXT(trace, 5, __FUNCTION__);
        if (sense & SNS0_INTERVENTION_REQ) {
                if (sense & 0x01) {
-                       ctc_pr_debug("%s: Interface disc. or Sel. reset "
+                       if (ch->protocol != CTC_PROTO_LINUX_TTY)
+                               ctc_pr_debug("%s: Interface disc. or Sel. reset "
                                        "(remote)\n", ch->id);
                        fsm_event(ch->fsm, CH_EVENT_UC_RCRESET, ch);
                } else {
@@ -1714,9 +1719,6 @@ add_channel(struct ccw_device *cdev, enum channel_types type)
                kfree(ch);
                return 0;
        }
-
-       spin_lock_init(&ch->collect_lock);
-
        fsm_settimer(ch->fsm, &ch->timer);
        skb_queue_head_init(&ch->io_queue);
        skb_queue_head_init(&ch->collect_queue);
@@ -2032,6 +2034,7 @@ static void
 dev_action_chup(fsm_instance * fi, int event, void *arg)
 {
        struct net_device *dev = (struct net_device *) arg;
+       struct ctc_priv *privptr = dev->priv;
 
        DBF_TEXT(trace, 3, __FUNCTION__);
        switch (fsm_getstate(fi)) {
@@ -2046,6 +2049,8 @@ dev_action_chup(fsm_instance * fi, int event, void *arg)
                                fsm_newstate(fi, DEV_STATE_RUNNING);
                                ctc_pr_info("%s: connected with remote side\n",
                                            dev->name);
+                               if (privptr->protocol == CTC_PROTO_LINUX_TTY)
+                                       ctc_tty_setcarrier(dev, 1);
                                ctc_clear_busy(dev);
                        }
                        break;
@@ -2054,6 +2059,8 @@ dev_action_chup(fsm_instance * fi, int event, void *arg)
                                fsm_newstate(fi, DEV_STATE_RUNNING);
                                ctc_pr_info("%s: connected with remote side\n",
                                            dev->name);
+                               if (privptr->protocol == CTC_PROTO_LINUX_TTY)
+                                       ctc_tty_setcarrier(dev, 1);
                                ctc_clear_busy(dev);
                        }
                        break;
@@ -2079,10 +2086,14 @@ dev_action_chup(fsm_instance * fi, int event, void *arg)
 static void
 dev_action_chdown(fsm_instance * fi, int event, void *arg)
 {
+       struct net_device *dev = (struct net_device *) arg;
+       struct ctc_priv *privptr = dev->priv;
 
        DBF_TEXT(trace, 3, __FUNCTION__);
        switch (fsm_getstate(fi)) {
                case DEV_STATE_RUNNING:
+                       if (privptr->protocol == CTC_PROTO_LINUX_TTY)
+                               ctc_tty_setcarrier(dev, 0);
                        if (event == DEV_EVENT_TXDOWN)
                                fsm_newstate(fi, DEV_STATE_STARTWAIT_TX);
                        else
@@ -2386,6 +2397,8 @@ ctc_tx(struct sk_buff *skb, struct net_device * dev)
         */
        if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
                fsm_event(privptr->fsm, DEV_EVENT_START, dev);
+               if (privptr->protocol == CTC_PROTO_LINUX_TTY)
+                       return -EBUSY;
                dev_kfree_skb(skb);
                privptr->stats.tx_dropped++;
                privptr->stats.tx_errors++;
@@ -2595,13 +2608,20 @@ ctc_netdev_unregister(struct net_device * dev)
        if (!dev)
                return;
        privptr = (struct ctc_priv *) dev->priv;
-       unregister_netdev(dev);
+       if (privptr->protocol != CTC_PROTO_LINUX_TTY)
+               unregister_netdev(dev);
+       else
+               ctc_tty_unregister_netdev(dev);
 }
 
 static int
 ctc_netdev_register(struct net_device * dev)
 {
-       return register_netdev(dev);
+       struct ctc_priv *privptr = (struct ctc_priv *) dev->priv;
+       if (privptr->protocol != CTC_PROTO_LINUX_TTY)
+               return register_netdev(dev);
+       else
+               return ctc_tty_register_netdev(dev);
 }
 
 static void
@@ -2647,9 +2667,7 @@ ctc_proto_store(struct device *dev, struct device_attribute *attr, const char *b
        if (!priv)
                return -ENODEV;
        sscanf(buf, "%u", &value);
-       if (!((value == CTC_PROTO_S390)  ||
-             (value == CTC_PROTO_LINUX) ||
-             (value == CTC_PROTO_OS390)))
+       if ((value < 0) || (value > CTC_PROTO_MAX))
                return -EINVAL;
        priv->protocol = value;
 
@@ -2689,17 +2707,9 @@ static struct attribute_group ctc_attr_group = {
 static int
 ctc_add_attributes(struct device *dev)
 {
-       int rc;
-
-       rc = device_create_file(dev, &dev_attr_loglevel);
-       if (rc)
-               goto out;
-       rc = device_create_file(dev, &dev_attr_stats);
-       if (!rc)
-               goto out;
-       device_remove_file(dev, &dev_attr_loglevel);
-out:
-       return rc;
+       device_create_file(dev, &dev_attr_loglevel);
+       device_create_file(dev, &dev_attr_stats);
+       return 0;
 }
 
 static void
@@ -2887,7 +2897,10 @@ ctc_new_device(struct ccwgroup_device *cgdev)
                goto out;
        }
 
-       strlcpy(dev->name, "ctc%d", IFNAMSIZ);
+       if (privptr->protocol == CTC_PROTO_LINUX_TTY)
+               strlcpy(dev->name, "ctctty%d", IFNAMSIZ);
+       else
+               strlcpy(dev->name, "ctc%d", IFNAMSIZ);
 
        for (direction = READ; direction <= WRITE; direction++) {
                privptr->channel[direction] =
@@ -2912,12 +2925,7 @@ ctc_new_device(struct ccwgroup_device *cgdev)
                goto out;
        }
 
-       if (ctc_add_attributes(&cgdev->dev)) {
-               ctc_netdev_unregister(dev);
-               dev->priv = NULL;
-               ctc_free_netdevice(dev, 1);
-               goto out;
-       }
+       ctc_add_attributes(&cgdev->dev);
 
        strlcpy(privptr->fsm->name, dev->name, sizeof (privptr->fsm->name));
 
@@ -3038,6 +3046,7 @@ ctc_exit(void)
 {
        DBF_TEXT(setup, 3, __FUNCTION__);
        unregister_cu3088_discipline(&ctc_group_driver);
+       ctc_tty_cleanup();
        ctc_unregister_dbf_views();
        ctc_pr_info("CTC driver unloaded\n");
 }
@@ -3064,8 +3073,10 @@ ctc_init(void)
                ctc_pr_crit("ctc_init failed with ctc_register_dbf_views rc = %d\n", ret);
                return ret;
        }
+       ctc_tty_init();
        ret = register_cu3088_discipline(&ctc_group_driver);
        if (ret) {
+               ctc_tty_cleanup();
                ctc_unregister_dbf_views();
        }
        return ret;