aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn/sc/timer.c
blob: 710d0f47ca35ccd2bdce256cc806b425bde3e8da (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/* $Id: timer.c,v 1.3.6.1 2001/09/23 22:24:59 kai Exp $
 *
 * Copyright (C) 1996  SpellCaster Telecommunications Inc.
 *
 * This software may be used and distributed according to the terms
 * of the GNU General Public License, incorporated herein by reference.
 *
 * For more information, please contact gpl-info@spellcast.com or write:
 *
 *     SpellCaster Telecommunications Inc.
 *     5621 Finch Avenue East, Unit #3
 *     Scarborough, Ontario  Canada
 *     M1B 2T9
 *     +1 (416) 297-8565
 *     +1 (416) 297-6433 Facsimile
 */

#include "includes.h"
#include "hardware.h"
#include "message.h"
#include "card.h"

extern board *sc_adapter[];

extern void flushreadfifo(int);
extern int  startproc(int);
extern int  indicate_status(int, int, unsigned long, char *);
extern int  sendmessage(int, unsigned int, unsigned int, unsigned int,
        unsigned int, unsigned int, unsigned int, unsigned int *);


/*
 * Write the proper values into the I/O ports following a reset
 */
void setup_ports(int card)
{

	outb((sc_adapter[card]->rambase >> 12), sc_adapter[card]->ioport[EXP_BASE]);

	/* And the IRQ */
	outb((sc_adapter[card]->interrupt | 0x80),
		sc_adapter[card]->ioport[IRQ_SELECT]);
}

/*
 * Timed function to check the status of a previous reset
 * Must be very fast as this function runs in the context of
 * an interrupt handler.
 *
 * Setup the ioports for the board that were cleared by the reset.
 * Then, check to see if the signate has been set. Next, set the
 * signature to a known value and issue a startproc if needed.
 */
void check_reset(unsigned long data)
{
	unsigned long flags;
	unsigned long sig;
	int card = (unsigned int) data;

	pr_debug("%s: check_timer timer called\n",
		sc_adapter[card]->devicename);

	/* Setup the io ports */
	setup_ports(card);

	spin_lock_irqsave(&sc_adapter[card]->lock, flags);
	outb(sc_adapter[card]->ioport[sc_adapter[card]->shmem_pgport],
		(sc_adapter[card]->shmem_magic>>14) | 0x80);
	sig = (unsigned long) *((unsigned long *)(sc_adapter[card]->rambase + SIG_OFFSET));

	/* check the signature */
	if(sig == SIGNATURE) {
		flushreadfifo(card);
		spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
		/* See if we need to do a startproc */
		if (sc_adapter[card]->StartOnReset)
			startproc(card);
	} else  {
		pr_debug("%s: No signature yet, waiting another %d jiffies.\n", 
			sc_adapter[card]->devicename, CHECKRESET_TIME);
		mod_timer(&sc_adapter[card]->reset_timer, jiffies+CHECKRESET_TIME);
		spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
	}
}

/*
 * Timed function to check the status of a previous reset
 * Must be very fast as this function runs in the context of
 * an interrupt handler.
 *
 * Send check sc_adapter->phystat to see if the channels are up
 * If they are, tell ISDN4Linux that the board is up. If not,
 * tell IADN4Linux that it is up. Always reset the timer to
 * fire again (endless loop).
 */
void check_phystat(unsigned long data)
{
	unsigned long flags;
	int card = (unsigned int) data;

	pr_debug("%s: Checking status...\n", sc_adapter[card]->devicename);
	/* 
	 * check the results of the last PhyStat and change only if
	 * has changed drastically
	 */
	if (sc_adapter[card]->nphystat && !sc_adapter[card]->phystat) {   /* All is well */
		pr_debug("PhyStat transition to RUN\n");
		pr_info("%s: Switch contacted, transmitter enabled\n", 
			sc_adapter[card]->devicename);
		indicate_status(card, ISDN_STAT_RUN, 0, NULL);
	}
	else if (!sc_adapter[card]->nphystat && sc_adapter[card]->phystat) {   /* All is not well */
		pr_debug("PhyStat transition to STOP\n");
		pr_info("%s: Switch connection lost, transmitter disabled\n", 
			sc_adapter[card]->devicename);

		indicate_status(card, ISDN_STAT_STOP, 0, NULL);
	}

	sc_adapter[card]->phystat = sc_adapter[card]->nphystat;

	/* Reinitialize the timer */
	spin_lock_irqsave(&sc_adapter[card]->lock, flags);
	mod_timer(&sc_adapter[card]->stat_timer, jiffies+CHECKSTAT_TIME);
	spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);

	/* Send a new cePhyStatus message */
	sendmessage(card, CEPID,ceReqTypePhy,ceReqClass2,
		ceReqPhyStatus,0,0,NULL);
}

/*
 * When in trace mode, this callback is used to swap the working shared
 * RAM page to the trace page(s) and process all received messages. It
 * must be called often enough to get all of the messages out of RAM before
 * it loops around.
 * Trace messages are \n terminated strings.
 * We output the messages in 64 byte chunks through readstat. Each chunk
 * is scanned for a \n followed by a time stamp. If the timerstamp is older
 * than the current time, scanning stops and the page and offset are recorded
 * as the starting point the next time the trace timer is called. The final
 * step is to restore the working page and reset the timer.
 */
void trace_timer(unsigned long data)
{
	/* not implemented */
}