xref: /openbmc/linux/drivers/pnp/quirks.c (revision 1da177e4)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  *  This file contains quirk handling code for PnP devices
31da177e4SLinus Torvalds  *  Some devices do not report all their resources, and need to have extra
41da177e4SLinus Torvalds  *  resources added. This is most easily accomplished at initialisation time
51da177e4SLinus Torvalds  *  when building up the resource structure for the first time.
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  *  Copyright (c) 2000 Peter Denison <peterd@pnd-pc.demon.co.uk>
81da177e4SLinus Torvalds  *
91da177e4SLinus Torvalds  *  Heavily based on PCI quirks handling which is
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  *  Copyright (c) 1999 Martin Mares <mj@ucw.cz>
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds #include <linux/config.h>
151da177e4SLinus Torvalds #include <linux/types.h>
161da177e4SLinus Torvalds #include <linux/kernel.h>
171da177e4SLinus Torvalds #include <linux/string.h>
181da177e4SLinus Torvalds #include <linux/slab.h>
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds #ifdef CONFIG_PNP_DEBUG
211da177e4SLinus Torvalds 	#define DEBUG
221da177e4SLinus Torvalds #else
231da177e4SLinus Torvalds 	#undef DEBUG
241da177e4SLinus Torvalds #endif
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #include <linux/pnp.h>
271da177e4SLinus Torvalds #include "base.h"
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds static void quirk_awe32_resources(struct pnp_dev *dev)
311da177e4SLinus Torvalds {
321da177e4SLinus Torvalds 	struct pnp_port *port, *port2, *port3;
331da177e4SLinus Torvalds 	struct pnp_option *res = dev->dependent;
341da177e4SLinus Torvalds 
351da177e4SLinus Torvalds 	/*
361da177e4SLinus Torvalds 	 * Unfortunately the isapnp_add_port_resource is too tightly bound
371da177e4SLinus Torvalds 	 * into the PnP discovery sequence, and cannot be used. Link in the
381da177e4SLinus Torvalds 	 * two extra ports (at offset 0x400 and 0x800 from the one given) by
391da177e4SLinus Torvalds 	 * hand.
401da177e4SLinus Torvalds 	 */
411da177e4SLinus Torvalds 	for ( ; res ; res = res->next ) {
421da177e4SLinus Torvalds 		port2 = pnp_alloc(sizeof(struct pnp_port));
431da177e4SLinus Torvalds 		if (!port2)
441da177e4SLinus Torvalds 			return;
451da177e4SLinus Torvalds 		port3 = pnp_alloc(sizeof(struct pnp_port));
461da177e4SLinus Torvalds 		if (!port3) {
471da177e4SLinus Torvalds 			kfree(port2);
481da177e4SLinus Torvalds 			return;
491da177e4SLinus Torvalds 		}
501da177e4SLinus Torvalds 		port = res->port;
511da177e4SLinus Torvalds 		memcpy(port2, port, sizeof(struct pnp_port));
521da177e4SLinus Torvalds 		memcpy(port3, port, sizeof(struct pnp_port));
531da177e4SLinus Torvalds 		port->next = port2;
541da177e4SLinus Torvalds 		port2->next = port3;
551da177e4SLinus Torvalds 		port2->min += 0x400;
561da177e4SLinus Torvalds 		port2->max += 0x400;
571da177e4SLinus Torvalds 		port3->min += 0x800;
581da177e4SLinus Torvalds 		port3->max += 0x800;
591da177e4SLinus Torvalds 	}
601da177e4SLinus Torvalds 	printk(KERN_INFO "pnp: AWE32 quirk - adding two ports\n");
611da177e4SLinus Torvalds }
621da177e4SLinus Torvalds 
631da177e4SLinus Torvalds static void quirk_cmi8330_resources(struct pnp_dev *dev)
641da177e4SLinus Torvalds {
651da177e4SLinus Torvalds 	struct pnp_option *res = dev->dependent;
661da177e4SLinus Torvalds 	unsigned long tmp;
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds 	for ( ; res ; res = res->next ) {
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds 		struct pnp_irq *irq;
711da177e4SLinus Torvalds 		struct pnp_dma *dma;
721da177e4SLinus Torvalds 
731da177e4SLinus Torvalds 		for( irq = res->irq; irq; irq = irq->next ) {	// Valid irqs are 5, 7, 10
741da177e4SLinus Torvalds 			tmp = 0x04A0;
751da177e4SLinus Torvalds 			bitmap_copy(irq->map, &tmp, 16);	// 0000 0100 1010 0000
761da177e4SLinus Torvalds 		}
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds 		for( dma = res->dma; dma; dma = dma->next ) // Valid 8bit dma channels are 1,3
791da177e4SLinus Torvalds 			if( ( dma->flags & IORESOURCE_DMA_TYPE_MASK ) == IORESOURCE_DMA_8BIT )
801da177e4SLinus Torvalds 				dma->map = 0x000A;
811da177e4SLinus Torvalds 	}
821da177e4SLinus Torvalds 	printk(KERN_INFO "pnp: CMI8330 quirk - fixing interrupts and dma\n");
831da177e4SLinus Torvalds }
841da177e4SLinus Torvalds 
851da177e4SLinus Torvalds static void quirk_sb16audio_resources(struct pnp_dev *dev)
861da177e4SLinus Torvalds {
871da177e4SLinus Torvalds 	struct pnp_port *port;
881da177e4SLinus Torvalds 	struct pnp_option *res = dev->dependent;
891da177e4SLinus Torvalds 	int    changed = 0;
901da177e4SLinus Torvalds 
911da177e4SLinus Torvalds 	/*
921da177e4SLinus Torvalds 	 * The default range on the mpu port for these devices is 0x388-0x388.
931da177e4SLinus Torvalds 	 * Here we increase that range so that two such cards can be
941da177e4SLinus Torvalds 	 * auto-configured.
951da177e4SLinus Torvalds 	 */
961da177e4SLinus Torvalds 
971da177e4SLinus Torvalds 	for( ; res ; res = res->next ) {
981da177e4SLinus Torvalds 		port = res->port;
991da177e4SLinus Torvalds 		if(!port)
1001da177e4SLinus Torvalds 			continue;
1011da177e4SLinus Torvalds 		port = port->next;
1021da177e4SLinus Torvalds 		if(!port)
1031da177e4SLinus Torvalds 			continue;
1041da177e4SLinus Torvalds 		port = port->next;
1051da177e4SLinus Torvalds 		if(!port)
1061da177e4SLinus Torvalds 			continue;
1071da177e4SLinus Torvalds 		if(port->min != port->max)
1081da177e4SLinus Torvalds 			continue;
1091da177e4SLinus Torvalds 		port->max += 0x70;
1101da177e4SLinus Torvalds 		changed = 1;
1111da177e4SLinus Torvalds 	}
1121da177e4SLinus Torvalds 	if(changed)
1131da177e4SLinus Torvalds 		printk(KERN_INFO "pnp: SB audio device quirk - increasing port range\n");
1141da177e4SLinus Torvalds 	return;
1151da177e4SLinus Torvalds }
1161da177e4SLinus Torvalds 
1171da177e4SLinus Torvalds /*
1181da177e4SLinus Torvalds  *  PnP Quirks
1191da177e4SLinus Torvalds  *  Cards or devices that need some tweaking due to incomplete resource info
1201da177e4SLinus Torvalds  */
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds static struct pnp_fixup pnp_fixups[] = {
1231da177e4SLinus Torvalds 	/* Soundblaster awe io port quirk */
1241da177e4SLinus Torvalds 	{ "CTL0021", quirk_awe32_resources },
1251da177e4SLinus Torvalds 	{ "CTL0022", quirk_awe32_resources },
1261da177e4SLinus Torvalds 	{ "CTL0023", quirk_awe32_resources },
1271da177e4SLinus Torvalds 	/* CMI 8330 interrupt and dma fix */
1281da177e4SLinus Torvalds 	{ "@X@0001", quirk_cmi8330_resources },
1291da177e4SLinus Torvalds 	/* Soundblaster audio device io port range quirk */
1301da177e4SLinus Torvalds 	{ "CTL0001", quirk_sb16audio_resources },
1311da177e4SLinus Torvalds 	{ "CTL0031", quirk_sb16audio_resources },
1321da177e4SLinus Torvalds 	{ "CTL0041", quirk_sb16audio_resources },
1331da177e4SLinus Torvalds 	{ "CTL0042", quirk_sb16audio_resources },
1341da177e4SLinus Torvalds 	{ "CTL0043", quirk_sb16audio_resources },
1351da177e4SLinus Torvalds 	{ "CTL0044", quirk_sb16audio_resources },
1361da177e4SLinus Torvalds 	{ "CTL0045", quirk_sb16audio_resources },
1371da177e4SLinus Torvalds 	{ "" }
1381da177e4SLinus Torvalds };
1391da177e4SLinus Torvalds 
1401da177e4SLinus Torvalds void pnp_fixup_device(struct pnp_dev *dev)
1411da177e4SLinus Torvalds {
1421da177e4SLinus Torvalds 	int i = 0;
1431da177e4SLinus Torvalds 
1441da177e4SLinus Torvalds 	while (*pnp_fixups[i].id) {
1451da177e4SLinus Torvalds 		if (compare_pnp_id(dev->id,pnp_fixups[i].id)) {
1461da177e4SLinus Torvalds 			pnp_dbg("Calling quirk for %s",
1471da177e4SLinus Torvalds 		                  dev->dev.bus_id);
1481da177e4SLinus Torvalds 			pnp_fixups[i].quirk_function(dev);
1491da177e4SLinus Torvalds 		}
1501da177e4SLinus Torvalds 		i++;
1511da177e4SLinus Torvalds 	}
1521da177e4SLinus Torvalds }
153