EmbLogic's Blog

Serial Port Driver

Following is the code prepared by me.Only interrupt is left working on it.It is done for a loop back process.Any mistake … leave the comments

#include”header.h”

static int my_proc (char * buf, char ** start,off_t off, int count)
{
int intr_id,lsr,msr,len=0;
int baudrate,div_lacth,lcr;
#ifdef PRINT
printk(KERN_INFO “Begin : ‘%s’\n”,__func__);
#endif

intr_id = inb(SERIAL_IIR);
lsr = inb(SERIAL_LSR);
msr = inb(SERIAL_MSR);

lcr = inb(SERIAL_LCR);
outb(lcr | 0×80 , SERIAL_LCR);
div_lacth = inw(SERIAL_DLL);
outb(lcr,SERIAL_LCR);

baudrate = CLOCKRATE / div_lacth;

len = len + sprintf(buf+len, “Baudrate = %d\n”,baudrate);
len = len + sprintf(buf+len, “Data Format = %d\n”, 5+(lcr & 3));
len = len + sprintf(buf+len, “MSR = %02x\n”,msr);
len = len + sprintf(buf+len, “LSR = %02x\n”,lsr);
len = len + sprintf(buf+len, “Interrupt ID = %02x\n”,intr_id);
len = len + sprintf(buf+len, “\n”);

#ifdef PRINT
printk(KERN_INFO “Exit : ‘%s’\n”,__func__);
#endif

return len;
}

static int my_open(struct inode *inode, struct file *filp)
{

#ifdef PRINT
printk(KERN_INFO “Begin :’%s’\n”,__func__);
printk(KERN_INFO “Device_Open = %d\n”,Device_Open);
#endif

if(Device_Open)
{
#ifdef PRINT
printk(KERN_INFO “The driver is busy\n”);
#endif
return -EBUSY;
}
Device_Open ++;

//MOD_INC_USE_COUNT(THIS_MODULE);
try_module_get(THIS_MODULE);
#ifdef PRINT
printk(KERN_INFO “Exit :’%s’\n”,__func__);
#endif
return 0;
}

static int my_release(struct inode *inode, struct file *filp)
{
#ifdef PRINT
printk(KERN_INFO “Begin :’%s’\n”,__func__);
#endif

Device_Open –;
#ifdef PRINT
printk(KERN_INFO “Decrementing the value of Device_Open, new value is %d\n”,Device_Open);
#endif

//MOD_INC_COUNT(THIS_MODULE);
module_put(THIS_MODULE);
#ifdef PRINT
printk(KERN_INFO “Decrementing the count in the kernel\n”);
#endif

#ifdef PRINT
printk(KERN_INFO “Exit :’%s’\n”,__func__);
#endif
return 0;
}

int my_ioctl(struct inode *inode, struct file *filp, unsigned int request, unsigned long address)
{
int lcr,div_lacth,baudrate = 0 ;
int *there = (int *) address;
#ifdef PRINT
printk(KERN_INFO “Begin :’%s’\n”,__func__);
#endif

switch(request)
{
case IOCTL_GET_BAUDRATE:
lcr = inb(SERIAL_LCR);
outb(inb(SERIAL_LCR) | 0×80, SERIAL_LCR);
div_lacth = inw(SERIAL_DLL);
outb(lcr,SERIAL_LCR);

if(div_lacth > 0)
{
baudrate = CLOCKRATE / div_lacth;
#ifdef PRINT
printk(KERN_INFO “div_lacth = %d\n”,div_lacth);
printk(KERN_INFO “baudrate = %d\n”,baudrate);
printk(KERN_INFO “Clockrate = %d”,CLOCKRATE);
#endif
}

if(copy_to_user(there, &baudrate, 4))
{
#ifdef PRINT
#endif
return -EFAULT;
}
return 0;
break;

case IOCTL_SET_BAUDRATE:
if(copy_from_user(&baudrate, there, 4))
{
#ifdef PRINT
#endif
return -EFAULT;
}

if((baudrate CLOCKRATE))
{
#ifdef PRINT
#endif
return -EFAULT;
}

div_lacth = CLOCKRATE / baudrate;
lcr = inb(SERIAL_LCR);
outb(inb(SERIAL_LCR)| 0×80, SERIAL_LCR);
outw(div_lacth,SERIAL_DLL);
outb(lcr,SERIAL_LCR);
return 0;
break;
}

#ifdef PRINT
printk(KERN_INFO “Exit :’%s’\n”,__func__);
#endif
return -EINVAL;
}

ssize_t my_read(struct file *filp, char *buf, size_t len, loff_t *pos)
{
unsigned char data;
int count,i,lsr;
#ifdef PRINT
printk(KERN_INFO “Begin :’%s’\n”,__func__);
#endif

lsr = inb(SERIAL_LSR);
#ifdef PRINT
printk(KERN_INFO “The LSR status is %04x\n”,lsr);
printk(KERN_INFO “The LSR status is %04x\n”,inb(SERIAL_LSR));
#endif

if((lsr & 0×01) == 0)
{
if(filp->f_flags & O_NONBLOCK)
{
#ifdef PRINT
printk(KERN_INFO “A NONBLOCK flag is on, exiting now\n”);
#endif
return 0;
}
}

count = 0;

for (i=0;if_flags & O_NONBLOCK)
#ifdef PRINT
printk(KERN_INFO “A NONBLOCK flag is on, exiting now\n”);
#endif
return 0;
}
count = 0;

for(i=0;i<len;i++)
{
if(copy_from_user(&data,buf+i,1))
{
#ifdef PRINT
printk(KERN_INFO "Unable to read macro failed\n");
#endif
return -EFAULT;
}

while((inb(SERIAL_LSR) & 0×20) == 0×00);
outb(data,SERIAL_TX_REG);
++count;

if((inb(SERIAL_MASK) & 0×01) != 0×01)
{
#ifdef PRINT
printk(KERN_INFO "the writer is not sending data to reciver\n");
#endif
break;
}
}
#ifdef PRINT
printk(KERN_INFO "Exit :'%s'\n",__func__);
#endif
return count;
}

static dev_t serial_setup_cdev (struct serial_dev *ldev , int i)
{
dev_t ldevno;
int result;
#ifdef PRINT
printk(KERN_INFO "Begin :'%s'\n",__func__);
#endif
ldevno = MKDEV(serial_major,serial_minor);
cdev_init(&ldev[i].cdev,&fops);
ldev[i].cdev.owner = THIS_MODULE;
ldev[i].cdev.ops = &fops;
result = cdev_add(&ldev[i].cdev,ldevno,ndevice);
#ifdef PRINT
printk(KERN_INFO "result = %d\n",result);
printk(KERN_INFO "device no : %d\t,minor number = %d\n",i,serial_minor);
#endif

serial_minor++;

#ifdef PRINT
printk(KERN_INFO "Exit :'%s'\n",__func__);
#endif
return 0;
}

static int __init my_init(void)
{
int ret,i;
#ifdef PRINT
printk(KERN_INFO "Begin :'%s'\n",__func__);
#endif

#ifdef PRINT
//printk(KERN_INFO "Current value of jiffies is %ld\n",j1);
printk(KERN_INFO "Major = %d\tMinor = %d\n",serial_major,serial_minor);
#endif

if(serial_major)
{
devno = MKDEV(serial_major,serial_minor);
ret = register_chrdev_region(devno, ndevice, device_name);
}
else
{
ret = alloc_chrdev_region(&devno, serial_minor, ndevice, device_name);
serial_major = MAJOR(devno);
#ifdef PRINT
printk(KERN_INFO "Major number allocated is %d\n",serial_major);
#endif
}

if(ret comm,current->pid);
#endif

if(serial_major)
{
serial_dev = (struct serial_dev *) kmalloc (sizeof(struct serial_dev),GFP_KERNEL);
if(!serial_dev)
{
#ifdef PRINT
printk(KERN_WARNING “Unable to allocate the memory for the device\n”);
#endif
return -ENOMEM;
}
#ifdef PRINT
printk(KERN_WARNING “allocate the memory for the device\n”);
#endif
memset(serial_dev, 0, sizeof(struct serial_dev));

for(i=0;icomm,current->pid);
#endif

//changing the register
#ifdef PRINT
printk(KERN_INFO “Setting the default values to the register…now\n”);
#endif

outb(0×00,SERIAL_IER); //disable the IER
outb(0×00,SERIAL_FIFO); //disable the FIFO
outb(0×00,SERIAL_MCR); //MCR = 0

#ifdef PRINT
printk(KERN_INFO “Setting the default values to the register done successfully\n”);
#endif

#ifdef PRINT
printk(KERN_INFO “Exit :’%s’\n”,__func__);
#endif
}

module_init(my_init);
module_exit(my_exit);

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>