/* -*- linux-c -*- */ /* $Id: 8253xutl.c,v 1.3 2002/02/10 22:17:26 martillo Exp $ * 8253xutl.c: SYNC TTY Driver for the SIEMENS SAB8253X DUSCC. * * Implementation, modifications and extensions * 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. */ /* Standard in kernel modules */ #define DEFINE_VARIABLE #include /* Specifically, a module */ #include #include #include #include #include #include #include #include #include "8253xctl.h" #include "8253x.h" #include #include #include "sp502.h" #ifdef MODULE #undef XCONFIG_SERIAL_CONSOLE #endif void sab8253x_start_txS(struct sab_port *port) { unsigned long flags; register int count; register int total; register int offset; char temporary[32]; register unsigned int slopspace; register int sendsize; unsigned int totaltransmit; unsigned fifospace; unsigned loadedcount; struct tty_struct *tty = port->tty; /* a little gross tty flags whether invoked from a tty or the network */ fifospace = port->xmit_fifo_size; /* This code can handle fragmented frames although currently none are generated*/ loadedcount = 0; if(port->sabnext2.transmit == NULL) { return; } save_flags(flags); cli(); if(count = port->sabnext2.transmit->Count, (count & OWNER) == OWN_SAB) { count &= ~OWN_SAB; /* OWN_SAB is really 0 but cannot guarantee in the future */ if(port->sabnext2.transmit->HostVaddr) { total = (port->sabnext2.transmit->HostVaddr->tail - port->sabnext2.transmit->HostVaddr->data); /* packet size */ } else { total = 0; /* the data is only the crc/trailer */ } if(tty && (tty->stopped || tty->hw_stopped) && (count == total)) { /* works for frame that only has a trailer (crc) */ port->interrupt_mask1 |= SAB82532_IMR1_XPR; WRITEB(port, imr1, port->interrupt_mask1); restore_flags(flags); /* can't send */ return; } offset = (total - count); /* offset to data still to send */ port->interrupt_mask1 &= ~(SAB82532_IMR1_ALLS); WRITEB(port, imr1, port->interrupt_mask1); port->all_sent = 0; if(READB(port,star) & SAB82532_STAR_XFW) { if(count <= fifospace) { port->xmit_cnt = count; slopspace = 0; sendsize = 0; if(port->sabnext2.transmit->sendcrc) /* obviously should not happen for async but might use for priority transmission */ { slopspace = fifospace - count; } if(slopspace) { if(count) { memcpy(temporary, &port->sabnext2.transmit->HostVaddr->data[offset], count); } sendsize = MIN(slopspace, (4 - port->sabnext2.transmit->crcindex)); /* how many bytes to send */ memcpy(&temporary[count], &((unsigned char*)(&port->sabnext2.transmit->crc)) [port->sabnext2.transmit->crcindex], sendsize); port->sabnext2.transmit->crcindex += sendsize; if(port->sabnext2.transmit->crcindex >= 4) { port->sabnext2.transmit->sendcrc = 0; } port->xmit_buf = temporary; } else { port->xmit_buf = /* set up wrifefifo variables */ &port->sabnext2.transmit->HostVaddr->data[offset]; } port->xmit_cnt += sendsize; count = 0; } else { count -= fifospace; port->xmit_cnt = fifospace; port->xmit_buf = /* set up wrifefifo variables */ &port->sabnext2.transmit->HostVaddr->data[offset]; } port->xmit_tail= 0; loadedcount = port->xmit_cnt; (*port->writefifo)(port); totaltransmit = Sab8253xCountTransmitDescriptors(port); if(tty && (totaltransmit < (sab8253xs_listsize/2))) /* only makes sense on a TTY */ { sab8253x_sched_event(port, SAB8253X_EVENT_WRITE_WAKEUP); } if((sab8253xt_listsize - totaltransmit) > (sab8253xt_listsize/2)) { port->buffergreedy = 0; } else { port->buffergreedy = 1; } port->xmit_buf = NULL; /* this var is used to indicate whether to call kfree */ /* fifospace -= loadedcount;*/ /* Here to make mods to handle arbitrarily fragmented frames look to 8253xtty.c for help */ if ((count <= 0) && (port->sabnext2.transmit->sendcrc == 0)) { port->sabnext2.transmit->Count = OWN_DRIVER; if(!tty) { /* called by network driver */ ++(port->Counters.transmitpacket); } #ifdef FREEININTERRUPT /* treat this routine as if taking place in interrupt */ if(port->sabnext2.transmit->HostVaddr) { skb_unlink(port->sabnext2.transmit->HostVaddr); dev_kfree_skb_any(port->sabnext2.transmit->HostVaddr); port->sabnext2.transmit->HostVaddr = 0; /* no skb */ } port->sabnext2.transmit->crcindex = 0; /* no single byte */ #endif sab8253x_cec_wait(port); WRITEB(port, cmdr, SAB82532_CMDR_XME|SAB82532_CMDR_XTF); /* Terminate the frame */ port->sabnext2.transmit = port->sabnext2.transmit->VNext; if(!tty && port->tx_full) /* invoked from the network driver */ { port->tx_full = 0; /* there is a free slot */ switch(port->open_type) { case OPEN_SYNC_NET: #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0) port->dev->start = 1; port->dev->tbusy = 0; /* maybe need mark_bh here */ #else netif_start_queue(port->dev); #endif break; case OPEN_SYNC_CHAR: wake_up_interruptible(&port->write_wait); break; default: break; } } if((port->sabnext2.transmit->Count & OWNER) == OWN_SAB) { /* new frame to send */ port->interrupt_mask1 &= ~(SAB82532_IMR1_XPR); WRITEB(port, imr1, port->interrupt_mask1); } else { port->interrupt_mask1 |= SAB82532_IMR1_XPR; WRITEB(port, imr1, port->interrupt_mask1); if((port->open_type == OPEN_SYNC_CHAR) && port->async_queue) { /* if indication of transmission is needed by the */ /* application on a per-frame basis kill_fasync */ /* can provide it */ kill_fasync(&port->async_queue, SIGIO, POLL_OUT); } } restore_flags(flags); return; } /* Issue a Transmit FIFO command. */ sab8253x_cec_wait(port); WRITEB(port, cmdr, SAB82532_CMDR_XTF); port->sabnext2.transmit->Count = (count|OWN_SAB); } port->interrupt_mask1 &= ~(SAB82532_IMR1_XPR); /* more to send */ WRITEB(port, imr1, port->interrupt_mask1); } else { /* nothing to send */ port->interrupt_mask1 |= SAB82532_IMR1_XPR; WRITEB(port, imr1, port->interrupt_mask1); } restore_flags(flags); return; } void sab8253x_transmit_charsS(struct sab_port *port, union sab8253x_irq_status *stat) { if (stat->sreg.isr1 & SAB82532_ISR1_ALLS) { port->interrupt_mask1 |= SAB82532_IMR1_ALLS; WRITEB(port, imr1, port->interrupt_mask1); port->all_sent = 1; } sab8253x_start_txS(port); } /* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ /*************************************************************************** * sab_baudenh: Function to compute the "enhanced" baudrate. * * * Parameters : * encbaud 2* the baudrate. We use the * double value so as to support 134.5 (in only) * clkspeed The board clock speed in Hz. * bgr Value of reg BGR for baudrate(output) * ccr2 Value of reg // CCR2 for baudrate (output) * ccr4 Value of reg CCR4 for baudrate (output) * truebaud The actual baudrate achieved (output). * * * Return value : Return FALSE the parameters could not be computed, * * Prerequisite : The various ports must have been initialized * * Remark : Stolen from the Aurora ase driver. * * Author : fw * * Revision : Oct 9 2000, creation ***************************************************************************/ /* * Macro to check to see if the high n bits of the given unsigned long * are zero. */ #define HIZERO(x, n) ( ((unsigned long) ((x) << (n)) >> (n)) == (x)) /* form an n-bit bitmask */ #define NBM(n) (~(((~(unsigned long) 0) >> (n)) << (n))) /* shift x by y bits to right, rounded */ #define ROUND_SHIFT(x, y) (((unsigned long) (x) + (NBM(y - 1) + 1)) >> (y)) /* perform rounded division */ #define ROUND_DIV(x, y) (((x) + ((y) >> 1)) / (y)) #define ABSDIF(x, y) ((x) > (y) ? ((x) - (y)) : ((y) - (x))) static unsigned int sab8253x_baudenh(unsigned long encbaud, unsigned long clk_speed, unsigned char *bgr, unsigned char *ccr2, unsigned long *truebaudp) { register unsigned short tmp; register unsigned char ccr2tmp; unsigned long power2, mant; unsigned int fastclock; if (encbaud == 0) { return FALSE; } /* * Keep dividing quotien by two until it is between the value of 1 and 64, * inclusive. */ fastclock = (clk_speed >= 10000000); /* >= 10 MHz */ for (power2 = 0; power2 < 16; power2++) { /* divisor = baud * 2^M * 16 */ if (!HIZERO(encbaud, power2 + 3)) { if (!HIZERO(encbaud, power2)) { /* baud rate still too big? */ mant = ROUND_DIV(ROUND_SHIFT(clk_speed, power2 + 3), encbaud); /* mant = (clk_speed / (8 * 2^M)) / (baud * 2) */ /* = clk_speed / (baud * 16 * 2^M) */ } else { mant = ROUND_DIV(ROUND_SHIFT(clk_speed, 3), encbaud << power2); /* mant = (clk_speed / 8) / (baud * 2 * 2^M) */ /* = clk_speed / (baud * 16 * 2^M) */ } } else { mant = ROUND_DIV(clk_speed, encbaud << (power2 + 3)); /* mant = clk_speed / (baud * 2 * 8 * 2^M) */ /* = clk_speed / (baud * 16 * 2^M) */ } /* mant = clk_speed / (baud * 2^M * 16) */ if (mant < 2 || (mant <= 64 && (!fastclock || power2 != 0))) { break; } } /* * Did we not succeed? (Baud rate is too small) */ if (mant > 64) { return FALSE; } /* * Now, calculate the true baud rate. */ if (mant < 1 || (mant == 1 && power2 == 0)) { /* bgr and ccr2 should be initialized to 0 */ *truebaudp = ROUND_SHIFT(clk_speed, 4); } else { *truebaudp = ROUND_DIV(clk_speed, mant << (4 + power2)); /* divisor is not zero because mant is [1, 64] */ mant--; /* now [0, 63] */ /* * Encode the N and M values into the bgr and ccr2 registers. */ tmp = ((unsigned short) mant) | ((unsigned short) power2 << 6); ccr2tmp = SAB82532_CCR2_BDF; if ((tmp & 0x200) != 0) { ccr2tmp |= SAB82532_CCR2_BR9; } if ((tmp & 0x100) != 0) { ccr2tmp |= SAB82532_CCR2_BR8; } *ccr2 = ccr2tmp | (*ccr2 & ~(SAB82532_CCR2_BDF|SAB82532_CCR2_BR8|SAB82532_CCR2_BR9)); *bgr = (unsigned char) tmp; } return TRUE; } /* * Calculate the standard mode baud divisor using an integral algorithm. */ /*************************************************************************** * sab_baudstd: Function to compute the "standard " baudrate. * * * Parameters : * encbaud 2* the baudrate. We use the * double value so as to support 134.5 (in only) * clkspeed The board clock speed in Hz. * bgr Value of reg BGR for baudrate(output) * ccr2 Value of reg CCR2 for baudrate (output) * ccr4 Value of reg CCR4 for baudrate (output) * truebaud The actual baudrate achieved (output). * * * Return value : Return FALSE the parameters could not be computed, * * Prerequisite : The various ports must have been initialized * * Remark : Stolen from the Aurora ase driver. * * Author : fw * * Revision : Oct 9 2000, creation ***************************************************************************/ static unsigned int sab8253x_baudstd(unsigned long encbaud, unsigned long clk_speed, unsigned char *bgr, unsigned char *ccr2, unsigned long *truebaudp) { register unsigned short quot; register unsigned char ccr2tmp; if (encbaud == 0) { return FALSE; } /* * This divisor algorithm is a little strange. The * divisors are all multiples of 2, except for the * magic value of 1. * * What we do is do most of the algorithm for multiples * of 1, and then switch at the last minute to multiples * of 2. */ /* * Will we lose any information by left shifting encbaud? * If so, then right shift clk_speed instead. */ if (!HIZERO(encbaud, 3)) { quot = (unsigned short) ROUND_DIV(ROUND_SHIFT(clk_speed, 3), encbaud); /* quot = (clk_speed / 8) / (baud * 2) = clk_speed / (16 * baud) */ } else { /* encbaud isn't a multiple of 2^29 (baud not mult. of 2^28) */ quot = (unsigned short) ROUND_DIV(clk_speed, encbaud << 3); } /* quot = clk_speed / (baud * 16) */ if (quot < 2) { /* bgr and ccr2 should be initialized to 0 */ *truebaudp = ROUND_SHIFT(clk_speed, 4); return TRUE; } /* * Divide the quotient by two. */ quot = ROUND_SHIFT(quot, 1); if (quot <= 0x400) { /* quot = [1, 0x400] -> (quot << 5) != 0 */ *truebaudp = ROUND_DIV(clk_speed, ((unsigned long) quot << 5)); quot--; ccr2tmp = SAB82532_CCR2_BDF; if ((quot & 0x200) != 0) { ccr2tmp |= SAB82532_CCR2_BR9; } if ((quot & 0x100) != 0) { ccr2tmp |=SAB82532_CCR2_BR8; } *ccr2 = ccr2tmp | (*ccr2 & ~(SAB82532_CCR2_BDF|SAB82532_CCR2_BR8|SAB82532_CCR2_BR9)); *bgr = (unsigned char) quot; } else { /* the baud rate is too small. */ return FALSE; } return TRUE; } /*************************************************************************** * sab_baud: Function to compute the best register value to achieve * a given baudrate. * * * Parameters : * port: The port being used (in only) * encbaud: 2* the baudrate. We use the * double value so as to support 134.5 (in only) * bgr Value of reg BGR for baudrate(output) * ccr2 Value of reg CCR2 for baudrate (output) * ccr4 Value of reg CCR4 for baudrate (output) * truebaud The actual baudrate achieved (output). * * * Return value : Return TRUE if the vaudrate can be set, FALSE otherwise * * Prerequisite : The various ports must have been initialized * * Remark : Stolen from the Aurora ase driver. * * Author : fw * * Revision : Oct 9 2000, creation ***************************************************************************/ unsigned int sab8253x_baud(sab_port_t *port, unsigned long encbaud, unsigned char *bgr, unsigned char *ccr2, unsigned char *ccr4, unsigned long *truebaudp) { unsigned char bgr_std, bgr_enh, ccr2_std, ccr2_enh, ccr4_enh; unsigned int ok_std, ok_enh; unsigned long truebaud_std, truebaud_enh, truebaud,clkspeed; bgr_std = bgr_enh = 0; ccr2_std = ccr2_enh = 0; ccr4_enh = 0; /* * the port/chip/board structure will tell us: * 1) clock speed * 2) chip revision (to figure out if the enhanced method is * available. */ clkspeed = port->chip->c_cim ? port->chip->c_cim->ci_clkspeed : port->board->b_clkspeed; #ifdef NODEBUGGING printk("With clk speed %ld, baud rate = %ld\n",clkspeed, encbaud); #endif ok_std = sab8253x_baudstd(encbaud, clkspeed, &bgr_std, &ccr2_std, &truebaud_std); #ifdef NODEBUGGING printk("Std gives bgr = 0x%x, ccr2=0x%x for speed %ld\n",bgr_std,ccr2_std,truebaud_std); #endif if(port->chip->c_revision >= SAB82532_VSTR_VN_3_2) { ok_enh = sab8253x_baudenh(encbaud, clkspeed, &bgr_enh, &ccr2_enh, &truebaud_enh); #ifdef NODEBUGGING printk("Enh gives bgr = 0x%x, ccr2=0x%x for speed %ld\n",bgr_enh,ccr2_enh,truebaud_enh); #endif } else ok_enh = FALSE; /* * Did both methods return values? */ if (ok_std && ok_enh) { /* * Find the closest of the two. */ if (ABSDIF((truebaud_enh<<1), encbaud) < ABSDIF((truebaud_std<<1), encbaud)) { ok_std = FALSE; } else { ok_enh = FALSE; } } /* * Now return the values. */ if (ok_std || ok_enh) { truebaud = ok_std ? truebaud_std : truebaud_enh; /* * If the true baud rate is off by more than 5%, then * we don't support it. */ if (ROUND_DIV(ABSDIF((truebaud<<1), encbaud), encbaud) != 0) { /* * We're not even in the right ballpark. This * test is here to deal with overflow conditions. */ return FALSE; } else if (ROUND_DIV(ABSDIF((truebaud<<1), encbaud) * 100, encbaud) >= 5) { return FALSE; } *truebaudp = truebaud; if (ok_enh) { *ccr4 |= SAB82532_CCR4_EBRG; *ccr2 = ccr2_enh; *bgr = bgr_enh; #ifdef DEBUGGING printk("Enhanced Baud at %ld, ccr4 = 0x%x, ccr2 = 9x%x, bgr = 0x%x\n", truebaud,*ccr4,*ccr2,*bgr); #endif } else { *ccr4 &= ~SAB82532_CCR4_EBRG; *ccr2 = ccr2_std; *bgr = bgr_std; #ifdef DEBUGGING printk("Standard Baud at %ld, ccr4 = 0x%x, ccr2 = 9x%x, bgr = 0x%x\n", truebaud,*ccr4,*ccr2,*bgr); #endif } return TRUE; } else { return FALSE; } } int Sab8253xCountTransmit(SAB_PORT *port) { register RING_DESCRIPTOR *rd; register int total; register int count; unsigned long flags; RING_DESCRIPTOR *start; if(port->sabnext2.transmit == NULL) { return 0; } save_flags(flags); cli(); rd = port->sabnext2.transmit; start = rd; total = 0; while(1) { count = rd->Count; if((count & OWNER) == OWN_DRIVER) { break; } total += (count & ~OWNER); if(rd->sendcrc) { total += (4 - rd->crcindex); } rd = rd->VNext; if(rd == start) { break; } } restore_flags(flags); return total; } int Sab8253xCountTransmitDescriptors(SAB_PORT *port) { register RING_DESCRIPTOR *rd; register int total; register int count; unsigned long flags; RING_DESCRIPTOR *start; if(port->sabnext2.transmit == NULL) { return 0; } save_flags(flags); cli(); rd = port->sabnext2.transmit; start = rd; total = 0; while(1) { count = rd->Count; if((count & OWNER) == OWN_DRIVER) { break; } ++total; rd = rd->VNext; if(rd == start) { break; } } restore_flags(flags); return total; } int getccr0configS(struct sab_port *port) { return port->ccontrol.ccr0; } int getccr1configS(struct sab_port *port) { return port->ccontrol.ccr1; } int getccr2configS(struct sab_port *port) { return port->ccontrol.ccr2; } int getccr3configS(struct sab_port *port) { return port->ccontrol.ccr3; } int getccr4configS(struct sab_port *port) { return port->ccontrol.ccr4; } int getrlcrconfigS(struct sab_port *port) { return port->ccontrol.rlcr; } int getmodeS(struct sab_port *port) { return port->ccontrol.mode; } void sab8253x_init_lineS(struct sab_port *port) { unsigned char stat; if(port->chip->c_cim) { if(port->chip->c_cim->ci_type == CIM_SP502) { aura_sp502_program(port, SP502_OFF_MODE); } } /* * Wait for any commands or immediate characters */ sab8253x_cec_wait(port); #if 0 sab8253x_tec_wait(port); /* I have to think about this one * should I assume the line was * previously in async mode*/ #endif /* * Clear the FIFO buffers. */ WRITEB(port, cmdr, SAB82532_CMDR_RHR); sab8253x_cec_wait(port); WRITEB(port,cmdr,SAB82532_CMDR_XRES); /* * Clear the interrupt registers. */ stat = READB(port, isr0); /* acks ints */ stat = READB(port, isr1); /* * Now, initialize the UART */ WRITEB(port, ccr0, 0); /* power-down */ WRITEB(port, ccr0, getccr0configS(port)); WRITEB(port, ccr1, getccr1configS(port)); WRITEB(port, ccr2, getccr2configS(port)); WRITEB(port, ccr3, getccr3configS(port)); WRITEB(port, ccr4, getccr4configS(port)); /* 32 byte receive fifo */ WRITEB(port, mode, getmodeS(port)); WRITEB(port, tic /* really rlcr */, getrlcrconfigS(port)); /* power-up */ switch(port->ccontrol.ccr4 & SAB82532_CCR4_RF02) { case SAB82532_CCR4_RF32: port->recv_fifo_size = 32; break; case SAB82532_CCR4_RF16: port->recv_fifo_size = 16; break; case SAB82532_CCR4_RF04: port->recv_fifo_size = 4; break; case SAB82532_CCR4_RF02: port->recv_fifo_size = 2; break; default: port->recv_fifo_size = 32; port->ccontrol.ccr4 &= ~SAB82532_CCR4_RF02; break; } if(port->ccontrol.ccr2 & SAB82532_CCR2_TOE) { RAISE(port, txclkdir); } else { LOWER(port, txclkdir); } SET_REG_BIT(port,ccr0,SAB82532_CCR0_PU); if(port->chip->c_cim) { if(port->chip->c_cim->ci_type == CIM_SP502) { aura_sp502_program(port, port->sigmode); } } } /* frees up all skbuffs currently */ /* held by driver */ void Sab8253xFreeAllFreeListSKBUFFS(SAB_PORT* priv) /* empty the skbuffer list */ /* either on failed open */ /* or on close*/ { struct sk_buff* skb; if(priv->sab8253xbuflist == NULL) { return; } DEBUGPRINT((KERN_ALERT "sab8253x: freeing %i skbuffs.\n", skb_queue_len(priv->sab8253xbuflist))); while(skb_queue_len(priv->sab8253xbuflist) > 0) { skb = skb_dequeue(priv->sab8253xbuflist); dev_kfree_skb_any(skb); } kfree(priv->sab8253xbuflist); priv->sab8253xbuflist = NULL; } int Sab8253xSetUpLists(SAB_PORT *priv) { if(priv->sab8253xbuflist) { if(priv->sab8253xc_rcvbuflist) { return 0; } else { return -1; } return 0; } else if(priv->sab8253xc_rcvbuflist) { return -1; } priv->sab8253xbuflist = (struct sk_buff_head*) kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL); if(priv->sab8253xbuflist == NULL) { return -1; } priv->sab8253xc_rcvbuflist = (struct sk_buff_head*) kmalloc(sizeof(struct sk_buff_head), GFP_KERNEL); if(priv->sab8253xc_rcvbuflist == NULL) { kfree(priv->sab8253xbuflist); return -1; } skb_queue_head_init(priv->sab8253xbuflist); skb_queue_head_init(priv->sab8253xc_rcvbuflist); return 0; } /* sets up transmit ring and one receive sk_buff */ /* set up transmit and receive sk_buff control structures */ int Sab8253xInitDescriptors2(SAB_PORT *priv, int listsize, int rbufsize) { RING_DESCRIPTOR *desc; RING_DESCRIPTOR *xdesc; if(priv->dcontrol2.transmit != NULL) { if(priv->dcontrol2.receive != NULL) { return 0; } return -1; } else if(priv->dcontrol2.receive != NULL) { return -1; } priv->dcontrol2.transmit = (RING_DESCRIPTOR*) kmalloc(sizeof(RING_DESCRIPTOR) * listsize, GFP_KERNEL); /* dcontrol2 is an historical artifact from when the code talked to an intelligent controller */ if(priv->dcontrol2.transmit == NULL) { return -1; } priv->dcontrol2.receive = (RING_DESCRIPTOR*) kmalloc(sizeof(RING_DESCRIPTOR), GFP_KERNEL); /* only one receive sk_buffer */ if(priv->dcontrol2.receive == NULL) { kfree(priv->dcontrol2.transmit); priv->dcontrol2.transmit = NULL; return -1; } for(xdesc = priv->dcontrol2.transmit; xdesc < &priv->dcontrol2.transmit[listsize - 1]; xdesc = &xdesc[1]) /* set up transmit descriptors */ { xdesc->HostVaddr = NULL; xdesc->VNext = &xdesc[1]; xdesc->Count = 0 | OWN_DRIVER; xdesc->crc = 0; xdesc->sendcrc = 0; xdesc->crcindex = 0; } xdesc->HostVaddr = NULL; xdesc->VNext = priv->dcontrol2.transmit; /* circular list */ xdesc->Count = 0 | OWN_DRIVER; xdesc->crc = 0; xdesc->sendcrc = 0; xdesc->crcindex = 0; desc = priv->dcontrol2.receive; /* only need one descriptor for receive */ desc->HostVaddr = NULL; desc->VNext = &desc[0]; desc = priv->dcontrol2.receive; desc->HostVaddr = dev_alloc_skb(rbufsize); if(desc->HostVaddr == NULL) { printk(KERN_ALERT "Unable to allocate skb_buffers (rx 0).\n"); printk(KERN_ALERT "Driver initialization failed.\n"); kfree(priv->dcontrol2.transmit); kfree(priv->dcontrol2.receive); priv->dcontrol2.transmit = NULL; /* get rid of descriptor ring */ priv->dcontrol2.receive = NULL; /* get rid of descriptor */ /* probably should do some deallocation of sk_buffs*/ /* but will take place in the open */ return -1; } skb_queue_head(priv->sab8253xbuflist, (struct sk_buff*) desc->HostVaddr); desc->Count = rbufsize|OWN_SAB; /* belongs to int handler */ desc->crc = 0; desc->sendcrc = 0; desc->crcindex = 0; /* setup the various pointers */ priv->active2 = priv->dcontrol2; /* insert new skbuff */ priv->sabnext2 = priv->dcontrol2; /* transmit from here */ return 0; } /* loads program, waits for PPC */ /* and completes initialization*/ void Sab8253xCleanUpTransceiveN(SAB_PORT* priv) { Sab8253xFreeAllFreeListSKBUFFS(priv); Sab8253xFreeAllReceiveListSKBUFFS(priv); /* these are also cleaned up in the module cleanup routine */ /* should probably only be done here */ if(priv->dcontrol2.receive) { kfree(priv->dcontrol2.receive); priv->dcontrol2.receive = NULL; } if(priv->dcontrol2.transmit) { kfree(priv->dcontrol2.transmit); priv->dcontrol2.transmit = NULL; } priv->active2 = priv->dcontrol2; priv->sabnext2 = priv->dcontrol2; } void Sab8253xFreeAllReceiveListSKBUFFS(SAB_PORT* priv) /* empty the skbuffer list */ /* either on failed open */ /* or on close*/ { struct sk_buff* skb; if(priv->sab8253xc_rcvbuflist == NULL) { return; } DEBUGPRINT((KERN_ALERT "sab8253x: freeing %i skbuffs.\n", skb_queue_len(priv->sab8253xc_rcvbuflist))); while(skb_queue_len(priv->sab8253xc_rcvbuflist) > 0) { skb = skb_dequeue(priv->sab8253xc_rcvbuflist); dev_kfree_skb_any(skb); } kfree(priv->sab8253xc_rcvbuflist); priv->sab8253xc_rcvbuflist = NULL; } /* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */ void sab8253x_change_speedN(struct sab_port *port) { unsigned long flags; unsigned char ccr2=0, ccr4=0, ebrg=0; int bits = 8; #ifdef DEBUGGING printk("Change speed! "); #endif if(!sab8253x_baud(port, (port->baud)*2, &ebrg, &ccr2, &ccr4, &(port->baud))) { printk("Aurora Warning. baudrate %ld could not be set! Using 115200", port->baud); port->baud = 115200; sab8253x_baud(port, (port->baud*2), &ebrg, &ccr2, &ccr4, &(port->baud)); } if (port->baud) { port->timeout = (port->xmit_fifo_size * HZ * bits) / port->baud; port->cec_timeout = port->tec_timeout >> 2; } else { port->timeout = 0; port->cec_timeout = SAB8253X_MAX_CEC_DELAY; } port->timeout += HZ / 50; /* Add .02 seconds of slop */ save_flags(flags); cli(); sab8253x_cec_wait(port); WRITEB(port, bgr, ebrg); WRITEB(port, ccr2, READB(port, ccr2) & ~(0xc0)); /* clear out current baud rage */ WRITEB(port, ccr2, READB(port, ccr2) | ccr2); WRITEB(port, ccr4, (READB(port,ccr4) & ~SAB82532_CCR4_EBRG) | ccr4); if (port->flags & FLAG8253X_CTS_FLOW) { WRITEB(port, mode, READB(port,mode) & ~(SAB82532_MODE_RTS)); port->interrupt_mask1 &= ~(SAB82532_IMR1_CSC); WRITEB(port, imr1, port->interrupt_mask1); } else { WRITEB(port, mode, READB(port,mode) | SAB82532_MODE_RTS); port->interrupt_mask1 |= SAB82532_IMR1_CSC; WRITEB(port, imr1, port->interrupt_mask1); } WRITEB(port, mode, READB(port, mode) | SAB82532_MODE_RAC); restore_flags(flags); } void sab8253x_shutdownN(struct sab_port *port) { unsigned long flags; if (!(port->flags & FLAG8253X_INITIALIZED)) { return; } save_flags(flags); cli(); /* Disable interrupts */ /* * clear delta_msr_wait queue to avoid mem leaks: we may free the irq * here so the queue might never be waken up */ wake_up_interruptible(&port->delta_msr_wait); /* Disable Interrupts */ port->interrupt_mask0 = 0xff; WRITEB(port, imr0, port->interrupt_mask0); port->interrupt_mask1 = 0xff; WRITEB(port, imr1, port->interrupt_mask1); LOWER(port,rts); LOWER(port,dtr); /* Disable Receiver */ CLEAR_REG_BIT(port,mode,SAB82532_MODE_RAC); /* Power Down */ CLEAR_REG_BIT(port,ccr0,SAB82532_CCR0_PU); port->flags &= ~FLAG8253X_INITIALIZED; restore_flags(flags); } int sab8253x_block_til_ready(struct tty_struct *tty, struct file * filp, struct sab_port *port) { DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0; unsigned long flags; /* * If the device is in the middle of being closed, then block * until it's done, and then try again. */ if (tty_hung_up_p(filp) || (port->flags & FLAG8253X_CLOSING)) { if (port->flags & FLAG8253X_CLOSING) { interruptible_sleep_on(&port->close_wait); /* finish up previous close */ } #ifdef SERIAL_DO_RESTART if (port->flags & FLAG8253X_HUP_NOTIFY) { return -EAGAIN; } else { return -ERESTARTSYS; } #else return -EAGAIN; #endif } /* * If this is a callout device, then just make sure the normal * device isn't being used. */ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { if (port->flags & FLAG8253X_NORMAL_ACTIVE) { return -EBUSY; /* async, sync tty or network driver active */ } if ((port->flags & FLAG8253X_CALLOUT_ACTIVE) && (port->flags & FLAG8253X_SESSION_LOCKOUT) && (port->session != current->session)) { return -EBUSY; } if ((port->flags & FLAG8253X_CALLOUT_ACTIVE) && (port->flags & FLAG8253X_PGRP_LOCKOUT) && (port->pgrp != current->pgrp)) { return -EBUSY; } port->flags |= FLAG8253X_CALLOUT_ACTIVE; /* doing a callout */ return 0; } /* sort out async vs sync tty, not call out */ /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { if (port->flags & FLAG8253X_CALLOUT_ACTIVE) { return -EBUSY; } port->flags |= FLAG8253X_NORMAL_ACTIVE; return 0; } if (port->flags & FLAG8253X_CALLOUT_ACTIVE) { if (port->normal_termios.c_cflag & CLOCAL) { do_clocal = 1; } } else if (tty->termios->c_cflag & CLOCAL) { do_clocal = 1; } /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in * this loop, port->count is dropped by one, so that * sab8253x_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ /* The port decrement logic is probably */ /* broken -- hence if def'd out -- it does*/ retval = 0; add_wait_queue(&port->open_wait, &wait); /* starts the wait but does not block here */ port->blocked_open++; while (1) { save_flags(flags); cli(); if (!(port->flags & FLAG8253X_CALLOUT_ACTIVE) && (tty->termios->c_cflag & CBAUD)) { RAISE(port, dtr); RAISE(port, rts); /* maybe not correct for sync */ /* * ??? Why changing the mode here? * port->regs->rw.mode |= SAB82532_MODE_FRTS; * port->regs->rw.mode &= ~(SAB82532_MODE_RTS); */ } restore_flags(flags); current->state = TASK_INTERRUPTIBLE; if (tty_hung_up_p(filp) || !(port->flags & FLAG8253X_INITIALIZED)) { #ifdef SERIAL_DO_RESTART if (port->flags & FLAG8253X_HUP_NOTIFY) { retval = -EAGAIN; } else { retval = -ERESTARTSYS; } #else retval = -EAGAIN; #endif break; } if (!(port->flags & FLAG8253X_CALLOUT_ACTIVE) && !(port->flags & FLAG8253X_CLOSING) && (do_clocal || ISON(port,dcd))) { break; } #ifdef DEBUG_OPEN printk("sab8253x_block_til_ready:2 flags = 0x%x\n",port->flags); #endif if (signal_pending(current)) { retval = -ERESTARTSYS; break; } #ifdef DEBUG_OPEN printk("sab8253x_block_til_ready blocking: ttyS%d, count = %d, flags = %x, clocal = %d, vstr = %02x\n", port->line, port->count, port->flags, do_clocal, READB(port,vstr)); #endif schedule(); } current->state = TASK_RUNNING; remove_wait_queue(&port->open_wait, &wait); port->blocked_open--; #ifdef DEBUG_OPEN printk("sab8253x_block_til_ready after blocking: ttys%d, count = %d\n", port->line, port->count); #endif if (retval) { return retval; } port->flags |= FLAG8253X_NORMAL_ACTIVE; return 0; } /* * sab8253x_wait_until_sent() --- wait until the transmitter is empty */ void sab8253x_wait_until_sent(struct tty_struct *tty, int timeout) { struct sab_port *port = (struct sab_port *)tty->driver_data; unsigned long orig_jiffies, char_time; if (sab8253x_serial_paranoia_check(port,tty->device,"sab8253x_wait_until_sent")) { return; } orig_jiffies = jiffies; /* * Set the check interval to be 1/5 of the estimated time to * send a single character, and make it at least 1. The check * interval should also be less than the timeout. * * Note: we have to use pretty tight timings here to satisfy * the NIST-PCTS. */ char_time = (port->timeout - HZ/50) / port->xmit_fifo_size; char_time = char_time / 5; if (char_time == 0) { char_time = 1; } if (timeout) { char_time = MIN(char_time, timeout); } while ((Sab8253xCountTransmit(port) > 0) || !port->all_sent) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(char_time); if (signal_pending(current)) { break; } if (timeout && time_after(jiffies, orig_jiffies + timeout)) { break; } } } void sab8253x_flush_buffer(struct tty_struct *tty) { struct sab_port *port = (struct sab_port *)tty->driver_data; unsigned long flags; register RING_DESCRIPTOR *freeme; if(sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_flush_buffer")) { return; } if(port->sabnext2.transmit == NULL) { return; } save_flags(flags); cli(); /* need to turn off ints because mucking with sabnext2 */ #ifndef FREEININTERRUPT freeme = port->active2.transmit; do /* just go all around */ { 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->Count = OWN_DRIVER; freeme = (RING_DESCRIPTOR*) freeme->VNext; } while(freeme != port->active2.transmit); #else /* buffers only from sabnext2.transmit to active2.transmit */ while((port->sabnext2.transmit->Count & OWNER) == OWN_SAB) /* clear out stuff waiting to be transmitted */ { freeme = port->sabnext2.transmit; 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->Count = OWN_DRIVER; port->sabnext2.transmit = freeme->VNext; } #endif port->sabnext2.transmit = port->active2.transmit; /* should already be equal to be sure */ sab8253x_cec_wait(port); WRITEB(port,cmdr,SAB82532_CMDR_XRES); restore_flags(flags); tty_wakeup(tty); }