📄 serial_8250.c
字号:
case CS5: lcr = LCR_CS5; break;
case CS6: lcr = LCR_CS6; break;
case CS7: lcr = LCR_CS7; break;
default: lcr = LCR_CS8; break;
}
if(cflag&CSTOPB)
lcr |= LCR_STOPB; //停止位为2或1.5;
if(cflag&PARENB){
lcr |= LCR_PARITY; //使能奇偶校验
if(!(cflag&PARODD))
lcr |= LCR_PEVEN; //偶校验
}
//port->read_status_mask = UART_OE;
//if(iflag&INPCK)
// port->read_status_mask |= UART_PE|UART_FE;
// port->ignore_status_mask = 0;
//if(iflag&IGNPAR)
// port->ignore_status_mask |= UART_PE|UART_FE;
// if(iflag&IGNBRK){
// port->ignore_status_mask |= UART_BE;
// if(iflag&IGNPAR)
// port->ignore_status_mask |= UART_OE;
//}
save_flags_cli(flags); //在system.h里定义,存储状态在flags里
lcr=inb(LCR)&0x80;//使能DLL和DLM寄存器
outb(lcr, LCR);
outb((quot-1)%256, DLL); //设置波特率
outb((quot-1)/256, DLM);
lcr=inb(LCR)&0x7F;
outb(lcr,LCR);
// DLL = (auot-1)%256;
// DLM = (auot-1)/256;
restore_flags(flags);//在system.h里定义,将flags里存储的状态恢复
}
static const char *port4_type(struct uart_port *port)// 返回一个描述特定端口的常量string的指针
{
return port->type == PORT_16654 ? "PORT4" : NULL;
}
/*
* Release the memory region(s) being used by 'port'
*/
static void port4_release_port(struct uart_port *port)
{
}
/*
* Request the memory region(s) being used by 'port'
*/
static int port4_request_port(struct uart_port *port)
{
return 0;
}
/*
* Configure/autoconfigure the port.
*/
static void port4_config_port(struct uart_port *port, int flags)
{
if(flags & UART_CONFIG_TYPE)//UART_CONFIG_TYPE定义在serial_core.h里,等于(1《0)
port->type =PORT_16654 ;
}
/*
* verify the new serial_struct (for TIOCSSERIAL).
*/
static int port4_verify_port(struct uart_port *port, struct serial_struct *ser)
{
return 0;
}
static struct uart_ops port4_pops = {
tx_empty: port4_tx_empty,
set_mctrl: port4_set_mctrl,
get_mctrl: port4_get_mctrl,
stop_tx: port4_stop_tx,
start_tx: port4_start_tx,
stop_rx: port4_stop_rx,
enable_ms: port4_enable_ms,
break_ctl: port4_break_ctl,
startup: port4_startup,
shutdown: port4_shutdown,
change_speed: port4_change_speed,
type: port4_type,
release_port: port4_release_port,
request_port: port4_request_port,
config_port: port4_config_port,
verify_port: port4_verify_port,
};
//#define UB_RHR REGL2(0x00)
#define UB_RHR (*(volatile unsigned int*)(0x06000000))
#define UC_RHR (*(volatile unsigned int*)(0x0A000000))
#define UD_RHR (*(volatile unsigned int*)(0x0E000000))
static struct uart_port port4_ports[4] = {
{
iobase: (void *)&UA_RHR,
irq: 21, //外部中断4
uartclk: CONFIG_PORT4_CLK,//29491200,
fifosize: 16,
ops: &port4_pops,
flags: ASYNC_BOOT_AUTOCONF, //0x10000000 ;定义在serial.h里
},
{
iobase: (void *)&UB_RHR,
irq: 23, //外部中断2
uartclk: CONFIG_PORT4_CLK,//29491200,
fifosize: 16,
ops: &port4_pops,
flags: ASYNC_BOOT_AUTOCONF,
},
{
iobase: (void *)&UC_RHR,
irq: 24, //外部中断1
uartclk: CONFIG_PORT4_CLK,//29491200,
fifosize: 16,
ops: &port4_pops,
flags: ASYNC_BOOT_AUTOCONF,
},
{
iobase: (void *)&UD_RHR,
irq: 25, //外部中断0
uartclk: CONFIG_PORT4_CLK,//29491200, //在autoconf.h中定义
fifosize: 16,
ops: &port4_pops,
flags: ASYNC_BOOT_AUTOCONF,
}
};
#ifdef CONFIG_SERIAL_PORT4_CONSOLE
static void port4_console_write(struct console *co, const char *s, u_int count)
{
struct uart_port *port = port4_ports + co->index;
unsigned char status1,status2, intmask;
int i;
intmask = inb(IER);
INT_DISABLE(port->irq); //定义在irq.h里
// status=(inb(IER)&0xFD); //禁止接收和发送数据中断
//outl(status,IER);
for (i = 0; i < count; i++) {
do {
status1 = inb(LSR);
} while (status1&TEMP); //等待发送空时,传输
outb(s[i], THR);
if (s[i] == '\n') {
do {
status1 = inb(LSR);
} while (status1&TEMP);
outb('\r',THR);
}
}
do {
status2 = inb(LSR);
} while ((status2&TEMP)==0); //当发送队列都为空时,恢复原来的中断标志
outb(intmask,IER);
}
static kdev_t port4_console_device(struct console *co) //为系统增加一个设备
{
return MKDEV(SERIAL_PORT4_MAJOR, SERIAL_PORT4_MINOR+co->index);
}
static int port4_console_wait_key(struct console *co) //系统调用时接收数据
{
struct uart_port *port = port4_ports + co->index;
unsigned char ch;
//int intmask = inl(IER); // save the IER
//int status=(inl(IER)&0xFC);// disable the interrupts so that the real driver for the port does not get the
//character.
unsigned char status1;
do{
status1 = inb(LSR);
}while(status1&0x01==0); //等待数据准备好,也就是等待接收中有数据
ch = inb(RHR);
//outl(intmask,IER);
return ch;
}
static void __init port4_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
{
unsigned char quotl,quoth, quot,status;
// status = inl(UCON);
//if(!status)
// return;
status = inb(LCR);
*bits = (status&3)+5;
*parity = 'n';
if(status&LCR_PARITY){
if(status&LCR_PEVEN)
*parity = 'e';
else
*parity = 'o';
}
quotl = inb(DLL);
quoth=inb(DLM);
quot=quoth*256+quotl+1;
//*baud = port->uartclk/(16*(quot+1));
if(quot<2">=1){
*baud = 115200;
return;
}
if(quot<3">=2){
*baud = 57600;
return;
}
if(quot<6&& quot>=3){
*baud = 38400;
return;
}
// if(*baud>34000 && *baud<42000){
// *baud = 38400;
// return;
//}
if(quot<12 && quot>=6){
*baud = 19200;
return;
}
if(quot<24 && quot>=12){
*baud = 9600;
return;
}
if(quot<48 && quot>=24){
*baud = 4800;
return;
}
if(quot<96&">=48){
*baud = 2400;
return;
}
if(quot<192 && quot>=96){
*baud = 1200;
return;
}
if(quot<384 && quot>=192){
*baud = 600;
return;
}
if(quot<2304&">=384){
*baud = 300;
return;
}
if(quot<65535&">=2304){
*baud = 50;
return;
}
}
static int __init port4_console_setup(struct console *co, char *options)
{
struct uart_port *port;
int baud = 115200;
int bits = 8;
int parity = 'n';
int flow = 'n';
/*
* Check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
* console support.
*/
port = uart_get_console(port4_ports, UART_NR, co);
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
else
port4_console_get_options(port, &baud, &parity, &bits);
outb(0xC7, FCR);
//outl(0x05, UCON);
return uart_set_options(port, co, baud, parity, bits, flow);
/*
outl(0x97, UFCON);
outl(0x03, ULCON);
outl(0x20, UBRDIV);
outl(0x05, UCON);
*/
return 0;
}
static struct console port4_console = {
name: "ttyS",
write: port4_console_write,
device: port4_console_device,
wait_key: port4_console_wait_key,
setup: port4_console_setup,
flags: CON_PRINTBUFFER,
index: -1,
};
void __init port4_console_init(void)
{
register_console(&port4_console);
}
#define PORT4_CONSOLE &port4_console
#else
#define PORT4_CONSOLE NULL
#endif
static struct uart_driver port4_reg = {
owner: THIS_MODULE,
normal_major: SERIAL_PORT4_MAJOR,
#ifdef CONFIG_DEVFS_FS
normal_name: "ttyS%d",
callout_name: "cua%d",
#else
normal_name: "ttyS",
callout_name: "cua",
#endif
normal_driver: &normal,
callout_major: CALLOUT_PORT4_MAJOR,
callout_driver: &callout,
table: port4_table,
termios: port4_termios,
termios_locked: port4_termios_locked,
minor: SERIAL_PORT4_MINOR,
nr: UART_NR,
port: port4_ports,
cons: PORT4_CONSOLE,
};
static int __init port4_init(void)
{
return uart_register_driver(&port4_reg);
}
static void __exit port4_exit(void)
{
uart_unregister_driver(&port4_reg);
}
module_init(port4_init); //在module.h里定义
module_exit(port4_exit);
EXPORT_NO_SYMBOLS;
MODULE_AUTHOR("SMQ"); //在module.h里定义
MODULE_DESCRIPTION("ARM S3C44B0 expand serial port4 driver");
MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -