Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 145c3ae4 authored by Finn Thain's avatar Finn Thain Committed by Martin K. Petersen
Browse files

scsi: g_NCR5380: Fix automatic IRQ on HP C2502 cards



When IRQ_AUTO is used, the interrupt for HP C2502 cards gets disabled.
Fix this by programming the card for a suitable free irq. The code for
the free irq search comes from ALSA.

Also allow IRQ 9 to work (it aliases to IRQ 2 on the card), as per
Ondrej Zary's patch.

Suggested-by: default avatarOndrej Zary <linux@rainbow-software.org>
Signed-off-by: default avatarFinn Thain <fthain@telegraphics.com.au>
Tested-by: default avatarOndrej Zary <linux@rainbow-software.org>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 906e4a3c
Loading
Loading
Loading
Loading
+57 −13
Original line number Original line Diff line number Diff line
@@ -131,14 +131,33 @@ static void magic_configure(int idx, u8 irq, u8 magic[])
	outb(magic[3], 0x379);
	outb(magic[3], 0x379);
	outb(magic[4], 0x379);
	outb(magic[4], 0x379);


	/* allowed IRQs for HP C2502 */
	if (irq == 9)
	if (irq != 2 && irq != 3 && irq != 4 && irq != 5 && irq != 7)
		irq = 2;
		irq = 0;

	if (idx >= 0 && idx <= 7)
	if (idx >= 0 && idx <= 7)
		cfg = 0x80 | idx | (irq << 4);
		cfg = 0x80 | idx | (irq << 4);
	outb(cfg, 0x379);
	outb(cfg, 0x379);
}
}


static irqreturn_t legacy_empty_irq_handler(int irq, void *dev_id)
{
	return IRQ_HANDLED;
}

static int legacy_find_free_irq(int *irq_table)
{
	while (*irq_table != -1) {
		if (!request_irq(*irq_table, legacy_empty_irq_handler,
		                 IRQF_PROBE_SHARED, "Test IRQ",
		                 (void *)irq_table)) {
			free_irq(*irq_table, (void *) irq_table);
			return *irq_table;
		}
		irq_table++;
	}
	return -1;
}

static unsigned int ncr_53c400a_ports[] = {
static unsigned int ncr_53c400a_ports[] = {
	0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0
	0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0
};
};
@@ -151,6 +170,9 @@ static u8 ncr_53c400a_magic[] = { /* 53C400A & DTC436 */
static u8 hp_c2502_magic[] = {	/* HP C2502 */
static u8 hp_c2502_magic[] = {	/* HP C2502 */
	0x0f, 0x22, 0xf0, 0x20, 0x80
	0x0f, 0x22, 0xf0, 0x20, 0x80
};
};
static int hp_c2502_irqs[] = {
	9, 5, 7, 3, 4, -1
};


static int generic_NCR5380_init_one(struct scsi_host_template *tpnt,
static int generic_NCR5380_init_one(struct scsi_host_template *tpnt,
			struct device *pdev, int base, int irq, int board)
			struct device *pdev, int base, int irq, int board)
@@ -319,19 +341,41 @@ static int generic_NCR5380_init_one(struct scsi_host_template *tpnt,


	NCR5380_maybe_reset_bus(instance);
	NCR5380_maybe_reset_bus(instance);


	if (irq != IRQ_AUTO)
		instance->irq = irq;
	else
		instance->irq = g_NCR5380_probe_irq(instance);

	/* Compatibility with documented NCR5380 kernel parameters */
	/* Compatibility with documented NCR5380 kernel parameters */
	if (instance->irq == 255)
	if (irq == 255 || irq == 0)
		instance->irq = NO_IRQ;
		irq = NO_IRQ;

	if (board == BOARD_HP_C2502) {
		int *irq_table = hp_c2502_irqs;
		int board_irq = -1;

		switch (irq) {
		case NO_IRQ:
			board_irq = 0;
			break;
		case IRQ_AUTO:
			board_irq = legacy_find_free_irq(irq_table);
			break;
		default:
			while (*irq_table != -1)
				if (*irq_table++ == irq)
					board_irq = irq;
		}

		if (board_irq <= 0) {
			board_irq = 0;
			irq = NO_IRQ;
		}

		magic_configure(port_idx, board_irq, magic);
	}

	if (irq == IRQ_AUTO)
		instance->irq = g_NCR5380_probe_irq(instance);
	else
		instance->irq = irq;


	if (instance->irq != NO_IRQ) {
	if (instance->irq != NO_IRQ) {
		/* set IRQ for HP C2502 */
		if (board == BOARD_HP_C2502)
			magic_configure(port_idx, instance->irq, magic);
		if (request_irq(instance->irq, generic_NCR5380_intr,
		if (request_irq(instance->irq, generic_NCR5380_intr,
				0, "NCR5380", instance)) {
				0, "NCR5380", instance)) {
			printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
			printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);