📄 8253xchr.c
字号:
/* -*- linux-c -*- *//* * Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * **/#include <linux/module.h>#include <linux/kernel.h>#include <linux/pci.h>#include <linux/stddef.h>#include <linux/string.h>#include <linux/sockios.h>#include <asm/io.h>#include <asm/byteorder.h>#include <asm/pgtable.h>#include <linux/skbuff.h>#include <linux/if_arp.h>#include <linux/fs.h>#include <linux/sched.h>#include <asm/uaccess.h>#include <linux/version.h>#include <linux/etherdevice.h>#include <linux/poll.h>#include "Reg9050.h"#include "8253xctl.h"#include "ring.h"#include "8253x.h"#include "crc32dcl.h"/* a raw character driver -- theoretically for implementing custom protocols, * async interrupts can be used for getting indication that a packet has * been successfully transmitted. */ /* the application read routine, can block according */ /* to flag, returns one packet at a time */int sab8253xc_read(struct file *filep, char *cptr, size_t cnt, loff_t *loffp){ unsigned int length; unsigned long flags; SAB_PORT *port = filep->private_data; struct sk_buff *skb; DEBUGPRINT((KERN_ALERT "Attempting to read %i bytes.\n", cnt)); if(port->sab8253xc_rcvbuflist == NULL) { return -ENOMEM; } save_flags(flags); cli(); if(skb_queue_len(port->sab8253xc_rcvbuflist) == 0) { port->rx_empty = 1; if(filep->f_flags & O_NONBLOCK) { restore_flags(flags); return -EAGAIN; } restore_flags(flags); interruptible_sleep_on(&port->read_wait); } else { restore_flags(flags); } skb = skb_peek(port->sab8253xc_rcvbuflist); length = skb->tail - skb->data; if(cnt < length) { return -ENOMEM; } skb = skb_dequeue(port->sab8253xc_rcvbuflist); save_flags(flags); cli(); if(skb_queue_len(port->sab8253xc_rcvbuflist) <= 0) { port->rx_empty = 1; } restore_flags(flags); DEBUGPRINT((KERN_ALERT "Copying to user space %s.\n", skb->data)); copy_to_user(cptr, skb->data, length); dev_kfree_skb_any(skb); return length;}/* application write */int sab8253xc_write(struct file *filep, const char *cptr, size_t cnt, loff_t *loffp){ struct sk_buff *skb; unsigned long flags; SAB_PORT *port = filep->private_data; if(cnt > sab8253xc_rbufsize) /* should not send bigger than can be received */ { return -ENOMEM; } if(port->active2.transmit == NULL) { return -ENOMEM; } save_flags(flags); cli(); /* can block on write when */ /* no space in transmit circular */ /* array. */ if((port->active2.transmit->Count & OWNER) == OWN_SAB) { ++(port->Counters.tx_drops); port->tx_full = 1; restore_flags(flags); if(filep->f_flags & O_NONBLOCK) { return -EAGAIN; } interruptible_sleep_on(&port->write_wait); } else { restore_flags(flags); } #ifndef FREEINTERRUPT if((port->active2.transmit->HostVaddr != NULL) || /* not OWN_SAB from above */ (port->active2.transmit->crcindex != 0)) { register RING_DESCRIPTOR *freeme; freeme = port->active2.transmit; do { if((freeme->crcindex == 0) && (freeme->HostVaddr == NULL)) { break; } if(freeme->HostVaddr) { skb_unlink((struct sk_buff*)freeme->HostVaddr); dev_kfree_skb_any((struct sk_buff*)freeme->HostVaddr); freeme->HostVaddr = NULL; } freeme->sendcrc = 0; freeme->crcindex = 0; freeme = (RING_DESCRIPTOR*) freeme->VNext; } while((freeme->Count & OWNER) != OWN_SAB); }#endif skb = alloc_skb(cnt, GFP_KERNEL); /* not called from int as with tty */ if(skb == NULL) { return -ENOMEM; } copy_from_user(skb->data, cptr, cnt); skb->tail = (skb->data + cnt); skb->len = cnt; skb->data_len = cnt; skb_queue_head(port->sab8253xbuflist, skb); port->active2.transmit->HostVaddr = skb; port->active2.transmit->sendcrc = 0; port->active2.transmit->crcindex = 0; port->active2.transmit->Count = (OWN_SAB|cnt); /* must be this order */ port->active2.transmit = (RING_DESCRIPTOR*) port->active2.transmit->VNext; port->Counters.transmitbytes += cnt; sab8253x_start_txS(port); return cnt;}static void sab8253x_receive_charsC(struct sab_port *port, union sab8253x_irq_status *stat){ unsigned char buf[32]; int free_fifo = 0; int reset_fifo = 0; int msg_done = 0; int msg_bad = 0; int count = 0; int total_size = 0; int rstatus = 0; struct sk_buff *skb; /* Read number of BYTES (Character + Status) available. */ if((stat->images[ISR1_IDX] & SAB82532_ISR1_RDO) || (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) ) { ++msg_bad; ++free_fifo; ++reset_fifo; } else { if (stat->images[ISR0_IDX] & SAB82532_ISR0_RPF) { count = port->recv_fifo_size; ++free_fifo; } if (stat->images[ISR0_IDX] & SAB82532_ISR0_RME) { count = READB(port, rbcl); count &= (port->recv_fifo_size - 1); ++msg_done; ++free_fifo; total_size = READB(port, rbch); if(total_size & SAB82532_RBCH_OV) /* need to revisit for 4096 byte frames */ { msg_bad++; } rstatus = READB(port, rsta); if((rstatus & SAB82532_RSTA_VFR) == 0) { msg_bad++; } if(rstatus & SAB82532_RSTA_RDO) { msg_bad++; } if((rstatus & SAB82532_RSTA_CRC) == 0) { msg_bad++; } if(rstatus & SAB82532_RSTA_RAB) { msg_bad++; } } } /* Read the FIFO. */ (*port->readfifo)(port, buf, count); /* Issue Receive Message Complete command. */ if (free_fifo) { sab8253x_cec_wait(port); WRITEB(port, cmdr, SAB82532_CMDR_RMC); } if(reset_fifo) { sab8253x_cec_wait(port); WRITEB(port, cmdr, SAB82532_CMDR_RHR); } if(msg_bad) { port->msgbufindex = 0; return; } memcpy(&port->msgbuf[port->msgbufindex], buf, count); port->msgbufindex += count; if(msg_done) { if(port->msgbufindex <= 3) /* min is 1 char + 2 CRC + status byte */ { port->msgbufindex = 0; return; } total_size = port->msgbufindex - 3; /* strip off the crc16 and the status byte */ port->msgbufindex = 0; /* ignore the receive buffer waiting -- we know the correct size here */ if(skb = dev_alloc_skb(total_size), skb) { memcpy(skb->data, &port->msgbuf[0], total_size); skb->tail = (skb->data + total_size); skb->data_len = total_size; skb->len = total_size; skb_queue_tail(port->sab8253xc_rcvbuflist, skb); if(port->rx_empty) { port->rx_empty = 0; wake_up_interruptible(&port->read_wait); } if(port->async_queue) { kill_fasync(&port->async_queue, SIGIO, POLL_IN); } } }}static void sab8253x_check_statusC(struct sab_port *port, union sab8253x_irq_status *stat){ int modem_change = 0; mctlsig_t *sig; if (stat->images[ISR0_IDX] & SAB82532_ISR0_RFO) { port->icount.buf_overrun++; } /* Checking DCD */ sig = &port->dcd; if (stat->images[sig->irq] & sig->irqmask) { sig->val = ISON(port,dcd); port->icount.dcd++; modem_change++; } /* Checking CTS */ sig = &port->cts; if (stat->images[sig->irq] & sig->irqmask) { sig->val = ISON(port,cts); port->icount.cts++; modem_change++; } /* Checking DSR */ sig = &port->dsr; if (stat->images[sig->irq] & sig->irqmask) { sig->val = ISON(port,dsr); port->icount.dsr++; modem_change++; } if (modem_change) { wake_up_interruptible(&port->delta_msr_wait); } sig = &port->dcd; if ((port->flags & FLAG8253X_CHECK_CD) && (stat->images[sig->irq] & sig->irqmask)) { if (sig->val) { wake_up_interruptible(&port->open_wait); /* in case waiting in block_til_ready */ } else if (!((port->flags & FLAG8253X_CALLOUT_ACTIVE) && (port->flags & FLAG8253X_CALLOUT_NOHUP))) { /* I think the code needs to walk through all the proces that have opened this * port and send a SIGHUP to them -- need to investigate somewhat more*/ } }}static int sab8253x_startupC(struct sab_port *port){ unsigned long flags; int retval = 0; save_flags(flags); cli(); if (port->flags & FLAG8253X_INITIALIZED) { goto errout; } if (!port->regs) { retval = -ENODEV; goto errout; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -