/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * Avanstar Xp pci uart driver */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h" #include "uartaxp.i" typedef struct Cc Cc;typedef struct Ccb Ccb;typedef struct Ctlr Ctlr;typedef struct Gcb Gcb; /* * Global Control Block. * Service Request fields must be accessed using XCHG. */struct Gcb { u16int gcw; /* Global Command Word */ u16int gsw; /* Global Status Word */ u16int gsr; /* Global Service Request */ u16int abs; /* Available Buffer Space */ u16int bt; /* Board Type */ u16int cpv; /* Control Program Version */ u16int ccbn; /* Ccb count */ u16int ccboff; /* Ccb offset */ u16int ccbsz; /* Ccb size */ u16int gcw2; /* Global Command Word 2 */ u16int gsw2; /* Global Status Word 2 */ u16int esr; /* Error Service Request */ u16int isr; /* Input Service Request */ u16int osr; /* Output Service Request */ u16int msr; /* Modem Service Request */ u16int csr; /* Command Service Request */}; /* * Channel Control Block. */struct Ccb { u16int br; /* Baud Rate */ u16int df; /* Data Format */ u16int lp; /* Line Protocol */ u16int ibs; /* Input Buffer Size */ u16int obs; /* Output Buffer Size */ u16int ibtr; /* Ib Trigger Rate */ u16int oblw; /* Ob Low Watermark */ u8int ixon[2]; /* IXON characters */ u16int ibhw; /* Ib High Watermark */ u16int iblw; /* Ib Low Watermark */ u16int cc; /* Channel Command */ u16int cs; /* Channel Status */ u16int ibsa; /* Ib Start Addr */ u16int ibea; /* Ib Ending Addr */ u16int obsa; /* Ob Start Addr */ u16int obea; /* Ob Ending Addr */ u16int ibwp; /* Ib write pointer (RO) */ u16int ibrp; /* Ib read pointer (R/W) */ u16int obwp; /* Ob write pointer (R/W) */ u16int obrp; /* Ob read pointer (RO) */ u16int ces; /* Communication Error Status */ u16int bcp; /* Bad Character Pointer */ u16int mc; /* Modem Control */ u16int ms; /* Modem Status */ u16int bs; /* Blocking Status */ u16int crf; /* Character Received Flag */ u8int ixoff[2]; /* IXOFF characters */ u16int cs2; /* Channel Status 2 */ u8int sec[2]; /* Strip/Error Characters */}; enum { /* br */ Br76800 = 0xFF00, Br115200 = 0xFF01,}; enum { /* df */ Db5 = 0x0000, /* Data Bits - 5 bits/byte */ Db6 = 0x0001, /* 6 bits/byte */ Db7 = 0x0002, /* 7 bits/byte */ Db8 = 0x0003, /* 8 bits/byte */ DbMASK = 0x0003, Sb1 = 0x0000, /* 1 Stop Bit */ Sb2 = 0x0004, /* 2 Stop Bit */ SbMASK = 0x0004, Np = 0x0000, /* No Parity */ Op = 0x0008, /* Odd Parity */ Ep = 0x0010, /* Even Parity */ Mp = 0x0020, /* Mark Parity */ Sp = 0x0030, /* Space Parity */ PMASK = 0x0038, Cmn = 0x0000, /* Channel Mode Normal */ Cme = 0x0040, /* CM Echo */ Cmll = 0x0080, /* CM Local Loopback */ Cmrl = 0x00C0, /* CM Remote Loopback */}; enum { /* lp */ Ixon = 0x0001, /* Obey IXON/IXOFF */ Ixany = 0x0002, /* Any character retarts Tx */ Ixgen = 0x0004, /* Generate IXON/IXOFF */ Cts = 0x0008, /* CTS controls Tx */ Dtr = 0x0010, /* Rx controls DTR */ ½d = 0x0020, /* RTS off during Tx */ Rts = 0x0040, /* generate RTS */ Emcs = 0x0080, /* Enable Modem Control */ Ecs = 0x1000, /* Enable Character Stripping */ Eia422 = 0x2000, /* EIA422 */}; enum { /* cc */ Ccu = 0x0001, /* Configure Channel and UART */ Cco = 0x0002, /* Configure Channel Only */ Fib = 0x0004, /* Flush Input Buffer */ Fob = 0x0008, /* Flush Output Buffer */ Er = 0x0010, /* Enable Receiver */ Dr = 0x0020, /* Disable Receiver */ Et = 0x0040, /* Enable Transmitter */ Dt = 0x0080, /* Disable Transmitter */}; enum { /* ces */ Oe = 0x0001, /* Overrun Error */ Pe = 0x0002, /* Parity Error */ Fe = 0x0004, /* Framing Error */ Br = 0x0008, /* Break Received */}; enum { /* mc */ Adtr = 0x0001, /* Assert DTR */ Arts = 0x0002, /* Assert RTS */ Ab = 0x0010, /* Assert BREAK */}; enum { /* ms */ Scts = 0x0001, /* Status od CTS */ Sdsr = 0x0002, /* Status of DSR */ Sri = 0x0004, /* Status of RI */ Sdcd = 0x0008, /* Status of DCD */}; enum { /* bs */ Rd = 0x0001, /* Receiver Disabled */ Td = 0x0002, /* Transmitter Disabled */ Tbxoff = 0x0004, /* Tx Blocked by XOFF */ Tbcts = 0x0008, /* Tx Blocked by CTS */ Rbxoff = 0x0010, /* Rx Blocked by XOFF */ Rbrts = 0x0020, /* Rx Blocked by RTS */}; enum { /* Local Configuration */ Range = 0x00, Remap = 0x04, Region = 0x18, Mb0 = 0x40, /* Mailbox 0 */ Ldb = 0x60, /* PCI to Local Doorbell */ Pdb = 0x64, /* Local to PCI Doorbell */ Ics = 0x68, /* Interrupt Control/Status */ Mcc = 0x6C, /* Misc. Command and Control */}; enum { /* Mb0 */ Edcc = 1, /* exec. downloaded code cmd */ Aic = 0x10, /* adapter init'zed correctly */ Cpr = 1ul << 31, /* control program ready */}; enum { /* Mcc */ Rcr = 1ul << 29, /* reload config. reg.s */ Asr = 1ul << 30, /* pci adapter sw reset */ Lis = 1ul << 31, /* local init status */}; typedef struct Cc Cc;typedef struct Ccb Ccb;typedef struct Ctlr Ctlr; /* * Channel Control, one per uart. * Devuart communicates via the PhysUart functions with * a Uart* argument. Uart.regs is filled in by this driver * to point to a Cc, and Cc.ctlr points to the Axp board * controller. */struct Cc { int uartno; Ccb* ccb; Ctlr* ctlr; Rendez; Uart;}; typedef struct Ctlr { char* name; Pcidev* pcidev; int ctlrno; Ctlr* next; u32int* reg; uchar* mem; Gcb* gcb; int im; /* interrupt mask */ Cc cc[16];} Ctlr; #define csr32r(c, r) (*((c)->reg+((r)/4)))#define csr32w(c, r, v) (*((c)->reg+((r)/4)) = (v)) static Ctlr* axpctlrhead;static Ctlr* axpctlrtail; extern PhysUart axpphysuart; static intaxpccdone(void* ccb){ return !((Ccb*)ccb)->cc; /* hw sets ccb->cc to zero */} static voidaxpcc(Cc* cc, int cmd){ Ccb *ccb; int timeo; u16int cs; ccb = cc->ccb; ccb->cc = cmd; if(!cc->ctlr->im) for(timeo = 0; timeo < 1000000; timeo++){ if(!ccb->cc) break; microdelay(1); } else tsleep(cc, axpccdone, ccb, 1000); cs = ccb->cs; if(ccb->cc || cs){ print("%s: cmd %#ux didn't terminate: %#ux %#ux\n", cc->name, cmd, ccb->cc, cs); if(cc->ctlr->im) error(Eio); }} static longaxpstatus(Uart* uart, void* buf, long n, long offset){ char *p; Ccb *ccb; u16int bs, fstat, ms; p = malloc(READSTR); if(p == nil) error(Enomem); ccb = ((Cc*)(uart->regs))->ccb; bs = ccb->bs; fstat = ccb->df; ms = ccb->ms; snprint(p, READSTR, "b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n" "dev(%d) type(%d) framing(%d) overruns(%d) " "berr(%d) serr(%d)%s%s%s%s\n", uart->baud, uart->hup_dcd, ms & Sdsr, uart->hup_dsr, (fstat & DbMASK) + 5, 0, (fstat & PMASK) ? ((fstat & Ep) == Ep? 'e': 'o'): 'n', (bs & Rbrts) ? 1 : 0, (fstat & Sb2) ? 2 : 1, 0, uart->dev, uart->type, uart->ferr, uart->oerr, uart->berr, uart->serr, (ms & Scts) ? " cts" : "", (ms & Sdsr) ? " dsr" : "", (ms & Sdcd) ? " dcd" : "", (ms & Sri) ? " ring" : "" ); n = readstr(offset, buf, n, p); free(p); return n;} static voidaxpfifo(Uart*, int){} static voidaxpdtr(Uart* uart, int on){ Ccb *ccb; u16int mc; ccb = ((Cc*)(uart->regs))->ccb; mc = ccb->mc; if(on) mc |= Adtr; else mc &= ~Adtr; ccb->mc = mc;} /* * can be called from uartstageinput() during an input interrupt, * with uart->rlock ilocked or the uart qlocked, sometimes both. */static voidaxprts(Uart* uart, int on){ Ccb *ccb; u16int mc; ccb = ((Cc*)(uart->regs))->ccb; mc = ccb->mc; if(on) mc |= Arts; else mc &= ~Arts; ccb->mc = mc;} static voidaxpmodemctl(Uart* uart, int on){ Ccb *ccb; u16int lp; ccb = ((Cc*)(uart->regs))->ccb; ilock(&uart->tlock); lp = ccb->lp; if(on){ lp |= Cts|Rts; lp &= ~Emcs; uart->cts = ccb->ms & Scts; } else{ lp &= ~(Cts|Rts); lp |= Emcs; uart->cts = 1; } uart->modem = on; iunlock(&uart->tlock); ccb->lp = lp; axpcc(uart->regs, Ccu);} static intaxpparity(Uart* uart, int parity){ Ccb *ccb; u16int df; switch(parity){ default: return -1; case 'e': parity = Ep; break; case 'o': parity = Op; break; case 'n': parity = Np; break; } ccb = ((Cc*)(uart->regs))->ccb; df = ccb->df & ~PMASK; ccb->df = df|parity; axpcc(uart->regs, Ccu); return 0;} static intaxpstop(Uart* uart, int stop){ Ccb *ccb; u16int df; switch(stop){ default: return -1; case 1: stop = Sb1; break; case 2: stop = Sb2; break; } ccb = ((Cc*)(uart->regs))->ccb; df = ccb->df & ~SbMASK; ccb->df = df|stop; axpcc(uart->regs, Ccu); return 0;} static intaxpbits(Uart* uart, int bits){ Ccb *ccb; u16int df; bits -= 5; if(bits < 0 || bits > 3) return -1; ccb = ((Cc*)(uart->regs))->ccb; df = ccb->df & ~DbMASK; ccb->df = df|bits; axpcc(uart->regs, Ccu); return 0;} static intaxpbaud(Uart* uart, int baud){ Ccb *ccb; int i, ibtr; /* * Set baud rate (high rates are special - only 16 bits). */ if(baud <= 0) return -1; uart->baud = baud; ccb = ((Cc*)(uart->regs))->ccb; switch(baud){ default: ccb->br = baud; break; case 76800: ccb->br = Br76800; break; case 115200: ccb->br = Br115200; break; } /* * Set trigger level to about 50 per second. */ ibtr = baud/500; i = (ccb->ibea - ccb->ibsa)/2; if(ibtr > i) ibtr = i; ccb->ibtr = ibtr; axpcc(uart->regs, Ccu); return 0;} static voidaxpbreak(Uart* uart, int ms){ Ccb *ccb; u16int mc; Lines 1–500 of 963. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * Avanstar Xp pci uart driver */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" #include "uartaxp.i" typedef struct Cc Cc; typedef struct Ccb Ccb; typedef struct Ctlr Ctlr; typedef struct Gcb Gcb; /* * Global Control Block. * Service Request fields must be accessed using XCHG. */ struct Gcb { u16int gcw; /* Global Command Word */ u16int gsw; /* Global Status Word */ u16int gsr; /* Global Service Request */ u16int abs; /* Available Buffer Space */ u16int bt; /* Board Type */ u16int cpv; /* Control Program Version */ u16int ccbn; /* Ccb count */ u16int ccboff; /* Ccb offset */ u16int ccbsz; /* Ccb size */ u16int gcw2; /* Global Command Word 2 */ u16int gsw2; /* Global Status Word 2 */ u16int esr; /* Error Service Request */ u16int isr; /* Input Service Request */ u16int osr; /* Output Service Request */ u16int msr; /* Modem Service Request */ u16int csr; /* Command Service Request */ }; /* * Channel Control Block. */ struct Ccb { u16int br; /* Baud Rate */ u16int df; /* Data Format */ u16int lp; /* Line Protocol */ u16int ibs; /* Input Buffer Size */ u16int obs; /* Output Buffer Size */ u16int ibtr; /* Ib Trigger Rate */ u16int oblw; /* Ob Low Watermark */ u8int ixon[2]; /* IXON characters */ u16int ibhw; /* Ib High Watermark */ u16int iblw; /* Ib Low Watermark */ u16int cc; /* Channel Command */ u16int cs; /* Channel Status */ u16int ibsa; /* Ib Start Addr */ u16int ibea; /* Ib Ending Addr */ u16int obsa; /* Ob Start Addr */ u16int obea; /* Ob Ending Addr */ u16int ibwp; /* Ib write pointer (RO) */ u16int ibrp; /* Ib read pointer (R/W) */ u16int obwp; /* Ob write pointer (R/W) */ u16int obrp; /* Ob read pointer (RO) */ u16int ces; /* Communication Error Status */ u16int bcp; /* Bad Character Pointer */ u16int mc; /* Modem Control */ u16int ms; /* Modem Status */ u16int bs; /* Blocking Status */ u16int crf; /* Character Received Flag */ u8int ixoff[2]; /* IXOFF characters */ u16int cs2; /* Channel Status 2 */ u8int sec[2]; /* Strip/Error Characters */ }; enum { /* br */ Br76800 = 0xFF00, Br115200 = 0xFF01, }; enum { /* df */ Db5 = 0x0000, /* Data Bits - 5 bits/byte */ Db6 = 0x0001, /* 6 bits/byte */ Db7 = 0x0002, /* 7 bits/byte */ Db8 = 0x0003, /* 8 bits/byte */ DbMASK = 0x0003, Sb1 = 0x0000, /* 1 Stop Bit */ Sb2 = 0x0004, /* 2 Stop Bit */ SbMASK = 0x0004, Np = 0x0000, /* No Parity */ Op = 0x0008, /* Odd Parity */ Ep = 0x0010, /* Even Parity */ Mp = 0x0020, /* Mark Parity */ Sp = 0x0030, /* Space Parity */ PMASK = 0x0038, Cmn = 0x0000, /* Channel Mode Normal */ Cme = 0x0040, /* CM Echo */ Cmll = 0x0080, /* CM Local Loopback */ Cmrl = 0x00C0, /* CM Remote Loopback */ }; enum { /* lp */ Ixon = 0x0001, /* Obey IXON/IXOFF */ Ixany = 0x0002, /* Any character retarts Tx */ Ixgen = 0x0004, /* Generate IXON/IXOFF */ Cts = 0x0008, /* CTS controls Tx */ Dtr = 0x0010, /* Rx controls DTR */ ½d = 0x0020, /* RTS off during Tx */ Rts = 0x0040, /* generate RTS */ Emcs = 0x0080, /* Enable Modem Control */ Ecs = 0x1000, /* Enable Character Stripping */ Eia422 = 0x2000, /* EIA422 */ }; enum { /* cc */ Ccu = 0x0001, /* Configure Channel and UART */ Cco = 0x0002, /* Configure Channel Only */ Fib = 0x0004, /* Flush Input Buffer */ Fob = 0x0008, /* Flush Output Buffer */ Er = 0x0010, /* Enable Receiver */ Dr = 0x0020, /* Disable Receiver */ Et = 0x0040, /* Enable Transmitter */ Dt = 0x0080, /* Disable Transmitter */ }; enum { /* ces */ Oe = 0x0001, /* Overrun Error */ Pe = 0x0002, /* Parity Error */ Fe = 0x0004, /* Framing Error */ Br = 0x0008, /* Break Received */ }; enum { /* mc */ Adtr = 0x0001, /* Assert DTR */ Arts = 0x0002, /* Assert RTS */ Ab = 0x0010, /* Assert BREAK */ }; enum { /* ms */ Scts = 0x0001, /* Status od CTS */ Sdsr = 0x0002, /* Status of DSR */ Sri = 0x0004, /* Status of RI */ Sdcd = 0x0008, /* Status of DCD */ }; enum { /* bs */ Rd = 0x0001, /* Receiver Disabled */ Td = 0x0002, /* Transmitter Disabled */ Tbxoff = 0x0004, /* Tx Blocked by XOFF */ Tbcts = 0x0008, /* Tx Blocked by CTS */ Rbxoff = 0x0010, /* Rx Blocked by XOFF */ Rbrts = 0x0020, /* Rx Blocked by RTS */ }; enum { /* Local Configuration */ Range = 0x00, Remap = 0x04, Region = 0x18, Mb0 = 0x40, /* Mailbox 0 */ Ldb = 0x60, /* PCI to Local Doorbell */ Pdb = 0x64, /* Local to PCI Doorbell */ Ics = 0x68, /* Interrupt Control/Status */ Mcc = 0x6C, /* Misc. Command and Control */ }; enum { /* Mb0 */ Edcc = 1, /* exec. downloaded code cmd */ Aic = 0x10, /* adapter init'zed correctly */ Cpr = 1ul << 31, /* control program ready */ }; enum { /* Mcc */ Rcr = 1ul << 29, /* reload config. reg.s */ Asr = 1ul << 30, /* pci adapter sw reset */ Lis = 1ul << 31, /* local init status */ }; typedef struct Cc Cc; typedef struct Ccb Ccb; typedef struct Ctlr Ctlr; /* * Channel Control, one per uart. * Devuart communicates via the PhysUart functions with * a Uart* argument. Uart.regs is filled in by this driver * to point to a Cc, and Cc.ctlr points to the Axp board * controller. */ struct Cc { int uartno; Ccb* ccb; Ctlr* ctlr; Rendez; Uart; }; typedef struct Ctlr { char* name; Pcidev* pcidev; int ctlrno; Ctlr* next; u32int* reg; uchar* mem; Gcb* gcb; int im; /* interrupt mask */ Cc cc[16]; } Ctlr; #define csr32r(c, r) (*((c)->reg+((r)/4))) #define csr32w(c, r, v) (*((c)->reg+((r)/4)) = (v)) static Ctlr* axpctlrhead; static Ctlr* axpctlrtail; extern PhysUart axpphysuart; static int axpccdone(void* ccb) { return !((Ccb*)ccb)->cc; /* hw sets ccb->cc to zero */ } static void axpcc(Cc* cc, int cmd) { Ccb *ccb; int timeo; u16int cs; ccb = cc->ccb; ccb->cc = cmd; if(!cc->ctlr->im) for(timeo = 0; timeo < 1000000; timeo++){ if(!ccb->cc) break; microdelay(1); } else tsleep(cc, axpccdone, ccb, 1000); cs = ccb->cs; if(ccb->cc || cs){ print("%s: cmd %#ux didn't terminate: %#ux %#ux\n", cc->name, cmd, ccb->cc, cs); if(cc->ctlr->im) error(Eio); } } static long axpstatus(Uart* uart, void* buf, long n, long offset) { char *p; Ccb *ccb; u16int bs, fstat, ms; p = malloc(READSTR); if(p == nil) error(Enomem); ccb = ((Cc*)(uart->regs))->ccb; bs = ccb->bs; fstat = ccb->df; ms = ccb->ms; snprint(p, READSTR, "b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n" "dev(%d) type(%d) framing(%d) overruns(%d) " "berr(%d) serr(%d)%s%s%s%s\n", uart->baud, uart->hup_dcd, ms & Sdsr, uart->hup_dsr, (fstat & DbMASK) + 5, 0, (fstat & PMASK) ? ((fstat & Ep) == Ep? 'e': 'o'): 'n', (bs & Rbrts) ? 1 : 0, (fstat & Sb2) ? 2 : 1, 0, uart->dev, uart->type, uart->ferr, uart->oerr, uart->berr, uart->serr, (ms & Scts) ? " cts" : "", (ms & Sdsr) ? " dsr" : "", (ms & Sdcd) ? " dcd" : "", (ms & Sri) ? " ring" : "" ); n = readstr(offset, buf, n, p); free(p); return n; } static void axpfifo(Uart*, int) { } static void axpdtr(Uart* uart, int on) { Ccb *ccb; u16int mc; ccb = ((Cc*)(uart->regs))->ccb; mc = ccb->mc; if(on) mc |= Adtr; else mc &= ~Adtr; ccb->mc = mc; } /* * can be called from uartstageinput() during an input interrupt, * with uart->rlock ilocked or the uart qlocked, sometimes both. */ static void axprts(Uart* uart, int on) { Ccb *ccb; u16int mc; ccb = ((Cc*)(uart->regs))->ccb; mc = ccb->mc; if(on) mc |= Arts; else mc &= ~Arts; ccb->mc = mc; } static void axpmodemctl(Uart* uart, int on) { Ccb *ccb; u16int lp; ccb = ((Cc*)(uart->regs))->ccb; ilock(&uart->tlock); lp = ccb->lp; if(on){ lp |= Cts|Rts; lp &= ~Emcs; uart->cts = ccb->ms & Scts; } else{ lp &= ~(Cts|Rts); lp |= Emcs; uart->cts = 1; } uart->modem = on; iunlock(&uart->tlock); ccb->lp = lp; axpcc(uart->regs, Ccu); } static int axpparity(Uart* uart, int parity) { Ccb *ccb; u16int df; switch(parity){ default: return -1; case 'e': parity = Ep; break; case 'o': parity = Op; break; case 'n': parity = Np; break; } ccb = ((Cc*)(uart->regs))->ccb; df = ccb->df & ~PMASK; ccb->df = df|parity; axpcc(uart->regs, Ccu); return 0; } static int axpstop(Uart* uart, int stop) { Ccb *ccb; u16int df; switch(stop){ default: return -1; case 1: stop = Sb1; break; case 2: stop = Sb2; break; } ccb = ((Cc*)(uart->regs))->ccb; df = ccb->df & ~SbMASK; ccb->df = df|stop; axpcc(uart->regs, Ccu); return 0; } static int axpbits(Uart* uart, int bits) { Ccb *ccb; u16int df; bits -= 5; if(bits < 0 || bits > 3) return -1; ccb = ((Cc*)(uart->regs))->ccb; df = ccb->df & ~DbMASK; ccb->df = df|bits; axpcc(uart->regs, Ccu); return 0; } static int axpbaud(Uart* uart, int baud) { Ccb *ccb; int i, ibtr; /* * Set baud rate (high rates are special - only 16 bits). */ if(baud <= 0) return -1; uart->baud = baud; ccb = ((Cc*)(uart->regs))->ccb; switch(baud){ default: ccb->br = baud; break; case 76800: ccb->br = Br76800; break; case 115200: ccb->br = Br115200; break; } /* * Set trigger level to about 50 per second. */ ibtr = baud/500; i = (ccb->ibea - ccb->ibsa)/2; if(ibtr > i) ibtr = i; ccb->ibtr = ibtr; axpcc(uart->regs, Ccu); return 0; } static void axpbreak(Uart* uart, int ms) { Ccb *ccb; u16int mc;