📄 zjmdmdrv.c
字号:
*********************************************/
void InitModemVariable(struct MdmDesc *p_mdm)
{
int i;
if(!p_mdm) return;
inb(DataPort[p_mdm->mdm_no]);
inb(StatePort[p_mdm->mdm_no]);
/* 初始化变量*/
p_mdm->f_flags = 0;
p_mdm->writed_head_flag = FALSE;
atomic_set(&p_mdm->writed_head , p_mdm->writed_head_flag);
atomic_set(&(p_mdm->expect_read_head),TRUE);
atomic_set(&p_mdm->is_data_head,FALSE);
p_mdm->head_at_last = 0;
p_mdm->next_write_chl_id = 0;
memset(p_mdm->cmd_buf,0,sizeof(p_mdm->cmd_buf));
p_mdm->cbuf_readpos = 0;
p_mdm->cbuf_writepos = 0;
p_mdm->cmdable_len = 0;
sema_init(&(p_mdm->cmd_sending_sem),1);
init_waitqueue_head(&(p_mdm->wait_queue_cmd));
for (i=0; i<CHL_NUM; i++)
{
p_mdm->ch_desc[i].chl_no = i;
p_mdm->ch_desc[i].mdm_no = p_mdm->mdm_no;
p_mdm->ch_desc[i].be_open = FALSE;
/*init wait queue*/
init_waitqueue_head(&(p_mdm->ch_desc[i].wait_queue_r));
init_waitqueue_head(&(p_mdm->ch_desc[i].wait_queue_w));
InitChannelVariable(&(p_mdm->ch_desc[i]));
}
return;
}
/**********************************************************
*根据探测modem卡的结果申请必须的内存资源
*并初始化所有资源
***********************************************************/
int InitDriverResource()
{
int i,count = 0,size;
struct MdmDesc *p_mdm = NULL;
gp_mdm_res = NULL;
g_MdmNum = 0;
g_CurReadCardCount = 0;
g_CurWriteCardCount = 0;
#ifdef _DEBUG
amount_recv_bytes = 0;
amount_send_bytes = 0;
no_read_data = 0;
max_no_read_data = 0;
recv_first_data = FALSE;
rbuf_full_times = 0;
head_err = FALSE;
#endif
memset(g_MdmNO,INVALID_MDMNO,sizeof(g_MdmNO));
for (i=0; i<MDM_NUM; i++)
{
gp_MdmDesc[i] = NULL;
if(DetectModem(i))
{
g_MdmNO[count++] = (u8)i;
g_MdmNum++;
}
}
if(g_MdmNum<1) return E_NONE_CARD;
size = sizeof(struct MdmDesc) * g_MdmNum;
gp_mdm_res = (char*)kmalloc(size,GFP_KERNEL);
p_mdm = (struct MdmDesc*)gp_mdm_res;
for (i=0; i<g_MdmNum; i++)
{
gp_MdmDesc[g_MdmNO[i]] = &p_mdm[i];
gp_MdmDesc[g_MdmNO[i]]->mdm_no = g_MdmNO[i];
InitModemVariable(gp_MdmDesc[g_MdmNO[i]]);
}
return NO_ERROR;
}
/*****************************************************
*释放驱动的相关资源
*****************************************************/
void FreeDriverResource()
{
if(gp_mdm_res) kfree(gp_mdm_res);
return;
}
/****************************************************
*Tasklet service routine
****************************************************/
void TastletRoutine(unsigned long arg)
{
return;
}
/*******************************************************
标记tasklet任务
********************************************************/
void MarkTasklet()
{
return;
}
/*****************************************************
* type:private
* 往命令缓冲中填入一个要发送的命令数据
******************************************************/
BOOL InfillByteToCmdBuff(struct MdmDesc *p_mdm,char data)
{
if(CheckCmdBufferPointer(p_mdm) == FULL)
{
#ifdef _DEBUG
Log(INVALID_MDMNO,INVALID_CHLNO,"Command buffer of card %d is full!\n",p_mdm->mdm_no);
#endif
return FALSE;
}
//d{
Log(INVALID_MDMNO,INVALID_CHLNO,"Infill cmd 0x%.2x to card %d cbuff, len=%d\n",
(u8)data,p_mdm->mdm_no,p_mdm->cmdable_len+1);
//d}
p_mdm->cmd_buf[p_mdm->cbuf_writepos]= data;
p_mdm->cbuf_writepos++;
p_mdm->cmdable_len++;
return TRUE;
}
/******************************************************
* type:public
* 把要发送的命令数据写到命令缓冲
* 直到命令发送完才返回
******************************************************/
ERRNO SendCmdDataToMdm(char *CmdBuf,int size,u8 mdm_no)
{
int writed_bytes = 0; //已写的字节数
unsigned long flags;
struct MdmDesc *p_mdm;
if(mdm_no>7) return -EINVAL;
p_mdm = gp_MdmDesc[mdm_no];
if(!p_mdm) return -EINVAL;
if(down_interruptible(&(p_mdm->cmd_sending_sem)))
{
#ifdef _DEBUG
Log(33,33,"Send command failed return on down_interruptible()\n");
#endif
return -ERESTARTSYS;/*failure*/
}
while(writed_bytes < size)
{
if(!InfillByteToCmdBuff(p_mdm,CmdBuf[writed_bytes]))
{
#ifdef _DEBUG
Log(33,33,"Send command failed return on InfillByteToCmdBuff()\n");
#endif
return E_SEND_CMD_FAIL;
}
writed_bytes++;
}
up(&(p_mdm->cmd_sending_sem));
/*等待命令发完*/
if(p_mdm->cmdable_len > 0 && !(p_mdm->f_flags & O_NONBLOCK)) //block access
{
save_flags(flags);
cli();
if(p_mdm->cmdable_len > 0)
{
restore_flags(flags);
if(wait_event_interruptible(p_mdm->wait_queue_cmd,p_mdm->cmdable_len <= 0))
{
#ifdef _DEBUG
Log(33,33,"Send command failed return on wait_event_interruptible()\n");
#endif
return -EFAULT;
}
}
else
{
restore_flags(flags);
}
}
return NO_ERROR;
}
/*********************************************
* type:private
* 发送命令给modem卡
**********************************************/
ERRNO SendCmd(u8 cmd_type,u8 mdm_no,u8 chl_no,char *phone)
{
int len = 0;
u8 cmd_buf[32];
struct MdmDesc *p_mdm;
struct ChannelDesc *p_ch;
p_mdm = gp_MdmDesc[mdm_no];
p_ch = &(p_mdm->ch_desc[chl_no]);
if(!p_ch || !p_mdm) return E_SEND_CMD_FAIL;
/* 构造命令包*/
if(cmd_type == CMD_CALLOUT && phone!=NULL)
{
len = ConvertStrToBCD(phone,(char*)&(cmd_buf[2]));
}
if(cmd_type == CMD_REVOVER_HEAD)
{
cmd_buf[0] = 0x0;
len = 1;
}
else
{
cmd_buf[0] = (len << 4) |chl_no | 0x08;
cmd_buf[1] = cmd_type;
len += 2;
}
if(SendCmdDataToMdm(cmd_buf,len,mdm_no) != NO_ERROR)
{
#ifdef _DEBUG
Log(mdm_no,chl_no,"Send command to channel %d-%d failed!\n",mdm_no,chl_no);
#endif
return E_SEND_CMD_FAIL;
}
switch(cmd_type)
{
case CMD_CONNECT:
#ifdef _VERBOSE
Log(mdm_no,chl_no,"Establish connect OK from channel %d-%d\n",mdm_no,chl_no);
#endif
break;
case CMD_DISCONN:
p_ch->connect = FALSE;
p_ch->connect_state = INVALID_STATE;
#ifdef _VERBOSE
Log(mdm_no,chl_no,"Desconnect!\n");
#endif
break;
case CMD_CALLOUT:
#ifdef _VERBOSE
if(phone)
Log(mdm_no,chl_no,"Calling to %s ...\n",phone);
else
Log(mdm_no,chl_no,"Calling out ...\n");
#endif
break;
case CMD_OPEN_CHL:
p_ch->be_open = TRUE;
#ifdef _VERBOSE
Log(mdm_no,chl_no,"Channel open!\n");
#endif
break;
case CMD_SHUT_CHL:
p_ch->be_open = FALSE;
#ifdef _VERBOSE
Log(mdm_no,chl_no,"Channel shut down\n");
#endif
break;
case CMD_DETECT:
#ifdef _VERBOSE
Log(mdm_no,chl_no,"Detecting modem card...\n");
#endif
break;
case CMD_QUERY_STATE:
#ifdef _VERBOSE
Log(mdm_no,chl_no,"Query hangup state\n");
#endif
break;
case CMD_REVOVER_HEAD:
#ifdef _DEBUG
Log(mdm_no,chl_no,"Try to recover head error\n");
#endif
break;
default:
#ifdef _DEBUG
Log(mdm_no,chl_no,"Command error!\n");
#endif
break;
}
return NO_ERROR;
}
/********************************************************
* type:private
* 从卡上读一个字节
********************************************************/
BOOL ReadOneByteFromCard(struct MdmDesc *p_mdm,char *data)
{
u8 chl_id;
char char_tmp;
struct ChannelDesc *p_ch;
chl_id = 0x07 & (p_mdm->head_at_last);
p_ch = &(p_mdm->ch_desc[chl_id]);
if(!(atomic_read(&p_mdm->expect_read_head)) && //不希望读到头,希望读到的是数据
atomic_read(&p_mdm->is_data_head)) //最后一次读到的头是数据头
{
if (CheckReadBuffPointer(&(p_mdm->ch_desc[chl_id])) == FULL) //缓冲满,不能再读
{
#ifdef _DEBUG
rbuf_full_times++;
Log(p_mdm->mdm_no,chl_id,"Read buffer full!\n");
#endif
p_ch->rbuf_max_full_times++;
if(p_ch->rbuf_max_full_times>MAX_FULL_TIMES)
{
CleanReadBuff(p_ch);
p_mdm->f_flags = p_mdm->f_flags | O_NONBLOCK;
SendCmd(CMD_DISCONN, p_mdm->mdm_no, chl_id, NULL);
#ifdef _DEBUG
Log(p_mdm->mdm_no,chl_id,"Clean read buffer by driver!\n");
#endif
}
else if(!(p_mdm->f_flags & O_NONBLOCK))
{
wake_up_interruptible(&(p_ch->wait_queue_r));
}
return FALSE;
}
}
char_tmp = inb(StatePort[p_mdm->mdm_no]);
if((char_tmp & 0x01) == 1) //无数据可读,马上返回
{
#ifdef _DEBUG
if(recv_first_data)
{
no_read_data++;
if(no_read_data>max_no_read_data)
max_no_read_data = no_read_data;
}
#endif
return FALSE;
}
*data = inb(DataPort[p_mdm->mdm_no]);
#ifdef _DEBUG
if(!recv_first_data)
{
max_no_read_data = 0;
recv_first_data = TRUE;
}
no_read_data = 0;
#endif
if(!(p_mdm->f_flags & O_NONBLOCK) &&
!(atomic_read(&p_mdm->expect_read_head)) &&
atomic_read(&p_mdm->is_data_head))
{
wake_up_interruptible(&(p_ch->wait_queue_r));
}
return TRUE;
}
/**********************************************************
* type:private
* 将收到卡上读到的数据存到读缓冲
**********************************************************/
void PutDataOfCardToReadBuf(struct ChannelDesc *p_ch,char data)
{
// if(!(p_ch->connect))
// return;
p_ch->read_buf[p_ch->rbuf_writepos]= data;
p_ch->rbuf_writepos++;
p_ch->readable_len++;
return;
}
/***********************************************
* type:private
* 处理卡上收到的命令
***********************************************/
void HandleCmdFromCard(struct MdmDesc *p_mdm,char cmd1,char cmd2)
{
u8 chl_id;
chl_id = 0x03 & cmd1;
switch((u8)cmd2)
{
case CMD_CONN_SUCCESS:
InitChannelVariable(&(p_mdm->ch_desc[chl_id]));
p_mdm->ch_desc[chl_id].connect = TRUE;
p_mdm->ch_desc[chl_id].connect_state = cmd2;
#ifdef _VERBOSE
Log(p_mdm->mdm_no,chl_id,"Establish connect success\n");
#endif
break;
case CMD_CONN_FAIL:
p_mdm->ch_desc[chl_id].connect = FALSE;
p_mdm->ch_desc[chl_id].connect_state = INVALID_STATE;
#ifdef _DEBUG
Log(p_mdm->mdm_no,chl_id,"Establish connect failed!Cause : Recv 0x%02x\n",(u8)cmd2);
#endif
break;
case CMD_HANGUP_BACK:
case CMD_BRINGUP_BACK:
p_mdm->ch_desc[chl_id].hangup_state = cmd2;
#ifdef _VERBOSE
Log(p_mdm->mdm_no,chl_id,"Return hangup state : 0x%.2x\n",(u8)cmd2);
#endif
break;
default:
break;
}
return;
}
/********************************************************
* type:private
* 从卡上读到一个有效数据,并分析
*********************************************************/
BOOL ReadAndAnalyseOne()
{
char ch_recv;
u8 chl_id;
struct MdmDesc *p_mdm;
struct ChannelDesc *p_ch;
p_mdm = gp_MdmDesc[g_MdmNO[g_CurReadCardCount++]];
if (!p_mdm) return FALSE;
if (p_mdm->mdm_no>=MDM_NUM) return FALSE;
if(g_CurReadCardCount>=g_MdmNum)
g_CurReadCardCount = 0;
if (!ReadOneByteFromCard(p_mdm,&ch_recv)) //没读到数据
return FALSE;
if(atomic_read(&p_mdm->expect_read_head)) //希望读到头
{
chl_id = 0x07 & ch_recv;
if(chl_id>=CHL_NUM) //头错误,通道号应该在[0,3]
{
#ifdef _DEBUG
head_err = TRUE;
Log(p_mdm->mdm_no,chl_id,"Data head of card %d error!\n",p_mdm->mdm_no);
#endif
for(chl_id=0; chl_id<CHL_NUM; chl_id++)
{
p_ch = &(p_mdm->ch_desc[chl_id]);
if(!(p_ch->connect))
{
CleanReadBuff(p_ch);
CleanWriteBuff(p_ch);
p_mdm->f_flags = p_mdm->f_flags | O_NONBLOCK;
SendCmd(CMD_DISCONN, p_mdm->mdm_no, chl_id, NULL);
#ifdef _DEBUG
Log(p_mdm->mdm_no,chl_id,"Send \"CMD_DISCONN\" because received error head!\n");
#endif
}
}
return FALSE;
}
#ifdef _DEBUG
else if(head_err)
{
head_err = FALSE;
Log(p_mdm->mdm_no,chl_id,"Data head of card %d become to good since error at last!\n",p_mdm->mdm_no);
}
#endif
p_mdm->head_at_last = ch_recv;
atomic_set(&p_mdm->expect_read_head,FALSE);
if (ch_recv & 0x08) //是命令头,下一字节是命令字
{
atomic_set(&p_mdm->is_data_head,FALSE);
}
else //是数据头,下一字节是数据
{
atomic_set(&p_mdm->is_data_head,TRUE);
}
}
else //是数据或命令
{
atomic_set(&p_mdm->expect_read_head,TRUE);
chl_id = 0x03 & (p_mdm->head_at_last);
if(atomic_read(&p_mdm->is_data_head))
{
#if defined _VERBOSE && defined _DEBUG
// Log(p_mdm->mdm_no,chl_id,"Recv: \"0x%02x\", rbuff %d bytes,amount %ld bytes.\n",
// (u8)ch_recv,p_mdm->ch_desc[chl_id].readable_len,amount_recv_bytes++);
#endif
PutDataOfCardToReadBuf(&(p_mdm->ch_desc[chl_id]),ch_recv);
}
else
{
HandleCmdFromCard(p_mdm, p_mdm->head_at_last, ch_recv);
}
p_mdm->head_at_last = 0;
}
return TRUE;
}
/******************************************************
* 发送一字节的命令数据
******************************************************/
BOOL SendOneByteCmdData(struct MdmDesc *p_mdm)
{
char data;
if (CheckCmdBufferPointer(p_mdm) == EMPTY)
{
return FALSE;
}
data = p_mdm->cmd_buf[p_mdm->cbuf_readpos];
/* 向端口写出一个字节*/
outb(data,DataPort[p_mdm->mdm_no]);
p_mdm->cbuf_readpos++;
p_mdm->cmdable_len--;
#ifdef _VERBOSE
Log(INVALID_MDMNO,INVALID_CHLNO,"Send cmd 0x%.2x to card %d , len=%d\n",
(u8)data,p_mdm->mdm_no,p_mdm->cmdable_len);
#endif
if(p_mdm->cmdable_len<=0 && !(p_mdm->f_flags & O_NONBLOCK))
{
wake_up_interruptible(&(p_mdm->wait_queue_cmd));
}
return TRUE;
}
/*******************************************************
改变要发送的通道号
*******************************************************/
inline void ChangeSendChlID(struct MdmDesc *p_mdm)
{
p_mdm->next_write_chl_id++;
if(p_mdm->next_write_chl_id>=CHL_NUM)
p_mdm->next_write_chl_id = 0;
}
/******************************************************
* 产生要发送的数据
******************************************************/
BOOL GenerateSendData(struct MdmDesc *p_mdm,char *data)
{
struct ChannelDesc *p_ch;
u8 chl_id;
chl_id = p_mdm->next_write_chl_id & 0x03;
p_ch = &(p_mdm->ch_desc[chl_id]);
/*头已经发送出去,数据是无论如何都要发送的,
所以不做任何判断*/
if (atomic_read(&p_mdm->writed_head))
{
*data = p_ch->write_buf[p_ch->wbuf_readpos];
p_ch->wbuf_readpos++;
p_ch->writeable_len--;
p_ch->wbytes_after_pause++;
ChangeSendChlID(p_mdm);
#ifdef _VERBOSE
// Log(p_mdm->mdm_no,chl_id,"Send: \"0x%02x\". wbuf %d bytes,amount %ld bytes\n",
// (u8)(*data),p_ch->writeable_len,amount_send_bytes++);
#endif
}
else //要发送头
{
if (CheckWriteBufferPointer(p_ch) == EMPTY)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -