2006-03-26 13:38:30 +04:00
/*
* Stuff used by all variants of the driver
*
2006-04-11 09:55:14 +04:00
* Copyright ( c ) 2001 by Stefan Eilers ,
2006-03-26 13:38:30 +04:00
* Hansjoerg Lipp < hjlipp @ web . de > ,
* Tilman Schmidt < tilman @ imap . cc > .
*
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* 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 of
* the License , or ( at your option ) any later version .
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# include "gigaset.h"
/* ========================================================== */
/* bit masks for pending commands */
2006-04-11 09:55:00 +04:00
# define PC_DIAL 0x001
# define PC_HUP 0x002
# define PC_INIT 0x004
# define PC_DLE0 0x008
# define PC_DLE1 0x010
# define PC_SHUTDOWN 0x020
# define PC_ACCEPT 0x040
# define PC_CID 0x080
# define PC_NOCID 0x100
# define PC_CIDMODE 0x200
# define PC_UMMODE 0x400
2006-03-26 13:38:30 +04:00
/* types of modem responses */
2006-04-11 09:55:00 +04:00
# define RT_NOTHING 0
# define RT_ZSAU 1
# define RT_RING 2
# define RT_NUMBER 3
# define RT_STRING 4
# define RT_HEX 5
# define RT_ZCAU 6
2006-03-26 13:38:30 +04:00
/* Possible ASCII responses */
2006-04-11 09:55:00 +04:00
# define RSP_OK 0
//#define RSP_BUSY 1
//#define RSP_CONNECT 2
# define RSP_ZGCI 3
# define RSP_RING 4
# define RSP_ZAOC 5
# define RSP_ZCSTR 6
# define RSP_ZCFGT 7
# define RSP_ZCFG 8
# define RSP_ZCCR 9
# define RSP_EMPTY 10
# define RSP_ZLOG 11
# define RSP_ZCAU 12
# define RSP_ZMWI 13
# define RSP_ZABINFO 14
# define RSP_ZSMLSTCHG 15
# define RSP_VAR 100
# define RSP_ZSAU (RSP_VAR + VAR_ZSAU)
# define RSP_ZDLE (RSP_VAR + VAR_ZDLE)
# define RSP_ZVLS (RSP_VAR + VAR_ZVLS)
# define RSP_ZCTP (RSP_VAR + VAR_ZCTP)
# define RSP_STR (RSP_VAR + VAR_NUM)
# define RSP_NMBR (RSP_STR + STR_NMBR)
# define RSP_ZCPN (RSP_STR + STR_ZCPN)
# define RSP_ZCON (RSP_STR + STR_ZCON)
# define RSP_ZBC (RSP_STR + STR_ZBC)
# define RSP_ZHLC (RSP_STR + STR_ZHLC)
# define RSP_ERROR -1 /* ERROR */
# define RSP_WRONG_CID -2 /* unknown cid in cmd */
//#define RSP_EMPTY -3
# define RSP_UNKNOWN -4 /* unknown response */
# define RSP_FAIL -5 /* internal error */
# define RSP_INVAL -6 /* invalid response */
# define RSP_NONE -19
# define RSP_STRING -20
# define RSP_NULL -21
//#define RSP_RETRYFAIL -22
//#define RSP_RETRY -23
//#define RSP_SKIP -24
# define RSP_INIT -27
# define RSP_ANY -26
# define RSP_LAST -28
# define RSP_NODEV -9
2006-03-26 13:38:30 +04:00
/* actions for process_response */
# define ACT_NOTHING 0
# define ACT_SETDLE1 1
# define ACT_SETDLE0 2
# define ACT_FAILINIT 3
# define ACT_HUPMODEM 4
# define ACT_CONFIGMODE 5
# define ACT_INIT 6
# define ACT_DLE0 7
# define ACT_DLE1 8
# define ACT_FAILDLE0 9
# define ACT_FAILDLE1 10
# define ACT_RING 11
# define ACT_CID 12
# define ACT_FAILCID 13
# define ACT_SDOWN 14
# define ACT_FAILSDOWN 15
# define ACT_DEBUG 16
# define ACT_WARN 17
# define ACT_DIALING 18
# define ACT_ABORTDIAL 19
# define ACT_DISCONNECT 20
# define ACT_CONNECT 21
# define ACT_REMOTEREJECT 22
2006-04-11 09:55:00 +04:00
# define ACT_CONNTIMEOUT 23
2006-03-26 13:38:30 +04:00
# define ACT_REMOTEHUP 24
# define ACT_ABORTHUP 25
# define ACT_ICALL 26
# define ACT_ACCEPTED 27
# define ACT_ABORTACCEPT 28
# define ACT_TIMEOUT 29
# define ACT_GETSTRING 30
# define ACT_SETVER 31
# define ACT_FAILVER 32
# define ACT_GOTVER 33
# define ACT_TEST 34
# define ACT_ERROR 35
# define ACT_ABORTCID 36
# define ACT_ZCAU 37
2006-04-11 09:55:00 +04:00
# define ACT_NOTIFY_BC_DOWN 38
# define ACT_NOTIFY_BC_UP 39
# define ACT_DIAL 40
# define ACT_ACCEPT 41
# define ACT_PROTO_L2 42
# define ACT_HUP 43
# define ACT_IF_LOCK 44
# define ACT_START 45
# define ACT_STOP 46
# define ACT_FAKEDLE0 47
# define ACT_FAKEHUP 48
# define ACT_FAKESDOWN 49
# define ACT_SHUTDOWN 50
# define ACT_PROC_CIDMODE 51
# define ACT_UMODESET 52
# define ACT_FAILUMODE 53
# define ACT_CMODESET 54
# define ACT_FAILCMODE 55
# define ACT_IF_VER 56
2006-03-26 13:38:30 +04:00
# define ACT_CMD 100
/* at command sequences */
2006-04-11 09:55:00 +04:00
# define SEQ_NONE 0
# define SEQ_INIT 100
# define SEQ_DLE0 200
# define SEQ_DLE1 250
# define SEQ_CID 300
# define SEQ_NOCID 350
# define SEQ_HUP 400
# define SEQ_DIAL 600
# define SEQ_ACCEPT 720
# define SEQ_SHUTDOWN 500
# define SEQ_CIDMODE 10
# define SEQ_UMMODE 11
2006-03-26 13:38:30 +04:00
// 100: init, 200: dle0, 250:dle1, 300: get cid (dial), 350: "hup" (no cid), 400: hup, 500: reset, 600: dial, 700: ring
struct reply_t gigaset_tab_nocid_m10x [ ] = /* with dle mode */
{
/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */
/* initialize device, set cid mode if possible */
//{RSP_INIT, -1, -1,100, 900, 0, {ACT_TEST}},
//{RSP_ERROR, 900,900, -1, 0, 0, {ACT_FAILINIT}},
//{RSP_OK, 900,900, -1, 100, INIT_TIMEOUT,
// {ACT_TIMEOUT}},
{ RSP_INIT , - 1 , - 1 , SEQ_INIT , 100 , INIT_TIMEOUT ,
2006-04-11 09:55:04 +04:00
{ ACT_TIMEOUT } } , /* wait until device is ready */
2006-03-26 13:38:30 +04:00
{ EV_TIMEOUT , 100 , 100 , - 1 , 101 , 3 , { 0 } , " Z \r " } , /* device in transparent mode? try to initialize it. */
{ RSP_OK , 101 , 103 , - 1 , 120 , 5 , { ACT_GETSTRING } , " +GMR \r " } , /* get version */
{ EV_TIMEOUT , 101 , 101 , - 1 , 102 , 5 , { 0 } , " Z \r " } , /* timeout => try once again. */
{ RSP_ERROR , 101 , 101 , - 1 , 102 , 5 , { 0 } , " Z \r " } , /* error => try once again. */
{ EV_TIMEOUT , 102 , 102 , - 1 , 108 , 5 , { ACT_SETDLE1 } , " ^SDLE=0 \r " } , /* timeout => try again in DLE mode. */
{ RSP_OK , 108 , 108 , - 1 , 104 , - 1 } ,
{ RSP_ZDLE , 104 , 104 , 0 , 103 , 5 , { 0 } , " Z \r " } ,
{ EV_TIMEOUT , 104 , 104 , - 1 , 0 , 0 , { ACT_FAILINIT } } ,
{ RSP_ERROR , 108 , 108 , - 1 , 0 , 0 , { ACT_FAILINIT } } ,
{ EV_TIMEOUT , 108 , 108 , - 1 , 105 , 2 , { ACT_SETDLE0 ,
2006-04-11 09:55:04 +04:00
ACT_HUPMODEM ,
ACT_TIMEOUT } } , /* still timeout => connection in unimodem mode? */
2006-03-26 13:38:30 +04:00
{ EV_TIMEOUT , 105 , 105 , - 1 , 103 , 5 , { 0 } , " Z \r " } ,
{ RSP_ERROR , 102 , 102 , - 1 , 107 , 5 , { 0 } , " ^GETPRE \r " } , /* ERROR on ATZ => maybe in config mode? */
{ RSP_OK , 107 , 107 , - 1 , 0 , 0 , { ACT_CONFIGMODE } } ,
{ RSP_ERROR , 107 , 107 , - 1 , 0 , 0 , { ACT_FAILINIT } } ,
{ EV_TIMEOUT , 107 , 107 , - 1 , 0 , 0 , { ACT_FAILINIT } } ,
{ RSP_ERROR , 103 , 103 , - 1 , 0 , 0 , { ACT_FAILINIT } } ,
{ EV_TIMEOUT , 103 , 103 , - 1 , 0 , 0 , { ACT_FAILINIT } } ,
{ RSP_STRING , 120 , 120 , - 1 , 121 , - 1 , { ACT_SETVER } } ,
{ EV_TIMEOUT , 120 , 121 , - 1 , 0 , 0 , { ACT_FAILVER , ACT_INIT } } ,
{ RSP_ERROR , 120 , 121 , - 1 , 0 , 0 , { ACT_FAILVER , ACT_INIT } } ,
{ RSP_OK , 121 , 121 , - 1 , 0 , 0 , { ACT_GOTVER , ACT_INIT } } ,
#if 0
{ EV_TIMEOUT , 120 , 121 , - 1 , 130 , 5 , { ACT_FAILVER } , " ^SGCI=1 \r " } ,
{ RSP_ERROR , 120 , 121 , - 1 , 130 , 5 , { ACT_FAILVER } , " ^SGCI=1 \r " } ,
{ RSP_OK , 121 , 121 , - 1 , 130 , 5 , { ACT_GOTVER } , " ^SGCI=1 \r " } ,
{ RSP_OK , 130 , 130 , - 1 , 0 , 0 , { ACT_INIT } } ,
{ RSP_ERROR , 130 , 130 , - 1 , 0 , 0 , { ACT_FAILINIT } } ,
{ EV_TIMEOUT , 130 , 130 , - 1 , 0 , 0 , { ACT_FAILINIT } } ,
# endif
/* leave dle mode */
{ RSP_INIT , 0 , 0 , SEQ_DLE0 , 201 , 5 , { 0 } , " ^SDLE=0 \r " } ,
{ RSP_OK , 201 , 201 , - 1 , 202 , - 1 } ,
//{RSP_ZDLE, 202,202, 0, 202, 0, {ACT_ERROR}},//DELETE
{ RSP_ZDLE , 202 , 202 , 0 , 0 , 0 , { ACT_DLE0 } } ,
{ RSP_NODEV , 200 , 249 , - 1 , 0 , 0 , { ACT_FAKEDLE0 } } ,
{ RSP_ERROR , 200 , 249 , - 1 , 0 , 0 , { ACT_FAILDLE0 } } ,
{ EV_TIMEOUT , 200 , 249 , - 1 , 0 , 0 , { ACT_FAILDLE0 } } ,
/* enter dle mode */
{ RSP_INIT , 0 , 0 , SEQ_DLE1 , 251 , 5 , { 0 } , " ^SDLE=1 \r " } ,
{ RSP_OK , 251 , 251 , - 1 , 252 , - 1 } ,
{ RSP_ZDLE , 252 , 252 , 1 , 0 , 0 , { ACT_DLE1 } } ,
{ RSP_ERROR , 250 , 299 , - 1 , 0 , 0 , { ACT_FAILDLE1 } } ,
{ EV_TIMEOUT , 250 , 299 , - 1 , 0 , 0 , { ACT_FAILDLE1 } } ,
/* incoming call */
{ RSP_RING , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_RING } } ,
/* get cid */
//{RSP_INIT, 0, 0,300, 901, 0, {ACT_TEST}},
//{RSP_ERROR, 901,901, -1, 0, 0, {ACT_FAILCID}},
//{RSP_OK, 901,901, -1, 301, 5, {0}, "^SGCI?\r"},
{ RSP_INIT , 0 , 0 , SEQ_CID , 301 , 5 , { 0 } , " ^SGCI? \r " } ,
{ RSP_OK , 301 , 301 , - 1 , 302 , - 1 } ,
{ RSP_ZGCI , 302 , 302 , - 1 , 0 , 0 , { ACT_CID } } ,
{ RSP_ERROR , 301 , 349 , - 1 , 0 , 0 , { ACT_FAILCID } } ,
{ EV_TIMEOUT , 301 , 349 , - 1 , 0 , 0 , { ACT_FAILCID } } ,
/* enter cid mode */
{ RSP_INIT , 0 , 0 , SEQ_CIDMODE , 150 , 5 , { 0 } , " ^SGCI=1 \r " } ,
{ RSP_OK , 150 , 150 , - 1 , 0 , 0 , { ACT_CMODESET } } ,
{ RSP_ERROR , 150 , 150 , - 1 , 0 , 0 , { ACT_FAILCMODE } } ,
{ EV_TIMEOUT , 150 , 150 , - 1 , 0 , 0 , { ACT_FAILCMODE } } ,
/* leave cid mode */
//{RSP_INIT, 0, 0,SEQ_UMMODE, 160, 5, {0}, "^SGCI=0\r"},
{ RSP_INIT , 0 , 0 , SEQ_UMMODE , 160 , 5 , { 0 } , " Z \r " } ,
{ RSP_OK , 160 , 160 , - 1 , 0 , 0 , { ACT_UMODESET } } ,
{ RSP_ERROR , 160 , 160 , - 1 , 0 , 0 , { ACT_FAILUMODE } } ,
{ EV_TIMEOUT , 160 , 160 , - 1 , 0 , 0 , { ACT_FAILUMODE } } ,
/* abort getting cid */
{ RSP_INIT , 0 , 0 , SEQ_NOCID , 0 , 0 , { ACT_ABORTCID } } ,
/* reset */
#if 0
{ RSP_INIT , 0 , 0 , SEQ_SHUTDOWN , 503 , 5 , { 0 } , " ^SGCI=0 \r " } ,
{ RSP_OK , 503 , 503 , - 1 , 504 , 5 , { 0 } , " Z \r " } ,
# endif
{ RSP_INIT , 0 , 0 , SEQ_SHUTDOWN , 504 , 5 , { 0 } , " Z \r " } ,
{ RSP_OK , 504 , 504 , - 1 , 0 , 0 , { ACT_SDOWN } } ,
{ RSP_ERROR , 501 , 599 , - 1 , 0 , 0 , { ACT_FAILSDOWN } } ,
{ EV_TIMEOUT , 501 , 599 , - 1 , 0 , 0 , { ACT_FAILSDOWN } } ,
{ RSP_NODEV , 501 , 599 , - 1 , 0 , 0 , { ACT_FAKESDOWN } } ,
{ EV_PROC_CIDMODE , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_PROC_CIDMODE } } , //FIXME
{ EV_IF_LOCK , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_IF_LOCK } } , //FIXME
{ EV_IF_VER , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_IF_VER } } , //FIXME
{ EV_START , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_START } } , //FIXME
{ EV_STOP , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_STOP } } , //FIXME
{ EV_SHUTDOWN , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_SHUTDOWN } } , //FIXME
/* misc. */
{ RSP_EMPTY , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_DEBUG } } , //FIXME
{ RSP_ZCFGT , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_DEBUG } } , //FIXME
{ RSP_ZCFG , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_DEBUG } } , //FIXME
{ RSP_ZLOG , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_DEBUG } } , //FIXME
{ RSP_ZMWI , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_DEBUG } } , //FIXME
{ RSP_ZABINFO , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_DEBUG } } , //FIXME
{ RSP_ZSMLSTCHG , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_DEBUG } } , //FIXME
{ RSP_ZCAU , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_ZCAU } } ,
{ RSP_NONE , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_DEBUG } } ,
{ RSP_ANY , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_WARN } } ,
{ RSP_LAST }
} ;
// 600: start dialing, 650: dial in progress, 800: connection is up, 700: ring, 400: hup, 750: accepted icall
struct reply_t gigaset_tab_cid_m10x [ ] = /* for M10x */
{
/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */
/* dial */
{ EV_DIAL , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_DIAL } } , //FIXME
{ RSP_INIT , 0 , 0 , SEQ_DIAL , 601 , 5 , { ACT_CMD + AT_BC } } ,
{ RSP_OK , 601 , 601 , - 1 , 602 , 5 , { ACT_CMD + AT_HLC } } ,
{ RSP_NULL , 602 , 602 , - 1 , 603 , 5 , { ACT_CMD + AT_PROTO } } ,
{ RSP_OK , 602 , 602 , - 1 , 603 , 5 , { ACT_CMD + AT_PROTO } } ,
{ RSP_OK , 603 , 603 , - 1 , 604 , 5 , { ACT_CMD + AT_TYPE } } ,
{ RSP_OK , 604 , 604 , - 1 , 605 , 5 , { ACT_CMD + AT_MSN } } ,
{ RSP_OK , 605 , 605 , - 1 , 606 , 5 , { ACT_CMD + AT_ISO } } ,
{ RSP_NULL , 605 , 605 , - 1 , 606 , 5 , { ACT_CMD + AT_ISO } } ,
{ RSP_OK , 606 , 606 , - 1 , 607 , 5 , { 0 } , " +VLS=17 \r " } , /* set "Endgeraetemodus" */
{ RSP_OK , 607 , 607 , - 1 , 608 , - 1 } ,
//{RSP_ZSAU, 608,608,ZSAU_PROCEEDING, 608, 0, {ACT_ERROR}},//DELETE
{ RSP_ZSAU , 608 , 608 , ZSAU_PROCEEDING , 609 , 5 , { ACT_CMD + AT_DIAL } } ,
{ RSP_OK , 609 , 609 , - 1 , 650 , 0 , { ACT_DIALING } } ,
{ RSP_ZVLS , 608 , 608 , 17 , - 1 , - 1 , { ACT_DEBUG } } ,
{ RSP_ZCTP , 609 , 609 , - 1 , - 1 , - 1 , { ACT_DEBUG } } ,
{ RSP_ZCPN , 609 , 609 , - 1 , - 1 , - 1 , { ACT_DEBUG } } ,
{ RSP_ERROR , 601 , 609 , - 1 , 0 , 0 , { ACT_ABORTDIAL } } ,
{ EV_TIMEOUT , 601 , 609 , - 1 , 0 , 0 , { ACT_ABORTDIAL } } ,
/* dialing */
{ RSP_ZCTP , 650 , 650 , - 1 , - 1 , - 1 , { ACT_DEBUG } } ,
{ RSP_ZCPN , 650 , 650 , - 1 , - 1 , - 1 , { ACT_DEBUG } } ,
{ RSP_ZSAU , 650 , 650 , ZSAU_CALL_DELIVERED , - 1 , - 1 , { ACT_DEBUG } } , /* some devices don't send this */
/* connection established */
{ RSP_ZSAU , 650 , 650 , ZSAU_ACTIVE , 800 , - 1 , { ACT_CONNECT } } , //FIXME -> DLE1
{ RSP_ZSAU , 750 , 750 , ZSAU_ACTIVE , 800 , - 1 , { ACT_CONNECT } } , //FIXME -> DLE1
{ EV_BC_OPEN , 800 , 800 , - 1 , 800 , - 1 , { ACT_NOTIFY_BC_UP } } , //FIXME new constate + timeout
/* remote hangup */
{ RSP_ZSAU , 650 , 650 , ZSAU_DISCONNECT_IND , 0 , 0 , { ACT_REMOTEREJECT } } ,
{ RSP_ZSAU , 750 , 750 , ZSAU_DISCONNECT_IND , 0 , 0 , { ACT_REMOTEHUP } } ,
{ RSP_ZSAU , 800 , 800 , ZSAU_DISCONNECT_IND , 0 , 0 , { ACT_REMOTEHUP } } ,
/* hangup */
{ EV_HUP , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_HUP } } , //FIXME
{ RSP_INIT , - 1 , - 1 , SEQ_HUP , 401 , 5 , { 0 } , " +VLS=0 \r " } , /* hang up */ //-1,-1?
{ RSP_OK , 401 , 401 , - 1 , 402 , 5 } ,
{ RSP_ZVLS , 402 , 402 , 0 , 403 , 5 } ,
{ RSP_ZSAU , 403 , 403 , ZSAU_DISCONNECT_REQ , - 1 , - 1 , { ACT_DEBUG } } , /* if not remote hup */
//{RSP_ZSAU, 403,403,ZSAU_NULL, 401, 0, {ACT_ERROR}}, //DELETE//FIXME -> DLE0 // should we do this _before_ hanging up for base driver?
{ RSP_ZSAU , 403 , 403 , ZSAU_NULL , 0 , 0 , { ACT_DISCONNECT } } , //FIXME -> DLE0 // should we do this _before_ hanging up for base driver?
{ RSP_NODEV , 401 , 403 , - 1 , 0 , 0 , { ACT_FAKEHUP } } , //FIXME -> DLE0 // should we do this _before_ hanging up for base driver?
{ RSP_ERROR , 401 , 401 , - 1 , 0 , 0 , { ACT_ABORTHUP } } ,
{ EV_TIMEOUT , 401 , 403 , - 1 , 0 , 0 , { ACT_ABORTHUP } } ,
{ EV_BC_CLOSED , 0 , 0 , - 1 , 0 , - 1 , { ACT_NOTIFY_BC_DOWN } } , //FIXME new constate + timeout
/* ring */
{ RSP_ZBC , 700 , 700 , - 1 , - 1 , - 1 , { 0 } } ,
{ RSP_ZHLC , 700 , 700 , - 1 , - 1 , - 1 , { 0 } } ,
{ RSP_NMBR , 700 , 700 , - 1 , - 1 , - 1 , { 0 } } ,
{ RSP_ZCPN , 700 , 700 , - 1 , - 1 , - 1 , { 0 } } ,
{ RSP_ZCTP , 700 , 700 , - 1 , - 1 , - 1 , { 0 } } ,
{ EV_TIMEOUT , 700 , 700 , - 1 , 720 , 720 , { ACT_ICALL } } ,
{ EV_BC_CLOSED , 720 , 720 , - 1 , 0 , - 1 , { ACT_NOTIFY_BC_DOWN } } ,
/*accept icall*/
{ EV_ACCEPT , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_ACCEPT } } , //FIXME
{ RSP_INIT , 720 , 720 , SEQ_ACCEPT , 721 , 5 , { ACT_CMD + AT_PROTO } } ,
{ RSP_OK , 721 , 721 , - 1 , 722 , 5 , { ACT_CMD + AT_ISO } } ,
{ RSP_OK , 722 , 722 , - 1 , 723 , 5 , { 0 } , " +VLS=17 \r " } , /* set "Endgeraetemodus" */
{ RSP_OK , 723 , 723 , - 1 , 724 , 5 , { 0 } } ,
{ RSP_ZVLS , 724 , 724 , 17 , 750 , 50 , { ACT_ACCEPTED } } ,
{ RSP_ERROR , 721 , 729 , - 1 , 0 , 0 , { ACT_ABORTACCEPT } } ,
{ EV_TIMEOUT , 721 , 729 , - 1 , 0 , 0 , { ACT_ABORTACCEPT } } ,
{ RSP_ZSAU , 700 , 729 , ZSAU_NULL , 0 , 0 , { ACT_ABORTACCEPT } } ,
{ RSP_ZSAU , 700 , 729 , ZSAU_ACTIVE , 0 , 0 , { ACT_ABORTACCEPT } } ,
{ RSP_ZSAU , 700 , 729 , ZSAU_DISCONNECT_IND , 0 , 0 , { ACT_ABORTACCEPT } } ,
{ EV_TIMEOUT , 750 , 750 , - 1 , 0 , 0 , { ACT_CONNTIMEOUT } } ,
2006-04-22 13:35:30 +04:00
/* B channel closed (general case) */
{ EV_BC_CLOSED , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_NOTIFY_BC_DOWN } } , //FIXME
2006-03-26 13:38:30 +04:00
/* misc. */
{ EV_PROTO_L2 , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_PROTO_L2 } } , //FIXME
{ RSP_ZCON , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_DEBUG } } , //FIXME
{ RSP_ZCCR , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_DEBUG } } , //FIXME
{ RSP_ZAOC , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_DEBUG } } , //FIXME
{ RSP_ZCSTR , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_DEBUG } } , //FIXME
{ RSP_ZCAU , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_ZCAU } } ,
{ RSP_NONE , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_DEBUG } } ,
{ RSP_ANY , - 1 , - 1 , - 1 , - 1 , - 1 , { ACT_WARN } } ,
{ RSP_LAST }
} ;
#if 0
2006-04-11 09:55:00 +04:00
static struct reply_t tab_nocid [ ] = /* no dle mode */ //FIXME
2006-03-26 13:38:30 +04:00
{
/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */
{ RSP_ANY , - 1 , - 1 , - 1 , - 1 , - 1 , ACT_WARN , NULL } ,
{ RSP_LAST , 0 , 0 , 0 , 0 , 0 , 0 }
} ;
2006-04-11 09:55:00 +04:00
static struct reply_t tab_cid [ ] = /* no dle mode */ //FIXME
2006-03-26 13:38:30 +04:00
{
/* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */
{ RSP_ANY , - 1 , - 1 , - 1 , - 1 , - 1 , ACT_WARN , NULL } ,
{ RSP_LAST , 0 , 0 , 0 , 0 , 0 , 0 }
} ;
# endif
2007-03-29 12:20:34 +04:00
static const struct resp_type_t resp_type [ ] =
2006-03-26 13:38:30 +04:00
{
2006-04-11 09:55:00 +04:00
/*{"", RSP_EMPTY, RT_NOTHING},*/
{ " OK " , RSP_OK , RT_NOTHING } ,
{ " ERROR " , RSP_ERROR , RT_NOTHING } ,
{ " ZSAU " , RSP_ZSAU , RT_ZSAU } ,
{ " ZCAU " , RSP_ZCAU , RT_ZCAU } ,
{ " RING " , RSP_RING , RT_RING } ,
{ " ZGCI " , RSP_ZGCI , RT_NUMBER } ,
{ " ZVLS " , RSP_ZVLS , RT_NUMBER } ,
{ " ZCTP " , RSP_ZCTP , RT_NUMBER } ,
{ " ZDLE " , RSP_ZDLE , RT_NUMBER } ,
{ " ZCFGT " , RSP_ZCFGT , RT_NUMBER } ,
{ " ZCCR " , RSP_ZCCR , RT_NUMBER } ,
{ " ZMWI " , RSP_ZMWI , RT_NUMBER } ,
{ " ZHLC " , RSP_ZHLC , RT_STRING } ,
{ " ZBC " , RSP_ZBC , RT_STRING } ,
{ " NMBR " , RSP_NMBR , RT_STRING } ,
{ " ZCPN " , RSP_ZCPN , RT_STRING } ,
{ " ZCON " , RSP_ZCON , RT_STRING } ,
{ " ZAOC " , RSP_ZAOC , RT_STRING } ,
{ " ZCSTR " , RSP_ZCSTR , RT_STRING } ,
{ " ZCFG " , RSP_ZCFG , RT_HEX } ,
{ " ZLOG " , RSP_ZLOG , RT_NOTHING } ,
{ " ZABINFO " , RSP_ZABINFO , RT_NOTHING } ,
{ " ZSMLSTCHG " , RSP_ZSMLSTCHG , RT_NOTHING } ,
2006-03-26 13:38:30 +04:00
{ NULL , 0 , 0 }
} ;
/*
* Get integer from char - pointer
*/
static int isdn_getnum ( char * p )
{
int v = - 1 ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_TRANSCMD , " string: %s " , p ) ;
2006-03-26 13:38:30 +04:00
while ( * p > = ' 0 ' & & * p < = ' 9 ' )
v = ( ( v < 0 ) ? 0 : ( v * 10 ) ) + ( int ) ( ( * p + + ) - ' 0 ' ) ;
if ( * p )
v = - 1 ; /* invalid Character */
return v ;
}
/*
* Get integer from char - pointer
*/
static int isdn_gethex ( char * p )
{
int v = 0 ;
int c ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_TRANSCMD , " string: %s " , p ) ;
2006-03-26 13:38:30 +04:00
if ( ! * p )
return - 1 ;
do {
if ( v > ( INT_MAX - 15 ) / 16 )
return - 1 ;
c = * p ;
if ( c > = ' 0 ' & & c < = ' 9 ' )
c - = ' 0 ' ;
else if ( c > = ' a ' & & c < = ' f ' )
c - = ' a ' - 10 ;
else if ( c > = ' A ' & & c < = ' F ' )
c - = ' A ' - 10 ;
else
return - 1 ;
v = v * 16 + c ;
} while ( * + + p ) ;
return v ;
}
/* retrieve CID from parsed response
* returns 0 if no CID , - 1 if invalid CID , or CID value 1. .65535
*/
static int cid_of_response ( char * s )
{
int cid ;
if ( s [ - 1 ] ! = ' ; ' )
return 0 ; /* no CID separator */
cid = isdn_getnum ( s ) ;
if ( cid < 0 )
return 0 ; /* CID not numeric */
if ( cid < 1 | | cid > 65535 )
return - 1 ; /* CID out of range */
return cid ;
//FIXME is ;<digit>+ at end of non-CID response really impossible?
}
/* This function will be called via task queue from the callback handler.
* We received a modem response and have to handle it . .
*/
void gigaset_handle_modem_response ( struct cardstate * cs )
{
unsigned char * argv [ MAX_REC_PARAMS + 1 ] ;
int params ;
int i , j ;
2007-03-29 12:20:34 +04:00
const struct resp_type_t * rt ;
2006-03-26 13:38:30 +04:00
int curarg ;
unsigned long flags ;
unsigned next , tail , head ;
struct event_t * event ;
int resp_code ;
int param_type ;
int abort ;
size_t len ;
int cid ;
int rawstring ;
len = cs - > cbytes ;
if ( ! len ) {
/* ignore additional LFs/CRs (M10x config mode or cx100) */
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_MCMD , " skipped EOL [%02X] " , cs - > respdata [ len ] ) ;
2006-03-26 13:38:30 +04:00
return ;
}
cs - > respdata [ len ] = 0 ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_TRANSCMD , " raw string: '%s' " , cs - > respdata ) ;
2006-03-26 13:38:30 +04:00
argv [ 0 ] = cs - > respdata ;
params = 1 ;
if ( cs - > at_state . getstring ) {
/* getstring only allowed without cid at the moment */
cs - > at_state . getstring = 0 ;
rawstring = 1 ;
cid = 0 ;
} else {
/* parse line */
for ( i = 0 ; i < len ; i + + )
switch ( cs - > respdata [ i ] ) {
case ' ; ' :
case ' , ' :
case ' = ' :
if ( params > MAX_REC_PARAMS ) {
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev ,
" too many parameters in response \n " ) ;
2006-03-26 13:38:30 +04:00
/* need last parameter (might be CID) */
params - - ;
}
argv [ params + + ] = cs - > respdata + i + 1 ;
}
rawstring = 0 ;
cid = params > 1 ? cid_of_response ( argv [ params - 1 ] ) : 0 ;
if ( cid < 0 ) {
gigaset_add_event ( cs , & cs - > at_state , RSP_INVAL ,
2006-04-11 09:55:04 +04:00
NULL , 0 , NULL ) ;
2006-03-26 13:38:30 +04:00
return ;
}
for ( j = 1 ; j < params ; + + j )
argv [ j ] [ - 1 ] = 0 ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_TRANSCMD , " CMD received: %s " , argv [ 0 ] ) ;
2006-03-26 13:38:30 +04:00
if ( cid ) {
- - params ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_TRANSCMD , " CID: %s " , argv [ params ] ) ;
2006-03-26 13:38:30 +04:00
}
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_TRANSCMD , " available params: %d " , params - 1 ) ;
2006-03-26 13:38:30 +04:00
for ( j = 1 ; j < params ; j + + )
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_TRANSCMD , " param %d: %s " , j , argv [ j ] ) ;
2006-03-26 13:38:30 +04:00
}
spin_lock_irqsave ( & cs - > ev_lock , flags ) ;
2006-04-11 09:55:16 +04:00
head = cs - > ev_head ;
tail = cs - > ev_tail ;
2006-03-26 13:38:30 +04:00
abort = 1 ;
curarg = 0 ;
while ( curarg < params ) {
next = ( tail + 1 ) % MAX_EVENTS ;
if ( unlikely ( next = = head ) ) {
2006-04-11 09:55:04 +04:00
dev_err ( cs - > dev , " event queue full \n " ) ;
2006-03-26 13:38:30 +04:00
break ;
}
event = cs - > events + tail ;
event - > at_state = NULL ;
event - > cid = cid ;
event - > ptr = NULL ;
event - > arg = NULL ;
tail = next ;
if ( rawstring ) {
resp_code = RSP_STRING ;
param_type = RT_STRING ;
} else {
for ( rt = resp_type ; rt - > response ; + + rt )
if ( ! strcmp ( argv [ curarg ] , rt - > response ) )
break ;
if ( ! rt - > response ) {
event - > type = RSP_UNKNOWN ;
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev ,
" unknown modem response: %s \n " ,
argv [ curarg ] ) ;
2006-03-26 13:38:30 +04:00
break ;
}
resp_code = rt - > resp_code ;
param_type = rt - > type ;
+ + curarg ;
}
event - > type = resp_code ;
switch ( param_type ) {
case RT_NOTHING :
break ;
case RT_RING :
if ( ! cid ) {
2006-04-11 09:55:04 +04:00
dev_err ( cs - > dev ,
" received RING without CID! \n " ) ;
2006-03-26 13:38:30 +04:00
event - > type = RSP_INVAL ;
abort = 1 ;
} else {
event - > cid = 0 ;
event - > parameter = cid ;
abort = 0 ;
}
break ;
case RT_ZSAU :
if ( curarg > = params ) {
event - > parameter = ZSAU_NONE ;
break ;
}
if ( ! strcmp ( argv [ curarg ] , " OUTGOING_CALL_PROCEEDING " ) )
event - > parameter = ZSAU_OUTGOING_CALL_PROCEEDING ;
else if ( ! strcmp ( argv [ curarg ] , " CALL_DELIVERED " ) )
event - > parameter = ZSAU_CALL_DELIVERED ;
else if ( ! strcmp ( argv [ curarg ] , " ACTIVE " ) )
event - > parameter = ZSAU_ACTIVE ;
else if ( ! strcmp ( argv [ curarg ] , " DISCONNECT_IND " ) )
event - > parameter = ZSAU_DISCONNECT_IND ;
else if ( ! strcmp ( argv [ curarg ] , " NULL " ) )
event - > parameter = ZSAU_NULL ;
else if ( ! strcmp ( argv [ curarg ] , " DISCONNECT_REQ " ) )
event - > parameter = ZSAU_DISCONNECT_REQ ;
else {
event - > parameter = ZSAU_UNKNOWN ;
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev ,
" %s: unknown parameter %s after ZSAU \n " ,
__func__ , argv [ curarg ] ) ;
2006-03-26 13:38:30 +04:00
}
+ + curarg ;
break ;
case RT_STRING :
if ( curarg < params ) {
2006-04-11 09:55:04 +04:00
event - > ptr = kstrdup ( argv [ curarg ] , GFP_ATOMIC ) ;
if ( ! event - > ptr )
dev_err ( cs - > dev , " out of memory \n " ) ;
2006-03-26 13:38:30 +04:00
+ + curarg ;
}
# ifdef CONFIG_GIGASET_DEBUG
if ( ! event - > ptr )
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " string==NULL " ) ;
2006-03-26 13:38:30 +04:00
else
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " string==%s " ,
( char * ) event - > ptr ) ;
2006-03-26 13:38:30 +04:00
# endif
break ;
case RT_ZCAU :
event - > parameter = - 1 ;
if ( curarg + 1 < params ) {
i = isdn_gethex ( argv [ curarg ] ) ;
j = isdn_gethex ( argv [ curarg + 1 ] ) ;
if ( i > = 0 & & i < 256 & & j > = 0 & & j < 256 )
event - > parameter = ( unsigned ) i < < 8
2006-04-11 09:55:04 +04:00
| j ;
2006-03-26 13:38:30 +04:00
curarg + = 2 ;
} else
curarg = params - 1 ;
break ;
case RT_NUMBER :
case RT_HEX :
if ( curarg < params ) {
if ( param_type = = RT_HEX )
event - > parameter =
isdn_gethex ( argv [ curarg ] ) ;
else
event - > parameter =
isdn_getnum ( argv [ curarg ] ) ;
+ + curarg ;
} else
event - > parameter = - 1 ;
# ifdef CONFIG_GIGASET_DEBUG
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " parameter==%d " , event - > parameter ) ;
2006-03-26 13:38:30 +04:00
# endif
break ;
}
if ( resp_code = = RSP_ZDLE )
cs - > dle = event - > parameter ;
if ( abort )
break ;
}
2006-04-11 09:55:16 +04:00
cs - > ev_tail = tail ;
2006-03-26 13:38:30 +04:00
spin_unlock_irqrestore ( & cs - > ev_lock , flags ) ;
if ( curarg ! = params )
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY ,
" invalid number of processed parameters: %d/%d " ,
curarg , params ) ;
2006-03-26 13:38:30 +04:00
}
EXPORT_SYMBOL_GPL ( gigaset_handle_modem_response ) ;
/* disconnect
* process closing of connection associated with given AT state structure
*/
static void disconnect ( struct at_state_t * * at_state_p )
{
unsigned long flags ;
2006-04-11 09:55:08 +04:00
struct bc_state * bcs = ( * at_state_p ) - > bcs ;
struct cardstate * cs = ( * at_state_p ) - > cs ;
2006-03-26 13:38:30 +04:00
2006-04-11 09:55:16 +04:00
spin_lock_irqsave ( & cs - > lock , flags ) ;
+ + ( * at_state_p ) - > seq_index ;
2006-03-26 13:38:30 +04:00
/* revert to selected idle mode */
2006-04-11 09:55:16 +04:00
if ( ! cs - > cidmode ) {
2006-03-26 13:38:30 +04:00
cs - > at_state . pending_commands | = PC_UMMODE ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " Scheduling PC_UMMODE " ) ;
2006-03-26 13:38:30 +04:00
}
2006-04-11 09:55:16 +04:00
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
2006-03-26 13:38:30 +04:00
if ( bcs ) {
/* B channel assigned: invoke hardware specific handler */
cs - > ops - > close_bchannel ( bcs ) ;
} else {
/* no B channel assigned: just deallocate */
spin_lock_irqsave ( & cs - > lock , flags ) ;
list_del ( & ( * at_state_p ) - > list ) ;
kfree ( * at_state_p ) ;
* at_state_p = NULL ;
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
}
}
/* get_free_channel
* get a free AT state structure : either one of those associated with the
* B channels of the Gigaset device , or if none of those is available ,
* a newly allocated one with bcs = NULL
* The structure should be freed by calling disconnect ( ) after use .
*/
static inline struct at_state_t * get_free_channel ( struct cardstate * cs ,
2006-04-11 09:55:04 +04:00
int cid )
2006-03-26 13:38:30 +04:00
/* cids: >0: siemens-cid
0 : without cid
- 1 : no cid assigned yet
*/
{
unsigned long flags ;
int i ;
struct at_state_t * ret ;
for ( i = 0 ; i < cs - > channels ; + + i )
if ( gigaset_get_channel ( cs - > bcs + i ) ) {
ret = & cs - > bcs [ i ] . at_state ;
ret - > cid = cid ;
return ret ;
}
spin_lock_irqsave ( & cs - > lock , flags ) ;
ret = kmalloc ( sizeof ( struct at_state_t ) , GFP_ATOMIC ) ;
if ( ret ) {
gigaset_at_init ( ret , NULL , cs , cid ) ;
list_add ( & ret - > list , & cs - > temp_at_states ) ;
}
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
return ret ;
}
static void init_failed ( struct cardstate * cs , int mode )
{
int i ;
struct at_state_t * at_state ;
cs - > at_state . pending_commands & = ~ PC_INIT ;
2008-02-06 12:38:28 +03:00
cs - > mode = mode ;
cs - > mstate = MS_UNINITIALIZED ;
2006-03-26 13:38:30 +04:00
gigaset_free_channels ( cs ) ;
for ( i = 0 ; i < cs - > channels ; + + i ) {
at_state = & cs - > bcs [ i ] . at_state ;
if ( at_state - > pending_commands & PC_CID ) {
at_state - > pending_commands & = ~ PC_CID ;
at_state - > pending_commands | = PC_NOCID ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-03-26 13:38:30 +04:00
}
}
}
static void schedule_init ( struct cardstate * cs , int state )
{
if ( cs - > at_state . pending_commands & PC_INIT ) {
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " not scheduling PC_INIT again " ) ;
2006-03-26 13:38:30 +04:00
return ;
}
2008-02-06 12:38:28 +03:00
cs - > mstate = state ;
cs - > mode = M_UNKNOWN ;
2006-03-26 13:38:30 +04:00
gigaset_block_channels ( cs ) ;
cs - > at_state . pending_commands | = PC_INIT ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " Scheduling PC_INIT " ) ;
2006-03-26 13:38:30 +04:00
}
2006-04-11 09:55:00 +04:00
/* Add "AT" to a command, add the cid, dle encode it, send the result to the
hardware . */
2006-03-26 13:38:30 +04:00
static void send_command ( struct cardstate * cs , const char * cmd , int cid ,
2006-04-11 09:55:04 +04:00
int dle , gfp_t kmallocflags )
2006-03-26 13:38:30 +04:00
{
size_t cmdlen , buflen ;
char * cmdpos , * cmdbuf , * cmdtail ;
cmdlen = strlen ( cmd ) ;
buflen = 11 + cmdlen ;
2006-04-11 09:55:04 +04:00
if ( unlikely ( buflen < = cmdlen ) ) {
dev_err ( cs - > dev , " integer overflow in buflen \n " ) ;
return ;
}
2006-03-26 13:38:30 +04:00
2006-04-11 09:55:04 +04:00
cmdbuf = kmalloc ( buflen , kmallocflags ) ;
if ( unlikely ( ! cmdbuf ) ) {
dev_err ( cs - > dev , " out of memory \n " ) ;
return ;
}
2006-03-26 13:38:30 +04:00
2006-04-11 09:55:04 +04:00
cmdpos = cmdbuf + 9 ;
cmdtail = cmdpos + cmdlen ;
memcpy ( cmdpos , cmd , cmdlen ) ;
2006-03-26 13:38:30 +04:00
2006-04-11 09:55:04 +04:00
if ( cid > 0 & & cid < = 65535 ) {
do {
* - - cmdpos = ' 0 ' + cid % 10 ;
cid / = 10 ;
+ + cmdlen ;
} while ( cid ) ;
}
2006-03-26 13:38:30 +04:00
2006-04-11 09:55:04 +04:00
cmdlen + = 2 ;
* - - cmdpos = ' T ' ;
* - - cmdpos = ' A ' ;
if ( dle ) {
cmdlen + = 4 ;
* - - cmdpos = ' ( ' ;
* - - cmdpos = 0x10 ;
* cmdtail + + = 0x10 ;
* cmdtail + + = ' ) ' ;
}
cs - > ops - > write_cmd ( cs , cmdpos , cmdlen , NULL ) ;
kfree ( cmdbuf ) ;
2006-03-26 13:38:30 +04:00
}
static struct at_state_t * at_state_from_cid ( struct cardstate * cs , int cid )
{
struct at_state_t * at_state ;
int i ;
unsigned long flags ;
if ( cid = = 0 )
return & cs - > at_state ;
for ( i = 0 ; i < cs - > channels ; + + i )
if ( cid = = cs - > bcs [ i ] . at_state . cid )
return & cs - > bcs [ i ] . at_state ;
spin_lock_irqsave ( & cs - > lock , flags ) ;
list_for_each_entry ( at_state , & cs - > temp_at_states , list )
if ( cid = = at_state - > cid ) {
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
return at_state ;
}
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
return NULL ;
}
static void bchannel_down ( struct bc_state * bcs )
{
if ( bcs - > chstate & CHS_B_UP ) {
bcs - > chstate & = ~ CHS_B_UP ;
gigaset_i4l_channel_cmd ( bcs , ISDN_STAT_BHUP ) ;
}
if ( bcs - > chstate & ( CHS_D_UP | CHS_NOTIFY_LL ) ) {
bcs - > chstate & = ~ ( CHS_D_UP | CHS_NOTIFY_LL ) ;
gigaset_i4l_channel_cmd ( bcs , ISDN_STAT_DHUP ) ;
}
gigaset_free_channel ( bcs ) ;
gigaset_bcs_reinit ( bcs ) ;
}
static void bchannel_up ( struct bc_state * bcs )
{
if ( ! ( bcs - > chstate & CHS_D_UP ) ) {
2006-04-11 09:55:04 +04:00
dev_notice ( bcs - > cs - > dev , " %s: D channel not up \n " , __func__ ) ;
2006-03-26 13:38:30 +04:00
bcs - > chstate | = CHS_D_UP ;
gigaset_i4l_channel_cmd ( bcs , ISDN_STAT_DCONN ) ;
}
if ( bcs - > chstate & CHS_B_UP ) {
2006-04-11 09:55:04 +04:00
dev_notice ( bcs - > cs - > dev , " %s: B channel already up \n " ,
__func__ ) ;
2006-03-26 13:38:30 +04:00
return ;
}
bcs - > chstate | = CHS_B_UP ;
gigaset_i4l_channel_cmd ( bcs , ISDN_STAT_BCONN ) ;
}
2006-04-11 09:55:16 +04:00
static void start_dial ( struct at_state_t * at_state , void * data , unsigned seq_index )
2006-03-26 13:38:30 +04:00
{
struct bc_state * bcs = at_state - > bcs ;
struct cardstate * cs = at_state - > cs ;
int retval ;
2006-04-11 09:55:16 +04:00
unsigned long flags ;
2006-03-26 13:38:30 +04:00
bcs - > chstate | = CHS_NOTIFY_LL ;
2006-04-11 09:55:16 +04:00
spin_lock_irqsave ( & cs - > lock , flags ) ;
if ( at_state - > seq_index ! = seq_index ) {
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
2006-03-26 13:38:30 +04:00
goto error ;
2006-04-11 09:55:16 +04:00
}
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
2006-03-26 13:38:30 +04:00
retval = gigaset_isdn_setup_dial ( at_state , data ) ;
if ( retval ! = 0 )
goto error ;
at_state - > pending_commands | = PC_CID ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " Scheduling PC_CID " ) ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-03-26 13:38:30 +04:00
return ;
error :
at_state - > pending_commands | = PC_NOCID ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " Scheduling PC_NOCID " ) ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-03-26 13:38:30 +04:00
return ;
}
static void start_accept ( struct at_state_t * at_state )
{
struct cardstate * cs = at_state - > cs ;
int retval ;
retval = gigaset_isdn_setup_accept ( at_state ) ;
if ( retval = = 0 ) {
at_state - > pending_commands | = PC_ACCEPT ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " Scheduling PC_ACCEPT " ) ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-03-26 13:38:30 +04:00
} else {
2008-02-06 12:38:28 +03:00
/* error reset */
2006-03-26 13:38:30 +04:00
at_state - > pending_commands | = PC_HUP ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " Scheduling PC_HUP " ) ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-03-26 13:38:30 +04:00
}
}
static void do_start ( struct cardstate * cs )
{
gigaset_free_channels ( cs ) ;
2008-02-06 12:38:28 +03:00
if ( cs - > mstate ! = MS_LOCKED )
2006-03-26 13:38:30 +04:00
schedule_init ( cs , MS_INIT ) ;
2006-04-11 09:55:16 +04:00
cs - > isdn_up = 1 ;
2006-03-26 13:38:30 +04:00
gigaset_i4l_cmd ( cs , ISDN_STAT_RUN ) ;
2006-04-11 09:55:04 +04:00
// FIXME: not in locked mode
// FIXME 2: only after init sequence
2006-03-26 13:38:30 +04:00
cs - > waiting = 0 ;
wake_up ( & cs - > waitqueue ) ;
}
static void finish_shutdown ( struct cardstate * cs )
{
2008-02-06 12:38:28 +03:00
if ( cs - > mstate ! = MS_LOCKED ) {
cs - > mstate = MS_UNINITIALIZED ;
cs - > mode = M_UNKNOWN ;
2006-03-26 13:38:30 +04:00
}
2006-04-11 09:55:16 +04:00
/* Tell the LL that the device is not available .. */
if ( cs - > isdn_up ) {
cs - > isdn_up = 0 ;
gigaset_i4l_cmd ( cs , ISDN_STAT_STOP ) ;
}
2006-03-26 13:38:30 +04:00
/* The rest is done by cleanup_cs () in user mode. */
cs - > cmd_result = - ENODEV ;
cs - > waiting = 0 ;
2007-02-12 11:52:34 +03:00
wake_up ( & cs - > waitqueue ) ;
2006-03-26 13:38:30 +04:00
}
static void do_shutdown ( struct cardstate * cs )
{
gigaset_block_channels ( cs ) ;
2008-02-06 12:38:28 +03:00
if ( cs - > mstate = = MS_READY ) {
cs - > mstate = MS_SHUTDOWN ;
2006-03-26 13:38:30 +04:00
cs - > at_state . pending_commands | = PC_SHUTDOWN ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " Scheduling PC_SHUTDOWN " ) ;
2006-03-26 13:38:30 +04:00
} else
finish_shutdown ( cs ) ;
}
static void do_stop ( struct cardstate * cs )
{
2006-04-11 09:55:16 +04:00
unsigned long flags ;
spin_lock_irqsave ( & cs - > lock , flags ) ;
cs - > connected = 0 ;
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
2006-03-26 13:38:30 +04:00
do_shutdown ( cs ) ;
}
/* Entering cid mode or getting a cid failed:
* try to initialize the device and try again .
*
* channel > = 0 : getting cid for the channel failed
* channel < 0 : entering cid mode failed
*
* returns 0 on failure
*/
static int reinit_and_retry ( struct cardstate * cs , int channel )
{
int i ;
if ( - - cs - > retry_count < = 0 )
return 0 ;
for ( i = 0 ; i < cs - > channels ; + + i )
if ( cs - > bcs [ i ] . at_state . cid > 0 )
return 0 ;
if ( channel < 0 )
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev ,
" Could not enter cid mode. Reinit device and try again. \n " ) ;
2006-03-26 13:38:30 +04:00
else {
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev ,
" Could not get a call id. Reinit device and try again. \n " ) ;
2006-03-26 13:38:30 +04:00
cs - > bcs [ channel ] . at_state . pending_commands | = PC_CID ;
}
schedule_init ( cs , MS_INIT ) ;
return 1 ;
}
static int at_state_invalid ( struct cardstate * cs ,
2006-04-11 09:55:04 +04:00
struct at_state_t * test_ptr )
2006-03-26 13:38:30 +04:00
{
unsigned long flags ;
unsigned channel ;
struct at_state_t * at_state ;
int retval = 0 ;
spin_lock_irqsave ( & cs - > lock , flags ) ;
if ( test_ptr = = & cs - > at_state )
goto exit ;
list_for_each_entry ( at_state , & cs - > temp_at_states , list )
if ( at_state = = test_ptr )
goto exit ;
for ( channel = 0 ; channel < cs - > channels ; + + channel )
if ( & cs - > bcs [ channel ] . at_state = = test_ptr )
goto exit ;
retval = 1 ;
exit :
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
return retval ;
}
static void handle_icall ( struct cardstate * cs , struct bc_state * bcs ,
struct at_state_t * * p_at_state )
{
int retval ;
struct at_state_t * at_state = * p_at_state ;
retval = gigaset_isdn_icall ( at_state ) ;
switch ( retval ) {
case ICALL_ACCEPT :
break ;
default :
2006-04-11 09:55:04 +04:00
dev_err ( cs - > dev , " internal error: disposition=%d \n " , retval ) ;
2006-03-26 13:38:30 +04:00
/* --v-- fall through --v-- */
case ICALL_IGNORE :
case ICALL_REJECT :
/* hang up actively
* Device doc says that would reject the call .
* In fact it doesn ' t .
*/
at_state - > pending_commands | = PC_HUP ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-03-26 13:38:30 +04:00
break ;
}
}
static int do_lock ( struct cardstate * cs )
{
int mode ;
int i ;
2008-02-06 12:38:28 +03:00
switch ( cs - > mstate ) {
2006-03-26 13:38:30 +04:00
case MS_UNINITIALIZED :
case MS_READY :
if ( cs - > cur_at_seq | | ! list_empty ( & cs - > temp_at_states ) | |
cs - > at_state . pending_commands )
return - EBUSY ;
for ( i = 0 ; i < cs - > channels ; + + i )
if ( cs - > bcs [ i ] . at_state . pending_commands )
return - EBUSY ;
if ( ! gigaset_get_channels ( cs ) )
return - EBUSY ;
break ;
case MS_LOCKED :
//retval = -EACCES;
break ;
default :
return - EBUSY ;
}
2008-02-06 12:38:28 +03:00
mode = cs - > mode ;
cs - > mstate = MS_LOCKED ;
cs - > mode = M_UNKNOWN ;
2006-03-26 13:38:30 +04:00
return mode ;
}
static int do_unlock ( struct cardstate * cs )
{
2008-02-06 12:38:28 +03:00
if ( cs - > mstate ! = MS_LOCKED )
2006-03-26 13:38:30 +04:00
return - EINVAL ;
2008-02-06 12:38:28 +03:00
cs - > mstate = MS_UNINITIALIZED ;
cs - > mode = M_UNKNOWN ;
2006-03-26 13:38:30 +04:00
gigaset_free_channels ( cs ) ;
2006-04-11 09:55:16 +04:00
if ( cs - > connected )
2006-03-26 13:38:30 +04:00
schedule_init ( cs , MS_INIT ) ;
return 0 ;
}
static void do_action ( int action , struct cardstate * cs ,
struct bc_state * bcs ,
struct at_state_t * * p_at_state , char * * pp_command ,
int * p_genresp , int * p_resp_code ,
struct event_t * ev )
{
struct at_state_t * at_state = * p_at_state ;
struct at_state_t * at_state2 ;
unsigned long flags ;
int channel ;
unsigned char * s , * e ;
int i ;
unsigned long val ;
switch ( action ) {
case ACT_NOTHING :
break ;
case ACT_TIMEOUT :
at_state - > waiting = 1 ;
break ;
case ACT_INIT :
cs - > at_state . pending_commands & = ~ PC_INIT ;
cs - > cur_at_seq = SEQ_NONE ;
2008-02-06 12:38:28 +03:00
cs - > mode = M_UNIMODEM ;
2006-04-11 09:55:16 +04:00
spin_lock_irqsave ( & cs - > lock , flags ) ;
if ( ! cs - > cidmode ) {
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
2006-03-26 13:38:30 +04:00
gigaset_free_channels ( cs ) ;
2008-02-06 12:38:28 +03:00
cs - > mstate = MS_READY ;
2006-03-26 13:38:30 +04:00
break ;
}
2006-04-11 09:55:16 +04:00
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
2006-03-26 13:38:30 +04:00
cs - > at_state . pending_commands | = PC_CIDMODE ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " Scheduling PC_CIDMODE " ) ;
2006-03-26 13:38:30 +04:00
break ;
case ACT_FAILINIT :
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev , " Could not initialize the device. \n " ) ;
2006-03-26 13:38:30 +04:00
cs - > dle = 0 ;
init_failed ( cs , M_UNKNOWN ) ;
cs - > cur_at_seq = SEQ_NONE ;
break ;
case ACT_CONFIGMODE :
init_failed ( cs , M_CONFIG ) ;
cs - > cur_at_seq = SEQ_NONE ;
break ;
case ACT_SETDLE1 :
cs - > dle = 1 ;
/* cs->inbuf[0].inputstate |= INS_command | INS_DLE_command; */
cs - > inbuf [ 0 ] . inputstate & =
~ ( INS_command | INS_DLE_command ) ;
break ;
case ACT_SETDLE0 :
cs - > dle = 0 ;
cs - > inbuf [ 0 ] . inputstate =
( cs - > inbuf [ 0 ] . inputstate & ~ INS_DLE_command )
| INS_command ;
break ;
case ACT_CMODESET :
2008-02-06 12:38:28 +03:00
if ( cs - > mstate = = MS_INIT | | cs - > mstate = = MS_RECOVER ) {
2006-03-26 13:38:30 +04:00
gigaset_free_channels ( cs ) ;
2008-02-06 12:38:28 +03:00
cs - > mstate = MS_READY ;
2006-03-26 13:38:30 +04:00
}
2008-02-06 12:38:28 +03:00
cs - > mode = M_CID ;
2006-03-26 13:38:30 +04:00
cs - > cur_at_seq = SEQ_NONE ;
break ;
case ACT_UMODESET :
2008-02-06 12:38:28 +03:00
cs - > mode = M_UNIMODEM ;
2006-03-26 13:38:30 +04:00
cs - > cur_at_seq = SEQ_NONE ;
break ;
case ACT_FAILCMODE :
cs - > cur_at_seq = SEQ_NONE ;
2008-02-06 12:38:28 +03:00
if ( cs - > mstate = = MS_INIT | | cs - > mstate = = MS_RECOVER ) {
2006-03-26 13:38:30 +04:00
init_failed ( cs , M_UNKNOWN ) ;
break ;
}
if ( ! reinit_and_retry ( cs , - 1 ) )
schedule_init ( cs , MS_RECOVER ) ;
break ;
case ACT_FAILUMODE :
cs - > cur_at_seq = SEQ_NONE ;
schedule_init ( cs , MS_RECOVER ) ;
break ;
case ACT_HUPMODEM :
/* send "+++" (hangup in unimodem mode) */
2006-06-26 11:25:34 +04:00
if ( cs - > connected )
cs - > ops - > write_cmd ( cs , " +++ " , 3 , NULL ) ;
2006-03-26 13:38:30 +04:00
break ;
case ACT_RING :
/* get fresh AT state structure for new CID */
at_state2 = get_free_channel ( cs , ev - > parameter ) ;
if ( ! at_state2 ) {
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev ,
" RING ignored: could not allocate channel structure \n " ) ;
2006-03-26 13:38:30 +04:00
break ;
}
/* initialize AT state structure
* note that bcs may be NULL if no B channel is free
*/
at_state2 - > ConState = 700 ;
kfree ( at_state2 - > str_var [ STR_NMBR ] ) ;
at_state2 - > str_var [ STR_NMBR ] = NULL ;
kfree ( at_state2 - > str_var [ STR_ZCPN ] ) ;
at_state2 - > str_var [ STR_ZCPN ] = NULL ;
kfree ( at_state2 - > str_var [ STR_ZBC ] ) ;
at_state2 - > str_var [ STR_ZBC ] = NULL ;
kfree ( at_state2 - > str_var [ STR_ZHLC ] ) ;
at_state2 - > str_var [ STR_ZHLC ] = NULL ;
at_state2 - > int_var [ VAR_ZCTP ] = - 1 ;
spin_lock_irqsave ( & cs - > lock , flags ) ;
at_state2 - > timer_expires = RING_TIMEOUT ;
at_state2 - > timer_active = 1 ;
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
break ;
case ACT_ICALL :
handle_icall ( cs , bcs , p_at_state ) ;
break ;
case ACT_FAILSDOWN :
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev , " Could not shut down the device. \n " ) ;
2006-03-26 13:38:30 +04:00
/* fall through */
case ACT_FAKESDOWN :
case ACT_SDOWN :
cs - > cur_at_seq = SEQ_NONE ;
finish_shutdown ( cs ) ;
break ;
case ACT_CONNECT :
if ( cs - > onechannel ) {
at_state - > pending_commands | = PC_DLE1 ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-03-26 13:38:30 +04:00
break ;
}
bcs - > chstate | = CHS_D_UP ;
gigaset_i4l_channel_cmd ( bcs , ISDN_STAT_DCONN ) ;
cs - > ops - > init_bchannel ( bcs ) ;
break ;
case ACT_DLE1 :
cs - > cur_at_seq = SEQ_NONE ;
bcs = cs - > bcs + cs - > curchannel ;
bcs - > chstate | = CHS_D_UP ;
gigaset_i4l_channel_cmd ( bcs , ISDN_STAT_DCONN ) ;
cs - > ops - > init_bchannel ( bcs ) ;
break ;
case ACT_FAKEHUP :
at_state - > int_var [ VAR_ZSAU ] = ZSAU_NULL ;
/* fall through */
case ACT_DISCONNECT :
cs - > cur_at_seq = SEQ_NONE ;
at_state - > cid = - 1 ;
if ( bcs & & cs - > onechannel & & cs - > dle ) {
/* Check for other open channels not needed:
* DLE only used for M10x with one B channel .
*/
at_state - > pending_commands | = PC_DLE0 ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-06-26 11:25:34 +04:00
} else
2006-03-26 13:38:30 +04:00
disconnect ( p_at_state ) ;
break ;
case ACT_FAKEDLE0 :
at_state - > int_var [ VAR_ZDLE ] = 0 ;
cs - > dle = 0 ;
/* fall through */
case ACT_DLE0 :
cs - > cur_at_seq = SEQ_NONE ;
at_state2 = & cs - > bcs [ cs - > curchannel ] . at_state ;
disconnect ( & at_state2 ) ;
break ;
case ACT_ABORTHUP :
cs - > cur_at_seq = SEQ_NONE ;
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev , " Could not hang up. \n " ) ;
2006-03-26 13:38:30 +04:00
at_state - > cid = - 1 ;
if ( bcs & & cs - > onechannel )
at_state - > pending_commands | = PC_DLE0 ;
2006-06-26 11:25:34 +04:00
else
2006-03-26 13:38:30 +04:00
disconnect ( p_at_state ) ;
schedule_init ( cs , MS_RECOVER ) ;
break ;
case ACT_FAILDLE0 :
cs - > cur_at_seq = SEQ_NONE ;
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev , " Could not leave DLE mode. \n " ) ;
2006-03-26 13:38:30 +04:00
at_state2 = & cs - > bcs [ cs - > curchannel ] . at_state ;
disconnect ( & at_state2 ) ;
schedule_init ( cs , MS_RECOVER ) ;
break ;
case ACT_FAILDLE1 :
cs - > cur_at_seq = SEQ_NONE ;
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev ,
" Could not enter DLE mode. Trying to hang up. \n " ) ;
2006-03-26 13:38:30 +04:00
channel = cs - > curchannel ;
cs - > bcs [ channel ] . at_state . pending_commands | = PC_HUP ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-03-26 13:38:30 +04:00
break ;
case ACT_CID : /* got cid; start dialing */
cs - > cur_at_seq = SEQ_NONE ;
channel = cs - > curchannel ;
if ( ev - > parameter > 0 & & ev - > parameter < = 65535 ) {
cs - > bcs [ channel ] . at_state . cid = ev - > parameter ;
cs - > bcs [ channel ] . at_state . pending_commands | =
PC_DIAL ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-03-26 13:38:30 +04:00
break ;
}
/* fall through */
case ACT_FAILCID :
cs - > cur_at_seq = SEQ_NONE ;
channel = cs - > curchannel ;
if ( ! reinit_and_retry ( cs , channel ) ) {
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev ,
" Could not get a call ID. Cannot dial. \n " ) ;
2006-03-26 13:38:30 +04:00
at_state2 = & cs - > bcs [ channel ] . at_state ;
disconnect ( & at_state2 ) ;
}
break ;
case ACT_ABORTCID :
cs - > cur_at_seq = SEQ_NONE ;
at_state2 = & cs - > bcs [ cs - > curchannel ] . at_state ;
disconnect ( & at_state2 ) ;
break ;
case ACT_DIALING :
case ACT_ACCEPTED :
cs - > cur_at_seq = SEQ_NONE ;
break ;
case ACT_ABORTACCEPT : /* hangup/error/timeout during ICALL processing */
disconnect ( p_at_state ) ;
break ;
case ACT_ABORTDIAL : /* error/timeout during dial preparation */
cs - > cur_at_seq = SEQ_NONE ;
at_state - > pending_commands | = PC_HUP ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-03-26 13:38:30 +04:00
break ;
case ACT_REMOTEREJECT : /* DISCONNECT_IND after dialling */
case ACT_CONNTIMEOUT : /* timeout waiting for ZSAU=ACTIVE */
case ACT_REMOTEHUP : /* DISCONNECT_IND with established connection */
at_state - > pending_commands | = PC_HUP ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-03-26 13:38:30 +04:00
break ;
2006-04-11 09:55:00 +04:00
case ACT_GETSTRING : /* warning: RING, ZDLE, ...
2006-04-11 09:55:04 +04:00
are not handled properly anymore */
2006-03-26 13:38:30 +04:00
at_state - > getstring = 1 ;
break ;
case ACT_SETVER :
if ( ! ev - > ptr ) {
* p_genresp = 1 ;
* p_resp_code = RSP_ERROR ;
break ;
}
s = ev - > ptr ;
if ( ! strcmp ( s , " OK " ) ) {
* p_genresp = 1 ;
* p_resp_code = RSP_ERROR ;
break ;
}
for ( i = 0 ; i < 4 ; + + i ) {
val = simple_strtoul ( s , ( char * * ) & e , 10 ) ;
if ( val > INT_MAX | | e = = s )
break ;
if ( i = = 3 ) {
if ( * e )
break ;
} else if ( * e ! = ' . ' )
break ;
else
s = e + 1 ;
cs - > fwver [ i ] = val ;
}
if ( i ! = 4 ) {
* p_genresp = 1 ;
* p_resp_code = RSP_ERROR ;
break ;
}
/*at_state->getstring = 1;*/
cs - > gotfwver = 0 ;
break ;
case ACT_GOTVER :
if ( cs - > gotfwver = = 0 ) {
cs - > gotfwver = 1 ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY ,
" firmware version %02d.%03d.%02d.%02d " ,
cs - > fwver [ 0 ] , cs - > fwver [ 1 ] ,
cs - > fwver [ 2 ] , cs - > fwver [ 3 ] ) ;
2006-03-26 13:38:30 +04:00
break ;
}
/* fall through */
case ACT_FAILVER :
cs - > gotfwver = - 1 ;
2006-04-11 09:55:04 +04:00
dev_err ( cs - > dev , " could not read firmware version. \n " ) ;
2006-03-26 13:38:30 +04:00
break ;
# ifdef CONFIG_GIGASET_DEBUG
case ACT_ERROR :
* p_genresp = 1 ;
* p_resp_code = RSP_ERROR ;
break ;
case ACT_TEST :
{
static int count = 3 ; //2; //1;
* p_genresp = 1 ;
* p_resp_code = count ? RSP_ERROR : RSP_OK ;
if ( count > 0 )
- - count ;
}
break ;
# endif
case ACT_DEBUG :
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " %s: resp_code %d in ConState %d " ,
2006-03-26 13:38:30 +04:00
__func__ , ev - > type , at_state - > ConState ) ;
break ;
case ACT_WARN :
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev , " %s: resp_code %d in ConState %d! \n " ,
__func__ , ev - > type , at_state - > ConState ) ;
2006-03-26 13:38:30 +04:00
break ;
case ACT_ZCAU :
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev , " cause code %04x in connection state %d. \n " ,
ev - > parameter , at_state - > ConState ) ;
2006-03-26 13:38:30 +04:00
break ;
/* events from the LL */
case ACT_DIAL :
start_dial ( at_state , ev - > ptr , ev - > parameter ) ;
break ;
case ACT_ACCEPT :
start_accept ( at_state ) ;
break ;
case ACT_PROTO_L2 :
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " set protocol to %u " ,
( unsigned ) ev - > parameter ) ;
2006-03-26 13:38:30 +04:00
at_state - > bcs - > proto2 = ev - > parameter ;
break ;
case ACT_HUP :
at_state - > pending_commands | = PC_HUP ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " Scheduling PC_HUP " ) ;
2006-03-26 13:38:30 +04:00
break ;
/* hotplug events */
case ACT_STOP :
do_stop ( cs ) ;
break ;
case ACT_START :
do_start ( cs ) ;
break ;
/* events from the interface */ // FIXME without ACT_xxxx?
case ACT_IF_LOCK :
cs - > cmd_result = ev - > parameter ? do_lock ( cs ) : do_unlock ( cs ) ;
cs - > waiting = 0 ;
wake_up ( & cs - > waitqueue ) ;
break ;
case ACT_IF_VER :
if ( ev - > parameter ! = 0 )
cs - > cmd_result = - EINVAL ;
else if ( cs - > gotfwver ! = 1 ) {
cs - > cmd_result = - ENOENT ;
} else {
memcpy ( ev - > arg , cs - > fwver , sizeof cs - > fwver ) ;
cs - > cmd_result = 0 ;
}
cs - > waiting = 0 ;
wake_up ( & cs - > waitqueue ) ;
break ;
/* events from the proc file system */ // FIXME without ACT_xxxx?
case ACT_PROC_CIDMODE :
2006-04-11 09:55:16 +04:00
spin_lock_irqsave ( & cs - > lock , flags ) ;
if ( ev - > parameter ! = cs - > cidmode ) {
cs - > cidmode = ev - > parameter ;
2006-03-26 13:38:30 +04:00
if ( ev - > parameter ) {
cs - > at_state . pending_commands | = PC_CIDMODE ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " Scheduling PC_CIDMODE " ) ;
2006-03-26 13:38:30 +04:00
} else {
cs - > at_state . pending_commands | = PC_UMMODE ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " Scheduling PC_UMMODE " ) ;
2006-03-26 13:38:30 +04:00
}
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-03-26 13:38:30 +04:00
}
2006-04-11 09:55:16 +04:00
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
2006-03-26 13:38:30 +04:00
cs - > waiting = 0 ;
wake_up ( & cs - > waitqueue ) ;
break ;
/* events from the hardware drivers */
case ACT_NOTIFY_BC_DOWN :
bchannel_down ( bcs ) ;
break ;
case ACT_NOTIFY_BC_UP :
bchannel_up ( bcs ) ;
break ;
case ACT_SHUTDOWN :
do_shutdown ( cs ) ;
break ;
default :
if ( action > = ACT_CMD & & action < ACT_CMD + AT_NUM ) {
* pp_command = at_state - > bcs - > commands [ action - ACT_CMD ] ;
if ( ! * pp_command ) {
* p_genresp = 1 ;
* p_resp_code = RSP_NULL ;
}
} else
2006-04-11 09:55:04 +04:00
dev_err ( cs - > dev , " %s: action==%d! \n " , __func__ , action ) ;
2006-03-26 13:38:30 +04:00
}
}
/* State machine to do the calling and hangup procedure */
static void process_event ( struct cardstate * cs , struct event_t * ev )
{
struct bc_state * bcs ;
char * p_command = NULL ;
struct reply_t * rep ;
int rcode ;
int genresp = 0 ;
int resp_code = RSP_ERROR ;
int sendcid ;
struct at_state_t * at_state ;
int index ;
int curact ;
unsigned long flags ;
if ( ev - > cid > = 0 ) {
at_state = at_state_from_cid ( cs , ev - > cid ) ;
if ( ! at_state ) {
gigaset_add_event ( cs , & cs - > at_state , RSP_WRONG_CID ,
2006-04-11 09:55:04 +04:00
NULL , 0 , NULL ) ;
2006-03-26 13:38:30 +04:00
return ;
}
} else {
at_state = ev - > at_state ;
if ( at_state_invalid ( cs , at_state ) ) {
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " event for invalid at_state %p " ,
at_state ) ;
2006-03-26 13:38:30 +04:00
return ;
}
}
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " connection state %d, event %d " ,
at_state - > ConState , ev - > type ) ;
2006-03-26 13:38:30 +04:00
bcs = at_state - > bcs ;
sendcid = at_state - > cid ;
/* Setting the pointer to the dial array */
rep = at_state - > replystruct ;
2006-04-11 09:55:16 +04:00
spin_lock_irqsave ( & cs - > lock , flags ) ;
2006-03-26 13:38:30 +04:00
if ( ev - > type = = EV_TIMEOUT ) {
2006-04-11 09:55:16 +04:00
if ( ev - > parameter ! = at_state - > timer_index
2006-03-26 13:38:30 +04:00
| | ! at_state - > timer_active ) {
ev - > type = RSP_NONE ; /* old timeout */
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " old timeout " ) ;
2006-03-26 13:38:30 +04:00
} else if ( ! at_state - > waiting )
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " timeout occurred " ) ;
2006-03-26 13:38:30 +04:00
else
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_ANY , " stopped waiting " ) ;
2006-03-26 13:38:30 +04:00
}
2006-04-11 09:55:16 +04:00
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
2006-03-26 13:38:30 +04:00
2006-04-11 09:55:00 +04:00
/* if the response belongs to a variable in at_state->int_var[VAR_XXXX]
or at_state - > str_var [ STR_XXXX ] , set it */
2006-03-26 13:38:30 +04:00
if ( ev - > type > = RSP_VAR & & ev - > type < RSP_VAR + VAR_NUM ) {
index = ev - > type - RSP_VAR ;
at_state - > int_var [ index ] = ev - > parameter ;
} else if ( ev - > type > = RSP_STR & & ev - > type < RSP_STR + STR_NUM ) {
index = ev - > type - RSP_STR ;
kfree ( at_state - > str_var [ index ] ) ;
at_state - > str_var [ index ] = ev - > ptr ;
2006-04-11 09:55:00 +04:00
ev - > ptr = NULL ; /* prevent process_events() from
deallocating ptr */
2006-03-26 13:38:30 +04:00
}
if ( ev - > type = = EV_TIMEOUT | | ev - > type = = RSP_STRING )
at_state - > getstring = 0 ;
2006-04-11 09:55:00 +04:00
/* Search row in dial array which matches modem response and current
constate */
2006-03-26 13:38:30 +04:00
for ( ; ; rep + + ) {
rcode = rep - > resp_code ;
if ( rcode = = RSP_LAST ) {
/* found nothing...*/
2006-04-11 09:55:04 +04:00
dev_warn ( cs - > dev , " %s: rcode=RSP_LAST: "
" resp_code %d in ConState %d! \n " ,
__func__ , ev - > type , at_state - > ConState ) ;
2006-03-26 13:38:30 +04:00
return ;
}
if ( ( rcode = = RSP_ANY | | rcode = = ev - > type )
& & ( ( int ) at_state - > ConState > = rep - > min_ConState )
& & ( rep - > max_ConState < 0
| | ( int ) at_state - > ConState < = rep - > max_ConState )
& & ( rep - > parameter < 0 | | rep - > parameter = = ev - > parameter ) )
break ;
}
p_command = rep - > command ;
at_state - > waiting = 0 ;
for ( curact = 0 ; curact < MAXACT ; + + curact ) {
/* The row tells us what we should do ..
*/
do_action ( rep - > action [ curact ] , cs , bcs , & at_state , & p_command , & genresp , & resp_code , ev ) ;
if ( ! at_state )
break ; /* may be freed after disconnect */
}
if ( at_state ) {
/* Jump to the next con-state regarding the array */
if ( rep - > new_ConState > = 0 )
at_state - > ConState = rep - > new_ConState ;
if ( genresp ) {
spin_lock_irqsave ( & cs - > lock , flags ) ;
at_state - > timer_expires = 0 ; //FIXME
at_state - > timer_active = 0 ; //FIXME
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
gigaset_add_event ( cs , at_state , resp_code , NULL , 0 , NULL ) ;
} else {
/* Send command to modem if not NULL... */
if ( p_command /*rep->command*/ ) {
2006-04-11 09:55:16 +04:00
if ( cs - > connected )
2006-03-26 13:38:30 +04:00
send_command ( cs , p_command ,
2006-04-11 09:55:04 +04:00
sendcid , cs - > dle ,
GFP_ATOMIC ) ;
2006-03-26 13:38:30 +04:00
else
gigaset_add_event ( cs , at_state ,
2006-04-11 09:55:04 +04:00
RSP_NODEV ,
NULL , 0 , NULL ) ;
2006-03-26 13:38:30 +04:00
}
spin_lock_irqsave ( & cs - > lock , flags ) ;
if ( ! rep - > timeout ) {
at_state - > timer_expires = 0 ;
at_state - > timer_active = 0 ;
} else if ( rep - > timeout > 0 ) { /* new timeout */
at_state - > timer_expires = rep - > timeout * 10 ;
at_state - > timer_active = 1 ;
2006-04-11 09:55:16 +04:00
+ + at_state - > timer_index ;
2006-03-26 13:38:30 +04:00
}
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
}
}
}
static void schedule_sequence ( struct cardstate * cs ,
struct at_state_t * at_state , int sequence )
{
cs - > cur_at_seq = sequence ;
gigaset_add_event ( cs , at_state , RSP_INIT , NULL , sequence , NULL ) ;
}
static void process_command_flags ( struct cardstate * cs )
{
struct at_state_t * at_state = NULL ;
struct bc_state * bcs ;
int i ;
int sequence ;
2006-04-11 09:55:16 +04:00
unsigned long flags ;
2006-03-26 13:38:30 +04:00
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 0 ;
2006-03-26 13:38:30 +04:00
if ( cs - > cur_at_seq ) {
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " not searching scheduled commands: busy " ) ;
2006-03-26 13:38:30 +04:00
return ;
}
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " searching scheduled commands " ) ;
2006-03-26 13:38:30 +04:00
sequence = SEQ_NONE ;
/* clear pending_commands and hangup channels on shutdown */
if ( cs - > at_state . pending_commands & PC_SHUTDOWN ) {
cs - > at_state . pending_commands & = ~ PC_CIDMODE ;
for ( i = 0 ; i < cs - > channels ; + + i ) {
bcs = cs - > bcs + i ;
at_state = & bcs - > at_state ;
at_state - > pending_commands & =
~ ( PC_DLE1 | PC_ACCEPT | PC_DIAL ) ;
if ( at_state - > cid > 0 )
at_state - > pending_commands | = PC_HUP ;
if ( at_state - > pending_commands & PC_CID ) {
at_state - > pending_commands | = PC_NOCID ;
at_state - > pending_commands & = ~ PC_CID ;
}
}
}
/* clear pending_commands and hangup channels on reset */
if ( cs - > at_state . pending_commands & PC_INIT ) {
cs - > at_state . pending_commands & = ~ PC_CIDMODE ;
for ( i = 0 ; i < cs - > channels ; + + i ) {
bcs = cs - > bcs + i ;
at_state = & bcs - > at_state ;
at_state - > pending_commands & =
~ ( PC_DLE1 | PC_ACCEPT | PC_DIAL ) ;
if ( at_state - > cid > 0 )
at_state - > pending_commands | = PC_HUP ;
2008-02-06 12:38:28 +03:00
if ( cs - > mstate = = MS_RECOVER ) {
2006-03-26 13:38:30 +04:00
if ( at_state - > pending_commands & PC_CID ) {
at_state - > pending_commands | = PC_NOCID ;
at_state - > pending_commands & = ~ PC_CID ;
}
}
}
}
/* only switch back to unimodem mode, if no commands are pending and no channels are up */
2006-04-11 09:55:16 +04:00
spin_lock_irqsave ( & cs - > lock , flags ) ;
2006-03-26 13:38:30 +04:00
if ( cs - > at_state . pending_commands = = PC_UMMODE
2006-04-11 09:55:16 +04:00
& & ! cs - > cidmode
2006-03-26 13:38:30 +04:00
& & list_empty ( & cs - > temp_at_states )
2008-02-06 12:38:28 +03:00
& & cs - > mode = = M_CID ) {
2006-03-26 13:38:30 +04:00
sequence = SEQ_UMMODE ;
at_state = & cs - > at_state ;
for ( i = 0 ; i < cs - > channels ; + + i ) {
bcs = cs - > bcs + i ;
if ( bcs - > at_state . pending_commands | |
bcs - > at_state . cid > 0 ) {
sequence = SEQ_NONE ;
break ;
}
}
}
2006-04-11 09:55:16 +04:00
spin_unlock_irqrestore ( & cs - > lock , flags ) ;
2006-03-26 13:38:30 +04:00
cs - > at_state . pending_commands & = ~ PC_UMMODE ;
if ( sequence ! = SEQ_NONE ) {
schedule_sequence ( cs , at_state , sequence ) ;
return ;
}
for ( i = 0 ; i < cs - > channels ; + + i ) {
bcs = cs - > bcs + i ;
if ( bcs - > at_state . pending_commands & PC_HUP ) {
bcs - > at_state . pending_commands & = ~ PC_HUP ;
if ( bcs - > at_state . pending_commands & PC_CID ) {
/* not yet dialing: PC_NOCID is sufficient */
bcs - > at_state . pending_commands | = PC_NOCID ;
bcs - > at_state . pending_commands & = ~ PC_CID ;
} else {
schedule_sequence ( cs , & bcs - > at_state , SEQ_HUP ) ;
return ;
}
}
if ( bcs - > at_state . pending_commands & PC_NOCID ) {
bcs - > at_state . pending_commands & = ~ PC_NOCID ;
cs - > curchannel = bcs - > channel ;
schedule_sequence ( cs , & cs - > at_state , SEQ_NOCID ) ;
return ;
} else if ( bcs - > at_state . pending_commands & PC_DLE0 ) {
bcs - > at_state . pending_commands & = ~ PC_DLE0 ;
cs - > curchannel = bcs - > channel ;
schedule_sequence ( cs , & cs - > at_state , SEQ_DLE0 ) ;
return ;
}
}
list_for_each_entry ( at_state , & cs - > temp_at_states , list )
if ( at_state - > pending_commands & PC_HUP ) {
at_state - > pending_commands & = ~ PC_HUP ;
schedule_sequence ( cs , at_state , SEQ_HUP ) ;
return ;
}
if ( cs - > at_state . pending_commands & PC_INIT ) {
cs - > at_state . pending_commands & = ~ PC_INIT ;
cs - > dle = 0 ; //FIXME
cs - > inbuf - > inputstate = INS_command ;
//FIXME reset card state (or -> LOCK0)?
schedule_sequence ( cs , & cs - > at_state , SEQ_INIT ) ;
return ;
}
if ( cs - > at_state . pending_commands & PC_SHUTDOWN ) {
cs - > at_state . pending_commands & = ~ PC_SHUTDOWN ;
schedule_sequence ( cs , & cs - > at_state , SEQ_SHUTDOWN ) ;
return ;
}
if ( cs - > at_state . pending_commands & PC_CIDMODE ) {
cs - > at_state . pending_commands & = ~ PC_CIDMODE ;
2008-02-06 12:38:28 +03:00
if ( cs - > mode = = M_UNIMODEM ) {
2006-03-26 13:38:30 +04:00
cs - > retry_count = 1 ;
schedule_sequence ( cs , & cs - > at_state , SEQ_CIDMODE ) ;
return ;
}
}
for ( i = 0 ; i < cs - > channels ; + + i ) {
bcs = cs - > bcs + i ;
if ( bcs - > at_state . pending_commands & PC_DLE1 ) {
bcs - > at_state . pending_commands & = ~ PC_DLE1 ;
cs - > curchannel = bcs - > channel ;
schedule_sequence ( cs , & cs - > at_state , SEQ_DLE1 ) ;
return ;
}
if ( bcs - > at_state . pending_commands & PC_ACCEPT ) {
bcs - > at_state . pending_commands & = ~ PC_ACCEPT ;
schedule_sequence ( cs , & bcs - > at_state , SEQ_ACCEPT ) ;
return ;
}
if ( bcs - > at_state . pending_commands & PC_DIAL ) {
bcs - > at_state . pending_commands & = ~ PC_DIAL ;
schedule_sequence ( cs , & bcs - > at_state , SEQ_DIAL ) ;
return ;
}
if ( bcs - > at_state . pending_commands & PC_CID ) {
2008-02-06 12:38:28 +03:00
switch ( cs - > mode ) {
2006-03-26 13:38:30 +04:00
case M_UNIMODEM :
cs - > at_state . pending_commands | = PC_CIDMODE ;
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_CMD , " Scheduling PC_CIDMODE " ) ;
2008-02-06 12:38:28 +03:00
cs - > commands_pending = 1 ;
2006-03-26 13:38:30 +04:00
return ;
# ifdef GIG_MAYINITONDIAL
case M_UNKNOWN :
schedule_init ( cs , MS_INIT ) ;
return ;
# endif
}
bcs - > at_state . pending_commands & = ~ PC_CID ;
cs - > curchannel = bcs - > channel ;
# ifdef GIG_RETRYCID
cs - > retry_count = 2 ;
# else
cs - > retry_count = 1 ;
# endif
schedule_sequence ( cs , & cs - > at_state , SEQ_CID ) ;
return ;
}
}
}
static void process_events ( struct cardstate * cs )
{
struct event_t * ev ;
unsigned head , tail ;
int i ;
int check_flags = 0 ;
int was_busy ;
2006-04-11 09:55:16 +04:00
unsigned long flags ;
2006-03-26 13:38:30 +04:00
2006-04-11 09:55:16 +04:00
spin_lock_irqsave ( & cs - > ev_lock , flags ) ;
head = cs - > ev_head ;
2006-03-26 13:38:30 +04:00
for ( i = 0 ; i < 2 * MAX_EVENTS ; + + i ) {
2006-04-11 09:55:16 +04:00
tail = cs - > ev_tail ;
2006-03-26 13:38:30 +04:00
if ( tail = = head ) {
2008-02-06 12:38:28 +03:00
if ( ! check_flags & & ! cs - > commands_pending )
2006-03-26 13:38:30 +04:00
break ;
check_flags = 0 ;
2006-04-11 09:55:16 +04:00
spin_unlock_irqrestore ( & cs - > ev_lock , flags ) ;
2006-03-26 13:38:30 +04:00
process_command_flags ( cs ) ;
2006-04-11 09:55:16 +04:00
spin_lock_irqsave ( & cs - > ev_lock , flags ) ;
tail = cs - > ev_tail ;
2006-03-26 13:38:30 +04:00
if ( tail = = head ) {
2008-02-06 12:38:28 +03:00
if ( ! cs - > commands_pending )
2006-03-26 13:38:30 +04:00
break ;
continue ;
}
}
ev = cs - > events + head ;
was_busy = cs - > cur_at_seq ! = SEQ_NONE ;
2006-04-11 09:55:16 +04:00
spin_unlock_irqrestore ( & cs - > ev_lock , flags ) ;
2006-03-26 13:38:30 +04:00
process_event ( cs , ev ) ;
2006-04-11 09:55:16 +04:00
spin_lock_irqsave ( & cs - > ev_lock , flags ) ;
2006-03-26 13:38:30 +04:00
kfree ( ev - > ptr ) ;
ev - > ptr = NULL ;
if ( was_busy & & cs - > cur_at_seq = = SEQ_NONE )
check_flags = 1 ;
head = ( head + 1 ) % MAX_EVENTS ;
2006-04-11 09:55:16 +04:00
cs - > ev_head = head ;
2006-03-26 13:38:30 +04:00
}
2006-04-11 09:55:16 +04:00
spin_unlock_irqrestore ( & cs - > ev_lock , flags ) ;
2006-03-26 13:38:30 +04:00
if ( i = = 2 * MAX_EVENTS ) {
2006-04-11 09:55:04 +04:00
dev_err ( cs - > dev ,
" infinite loop in process_events; aborting. \n " ) ;
2006-03-26 13:38:30 +04:00
}
}
/* tasklet scheduled on any event received from the Gigaset device
* parameter :
* data ISDN controller state structure
*/
void gigaset_handle_event ( unsigned long data )
{
struct cardstate * cs = ( struct cardstate * ) data ;
/* handle incoming data on control/common channel */
2008-02-06 12:38:28 +03:00
if ( cs - > inbuf - > head ! = cs - > inbuf - > tail ) {
2006-04-11 09:55:04 +04:00
gig_dbg ( DEBUG_INTR , " processing new data " ) ;
2006-03-26 13:38:30 +04:00
cs - > ops - > handle_input ( cs - > inbuf ) ;
}
process_events ( cs ) ;
}