cregit-Linux how code gets into the kernel

Release 4.11 drivers/net/arcnet/com90xx.c

/*
 * Linux ARCnet driver - COM90xx chipset (memory-mapped buffers)
 *
 * Written 1994-1999 by Avery Pennarun.
 * Written 1999 by Martin Mares <mj@ucw.cz>.
 * Derived from skeleton.c by Donald Becker.
 *
 * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com)
 *  for sponsoring the further development of this driver.
 *
 * **********************
 *
 * The original copyright of skeleton.c was as follows:
 *
 * skeleton.c Written 1993 by Donald Becker.
 * Copyright 1993 United States Government as represented by the
 * Director, National Security Agency.  This software may only be used
 * and distributed according to the terms of the GNU General Public License as
 * modified by SRC, incorporated herein by reference.
 *
 * **********************
 *
 * For more details, see drivers/net/arcnet.c
 *
 * **********************
 */


#define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt

#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/netdevice.h>
#include <linux/slab.h>
#include <linux/io.h>

#include "arcdevice.h"
#include "com9026.h"

/* Define this to speed up the autoprobe by assuming if only one io port and
 * shmem are left in the list at Stage 5, they must correspond to each
 * other.
 *
 * This is undefined by default because it might not always be true, and the
 * extra check makes the autoprobe even more careful.  Speed demons can turn
 * it on - I think it should be fine if you only have one ARCnet card
 * installed.
 *
 * If no ARCnet cards are installed, this delay never happens anyway and thus
 * the option has no effect.
 */

#undef FAST_PROBE

/* Internal function declarations */
static int com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem *);
static void com90xx_command(struct net_device *dev, int command);
static int com90xx_status(struct net_device *dev);
static void com90xx_setmask(struct net_device *dev, int mask);
static int com90xx_reset(struct net_device *dev, int really_reset);
static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset,
				 void *buf, int count);
static void com90xx_copy_from_card(struct net_device *dev, int bufnum,
				   int offset, void *buf, int count);

/* Known ARCnet cards */


static struct net_device *cards[16];

static int numcards;

/* Handy defines for ARCnet specific stuff */

/* The number of low I/O ports used by the card */

#define ARCNET_TOTAL_SIZE	16

/* Amount of I/O memory used by the card */

#define BUFFER_SIZE (512)

#define MIRROR_SIZE (BUFFER_SIZE * 4)


static int com90xx_skip_probe __initdata = 0;

/* Module parameters */


static int io;			
/* use the insmod io= irq= shmem= options */

static int irq;

static int shmem;

static char device[9];		
/* use eg. device=arc1 to change name */

module_param(io, int, 0);
module_param(irq, int, 0);
module_param(shmem, int, 0);
module_param_string(device, device, sizeof(device), 0);


static void __init com90xx_probe(void) { int count, status, ioaddr, numprint, airq, openparen = 0; unsigned long airqmask; int ports[(0x3f0 - 0x200) / 16 + 1] = { 0 }; unsigned long *shmems; void __iomem **iomem; int numports, numshmems, *port; u_long *p; int index; if (!io && !irq && !shmem && !*device && com90xx_skip_probe) return; shmems = kzalloc(((0x100000 - 0xa0000) / 0x800) * sizeof(unsigned long), GFP_KERNEL); if (!shmems) return; iomem = kzalloc(((0x100000 - 0xa0000) / 0x800) * sizeof(void __iomem *), GFP_KERNEL); if (!iomem) { kfree(shmems); return; } if (BUGLVL(D_NORMAL)) pr_info("%s\n", "COM90xx chipset support"); /* set up the arrays where we'll store the possible probe addresses */ numports = numshmems = 0; if (io) ports[numports++] = io; else for (count = 0x200; count <= 0x3f0; count += 16) ports[numports++] = count; if (shmem) shmems[numshmems++] = shmem; else for (count = 0xA0000; count <= 0xFF800; count += 2048) shmems[numshmems++] = count; /* Stage 1: abandon any reserved ports, or ones with status==0xFF * (empty), and reset any others by reading the reset port. */ numprint = -1; for (port = &ports[0]; port - ports < numports; port++) { numprint++; numprint %= 8; if (!numprint) { arc_cont(D_INIT, "\n"); arc_cont(D_INIT, "S1: "); } arc_cont(D_INIT, "%Xh ", *port); ioaddr = *port; if (!request_region(*port, ARCNET_TOTAL_SIZE, "arcnet (90xx)")) { arc_cont(D_INIT_REASONS, "(request_region)\n"); arc_cont(D_INIT_REASONS, "S1: "); if (BUGLVL(D_INIT_REASONS)) numprint = 0; *port-- = ports[--numports]; continue; } if (arcnet_inb(ioaddr, COM9026_REG_R_STATUS) == 0xFF) { arc_cont(D_INIT_REASONS, "(empty)\n"); arc_cont(D_INIT_REASONS, "S1: "); if (BUGLVL(D_INIT_REASONS)) numprint = 0; release_region(*port, ARCNET_TOTAL_SIZE); *port-- = ports[--numports]; continue; } /* begin resetting card */ arcnet_inb(ioaddr, COM9026_REG_R_RESET); arc_cont(D_INIT_REASONS, "\n"); arc_cont(D_INIT_REASONS, "S1: "); if (BUGLVL(D_INIT_REASONS)) numprint = 0; } arc_cont(D_INIT, "\n"); if (!numports) { arc_cont(D_NORMAL, "S1: No ARCnet cards found.\n"); kfree(shmems); kfree(iomem); return; } /* Stage 2: we have now reset any possible ARCnet cards, so we can't * do anything until they finish. If D_INIT, print the list of * cards that are left. */ numprint = -1; for (port = &ports[0]; port < ports + numports; port++) { numprint++; numprint %= 8; if (!numprint) { arc_cont(D_INIT, "\n"); arc_cont(D_INIT, "S2: "); } arc_cont(D_INIT, "%Xh ", *port); } arc_cont(D_INIT, "\n"); mdelay(RESETtime); /* Stage 3: abandon any shmem addresses that don't have the signature * 0xD1 byte in the right place, or are read-only. */ numprint = -1; for (index = 0, p = &shmems[0]; index < numshmems; p++, index++) { void __iomem *base; numprint++; numprint %= 8; if (!numprint) { arc_cont(D_INIT, "\n"); arc_cont(D_INIT, "S3: "); } arc_cont(D_INIT, "%lXh ", *p); if (!request_mem_region(*p, MIRROR_SIZE, "arcnet (90xx)")) { arc_cont(D_INIT_REASONS, "(request_mem_region)\n"); arc_cont(D_INIT_REASONS, "Stage 3: "); if (BUGLVL(D_INIT_REASONS)) numprint = 0; goto out; } base = ioremap(*p, MIRROR_SIZE); if (!base) { arc_cont(D_INIT_REASONS, "(ioremap)\n"); arc_cont(D_INIT_REASONS, "Stage 3: "); if (BUGLVL(D_INIT_REASONS)) numprint = 0; goto out1; } if (arcnet_readb(base, COM9026_REG_R_STATUS) != TESTvalue) { arc_cont(D_INIT_REASONS, "(%02Xh != %02Xh)\n", arcnet_readb(base, COM9026_REG_R_STATUS), TESTvalue); arc_cont(D_INIT_REASONS, "S3: "); if (BUGLVL(D_INIT_REASONS)) numprint = 0; goto out2; } /* By writing 0x42 to the TESTvalue location, we also make * sure no "mirror" shmem areas show up - if they occur * in another pass through this loop, they will be discarded * because *cptr != TESTvalue. */ arcnet_writeb(0x42, base, COM9026_REG_W_INTMASK); if (arcnet_readb(base, COM9026_REG_R_STATUS) != 0x42) { arc_cont(D_INIT_REASONS, "(read only)\n"); arc_cont(D_INIT_REASONS, "S3: "); goto out2; } arc_cont(D_INIT_REASONS, "\n"); arc_cont(D_INIT_REASONS, "S3: "); if (BUGLVL(D_INIT_REASONS)) numprint = 0; iomem[index] = base; continue; out2: iounmap(base); out1: release_mem_region(*p, MIRROR_SIZE); out: *p-- = shmems[--numshmems]; index--; } arc_cont(D_INIT, "\n"); if (!numshmems) { arc_cont(D_NORMAL, "S3: No ARCnet cards found.\n"); for (port = &ports[0]; port < ports + numports; port++) release_region(*port, ARCNET_TOTAL_SIZE); kfree(shmems); kfree(iomem); return; } /* Stage 4: something of a dummy, to report the shmems that are * still possible after stage 3. */ numprint = -1; for (p = &shmems[0]; p < shmems + numshmems; p++) { numprint++; numprint %= 8; if (!numprint) { arc_cont(D_INIT, "\n"); arc_cont(D_INIT, "S4: "); } arc_cont(D_INIT, "%lXh ", *p); } arc_cont(D_INIT, "\n"); /* Stage 5: for any ports that have the correct status, can disable * the RESET flag, and (if no irq is given) generate an autoirq, * register an ARCnet device. * * Currently, we can only register one device per probe, so quit * after the first one is found. */ numprint = -1; for (port = &ports[0]; port < ports + numports; port++) { int found = 0; numprint++; numprint %= 8; if (!numprint) { arc_cont(D_INIT, "\n"); arc_cont(D_INIT, "S5: "); } arc_cont(D_INIT, "%Xh ", *port); ioaddr = *port; status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS); if ((status & 0x9D) != (NORXflag | RECONflag | TXFREEflag | RESETflag)) { arc_cont(D_INIT_REASONS, "(status=%Xh)\n", status); arc_cont(D_INIT_REASONS, "S5: "); if (BUGLVL(D_INIT_REASONS)) numprint = 0; release_region(*port, ARCNET_TOTAL_SIZE); *port-- = ports[--numports]; continue; } arcnet_outb(CFLAGScmd | RESETclear | CONFIGclear, ioaddr, COM9026_REG_W_COMMAND); status = arcnet_inb(ioaddr, COM9026_REG_R_STATUS); if (status & RESETflag) { arc_cont(D_INIT_REASONS, " (eternal reset, status=%Xh)\n", status); arc_cont(D_INIT_REASONS, "S5: "); if (BUGLVL(D_INIT_REASONS)) numprint = 0; release_region(*port, ARCNET_TOTAL_SIZE); *port-- = ports[--numports]; continue; } /* skip this completely if an IRQ was given, because maybe * we're on a machine that locks during autoirq! */ if (!irq) { /* if we do this, we're sure to get an IRQ since the * card has just reset and the NORXflag is on until * we tell it to start receiving. */ airqmask = probe_irq_on(); arcnet_outb(NORXflag, ioaddr, COM9026_REG_W_INTMASK); udelay(1); arcnet_outb(0, ioaddr, COM9026_REG_W_INTMASK); airq = probe_irq_off(airqmask); if (airq <= 0) { arc_cont(D_INIT_REASONS, "(airq=%d)\n", airq); arc_cont(D_INIT_REASONS, "S5: "); if (BUGLVL(D_INIT_REASONS)) numprint = 0; release_region(*port, ARCNET_TOTAL_SIZE); *port-- = ports[--numports]; continue; } } else { airq = irq; } arc_cont(D_INIT, "(%d,", airq); openparen = 1; /* Everything seems okay. But which shmem, if any, puts * back its signature byte when the card is reset? * * If there are multiple cards installed, there might be * multiple shmems still in the list. */ #ifdef FAST_PROBE if (numports > 1 || numshmems > 1) { arcnet_inb(ioaddr, COM9026_REG_R_RESET); mdelay(RESETtime); } else { /* just one shmem and port, assume they match */ arcnet_writeb(TESTvalue, iomem[0], COM9026_REG_W_INTMASK); } #else arcnet_inb(ioaddr, COM9026_REG_R_RESET); mdelay(RESETtime); #endif for (index = 0; index < numshmems; index++) { u_long ptr = shmems[index]; void __iomem *base = iomem[index]; if (arcnet_readb(base, COM9026_REG_R_STATUS) == TESTvalue) { /* found one */ arc_cont(D_INIT, "%lXh)\n", *p); openparen = 0; /* register the card */ if (com90xx_found(*port, airq, ptr, base) == 0) found = 1; numprint = -1; /* remove shmem from the list */ shmems[index] = shmems[--numshmems]; iomem[index] = iomem[numshmems]; break; /* go to the next I/O port */ } else { arc_cont(D_INIT_REASONS, "%Xh-", arcnet_readb(base, COM9026_REG_R_STATUS)); } } if (openparen) { if (BUGLVL(D_INIT)) pr_cont("no matching shmem)\n"); if (BUGLVL(D_INIT_REASONS)) { pr_cont("S5: "); numprint = 0; } } if (!found) release_region(*port, ARCNET_TOTAL_SIZE); *port-- = ports[--numports]; } if (BUGLVL(D_INIT_REASONS)) pr_cont("\n"); /* Now put back TESTvalue on all leftover shmems. */ for (index = 0; index < numshmems; index++) { arcnet_writeb(TESTvalue, iomem[index], COM9026_REG_W_INTMASK); iounmap(iomem[index]); release_mem_region(shmems[index], MIRROR_SIZE); } kfree(shmems); kfree(iomem); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)106963.82%428.57%
Al Viro42025.07%214.29%
Joe Perches18110.81%535.71%
Andrew Morton40.24%214.29%
Christoph Hellwig10.06%17.14%
Total1675100.00%14100.00%


static int __init check_mirror(unsigned long addr, size_t size) { void __iomem *p; int res = -1; if (!request_mem_region(addr, size, "arcnet (90xx)")) return -1; p = ioremap(addr, size); if (p) { if (arcnet_readb(p, COM9026_REG_R_STATUS) == TESTvalue) res = 1; else res = 0; iounmap(p); } release_mem_region(addr, size); return res; }

Contributors

PersonTokensPropCommitsCommitProp
Al Viro8391.21%240.00%
Linus Torvalds (pre-git)44.40%120.00%
Joe Perches33.30%120.00%
Julia Lawall11.10%120.00%
Total91100.00%5100.00%

/* Set up the struct net_device associated with this card. Called after * probing succeeds. */
static int __init com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem *p) { struct net_device *dev = NULL; struct arcnet_local *lp; u_long first_mirror, last_mirror; int mirror_size; /* allocate struct net_device */ dev = alloc_arcdev(device); if (!dev) { arc_cont(D_NORMAL, "com90xx: Can't allocate device!\n"); iounmap(p); release_mem_region(shmem, MIRROR_SIZE); return -ENOMEM; } lp = netdev_priv(dev); /* find the real shared memory start/end points, including mirrors */ /* guess the actual size of one "memory mirror" - the number of * bytes between copies of the shared memory. On most cards, it's * 2k (or there are no mirrors at all) but on some, it's 4k. */ mirror_size = MIRROR_SIZE; if (arcnet_readb(p, COM9026_REG_R_STATUS) == TESTvalue && check_mirror(shmem - MIRROR_SIZE, MIRROR_SIZE) == 0 && check_mirror(shmem - 2 * MIRROR_SIZE, MIRROR_SIZE) == 1) mirror_size = 2 * MIRROR_SIZE; first_mirror = shmem - mirror_size; while (check_mirror(first_mirror, mirror_size) == 1) first_mirror -= mirror_size; first_mirror += mirror_size; last_mirror = shmem + mirror_size; while (check_mirror(last_mirror, mirror_size) == 1) last_mirror += mirror_size; last_mirror -= mirror_size; dev->mem_start = first_mirror; dev->mem_end = last_mirror + MIRROR_SIZE - 1; iounmap(p); release_mem_region(shmem, MIRROR_SIZE); if (!request_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1, "arcnet (90xx)")) goto err_free_dev; /* reserve the irq */ if (request_irq(airq, arcnet_interrupt, 0, "arcnet (90xx)", dev)) { arc_printk(D_NORMAL, dev, "Can't get IRQ %d!\n", airq); goto err_release_mem; } dev->irq = airq; /* Initialize the rest of the device structure. */ lp->card_name = "COM90xx"; lp->hw.command = com90xx_command; lp->hw.status = com90xx_status; lp->hw.intmask = com90xx_setmask; lp->hw.reset = com90xx_reset; lp->hw.owner = THIS_MODULE; lp->hw.copy_to_card = com90xx_copy_to_card; lp->hw.copy_from_card = com90xx_copy_from_card; lp->mem_start = ioremap(dev->mem_start, dev->mem_end - dev->mem_start + 1); if (!lp->mem_start) { arc_printk(D_NORMAL, dev, "Can't remap device memory!\n"); goto err_free_irq; } /* get and check the station ID from offset 1 in shmem */ dev->dev_addr[0] = arcnet_readb(lp->mem_start, COM9026_REG_R_STATION); dev->base_addr = ioaddr; arc_printk(D_NORMAL, dev, "COM90xx station %02Xh found at %03lXh, IRQ %d, ShMem %lXh (%ld*%xh).\n", dev->dev_addr[0], dev->base_addr, dev->irq, dev->mem_start, (dev->mem_end - dev->mem_start + 1) / mirror_size, mirror_size); if (register_netdev(dev)) goto err_unmap; cards[numcards++] = dev; return 0; err_unmap: iounmap(lp->mem_start); err_free_irq: free_irq(dev->irq, dev); err_release_mem: release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); err_free_dev: free_netdev(dev); return -EIO; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)33865.38%538.46%
Al Viro15730.37%323.08%
Joe Perches173.29%323.08%
Wang Chen30.58%17.69%
Christoph Hellwig20.39%17.69%
Total517100.00%13100.00%


static void com90xx_command(struct net_device *dev, int cmd) { short ioaddr = dev->base_addr; arcnet_outb(cmd, ioaddr, COM9026_REG_W_COMMAND); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2583.33%266.67%
Joe Perches516.67%133.33%
Total30100.00%3100.00%


static int com90xx_status(struct net_device *dev) { short ioaddr = dev->base_addr; return arcnet_inb(ioaddr, COM9026_REG_R_STATUS); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2076.92%150.00%
Joe Perches623.08%150.00%
Total26100.00%2100.00%


static void com90xx_setmask(struct net_device *dev, int mask) { short ioaddr = dev->base_addr; arcnet_outb(mask, ioaddr, COM9026_REG_W_INTMASK); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)2583.33%266.67%
Joe Perches516.67%133.33%
Total30100.00%3100.00%

/* Do a hardware reset on the card, and set up necessary registers. * * This should be called as little as possible, because it disrupts the * token on the network (causes a RECON) and requires a significant delay. * * However, it does make sure the card is in a defined state. */
static int com90xx_reset(struct net_device *dev, int really_reset) { struct arcnet_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; arc_printk(D_INIT, dev, "Resetting (status=%02Xh)\n", arcnet_inb(ioaddr, COM9026_REG_R_STATUS)); if (really_reset) { /* reset the card */ arcnet_inb(ioaddr, COM9026_REG_R_RESET); mdelay(RESETtime); } /* clear flags & end reset */ arcnet_outb(CFLAGScmd | RESETclear, ioaddr, COM9026_REG_W_COMMAND); arcnet_outb(CFLAGScmd | CONFIGclear, ioaddr, COM9026_REG_W_COMMAND); #if 0 /* don't do this until we verify that it doesn't hurt older cards! */ arcnet_outb(arcnet_inb(ioaddr, COM9026_REG_RW_CONFIG) | ENABLE16flag, ioaddr, COM9026_REG_RW_CONFIG); #endif /* verify that the ARCnet signature byte is present */ if (arcnet_readb(lp->mem_start, COM9026_REG_R_STATUS) != TESTvalue) { if (really_reset) arc_printk(D_NORMAL, dev, "reset failed: TESTvalue not present.\n"); return 1; } /* enable extended (512-byte) packets */ arcnet_outb(CONFIGcmd | EXTconf, ioaddr, COM9026_REG_W_COMMAND); /* clean out all the memory to make debugging make more sense :) */ if (BUGLVL(D_DURING)) memset_io(lp->mem_start, 0x42, 2048); /* done! return success. */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)11469.94%545.45%
Joe Perches4527.61%436.36%
Wang Chen31.84%19.09%
Hannes Eder10.61%19.09%
Total163100.00%11100.00%


static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count) { struct arcnet_local *lp = netdev_priv(dev); void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset; TIME(dev, "memcpy_toio", count, memcpy_toio(memaddr, buf, count)); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6191.04%240.00%
Wang Chen34.48%120.00%
Joe Perches22.99%120.00%
Al Viro11.49%120.00%
Total67100.00%5100.00%


static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset, void *buf, int count) { struct arcnet_local *lp = netdev_priv(dev); void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset; TIME(dev, "memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)6191.04%240.00%
Wang Chen34.48%120.00%
Joe Perches22.99%120.00%
Al Viro11.49%120.00%
Total67100.00%5100.00%

MODULE_LICENSE("GPL");
static int __init com90xx_init(void) { if (irq == 2) irq = 9; com90xx_probe(); if (!numcards) return -EIO; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)3088.24%250.00%
Christoph Hellwig38.82%125.00%
Al Viro12.94%125.00%
Total34100.00%4100.00%


static void __exit com90xx_exit(void) { struct net_device *dev; struct arcnet_local *lp; int count; for (count = 0; count < numcards; count++) { dev = cards[count]; lp = netdev_priv(dev); unregister_netdev(dev); free_irq(dev->irq, dev); iounmap(lp->mem_start); release_region(dev->base_addr, ARCNET_TOTAL_SIZE); release_mem_region(dev->mem_start, dev->mem_end - dev->mem_start + 1); free_netdev(dev); } }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)9693.20%562.50%
Christoph Hellwig32.91%112.50%
Wang Chen32.91%112.50%
Stephen Hemminger10.97%112.50%
Total103100.00%8100.00%

module_init(com90xx_init); module_exit(com90xx_exit); #ifndef MODULE
static int __init com90xx_setup(char *s) { int ints[8]; s = get_options(s, 8, ints); if (!ints[0] && !*s) { pr_notice("Disabled\n"); return 1; } switch (ints[0]) { default: /* ERROR */ pr_err("Too many arguments\n"); case 3: /* Mem address */ shmem = ints[3]; case 2: /* IRQ */ irq = ints[2]; case 1: /* IO address */ io = ints[1]; } if (*s) snprintf(device, sizeof(device), "%s", s); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)10788.43%350.00%
Al Viro64.96%116.67%
Christoph Hellwig43.31%116.67%
Joe Perches43.31%116.67%
Total121100.00%6100.00%

__setup("com90xx=", com90xx_setup); #endif

Overall Contributors

PersonTokensPropCommitsCommitProp
Linus Torvalds (pre-git)212866.27%925.71%
Al Viro73923.01%411.43%
Joe Perches2858.88%1131.43%
Christoph Hellwig260.81%25.71%
Wang Chen150.47%12.86%
Dave Jones50.16%12.86%
Andrew Morton40.12%25.71%
Tejun Heo30.09%12.86%
Alexey Dobriyan30.09%12.86%
Julia Lawall10.03%12.86%
Hannes Eder10.03%12.86%
Stephen Hemminger10.03%12.86%
Total3211100.00%35100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.