#include <linux/init.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/interrupt.h>
#include <asm/system.h>
#include <asm/irq.h>
#include <linux/delay.h>
#include <linux/string.h>
#include "serial.h"
MODULE_AUTHOR("Felixls");
MODULE_LICENSE("Dual BSD/GPL");
int ser_busy = SER_FREE;
static int ser_open(struct inode * inode, struct file * file)
{
  int codigo;
  unsigned int minor = MINOR(inode->i_rdev);
  printk(KERN_ALERT " SER: opening...\n");
  if (minor != 0)
    return -ENODEV;
  
  if (ser_busy==SER_BUSY) 
    return -EBUSY; 
      
  printk (KERN_ALERT "SER: serial abierto.\n");
  outb(0x80, SER_BASE + 3);  // Set DLAB ON
  outb(0x0C, SER_BASE + 0);  // Set Baud rate DL low (9600)  (DLL) 0x0C
  /* 0x01 = 115.200 BPS */
  /* 0x02 =  57.600 BPS */
  /* 0x03 =  38.400 BPS */
  /* 0x06 =  19.200 BPS */
  /* 0x0C =   9.600 BPS */
  /* 0x18 =   2.400 BPS */
  outb(0x00, SER_BASE + 1);  // Set Baud rate DL high        (DLM)
  outb(0x03, SER_BASE + 3);  // 8bits, No Parity, 1 Stop bit (LCR)
  outb(0xC7, SER_BASE + 2);  // Enable FIFO Control Register (FCR)
  outb(0x0B, SER_BASE + 4);  // Turn on DTR, RTS             (MCR)
  ser_busy = SER_BUSY;
  return 0;
}
int serial_recieved()
{
  return inb(SER_IN + 5) & 1;
}
int is_transmit_empty()
{
  return inb(SER_IN + 5) & 0x20;
}
static ssize_t ser_read (struct file *file, char *buf, size_t count, loff_t *nose)
{
  int i, c;
  int readed = 0;
  int timeout = 100;
  char *readbuffer;
  readbuffer = kmalloc(count, GFP_KERNEL);
  for(i = 0; i < count; i++)
  {
    c = 0;
    while (serial_recieved() == 0 && c < timeout)
    {
      msleep(1);
      c++;
      continue;
    }
    if (c >= timeout) break;
    readbuffer[i] = inb(SER_IN);
    readed++;
  }
  if (readed > 0)
    __copy_to_user(buf, readbuffer, readed);
  kfree(readbuffer);
  if (readed == 0 && c >= timeout)
    return -EINTR;
  return readed;
}
static ssize_t ser_write(struct file *file, const char *buf,size_t count, loff_t *nose) 
{
  char *writebuffer;
  int i;
  writebuffer = kmalloc(count, GFP_KERNEL);
  __copy_from_user(writebuffer, buf, count);
  int written = 0;
  for(i=0; i<count; i++)
  {
    while (is_transmit_empty()==0) 
    {
      msleep(1);
      continue; 
    }
    outb(writebuffer[i], SER_OUT);
    written++;
  }
  kfree(writebuffer);
  return written;
}
static int ser_release (struct inode *inode, struct file *file)
{
  ser_busy = SER_FREE;
  printk (KERN_ALERT "SER: serial cerrado.\n");
  return 0;
}
struct file_operations ser_fops=
{
  .owner =   THIS_MODULE,
  .read  =   ser_read,
  .write =   ser_write,
  .open  =   ser_open,
  .release = ser_release,
};
static int serial_init(void)
{
  if (register_chrdev(SER_MAYOR, "ser", &ser_fops))
  {
    printk(KERN_ALERT "ERROR: init_module ha fallado instalando SER driver...\n");
    return -EIO;
  }
  printk(KERN_ALERT "modulo instalado!\n");
  return 0;
}
static void serial_exit(void)
{
  if (ser_busy)
  {
    printk(KERN_ALERT "WARNG: SER driver ocupado, no se pudo remover....\n");
    return;
  }
  if (unregister_chrdev(SER_MAYOR,"ser") != 0)
    printk(KERN_ALERT "ERROR: cleanup_module ha fallado, no se puede desregistrar SER deiver...\n");
  else
    printk(KERN_ALERT "modulo desinstalado!\n");
}
module_init(serial_init);
module_exit(serial_exit);
miércoles, abril 26, 2006
Suscribirse a:
Comentarios de la entrada (Atom)
No hay comentarios.:
Publicar un comentario
Nota: sólo los miembros de este blog pueden publicar comentarios.