Chinaunix首页 | 论坛 | 博客
  • 博客访问: 90156
  • 博文数量: 17
  • 博客积分: 408
  • 博客等级: 一等列兵
  • 技术积分: 210
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-24 10:11
文章分类
文章存档

2012年(1)

2011年(16)

分类: LINUX

2011-10-14 08:55:10

我用的是友善的mini2440开发板,这是linux-2.6.32内核下driver/serial/s3c2440.c 也就是2440的uart驱动注册函数,uart是paltform注册的函数,挂载好文件系统后在文件系统下/dev/ttySAC0 /dev/ttySAC1 /dev/ttySAC2 这说明三个串口的驱动都是能用的,这是内核源码:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "samsung.h"

static int s3c2440_serial_setsource(struct uart_port *port,
         struct s3c24xx_uart_clksrc *clk)
{
 unsigned long ucon = rd_regl(port, S3C2410_UCON);
 /* todo - proper fclk<>nonfclk switch. */
 ucon &= ~S3C2440_UCON_CLKMASK;
 if (strcmp(clk->name, "uclk") == 0)
  ucon |= S3C2440_UCON_UCLK;
 else if (strcmp(clk->name, "pclk") == 0)
  ucon |= S3C2440_UCON_PCLK;
 else if (strcmp(clk->name, "fclk") == 0)
  ucon |= S3C2440_UCON_FCLK;
 else {
  printk(KERN_ERR "unknown clock source %s\n", clk->name);
  return -EINVAL;
 }
 wr_regl(port, S3C2410_UCON, ucon);
 return 0;
}

