public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] PCMCIA updates
@ 2003-04-22  0:19 Russell King
  0 siblings, 0 replies; 4+ messages in thread
From: Russell King @ 2003-04-22  0:19 UTC (permalink / raw)
  To: Linux Kernel List

A request for Linus to pull a set of PCMCIA changes has been made.  You
can get the patch from:

  http://patches.arm.linux.org.uk/pcmcia-20030421.diff

Much of this stuff has been aired on the linux-pcmcia list (iirc care of
lists.infradead.org)

This will update the following files:

 drivers/net/wireless/orinoco_cs.c |    1 
 drivers/pcmcia/cs.c               |  827 +++++++++++++++++++++++++++-----------
 drivers/pcmcia/cs_internal.h      |   18 
 drivers/pcmcia/rsrc_mgr.c         |   20 
 include/pcmcia/bus_ops.h          |    2 
 include/pcmcia/driver_ops.h       |    2 
 include/pcmcia/ds.h               |    2 
 7 files changed, 617 insertions, 255 deletions

through these ChangeSets:

<proski@org.rmk.(none)> (03/04/21 1.1122)
	[PCMCIA] validate_mem uses uninitialized memory.
	
	Patch from Pavel Roskin.
	
	If I compile a recent 2.5.x kernel without CONFIG_ISA defined, I get
	an oops in validate_mem().  Stack trace contains 0x6b6b6b6 - a clear
	sign that freed memory is being accessed.
	
	It's the second validate_mem() in drivers/pcmcia/rsrc_mgr.c - the one
	used when CONFIG_PCMCIA_PROBE is not defined.  It turns out the memory
	is freed in do_mem_probe() when it's called from validate_mem().
	
	The solution is to use the same trick as in the first validate_mem().
	This problem is quite serious and it's not specific to the plx9052
	driver.  I see it with yenta_socket as well.

<linux@de.rmk.(none)> (03/04/19 1.1121)
	[PCMCIA] remove unused files [Christoph Hellwig]
	
	From Christoph Hellwig
	
	There's no need to keep the stubs around.

<linux@de.rmk.(none)> (03/04/19 1.1120)
	[PCMCIA] Fix compilation of cardmgr [Pavel Roskin]
	
	From Pavel Roskin
	
	ds.h should not be including linux/device.h when compiling userspace
	code.

<rmk@flint.arm.linux.org.uk> (03/04/19 1.1119)
	[PCMCIA] Bring in PCMCIA work queue and state machine.
	
	This cset fixes the boot-time deadlock which occurs when a Cardbus
	card is inserted.  The deadlock occurs because:
	
	- the ds module is inserted
	- ds registers a driver model interface for pcmcia socket drivers,
	  which takes the global devclass_sem.
	- ds causes the pcmcia core to evaluate the status of the sockets,
	  and perform "card insertion" processing if cards are present.
	- this processing detects a cardbus card, and calls the cardbus code
	  to scan pci devices, and add them to the device tree.
	- each device gets passed to the device model's class layer, which
	  tries to take devclass_sem.  However, we locked it while
	  initialising the ds module -> deadlock.
	
	We fix this by making the card insertion/removal asynchronous to the
	initialisation thread by using a work queue.  However, since we will
	be calling drivers, which may want to use workqueue services, we
	need to use a separate workqueue.
	
	We also bring in a state machine to handle the card insertion,
	removal, suspend and reset code.  This ensures that two operations
	can not run against a single socket at the same time.
	
	Unfortunately, the workqueue model has an annoying feature which
	causes it to we spawn N threads, one for each CPU in the system,
	when we create our work queue.  This is rather overkill.


-- 
Russell King (rmk@arm.linux.org.uk)                The developer of ARM Linux
             http://www.arm.linux.org.uk/personal/aboutme.html


^ permalink raw reply	[flat|nested] 4+ messages in thread
* [PATCH] PCMCIA updates
@ 2003-05-28 15:22 Russell King
  0 siblings, 0 replies; 4+ messages in thread
From: Russell King @ 2003-05-28 15:22 UTC (permalink / raw)
  To: Linux Kernel List

Here's the patch for a set of PCMCIA updates which will shortly be heading
Linus-ward.  As normal, if you want a bk tree to pull, just ask in personal
mail.

<proski@org.rmk.(none)> (03/05/28 1.1127.7.2)
	[PATCH] Fix crash when unloading yenta_socket in Linux 2.5.69
	
	socket->base is unmapped in yenta_close(), which is called by
	cardbus_remove().  The value of socket->base is not changed to
	NULL, so it becomes invalid.
	
	Then cardbus_remove() calls class_device_unregister(), which calls
	pcmcia_unregister_socket(), which it turn tries to access memory
	space of the socket.

<hch@de.rmk.(none)> (03/05/18 1.1127.7.1)
	[PATCH] kill register_pccard_driver
	
	I tried to get as much in as possible through the maintainers but
	didn't get much feedback.. (Except two batches included and Kai
	ACKing the ISDN stuff).
	
	So here's a big patch to move the reamining users over to
	pcmcia_register_driver and kill it off.

diff -Nru a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
--- a/drivers/char/pcmcia/synclink_cs.c	Wed May 28 16:18:29 2003
+++ b/drivers/char/pcmcia/synclink_cs.c	Wed May 28 16:18:30 2003
@@ -3131,9 +3131,18 @@
 	}
 }
 
+static struct pcmcia_driver mgslpc_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "synclink_cs",
+	},
+	.attach		= mgslpc_attach,
+	.detach		= mgslpc_detach,
+};
+
 static int __init synclink_cs_init(void)
 {
-    servinfo_t serv;
+    int error;
 
     if (break_on_load) {
 	    mgslpc_get_text_ptr();
@@ -3142,13 +3151,9 @@
 
     printk("%s %s\n", driver_name, driver_version);
 
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	    printk(KERN_NOTICE "synclink_cs: Card Services release "
-		   "does not match!\n");
-	    return -1;
-    }
-    register_pccard_driver(&dev_info, &mgslpc_attach, &mgslpc_detach);
+    error = pcmcia_register_driver(&mgslpc_driver);
+    if (error)
+	    return error;
 
     /* Initialize the tty_driver structure */
 	
@@ -3217,7 +3222,9 @@
 		printk("%s(%d) failed to unregister tty driver err=%d\n",
 		       __FILE__,__LINE__,rc);
 
-	unregister_pccard_driver(&dev_info);
+	pcmcia_unregister_driver(&mgslpc_driver);
+
+	/* XXX: this really needs to move into generic code.. */
 	while (dev_list != NULL) {
 		if (dev_list->state & DEV_CONFIG)
 			mgslpc_release((u_long)dev_list);
diff -Nru a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
--- a/drivers/ide/legacy/ide-cs.c	Wed May 28 16:18:30 2003
+++ b/drivers/ide/legacy/ide-cs.c	Wed May 28 16:18:30 2003
@@ -470,28 +470,25 @@
     return 0;
 } /* ide_event */
 
-/*====================================================================*/
+static struct pcmcia_driver ide_cs_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "ide_cs",
+	},
+	.attach		= ide_attach,
+	.detach		= ide_detach,
+};
 
 static int __init init_ide_cs(void)
 {
-    servinfo_t serv;
-    DEBUG(0, "%s\n", version);
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "ide-cs: Card Services release "
-	       "does not match!\n");
-	return -EINVAL;
-    }
-    register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
-    return 0;
+	return pcmcia_register_driver(&ide_cs_driver);
 }
 
 static void __exit exit_ide_cs(void)
 {
-    DEBUG(0, "ide-cs: unloading\n");
-    unregister_pccard_driver(&dev_info);
-    while (dev_list != NULL)
-	ide_detach(dev_list);
+	pcmcia_unregister_driver(&ide_cs_driver);
+	while (dev_list != NULL)
+		ide_detach(dev_list);
 }
 
 module_init(init_ide_cs);
diff -Nru a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
--- a/drivers/isdn/hardware/avm/avm_cs.c	Wed May 28 16:18:29 2003
+++ b/drivers/isdn/hardware/avm/avm_cs.c	Wed May 28 16:18:29 2003
@@ -510,29 +510,30 @@
     return 0;
 } /* avmcs_event */
 
-/*====================================================================*/
+static struct pcmcia_driver avmcs_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "avmcs_cs",
+	},
+	.attach		= avmcs_attach,
+	.detach		= avmcs_detach,
+};
 
 static int __init avmcs_init(void)
 {
-    servinfo_t serv;
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "avm_cs: Card Services release "
-	       "does not match!\n");
-	return -1;
-    }
-    register_pccard_driver(&dev_info, &avmcs_attach, &avmcs_detach);
-    return 0;
+	return pcmcia_register_driver(&avmcs_driver);
 }
 
 static void __exit avmcs_exit(void)
 {
-    unregister_pccard_driver(&dev_info);
-    while (dev_list != NULL) {
-	if (dev_list->state & DEV_CONFIG)
-	    avmcs_release((u_long)dev_list);
-	avmcs_detach(dev_list);
-    }
+	pcmcia_unregister_driver(&avmcs_driver);
+
+	/* XXX: this really needs to move into generic code.. */
+	while (dev_list != NULL) {
+		if (dev_list->state & DEV_CONFIG)
+			avmcs_release((u_long)dev_list);
+		avmcs_detach(dev_list);
+	}
 }
 
 module_init(avmcs_init);
diff -Nru a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
--- a/drivers/isdn/hisax/avma1_cs.c	Wed May 28 16:18:30 2003
+++ b/drivers/isdn/hisax/avma1_cs.c	Wed May 28 16:18:30 2003
@@ -515,30 +515,30 @@
     return 0;
 } /* avma1cs_event */
 
-/*====================================================================*/
+static struct pcmcia_driver avma1cs_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "avma1_cs",
+	},
+	.attach		= avma1cs_attach,
+	.detach		= avma1cs_detach,
+};
 
 static int __init init_avma1_cs(void)
 {
-    servinfo_t serv;
-    DEBUG(0, "%s\n", version);
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-        printk(KERN_NOTICE "avma1_cs: Card Services release "
-               "does not match!\n");
-        return -1;
-    }
-    register_pccard_driver(&dev_info, &avma1cs_attach, &avma1cs_detach);
-    return 0;
+	return pcmcia_register_driver(&avma1cs_driver);
 }
 
 static void __exit exit_avma1_cs(void)
 {
-    DEBUG(0, "avma1_cs: unloading\n");
-    unregister_pccard_driver(&dev_info);
-    while (dev_list != NULL)
-	if (dev_list->state & DEV_CONFIG)
-	    avma1cs_release((u_long)dev_list);
-        avma1cs_detach(dev_list);
+	pcmcia_unregister_driver(&avma1cs_driver);
+
+	/* XXX: this really needs to move into generic code.. */
+	while (dev_list != NULL) {
+		if (dev_list->state & DEV_CONFIG)
+			avma1cs_release((u_long)dev_list);
+		avma1cs_detach(dev_list);
+	}
 }
 
 module_init(init_avma1_cs);
diff -Nru a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
--- a/drivers/isdn/hisax/elsa_cs.c	Wed May 28 16:18:30 2003
+++ b/drivers/isdn/hisax/elsa_cs.c	Wed May 28 16:18:30 2003
@@ -531,28 +531,27 @@
     return 0;
 } /* elsa_cs_event */
 
-/*====================================================================*/
+static struct pcmcia_driver elsa_cs_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "elsa_cs",
+	},
+	.attach		= elsa_cs_attach,
+	.detach		= elsa_cs_detach,
+};
 
 static int __init init_elsa_cs(void)
 {
-    servinfo_t serv;
-    DEBUG(0, "%s\n", version);
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-        printk(KERN_NOTICE "elsa_cs: Card Services release "
-               "does not match!\n");
-        return -1;
-    }
-    register_pccard_driver(&dev_info, &elsa_cs_attach, &elsa_cs_detach);
-    return 0;
+	return pcmcia_register_driver(&elsa_cs_driver);
 }
 
 static void __exit exit_elsa_cs(void)
 {
-    DEBUG(0, "elsa_cs: unloading\n");
-    unregister_pccard_driver(&dev_info);
-    while (dev_list != NULL)
-        elsa_cs_detach(dev_list);
+	pcmcia_unregister_driver(&elsa_cs_driver);
+
+	/* XXX: this really needs to move into generic code.. */
+	while (dev_list != NULL)
+		elsa_cs_detach(dev_list);
 }
 
 module_init(init_elsa_cs);
diff -Nru a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
--- a/drivers/isdn/hisax/sedlbauer_cs.c	Wed May 28 16:18:29 2003
+++ b/drivers/isdn/hisax/sedlbauer_cs.c	Wed May 28 16:18:29 2003
@@ -633,34 +633,32 @@
     return 0;
 } /* sedlbauer_event */
 
-/*====================================================================*/
+static struct pcmcia_driver sedlbauer_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "sedlbauer_cs",
+	},
+	.attach		= sedlbauer_attach,
+	.detach		= sedlbauer_detach,
+};
 
 static int __init init_sedlbauer_cs(void)
 {
-    servinfo_t serv;
-    DEBUG(0, "%s\n", version);
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "sedlbauer_cs: Card Services release "
-	       "does not match!\n");
-	return -1;
-    }
-    register_pccard_driver(&dev_info, &sedlbauer_attach, &sedlbauer_detach);
-    return 0;
+	return pcmcia_register_driver(&sedlbauer_driver);
 }
 
 static void __exit exit_sedlbauer_cs(void)
 {
-    DEBUG(0, "sedlbauer_cs: unloading\n");
-    unregister_pccard_driver(&dev_info);
-    while (dev_list != NULL) {
-	del_timer(&dev_list->release);
-	if (dev_list->state & DEV_CONFIG)
-	    sedlbauer_release((u_long)dev_list);
-	sedlbauer_detach(dev_list);
-    }
+	pcmcia_unregister_driver(&sedlbauer_driver);
+
+	/* XXX: this really needs to move into generic code.. */
+	while (dev_list != NULL) {
+		del_timer(&dev_list->release);
+		if (dev_list->state & DEV_CONFIG)
+			sedlbauer_release((u_long)dev_list);
+		sedlbauer_detach(dev_list);
+	}
 }
 
 module_init(init_sedlbauer_cs);
 module_exit(exit_sedlbauer_cs);
-
diff -Nru a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
--- a/drivers/mtd/maps/pcmciamtd.c	Wed May 28 16:18:29 2003
+++ b/drivers/mtd/maps/pcmciamtd.c	Wed May 28 16:18:29 2003
@@ -836,17 +836,18 @@
 	return link;
 }
 
+static struct pcmcia_driver pcmciamtd_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "pcmciamtd",
+	},
+	.attach		= pcmciamtd_attach,
+	.detach		= pcmciamtd_detach,
+};
 
 static int __init init_pcmciamtd(void)
 {
-	servinfo_t serv;
-
 	info(DRIVER_DESC " " DRIVER_VERSION);
-	CardServices(GetCardServicesInfo, &serv);
-	if (serv.Revision != CS_RELEASE_CODE) {
-		err("Card Services release does not match!");
-		return -1;
-	}
 
 	if(buswidth && buswidth != 1 && buswidth != 2) {
 		info("bad buswidth (%d), using default", buswidth);
@@ -860,8 +861,8 @@
 		info("bad mem_type (%d), using default", mem_type);
 		mem_type = 0;
 	}
-	register_pccard_driver(&dev_info, &pcmciamtd_attach, &pcmciamtd_detach);
-	return 0;
+
+	return pcmcia_register_driver(&pcmciamtd_driver);
 }
 
 
@@ -870,7 +871,10 @@
 	struct list_head *temp1, *temp2;
 
 	DEBUG(1, DRIVER_DESC " unloading");
-	unregister_pccard_driver(&dev_info);
+
+	pcmcia_unregister_driver(&pcmciamtd_driver);
+
+	/* XXX: this really needs to move into generic code.. */
 	list_for_each_safe(temp1, temp2, &dev_list) {
 		dev_link_t *link = &list_entry(temp1, struct pcmciamtd_dev, list)->link;
 		if (link && (link->state & DEV_CONFIG)) {
diff -Nru a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
--- a/drivers/net/pcmcia/pcnet_cs.c	Wed May 28 16:18:30 2003
+++ b/drivers/net/pcmcia/pcnet_cs.c	Wed May 28 16:18:30 2003
@@ -1620,16 +1620,7 @@
 
 static int __init init_pcnet_cs(void)
 {
-    servinfo_t serv;
-    DEBUG(0, "%s\n", version);
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "pcnet_cs: Card Services release "
-	       "does not match!\n");
-	return -EINVAL;
-    }
-    pcmcia_register_driver(&pcnet_driver);
-    return 0;
+    return pcmcia_register_driver(&pcnet_driver);
 }
 
 static void __exit exit_pcnet_cs(void)
diff -Nru a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
--- a/drivers/parport/parport_cs.c	Wed May 28 16:18:31 2003
+++ b/drivers/parport/parport_cs.c	Wed May 28 16:18:31 2003
@@ -390,28 +390,27 @@
     return 0;
 } /* parport_event */
 
-/*====================================================================*/
+static struct pcmcia_driver parport_cs_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "parport_cs",
+	},
+	.attach		= parport_attach,
+	.detach		= parport_detach,
+};
 
 static int __init init_parport_cs(void)
 {
-    servinfo_t serv;
-    DEBUG(0, "%s\n", version);
-    CardServices(GetCardServicesInfo, &serv);
-    if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "parport_cs: Card Services release "
-	       "does not match!\n");
-	return -EINVAL;
-    }
-    register_pccard_driver(&dev_info, &parport_attach, &parport_detach);
-    return 0;
+	return pcmcia_register_driver(&parport_cs_driver);
 }
 
 static void __exit exit_parport_cs(void)
 {
-    DEBUG(0, "parport_cs: unloading\n");
-    unregister_pccard_driver(&dev_info);
-    while (dev_list != NULL)
-	parport_detach(dev_list);
+	pcmcia_unregister_driver(&parport_cs_driver);
+
+	/* XXX: this really needs to move into generic code.. */
+	while (dev_list != NULL)
+		parport_detach(dev_list);
 }
 
 module_init(init_parport_cs);
diff -Nru a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
--- a/drivers/pcmcia/ds.c	Wed May 28 16:18:30 2003
+++ b/drivers/pcmcia/ds.c	Wed May 28 16:18:30 2003
@@ -182,50 +182,6 @@
 }
 EXPORT_SYMBOL(pcmcia_unregister_driver);
 
-
-int register_pccard_driver(dev_info_t *dev_info,
-			   dev_link_t *(*attach)(void),
-			   void (*detach)(dev_link_t *))
-{
-    struct pcmcia_driver *driver;
-
-    DEBUG(0, "ds: register_pccard_driver('%s')\n", (char *)dev_info);
-    driver = get_pcmcia_driver(dev_info);
-    if (driver)
-	    return -EBUSY;
-
-    driver = kmalloc(sizeof(struct pcmcia_driver), GFP_KERNEL);
-    if (!driver) return -ENOMEM;
-    memset(driver, 0, sizeof(struct pcmcia_driver));
-    driver->drv.name = (char *)dev_info;
-    pcmcia_register_driver(driver);
-
-    driver->attach = attach;
-    driver->detach = detach;
-
-    return 0;
-} /* register_pccard_driver */
-
-/*====================================================================*/
-
-int unregister_pccard_driver(dev_info_t *dev_info)
-{
-    struct pcmcia_driver *driver;
-
-    DEBUG(0, "ds: unregister_pccard_driver('%s')\n",
-	  (char *)dev_info);
-
-    driver = get_pcmcia_driver(dev_info);
-    if (!driver)
-	return -ENODEV;
-    
-    pcmcia_unregister_driver(driver);
-    kfree(driver);
-    return 0;
-} /* unregister_pccard_driver */
-
-/*====================================================================*/
-
 #ifdef CONFIG_PROC_FS
 static int proc_read_drivers_callback(struct device_driver *driver, void *d)
 {
@@ -875,11 +831,6 @@
 	.write		= ds_write,
 	.poll		= ds_poll,
 };
-
-EXPORT_SYMBOL(register_pccard_driver);
-EXPORT_SYMBOL(unregister_pccard_driver);
-
-/*====================================================================*/
 
 static int __devinit pcmcia_bus_add_socket(struct device *dev, unsigned int socket_nr)
 {
diff -Nru a/drivers/pcmcia/pci_socket.c b/drivers/pcmcia/pci_socket.c
--- a/drivers/pcmcia/pci_socket.c	Wed May 28 16:18:31 2003
+++ b/drivers/pcmcia/pci_socket.c	Wed May 28 16:18:31 2003
@@ -196,9 +196,9 @@
 	pci_socket_t *socket = pci_get_drvdata(dev);
 
 	/* note: we are already unregistered from the cs core */
+	class_device_unregister(&socket->cls_d.class_dev);
 	if (socket->op && socket->op->close)
 		socket->op->close(socket);
-	class_device_unregister(&socket->cls_d.class_dev);
 	pci_set_drvdata(dev, NULL);
 }
 
diff -Nru a/include/pcmcia/ds.h b/include/pcmcia/ds.h
--- a/include/pcmcia/ds.h	Wed May 28 16:18:29 2003
+++ b/include/pcmcia/ds.h	Wed May 28 16:18:29 2003
@@ -156,12 +156,6 @@
 int pcmcia_register_driver(struct pcmcia_driver *driver);
 void pcmcia_unregister_driver(struct pcmcia_driver *driver);
 
-/* legacy driver registration interface.  don't use in new code */
-int register_pccard_driver(dev_info_t *dev_info,
-			   dev_link_t *(*attach)(void),
-			   void (*detach)(dev_link_t *));
-int unregister_pccard_driver(dev_info_t *dev_info);
-
 /* error reporting */
 void cs_error(client_handle_t handle, int func, int ret);
 

-- 
Russell King (rmk@arm.linux.org.uk)                The developer of ARM Linux
             http://www.arm.linux.org.uk/personal/aboutme.html


^ permalink raw reply	[flat|nested] 4+ messages in thread
* [PATCH] PCMCIA updates
@ 2003-12-22 17:21 Russell King
  2003-12-22 17:37 ` Davide Libenzi
  0 siblings, 1 reply; 4+ messages in thread
From: Russell King @ 2003-12-22 17:21 UTC (permalink / raw)
  To: Linux Kernel List

Here's a patch covering a forward-port of a couple of changes from
David Hinds to 2.6.  I've tested them, and the ISA/PCI irq fix has
been independently tested.

I'm also sending this to Linus/akpm shortly.

| [PCMCIA] fix ISA/PCI interrupt allocation
| 
| Patch from David Hinds
| 
| This is a forward port of a patch for 2.4.  This changes interrupt
| allocation for 16-bit cards so that if ISA interrupts are all in
| use, the bridge's PCI interrupt will be used.
|
| [PCMCIA] fix half/full duplex selection for pcnet_cs driver
| 
| Patch from David Hinds.
| 
| Another forward port from 2.4; this fixes full/half duplex selection
| for certain DL10019 based cards.


diff -Nru a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
--- a/drivers/net/pcmcia/pcnet_cs.c	Mon Dec 22 17:16:34 2003
+++ b/drivers/net/pcmcia/pcnet_cs.c	Mon Dec 22 17:16:34 2003
@@ -11,7 +11,7 @@
 
     Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
 
-    pcnet_cs.c 1.149 2002/06/29 06:27:37
+    pcnet_cs.c 1.153 2003/11/09 18:53:09
     
     The network driver code is based on Donald Becker's NE2000 code:
 
@@ -74,7 +74,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"pcnet_cs.c 1.149 2002/06/29 06:27:37 (David Hinds)";
+"pcnet_cs.c 1.153 2003/11/09 18:53:09 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -871,13 +871,15 @@
 
     MII interface support for DL10019 and DL10022 based cards
 
-    On the DL10019, the MII IO direction bit is 0x10; on  the DL10022
+    On the DL10019, the MII IO direction bit is 0x10; on the DL10022
     it is 0x20.  Setting both bits seems to work on both card types.
 
 ======================================================================*/
 
 #define DLINK_GPIO		0x1c
 #define DLINK_DIAG		0x1d
+#define DLINK_EEPROM		0x1e
+
 #define MDIO_SHIFT_CLK		0x80
 #define MDIO_DATA_OUT		0x40
 #define MDIO_DIR_WRITE		0x30
@@ -940,6 +942,98 @@
     outb_p(0x00, addr);
 }
 
+/*======================================================================
+
+    EEPROM access routines for DL10019 and DL10022 based cards
+
+======================================================================*/
+
+#define EE_EEP		0x40
+#define EE_ASIC		0x10
+#define EE_CS		0x08
+#define EE_CK		0x04
+#define EE_DO		0x02
+#define EE_DI		0x01
+#define EE_ADOT		0x01	/* DataOut for ASIC */
+#define EE_READ_CMD	0x06	
+
+#define DL19FDUPLX	0x0400	/* DL10019 Full duplex mode */
+
+static int read_eeprom(ioaddr_t ioaddr, int location)
+{
+    int i, retval = 0;
+    ioaddr_t ee_addr = ioaddr + DLINK_EEPROM;
+    int read_cmd = location | (EE_READ_CMD << 8);
+
+    outb(0, ee_addr);
+    outb(EE_EEP|EE_CS, ee_addr);
+
+    /* Shift the read command bits out. */
+    for (i = 10; i >= 0; i--) {
+	short dataval = (read_cmd & (1 << i)) ? EE_DO : 0;
+	outb_p(EE_EEP|EE_CS|dataval, ee_addr);
+	outb_p(EE_EEP|EE_CS|dataval|EE_CK, ee_addr);
+    }
+    outb(EE_EEP|EE_CS, ee_addr);
+
+    for (i = 16; i > 0; i--) {
+	outb_p(EE_EEP|EE_CS | EE_CK, ee_addr);
+	retval = (retval << 1) | ((inb(ee_addr) & EE_DI) ? 1 : 0);
+	outb_p(EE_EEP|EE_CS, ee_addr);
+    }
+
+    /* Terminate the EEPROM access. */
+    outb(0, ee_addr);
+    return retval;
+}
+
+/*
+    The internal ASIC registers can be changed by EEPROM READ access
+    with EE_ASIC bit set.
+    In ASIC mode, EE_ADOT is used to output the data to the ASIC.
+*/ 
+
+static void write_asic(ioaddr_t ioaddr, int location, short asic_data)
+{
+	int i;
+	ioaddr_t ee_addr = ioaddr + DLINK_EEPROM;
+	short dataval;
+	int read_cmd = location | (EE_READ_CMD << 8);
+
+	asic_data |= read_eeprom(ioaddr, location);
+
+	outb(0, ee_addr);
+	outb(EE_ASIC|EE_CS|EE_DI, ee_addr);
+	
+	read_cmd = read_cmd >> 1;
+
+	/* Shift the read command bits out. */
+	for (i = 9; i >= 0; i--) {
+		dataval = (read_cmd & (1 << i)) ? EE_DO : 0;
+		outb_p(EE_ASIC|EE_CS|EE_DI|dataval, ee_addr);
+		outb_p(EE_ASIC|EE_CS|EE_DI|dataval|EE_CK, ee_addr);
+		outb_p(EE_ASIC|EE_CS|EE_DI|dataval, ee_addr);
+	}
+	// sync
+	outb(EE_ASIC|EE_CS, ee_addr);
+	outb(EE_ASIC|EE_CS|EE_CK, ee_addr);
+	outb(EE_ASIC|EE_CS, ee_addr);
+
+	for (i = 15; i >= 0; i--) {
+		dataval = (asic_data & (1 << i)) ? EE_ADOT : 0;
+		outb_p(EE_ASIC|EE_CS|dataval, ee_addr);
+		outb_p(EE_ASIC|EE_CS|dataval|EE_CK, ee_addr);
+		outb_p(EE_ASIC|EE_CS|dataval, ee_addr);
+	}
+
+	/* Terminate the ASIC access. */
+	outb(EE_ASIC|EE_DI, ee_addr);
+	outb(EE_ASIC|EE_DI| EE_CK, ee_addr);
+	outb(EE_ASIC|EE_DI, ee_addr);
+
+	outb(0, ee_addr);
+}
+
 /*====================================================================*/
 
 static void set_misc_reg(struct net_device *dev)
@@ -1154,6 +1248,9 @@
 	if (link && (info->flags & IS_DL10022)) {
 	    /* Disable collision detection on full duplex links */
 	    outb((p & 0x0140) ? 4 : 0, nic_base + DLINK_DIAG);
+	} else if (link && (info->flags & IS_DL10019)) {
+	    /* Disable collision detection on full duplex links */
+	    write_asic(dev->base_addr, 4, (p & 0x140) ? DL19FDUPLX : 0);
 	}
 	if (link) {
 	    if (info->phy_id == info->eth_phy) {
diff -Nru a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
--- a/drivers/pcmcia/cs.c	Mon Dec 22 17:16:34 2003
+++ b/drivers/pcmcia/cs.c	Mon Dec 22 17:16:34 2003
@@ -1916,7 +1916,7 @@
 {
     struct pcmcia_socket *s;
     config_t *c;
-    int ret = 0, irq = 0;
+    int ret = CS_IN_USE, irq = 0;
     
     if (CHECK_HANDLE(handle))
 	return CS_BAD_HANDLE;
@@ -1928,13 +1928,9 @@
 	return CS_CONFIGURATION_LOCKED;
     if (c->state & CONFIG_IRQ_REQ)
 	return CS_IN_USE;
-    
-    /* Short cut: if there are no ISA interrupts, then it is PCI */
-    if (!s->irq_mask) {
-	irq = s->pci_irq;
-	ret = (irq) ? 0 : CS_IN_USE;
+
 #ifdef CONFIG_PCMCIA_PROBE
-    } else if (s->irq.AssignedIRQ != 0) {
+    if (s->irq.AssignedIRQ != 0) {
 	/* If the interrupt is already assigned, it must match */
 	irq = s->irq.AssignedIRQ;
 	if (req->IRQInfo1 & IRQ_INFO2_VALID) {
@@ -1943,7 +1939,6 @@
 	} else
 	    ret = ((req->IRQInfo1&IRQ_MASK) == irq) ? 0 : CS_BAD_ARGS;
     } else {
-	ret = CS_IN_USE;
 	if (req->IRQInfo1 & IRQ_INFO2_VALID) {
 	    u_int try, mask = req->IRQInfo2 & s->irq_mask;
 	    for (try = 0; try < 2; try++) {
@@ -1958,12 +1953,13 @@
 	    irq = req->IRQInfo1 & IRQ_MASK;
 	    ret = try_irq(req->Attributes, irq, 1);
 	}
-#else
-    } else {
-	ret = CS_UNSUPPORTED_MODE;
+    }
 #endif
+    if (ret != 0) {
+	if (!s->pci_irq)
+	    return ret;
+	irq = s->pci_irq;
     }
-    if (ret != 0) return ret;
 
     if (req->Attributes & IRQ_HANDLE_PRESENT) {
 	if (request_irq(irq, req->Handler,

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 PCMCIA      - http://pcmcia.arm.linux.org.uk/
                 2.6 Serial core

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2003-12-22 17:37 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-04-22  0:19 [PATCH] PCMCIA updates Russell King
  -- strict thread matches above, loose matches on Subject: below --
2003-05-28 15:22 Russell King
2003-12-22 17:21 Russell King
2003-12-22 17:37 ` Davide Libenzi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox