11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DSS.1 Finite State Machine
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * base: ITU-T Rec Q.931
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1996 Universidade de Lisboa
6475be4d85a274d0961593db41cf85689db1d583cJoe Perches *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
9475be4d85a274d0961593db41cf85689db1d583cJoe Perches * This software may be used and distributed according to the terms of
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the GNU General Public License, incorporated herein by reference.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *        TODO: complete the FSM
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *              move state/event descriptions to a user space logger
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h>
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/isdnif.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pcbit.h"
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "edss1.h"
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "layer2.h"
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "callbacks.h"
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
366f68ad7fbb421df0aa3c267768245b2e86a91f74Joe Perchesconst char * const isdn_state_table[] = {
37475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Closed",
38475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Call initiated",
39475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Overlap sending",
40475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Outgoing call proceeding",
41475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"NOT DEFINED",
42475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Call delivered",
43475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Call present",
44475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Call received",
45475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Connect request",
46475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Incoming call proceeding",
47475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Active",
48475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Disconnect request",
49475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Disconnect indication",
50475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"NOT DEFINED",
51475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"NOT DEFINED",
52475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Suspend request",
53475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"NOT DEFINED",
54475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Resume request",
55475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"NOT DEFINED",
56475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Release Request",
57475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"NOT DEFINED",
58475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"NOT DEFINED",
59475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"NOT DEFINED",
60475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"NOT DEFINED",
61475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"NOT DEFINED",
62475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Overlap receiving",
63475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Select protocol on B-Channel",
64475be4d85a274d0961593db41cf85689db1d583cJoe Perches	"Activate B-channel protocol"
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_ERRS
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct CauseValue {
70475be4d85a274d0961593db41cf85689db1d583cJoe Perches	byte nr;
71475be4d85a274d0961593db41cf85689db1d583cJoe Perches	char *descr;
72475be4d85a274d0961593db41cf85689db1d583cJoe Perches} cvlist[] = {
73475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x01, "Unallocated (unassigned) number"},
74475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x02, "No route to specified transit network"},
75475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x03, "No route to destination"},
76475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x04, "Send special information tone"},
77475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x05, "Misdialled trunk prefix"},
78475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x06, "Channel unacceptable"},
79475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x07, "Channel awarded and being delivered in an established channel"},
80475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x08, "Preemption"},
81475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x09, "Preemption - circuit reserved for reuse"},
82475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x10, "Normal call clearing"},
83475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x11, "User busy"},
84475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x12, "No user responding"},
85475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x13, "No answer from user (user alerted)"},
86475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x14, "Subscriber absent"},
87475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x15, "Call rejected"},
88475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x16, "Number changed"},
89475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x1a, "non-selected user clearing"},
90475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x1b, "Destination out of order"},
91475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x1c, "Invalid number format (address incomplete)"},
92475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x1d, "Facility rejected"},
93475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x1e, "Response to Status enquiry"},
94475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x1f, "Normal, unspecified"},
95475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x22, "No circuit/channel available"},
96475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x26, "Network out of order"},
97475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x27, "Permanent frame mode connection out-of-service"},
98475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x28, "Permanent frame mode connection operational"},
99475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x29, "Temporary failure"},
100475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x2a, "Switching equipment congestion"},
101475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x2b, "Access information discarded"},
102475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x2c, "Requested circuit/channel not available"},
103475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x2e, "Precedence call blocked"},
104475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x2f, "Resource unavailable, unspecified"},
105475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x31, "Quality of service unavailable"},
106475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x32, "Requested facility not subscribed"},
107475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x35, "Outgoing calls barred within CUG"},
108475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x37, "Incoming calls barred within CUG"},
109475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x39, "Bearer capability not authorized"},
110475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x3a, "Bearer capability not presently available"},
111475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x3e, "Inconsistency in designated outgoing access information and subscriber class"},
112475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x3f, "Service or option not available, unspecified"},
113475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x41, "Bearer capability not implemented"},
114475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x42, "Channel type not implemented"},
115475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x43, "Requested facility not implemented"},
116475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x44, "Only restricted digital information bearer capability is available"},
117475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x4f, "Service or option not implemented"},
118475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x51, "Invalid call reference value"},
119475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x52, "Identified channel does not exist"},
120475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x53, "A suspended call exists, but this call identity does not"},
121475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x54, "Call identity in use"},
122475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x55, "No call suspended"},
123475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x56, "Call having the requested call identity has been cleared"},
124475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x57, "User not member of CUG"},
125475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x58, "Incompatible destination"},
126475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x5a, "Non-existent CUG"},
127475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x5b, "Invalid transit network selection"},
128475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x5f, "Invalid message, unspecified"},
129475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x60, "Mandatory information element is missing"},
130475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x61, "Message type non-existent or not implemented"},
131475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x62, "Message not compatible with call state or message type non-existent or not implemented"},
132475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x63, "Information element/parameter non-existent or not implemented"},
133475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x64, "Invalid information element contents"},
134475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x65, "Message not compatible with call state"},
135475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x66, "Recovery on timer expiry"},
136475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x67, "Parameter non-existent or not implemented - passed on"},
137475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x6e, "Message with unrecognized parameter discarded"},
138475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x6f, "Protocol error, unspecified"},
139475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0x7f, "Interworking, unspecified"}
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct isdn_event_desc {
145475be4d85a274d0961593db41cf85689db1d583cJoe Perches	unsigned short ev;
146475be4d85a274d0961593db41cf85689db1d583cJoe Perches	char *desc;
147475be4d85a274d0961593db41cf85689db1d583cJoe Perches} isdn_event_table[] = {
148475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{EV_USR_SETUP_REQ,     "CC->L3: Setup Request"},
149475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{EV_USR_SETUP_RESP,    "CC->L3: Setup Response"},
150475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{EV_USR_PROCED_REQ,    "CC->L3: Proceeding Request"},
151475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{EV_USR_RELEASE_REQ,   "CC->L3: Release Request"},
152475be4d85a274d0961593db41cf85689db1d583cJoe Perches
153475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{EV_NET_SETUP,        "NET->TE: setup "},
154475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{EV_NET_CALL_PROC,    "NET->TE: call proceeding"},
155475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{EV_NET_SETUP_ACK,    "NET->TE: setup acknowledge (more info needed)"},
156475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{EV_NET_CONN,         "NET->TE: connect"},
157475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{EV_NET_CONN_ACK,     "NET->TE: connect acknowledge"},
158475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{EV_NET_DISC,         "NET->TE: disconnect indication"},
159475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{EV_NET_RELEASE,      "NET->TE: release"},
160475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{EV_NET_RELEASE_COMP, "NET->TE: release complete"},
161475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{EV_NET_SELP_RESP,    "Board: Select B-channel protocol ack"},
162475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{EV_NET_ACTV_RESP,    "Board: Activate B-channel protocol ack"},
163475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{EV_TIMER,            "Timeout"},
164475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0, "NULL"}
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
167475be4d85a274d0961593db41cf85689db1d583cJoe Percheschar *strisdnevent(ushort ev)
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
169475be4d85a274d0961593db41cf85689db1d583cJoe Perches	struct isdn_event_desc *entry;
170475be4d85a274d0961593db41cf85689db1d583cJoe Perches
171475be4d85a274d0961593db41cf85689db1d583cJoe Perches	for (entry = isdn_event_table; entry->ev; entry++)
172475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (entry->ev == ev)
173475be4d85a274d0961593db41cf85689db1d583cJoe Perches			break;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
175475be4d85a274d0961593db41cf85689db1d583cJoe Perches	return entry->desc;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Euro ISDN finite state machine
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct fsm_timer_entry fsm_timers[] = {
183475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_CALL_PROC, 10},
184475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_DISC_REQ, 2},
185475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_ACTIVE_SELP, 5},
186475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_ACTIVE_ACTV, 5},
187475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_INCM_PROC, 10},
188475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_CONN_REQ, 2},
189475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0xff, 0}
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct fsm_entry fsm_table[] = {
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Connect Phase */
194475be4d85a274d0961593db41cf85689db1d583cJoe Perches	/* Outgoing */
195475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_NULL, ST_CALL_INIT, EV_USR_SETUP_REQ, cb_out_1},
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
197475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_CALL_INIT, ST_OVER_SEND, EV_NET_SETUP_ACK, cb_notdone},
198475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_CALL_INIT, ST_CALL_PROC, EV_NET_CALL_PROC, NULL},
199475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_CALL_INIT, ST_NULL, EV_NET_DISC, cb_out_2},
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
201475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_CALL_PROC, ST_ACTIVE_SELP, EV_NET_CONN, cb_out_2},
202475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_CALL_PROC, ST_NULL, EV_NET_DISC, cb_disc_1},
203475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_CALL_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
205475be4d85a274d0961593db41cf85689db1d583cJoe Perches	/* Incoming */
206475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_NULL, ST_CALL_PRES, EV_NET_SETUP, NULL},
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
208475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_CALL_PRES, ST_INCM_PROC, EV_USR_PROCED_REQ, cb_in_1},
209475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_CALL_PRES, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_INCM_PROC, ST_CONN_REQ, EV_USR_SETUP_RESP, cb_in_2},
212475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_INCM_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
214475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_CONN_REQ, ST_ACTIVE_SELP, EV_NET_CONN_ACK, cb_in_3},
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
216475be4d85a274d0961593db41cf85689db1d583cJoe Perches	/* Active */
217475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_ACTIVE, ST_NULL, EV_NET_DISC, cb_disc_1},
218475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_ACTIVE, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
219475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_ACTIVE, ST_NULL, EV_NET_RELEASE, cb_disc_3},
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
221475be4d85a274d0961593db41cf85689db1d583cJoe Perches	/* Disconnect */
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
223475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_DISC_REQ, ST_NULL, EV_NET_DISC, cb_disc_1},
224475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_DISC_REQ, ST_NULL, EV_NET_RELEASE, cb_disc_3},
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
226475be4d85a274d0961593db41cf85689db1d583cJoe Perches	/* protocol selection */
227475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_ACTIVE_SELP, ST_ACTIVE_ACTV, EV_NET_SELP_RESP, cb_selp_1},
228475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_ACTIVE_SELP, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
230475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_ACTIVE_ACTV, ST_ACTIVE, EV_NET_ACTV_RESP, cb_open},
231475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_ACTIVE_ACTV, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
233475be4d85a274d0961593db41cf85689db1d583cJoe Perches	/* Timers */
234475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_CALL_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2},
235475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_DISC_REQ, ST_NULL, EV_TIMER, cb_disc_3},
236475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_ACTIVE_SELP, ST_DISC_REQ, EV_TIMER, cb_disc_2},
237475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_ACTIVE_ACTV, ST_DISC_REQ, EV_TIMER, cb_disc_2},
238475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_INCM_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2},
239475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{ST_CONN_REQ, ST_CONN_REQ, EV_TIMER, cb_in_2},
240475be4d85a274d0961593db41cf85689db1d583cJoe Perches
241475be4d85a274d0961593db41cf85689db1d583cJoe Perches	{0xff, 0, 0, NULL}
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pcbit_fsm_timer(unsigned long data)
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
247475be4d85a274d0961593db41cf85689db1d583cJoe Perches	struct pcbit_dev *dev;
248475be4d85a274d0961593db41cf85689db1d583cJoe Perches	struct pcbit_chan *chan;
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
250475be4d85a274d0961593db41cf85689db1d583cJoe Perches	chan = (struct pcbit_chan *) data;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
252475be4d85a274d0961593db41cf85689db1d583cJoe Perches	del_timer(&chan->fsm_timer);
253475be4d85a274d0961593db41cf85689db1d583cJoe Perches	chan->fsm_timer.function = NULL;
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
255475be4d85a274d0961593db41cf85689db1d583cJoe Perches	dev = chan2dev(chan);
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
257475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (dev == NULL) {
258475be4d85a274d0961593db41cf85689db1d583cJoe Perches		printk(KERN_WARNING "pcbit: timer for unknown device\n");
259475be4d85a274d0961593db41cf85689db1d583cJoe Perches		return;
260475be4d85a274d0961593db41cf85689db1d583cJoe Perches	}
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
262475be4d85a274d0961593db41cf85689db1d583cJoe Perches	pcbit_fsm_event(dev, chan, EV_TIMER, NULL);
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid pcbit_fsm_event(struct pcbit_dev *dev, struct pcbit_chan *chan,
267475be4d85a274d0961593db41cf85689db1d583cJoe Perches		     unsigned short event, struct callb_data *data)
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
269475be4d85a274d0961593db41cf85689db1d583cJoe Perches	struct fsm_entry *action;
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct fsm_timer_entry *tentry;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&dev->lock, flags);
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
275475be4d85a274d0961593db41cf85689db1d583cJoe Perches	for (action = fsm_table; action->init != 0xff; action++)
276475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (action->init == chan->fsm_state && action->event == event)
277475be4d85a274d0961593db41cf85689db1d583cJoe Perches			break;
278475be4d85a274d0961593db41cf85689db1d583cJoe Perches
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (action->init == 0xff) {
280475be4d85a274d0961593db41cf85689db1d583cJoe Perches
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&dev->lock, flags);
282475be4d85a274d0961593db41cf85689db1d583cJoe Perches		printk(KERN_DEBUG "fsm error: event %x on state %x\n",
283475be4d85a274d0961593db41cf85689db1d583cJoe Perches		       event, chan->fsm_state);
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
287475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (chan->fsm_timer.function) {
288475be4d85a274d0961593db41cf85689db1d583cJoe Perches		del_timer(&chan->fsm_timer);
289475be4d85a274d0961593db41cf85689db1d583cJoe Perches		chan->fsm_timer.function = NULL;
290475be4d85a274d0961593db41cf85689db1d583cJoe Perches	}
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	chan->fsm_state = action->final;
293475be4d85a274d0961593db41cf85689db1d583cJoe Perches
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pcbit_state_change(dev, chan, action->init, event, action->final);
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
296475be4d85a274d0961593db41cf85689db1d583cJoe Perches	for (tentry = fsm_timers; tentry->init != 0xff; tentry++)
297475be4d85a274d0961593db41cf85689db1d583cJoe Perches		if (tentry->init == chan->fsm_state)
298475be4d85a274d0961593db41cf85689db1d583cJoe Perches			break;
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
300475be4d85a274d0961593db41cf85689db1d583cJoe Perches	if (tentry->init != 0xff) {
301475be4d85a274d0961593db41cf85689db1d583cJoe Perches		init_timer(&chan->fsm_timer);
302475be4d85a274d0961593db41cf85689db1d583cJoe Perches		chan->fsm_timer.function = &pcbit_fsm_timer;
303475be4d85a274d0961593db41cf85689db1d583cJoe Perches		chan->fsm_timer.data = (ulong) chan;
304475be4d85a274d0961593db41cf85689db1d583cJoe Perches		chan->fsm_timer.expires = jiffies + tentry->timeout * HZ;
305475be4d85a274d0961593db41cf85689db1d583cJoe Perches		add_timer(&chan->fsm_timer);
306475be4d85a274d0961593db41cf85689db1d583cJoe Perches	}
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&dev->lock, flags);
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (action->callb)
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		action->callb(dev, chan, data);
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
314