📄 zjmdmdrv.c
字号:
{
ChangeSendChlID(p_mdm);
return FALSE;
}
if(p_ch->wbytes_after_pause >= p_ch->wbytes_once) //已经发完wbytes_once 字节
{
START_TIMER(p_ch);
#ifdef _VERBOSE
Log(p_mdm->mdm_no,chl_id,"Wait for %d milli-seconds ...\n",
p_ch->pause_time);
#endif
ChangeSendChlID(p_mdm);
return FALSE;
}
if (p_ch->writeable_len==1) //最后一个字节的数据
{
#if defined _DEBUG && defined _VERBOSE
amount_send_bytes = 0;
amount_recv_bytes = 0;
#endif
*data = (chl_id) | 0xf0;
}
else
*data = chl_id;
if(p_ch->wtimer_started)
{
if(TIMER_ARRIVED(p_ch)
{
STOP_TIMER(p_ch);
}
else
{
ChangeSendChlID(p_mdm);
return FALSE;
}
}
}
if(p_ch->writeable_len<=0 && !(p_mdm->f_flags & O_NONBLOCK)) //缓冲中的数据已经写完
{
wake_up_interruptible(&(p_ch->wait_queue_w));
}
return TRUE;
}
/*****************************************************
* type:private
* 从写/命令缓冲中取一个字节数发送到卡上
******************************************************/
BOOL WriteOneOfBufToCard(void)
{
char data;
struct MdmDesc *p_mdm;
p_mdm = gp_MdmDesc[g_MdmNO[g_CurWriteCardCount++]];
if (!p_mdm) return FALSE;
if (p_mdm->mdm_no>7) return FALSE;
if(g_CurWriteCardCount>=g_MdmNum)
g_CurWriteCardCount = 0;
if (!(((inb(StatePort[p_mdm->mdm_no]))&0x02))) //端口不可写
{
return FALSE;
}
if(p_mdm->cmdable_len>0 && !atomic_read(&p_mdm->writed_head)) //有命令要发送且不是刚发完数据头
{
return SendOneByteCmdData(p_mdm);
}
if (!GenerateSendData(p_mdm,&data))
{
//ReadAndAnalyseOne();
return FALSE;
}
/* 向端口写出一个字节普通数据*/
outb(data,DataPort[p_mdm->mdm_no]);
p_mdm->writed_head_flag = !(p_mdm->writed_head_flag);
atomic_set(&p_mdm->writed_head,p_mdm->writed_head_flag);
return TRUE;
}
/*****************************************************
* type:private
* 从用户空间中取得数据并填入发送缓冲
******************************************************/
u16 GetDataFromUserAndInfillToWBuf(struct ChannelDesc *p_ch,const char *data,u16 size)
{
u16 write_bytes = 0;
struct MdmDesc *p_mdm;
p_mdm = gp_MdmDesc[p_ch->mdm_no];
while(write_bytes<size)
{
if(CheckWriteBufferPointer(p_ch) == FULL)
{
p_ch->wbuf_max_full_times++;
if(p_ch->wbuf_max_full_times>MAX_FULL_TIMES)
{
CleanWriteBuff(p_ch);
p_mdm->f_flags = p_mdm->f_flags | O_NONBLOCK;
SendCmd(CMD_DISCONN, p_mdm->mdm_no, p_ch->chl_no, NULL);
#ifdef _DEBUG
Log(p_ch->mdm_no,p_ch->chl_no,"Clean write buffer by driver!\n");
#endif
}
#ifdef _DEBUG
Log(p_ch->mdm_no,p_ch->chl_no,"Write buffer full!\n");
#endif
return write_bytes;
}
get_user(p_ch->write_buf[p_ch->wbuf_writepos],data+write_bytes);
p_ch->wbuf_writepos++;
p_ch->writeable_len++;
write_bytes++;
}
return write_bytes;
}
/***********************************************************
将数据写到用户缓冲
************************************************************/
u16 PutDataToUser(struct ChannelDesc *p_ch,char *user_buff,u16 size)
{
u16 read_bytes = 0;
while(read_bytes<size)
{
if (CheckReadBuffPointer(p_ch) == EMPTY)
{
return read_bytes;
}
put_user(p_ch->read_buf[p_ch->rbuf_readpos],user_buff+read_bytes);
read_bytes++;
p_ch->rbuf_readpos++;
p_ch->readable_len--;
}
return read_bytes;
}
/**********************************************
* 获取可以读取数据的通道号
**********************************************/
char GetReadableCH(u8 mdm_no)
{
int i;
struct MdmDesc *p_mdm;
char result = 0;
p_mdm = gp_MdmDesc[mdm_no];
if(!p_mdm)
return -EINVAL;
for (i=0; i<CHL_NUM; i++)
{
if (p_mdm->ch_desc[i].readable_len>0)
{
result |= 0x01<<i;
}
}
return result;
}
/**********************************************
*Interrupt Server Routine
***********************************************/
void IRQSverviceRoutine(int irq,void *dev_id,struct pt_regs *regs)
{
int i;
for (i=0; i<OPT_CARD_NUM_ONE_IRQ; i++)
{
/* 读一个字节的有效数据并分析 */
ReadAndAnalyseOne();
/* 从缓冲中取一字节发送到卡上*/
WriteOneOfBufToCard();
}
}
/******************************************************
* lseek()系统调用
*******************************************************/
static loff_t zjmdm_lseek(struct file *filp,loff_t off,int whence)
{
return -ESPIPE; /*unseekable*/
}
/************************************************************
open()函数
*************************************************************/
static int zjmdm_open(struct inode *inode,struct file *filp)
{
u8 mdm_id;
struct MdmDesc *p_mdm;
mdm_id = MINOR(filp->f_dentry->d_inode->i_rdev);
if(mdm_id>7)
return -EFAULT;
p_mdm = gp_MdmDesc[mdm_id];
if(!p_mdm) return -EFAULT;
p_mdm->f_flags = filp->f_flags;
MOD_INC_USE_COUNT;
return NO_ERROR;
}
/************************************************************
release()函数
************************************************************/
static int zjmdm_release(struct inode *inode,struct file *filp)
{
MOD_DEC_USE_COUNT;
return 0;
}
/*********************************************************************
read()函数
**********************************************************************/
static ssize_t zjmdm_read(struct file *filp,char *buffer,size_t length,loff_t *offset)
{
int read_bytes = 0;
u8 mdm_id,chl_id;
unsigned long flags;
struct MdmDesc *p_mdm;
struct ChannelDesc *p_ch;
mdm_id = MINOR(filp->f_dentry->d_inode->i_rdev);
chl_id = length & 0x07;
length = length >> 3;
if(mdm_id>7 || chl_id>3)
return -EFAULT;
if(!access_ok(VERIFY_WRITE,(void *)buffer,length))
{
#ifdef DEBUG
Log(mdm_id,chl_id,"Invalid user read address!\n");
#endif
return -EFAULT;
}
p_mdm = gp_MdmDesc[mdm_id];
p_ch = &(p_mdm->ch_desc[chl_id]);
if(!p_mdm || !p_ch) return -EFAULT;
p_mdm->f_flags = filp->f_flags;
//============== start write data to user space =============
read_bytes += PutDataToUser(p_ch,&buffer[read_bytes],length - read_bytes);
if(read_bytes<length && !(filp->f_flags & O_NONBLOCK)) /*block read*/
{
#ifdef _VERBOSE
Log(mdm_id,chl_id,"Read_process %i sleep\n",current->pid);
#endif
save_flags(flags);
cli();
if(p_ch->readable_len<=0)
{
restore_flags(flags);
if(wait_event_interruptible(p_ch->wait_queue_r,p_ch->readable_len>0))
{
return read_bytes;
}
if(signal_pending(current)) //a signal arrived
{
#ifdef _DEBUG
Log(mdm_id,chl_id,"Got signal when sleep on read().\n");
#endif
return -ERESTARTSYS; //tell the fs layer to handle it
}
}
#ifdef _VERBOSE
Log(mdm_id,chl_id,"Read_process %i awoken\n",current->pid);
#endif
read_bytes += PutDataToUser(p_ch,&buffer[read_bytes],length - read_bytes);
}
return read_bytes;
}
/****************************************************************************
write()函数
*****************************************************************************/
static ssize_t zjmdm_write(struct file *filp,const char *buffer,size_t length,loff_t *offset)
{
int writed_bytes = 0;
u8 mdm_id,chl_id;
struct MdmDesc *p_mdm;
struct ChannelDesc *p_ch;
unsigned long flags;
mdm_id = MINOR(filp->f_dentry->d_inode->i_rdev);
chl_id = length & 0x07;
length = length >> 3;
if(mdm_id>7 || chl_id>3)
return -EFAULT;
if(!access_ok(VERIFY_READ,(void *)buffer,length))
{
#ifdef DEBUG
Log(mdm_id,chl_id,"Invalid user write address!\n");
#endif
return -EFAULT;
}
p_mdm = gp_MdmDesc[mdm_id];
p_ch = &(p_mdm->ch_desc[chl_id]);
if(!p_mdm || !p_ch) return -EFAULT;
p_mdm->f_flags = filp->f_flags;
p_ch->wbytes_after_pause = 0;
while(writed_bytes < length)
{
writed_bytes += GetDataFromUserAndInfillToWBuf(p_ch,buffer+writed_bytes,length-writed_bytes);
if(writed_bytes < length && !(filp->f_flags & O_NONBLOCK)) /*block write*/
{
#ifdef _VERBOSE
Log(mdm_id,chl_id,"Write process wait_queue %d going to sleep\n",p_ch->wait_queue_w);
#endif
save_flags(flags);
cli();
if(p_ch->writeable_len>0)
{
restore_flags(flags);
/*wait_event_interruptible()在条件不成立时睡眠也就是等待考察的条件成立*/
if(wait_event_interruptible(p_ch->wait_queue_w,p_ch->writeable_len<=0))
{
return writed_bytes;
}
if(signal_pending(current)) //a signal arrived
{
#ifdef _DEBUG
Log(mdm_id,chl_id,"Got signal when sleep on write().\n");
#endif
return -ERESTARTSYS; //tell the fs layer to handle it
}
}
#ifdef _VERBOSE
Log(mdm_id,chl_id,"Write process awoken %i(%s)\n",current->pid,current->comm);
#endif
}
else
break;
}
/*Now ,all data have writed to "w_buff" already,Let's wait data send over*/
if(p_ch->writeable_len>0 && !(filp->f_flags & O_NONBLOCK)) /*block write*/
{
save_flags(flags);
cli();
if(p_ch->writeable_len>0)
{
restore_flags(flags);
if(wait_event_interruptible(p_ch->wait_queue_w,p_ch->writeable_len<=0))
{
return writed_bytes;
}
if(signal_pending(current)) //a signal arrived
{
#ifdef _DEBUG
Log(mdm_id,chl_id,"Got signal when sleep on write().\n");
#endif
return -ERESTARTSYS; //tell the fs layer to handle it
}
#ifdef _VERBOSE
Log(mdm_id,chl_id,"Write process awoken %i(%s)\n",current->pid,current->comm);
#endif
}
else
{
restore_flags(flags);
}
}
return writed_bytes;
}
/*******************************************************************************
ioctl()函数
*******************************************************************************/
int zjmdm_ioctl(struct inode *inode,struct file *filp,unsigned int ioctl_num,unsigned long ioctl_param)
{
int i;
u8 mdm_id,chl_id;
unsigned int ioctl_type;
char phone[32],*p_char,state_data;
struct MdmDesc *p_mdm;
struct ChannelDesc *p_ch;
mdm_id = MINOR(filp->f_dentry->d_inode->i_rdev);
chl_id = (ioctl_num & 0x00f0) >> 4;
if(MDMNO_IS_NO_VALID(mdm_id) || CHLNO_IS_NO_VALID(chl_id))
return -EINVAL;
p_mdm = gp_MdmDesc[mdm_id];
p_ch = &(p_mdm->ch_desc[chl_id]);
ioctl_type = ioctl_num & 0xff0f;
if(ioctl_type == IOCTL_CMD_CARD_USABLE)
return p_mdm?TRUE:FALSE;
if(ioctl_type == IOCTL_CMD_CORRECTTIME)
{
CorrectLinuxTimeByCMOS();
return NO_ERROR;
}
if(!p_mdm ||!p_ch) return -EINVAL;
/*执行ioctl命令*/
switch(ioctl_type)
{
case IOCTL_CMD_SHUTCH:
return SendCmd(CMD_SHUT_CHL, mdm_id, chl_id, NULL);
break;
case IOCTL_CMD_OPENCH:
return SendCmd(CMD_OPEN_CHL, mdm_id, chl_id, NULL);
break;
case IOCTL_CMD_DISCONN:
return SendCmd(CMD_DISCONN, mdm_id, chl_id, NULL);
break;
case IOCTL_CMD_MAKECALL:
if(!access_ok(VERIFY_READ,(void *)ioctl_param,sizeof(long)))
{
#ifdef _DEBUG
Log(mdm_id,chl_id,"Invalid user address of phone\n");
#endif
return -EINVAL;
}
for(i=0,p_char = (char*)ioctl_param; ;p_char++)
{
get_user(phone[i],p_char);
if(phone[i]>'9' || phone[i]<'0')
break;
i++;
}
phone[i] = '\0';
return SendCmd(CMD_CALLOUT, mdm_id, chl_id, phone);
break;
case IOCTL_CMD_GETSTAT:
state_data = p_ch->connect_state;
if(state_data != INVALID_STATE)
{
p_ch->connect_state = INVALID_STATE;
return (u8)state_data;
}
else return -EFAULT;
break;
case IOCTL_CMD_GetRdableCH:
return GetReadableCH(mdm_id);
break;
case IOCTL_CMD_IsWriteOver:
return (p_ch->writeable_len>0)? FALSE:TRUE;
break;
case IOCTL_CMD_CmdSendOver:
return (p_mdm->cmdable_len>0)? FALSE:TRUE;
break;
case IOCTL_CMD_RESETCH:
InitChannelVariable(p_ch);
return NO_ERROR;
break;
case IOCTL_CMD_QUERY_STATE:
p_ch->hangup_state = INVALID_STATE;
return SendCmd(CMD_QUERY_STATE, mdm_id, chl_id, NULL);
break;
case IOCTL_CMD_GetQueryResult:
state_data = p_ch->hangup_state;
if(state_data != INVALID_STATE)
{
return (u8)state_data;
}
else return -EFAULT;
break;
case IOCTL_CMD_RecoverHead:
return SendCmd(CMD_REVOVER_HEAD, mdm_id, chl_id, NULL);
break;
default:
#ifdef _DEBUG
Log(mdm_id,chl_id,"Invalid ioctl command : 0x%02x\n",ioctl_num);
#endif
return -EINVAL;
break;
}
return NO_ERROR;
}
/******************************************************************
*这个设备驱动程序提供给文件系统的接口
******************************************************************/
struct file_operations Fops =
{
llseek:zjmdm_lseek,
read:zjmdm_read,
write:zjmdm_write,
ioctl:zjmdm_ioctl,
open:zjmdm_open,
release:zjmdm_release
};
/*****************************************************************************
模块的初始化
******************************************************************************/
int init_module(void)
{
int err;
unsigned long flags;
struct resource *iosrc;
save_flags(flags);
cli();
err = InitDriverResource();
if(err) return E_NONE_CARD;
/*request I/O ports*/
iosrc=request_region(IOPORTBASE,PORT_RANGE,DEVICE_NAME);
if(iosrc==NULL)//ioport is busy
{
Log(INVALID_MDMNO,INVALID_CHLNO,"\nIoport request fail!");
return -EBUSY;
}
/*Register IRQ service routine */
if(request_irq(IRQ_NO,IRQSverviceRoutine,SA_INTERRUPT,DEVICE_NAME,NULL))
{
Log(INVALID_MDMNO,INVALID_CHLNO,"Cannot hook irq!\n");
release_region(IOPORTBASE,PORT_RANGE);
return -EBUSY;
}
restore_flags(flags);
/*Register character device*/
Major = register_chrdev(MAJOR,DEVICE_NAME,&Fops);
if(Major<0)
{
free_irq(IRQ_NO,NULL);
release_region(IOPORTBASE,PORT_RANGE);
Log(INVALID_MDMNO,INVALID_CHLNO,"%s device failed with %d\n","Sorry,registering the character",Major);
return Major;
}
#ifdef _VERBOSE
Log(INVALID_MDMNO,INVALID_CHLNO,"Load %s driver successfully\n",DEVICE_NAME);
#endif
return NO_ERROR;
}
/*************************************************************************
这个函数的功能是卸载模块,主要是从/proc 中取消注册
的设备特殊文件。
**************************************************************************/
void cleanup_module(void)
{
int ret = 0;
/*Free resource of system */
FreeDriverResource();
free_irq(IRQ_NO,NULL);
release_region(IOPORTBASE,PORT_RANGE);
ret = unregister_chrdev(Major,DEVICE_NAME);
if(ret<0)
{
Log(INVALID_MDMNO,INVALID_CHLNO,"Error in unregister %s:%d\n",DEVICE_NAME,ret);
}
#ifdef _VERBOSE
Log(INVALID_MDMNO,INVALID_CHLNO,"Zjmdm driver module unload from system safely\n");
#endif
#ifdef _DEBUG
Log(INVALID_MDMNO,INVALID_CHLNO,"Max no data read times is %ld\n",max_no_read_data);
Log(INVALID_MDMNO,INVALID_CHLNO,"Read buffer full times is %ld\n",rbuf_full_times);
Log(INVALID_MDMNO,INVALID_CHLNO,"Amount sent %ld bytes\n",amount_send_bytes);
Log(INVALID_MDMNO,INVALID_CHLNO,"Amount recveived %ld bytes\n",amount_recv_bytes);
#endif
return;
}
/*EOF */
/*amount 1636 lines*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -