Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/moduleparam.h>
- #include <linux/errno.h>
- #include <linux/types.h>
- #include <linux/proc_fs.h>
- #include <linux/fcntl.h>
- #include <linux/interrupt.h>
- #include <linux/aio.h>
- #include <linux/cdev.h>
- #include <linux/delay.h>
- #include <linux/fs.h>
- #include <linux/proc_fs.h>
- #include <linux/cdev.h>
- #include <linux/kernel.h>
- #include <linux/kdev_t.h>
- #include <linux/slab.h>
- #include <linux/sched.h>
- #include <linux/mm.h>
- #include <linux/kfifo.h>
- #include <linux/ioctl.h>
- #include <linux/ioport.h>
- #include <linux/spinlock.h>
- #include <linux/wait.h>
- #include <asm/uaccess.h>
- #include <asm/io.h>
- #include <asm/delay.h>
- #include <asm/errno.h>
- #include "serial_reg.h"
- MODULE_LICENSE("Dual BSD/GPL");
- #define PORT_UART 0x3F8
- #define PORT_RANGE 8
- #define lsr PORT_UART+UART_LSR
- #define TAMFIFO 8
- static int init(void);
- static void exit(void);
- irqreturn_t handler(int irq, void* cdevs);
- ssize_t as_read (struct file *, char __user *, size_t, loff_t *);
- ssize_t as_write (struct file *, const char __user *, size_t, loff_t *);
- int as_open (struct inode *, struct file *);
- int as_release (struct inode *, struct file *);
- void strcut(char *f, char *t, int i);
- struct seri_dev_t {
- struct cdev cdev; // struct cdev for this device
- int cnt; // number of characters written to device
- wait_queue_head_t readQ;
- wait_queue_head_t writeQ;
- struct kfifo* fr;
- struct kfifo* fw;
- spinlock_t Rlock;
- spinlock_t Wlock;
- int Rflag;
- };
- struct seri_dev_t *cdevs;
- dev_t dev;
- int status;
- struct cdev *cdp;
- struct file_operations as_fops = {
- .owner = THIS_MODULE,
- .read = as_read,
- .write = as_write,
- .open = as_open,
- .release = as_release,
- };
- irqreturn_t handler(int irq, void* cdevs){
- struct seri_dev_t* cdev = (struct seri_dev_t*) cdevs;
- unsigned m;
- char c;
- int n;
- m = inb(PORT_UART + UART_IIR); // Check who made the interrupt
- if((m & UART_IIR_THRI)&&(kfifo_len(cdev->fw)>0))
- { // something to write, write
- n = kfifo_get(cdev->fw, &c, 1);
- if(n)
- {
- outb(c, PORT_UART + UART_TX);
- wake_up_interruptible(&(cdev->writeQ));
- }
- }
- if(m & UART_IIR_RDI)
- { // If receiving, read
- c = inb(PORT_UART + UART_RX);
- kfifo_put(cdev->fr, &c, 1);
- wake_up_interruptible(&(cdev->readQ));
- }
- return IRQ_HANDLED;
- }
- static int init(void)
- {
- //Initialization UART
- int erro;
- unsigned lcr = 0, interrup=0;
- unsigned fifo=0;
- struct resource* region;
- region = request_region(PORT_UART, PORT_RANGE, "seri");
- if(region==NULL){
- printk(KERN_ALERT "ERROR ALLOCATION SPACE\n");
- return -1;
- }
- //8-bit chars, 2 stop bits, parity even, activate DLatch
- lcr = UART_LCR_WLEN8|UART_LCR_STOP|UART_LCR_EPAR|UART_LCR_DLAB;
- outb(lcr, PORT_UART+UART_LCR);
- outb(UART_DIV_1200, PORT_UART+UART_DLL); // LSB = bitrate we want
- outb(0x00, PORT_UART+UART_DLM); // MSB 8 bytes = 0
- while(!(inb(lsr) & UART_LSR_THRE)){
- schedule();
- }
- lcr &= ~UART_LCR_DLAB; // Bit from DLAB back to 0, while others remain (AND operation)
- outb(lcr, PORT_UART+UART_LCR);
- //Initialization CDEV
- printk(KERN_ALERT "CHECKING IN\n");
- alloc_chrdev_region(&dev, 0, 1, "seri");
- cdevs = kmalloc(sizeof(struct seri_dev_t), GFP_KERNEL);
- cdev_init(&(cdevs[0].cdev), &as_fops);
- cdevs[0].cdev.ops=&as_fops;
- cdevs[0].cdev.owner=THIS_MODULE;
- spin_lock_init(&(cdevs->Wlock));
- spin_lock_init(&(cdevs->Rlock));
- cdevs->fr =kfifo_alloc(TAMFIFO, GFP_KERNEL, &(cdevs->Rlock));
- cdevs->fw =kfifo_alloc(TAMFIFO, GFP_KERNEL, &(cdevs->Wlock));
- init_waitqueue_head(&(cdevs->readQ));
- init_waitqueue_head(&(cdevs->writeQ));
- if(cdev_add(&(cdevs[0].cdev), dev, 1)<0){
- printk(KERN_ALERT "ERROR ADDING CDEV!\n");
- }
- else printk(KERN_ALERT "%d\n", MAJOR(dev));
- erro = request_irq(4,handler, SA_INTERRUPT,"seri",(void*)cdevs);
- if(erro!=0){
- printk(KERN_ALERT "ERROR REQUEST IRQ\n");
- return -1;
- }
- interrup=UART_IER_THRI | UART_IER_RDI;
- outb(interrup,PORT_UART+UART_IER);
- fifo=UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14;
- outb(fifo, PORT_UART + UART_FCR);
- return 0;
- }
- static void exit(void)
- {
- kfifo_free(cdevs->fw);
- kfifo_free(cdevs->fr);
- free_irq(4, (void*) cdevs);
- release_region(PORT_UART, PORT_RANGE);
- cdev_del(&(cdevs[0].cdev));
- unregister_chrdev_region(dev, 1);
- kfree(cdevs);
- printk(KERN_ALERT "FREE\n");
- }
- int as_open (struct inode * ino, struct file * filp){
- struct seri_dev_t *edevp;
- edevp = container_of(ino->i_cdev, struct seri_dev_t, cdev);
- filp->private_data = edevp;
- printk(KERN_ALERT "OPENED\n");
- edevp->cnt=0;
- nonseekable_open(ino, filp);
- return 0;
- }
- int as_release (struct inode *ino, struct file *filp){
- printk(KERN_ALERT "RELEASED\n");
- return 0;
- }
- ssize_t as_read (struct file *filp, char __user * buff, size_t count, loff_t * f_pos){
- printk(KERN_ALERT "READING\n");
- /*O FIFO sempre a ser cheio automaticamente. Read chamado para copiar o que esta no FIFO para o buffer*/
- unsigned long err1;
- int erro, cnt=count, aux;
- char *in;
- struct seri_dev_t *cdev;
- cdev=filp->private_data;
- in = kmalloc(sizeof(char)*(cnt+1), GFP_KERNEL);
- while((aux=kfifo_len(cdevs->fr))<cnt){
- if(filp->f_flags & O_NONBLOCK)
- {
- if(kfifo_len(cdev->fr)<cnt)
- {
- kfree(in);
- printk(KERN_ALERT "O_NONBLOCK OUT\n");
- return -EAGAIN;
- }
- }
- erro=wait_event_interruptible(cdevs->readQ, ((kfifo_len(cdevs->fr))>aux));
- if(erro==-ERESTARTSYS){// CTRL-C
- printk(KERN_ALERT "WAIT OUTPUT ERROR\n");
- return -1;
- }
- }
- erro=kfifo_get(cdevs->fr, in, cnt);
- if(erro!=cnt){
- printk(KERN_ALERT "ERROR KFIFO_GET\n");
- return -1;
- }
- in[cnt]='\0';
- err1 = copy_to_user(buff, in, (cnt+1));
- if(err1 != 0){
- printk(KERN_ALERT "ERROR COPY_TO_USER\n");
- return EAGAIN;
- }
- kfree(in);
- return count;
- }
- void strcut( char * f, char * t, int ind)
- {
- int c=0;
- while(f[c+ind]!=('\0'))
- {
- t[c]=f[ind+c];
- c++;
- }
- t[c]='\0';
- c=0;
- while(f[c]!=('\0'))
- {
- f[c]=t[c];
- c++;
- }
- f[c]='\0';
- }
- ssize_t as_write (struct file *filp, const char __user *buff, size_t count, loff_t *f_pos){
- ssize_t s;
- int c, n, erro;
- char *tobuff, *aux, imp;
- struct seri_dev_t *cdev;
- cdev=filp->private_data;
- tobuff=kmalloc(sizeof(char)*count, GFP_KERNEL);
- aux=kmalloc(sizeof(char)*count,GFP_KERNEL);
- s=copy_from_user(tobuff, buff, strlen(buff));
- tobuff[count]='\0';
- if(s!=0){
- printk(KERN_ALERT "ERROR WRITING");
- return -1;
- }
- c=count+1;
- while(c>0){
- if(filp->f_flags & O_NONBLOCK)
- {
- if(kfifo_len(cdev->fw)==TAMFIFO)
- {
- kfree(tobuff);
- kfree(aux);
- printk(KERN_ALERT "O_NONBLOCK OUT\n");
- return -EAGAIN;
- }
- }
- erro=wait_event_interruptible(cdevs->writeQ, (kfifo_len(cdev->fw) < TAMFIFO));
- if(erro==-ERESTARTSYS)//CTRL-C
- {
- printk( KERN_ALERT "ERROR WRITING\n");
- return -1;
- }
- n=kfifo_put(cdev->fw, tobuff, c);
- c = c-n;
- if(c!=0)
- {
- strcut(tobuff,aux,n);
- }
- if((inb(PORT_UART + UART_LSR) & UART_LSR_THRE))//Outb estΰΈ£ΰΈ vazio, ja mandou tudo do FIFO
- {
- erro = kfifo_get(cdev->fw, &imp, 1);
- if(erro!=0)
- {
- outb(imp, PORT_UART + UART_TX);
- }
- }
- }
- printk(KERN_ALERT "WROTE %s\n", tobuff);
- s=count;
- kfree(tobuff);
- kfree(aux);
- cdevs[0].cnt=count;
- return s;
- }
- module_init(init);
- module_exit(exit);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement