Commit 6ac48313 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Linus Torvalds

[PATCH] s390: ctc driver changes

From: Peter Tiedemann <ptiedem@de.ibm.com>

ctc driver changes:
 - Make use of the debug feature to ease debugging.
 - ctctty: use dev_alloc_name to allocate a network device name.
 - ctctty: avoid deadlock of ctc_tty_close vs ctc_tty_flush_buffer.
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 17f0cb1f
......@@ -2,7 +2,7 @@
# S/390 network devices
#
ctc-objs := ctcmain.o ctctty.o
ctc-objs := ctcmain.o ctctty.o ctcdbug.o
obj-$(CONFIG_IUCV) += iucv.o
obj-$(CONFIG_NETIUCV) += netiucv.o fsm.o
......
/*
*
* linux/drivers/s390/net/ctcdbug.c ($Revision: 1.1 $)
*
* Linux on zSeries OSA Express and HiperSockets support
*
* Copyright 2000,2003 IBM Corporation
*
* Author(s): Original Code written by
* Peter Tiedemann (ptiedem@de.ibm.com)
*
* $Revision: 1.1 $ $Date: 2004/07/02 16:31:22 $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "ctcdbug.h"
/**
* Debug Facility Stuff
*/
debug_info_t *dbf_setup = NULL;
debug_info_t *dbf_data = NULL;
debug_info_t *dbf_trace = NULL;
DEFINE_PER_CPU(char[256], dbf_txt_buf);
void
unregister_dbf_views(void)
{
if (dbf_setup)
debug_unregister(dbf_setup);
if (dbf_data)
debug_unregister(dbf_data);
if (dbf_trace)
debug_unregister(dbf_trace);
}
int
register_dbf_views(void)
{
dbf_setup = debug_register(CTC_DBF_SETUP_NAME,
CTC_DBF_SETUP_INDEX,
CTC_DBF_SETUP_NR_AREAS,
CTC_DBF_SETUP_LEN);
dbf_data = debug_register(CTC_DBF_DATA_NAME,
CTC_DBF_DATA_INDEX,
CTC_DBF_DATA_NR_AREAS,
CTC_DBF_DATA_LEN);
dbf_trace = debug_register(CTC_DBF_TRACE_NAME,
CTC_DBF_TRACE_INDEX,
CTC_DBF_TRACE_NR_AREAS,
CTC_DBF_TRACE_LEN);
if ((dbf_setup == NULL) || (dbf_data == NULL) ||
(dbf_trace == NULL)) {
unregister_dbf_views();
return -ENOMEM;
}
debug_register_view(dbf_setup, &debug_hex_ascii_view);
debug_set_level(dbf_setup, CTC_DBF_SETUP_LEVEL);
debug_register_view(dbf_data, &debug_hex_ascii_view);
debug_set_level(dbf_data, CTC_DBF_DATA_LEVEL);
debug_register_view(dbf_trace, &debug_hex_ascii_view);
debug_set_level(dbf_trace, CTC_DBF_TRACE_LEVEL);
return 0;
}
/*
*
* linux/drivers/s390/net/ctcdbug.h ($Revision: 1.1 $)
*
* Linux on zSeries OSA Express and HiperSockets support
*
* Copyright 2000,2003 IBM Corporation
*
* Author(s): Original Code written by
* Peter Tiedemann (ptiedem@de.ibm.com)
*
* $Revision: 1.1 $ $Date: 2004/07/02 16:31:22 $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <asm/debug.h>
/**
* Debug Facility stuff
*/
#define CTC_DBF_SETUP_NAME "ctc_setup"
#define CTC_DBF_SETUP_LEN 16
#define CTC_DBF_SETUP_INDEX 3
#define CTC_DBF_SETUP_NR_AREAS 1
#define CTC_DBF_SETUP_LEVEL 3
#define CTC_DBF_DATA_NAME "ctc_data"
#define CTC_DBF_DATA_LEN 128
#define CTC_DBF_DATA_INDEX 3
#define CTC_DBF_DATA_NR_AREAS 1
#define CTC_DBF_DATA_LEVEL 2
#define CTC_DBF_TRACE_NAME "ctc_trace"
#define CTC_DBF_TRACE_LEN 16
#define CTC_DBF_TRACE_INDEX 2
#define CTC_DBF_TRACE_NR_AREAS 2
#define CTC_DBF_TRACE_LEVEL 3
#define DBF_TEXT(name,level,text) \
do { \
debug_text_event(dbf_##name,level,text); \
} while (0)
#define DBF_HEX(name,level,addr,len) \
do { \
debug_event(dbf_##name,level,(void*)(addr),len); \
} while (0)
extern DEFINE_PER_CPU(char[256], dbf_txt_buf);
extern debug_info_t *dbf_setup;
extern debug_info_t *dbf_data;
extern debug_info_t *dbf_trace;
#define DBF_TEXT_(name,level,text...) \
do { \
char* dbf_txt_buf = get_cpu_var(dbf_txt_buf); \
sprintf(dbf_txt_buf, text); \
debug_text_event(dbf_##name,level,dbf_txt_buf); \
put_cpu_var(dbf_txt_buf); \
} while (0)
#define DBF_SPRINTF(name,level,text...) \
do { \
debug_sprintf_event(dbf_trace, level, ##text ); \
debug_sprintf_event(dbf_trace, level, text ); \
} while (0)
int register_dbf_views(void);
void unregister_dbf_views(void);
/**
* some more debug stuff
*/
#define HEXDUMP16(importance,header,ptr) \
PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
"%02x %02x %02x %02x %02x %02x %02x %02x\n", \
*(((char*)ptr)),*(((char*)ptr)+1),*(((char*)ptr)+2), \
*(((char*)ptr)+3),*(((char*)ptr)+4),*(((char*)ptr)+5), \
*(((char*)ptr)+6),*(((char*)ptr)+7),*(((char*)ptr)+8), \
*(((char*)ptr)+9),*(((char*)ptr)+10),*(((char*)ptr)+11), \
*(((char*)ptr)+12),*(((char*)ptr)+13), \
*(((char*)ptr)+14),*(((char*)ptr)+15)); \
PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \
"%02x %02x %02x %02x %02x %02x %02x %02x\n", \
*(((char*)ptr)+16),*(((char*)ptr)+17), \
*(((char*)ptr)+18),*(((char*)ptr)+19), \
*(((char*)ptr)+20),*(((char*)ptr)+21), \
*(((char*)ptr)+22),*(((char*)ptr)+23), \
*(((char*)ptr)+24),*(((char*)ptr)+25), \
*(((char*)ptr)+26),*(((char*)ptr)+27), \
*(((char*)ptr)+28),*(((char*)ptr)+29), \
*(((char*)ptr)+30),*(((char*)ptr)+31));
static inline void
hex_dump(unsigned char *buf, size_t len)
{
size_t i;
for (i = 0; i < len; i++) {
if (i && !(i % 16))
printk("\n");
printk("%02x ", *(buf + i));
}
printk("\n");
}
/*
* $Id: ctcmain.c,v 1.60 2004/06/18 15:13:51 ptiedem Exp $
* $Id: ctcmain.c,v 1.61 2004/07/02 16:31:22 ptiedem Exp $
*
* CTC / ESCON network driver
*
......@@ -36,7 +36,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* RELEASE-TAG: CTC/ESCON network driver $Revision: 1.60 $
* RELEASE-TAG: CTC/ESCON network driver $Revision: 1.61 $
*
*/
......@@ -73,6 +73,7 @@
#include "ctctty.h"
#include "fsm.h"
#include "cu3088.h"
#include "ctcdbug.h"
MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
MODULE_DESCRIPTION("Linux for S/390 CTC/Escon Driver");
......@@ -319,7 +320,7 @@ static void
print_banner(void)
{
static int printed = 0;
char vbuf[] = "$Revision: 1.60 $";
char vbuf[] = "$Revision: 1.61 $";
char *version = vbuf;
if (printed)
......@@ -616,8 +617,9 @@ ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
{
struct net_device *dev = ch->netdev;
struct ctc_priv *privptr = (struct ctc_priv *) dev->priv;
__u16 len = *((__u16 *) pskb->data);
DBF_TEXT(trace, 2, __FUNCTION__);
skb_put(pskb, 2 + LL_HEADER_LENGTH);
skb_pull(pskb, 2);
pskb->dev = dev;
......@@ -759,6 +761,7 @@ ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
static void inline
ccw_check_return_code(struct channel *ch, int return_code, char *msg)
{
DBF_TEXT(trace, 2, __FUNCTION__);
switch (return_code) {
case 0:
fsm_event(ch->fsm, CH_EVENT_IO_SUCCESS, ch);
......@@ -793,6 +796,7 @@ ccw_check_return_code(struct channel *ch, int return_code, char *msg)
static void inline
ccw_unit_check(struct channel *ch, unsigned char sense)
{
DBF_TEXT(trace, 2, __FUNCTION__);
if (sense & SNS0_INTERVENTION_REQ) {
if (sense & 0x01) {
if (ch->protocol != CTC_PROTO_LINUX_TTY)
......@@ -838,6 +842,8 @@ ctc_purge_skb_queue(struct sk_buff_head *q)
{
struct sk_buff *skb;
DBF_TEXT(trace, 2, __FUNCTION__);
while ((skb = skb_dequeue(q))) {
atomic_dec(&skb->users);
dev_kfree_skb_irq(skb);
......@@ -847,6 +853,7 @@ ctc_purge_skb_queue(struct sk_buff_head *q)
static __inline__ int
ctc_checkalloc_buffer(struct channel *ch, int warn)
{
DBF_TEXT(trace, 2, __FUNCTION__);
if ((ch->trans_skb == NULL) ||
(ch->flags & CHANNEL_FLAGS_BUFSIZE_CHANGED)) {
if (ch->trans_skb != NULL)
......@@ -913,9 +920,12 @@ ch_action_txdone(fsm_instance * fi, int event, void *arg)
struct sk_buff *skb;
int first = 1;
int i;
unsigned long duration;
struct timespec done_stamp = xtime;
unsigned long duration =
DBF_TEXT(trace, 2, __FUNCTION__);
duration =
(done_stamp.tv_sec - ch->prof.send_stamp.tv_sec) * 1000000 +
(done_stamp.tv_nsec - ch->prof.send_stamp.tv_nsec) / 1000;
if (duration > ch->prof.tx_time)
......@@ -996,6 +1006,7 @@ ch_action_txidle(fsm_instance * fi, int event, void *arg)
{
struct channel *ch = (struct channel *) arg;
DBF_TEXT(trace, 2, __FUNCTION__);
fsm_deltimer(&ch->timer);
fsm_newstate(fi, CH_STATE_TXIDLE);
fsm_event(((struct ctc_priv *) ch->netdev->priv)->fsm, DEV_EVENT_TXUP,
......@@ -1022,6 +1033,7 @@ ch_action_rx(fsm_instance * fi, int event, void *arg)
int check_len;
int rc;
DBF_TEXT(trace, 2, __FUNCTION__);
fsm_deltimer(&ch->timer);
if (len < 8) {
ctc_pr_debug("%s: got packet with length %d < 8\n",
......@@ -1092,6 +1104,8 @@ ch_action_firstio(fsm_instance * fi, int event, void *arg)
struct channel *ch = (struct channel *) arg;
int rc;
DBF_TEXT(trace, 2, __FUNCTION__);
if (fsm_getstate(fi) == CH_STATE_TXIDLE)
ctc_pr_debug("%s: remote side issued READ?, init ...\n", ch->id);
fsm_deltimer(&ch->timer);
......@@ -1166,6 +1180,7 @@ ch_action_rxidle(fsm_instance * fi, int event, void *arg)
__u16 buflen;
int rc;
DBF_TEXT(trace, 2, __FUNCTION__);
fsm_deltimer(&ch->timer);
buflen = *((__u16 *) ch->trans_skb->data);
#ifdef DEBUG
......@@ -1205,6 +1220,7 @@ ch_action_setmode(fsm_instance * fi, int event, void *arg)
int rc;
unsigned long saveflags;
DBF_TEXT(trace, 2, __FUNCTION__);
fsm_deltimer(&ch->timer);
fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
fsm_newstate(fi, CH_STATE_SETUPWAIT);
......@@ -1236,6 +1252,7 @@ ch_action_start(fsm_instance * fi, int event, void *arg)
int rc;
struct net_device *dev;
DBF_TEXT(trace, 2, __FUNCTION__);
if (ch == NULL) {
ctc_pr_warn("ch_action_start ch=NULL\n");
return;
......@@ -1315,6 +1332,7 @@ ch_action_haltio(fsm_instance * fi, int event, void *arg)
int rc;
int oldstate;
DBF_TEXT(trace, 2, __FUNCTION__);
fsm_deltimer(&ch->timer);
fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
if (event == CH_EVENT_STOP)
......@@ -1347,6 +1365,7 @@ ch_action_stopped(fsm_instance * fi, int event, void *arg)
struct channel *ch = (struct channel *) arg;
struct net_device *dev = ch->netdev;
DBF_TEXT(trace, 2, __FUNCTION__);
fsm_deltimer(&ch->timer);
fsm_newstate(fi, CH_STATE_STOPPED);
if (ch->trans_skb != NULL) {
......@@ -1398,6 +1417,7 @@ ch_action_fail(fsm_instance * fi, int event, void *arg)
struct channel *ch = (struct channel *) arg;
struct net_device *dev = ch->netdev;
DBF_TEXT(trace, 2, __FUNCTION__);
fsm_deltimer(&ch->timer);
fsm_newstate(fi, CH_STATE_NOTOP);
if (CHANNEL_DIRECTION(ch->flags) == READ) {
......@@ -1428,6 +1448,7 @@ ch_action_setuperr(fsm_instance * fi, int event, void *arg)
struct channel *ch = (struct channel *) arg;
struct net_device *dev = ch->netdev;
DBF_TEXT(setup, 2, __FUNCTION__);
/**
* Special case: Got UC_RCRESET on setmode.
* This means that remote side isn't setup. In this case
......@@ -1480,6 +1501,7 @@ ch_action_restart(fsm_instance * fi, int event, void *arg)
struct channel *ch = (struct channel *) arg;
struct net_device *dev = ch->netdev;
DBF_TEXT(trace, 2, __FUNCTION__);
fsm_deltimer(&ch->timer);
ctc_pr_debug("%s: %s channel restart\n", dev->name,
(CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX");
......@@ -1514,6 +1536,7 @@ ch_action_rxiniterr(fsm_instance * fi, int event, void *arg)
struct channel *ch = (struct channel *) arg;
struct net_device *dev = ch->netdev;
DBF_TEXT(setup, 2, __FUNCTION__);
if (event == CH_EVENT_TIMER) {
fsm_deltimer(&ch->timer);
ctc_pr_debug("%s: Timeout during RX init handshake\n", dev->name);
......@@ -1542,6 +1565,7 @@ ch_action_rxinitfail(fsm_instance * fi, int event, void *arg)
struct channel *ch = (struct channel *) arg;
struct net_device *dev = ch->netdev;
DBF_TEXT(setup, 2, __FUNCTION__);
fsm_newstate(fi, CH_STATE_RXERR);
ctc_pr_warn("%s: RX initialization failed\n", dev->name);
ctc_pr_warn("%s: RX <-> RX connection detected\n", dev->name);
......@@ -1562,6 +1586,7 @@ ch_action_rxdisc(fsm_instance * fi, int event, void *arg)
struct channel *ch2;
struct net_device *dev = ch->netdev;
DBF_TEXT(trace, 2, __FUNCTION__);
fsm_deltimer(&ch->timer);
ctc_pr_debug("%s: Got remote disconnect, re-initializing ...\n",
dev->name);
......@@ -1593,6 +1618,7 @@ ch_action_txiniterr(fsm_instance * fi, int event, void *arg)
struct channel *ch = (struct channel *) arg;
struct net_device *dev = ch->netdev;
DBF_TEXT(setup, 2, __FUNCTION__);
if (event == CH_EVENT_TIMER) {
fsm_deltimer(&ch->timer);
ctc_pr_debug("%s: Timeout during TX init handshake\n", dev->name);
......@@ -1621,6 +1647,7 @@ ch_action_txretry(fsm_instance * fi, int event, void *arg)
struct net_device *dev = ch->netdev;
unsigned long saveflags;
DBF_TEXT(trace, 2, __FUNCTION__);
fsm_deltimer(&ch->timer);
if (ch->retry++ > 3) {
ctc_pr_debug("%s: TX retry failed, restarting channel\n",
......@@ -1678,6 +1705,7 @@ ch_action_iofatal(fsm_instance * fi, int event, void *arg)
struct channel *ch = (struct channel *) arg;
struct net_device *dev = ch->netdev;
DBF_TEXT(trace, 2, __FUNCTION__);
fsm_deltimer(&ch->timer);
if (CHANNEL_DIRECTION(ch->flags) == READ) {
ctc_pr_debug("%s: RX I/O error\n", dev->name);
......@@ -1699,6 +1727,7 @@ ch_action_reinit(fsm_instance *fi, int event, void *arg)
struct net_device *dev = ch->netdev;
struct ctc_priv *privptr = dev->priv;
DBF_TEXT(trace, 2, __FUNCTION__);
ch_action_iofatal(fi, event, arg);
fsm_addtimer(&privptr->restart_timer, 1000, DEV_EVENT_RESTART, dev);
}
......@@ -1849,6 +1878,7 @@ add_channel(struct ccw_device *cdev, enum channel_types type)
struct channel **c = &channels;
struct channel *ch;
DBF_TEXT(trace, 2, __FUNCTION__);
if ((ch =
(struct channel *) kmalloc(sizeof (struct channel),
GFP_KERNEL)) == NULL) {
......@@ -1954,6 +1984,7 @@ channel_remove(struct channel *ch)
{
struct channel **c = &channels;
DBF_TEXT(trace, 2, __FUNCTION__);
if (ch == NULL)
return;
......@@ -1990,6 +2021,7 @@ channel_get(enum channel_types type, char *id, int direction)
{
struct channel *ch = channels;
DBF_TEXT(trace, 2, __FUNCTION__);
#ifdef DEBUG
ctc_pr_debug("ctc: %s(): searching for ch with id %s and type %d\n",
__func__, id, type);
......@@ -2085,6 +2117,7 @@ ctc_irq_handler(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
struct net_device *dev;
struct ctc_priv *priv;
DBF_TEXT(trace, 2, __FUNCTION__);
if (__ctc_check_irb_error(cdev, irb))
return;
......@@ -2178,6 +2211,7 @@ dev_action_start(fsm_instance * fi, int event, void *arg)
struct ctc_priv *privptr = dev->priv;
int direction;
DBF_TEXT(setup, 2, __FUNCTION__);
fsm_deltimer(&privptr->restart_timer);
fsm_newstate(fi, DEV_STATE_STARTWAIT_RXTX);
for (direction = READ; direction <= WRITE; direction++) {
......@@ -2200,6 +2234,7 @@ dev_action_stop(fsm_instance * fi, int event, void *arg)
struct ctc_priv *privptr = dev->priv;
int direction;
DBF_TEXT(trace, 2, __FUNCTION__);
fsm_newstate(fi, DEV_STATE_STOPWAIT_RXTX);
for (direction = READ; direction <= WRITE; direction++) {
struct channel *ch = privptr->channel[direction];
......@@ -2212,6 +2247,7 @@ dev_action_restart(fsm_instance *fi, int event, void *arg)
struct net_device *dev = (struct net_device *)arg;
struct ctc_priv *privptr = dev->priv;
DBF_TEXT(trace, 2, __FUNCTION__);
ctc_pr_debug("%s: Restarting\n", dev->name);
dev_action_stop(fi, event, arg);
fsm_event(privptr->fsm, DEV_EVENT_STOP, dev);
......@@ -2233,6 +2269,7 @@ 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, 2, __FUNCTION__);
switch (fsm_getstate(fi)) {
case DEV_STATE_STARTWAIT_RXTX:
if (event == DEV_EVENT_RXUP)
......@@ -2285,6 +2322,7 @@ 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, 2, __FUNCTION__);
switch (fsm_getstate(fi)) {
case DEV_STATE_RUNNING:
if (privptr->protocol == CTC_PROTO_LINUX_TTY)
......@@ -2386,6 +2424,7 @@ transmit_skb(struct channel *ch, struct sk_buff *skb)
struct ll_header header;
int rc = 0;
DBF_TEXT(trace, 2, __FUNCTION__);
if (fsm_getstate(ch->fsm) != CH_STATE_TXIDLE) {
int l = skb->len + LL_HEADER_LENGTH;
......@@ -2558,6 +2597,7 @@ ctc_tx(struct sk_buff *skb, struct net_device * dev)
int rc = 0;
struct ctc_priv *privptr = (struct ctc_priv *) dev->priv;
DBF_TEXT(trace, 2, __FUNCTION__);
/**
* Some sanity checks ...
*/
......@@ -2615,6 +2655,7 @@ ctc_change_mtu(struct net_device * dev, int new_mtu)
{
struct ctc_priv *privptr = (struct ctc_priv *) dev->priv;
DBF_TEXT(trace, 2, __FUNCTION__);
if ((new_mtu < 576) || (new_mtu > 65527) ||
(new_mtu > (privptr->channel[READ]->max_bufsize -
LL_HEADER_LENGTH - 2)))
......@@ -2659,6 +2700,7 @@ buffer_write(struct device *dev, const char *buf, size_t count)
struct net_device *ndev;
int bs1;
DBF_TEXT(trace, 2, __FUNCTION__);
priv = dev->driver_data;
if (!priv)
return -ENODEV;
......@@ -2703,6 +2745,7 @@ loglevel_write(struct device *dev, const char *buf, size_t count)
struct ctc_priv *priv;
int ll1;
DBF_TEXT(trace, 2, __FUNCTION__);
priv = dev->driver_data;
if (!priv)
return -ENODEV;
......@@ -2720,6 +2763,7 @@ ctc_print_statistics(struct ctc_priv *priv)
char *sbuf;
char *p;
DBF_TEXT(trace, 2, __FUNCTION__);
if (!priv)
return;
sbuf = (char *)kmalloc(2048, GFP_KERNEL);
......@@ -2849,6 +2893,7 @@ ctc_init_netdevice(struct net_device * dev, int alloc_device,
if (!privptr)
return NULL;
DBF_TEXT(setup, 2, __FUNCTION__);
if (alloc_device) {
dev = kmalloc(sizeof (struct net_device), GFP_KERNEL);
if (!dev)
......@@ -2900,6 +2945,7 @@ ctc_proto_store(struct device *dev, const char *buf, size_t count)
struct ctc_priv *priv;
int value;
DBF_TEXT(trace, 2, __FUNCTION__);
pr_debug("%s() called\n", __FUNCTION__);
priv = dev->driver_data;
......@@ -2971,6 +3017,7 @@ ctc_probe_device(struct ccwgroup_device *cgdev)
int rc;
pr_debug("%s() called\n", __FUNCTION__);
DBF_TEXT(trace, 2, __FUNCTION__);
if (!get_device(&cgdev->dev))
return -ENODEV;
......@@ -3017,6 +3064,7 @@ ctc_new_device(struct ccwgroup_device *cgdev)
int ret;
pr_debug("%s() called\n", __FUNCTION__);
DBF_TEXT(setup, 2, __FUNCTION__);
privptr = cgdev->dev.driver_data;
if (!privptr)
......@@ -3110,7 +3158,7 @@ ctc_shutdown_device(struct ccwgroup_device *cgdev)
struct ctc_priv *priv;
struct net_device *ndev;
DBF_TEXT(trace, 2, __FUNCTION__);
pr_debug("%s() called\n", __FUNCTION__);
priv = cgdev->dev.driver_data;
......@@ -3161,6 +3209,7 @@ ctc_remove_device(struct ccwgroup_device *cgdev)
struct ctc_priv *priv;
pr_debug("%s() called\n", __FUNCTION__);
DBF_TEXT(trace, 2, __FUNCTION__);
priv = cgdev->dev.driver_data;
if (!priv)
......@@ -3199,6 +3248,7 @@ ctc_exit(void)
{
unregister_cu3088_discipline(&ctc_group_driver);
ctc_tty_cleanup();
unregister_dbf_views();
ctc_pr_info("CTC driver unloaded\n");
}
......@@ -3215,10 +3265,17 @@ ctc_init(void)
print_banner();
ret = register_dbf_views();
if (ret){
ctc_pr_crit("ctc_init failed with register_dbf_views rc = %d\n", ret);
return ret;
}
ctc_tty_init();
ret = register_cu3088_discipline(&ctc_group_driver);
if (ret)
if (ret) {
ctc_tty_cleanup();
unregister_dbf_views();
}
return ret;
}
......
/*
* $Id: ctctty.c,v 1.17 2004/03/31 17:06:34 ptiedem Exp $
* $Id: ctctty.c,v 1.21 2004/07/02 16:31:22 ptiedem Exp $
*
* CTC / ESCON network driver, tty interface.
*
......@@ -30,6 +30,7 @@
#include <asm/uaccess.h>
#include <linux/devfs_fs_kernel.h>
#include "ctctty.h"
#include "ctcdbug.h"
#define CTC_TTY_MAJOR 43
#define CTC_TTY_MAX_DEVICES 64
......@@ -103,6 +104,7 @@ ctc_tty_try_read(ctc_tty_info * info, struct sk_buff *skb)
int len;
struct tty_struct *tty;
DBF_TEXT(trace, 2, __FUNCTION__);
if ((tty = info->tty)) {
if (info->mcr & UART_MCR_RTS) {
c = TTY_FLIPBUF_SIZE - tty->flip.count;
......@@ -132,6 +134,7 @@ ctc_tty_readmodem(ctc_tty_info *info)
int ret = 1;
struct tty_struct *tty;
DBF_TEXT(trace, 2, __FUNCTION__);
if ((tty = info->tty)) {
if (info->mcr & UART_MCR_RTS) {
int c = TTY_FLIPBUF_SIZE - tty->flip.count;
......@@ -165,6 +168,7 @@ ctc_tty_setcarrier(struct net_device *netdev, int on)
{
int i;
DBF_TEXT(trace, 2, __FUNCTION__);
if ((!driver) || ctc_tty_shuttingdown)
return;
for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
......@@ -185,6 +189,7 @@ ctc_tty_netif_rx(struct sk_buff *skb)
int i;
ctc_tty_info *info = NULL;
DBF_TEXT(trace, 2, __FUNCTION__);
if (!skb)
return;
if ((!skb->dev) || (!driver) || ctc_tty_shuttingdown) {
......@@ -249,6 +254,7 @@ ctc_tty_tint(ctc_tty_info * info)
int wake = 1;
int rc;
DBF_TEXT(trace, 2, __FUNCTION__);
if (!info->netdev) {
if (skb)
kfree_skb(skb);
......@@ -341,6 +347,7 @@ ctc_tty_inject(ctc_tty_info *info, char c)
int skb_res;
struct sk_buff *skb;
DBF_TEXT(trace, 2, __FUNCTION__);
if (ctc_tty_shuttingdown)
return;
skb_res = info->netdev->hard_header_len + sizeof(info->mcr) +
......@@ -361,6 +368,7 @@ ctc_tty_inject(ctc_tty_info *info, char c)
static void
ctc_tty_transmit_status(ctc_tty_info *info)
{
DBF_TEXT(trace, 2, __FUNCTION__);
if (ctc_tty_shuttingdown)
return;
info->flags |= CTC_ASYNC_TX_LINESTAT;
......@@ -374,6 +382,7 @@ ctc_tty_change_speed(ctc_tty_info * info)
unsigned int quot;
int i;
DBF_TEXT(trace, 2, __FUNCTION__);
if (!info->tty || !info->tty->termios)
return;
cflag = info->tty->termios->c_cflag;
......@@ -412,6 +421,7 @@ ctc_tty_change_speed(ctc_tty_info * info)
static int
ctc_tty_startup(ctc_tty_info * info)
{
DBF_TEXT(trace, 2, __FUNCTION__);
if (info->flags & CTC_ASYNC_INITIALIZED)
return 0;
#ifdef CTC_DEBUG_MODEM_OPEN
......@@ -454,6 +464,7 @@ ctc_tty_stopdev(unsigned long data)
static void
ctc_tty_shutdown(ctc_tty_info * info)
{
DBF_TEXT(trace, 2, __FUNCTION__);
if (!(info->flags & CTC_ASYNC_INITIALIZED))
return;
#ifdef CTC_DEBUG_MODEM_OPEN
......@@ -486,14 +497,17 @@ ctc_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int cou
int total = 0;
ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
DBF_TEXT(trace, 2, __FUNCTION__);
if (ctc_tty_shuttingdown)
return 0;
goto ex;
if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_write"))
return 0;
goto ex;
if (!tty)
return 0;
if (!info->netdev)
return -ENODEV;
goto ex;
if (!info->netdev) {
total = -ENODEV;
goto ex;
}
if (from_user)
down(&info->write_sem);
while (1) {
......@@ -530,6 +544,8 @@ ctc_tty_write(struct tty_struct *tty, int from_user, const u_char * buf, int cou
}
if (from_user)
up(&info->write_sem);
ex:
DBF_TEXT(trace, 6, __FUNCTION__);
return total;
}
......@@ -559,13 +575,14 @@ ctc_tty_flush_buffer(struct tty_struct *tty)
ctc_tty_info *info;
unsigned long flags;
DBF_TEXT(trace, 2, __FUNCTION__);
if (!tty)
return;
goto ex;
spin_lock_irqsave(&ctc_tty_lock, flags);
info = (ctc_tty_info *) tty->driver_data;
if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_flush_buffer")) {
spin_unlock_irqrestore(&ctc_tty_lock, flags);
return;
goto ex;
}
skb_queue_purge(&info->tx_queue);
info->lsr |= UART_LSR_TEMT;
......@@ -574,6 +591,9 @@ ctc_tty_flush_buffer(struct tty_struct *tty)
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
tty->ldisc.write_wakeup)
(tty->ldisc.write_wakeup) (tty);
ex:
DBF_TEXT_(trace, 2, "ex: %s ", __FUNCTION__);
return;
}
static void
......@@ -783,7 +803,6 @@ ctc_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
{
ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
unsigned int cflag = tty->termios->c_cflag;
ctc_tty_change_speed(info);
/* Handle transition to B0 */
......@@ -1032,8 +1051,10 @@ ctc_tty_close(struct tty_struct *tty, struct file *filp)
}
}
ctc_tty_shutdown(info);
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
if (tty->driver->flush_buffer) {
skb_queue_purge(&info->tx_queue);
info->lsr |= UART_LSR_TEMT;
}
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
info->tty = 0;
......@@ -1059,7 +1080,6 @@ ctc_tty_hangup(struct tty_struct *tty)
{
ctc_tty_info *info = (ctc_tty_info *)tty->driver_data;
unsigned long saveflags;
if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_hangup"))
return;
ctc_tty_shutdown(info);
......@@ -1185,6 +1205,21 @@ ctc_tty_register_netdev(struct net_device *dev) {
"with NULL dev or NULL dev-name\n");
return -1;
}
/*
* If the name is a format string the caller wants us to
* do a name allocation : format string must end with %d
*/
if (strchr(dev->name, '%'))
{
int err = dev_alloc_name(dev, dev->name); // dev->name is changed by this
if (err < 0) {
printk(KERN_DEBUG "dev_alloc returned error %d\n", err);
return err;
}
}
for (p = dev->name; p && ((*p < '0') || (*p > '9')); p++);
ttynum = simple_strtoul(p, &err, 0);
if ((ttynum < 0) || (ttynum >= CTC_TTY_MAX_DEVICES) ||
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment