⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 zjmdmdrv.c

📁 MODEM卡驱源码
💻 C
📖 第 1 页 / 共 3 页
字号:
		{
			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 + -