引用 SAMSUNG_S3C2410串口驱动


转自:http://blog.chinaunix.net/u/7971/showart_548176.html

引用

Akem  的  SAMSUNG_S3C2410串口驱动

        今天写了一个2410的串口驱动.在此总结一下.也当作一次复习.  废话不多说了.进入正题.          
        2410支持3个COM口,在u-boot中已经打开了COM1, 所以现在要打开COM2口.以模块方式加载驱动程序.并在COM2口打印测试. 开发板上有两个串口接口,所以要用两台PC机进行测试.一台作为宿主机COM1,一台测试串口读写COM2.

        在开发板已经下载了Linux2.4内核.通过NFS文件系统.和宿主机进行开发通信.也就是说在PC机上进行开发和交叉编译,把目标文件通过NFS加载到开发版上运行

操作步骤:

串口数据发送

1.  设置串口工作在中断和轮训模式

2.  设置串口的数据位长度, 停止位, 是否有奇偶校验位

3.  设置串口收发数据波特率

4.  将数据写到发送寄存器

5.  检测状态寄存器相关位判断是否发送完成

串口数据读取

1.  设置串口工作在中断和轮询模式

2.  设置串口收发数据位长度, 停止位, 是否有奇偶校验

3.  设置串口收发数据的波特率

4.  检测状态寄存器是否有数据

5.  读取数据


代码

----------------------------------------------------------------------
utrs_driver.h         配置相关寄存器
-------------------------------------------------------------------------------

#include<asm/hardware.h>

/* 通过2410手册得到的串口寄存器地址 ,驱动要设置的相关寄存器 */

/* 控制寄存器: 设置数据位, 停止位, 校验位 0x50004000*/
#define UART_ULCON1          __REG(0x50004000 + 0x00)
/* 设置串口工作模式, UCON1是第二串口,偏移量0x04设置中断轮询模式 */     
#define UART_UCON1            __REG(0x50004000 + 0x04)
/* 设置接收寄存器, 发送数据偏移量0x24是L模式 */
#define UART_URXH1            __REG(0x50004000 + 0x24)
/* 设置接收寄存器, 发送和接收状态,偏移量0x20是L模式 */
#define UART_UTXH1            __REG(0x50004000 + 0x20)
/* 设置串口通讯波特率寄存器 */
#define UART_UBRDIV1         __REG(0x50004000 + 0x28)
/* 设置接受状态偏移量0x10设置清空buffer */
#define UART_UTRSTAT1      __REG(0x50004000 + 0x10)

int s3c2410_serial_open(void);
int s3c2410_serial_release(void);
int s3c2410_serial_read(unsigned char *buf, int count);
int s3c2410_serial_write(unsigned char *buf, int count);

---------------------------------------------------------------------------------------
utrs_driver.c      驱动模块
---------------------------------------------------------------------------------------
#include<linux/config.h>
#include<linux/module.h>
#include<linux/kernel.h>
#include<linux/init.h>
#include"utrs_driver.h"

/* 打开串口并且初始化 */
int s3c2410_serial_open(void)
{

        UART_UCON1 = 0x05;        /* 初始化控制寄存器的 [3 : 0] 读写模式为中断轮询 */
        UART_ULCON1 = 0x03;      /*  初始化线控制寄存器 [1 : 0] 读写为8-bit即一个字符 */
        UART_UBRDIV1 = 26;        /* 初始化串口波特率 26 为115200 */
        
        return 0;
}

int s3c2410_serial_release(void)
{
        return 0;
}

/* 接收模块 */
int s3c2410_serial_read( unsigned char *buf, int count )
{
        int i;
        unsigned char ch;
        
        for(i = 0; i < count; i++)
        {
            while(!(UART_UTRSTAT1 & 0x1));      /* 监控接收寄存器是否有数据 */

            ch = UART_URXH1;                           /* 如果有数据用一个字符保存 */

            *(buf + i) = ch;                                /* 然后放在缓冲区buffer里 */
        }
        return count;
}

/* 发送模块 */
int s3c2410_serial_write( unsigned char *buf, int count )
{
        int i;
        unsigned char ch;
    
        for(i = 0; i < count; i++)
        {
            ch = *(buf + i);                                              /* 从缓冲区读一个字符 */
            
            while(!((UART_UTRSTAT1 & 0x2) == 0x2));      /* 判断接收寄存器里是否有为空 */

            UART_UTXH1 = ch;                                          /* 如果为空就向寄存器里写入数据 */
        }
        return 0;
}

/* 串口的读写模块是分开的,并不是说write发送read就是接收,当写过去的时候COM2屏幕就已经打印了, read是在COM2写数据在宿主机打印出来 */

---------------------------------------------------------------------------------------
utrs_test.c      测试模块
---------------------------------------------------------------------------------------
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/string.h>
#include"utrs_driver.h"

int s3c2410_serial_init(void)
{
        unsigned char str[200] = "HELLO FUCK!/r/n";
        unsigned char ch;
        int len;    

        len = strlen(str);
        
        printk("init moule!/n");
        
        s3c2410_serial_open();                          /* 打开串口 */
        s3c2410_serial_release();                       
        s3c2410_serial_write(str, len);             /* 相串口里写数据, 此时COM2连接的PC会打印出HELLO FUCK! */  

        while(ch != '#')                                         
        {
            s3c2410_serial_read(&ch, 1);                /* 在COM2的PC上输入数据会写入到接收寄存器,  在宿主机打印 */

                                                                         /* 寄存器是以一个字节读写 */   
            printk("%c",ch);                                      /* 把在COM2端写入的数据打印到主机 */
        }
        return 0;
}

void s3c2410_serial_cleanup(void)                  
{
    printk("clean moule!/n");
}

int init_module(void)                                /* 加载模块 */
{
    s3c2410_serial_init();
    return 0;
}

void cleanup_module(void)                            /* 卸载模块 */
{
    s3c2410_serial_cleanup();
}
-------------------------------------------------------------------------------------------

    驱动程序是在内核启动时,通过系统脚本创建设备文件的,而应用程序要和驱动打交道就必须通过打开相应的设备文件进行操作。上述的例子不能算是一个完整的驱动程序,因为是通过模块加载的方式对设备进行操作,并没有创建设备文件。也就是说要手工的进行加载。以下的例子是通过创建真实设备文件的形式,所以是货真价实的驱动程序。

----------------------------------------------------------------------------------------------------------------

utrs_driver.h

----------------------------------------------------------------------------------------------------------------

#include<asm/hardware.h>

#define UART_ULCON1   __REG(0x50004000 + 0x00)
#define UART_UCON1     __REG(0x50004000 + 0x04)
#define UART_URXH1      __REG(0x50004000 + 0x24)
#define UART_UTXH1      __REG(0x50004000 + 0x20)
#define UART_UBRDIV1   __REG(0x50004000 + 0x28)
#define UART_UTRSTAT1 __REG(0x50004000 + 0x10)

----------------------------------------------------------------------------------------------------------------

utrs_driver.c

----------------------------------------------------------------------------------------------------------------

#include <linux/config.h> 
#include <linux/module.h> 
#include <linux/kernel.h> 
#include <linux/init.h> 
#include <linux/sched.h> 
#include <linux/miscdevice.h> 
#include <linux/delay.h> 
#include <linux/poll.h> 
#include <asm/hardware.h> 
#include "utrs_driver.h" 
 
#define DEVICE_NAME  "akem"    //设备文件名
#define BUTTON_MAJOR 232      //主设备号
 

/* 打开驱动inode结构在内部表示文件,file结构是打开上面传来的文件描述符fd对应的file结构,file结构都指向单个inode */
static int akem_open(struct inode *inode, struct file * file) 

     /* 设置寄存器 */
    UART_UCON1 = 0x05; 
    UART_ULCON1 = 0x03; 
 
    printk("Kernel : in open,we do nothing....../n"); 
    return 0; 

 

/* 从设备读取数据,上层的read函数会调用到这里,file是read的fd对应的结构, ppos是系统回调 */
static int akem_read(struct file * file, char * buff, size_t count, loff_t *ppos) 

    int i; 
    unsigned char ch; 

    for(i = 0; i < count; i++) 
    { 
        while(!(UART_UTRSTAT1 & 0x1));   /* 扫描寄存器是否有数据 */
        ch = UART_URXH1;                          /*  从寄存器里读出一个字节 */
        *(buff + i) = ch;                                  /*  存放在buff里 */
    }
      return strlen(buff);                               /* 返回buff的长度 */


 /* 向设备写入数据,上层的write函数会调用到这里,file是write的fd对应的结构, offp是系统回调 */
int akem_write( struct file *filp, const char *buff, size_t count, loff_t *offp )

    int i; 
    unsigned char ch; 
     
    for(i = 0; i < count; i++) 
    { 
        ch = *(buff + i);  
        while(!((UART_UTRSTAT1 & 0x2) == 0x2));     /* 扫描寄存器是否有数据 */
        UART_UTXH1 = ch;                                           /* 把一格字节写入寄存器 */
    }
    return 0; 

 /*  设置串口的波特率 */
static int akem_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 

    int ret; 
    ret = -EINVAL; 
      switch(cmd)  
    { 
        case 111:      /* 功过命令来配置波特率 */
        { 
            if(arg == 115200) 
            { 
                UART_UBRDIV1 = 26; 
                ret = 0; 
            } 
        }; break; 
 
          default: 
        return -EINVAL; 
      } 
 
    printk("Kernel : in ioctl, (%d, %d)/n", cmd, arg);

 
int akem_release(struct inode *inode, struct file *filp) 

    printk("release!!/n"); 
    return 0; 

 /* file_operations结构是建立驱动程序和设备编号的连接,内部是一组函数指针,每个打开的文件,也就是file结构,和一组函数关联,这些操作主要用来实现系统调用的 */
static struct file_operations akae_fops = { 
 
      owner:  THIS_MODULE, 
      open:     akae_open, 
      ioctl:     akae_ioctl, 
      read:     akae_read, 
    write:    akae_write, 
    release:    akae_release 
 
}; 
 /* 初始化驱动模块,驱动程序要注册一个设备文件,并对其进行操作 */
static int __init akem_init(void) 

      int ret; 
      int ready = 0;

      /* 注册一个字符设备,并分配设备编号,major是设备号,name是驱动程序名称 fops是file_operations结构 */
      ret = register_chrdev(BUTTON_MAJOR, DEVICE_NAME, &akae_fops); 
      
      if (ret < 0)  
    { 
        printk(DEVICE_NAME " can't register major number/n"); 
        return ret; 
     }
      printk(" init ok!....../n"); 
      return 0;        /* 注册成功返回0 */

 /*  卸载模块 */
static void __exit akem_exit(void) 
{

      /* 如果不使用该设备时释放编号 */
      unregister_chrdev(BUTTON_MAJOR, DEVICE_NAME); 
      printk("bye !/n"); 

 
module_init(akem_init); 
module_exit(akem_exit); 
MODULE_LICENSE("GPL");

----------------------------------------------------------------------------------------------------------------

test.c       测试模块

这个测试模快是以应用程序调用驱动,而不以模块的形式加载,所以这正是驱动本质

----------------------------------------------------------------------------------------------------------------

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

#define BOUNDRATE 111     /*  设置伯特率命令参数  */

int main(void)
{
  int fd;
  int ret = 0;
  char buf[100] = "HELLO FUCK!/n/r";
  char ch;

  fd = open("/temp/akem", O_RDWR);   /* open会直接调用到驱动里的akem_open */
  if(fd == -1)
  {
    perror("open");
    exit(1);
  }

  ret = ioctl(fd, BOUNDRATE, 115200);      /*  设置伯特律115200 */

  ret = write(fd, buf, strlen(buf));     /* write会调用驱动里的akem_write  */
  if(ret == -1)
  {
    perror("write error");
    exit(1);
  }

  while(ch != '#')
  {
   read(fd, &ch,1);
   printf("%c",ch);
   fflush(stdout);
  }

  close(fd);
}

linuxdriver_code_tool |-- 03 | `-- 2.6内核升级工具 | |-- device-mapper-1.00.19-2.i386.rpm | |-- lvm2-2.00.25-1.01.i386.rpm | |-- mkinitrd-4.2.0.3.tar.tar | |-- module-init-tools-3.2.2.tar.bz2 | `-- modutils-2.4.5-1.src.rpm |-- 04 | |-- 内核模块参数范例 | | `-- book.c | |-- 内核模块导出符号 | | `-- export_symb.c | `-- 最简单的内核模块 | `-- hello.c |-- 05 | `-- udev源代码 | `-- udev-114.tar.gz |-- 06 | |-- globalmem驱动 | | `-- globalmem.c | `-- 包含2个globalmem设备的驱动 | `-- globalmem_two.c |-- 07 | `-- 含并发控制的globalmem驱动 | `-- globalmem_lock.c |-- 08 | |-- globalfifo驱动 | | `-- globalfifo.c | `-- poll应用程序范例 | `-- pollmonitor.c |-- 09 | |-- 异步通知应用程序范例 | | `-- asyncmonitor.c | `-- 支持异步通知的globalfifo | `-- globalfifo_async.c |-- 10 | |-- S3C2410实时钟驱动 | | `-- s3c2410-rtc.c | `-- 秒设备驱动与应用程序 | |-- second.c | `-- second_test.c |-- 11 | |-- DMA范例 | | |-- 3c505.c | | |-- 3c505.h | | `-- dma.h | `-- 静态映射范例 | `-- mach-smdk2440.c |-- 12 | |-- NVRAM驱动 | | `-- generic_nvram.c | |-- 触摸屏驱动 | | |-- 作为input设备 | | | |-- s3c2410_ts.c | | | `-- s3c2410_ts.h | | `-- 作为普通字符设备 | | `-- s3c2410-ts.c | |-- 看门狗驱动 | | `-- s3c2410_wdt.c | `-- 平台设备 | `-- devs.c |-- 13 | |-- IDE驱动 | | |-- ide-disk.c | | `-- ide-h8300.c | `-- RAMDISK驱动 | `-- rd.c |-- 14 | |-- S3C2410串口驱动 | | |-- regs-gpio.h | | |-- regs-serial.h | | `-- s3c2410.c | `-- 串口核心层 | |-- serial_core.c | `-- serial_core.h |-- 15 | |-- S3C2410 I2C主机驱动 | | |-- i2c-s3c2410.c | | |-- iic.h | | |-- regs-gpio.h | | `-- regs-iic.h | `-- SAA711x I2C设备驱动 | `-- saa711x.c |-- 16 | `-- CS8900以太网设备驱动 | |-- cs89x0.c | `-- cs89x0.h |-- 17 | |-- ALSA工具及库 | | |-- alsa-driver-1.0.15.tar.bz2 | | |-- alsa-firmware-1.0.15.tar.bz2 | | |-- alsa-lib-1.0.15.tar.bz2 | | |-- alsa-oss-1.0.15.tar.bz2 | | |-- alsa-tools-1.0.15.tar.bz2 | | |-- alsa-utils-1.0.13.tar.bz2 | | `-- pyalsa-1.0.15.tar.bz2 | |-- ALSA驱动范例 | | |-- sa11xx-uda1341.c | | `-- uda1341.h | |-- ALSA应用程序范例 | | |-- pcm.c | | `-- pcm_min.c | |-- OSS驱动范例 | | `-- s3c2410-uda1341.c | `-- OSS应用程序范例 | |-- mixer.c | `-- sound.c |-- 18 | |-- FRAMEBUFFER应用程序范例 | | `-- fb_display | | |-- fb_display.c | | |-- fb_display.h | | |-- Makefile | | |-- README | | `-- test.c | `-- S3C2410 LCD驱动 | |-- s3c2410fb.c | `-- s3c2410fb.h |-- 19 | |-- busybox源代码 | | `-- busybox-1.2.1.tar.bz2 | |-- MTD工具 | | `-- mtd-utils-1.0.0.tar.gz | |-- nand驱动范例 | | `-- s3c2410.c | |-- nor驱动范例 | | `-- s3c2410nor.c | `-- yaffs&yaffs2源代码 | |-- yaffs.tar.gz | `-- yaffs2.tar.gz |-- 20 | |-- USB串口驱动 | | |-- usb-serial.c | | `-- usb-serial.h | |-- USB工具 | | `-- usbview-1.0.tar.tar | |-- USB骨架程序 | | `-- usb-skeleton.c | |-- USB键盘驱动 | | |-- input.h | | |-- usb_input.h | | `-- usbkbd.c | `-- usb主机控制器驱动范例 | |-- ohci-s3c2410.c | `-- usb-control.h |-- 21 | |-- PCI骨架程序 | | `-- pci-skeleton.c | `-- PCI驱动范例 | `-- i810_audio.c `-- 22 |-- 范例代码 | |-- oops范例 | | |-- oops_example.asm | | `-- oops_example.c | `-- proc范例 | `-- sim_proc.c `-- 内核调试工具 |-- ddd-3.3.11.tar.gz |-- gdbmod-2.4.bz2 |-- kdb-v4.4-2.6.15-rc5-common-1.bz2 |-- kdb-v4.4-2.6.15-rc5-common-2.bz2 |-- kdb-v4.4-2.6.15-rc5-i386-1.bz2 `-- linux-2.6.15.5-kgdb-2.4.tar.tar 73 directories, 91 files
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值