static int s3c2440_serial_getsource(struct uart_port *port,
        struct s3c24xx_uart_clksrc *clk)
{
 unsigned long ucon = rd_regl(port, S3C2410_UCON);
 unsigned long ucon0, ucon1, ucon2;
 switch (ucon & S3C2440_UCON_CLKMASK) {
 case S3C2440_UCON_UCLK:
  clk->divisor = 1;
  clk->name = "uclk";
  break;
 case S3C2440_UCON_PCLK:
 case S3C2440_UCON_PCLK2:
  clk->divisor = 1;
  clk->name = "pclk";
  break;
 case S3C2440_UCON_FCLK:
  /* the fun of calculating the uart divisors on
   * the s3c2440 */
  ucon0 = __raw_readl(S3C24XX_VA_UART0 + S3C2410_UCON);
  ucon1 = __raw_readl(S3C24XX_VA_UART1 + S3C2410_UCON);
  ucon2 = __raw_readl(S3C24XX_VA_UART2 + S3C2410_UCON);
  printk("ucons: %08lx, %08lx, %08lx\n", ucon0, ucon1, ucon2);
  ucon0 &= S3C2440_UCON0_DIVMASK;
  ucon1 &= S3C2440_UCON1_DIVMASK;
  ucon2 &= S3C2440_UCON2_DIVMASK;
  if (ucon0 != 0) {
   clk->divisor = ucon0 >> S3C2440_UCON_DIVSHIFT;
   clk->divisor += 6;
  } else if (ucon1 != 0) {
   clk->divisor = ucon1 >> S3C2440_UCON_DIVSHIFT;
   clk->divisor += 21;
  } else if (ucon2 != 0) {
   clk->divisor = ucon2 >> S3C2440_UCON_DIVSHIFT;
   clk->divisor += 36;
  } else {
   /* manual calims 44, seems to be 9 */
   clk->divisor = 9;
  }
  clk->name = "fclk";
  break;
 }
 return 0;
}
static int s3c2440_serial_resetport(struct uart_port *port,
        struct s3c2410_uartcfg *cfg)
{
 unsigned long ucon = rd_regl(port, S3C2410_UCON);
 dbg("s3c2440_serial_resetport: port=%p (%08lx), cfg=%p\n",
     port, port->mapbase, cfg);
 /* ensure we don't change the clock settings... */
 ucon &= (S3C2440_UCON0_DIVMASK | (3<<10));
 wr_regl(port, S3C2410_UCON,  ucon | cfg->ucon);
 wr_regl(port, S3C2410_ULCON, cfg->ulcon);
 /* reset both fifos */
 wr_regl(port, S3C2410_UFCON, cfg->ufcon | S3C2410_UFCON_RESETBOTH);
 wr_regl(port, S3C2410_UFCON, cfg->ufcon);
 return 0;
}
static struct s3c24xx_uart_info s3c2440_uart_inf = {
 .name  = "Samsung S3C2440 UART",
 .type  = PORT_S3C2440,
 .fifosize = 64,
 .rx_fifomask = S3C2440_UFSTAT_RXMASK,
 .rx_fifoshift = S3C2440_UFSTAT_RXSHIFT,
 .rx_fifofull = S3C2440_UFSTAT_RXFULL,
 .tx_fifofull = S3C2440_UFSTAT_TXFULL,
 .tx_fifomask = S3C2440_UFSTAT_TXMASK,
 .tx_fifoshift = S3C2440_UFSTAT_TXSHIFT,
 .get_clksrc = s3c2440_serial_getsource,
 .set_clksrc = s3c2440_serial_setsource,
 .reset_port = s3c2440_serial_resetport,
};
/* device management */
static int s3c2440_serial_probe(struct platform_device *dev)
{
 dbg("s3c2440_serial_probe: dev=%p\n", dev);
 return s3c24xx_serial_probe(dev, &s3c2440_uart_inf);
}
static struct platform_driver s3c2440_serial_driver = {
 .probe  = s3c2440_serial_probe,
 .remove  = __devexit_p(s3c24xx_serial_remove),
 .driver  = {
  .name = "s3c2440-uart",
  .owner = THIS_MODULE,
 },
};
s3c24xx_console_init(&s3c2440_serial_driver, &s3c2440_uart_inf);
static int __init s3c2440_serial_init(void)
{
 return s3c24xx_serial_init(&s3c2440_serial_driver, &s3c2440_uart_inf);
}
static void __exit s3c2440_serial_exit(void)
{
 platform_driver_unregister(&s3c2440_serial_driver);
}
module_init(s3c2440_serial_init);
module_exit(s3c2440_serial_exit);
MODULE_DESCRIPTION("Samsung S3C2440,S3C2442 SoC Serial port driver");
MODULE_AUTHOR("Ben Dooks <
>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:s3c2440-uart");
 
 
下面是从串口读取数据的程序仅供参考:
 
 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "common.h"
#define FALSE  -1
#define TRUE   0
#define at01 "AT\r"
#define at02 "ATE0\r"
#define at03 "AT^DGPIOSM=1\r"
#define at04 "AT^DSLP=0,0\r"
#define at05 "AT+CR=1\r"
#define at06 "AT+CRC=1\r"
#define at07 "AT+CMER=2,0,0,2\r"
#define at08 "AT^DSCI=1\r"
#define at09 "AT^DCPI=1\r"
#define at10 "AT+CREG=1\r"
#define at11 "AT^DSQ=1\r"
#define at12 "AT+CFUN=5\r"
#define at13 "AT+CFUN=1\r"
#define at14 "AT+COPS=0\r"
#define at15    "ATD15210684584;\r"
#define at100   "AT+CREG?\r"
//*************delete char***********************************************8
void RemoveChars(char str[],char remove[])
{
 int src ,dst,removeArray[256];
 
 src = 0;
 memset(removeArray, 0, sizeof(removeArray));
 
 while(remove[src])
 {
  removeArray[remove[src]] = 1;
  src++;
 }
 
 src = dst = 0;
 
 do
 {
  if(!removeArray[str[src]])
  {
   str[dst++] = str[src];
  } 
 }while(str[src++]);
}
int speed_arr[] = {B115200, B57600, B38400, B19200,
  B9600, B4800, B2400, B1200, B300, };
int name_arr[] = {115200, 57600, 38400, 19200,
  9600,  4800,  2400,  1200,  300, };
void set_speed(int fd, int speed)
{
 int  i, status;
 struct termios Opt;
 if (tcgetattr(fd, &Opt) != 0)
 {
  perror("SetupSerial baud 1");
  return;
 }
 for ( i= 0;  i < sizeof(speed_arr) / sizeof(int);  i++)
 {
  if (speed == name_arr[i])
  {
   tcflush(fd, TCIOFLUSH);
   cfsetispeed(&Opt, speed_arr[i]);
   cfsetospeed(&Opt, speed_arr[i]);
   status = tcsetattr(fd, TCSANOW, &Opt);
   if  (status != 0)
   {
    perror("tcsetattr fd");
    return;
   }
   tcflush(fd,TCIOFLUSH);
  }
 }
}
int set_Parity(int fd,int databits,int stopbits,int parity)
{
 struct termios options;
 if (tcgetattr(fd,&options) != 0)
 {
  perror("SetupSerial 1");
  return(FALSE);
 }
 options.c_cflag &= ~CSIZE;
 options.c_iflag = 0;
 switch (databits)
 {
 case 7:
  options.c_cflag |= CS7;
  break;
 case 8:
  options.c_cflag |= CS8;
  break;
 default:
  fprintf(stderr,"Unsupported data size\n");
  return (FALSE);
 }
 switch (parity)
 {
 case 'n':
 case 'N':
  options.c_cflag &= ~PARENB;   /* Clear parity enable */
  options.c_iflag &= ~INPCK;     /* Enable parity checking */
  break;
 case 'o':
 case 'O':
  options.c_cflag |= (PARODD | PARENB); /* set to odd check */
  options.c_iflag |= INPCK;             /* Disnable parity checking */
  break;
 case 'e':
 case 'E':
  options.c_cflag |= PARENB;     /* Enable parity */
  options.c_cflag &= ~PARODD;   /* set to even check */
  options.c_iflag |= INPCK;       /* Disnable parity checking */
  break;
 case 'S':
 case 's':  /*as no parity*/
     options.c_cflag &= ~PARENB;
  options.c_cflag &= ~CSTOPB;
  break;
 default:
  fprintf(stderr,"Unsupported parity\n");
  return (FALSE);
 }
 switch (stopbits)
 {
 case 1:
  options.c_cflag &= ~CSTOPB;
  break;
 case 2:
  options.c_cflag |= CSTOPB;
    break;
 default:
   fprintf(stderr,"Unsupported stop bits\n");
   return (FALSE);
 }
 /* Set input parity option */
 if (parity != 'n')
  options.c_iflag |= INPCK;
 tcflush(fd,TCIFLUSH);
 options.c_cc[VTIME] = 150; /* set 15 seconds timeout */
 options.c_cc[VMIN] = 0; /* Update the options and do it NOW */
 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
 options.c_oflag &= ~OPOST;
 /* end */
 if (tcsetattr(fd,TCSANOW,&options) != 0)
 {
  perror("SetupSerial 3");
  return (FALSE);
 }
 return (TRUE);
}
int OpenDev(char *Dev)
{
 int fd;
 fd = open(Dev, O_RDWR );
 if (-1 == fd)
 {
  perror("Can't Open Serial Port");
  return -1;
 }
 return fd;
}
static int  fd_dev;
fd_set  rfds;
struct timeval tv;
int  retval;
int  nread;
char buff[512];
int atsendrecv(char atin[215],int timeout)
{
 int returnvalue = 0;
 FD_ZERO(&rfds);
 FD_SET(fd_dev,&rfds);
 tv.tv_sec= timeout;
 tv.tv_usec=timeout;
 
 do
 {
  retval=select(fd_dev+1,&rfds,NULL,NULL,&tv);
  if (retval)
  {
   nread=read(fd_dev,buff,sizeof(buff));
   if (nread > 2)
   {
    buff[nread] = '\0';
    RemoveChars(buff,"\r\n");
    printf( "Recv<--%s\n\n", buff);
    nread = 0;
    memset(buff, 0, sizeof(buff));
   }
   returnvalue = 1;
  }
 }while(0 < retval);
 
 return returnvalue;
}
int main(int argc, char **argv)
{
 int baud;
 int creg_status = 0;
 char dev[32];
    int i;
 memset(dev, 0, sizeof(dev));
 if (argc < 3)
 {
  strcpy(dev, "/dev/ttySAC2");
  baud = 9600;
 }
 else
 {
  strcpy(dev, argv[1]);
  baud = atoi(argv[2]);
 }
 fd_dev = OpenDev(dev);
 if (-1 == fd_dev)
 {
  printf("Open %s Error\n", dev);
  exit (0);
 }
 set_speed(fd_dev, baud);
 if (set_Parity(fd_dev,8,1,'N') == FALSE)
 {
  printf("Set Parity Error\n");
  exit (0);
 }
 do
 {
  usleep(20);
  if((nread = read(fd_dev, buff, sizeof(buff))) > 0)
  {
   buff[nread] = '\0';
   for(i=0; i    //uart.data[i] = buff[i];
    printf("recv[%d] is 0x%x\n", i, buff[i]);
    //printf("recv[%d] is 0x%x\n", i, uart.data[i]);
   }
  }
  else
   printf("read failed!\n");
 }while(1);
 close(fd_dev);
 return 0;
}
 
 
 
 
 
 
阅读(2246) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~