[PATCH WIP] X-Surf-100 Ethernet driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a preliminary driver for the Individual Computers X-Surf-100 Ethernet
card, written by Michael Karcher. It currently works fine with the 3.2.0-4
kernel in Debian.

I'm posting it here as there may be other XSurf100 owners who are interested
in completing the driver.

Some documentation can be found at http://wiki.icomp.de/wiki/X-Surf-100

--- linux-3.2.0-4/drivers/net/ethernet/8390/ax88796.c.orig	2013-11-16 13:49:37.000000000 +0100
+++ linux-3.2.0-4/drivers/net/ethernet/8390/ax88796.c	2013-09-14 13:52:35.000000000 +0200
@@ -10,6 +10,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+#define CONFIG_AX88796_93CX6
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -18,7 +19,6 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
-#include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/netdevice.h>
@@ -28,9 +28,11 @@
 #include <linux/phy.h>
 #include <linux/eeprom_93cx6.h>
 #include <linux/slab.h>
+#include <linux/zorro.h>
 
 #include <net/ax88796.h>
 
+#include <asm/amigaints.h>
 #include <asm/system.h>
 
 /* Rename the lib8390.c functions to show that they are in this driver */
@@ -48,8 +50,8 @@
 /* force unsigned long back to 'void __iomem *' */
 #define ax_convert_addr(_a) ((void __force __iomem *)(_a))
 
-#define ei_inb(_a) readb(ax_convert_addr(_a))
-#define ei_outb(_v, _a) writeb(_v, ax_convert_addr(_a))
+#define ei_inb(_a) (z_readb(ax_convert_addr(_a)))
+#define ei_outb(_v, _a) z_writeb((_v), ax_convert_addr(_a))
 
 #define ei_inb_p(_a) ei_inb(_a)
 #define ei_outb_p(_v, _a) ei_outb(_v, _a)
@@ -79,6 +81,8 @@ static unsigned char version[] = "ax8879
 
 #define AX_GPOC_PPDSET	BIT(6)
 
+static int ax_mii_init(struct net_device *dev);
+
 /* device private data */
 
 struct ax_device {
@@ -101,6 +105,19 @@ struct ax_device {
 	u32 reg_offsets[0x20];
 };
 
+static inline void fast_out32(char *out, const char *in, size_t len)
+{
+	while(len > 128)
+	{
+		memcpy(out, in, 128);
+		in += 128;
+		len -= 128;
+	}
+	memcpy(out, in, len & 0xFC);
+	in += len & 0xFC;
+	memcpy(out, in, len & 3);
+}
+
 static inline struct ax_device *to_ax_dev(struct net_device *dev)
 {
 	struct ei_device *ei_local = netdev_priv(dev);
@@ -192,10 +209,10 @@ static void ax_get_8390_hdr(struct net_d
 	ei_outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
 
 	if (ei_local->word16)
-		readsw(nic_base + NE_DATAPORT, hdr,
+		ioread16_rep(nic_base + NE_DATAPORT, hdr,
 		       sizeof(struct e8390_pkt_hdr) >> 1);
 	else
-		readsb(nic_base + NE_DATAPORT, hdr,
+		ioread8_rep(nic_base + NE_DATAPORT, hdr,
 		       sizeof(struct e8390_pkt_hdr));
 
 	ei_outb(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
@@ -238,12 +255,12 @@ static void ax_block_input(struct net_de
 	ei_outb(E8390_RREAD+E8390_START, nic_base + NE_CMD);
 
 	if (ei_local->word16) {
-		readsw(nic_base + NE_DATAPORT, buf, count >> 1);
+		ioread16_rep(nic_base + NE_DATAPORT, buf, count >> 1);
 		if (count & 0x01)
 			buf[count-1] = ei_inb(nic_base + NE_DATAPORT);
 
 	} else {
-		readsb(nic_base + NE_DATAPORT, buf, count);
+		ioread8_rep(nic_base + NE_DATAPORT, buf, count);
 	}
 
 	ei_local->dmaing &= ~1;
@@ -286,10 +303,11 @@ static void ax_block_output(struct net_d
 	ei_outb(start_page, nic_base + EN0_RSARHI);
 
 	ei_outb(E8390_RWRITE+E8390_START, nic_base + NE_CMD);
-	if (ei_local->word16)
-		writesw(nic_base + NE_DATAPORT, buf, count >> 1);
+/*	if (ei_local->word16)
+		iowrite16_rep(nic_base + NE_DATAPORT, buf, count >> 1);
 	else
-		writesb(nic_base + NE_DATAPORT, buf, count);
+		iowrite8_rep(nic_base + NE_DATAPORT, buf, count);*/
+	fast_out32(nic_base + NE_DATAPORT, buf, count);
 
 	dma_start = jiffies;
 
@@ -400,6 +418,10 @@ static int ax_open(struct net_device *de
 
 	netdev_dbg(dev, "open\n");
 
+	ret = ax_mii_init(dev);
+	if (ret)
+		goto failed_request_irq;
+
 	ret = request_irq(dev->irq, ax_ei_interrupt, ax->irqflags,
 			  dev->name, dev);
 	if (ret)
@@ -446,6 +468,10 @@ static int ax_close(struct net_device *d
 	phy_disconnect(ax->phy_dev);
 
 	free_irq(dev->irq, dev);
+
+	mdiobus_unregister(ax->mii_bus);
+	kfree(ax->mii_bus->irq);
+	free_mdio_bitbang(ax->mii_bus);
 	return 0;
 }
 
@@ -468,7 +494,7 @@ static int ax_ioctl(struct net_device *d
 static void ax_get_drvinfo(struct net_device *dev,
 			   struct ethtool_drvinfo *info)
 {
-	struct platform_device *pdev = to_platform_device(dev->dev.parent);
+	struct zorro_dev *pdev = to_zorro_dev(dev->dev.parent);
 
 	strcpy(info->driver, DRV_NAME);
 	strcpy(info->version, DRV_VERSION);
@@ -608,7 +634,7 @@ static struct mdiobb_ops bb_ops = {
 
 static int ax_mii_init(struct net_device *dev)
 {
-	struct platform_device *pdev = to_platform_device(dev->dev.parent);
+	struct zorro_dev *pdev = to_zorro_dev(dev->dev.parent);
 	struct ei_device *ei_local = netdev_priv(dev);
 	struct ax_device *ax = to_ax_dev(dev);
 	int err, i;
@@ -692,10 +718,16 @@ static int ax_init_dev(struct net_device
 	if (ax->plat->flags & AXFLG_HAS_EEPROM) {
 		unsigned char SA_prom[32];
 
+		ei_outb(6, ioaddr + EN0_RCNTLO);
+		ei_outb(0, ioaddr + EN0_RCNTHI);
+		ei_outb(0, ioaddr + EN0_RSARLO);
+		ei_outb(0, ioaddr + EN0_RSARHI);
+		ei_outb(E8390_RREAD+E8390_START, ioaddr + NE_CMD);
 		for (i = 0; i < sizeof(SA_prom); i += 2) {
 			SA_prom[i] = ei_inb(ioaddr + NE_DATAPORT);
 			SA_prom[i + 1] = ei_inb(ioaddr + NE_DATAPORT);
 		}
+		ei_outb(ENISR_RDC, ioaddr + EN0_ISR);	/* Ack intr. */
 
 		if (ax->plat->wordlength == 2)
 			for (i = 0; i < 16; i++)
@@ -767,10 +799,6 @@ static int ax_init_dev(struct net_device
 	dev->netdev_ops = &ax_netdev_ops;
 	dev->ethtool_ops = &ax_ethtool_ops;
 
-	ret = ax_mii_init(dev);
-	if (ret)
-		goto out_irq;
-
 	ax_NS8390_init(dev, 0);
 
 	ret = register_netdev(dev);
@@ -790,31 +818,27 @@ static int ax_init_dev(struct net_device
 	return ret;
 }
 
-static int ax_remove(struct platform_device *pdev)
+static void ax_remove(struct zorro_dev *pdev)
 {
-	struct net_device *dev = platform_get_drvdata(pdev);
+	struct net_device *dev = zorro_get_drvdata(pdev);
 	struct ei_device *ei_local = netdev_priv(dev);
 	struct ax_device *ax = to_ax_dev(dev);
-	struct resource *mem;
 
 	unregister_netdev(dev);
-	free_irq(dev->irq, dev);
 
-	iounmap(ei_local->mem);
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(mem->start, resource_size(mem));
-
-	if (ax->map2) {
-		iounmap(ax->map2);
-		mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-		release_mem_region(mem->start, resource_size(mem));
-	}
+	z_iounmap(ei_local->mem);
+	release_mem_region(pdev->resource.start, 4*0x20+0x800);
 
 	free_netdev(dev);
-
-	return 0;
 }
 
+static const struct ax_plat_data xsurf100_plat_data = {
+	.flags = AXFLG_HAS_EEPROM,
+	.wordlength = 2,
+	.dcr_val = 0x48,
+	.rcr_val = 0x40,
+};
+
 /*
  * ax_probe
  *
@@ -822,13 +846,11 @@ static int ax_remove(struct platform_dev
  * notify us of a new device to attach to. Allocate memory, find the
  * resources and information passed, and map the necessary registers.
  */
-static int ax_probe(struct platform_device *pdev)
+static int ax_probe(struct zorro_dev *z, const struct zorro_device_id *ent)
 {
 	struct net_device *dev;
 	struct ei_device *ei_local;
 	struct ax_device *ax;
-	struct resource *irq, *mem, *mem2;
-	resource_size_t mem_size, mem2_size = 0;
 	int ret = 0;
 
 	dev = ax__alloc_ei_netdev(sizeof(struct ax_device));
@@ -836,107 +858,51 @@ static int ax_probe(struct platform_devi
 		return -ENOMEM;
 
 	/* ok, let's setup our device */
-	SET_NETDEV_DEV(dev, &pdev->dev);
+	SET_NETDEV_DEV(dev, &z->dev);
 	ei_local = netdev_priv(dev);
 	ax = to_ax_dev(dev);
 
-	ax->plat = pdev->dev.platform_data;
-	platform_set_drvdata(pdev, dev);
+	ax->plat = &xsurf100_plat_data;
+	zorro_set_drvdata(z, dev);
 
 	ei_local->rxcr_base = ax->plat->rcr_val;
 
-	/* find the platform resources */
-	irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-	if (!irq) {
-		dev_err(&pdev->dev, "no IRQ specified\n");
-		ret = -ENXIO;
-		goto exit_mem;
-	}
-
-	dev->irq = irq->start;
-	ax->irqflags = irq->flags & IRQF_TRIGGER_MASK;
-
-	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!mem) {
-		dev_err(&pdev->dev, "no MEM specified\n");
-		ret = -ENXIO;
-		goto exit_mem;
-	}
-
-	mem_size = resource_size(mem);
+	dev->irq = IRQ_AMIGA_PORTS;
+	ax->irqflags = IRQF_SHARED;
 
 	/*
 	 * setup the register offsets from either the platform data or
 	 * by using the size of the resource provided
 	 */
-	if (ax->plat->reg_offsets)
-		ei_local->reg_offset = ax->plat->reg_offsets;
-	else {
-		ei_local->reg_offset = ax->reg_offsets;
-		for (ret = 0; ret < 0x18; ret++)
-			ax->reg_offsets[ret] = (mem_size / 0x18) * ret;
-	}
+	ei_local->reg_offset = ax->reg_offsets;
+	for (ret = 0; ret < 0x20; ret++)
+		ax->reg_offsets[ret] = 4 * ret + 0x800;
 
-	if (!request_mem_region(mem->start, mem_size, pdev->name)) {
-		dev_err(&pdev->dev, "cannot reserve registers\n");
+	if (!request_mem_region(z->resource.start, 4*0x20+0x800, "X-Surf 100")) {
+		dev_err(&z->dev, "cannot reserve registers\n");
 		ret = -ENXIO;
 		goto exit_mem;
 	}
 
-	ei_local->mem = ioremap(mem->start, mem_size);
+	ei_local->mem = z_ioremap(z->resource.start, 4*0x20+0x800);
 	dev->base_addr = (unsigned long)ei_local->mem;
 
 	if (ei_local->mem == NULL) {
-		dev_err(&pdev->dev, "Cannot ioremap area %pR\n", mem);
+		dev_err(&z->dev, "Cannot ioremap area %pR\n", (void*)z->resource.start);
 
 		ret = -ENXIO;
 		goto exit_req;
 	}
 
-	/* look for reset area */
-	mem2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (!mem2) {
-		if (!ax->plat->reg_offsets) {
-			for (ret = 0; ret < 0x20; ret++)
-				ax->reg_offsets[ret] = (mem_size / 0x20) * ret;
-		}
-	} else {
-		mem2_size = resource_size(mem2);
-
-		if (!request_mem_region(mem2->start, mem2_size, pdev->name)) {
-			dev_err(&pdev->dev, "cannot reserve registers\n");
-			ret = -ENXIO;
-			goto exit_mem1;
-		}
-
-		ax->map2 = ioremap(mem2->start, mem2_size);
-		if (!ax->map2) {
-			dev_err(&pdev->dev, "cannot map reset register\n");
-			ret = -ENXIO;
-			goto exit_mem2;
-		}
-
-		ei_local->reg_offset[0x1f] = ax->map2 - ei_local->mem;
-	}
-
 	/* got resources, now initialise and register device */
 	ret = ax_init_dev(dev);
 	if (!ret)
 		return 0;
 
-	if (!ax->map2)
-		goto exit_mem1;
-
-	iounmap(ax->map2);
-
- exit_mem2:
-	release_mem_region(mem2->start, mem2_size);
-
- exit_mem1:
-	iounmap(ei_local->mem);
+	z_iounmap(ei_local->mem);
 
  exit_req:
-	release_mem_region(mem->start, mem_size);
+	release_mem_region(z->resource.start, 4*0x20+0x800);
 
  exit_mem:
 	free_netdev(dev);
@@ -944,43 +910,22 @@ static int ax_probe(struct platform_devi
 	return ret;
 }
 
-/* suspend and resume */
-
-#ifdef CONFIG_PM
-static int ax_suspend(struct platform_device *dev, pm_message_t state)
-{
-	struct net_device *ndev = platform_get_drvdata(dev);
-	struct ax_device *ax = to_ax_dev(ndev);
-
-	ax->resume_open = ax->running;
+#define ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF100 ZORRO_ID(INDIVIDUAL_COMPUTERS, 0x64, 0)
 
-	netif_device_detach(ndev);
-	ax_close(ndev);
-
-	return 0;
-}
-
-static int ax_resume(struct platform_device *pdev)
-{
-	struct net_device *ndev = platform_get_drvdata(pdev);
-	struct ax_device *ax = to_ax_dev(ndev);
-
-	ax_initial_setup(ndev, netdev_priv(ndev));
-	ax_NS8390_init(ndev, ax->resume_open);
-	netif_device_attach(ndev);
-
-	if (ax->resume_open)
-		ax_open(ndev);
-
-	return 0;
-}
+static struct zorro_device_id xsurf100_zorro_tbl[] __devinitdata = {
+	{ ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF100, },
+	{ 0 }
+};
+MODULE_DEVICE_TABLE(zorro, xsurf100_zorro_tbl);
 
-#else
-#define ax_suspend NULL
-#define ax_resume NULL
-#endif
+static struct zorro_driver xsurf100_driver = {
+	.name		= "xsurf100",
+	.id_table	= xsurf100_zorro_tbl,
+	.probe		= ax_probe,
+	.remove		= __devexit_p(ax_remove),
+};
 
-static struct platform_driver axdrv = {
+/*static struct platform_driver axdrv = {
 	.driver	= {
 		.name		= "ax88796",
 		.owner		= THIS_MODULE,
@@ -989,22 +934,23 @@ static struct platform_driver axdrv = {
 	.remove		= ax_remove,
 	.suspend	= ax_suspend,
 	.resume		= ax_resume,
-};
+};*/
 
 static int __init axdrv_init(void)
 {
-	return platform_driver_register(&axdrv);
+	return zorro_register_driver(&xsurf100_driver);
+//	return platform_driver_register(&axdrv);
 }
 
 static void __exit axdrv_exit(void)
 {
-	platform_driver_unregister(&axdrv);
+	zorro_unregister_driver(&xsurf100_driver);
+//	platform_driver_unregister(&axdrv);
 }
 
 module_init(axdrv_init);
 module_exit(axdrv_exit);
 
-MODULE_DESCRIPTION("AX88796 10/100 Ethernet platform driver");
-MODULE_AUTHOR("Ben Dooks, <ben@xxxxxxxxxxxx>");
+MODULE_DESCRIPTION("X-Surf 100 driver");
+MODULE_AUTHOR("Michael Karcher <kernel@xxxxxxxxxxxxxxxxxxxxxxxxxxxx>");
 MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:ax88796");

Gr{oetje,eeting}s,

						Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@xxxxxxxxxxxxxx

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
							    -- Linus Torvalds
--
To unsubscribe from this list: send the line "unsubscribe linux-m68k" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Video for Linux]     [Yosemite News]     [Linux S/390]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux