📄 s3c44b0_uart.c
字号:
/*======================================================
* File Name: s3c44b0_uart.c
*
* Author:gong
*
* Email:gongyanlei@msn.com
*
* QQ & MSN:6213599, gongyanlei@msn.com
* Modification History: 2008-05 gong, created.
*
* Debug History: 2008-05
*
======================================================*/
#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 "s3c44b0_uart.h"
/* =============for debugging usage================*/
#define DEBUG /*used while debugging*/
/*===========================================*/
/* globals */
/*===========================================*/
#define IRQ_S3C44B0_UART INT_EINT2
static LOOP_QUEUE rxQueue; /*for received data */
static LOOP_QUEUE txQueue; /*for transmitted data */
static char * dev_idkp = S3C44B0_UART_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_s3c44b0_uart_all_int().
=============================================*/
static void enable_s3c44b0_uart_thre_int(void)
{
S3C44B0_UART_LCR = S3C44B0_UART_LCR & ( ~ LCR_DLAB ); /*DLAB=0*/
S3C44B0_UART_IER = S3C44B0_UART_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_s3c44b0_uart_all_int().
=============================================*/
static void disable_s3c44b0_uart_thre_int(void)
{
S3C44B0_UART_LCR = S3C44B0_UART_LCR & ( ~ LCR_DLAB ); /*DLAB=0*/
S3C44B0_UART_IER = S3C44B0_UART_IER & ( ~ IER_EN_THRE_INT );
}
/*============================================
Description: we need to configure LCR,BAUD RATE,MCR,FCR,IER for
s3c44b0_uart.
=============================================*/
static void config_s3c44b0_uart(void)
{
/*line control registe=0000 1011*/
/*8 bits, 1 stop bit, odd*/
S3C44B0_UART_LCR = LCR_8_CHR_BIT | LCR_1_STOP_BIT | LCR_EN_PARITY ;
/*Baud Rate*/
/*DLAB=1*/
S3C44B0_UART_LCR = S3C44B0_UART_LCR | LCR_DLAB ;
/*divisor = XIN frequency input ÷(desired baud rate ×16)*/
S3C44B0_UART_DLSB = ( XTALL / ( DESIRED_BAUD_RATE * 16 ) ) & 0x00FF ;
S3C44B0_UART_DMSB = ( XTALL / ( DESIRED_BAUD_RATE * 16 ) ) >> 8 ;
/*Modem Control Register=0010 0010*/
/* Auto-RTS and auto-CTS enabled*/
//S3C44B0_UART_MCR = MCR_EN_AUTO_FLOW;
/*FIFO Interrupt Control Register=0100 0001*/
/*64bytes mode, trigger level=56, enable the transmit and receive FIFOs*/
S3C44B0_UART_LCR = S3C44B0_UART_LCR | LCR_DLAB ; /* DLAB = 1 */
S3C44B0_UART_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*/
S3C44B0_UART_LCR = S3C44B0_UART_LCR & ( ~LCR_DLAB) ;
/*enable received data available interrupt, and receiver line status interrupt; disable THRE interrupt*/
S3C44B0_UART_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 int s3c44b0_uart_read(struct file *filp, char *buf, int count, loff_t *l)
{
unsigned char i = 0 ;
disable_irq( IRQ_S3C44B0_UART ); /*disable s3c44b0_uart interrupt on ARM*/
if ( query_queue_empty( &rxQueue) != 1 )
{
#ifdef DEBUG
printk("enter S3C44B0_UART_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 S3C44B0_UART_read( ).\n\n" );
#endif
}
else
{
count = 0;
}
enable_irq(IRQ_S3C44B0_UART); /*enable s3c44b0_uart 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 int s3c44b0_uart_write(struct file *filp, const char *buf, int 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_S3C44B0_UART ); /*disable s3c44b0_uart interrupt on ARM*/
//pBuf = (unsigned char *)buf;
lsr_val = S3C44B0_UART_LSR;
printk("LSR = 0x%x\n", lsr_val);
if ( lsr_val & LSR_THRE )
{
#ifdef DEBUG
printk("we will send msg directly\n");
printk("coping msg from user... ...");
#endif
copy_from_user( txMsg, buf , count ) ;
#ifdef DEBUG
printk("done\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -