S3C2410串口驱动程序

 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);
}
 

你可能感兴趣的:(职场,休闲,串口驱动程序)