📄 tl16c750.c
字号:
/*======================================================
*
* File Name:
* ---------
* tl16c750.c
*
*
* Author:
* -------
* zhang dahai
*
* Email:
* ------
* olivercheung@126.com
*
* QQ & MSN;
* ---------
* 334654529, olivercheung2005@yahoo.com.cn
* Modification History:
* -----------------
* 2006-7-17, zhang dahai, created.
*
* Debug History:
* -----------------
* 2006-9-7,22:35, zhang dahai.
*
======================================================*/
#ifndef __KERNEL__
#define __KERNEL__
#endif
//#ifndef MODULE
// #define MODULE
//#endif
/* includes */
#include <linux/kernel.h> /* printk() */
#include <linux/module.h> /*this is a kernel module, so ....*/
#include <linux/interrupt.h>
#include <linux/init.h> /*module_init, module_exit, etc*/
#include <linux/types.h> /* size_t */
#include <linux/sched.h> /* current and everything */
//#include <linux/tqueue.h>
#include <linux/fs.h> /*register_chrdev, file etc*/
#include <asm/uaccess.h> /*copy_to_user, copy_from_user*/
#include <asm/hardware.h>
#include <asm/irq.h> /*request_irq, etc*/
#include <asm/io.h>
//#include <asm/system.h>
//#include <asm/bitops.h>
#include "tl16c750.h"
/* =============for debugging usage================*/
#define DEBUG /*used while debugging*/
/*===========================================*/
/* globals */
/*===========================================*/
#define IRQ_TL16C750 INT_EINT2
static LOOP_QUEUE rxQueue; /*for received data */
static LOOP_QUEUE txQueue; /*for transmitted data */
static char * dev_idkp = TL16C750_NAME; /*for request_irq()*/
static unsigned char lstCmdReqSN = 0 ; /*last sequence number of command request*/
static unsigned char lstStsRepSN = 0 ; /*last sequence number of transmitted status report*/
/*============================================
Description: 1.reset queue.
=============================================*/
static void reset_queue( LOOP_QUEUE * pQueue )
{
int i = 0 ;
int j = 0 ;
pQueue->rear = 0 ;
pQueue->front = 0 ;
for ( i = 0 ; i < MAX_ITEM_NUM ; i++ )
{
for ( j = 0 ; j < MAX_MSG_LEN ; j++ )
{
pQueue->data[ i ][ j ] = 0;
}
}
}
/*============================================
Description: 1.query if the query is empty.
Return: 1--empty.
0--not empty.
=============================================*/
static int query_queue_empty ( LOOP_QUEUE * pQueue )
{
return ( pQueue->rear == pQueue->front );
}
/*============================================
Description: 1.query if the query is full.
Return: 1--full.
0--not full.
=============================================*/
static int query_queue_full ( LOOP_QUEUE * pQueue )
{
return ( ( pQueue->rear + 1 ) % MAX_ITEM_NUM == pQueue->front );
}
/*============================================
Description: insert an item into queue.
=============================================*/
static void in_queue ( LOOP_QUEUE * pQueue )
{
pQueue->rear = ( pQueue->rear + 1 ) % MAX_ITEM_NUM;
}
/*============================================
Description: remove an item out of queue.
=============================================*/
static void out_queue ( LOOP_QUEUE * pQueue )
{
unsigned char i = 0 ;
for ( i = 0 ; i < pQueue->len[ pQueue->front ] ; i ++ )
{
pQueue->data[ pQueue->front ][ i ] = 0 ;
}
pQueue->front = ( pQueue->front + 1 ) % MAX_ITEM_NUM;
}
/*============================================
Description: 1.disable THRE interrupt
2.enable received data available interrupt,and receiver line
tatus interrupt
3.this function shoud be used after enable_tl16c750_all_int().
=============================================*/
static void enable_tl16c750_thre_int(void)
{
TL16C750_LCR = TL16C750_LCR & ( ~ LCR_DLAB ); /*DLAB=0*/
TL16C750_IER = TL16C750_IER | IER_EN_THRE_INT ;
}
/*============================================
Description: 1.disable THRE interrupt
2.enable received data available interrupt,and receiver line
status interrupt
3.this function shoud be used after enable_tl16c750_all_int().
=============================================*/
static void disable_tl16c750_thre_int(void)
{
TL16C750_LCR = TL16C750_LCR & ( ~ LCR_DLAB ); /*DLAB=0*/
TL16C750_IER = TL16C750_IER & ( ~ IER_EN_THRE_INT );
}
/*============================================
Description: we need to configure LCR,BAUD RATE,MCR,FCR,IER for
tl16c750.
=============================================*/
static void config_tl16c750(void)
{
/*line control registe=0000 1011*/
/*8 bits, 1 stop bit, odd*/
TL16C750_LCR = LCR_8_CHR_BIT | LCR_1_STOP_BIT | LCR_EN_PARITY ;
/*Baud Rate*/
/*DLAB=1*/
TL16C750_LCR = TL16C750_LCR | LCR_DLAB ;
/*divisor = XIN frequency input ÷(desired baud rate ×16)*/
TL16C750_DLSB = ( XTALL / ( DESIRED_BAUD_RATE * 16 ) ) & 0x00FF ;
TL16C750_DMSB = ( XTALL / ( DESIRED_BAUD_RATE * 16 ) ) >> 8 ;
/*Modem Control Register=0010 0010*/
/* Auto-RTS and auto-CTS enabled*/
//TL16C750_MCR = MCR_EN_AUTO_FLOW;
/*FIFO Interrupt Control Register=0100 0001*/
/*64bytes mode, trigger level=56, enable the transmit and receive FIFOs*/
TL16C750_LCR = TL16C750_LCR | LCR_DLAB ; /* DLAB = 1 */
TL16C750_FCR = FCR_64_BYTE_MODE | FCR_56_TRIGGER_LEVEL_64 | FCR_FIFO_ENALBE| FCR_CLR_RX_FIFO |FCR_CLR_TX_FIFO ;
/*Interrupt Enable Register=0000 0101*/
/*DLAB=0*/
TL16C750_LCR = TL16C750_LCR & ( ~LCR_DLAB) ;
/*enable received data available interrupt, and receiver line status interrupt; disable THRE interrupt*/
TL16C750_IER = IER_EN_RDA_INT | IER_EN_RLS_INT ;
}
/*============================================
Description: 1.if there are items in rxQueue, read one of them.
2.we should enter the critical area to protect the shared data.
3.we need do the maintenance of the rxQueue.
=============================================*/
static ssize_t tl16c750_read(struct file *filp, char *buf, size_t count, loff_t *l)
{
unsigned char i = 0 ;
disable_irq( IRQ_TL16C750 ); /*disable tl16c750 interrupt on ARM*/
if ( query_queue_empty( &rxQueue) != 1 )
{
#ifdef DEBUG
printk("enter TL16C750_read( ).\n");
printk("rxQueue is not empty.\n");
#endif
count = rxQueue.len[ rxQueue.front ] ; /*get the length of data*/
#ifdef DEBUG
printk("rxQueue.len[ %u ] = %u\n", rxQueue.front , count );
printk("copying rxQueue.data[ %u ] to user... ...", rxQueue.front );
#endif
copy_to_user( buf, &rxQueue.data[ rxQueue.front ], count );
#ifdef DEBUG
printk("done\n" );
printk("they are:\n");
for( i = 0 ; i < count ; i ++ )
{
printk("0x%x ", rxQueue.data[ rxQueue.front ][ i ] );
}
printk("\n");
printk("out rxQueue... ...");
#endif
out_queue( &rxQueue ); /*maintanence of the rxQueue*/
#ifdef DEBUG
printk("done\n" );
printk("rxQueue.front = %u, rxQueue.rear = %u\n", rxQueue.front , rxQueue.rear );
#endif
#ifdef DEBUG
printk("exit TL16C750_read( ).\n\n" );
#endif
}
else
{
count = 0;
}
enable_irq(IRQ_TL16C750); /*enable tl16c750 interrupt on ARM*/
return count;
}
/*=====================================================
Description: 1.check if the transimtter FIFO is empty.
2.if transimitter FIFO is empty, write the tramsimitted data into
transimitter FIFO directly.
3.if transimitter FIFO is not empty, write the transimitted data into
txQueue.
Returns: count: the length of transmitted data which have been written
into txQueue or transmitter FIFO.
0: the txQueue is full and transimitter FIFO is not empty!
======================================================*/
static ssize_t tl16c750_write(struct file *filp, const char *buf, size_t count, loff_t *l)
{
unsigned char lsr_val = 0 ; /*to store the value of IIR*/
unsigned char txMsg[MAX_MSG_LEN]; /*to store the data of buf temporarily*/
unsigned char i = 0 ;
//unsigned char * pBuf;
printk("enter write\n");
disable_irq( IRQ_TL16C750 ); /*disable tl16c750 interrupt on ARM*/
//pBuf = (unsigned char *)buf;
lsr_val = TL16C750_LSR;
printk("LSR = 0x%x\n", lsr_val);
if ( lsr_val & LSR_THRE )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -