PCMCIA fixes and cleanups for v7.1
A number of minor PCMCIA bugfixes and cleanups, and a patch removing obsolete host controller drivers. -----BEGIN PGP SIGNATURE----- iQJPBAABCgA5FiEEmgXaWKgmjrvkPhLCmpdgiUyNow0FAmnqWwIbHGxpbnV4QGRv bWluaWticm9kb3dza2kubmV0AAoJEJqXYIlMjaMNifYP/R89OwUCazfebvE+mzTT Nlj11sxOaMF9ZMDkWZlP49TkoBZjQ9MEb6hGgw99SLLf5bYoHQFHZ0RMIwM/7UXv y66ZLqfuGgdenUre8QROsYP1uegO4gh41aRm9a7cswoAkNlnIgKhH1k2/jhRwlXT rrl2CObgkdAtpnZDb2GFyjL2Y5VEKoKJf3nrNlDs1R4NBDVmfisojlfLeYFGGBsq CESwNcj9eEj+NuUhdWOmHXjXOvsDxk2PpTUEettswcdInOj8MApScbmyj/UqCX6A RTI/myAeLeGTMgTrZCfIqhCiaZbBdVcoKYakRfAZVyM1KuHQo/PmAlMPhv5C4lRT V8Fqz3RTtcYxblTMoxWh8pMaCKoH905YIINs54rkFwAqgq6TXgu26QdZtH+YR2V/ /0JI613MfSDhC2WwEF3j+sW0WlCnGSFZ5yzUZQmoQYf4US3ZOhp1JgaK+18QtqUa 00e0OQkLNN03Nj7UcoMfLHANOBVjLV8C8U+zkHT1t5AI4bRlP8FSTNrFP0f2VKWZ rm0S7CWovRS9mewOOXVHv2Wo0bxSaBsBxrD2G8n1PRE96xpXZvjuUKQtSyX6Totk lacS2HziABD7IiuKH0djC1MPPZkbZcct3TO8PggVYkrDa9nyQAsG4Z2+S85f8+Qg ALVHDj4B4bbJEVyn4duU9y+F =y3cK -----END PGP SIGNATURE----- Merge tag 'pcmcia-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brodo/linux Pull PCMCIA updates from Dominik Brodowski: "A number of minor PCMCIA bugfixes and cleanups, and a patch removing obsolete host controller drivers" * tag 'pcmcia-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brodo/linux: pcmcia: remove obsolete host controller drivers pcmcia: Convert to use less arguments in pci_bus_for_each_resource() PCMCIA: Fix garbled log messages for KERN_CONTmaster
commit
45dcf5e288
|
|
@ -15,7 +15,6 @@ CONFIG_PCI=y
|
|||
CONFIG_PCCARD=m
|
||||
CONFIG_YENTA=m
|
||||
CONFIG_PD6729=m
|
||||
CONFIG_I82092=m
|
||||
CONFIG_MODULES=y
|
||||
CONFIG_MODULE_UNLOAD=y
|
||||
CONFIG_MODVERSIONS=y
|
||||
|
|
|
|||
|
|
@ -72,8 +72,6 @@ CONFIG_PCI_MSI=y
|
|||
CONFIG_PCCARD=y
|
||||
CONFIG_YENTA=y
|
||||
CONFIG_PD6729=m
|
||||
CONFIG_I82092=m
|
||||
CONFIG_I82365=m
|
||||
CONFIG_ADVANCED_OPTIONS=y
|
||||
CONFIG_NET=y
|
||||
CONFIG_PACKET=y
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ void arch_remove_reservations(struct resource *avail)
|
|||
/*
|
||||
* Trim out BIOS area (high 2MB) and E820 regions. We do not remove
|
||||
* the low 1MB unconditionally, as this area is needed for some ISA
|
||||
* cards requiring a memory range, e.g. the i82365 PCMCIA controller.
|
||||
* cards requiring a memory range.
|
||||
*/
|
||||
if (avail->flags & IORESOURCE_MEM) {
|
||||
resource_clip(avail, BIOS_ROM_BASE, BIOS_ROM_END);
|
||||
|
|
|
|||
|
|
@ -1296,9 +1296,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt
|
|||
|
||||
/*
|
||||
* CardBus controllers have a legacy base address that enables them to
|
||||
* respond as i82365 pcmcia controllers. We don't want them to do this
|
||||
* even if the Linux CardBus driver is not loaded, because the Linux i82365
|
||||
* driver does not (and should not) handle CardBus.
|
||||
* respond as i82365 PCMCIA controllers. We don't want them to do this.
|
||||
*/
|
||||
static void quirk_cardbus_legacy(struct pci_dev *dev)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -119,36 +119,6 @@ config PD6729
|
|||
This provides support for the Cirrus PD6729 PCI-to-PCMCIA bridge
|
||||
device, found in some older laptops and PCMCIA card readers.
|
||||
|
||||
config I82092
|
||||
tristate "i82092 compatible bridge support"
|
||||
depends on PCMCIA && PCI && HAS_IOPORT
|
||||
select PCCARD_NONSTATIC
|
||||
help
|
||||
This provides support for the Intel I82092AA PCI-to-PCMCIA bridge device,
|
||||
found in some older laptops and more commonly in evaluation boards for the
|
||||
chip.
|
||||
|
||||
config I82365
|
||||
tristate "i82365 compatible bridge support"
|
||||
depends on PCMCIA && ISA
|
||||
select PCCARD_NONSTATIC
|
||||
help
|
||||
Say Y here to include support for ISA-bus PCMCIA host bridges that
|
||||
are register compatible with the Intel i82365. These are found on
|
||||
older laptops and ISA-bus card readers for desktop systems. A
|
||||
"bridge" is the hardware inside your computer that PCMCIA cards are
|
||||
plugged into. If unsure, say N.
|
||||
|
||||
config TCIC
|
||||
tristate "Databook TCIC host bridge support"
|
||||
depends on PCMCIA && ISA
|
||||
select PCCARD_NONSTATIC
|
||||
help
|
||||
Say Y here to include support for the Databook TCIC family of PCMCIA
|
||||
host bridges. These are only found on a handful of old systems.
|
||||
"Bridge" is the name used for the hardware inside your computer that
|
||||
PCMCIA cards are plugged into. If unsure, say N.
|
||||
|
||||
config PCMCIA_ALCHEMY_DEVBOARD
|
||||
tristate "Alchemy Db/Pb1xxx PCMCIA socket services"
|
||||
depends on MIPS_DB1XXX && PCMCIA
|
||||
|
|
|
|||
|
|
@ -20,9 +20,6 @@ obj-$(CONFIG_PCCARD) += pcmcia_rsrc.o
|
|||
obj-$(CONFIG_YENTA) += yenta_socket.o
|
||||
|
||||
obj-$(CONFIG_PD6729) += pd6729.o
|
||||
obj-$(CONFIG_I82365) += i82365.o
|
||||
obj-$(CONFIG_I82092) += i82092.o
|
||||
obj-$(CONFIG_TCIC) += tcic.o
|
||||
obj-$(CONFIG_PCMCIA_SOC_COMMON) += soc_common.o
|
||||
obj-$(CONFIG_PCMCIA_SA11XX_BASE) += sa11xx_base.o
|
||||
obj-$(CONFIG_PCMCIA_SA1100) += sa1100_cs.o
|
||||
|
|
|
|||
|
|
@ -1,679 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Driver for Intel I82092AA PCI-PCMCIA bridge.
|
||||
*
|
||||
* (C) 2001 Red Hat, Inc.
|
||||
*
|
||||
* Author: Arjan Van De Ven <arjanv@redhat.com>
|
||||
* Loosly based on i82365.c from the pcmcia-cs package
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/device.h>
|
||||
|
||||
#include <pcmcia/ss.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "i82092aa.h"
|
||||
#include "i82365.h"
|
||||
|
||||
MODULE_DESCRIPTION("Driver for Intel I82092AA PCI-PCMCIA bridge");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/* PCI core routines */
|
||||
static const struct pci_device_id i82092aa_pci_ids[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82092AA_0) },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids);
|
||||
|
||||
static struct pci_driver i82092aa_pci_driver = {
|
||||
.name = "i82092aa",
|
||||
.id_table = i82092aa_pci_ids,
|
||||
.probe = i82092aa_pci_probe,
|
||||
.remove = i82092aa_pci_remove,
|
||||
};
|
||||
|
||||
|
||||
/* the pccard structure and its functions */
|
||||
static struct pccard_operations i82092aa_operations = {
|
||||
.init = i82092aa_init,
|
||||
.get_status = i82092aa_get_status,
|
||||
.set_socket = i82092aa_set_socket,
|
||||
.set_io_map = i82092aa_set_io_map,
|
||||
.set_mem_map = i82092aa_set_mem_map,
|
||||
};
|
||||
|
||||
/* The card can do up to 4 sockets, allocate a structure for each of them */
|
||||
|
||||
struct socket_info {
|
||||
int number;
|
||||
int card_state;
|
||||
/* 0 = no socket,
|
||||
* 1 = empty socket,
|
||||
* 2 = card but not initialized,
|
||||
* 3 = operational card
|
||||
*/
|
||||
unsigned int io_base; /* base io address of the socket */
|
||||
|
||||
struct pcmcia_socket socket;
|
||||
struct pci_dev *dev; /* The PCI device for the socket */
|
||||
};
|
||||
|
||||
#define MAX_SOCKETS 4
|
||||
static struct socket_info sockets[MAX_SOCKETS];
|
||||
static int socket_count; /* shortcut */
|
||||
|
||||
|
||||
static int i82092aa_pci_probe(struct pci_dev *dev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
unsigned char configbyte;
|
||||
int i, ret;
|
||||
|
||||
ret = pci_enable_device(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* PCI Configuration Control */
|
||||
pci_read_config_byte(dev, 0x40, &configbyte);
|
||||
|
||||
switch (configbyte&6) {
|
||||
case 0:
|
||||
socket_count = 2;
|
||||
break;
|
||||
case 2:
|
||||
socket_count = 1;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
socket_count = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(&dev->dev,
|
||||
"Oops, you did something we didn't think of.\n");
|
||||
ret = -EIO;
|
||||
goto err_out_disable;
|
||||
}
|
||||
dev_info(&dev->dev, "configured as a %d socket device.\n",
|
||||
socket_count);
|
||||
|
||||
if (!request_region(pci_resource_start(dev, 0), 2, "i82092aa")) {
|
||||
ret = -EBUSY;
|
||||
goto err_out_disable;
|
||||
}
|
||||
|
||||
for (i = 0; i < socket_count; i++) {
|
||||
sockets[i].card_state = 1; /* 1 = present but empty */
|
||||
sockets[i].io_base = pci_resource_start(dev, 0);
|
||||
sockets[i].dev = dev;
|
||||
sockets[i].socket.features |= SS_CAP_PCCARD;
|
||||
sockets[i].socket.map_size = 0x1000;
|
||||
sockets[i].socket.irq_mask = 0;
|
||||
sockets[i].socket.pci_irq = dev->irq;
|
||||
sockets[i].socket.cb_dev = dev;
|
||||
sockets[i].socket.owner = THIS_MODULE;
|
||||
|
||||
sockets[i].number = i;
|
||||
|
||||
if (card_present(i)) {
|
||||
sockets[i].card_state = 3;
|
||||
dev_dbg(&dev->dev, "slot %i is occupied\n", i);
|
||||
} else {
|
||||
dev_dbg(&dev->dev, "slot %i is vacant\n", i);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now, specifiy that all interrupts are to be done as PCI interrupts
|
||||
* bitmask, one bit per event, 1 = PCI interrupt, 0 = ISA interrupt
|
||||
*/
|
||||
configbyte = 0xFF;
|
||||
|
||||
/* PCI Interrupt Routing Register */
|
||||
pci_write_config_byte(dev, 0x50, configbyte);
|
||||
|
||||
/* Register the interrupt handler */
|
||||
dev_dbg(&dev->dev, "Requesting interrupt %i\n", dev->irq);
|
||||
ret = request_irq(dev->irq, i82092aa_interrupt, IRQF_SHARED,
|
||||
"i82092aa", i82092aa_interrupt);
|
||||
if (ret) {
|
||||
dev_err(&dev->dev, "Failed to register IRQ %d, aborting\n",
|
||||
dev->irq);
|
||||
goto err_out_free_res;
|
||||
}
|
||||
|
||||
for (i = 0; i < socket_count; i++) {
|
||||
sockets[i].socket.dev.parent = &dev->dev;
|
||||
sockets[i].socket.ops = &i82092aa_operations;
|
||||
sockets[i].socket.resource_ops = &pccard_nonstatic_ops;
|
||||
ret = pcmcia_register_socket(&sockets[i].socket);
|
||||
if (ret)
|
||||
goto err_out_free_sockets;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_out_free_sockets:
|
||||
if (i) {
|
||||
for (i--; i >= 0; i--)
|
||||
pcmcia_unregister_socket(&sockets[i].socket);
|
||||
}
|
||||
free_irq(dev->irq, i82092aa_interrupt);
|
||||
err_out_free_res:
|
||||
release_region(pci_resource_start(dev, 0), 2);
|
||||
err_out_disable:
|
||||
pci_disable_device(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void i82092aa_pci_remove(struct pci_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
free_irq(dev->irq, i82092aa_interrupt);
|
||||
|
||||
for (i = 0; i < socket_count; i++)
|
||||
pcmcia_unregister_socket(&sockets[i].socket);
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(port_lock);
|
||||
|
||||
/* basic value read/write functions */
|
||||
|
||||
static unsigned char indirect_read(int socket, unsigned short reg)
|
||||
{
|
||||
unsigned short int port;
|
||||
unsigned char val;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port_lock, flags);
|
||||
reg += socket * 0x40;
|
||||
port = sockets[socket].io_base;
|
||||
outb(reg, port);
|
||||
val = inb(port+1);
|
||||
spin_unlock_irqrestore(&port_lock, flags);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void indirect_write(int socket, unsigned short reg, unsigned char value)
|
||||
{
|
||||
unsigned short int port;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port_lock, flags);
|
||||
reg = reg + socket * 0x40;
|
||||
port = sockets[socket].io_base;
|
||||
outb(reg, port);
|
||||
outb(value, port+1);
|
||||
spin_unlock_irqrestore(&port_lock, flags);
|
||||
}
|
||||
|
||||
static void indirect_setbit(int socket, unsigned short reg, unsigned char mask)
|
||||
{
|
||||
unsigned short int port;
|
||||
unsigned char val;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port_lock, flags);
|
||||
reg = reg + socket * 0x40;
|
||||
port = sockets[socket].io_base;
|
||||
outb(reg, port);
|
||||
val = inb(port+1);
|
||||
val |= mask;
|
||||
outb(reg, port);
|
||||
outb(val, port+1);
|
||||
spin_unlock_irqrestore(&port_lock, flags);
|
||||
}
|
||||
|
||||
|
||||
static void indirect_resetbit(int socket,
|
||||
unsigned short reg, unsigned char mask)
|
||||
{
|
||||
unsigned short int port;
|
||||
unsigned char val;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port_lock, flags);
|
||||
reg = reg + socket * 0x40;
|
||||
port = sockets[socket].io_base;
|
||||
outb(reg, port);
|
||||
val = inb(port+1);
|
||||
val &= ~mask;
|
||||
outb(reg, port);
|
||||
outb(val, port+1);
|
||||
spin_unlock_irqrestore(&port_lock, flags);
|
||||
}
|
||||
|
||||
static void indirect_write16(int socket,
|
||||
unsigned short reg, unsigned short value)
|
||||
{
|
||||
unsigned short int port;
|
||||
unsigned char val;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&port_lock, flags);
|
||||
reg = reg + socket * 0x40;
|
||||
port = sockets[socket].io_base;
|
||||
|
||||
outb(reg, port);
|
||||
val = value & 255;
|
||||
outb(val, port+1);
|
||||
|
||||
reg++;
|
||||
|
||||
outb(reg, port);
|
||||
val = value>>8;
|
||||
outb(val, port+1);
|
||||
spin_unlock_irqrestore(&port_lock, flags);
|
||||
}
|
||||
|
||||
/* simple helper functions */
|
||||
/* External clock time, in nanoseconds. 120 ns = 8.33 MHz */
|
||||
static int cycle_time = 120;
|
||||
|
||||
static int to_cycles(int ns)
|
||||
{
|
||||
if (cycle_time != 0)
|
||||
return ns/cycle_time;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Interrupt handler functionality */
|
||||
|
||||
static irqreturn_t i82092aa_interrupt(int irq, void *dev)
|
||||
{
|
||||
int i;
|
||||
int loopcount = 0;
|
||||
int handled = 0;
|
||||
|
||||
unsigned int events, active = 0;
|
||||
|
||||
while (1) {
|
||||
loopcount++;
|
||||
if (loopcount > 20) {
|
||||
pr_err("i82092aa: infinite eventloop in interrupt\n");
|
||||
break;
|
||||
}
|
||||
|
||||
active = 0;
|
||||
|
||||
for (i = 0; i < socket_count; i++) {
|
||||
int csc;
|
||||
|
||||
/* Inactive socket, should not happen */
|
||||
if (sockets[i].card_state == 0)
|
||||
continue;
|
||||
|
||||
/* card status change register */
|
||||
csc = indirect_read(i, I365_CSC);
|
||||
|
||||
if (csc == 0) /* no events on this socket */
|
||||
continue;
|
||||
handled = 1;
|
||||
events = 0;
|
||||
|
||||
if (csc & I365_CSC_DETECT) {
|
||||
events |= SS_DETECT;
|
||||
dev_info(&sockets[i].dev->dev,
|
||||
"Card detected in socket %i!\n", i);
|
||||
}
|
||||
|
||||
if (indirect_read(i, I365_INTCTL) & I365_PC_IOCARD) {
|
||||
/* For IO/CARDS, bit 0 means "read the card" */
|
||||
if (csc & I365_CSC_STSCHG)
|
||||
events |= SS_STSCHG;
|
||||
} else {
|
||||
/* Check for battery/ready events */
|
||||
if (csc & I365_CSC_BVD1)
|
||||
events |= SS_BATDEAD;
|
||||
if (csc & I365_CSC_BVD2)
|
||||
events |= SS_BATWARN;
|
||||
if (csc & I365_CSC_READY)
|
||||
events |= SS_READY;
|
||||
}
|
||||
|
||||
if (events)
|
||||
pcmcia_parse_events(&sockets[i].socket, events);
|
||||
active |= events;
|
||||
}
|
||||
|
||||
if (active == 0) /* no more events to handle */
|
||||
break;
|
||||
}
|
||||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* socket functions */
|
||||
|
||||
static int card_present(int socketno)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if ((socketno < 0) || (socketno >= MAX_SOCKETS))
|
||||
return 0;
|
||||
if (sockets[socketno].io_base == 0)
|
||||
return 0;
|
||||
|
||||
|
||||
val = indirect_read(socketno, 1); /* Interface status register */
|
||||
if ((val&12) == 12)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_bridge_state(int sock)
|
||||
{
|
||||
indirect_write(sock, I365_GBLCTL, 0x00);
|
||||
indirect_write(sock, I365_GENCTL, 0x00);
|
||||
|
||||
indirect_setbit(sock, I365_INTCTL, 0x08);
|
||||
}
|
||||
|
||||
|
||||
static int i82092aa_init(struct pcmcia_socket *sock)
|
||||
{
|
||||
int i;
|
||||
struct resource res = { .start = 0, .end = 0x0fff };
|
||||
pccard_io_map io = { 0, 0, 0, 0, 1 };
|
||||
pccard_mem_map mem = { .res = &res, };
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
io.map = i;
|
||||
i82092aa_set_io_map(sock, &io);
|
||||
}
|
||||
for (i = 0; i < 5; i++) {
|
||||
mem.map = i;
|
||||
i82092aa_set_mem_map(sock, &mem);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i82092aa_get_status(struct pcmcia_socket *socket, u_int *value)
|
||||
{
|
||||
unsigned int sock = container_of(socket,
|
||||
struct socket_info, socket)->number;
|
||||
unsigned int status;
|
||||
|
||||
/* Interface Status Register */
|
||||
status = indirect_read(sock, I365_STATUS);
|
||||
|
||||
*value = 0;
|
||||
|
||||
if ((status & I365_CS_DETECT) == I365_CS_DETECT)
|
||||
*value |= SS_DETECT;
|
||||
|
||||
/* IO cards have a different meaning of bits 0,1 */
|
||||
/* Also notice the inverse-logic on the bits */
|
||||
if (indirect_read(sock, I365_INTCTL) & I365_PC_IOCARD) {
|
||||
/* IO card */
|
||||
if (!(status & I365_CS_STSCHG))
|
||||
*value |= SS_STSCHG;
|
||||
} else { /* non I/O card */
|
||||
if (!(status & I365_CS_BVD1))
|
||||
*value |= SS_BATDEAD;
|
||||
if (!(status & I365_CS_BVD2))
|
||||
*value |= SS_BATWARN;
|
||||
}
|
||||
|
||||
if (status & I365_CS_WRPROT)
|
||||
(*value) |= SS_WRPROT; /* card is write protected */
|
||||
|
||||
if (status & I365_CS_READY)
|
||||
(*value) |= SS_READY; /* card is not busy */
|
||||
|
||||
if (status & I365_CS_POWERON)
|
||||
(*value) |= SS_POWERON; /* power is applied to the card */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int i82092aa_set_socket(struct pcmcia_socket *socket,
|
||||
socket_state_t *state)
|
||||
{
|
||||
struct socket_info *sock_info = container_of(socket, struct socket_info,
|
||||
socket);
|
||||
unsigned int sock = sock_info->number;
|
||||
unsigned char reg;
|
||||
|
||||
/* First, set the global controller options */
|
||||
|
||||
set_bridge_state(sock);
|
||||
|
||||
/* Values for the IGENC register */
|
||||
|
||||
reg = 0;
|
||||
|
||||
/* The reset bit has "inverse" logic */
|
||||
if (!(state->flags & SS_RESET))
|
||||
reg = reg | I365_PC_RESET;
|
||||
if (state->flags & SS_IOCARD)
|
||||
reg = reg | I365_PC_IOCARD;
|
||||
|
||||
/* IGENC, Interrupt and General Control Register */
|
||||
indirect_write(sock, I365_INTCTL, reg);
|
||||
|
||||
/* Power registers */
|
||||
|
||||
reg = I365_PWR_NORESET; /* default: disable resetdrv on resume */
|
||||
|
||||
if (state->flags & SS_PWR_AUTO) {
|
||||
dev_info(&sock_info->dev->dev, "Auto power\n");
|
||||
reg |= I365_PWR_AUTO; /* automatic power mngmnt */
|
||||
}
|
||||
if (state->flags & SS_OUTPUT_ENA) {
|
||||
dev_info(&sock_info->dev->dev, "Power Enabled\n");
|
||||
reg |= I365_PWR_OUT; /* enable power */
|
||||
}
|
||||
|
||||
switch (state->Vcc) {
|
||||
case 0:
|
||||
break;
|
||||
case 50:
|
||||
dev_info(&sock_info->dev->dev,
|
||||
"setting voltage to Vcc to 5V on socket %i\n",
|
||||
sock);
|
||||
reg |= I365_VCC_5V;
|
||||
break;
|
||||
default:
|
||||
dev_err(&sock_info->dev->dev,
|
||||
"%s called with invalid VCC power value: %i",
|
||||
__func__, state->Vcc);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (state->Vpp) {
|
||||
case 0:
|
||||
dev_info(&sock_info->dev->dev,
|
||||
"not setting Vpp on socket %i\n", sock);
|
||||
break;
|
||||
case 50:
|
||||
dev_info(&sock_info->dev->dev,
|
||||
"setting Vpp to 5.0 for socket %i\n", sock);
|
||||
reg |= I365_VPP1_5V | I365_VPP2_5V;
|
||||
break;
|
||||
case 120:
|
||||
dev_info(&sock_info->dev->dev, "setting Vpp to 12.0\n");
|
||||
reg |= I365_VPP1_12V | I365_VPP2_12V;
|
||||
break;
|
||||
default:
|
||||
dev_err(&sock_info->dev->dev,
|
||||
"%s called with invalid VPP power value: %i",
|
||||
__func__, state->Vcc);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (reg != indirect_read(sock, I365_POWER)) /* only write if changed */
|
||||
indirect_write(sock, I365_POWER, reg);
|
||||
|
||||
/* Enable specific interrupt events */
|
||||
|
||||
reg = 0x00;
|
||||
if (state->csc_mask & SS_DETECT)
|
||||
reg |= I365_CSC_DETECT;
|
||||
if (state->flags & SS_IOCARD) {
|
||||
if (state->csc_mask & SS_STSCHG)
|
||||
reg |= I365_CSC_STSCHG;
|
||||
} else {
|
||||
if (state->csc_mask & SS_BATDEAD)
|
||||
reg |= I365_CSC_BVD1;
|
||||
if (state->csc_mask & SS_BATWARN)
|
||||
reg |= I365_CSC_BVD2;
|
||||
if (state->csc_mask & SS_READY)
|
||||
reg |= I365_CSC_READY;
|
||||
|
||||
}
|
||||
|
||||
/* now write the value and clear the (probably bogus) pending stuff
|
||||
* by doing a dummy read
|
||||
*/
|
||||
|
||||
indirect_write(sock, I365_CSCINT, reg);
|
||||
(void)indirect_read(sock, I365_CSC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i82092aa_set_io_map(struct pcmcia_socket *socket,
|
||||
struct pccard_io_map *io)
|
||||
{
|
||||
struct socket_info *sock_info = container_of(socket, struct socket_info,
|
||||
socket);
|
||||
unsigned int sock = sock_info->number;
|
||||
unsigned char map, ioctl;
|
||||
|
||||
map = io->map;
|
||||
|
||||
/* Check error conditions */
|
||||
if (map > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if ((io->start > 0xffff) || (io->stop > 0xffff)
|
||||
|| (io->stop < io->start))
|
||||
return -EINVAL;
|
||||
|
||||
/* Turn off the window before changing anything */
|
||||
if (indirect_read(sock, I365_ADDRWIN) & I365_ENA_IO(map))
|
||||
indirect_resetbit(sock, I365_ADDRWIN, I365_ENA_IO(map));
|
||||
|
||||
/* write the new values */
|
||||
indirect_write16(sock, I365_IO(map)+I365_W_START, io->start);
|
||||
indirect_write16(sock, I365_IO(map)+I365_W_STOP, io->stop);
|
||||
|
||||
ioctl = indirect_read(sock, I365_IOCTL) & ~I365_IOCTL_MASK(map);
|
||||
|
||||
if (io->flags & (MAP_16BIT|MAP_AUTOSZ))
|
||||
ioctl |= I365_IOCTL_16BIT(map);
|
||||
|
||||
indirect_write(sock, I365_IOCTL, ioctl);
|
||||
|
||||
/* Turn the window back on if needed */
|
||||
if (io->flags & MAP_ACTIVE)
|
||||
indirect_setbit(sock, I365_ADDRWIN, I365_ENA_IO(map));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int i82092aa_set_mem_map(struct pcmcia_socket *socket,
|
||||
struct pccard_mem_map *mem)
|
||||
{
|
||||
struct socket_info *sock_info = container_of(socket, struct socket_info,
|
||||
socket);
|
||||
unsigned int sock = sock_info->number;
|
||||
struct pci_bus_region region;
|
||||
unsigned short base, i;
|
||||
unsigned char map;
|
||||
|
||||
pcibios_resource_to_bus(sock_info->dev->bus, ®ion, mem->res);
|
||||
|
||||
map = mem->map;
|
||||
if (map > 4)
|
||||
return -EINVAL;
|
||||
|
||||
if ((mem->card_start > 0x3ffffff) || (region.start > region.end) ||
|
||||
(mem->speed > 1000)) {
|
||||
dev_err(&sock_info->dev->dev,
|
||||
"invalid mem map for socket %i: %llx to %llx with a start of %x\n",
|
||||
sock,
|
||||
(unsigned long long)region.start,
|
||||
(unsigned long long)region.end,
|
||||
mem->card_start);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Turn off the window before changing anything */
|
||||
if (indirect_read(sock, I365_ADDRWIN) & I365_ENA_MEM(map))
|
||||
indirect_resetbit(sock, I365_ADDRWIN, I365_ENA_MEM(map));
|
||||
|
||||
/* write the start address */
|
||||
base = I365_MEM(map);
|
||||
i = (region.start >> 12) & 0x0fff;
|
||||
if (mem->flags & MAP_16BIT)
|
||||
i |= I365_MEM_16BIT;
|
||||
if (mem->flags & MAP_0WS)
|
||||
i |= I365_MEM_0WS;
|
||||
indirect_write16(sock, base+I365_W_START, i);
|
||||
|
||||
/* write the stop address */
|
||||
|
||||
i = (region.end >> 12) & 0x0fff;
|
||||
switch (to_cycles(mem->speed)) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
i |= I365_MEM_WS0;
|
||||
break;
|
||||
case 2:
|
||||
i |= I365_MEM_WS1;
|
||||
break;
|
||||
default:
|
||||
i |= I365_MEM_WS1 | I365_MEM_WS0;
|
||||
break;
|
||||
}
|
||||
|
||||
indirect_write16(sock, base+I365_W_STOP, i);
|
||||
|
||||
/* card start */
|
||||
|
||||
i = ((mem->card_start - region.start) >> 12) & 0x3fff;
|
||||
if (mem->flags & MAP_WRPROT)
|
||||
i |= I365_MEM_WRPROT;
|
||||
if (mem->flags & MAP_ATTRIB)
|
||||
i |= I365_MEM_REG;
|
||||
indirect_write16(sock, base+I365_W_OFF, i);
|
||||
|
||||
/* Enable the window if necessary */
|
||||
if (mem->flags & MAP_ACTIVE)
|
||||
indirect_setbit(sock, I365_ADDRWIN, I365_ENA_MEM(map));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init i82092aa_module_init(void)
|
||||
{
|
||||
return pci_register_driver(&i82092aa_pci_driver);
|
||||
}
|
||||
|
||||
static void __exit i82092aa_module_exit(void)
|
||||
{
|
||||
pci_unregister_driver(&i82092aa_pci_driver);
|
||||
if (sockets[0].io_base > 0)
|
||||
release_region(sockets[0].io_base, 2);
|
||||
}
|
||||
|
||||
module_init(i82092aa_module_init);
|
||||
module_exit(i82092aa_module_exit);
|
||||
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef _INCLUDE_GUARD_i82092aa_H_
|
||||
#define _INCLUDE_GUARD_i82092aa_H_
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
/* prototypes */
|
||||
|
||||
static int i82092aa_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
|
||||
static void i82092aa_pci_remove(struct pci_dev *dev);
|
||||
static int card_present(int socketno);
|
||||
static irqreturn_t i82092aa_interrupt(int irq, void *dev);
|
||||
|
||||
|
||||
|
||||
|
||||
static int i82092aa_get_status(struct pcmcia_socket *socket, u_int *value);
|
||||
static int i82092aa_set_socket(struct pcmcia_socket *socket, socket_state_t *state);
|
||||
static int i82092aa_set_io_map(struct pcmcia_socket *socket, struct pccard_io_map *io);
|
||||
static int i82092aa_set_mem_map(struct pcmcia_socket *socket, struct pccard_mem_map *mem);
|
||||
static int i82092aa_init(struct pcmcia_socket *socket);
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -187,7 +187,7 @@ static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
|
|||
int any;
|
||||
u_char *b, hole, most;
|
||||
|
||||
dev_info(&s->dev, "cs: IO port probe %#x-%#x:", base, base+num-1);
|
||||
pr_info("%s: cs: IO port probe %#x-%#x:", dev_name(&s->dev), base, base+num-1);
|
||||
|
||||
/* First, what does a floating port look like? */
|
||||
b = kzalloc(256, GFP_KERNEL);
|
||||
|
|
@ -409,8 +409,8 @@ static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num,
|
|||
struct socket_data *s_data = s->resource_data;
|
||||
u_long i, j, bad, fail, step;
|
||||
|
||||
dev_info(&s->dev, "cs: memory probe 0x%06lx-0x%06lx:",
|
||||
base, base+num-1);
|
||||
pr_info("%s: cs: memory probe 0x%06lx-0x%06lx:",
|
||||
dev_name(&s->dev), base, base+num-1);
|
||||
bad = fail = 0;
|
||||
step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
|
||||
/* don't allow too large steps */
|
||||
|
|
@ -936,7 +936,7 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long
|
|||
static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
|
||||
{
|
||||
struct resource *res;
|
||||
int i, done = 0;
|
||||
int done = 0;
|
||||
|
||||
if (!s->cb_dev || !s->cb_dev->bus)
|
||||
return -ENODEV;
|
||||
|
|
@ -963,10 +963,10 @@ static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
|
|||
if (s->cb_dev->bus->number == 0)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
|
||||
for (unsigned int i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
|
||||
res = s->cb_dev->bus->resource[i];
|
||||
#else
|
||||
pci_bus_for_each_resource(s->cb_dev->bus, res, i) {
|
||||
pci_bus_for_each_resource(s->cb_dev->bus, res) {
|
||||
#endif
|
||||
if (!res)
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -1,805 +0,0 @@
|
|||
/*======================================================================
|
||||
|
||||
Device driver for Databook TCIC-2 PCMCIA controller
|
||||
|
||||
tcic.c 1.111 2000/02/15 04:13:12
|
||||
|
||||
The contents of this file are subject to the Mozilla Public
|
||||
License Version 1.1 (the "License"); you may not use this file
|
||||
except in compliance with the License. You may obtain a copy of
|
||||
the License at http://www.mozilla.org/MPL/
|
||||
|
||||
Software distributed under the License is distributed on an "AS
|
||||
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||||
implied. See the License for the specific language governing
|
||||
rights and limitations under the License.
|
||||
|
||||
The initial developer of the original code is David A. Hinds
|
||||
<dahinds@users.sourceforge.net>. Portions created by David A. Hinds
|
||||
are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
|
||||
|
||||
Alternatively, the contents of this file may be used under the
|
||||
terms of the GNU General Public License version 2 (the "GPL"), in which
|
||||
case the provisions of the GPL are applicable instead of the
|
||||
above. If you wish to allow the use of your version of this file
|
||||
only under the terms of the GPL and not to allow others to use
|
||||
your version of this file under the MPL, indicate your decision
|
||||
by deleting the provisions above and replace them with the notice
|
||||
and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this
|
||||
file under either the MPL or the GPL.
|
||||
|
||||
======================================================================*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
#include <pcmcia/ss.h>
|
||||
#include "tcic.h"
|
||||
|
||||
MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
|
||||
MODULE_DESCRIPTION("Databook TCIC-2 PCMCIA socket driver");
|
||||
MODULE_LICENSE("Dual MPL/GPL");
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
/* Parameters that can be set with 'insmod' */
|
||||
|
||||
/* The base port address of the TCIC-2 chip */
|
||||
static unsigned long tcic_base = TCIC_BASE;
|
||||
|
||||
/* Specify a socket number to ignore */
|
||||
static int ignore = -1;
|
||||
|
||||
/* Probe for safe interrupts? */
|
||||
static int do_scan = 1;
|
||||
|
||||
/* Bit map of interrupts to choose from */
|
||||
static u_int irq_mask = 0xffff;
|
||||
static int irq_list[16];
|
||||
static unsigned int irq_list_count;
|
||||
|
||||
/* The card status change interrupt -- 0 means autoselect */
|
||||
static int cs_irq;
|
||||
|
||||
/* Poll status interval -- 0 means default to interrupt */
|
||||
static int poll_interval;
|
||||
|
||||
/* Delay for card status double-checking */
|
||||
static int poll_quick = HZ/20;
|
||||
|
||||
/* CCLK external clock time, in nanoseconds. 70 ns = 14.31818 MHz */
|
||||
static int cycle_time = 70;
|
||||
|
||||
module_param_hw(tcic_base, ulong, ioport, 0444);
|
||||
module_param(ignore, int, 0444);
|
||||
module_param(do_scan, int, 0444);
|
||||
module_param_hw(irq_mask, int, other, 0444);
|
||||
module_param_hw_array(irq_list, int, irq, &irq_list_count, 0444);
|
||||
module_param_hw(cs_irq, int, irq, 0444);
|
||||
module_param(poll_interval, int, 0444);
|
||||
module_param(poll_quick, int, 0444);
|
||||
module_param(cycle_time, int, 0444);
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
static irqreturn_t tcic_interrupt(int irq, void *dev);
|
||||
static void tcic_timer(struct timer_list *unused);
|
||||
static struct pccard_operations tcic_operations;
|
||||
|
||||
struct tcic_socket {
|
||||
u_short psock;
|
||||
u_char last_sstat;
|
||||
u_char id;
|
||||
struct pcmcia_socket socket;
|
||||
};
|
||||
|
||||
static struct timer_list poll_timer;
|
||||
static int tcic_timer_pending;
|
||||
|
||||
static int sockets;
|
||||
static struct tcic_socket socket_table[2];
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
/* Trick when selecting interrupts: the TCIC sktirq pin is supposed
|
||||
to map to irq 11, but is coded as 0 or 1 in the irq registers. */
|
||||
#define TCIC_IRQ(x) ((x) ? (((x) == 11) ? 1 : (x)) : 15)
|
||||
|
||||
#ifdef DEBUG_X
|
||||
static u_char tcic_getb(u_char reg)
|
||||
{
|
||||
u_char val = inb(tcic_base+reg);
|
||||
printk(KERN_DEBUG "tcic_getb(%#lx) = %#x\n", tcic_base+reg, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static u_short tcic_getw(u_char reg)
|
||||
{
|
||||
u_short val = inw(tcic_base+reg);
|
||||
printk(KERN_DEBUG "tcic_getw(%#lx) = %#x\n", tcic_base+reg, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static void tcic_setb(u_char reg, u_char data)
|
||||
{
|
||||
printk(KERN_DEBUG "tcic_setb(%#lx, %#x)\n", tcic_base+reg, data);
|
||||
outb(data, tcic_base+reg);
|
||||
}
|
||||
|
||||
static void tcic_setw(u_char reg, u_short data)
|
||||
{
|
||||
printk(KERN_DEBUG "tcic_setw(%#lx, %#x)\n", tcic_base+reg, data);
|
||||
outw(data, tcic_base+reg);
|
||||
}
|
||||
#else
|
||||
#define tcic_getb(reg) inb(tcic_base+reg)
|
||||
#define tcic_getw(reg) inw(tcic_base+reg)
|
||||
#define tcic_setb(reg, data) outb(data, tcic_base+reg)
|
||||
#define tcic_setw(reg, data) outw(data, tcic_base+reg)
|
||||
#endif
|
||||
|
||||
static void tcic_setl(u_char reg, u_int data)
|
||||
{
|
||||
#ifdef DEBUG_X
|
||||
printk(KERN_DEBUG "tcic_setl(%#x, %#lx)\n", tcic_base+reg, data);
|
||||
#endif
|
||||
outw(data & 0xffff, tcic_base+reg);
|
||||
outw(data >> 16, tcic_base+reg+2);
|
||||
}
|
||||
|
||||
static void tcic_aux_setb(u_short reg, u_char data)
|
||||
{
|
||||
u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
|
||||
tcic_setb(TCIC_MODE, mode);
|
||||
tcic_setb(TCIC_AUX, data);
|
||||
}
|
||||
|
||||
static u_short tcic_aux_getw(u_short reg)
|
||||
{
|
||||
u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
|
||||
tcic_setb(TCIC_MODE, mode);
|
||||
return tcic_getw(TCIC_AUX);
|
||||
}
|
||||
|
||||
static void tcic_aux_setw(u_short reg, u_short data)
|
||||
{
|
||||
u_char mode = (tcic_getb(TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
|
||||
tcic_setb(TCIC_MODE, mode);
|
||||
tcic_setw(TCIC_AUX, data);
|
||||
}
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
/* Time conversion functions */
|
||||
|
||||
static int to_cycles(int ns)
|
||||
{
|
||||
if (ns < 14)
|
||||
return 0;
|
||||
else
|
||||
return 2*(ns-14)/cycle_time;
|
||||
}
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
static volatile u_int irq_hits;
|
||||
|
||||
static irqreturn_t __init tcic_irq_count(int irq, void *dev)
|
||||
{
|
||||
irq_hits++;
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static u_int __init try_irq(int irq)
|
||||
{
|
||||
u_short cfg;
|
||||
|
||||
irq_hits = 0;
|
||||
if (request_irq(irq, tcic_irq_count, 0, "irq scan", tcic_irq_count) != 0)
|
||||
return -1;
|
||||
mdelay(10);
|
||||
if (irq_hits) {
|
||||
free_irq(irq, tcic_irq_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Generate one interrupt */
|
||||
cfg = TCIC_SYSCFG_AUTOBUSY | 0x0a00;
|
||||
tcic_aux_setw(TCIC_AUX_SYSCFG, cfg | TCIC_IRQ(irq));
|
||||
tcic_setb(TCIC_IENA, TCIC_IENA_ERR | TCIC_IENA_CFG_HIGH);
|
||||
tcic_setb(TCIC_ICSR, TCIC_ICSR_ERR | TCIC_ICSR_JAM);
|
||||
|
||||
udelay(1000);
|
||||
free_irq(irq, tcic_irq_count);
|
||||
|
||||
/* Turn off interrupts */
|
||||
tcic_setb(TCIC_IENA, TCIC_IENA_CFG_OFF);
|
||||
while (tcic_getb(TCIC_ICSR))
|
||||
tcic_setb(TCIC_ICSR, TCIC_ICSR_JAM);
|
||||
tcic_aux_setw(TCIC_AUX_SYSCFG, cfg);
|
||||
|
||||
return (irq_hits != 1);
|
||||
}
|
||||
|
||||
static u_int __init irq_scan(u_int mask0)
|
||||
{
|
||||
u_int mask1;
|
||||
int i;
|
||||
|
||||
#ifdef __alpha__
|
||||
#define PIC 0x4d0
|
||||
/* Don't probe level-triggered interrupts -- reserved for PCI */
|
||||
int level_mask = inb_p(PIC) | (inb_p(PIC+1) << 8);
|
||||
if (level_mask)
|
||||
mask0 &= ~level_mask;
|
||||
#endif
|
||||
|
||||
mask1 = 0;
|
||||
if (do_scan) {
|
||||
for (i = 0; i < 16; i++)
|
||||
if ((mask0 & (1 << i)) && (try_irq(i) == 0))
|
||||
mask1 |= (1 << i);
|
||||
for (i = 0; i < 16; i++)
|
||||
if ((mask1 & (1 << i)) && (try_irq(i) != 0)) {
|
||||
mask1 ^= (1 << i);
|
||||
}
|
||||
}
|
||||
|
||||
if (mask1) {
|
||||
printk("scanned");
|
||||
} else {
|
||||
/* Fallback: just find interrupts that aren't in use */
|
||||
for (i = 0; i < 16; i++)
|
||||
if ((mask0 & (1 << i)) &&
|
||||
(request_irq(i, tcic_irq_count, 0, "x", tcic_irq_count) == 0)) {
|
||||
mask1 |= (1 << i);
|
||||
free_irq(i, tcic_irq_count);
|
||||
}
|
||||
printk("default");
|
||||
}
|
||||
|
||||
printk(") = ");
|
||||
for (i = 0; i < 16; i++)
|
||||
if (mask1 & (1<<i))
|
||||
printk("%s%d", ((mask1 & ((1<<i)-1)) ? "," : ""), i);
|
||||
printk(" ");
|
||||
|
||||
return mask1;
|
||||
}
|
||||
|
||||
/*======================================================================
|
||||
|
||||
See if a card is present, powered up, in IO mode, and already
|
||||
bound to a (non-PCMCIA) Linux driver.
|
||||
|
||||
We make an exception for cards that look like serial devices.
|
||||
|
||||
======================================================================*/
|
||||
|
||||
static int __init is_active(int s)
|
||||
{
|
||||
u_short scf1, ioctl, base, num;
|
||||
u_char pwr, sstat;
|
||||
u_int addr;
|
||||
|
||||
tcic_setl(TCIC_ADDR, (s << TCIC_ADDR_SS_SHFT)
|
||||
| TCIC_ADDR_INDREG | TCIC_SCF1(s));
|
||||
scf1 = tcic_getw(TCIC_DATA);
|
||||
pwr = tcic_getb(TCIC_PWR);
|
||||
sstat = tcic_getb(TCIC_SSTAT);
|
||||
addr = TCIC_IWIN(s, 0);
|
||||
tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);
|
||||
base = tcic_getw(TCIC_DATA);
|
||||
tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);
|
||||
ioctl = tcic_getw(TCIC_DATA);
|
||||
|
||||
if (ioctl & TCIC_ICTL_TINY)
|
||||
num = 1;
|
||||
else {
|
||||
num = (base ^ (base-1));
|
||||
base = base & (base-1);
|
||||
}
|
||||
|
||||
if ((sstat & TCIC_SSTAT_CD) && (pwr & TCIC_PWR_VCC(s)) &&
|
||||
(scf1 & TCIC_SCF1_IOSTS) && (ioctl & TCIC_ICTL_ENA) &&
|
||||
((base & 0xfeef) != 0x02e8)) {
|
||||
struct resource *res = request_region(base, num, "tcic-2");
|
||||
if (!res) /* region is busy */
|
||||
return 1;
|
||||
release_region(base, num);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*======================================================================
|
||||
|
||||
This returns the revision code for the specified socket.
|
||||
|
||||
======================================================================*/
|
||||
|
||||
static int __init get_tcic_id(void)
|
||||
{
|
||||
u_short id;
|
||||
|
||||
tcic_aux_setw(TCIC_AUX_TEST, TCIC_TEST_DIAG);
|
||||
id = tcic_aux_getw(TCIC_AUX_ILOCK);
|
||||
id = (id & TCIC_ILOCKTEST_ID_MASK) >> TCIC_ILOCKTEST_ID_SH;
|
||||
tcic_aux_setw(TCIC_AUX_TEST, 0);
|
||||
return id;
|
||||
}
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
static struct platform_driver tcic_driver = {
|
||||
.driver = {
|
||||
.name = "tcic-pcmcia",
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device tcic_device = {
|
||||
.name = "tcic-pcmcia",
|
||||
.id = 0,
|
||||
};
|
||||
|
||||
|
||||
static int __init init_tcic(void)
|
||||
{
|
||||
int i, sock, ret = 0;
|
||||
u_int mask, scan;
|
||||
|
||||
if (platform_driver_register(&tcic_driver))
|
||||
return -1;
|
||||
|
||||
printk(KERN_INFO "Databook TCIC-2 PCMCIA probe: ");
|
||||
sock = 0;
|
||||
|
||||
if (!request_region(tcic_base, 16, "tcic-2")) {
|
||||
printk("could not allocate ports,\n ");
|
||||
platform_driver_unregister(&tcic_driver);
|
||||
return -ENODEV;
|
||||
}
|
||||
else {
|
||||
tcic_setw(TCIC_ADDR, 0);
|
||||
if (tcic_getw(TCIC_ADDR) == 0) {
|
||||
tcic_setw(TCIC_ADDR, 0xc3a5);
|
||||
if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2;
|
||||
}
|
||||
if (sock == 0) {
|
||||
/* See if resetting the controller does any good */
|
||||
tcic_setb(TCIC_SCTRL, TCIC_SCTRL_RESET);
|
||||
tcic_setb(TCIC_SCTRL, 0);
|
||||
tcic_setw(TCIC_ADDR, 0);
|
||||
if (tcic_getw(TCIC_ADDR) == 0) {
|
||||
tcic_setw(TCIC_ADDR, 0xc3a5);
|
||||
if (tcic_getw(TCIC_ADDR) == 0xc3a5) sock = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sock == 0) {
|
||||
printk("not found.\n");
|
||||
release_region(tcic_base, 16);
|
||||
platform_driver_unregister(&tcic_driver);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
sockets = 0;
|
||||
for (i = 0; i < sock; i++) {
|
||||
if ((i == ignore) || is_active(i)) continue;
|
||||
socket_table[sockets].psock = i;
|
||||
socket_table[sockets].id = get_tcic_id();
|
||||
|
||||
socket_table[sockets].socket.owner = THIS_MODULE;
|
||||
/* only 16-bit cards, memory windows must be size-aligned */
|
||||
/* No PCI or CardBus support */
|
||||
socket_table[sockets].socket.features = SS_CAP_PCCARD | SS_CAP_MEM_ALIGN;
|
||||
/* irq 14, 11, 10, 7, 6, 5, 4, 3 */
|
||||
socket_table[sockets].socket.irq_mask = 0x4cf8;
|
||||
/* 4K minimum window size */
|
||||
socket_table[sockets].socket.map_size = 0x1000;
|
||||
sockets++;
|
||||
}
|
||||
|
||||
switch (socket_table[0].id) {
|
||||
case TCIC_ID_DB86082:
|
||||
printk("DB86082"); break;
|
||||
case TCIC_ID_DB86082A:
|
||||
printk("DB86082A"); break;
|
||||
case TCIC_ID_DB86084:
|
||||
printk("DB86084"); break;
|
||||
case TCIC_ID_DB86084A:
|
||||
printk("DB86084A"); break;
|
||||
case TCIC_ID_DB86072:
|
||||
printk("DB86072"); break;
|
||||
case TCIC_ID_DB86184:
|
||||
printk("DB86184"); break;
|
||||
case TCIC_ID_DB86082B:
|
||||
printk("DB86082B"); break;
|
||||
default:
|
||||
printk("Unknown ID 0x%02x", socket_table[0].id);
|
||||
}
|
||||
|
||||
/* Set up polling */
|
||||
timer_setup(&poll_timer, tcic_timer, 0);
|
||||
|
||||
/* Build interrupt mask */
|
||||
printk(KERN_CONT ", %d sockets\n", sockets);
|
||||
printk(KERN_INFO " irq list (");
|
||||
if (irq_list_count == 0)
|
||||
mask = irq_mask;
|
||||
else
|
||||
for (i = mask = 0; i < irq_list_count; i++)
|
||||
mask |= (1<<irq_list[i]);
|
||||
|
||||
/* irq 14, 11, 10, 7, 6, 5, 4, 3 */
|
||||
mask &= 0x4cf8;
|
||||
/* Scan interrupts */
|
||||
mask = irq_scan(mask);
|
||||
for (i=0;i<sockets;i++)
|
||||
socket_table[i].socket.irq_mask = mask;
|
||||
|
||||
/* Check for only two interrupts available */
|
||||
scan = (mask & (mask-1));
|
||||
if (((scan & (scan-1)) == 0) && (poll_interval == 0))
|
||||
poll_interval = HZ;
|
||||
|
||||
if (poll_interval == 0) {
|
||||
/* Avoid irq 12 unless it is explicitly requested */
|
||||
u_int cs_mask = mask & ((cs_irq) ? (1<<cs_irq) : ~(1<<12));
|
||||
for (i = 15; i > 0; i--)
|
||||
if ((cs_mask & (1 << i)) &&
|
||||
(request_irq(i, tcic_interrupt, 0, "tcic",
|
||||
tcic_interrupt) == 0))
|
||||
break;
|
||||
cs_irq = i;
|
||||
if (cs_irq == 0) poll_interval = HZ;
|
||||
}
|
||||
|
||||
if (socket_table[0].socket.irq_mask & (1 << 11))
|
||||
printk("sktirq is irq 11, ");
|
||||
if (cs_irq != 0)
|
||||
printk("status change on irq %d\n", cs_irq);
|
||||
else
|
||||
printk("polled status, interval = %d ms\n",
|
||||
poll_interval * 1000 / HZ);
|
||||
|
||||
for (i = 0; i < sockets; i++) {
|
||||
tcic_setw(TCIC_ADDR+2, socket_table[i].psock << TCIC_SS_SHFT);
|
||||
socket_table[i].last_sstat = tcic_getb(TCIC_SSTAT);
|
||||
}
|
||||
|
||||
/* jump start interrupt handler, if needed */
|
||||
tcic_interrupt(0, NULL);
|
||||
|
||||
platform_device_register(&tcic_device);
|
||||
|
||||
for (i = 0; i < sockets; i++) {
|
||||
socket_table[i].socket.ops = &tcic_operations;
|
||||
socket_table[i].socket.resource_ops = &pccard_nonstatic_ops;
|
||||
socket_table[i].socket.dev.parent = &tcic_device.dev;
|
||||
ret = pcmcia_register_socket(&socket_table[i].socket);
|
||||
if (ret && i)
|
||||
pcmcia_unregister_socket(&socket_table[0].socket);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
|
||||
} /* init_tcic */
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
static void __exit exit_tcic(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
timer_delete_sync(&poll_timer);
|
||||
if (cs_irq != 0) {
|
||||
tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00);
|
||||
free_irq(cs_irq, tcic_interrupt);
|
||||
}
|
||||
release_region(tcic_base, 16);
|
||||
|
||||
for (i = 0; i < sockets; i++) {
|
||||
pcmcia_unregister_socket(&socket_table[i].socket);
|
||||
}
|
||||
|
||||
platform_device_unregister(&tcic_device);
|
||||
platform_driver_unregister(&tcic_driver);
|
||||
} /* exit_tcic */
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
static irqreturn_t tcic_interrupt(int irq, void *dev)
|
||||
{
|
||||
int i, quick = 0;
|
||||
u_char latch, sstat;
|
||||
u_short psock;
|
||||
u_int events;
|
||||
static volatile int active = 0;
|
||||
|
||||
if (active) {
|
||||
printk(KERN_NOTICE "tcic: reentered interrupt handler!\n");
|
||||
return IRQ_NONE;
|
||||
} else
|
||||
active = 1;
|
||||
|
||||
pr_debug("tcic_interrupt()\n");
|
||||
|
||||
for (i = 0; i < sockets; i++) {
|
||||
psock = socket_table[i].psock;
|
||||
tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)
|
||||
| TCIC_ADDR_INDREG | TCIC_SCF1(psock));
|
||||
sstat = tcic_getb(TCIC_SSTAT);
|
||||
latch = sstat ^ socket_table[psock].last_sstat;
|
||||
socket_table[i].last_sstat = sstat;
|
||||
if (tcic_getb(TCIC_ICSR) & TCIC_ICSR_CDCHG) {
|
||||
tcic_setb(TCIC_ICSR, TCIC_ICSR_CLEAR);
|
||||
quick = 1;
|
||||
}
|
||||
if (latch == 0)
|
||||
continue;
|
||||
events = (latch & TCIC_SSTAT_CD) ? SS_DETECT : 0;
|
||||
events |= (latch & TCIC_SSTAT_WP) ? SS_WRPROT : 0;
|
||||
if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) {
|
||||
events |= (latch & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0;
|
||||
} else {
|
||||
events |= (latch & TCIC_SSTAT_RDY) ? SS_READY : 0;
|
||||
events |= (latch & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0;
|
||||
events |= (latch & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0;
|
||||
}
|
||||
if (events) {
|
||||
pcmcia_parse_events(&socket_table[i].socket, events);
|
||||
}
|
||||
}
|
||||
|
||||
/* Schedule next poll, if needed */
|
||||
if (((cs_irq == 0) || quick) && (!tcic_timer_pending)) {
|
||||
poll_timer.expires = jiffies + (quick ? poll_quick : poll_interval);
|
||||
add_timer(&poll_timer);
|
||||
tcic_timer_pending = 1;
|
||||
}
|
||||
active = 0;
|
||||
|
||||
pr_debug("interrupt done\n");
|
||||
return IRQ_HANDLED;
|
||||
} /* tcic_interrupt */
|
||||
|
||||
static void tcic_timer(struct timer_list *unused)
|
||||
{
|
||||
pr_debug("tcic_timer()\n");
|
||||
tcic_timer_pending = 0;
|
||||
tcic_interrupt(0, NULL);
|
||||
} /* tcic_timer */
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
static int tcic_get_status(struct pcmcia_socket *sock, u_int *value)
|
||||
{
|
||||
u_short psock = container_of(sock, struct tcic_socket, socket)->psock;
|
||||
u_char reg;
|
||||
|
||||
tcic_setl(TCIC_ADDR, (psock << TCIC_ADDR_SS_SHFT)
|
||||
| TCIC_ADDR_INDREG | TCIC_SCF1(psock));
|
||||
reg = tcic_getb(TCIC_SSTAT);
|
||||
*value = (reg & TCIC_SSTAT_CD) ? SS_DETECT : 0;
|
||||
*value |= (reg & TCIC_SSTAT_WP) ? SS_WRPROT : 0;
|
||||
if (tcic_getw(TCIC_DATA) & TCIC_SCF1_IOSTS) {
|
||||
*value |= (reg & TCIC_SSTAT_LBAT1) ? SS_STSCHG : 0;
|
||||
} else {
|
||||
*value |= (reg & TCIC_SSTAT_RDY) ? SS_READY : 0;
|
||||
*value |= (reg & TCIC_SSTAT_LBAT1) ? SS_BATDEAD : 0;
|
||||
*value |= (reg & TCIC_SSTAT_LBAT2) ? SS_BATWARN : 0;
|
||||
}
|
||||
reg = tcic_getb(TCIC_PWR);
|
||||
if (reg & (TCIC_PWR_VCC(psock)|TCIC_PWR_VPP(psock)))
|
||||
*value |= SS_POWERON;
|
||||
dev_dbg(&sock->dev, "GetStatus(%d) = %#2.2x\n", psock, *value);
|
||||
return 0;
|
||||
} /* tcic_get_status */
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
static int tcic_set_socket(struct pcmcia_socket *sock, socket_state_t *state)
|
||||
{
|
||||
u_short psock = container_of(sock, struct tcic_socket, socket)->psock;
|
||||
u_char reg;
|
||||
u_short scf1, scf2;
|
||||
|
||||
dev_dbg(&sock->dev, "SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
|
||||
"io_irq %d, csc_mask %#2.2x)\n", psock, state->flags,
|
||||
state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
|
||||
tcic_setw(TCIC_ADDR+2, (psock << TCIC_SS_SHFT) | TCIC_ADR2_INDREG);
|
||||
|
||||
reg = tcic_getb(TCIC_PWR);
|
||||
reg &= ~(TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock));
|
||||
|
||||
if (state->Vcc == 50) {
|
||||
switch (state->Vpp) {
|
||||
case 0: reg |= TCIC_PWR_VCC(psock) | TCIC_PWR_VPP(psock); break;
|
||||
case 50: reg |= TCIC_PWR_VCC(psock); break;
|
||||
case 120: reg |= TCIC_PWR_VPP(psock); break;
|
||||
default: return -EINVAL;
|
||||
}
|
||||
} else if (state->Vcc != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (reg != tcic_getb(TCIC_PWR))
|
||||
tcic_setb(TCIC_PWR, reg);
|
||||
|
||||
reg = TCIC_ILOCK_HOLD_CCLK | TCIC_ILOCK_CWAIT;
|
||||
if (state->flags & SS_OUTPUT_ENA) {
|
||||
tcic_setb(TCIC_SCTRL, TCIC_SCTRL_ENA);
|
||||
reg |= TCIC_ILOCK_CRESENA;
|
||||
} else
|
||||
tcic_setb(TCIC_SCTRL, 0);
|
||||
if (state->flags & SS_RESET)
|
||||
reg |= TCIC_ILOCK_CRESET;
|
||||
tcic_aux_setb(TCIC_AUX_ILOCK, reg);
|
||||
|
||||
tcic_setw(TCIC_ADDR, TCIC_SCF1(psock));
|
||||
scf1 = TCIC_SCF1_FINPACK;
|
||||
scf1 |= TCIC_IRQ(state->io_irq);
|
||||
if (state->flags & SS_IOCARD) {
|
||||
scf1 |= TCIC_SCF1_IOSTS;
|
||||
if (state->flags & SS_SPKR_ENA)
|
||||
scf1 |= TCIC_SCF1_SPKR;
|
||||
if (state->flags & SS_DMA_MODE)
|
||||
scf1 |= TCIC_SCF1_DREQ2 << TCIC_SCF1_DMA_SHIFT;
|
||||
}
|
||||
tcic_setw(TCIC_DATA, scf1);
|
||||
|
||||
/* Some general setup stuff, and configure status interrupt */
|
||||
reg = TCIC_WAIT_ASYNC | TCIC_WAIT_SENSE | to_cycles(250);
|
||||
tcic_aux_setb(TCIC_AUX_WCTL, reg);
|
||||
tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00|
|
||||
TCIC_IRQ(cs_irq));
|
||||
|
||||
/* Card status change interrupt mask */
|
||||
tcic_setw(TCIC_ADDR, TCIC_SCF2(psock));
|
||||
scf2 = TCIC_SCF2_MALL;
|
||||
if (state->csc_mask & SS_DETECT) scf2 &= ~TCIC_SCF2_MCD;
|
||||
if (state->flags & SS_IOCARD) {
|
||||
if (state->csc_mask & SS_STSCHG) reg &= ~TCIC_SCF2_MLBAT1;
|
||||
} else {
|
||||
if (state->csc_mask & SS_BATDEAD) reg &= ~TCIC_SCF2_MLBAT1;
|
||||
if (state->csc_mask & SS_BATWARN) reg &= ~TCIC_SCF2_MLBAT2;
|
||||
if (state->csc_mask & SS_READY) reg &= ~TCIC_SCF2_MRDY;
|
||||
}
|
||||
tcic_setw(TCIC_DATA, scf2);
|
||||
/* For the ISA bus, the irq should be active-high totem-pole */
|
||||
tcic_setb(TCIC_IENA, TCIC_IENA_CDCHG | TCIC_IENA_CFG_HIGH);
|
||||
|
||||
return 0;
|
||||
} /* tcic_set_socket */
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
static int tcic_set_io_map(struct pcmcia_socket *sock, struct pccard_io_map *io)
|
||||
{
|
||||
u_short psock = container_of(sock, struct tcic_socket, socket)->psock;
|
||||
u_int addr;
|
||||
u_short base, len, ioctl;
|
||||
|
||||
dev_dbg(&sock->dev, "SetIOMap(%d, %d, %#2.2x, %d ns, "
|
||||
"%#llx-%#llx)\n", psock, io->map, io->flags, io->speed,
|
||||
(unsigned long long)io->start, (unsigned long long)io->stop);
|
||||
if ((io->map > 1) || (io->start > 0xffff) || (io->stop > 0xffff) ||
|
||||
(io->stop < io->start)) return -EINVAL;
|
||||
tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
|
||||
addr = TCIC_IWIN(psock, io->map);
|
||||
|
||||
base = io->start; len = io->stop - io->start;
|
||||
/* Check to see that len+1 is power of two, etc */
|
||||
if ((len & (len+1)) || (base & len)) return -EINVAL;
|
||||
base |= (len+1)>>1;
|
||||
tcic_setw(TCIC_ADDR, addr + TCIC_IBASE_X);
|
||||
tcic_setw(TCIC_DATA, base);
|
||||
|
||||
ioctl = (psock << TCIC_ICTL_SS_SHFT);
|
||||
ioctl |= (len == 0) ? TCIC_ICTL_TINY : 0;
|
||||
ioctl |= (io->flags & MAP_ACTIVE) ? TCIC_ICTL_ENA : 0;
|
||||
ioctl |= to_cycles(io->speed) & TCIC_ICTL_WSCNT_MASK;
|
||||
if (!(io->flags & MAP_AUTOSZ)) {
|
||||
ioctl |= TCIC_ICTL_QUIET;
|
||||
ioctl |= (io->flags & MAP_16BIT) ? TCIC_ICTL_BW_16 : TCIC_ICTL_BW_8;
|
||||
}
|
||||
tcic_setw(TCIC_ADDR, addr + TCIC_ICTL_X);
|
||||
tcic_setw(TCIC_DATA, ioctl);
|
||||
|
||||
return 0;
|
||||
} /* tcic_set_io_map */
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
static int tcic_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *mem)
|
||||
{
|
||||
u_short psock = container_of(sock, struct tcic_socket, socket)->psock;
|
||||
u_short addr, ctl;
|
||||
u_long base, len, mmap;
|
||||
|
||||
dev_dbg(&sock->dev, "SetMemMap(%d, %d, %#2.2x, %d ns, "
|
||||
"%#llx-%#llx, %#x)\n", psock, mem->map, mem->flags,
|
||||
mem->speed, (unsigned long long)mem->res->start,
|
||||
(unsigned long long)mem->res->end, mem->card_start);
|
||||
if ((mem->map > 3) || (mem->card_start > 0x3ffffff) ||
|
||||
(mem->res->start > 0xffffff) || (mem->res->end > 0xffffff) ||
|
||||
(mem->res->start > mem->res->end) || (mem->speed > 1000))
|
||||
return -EINVAL;
|
||||
tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG | (psock << TCIC_SS_SHFT));
|
||||
addr = TCIC_MWIN(psock, mem->map);
|
||||
|
||||
base = mem->res->start; len = mem->res->end - mem->res->start;
|
||||
if ((len & (len+1)) || (base & len)) return -EINVAL;
|
||||
if (len == 0x0fff)
|
||||
base = (base >> TCIC_MBASE_HA_SHFT) | TCIC_MBASE_4K_BIT;
|
||||
else
|
||||
base = (base | (len+1)>>1) >> TCIC_MBASE_HA_SHFT;
|
||||
tcic_setw(TCIC_ADDR, addr + TCIC_MBASE_X);
|
||||
tcic_setw(TCIC_DATA, base);
|
||||
|
||||
mmap = mem->card_start - mem->res->start;
|
||||
mmap = (mmap >> TCIC_MMAP_CA_SHFT) & TCIC_MMAP_CA_MASK;
|
||||
if (mem->flags & MAP_ATTRIB) mmap |= TCIC_MMAP_REG;
|
||||
tcic_setw(TCIC_ADDR, addr + TCIC_MMAP_X);
|
||||
tcic_setw(TCIC_DATA, mmap);
|
||||
|
||||
ctl = TCIC_MCTL_QUIET | (psock << TCIC_MCTL_SS_SHFT);
|
||||
ctl |= to_cycles(mem->speed) & TCIC_MCTL_WSCNT_MASK;
|
||||
ctl |= (mem->flags & MAP_16BIT) ? 0 : TCIC_MCTL_B8;
|
||||
ctl |= (mem->flags & MAP_WRPROT) ? TCIC_MCTL_WP : 0;
|
||||
ctl |= (mem->flags & MAP_ACTIVE) ? TCIC_MCTL_ENA : 0;
|
||||
tcic_setw(TCIC_ADDR, addr + TCIC_MCTL_X);
|
||||
tcic_setw(TCIC_DATA, ctl);
|
||||
|
||||
return 0;
|
||||
} /* tcic_set_mem_map */
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
static int tcic_init(struct pcmcia_socket *s)
|
||||
{
|
||||
int i;
|
||||
struct resource res = { .start = 0, .end = 0x1000 };
|
||||
pccard_io_map io = { 0, 0, 0, 0, 1 };
|
||||
pccard_mem_map mem = { .res = &res, };
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
io.map = i;
|
||||
tcic_set_io_map(s, &io);
|
||||
}
|
||||
for (i = 0; i < 5; i++) {
|
||||
mem.map = i;
|
||||
tcic_set_mem_map(s, &mem);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct pccard_operations tcic_operations = {
|
||||
.init = tcic_init,
|
||||
.get_status = tcic_get_status,
|
||||
.set_socket = tcic_set_socket,
|
||||
.set_io_map = tcic_set_io_map,
|
||||
.set_mem_map = tcic_set_mem_map,
|
||||
};
|
||||
|
||||
/*====================================================================*/
|
||||
|
||||
module_init(init_tcic);
|
||||
module_exit(exit_tcic);
|
||||
|
|
@ -1,266 +0,0 @@
|
|||
/*
|
||||
* tcic.h 1.13 1999/10/25 20:03:34
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License
|
||||
* Version 1.1 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License
|
||||
* at http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS"
|
||||
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
|
||||
* the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* The initial developer of the original code is David A. Hinds
|
||||
* <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
|
||||
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* terms of the GNU General Public License version 2 (the "GPL"), in which
|
||||
* case the provisions of the GPL are applicable instead of the
|
||||
* above. If you wish to allow the use of your version of this file
|
||||
* only under the terms of the GPL and not to allow others to use
|
||||
* your version of this file under the MPL, indicate your decision by
|
||||
* deleting the provisions above and replace them with the notice and
|
||||
* other provisions required by the GPL. If you do not delete the
|
||||
* provisions above, a recipient may use your version of this file
|
||||
* under either the MPL or the GPL.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_TCIC_H
|
||||
#define _LINUX_TCIC_H
|
||||
|
||||
#define TCIC_BASE 0x240
|
||||
|
||||
/* offsets of registers from TCIC_BASE */
|
||||
#define TCIC_DATA 0x00
|
||||
#define TCIC_ADDR 0x02
|
||||
#define TCIC_SCTRL 0x06
|
||||
#define TCIC_SSTAT 0x07
|
||||
#define TCIC_MODE 0x08
|
||||
#define TCIC_PWR 0x09
|
||||
#define TCIC_EDC 0x0A
|
||||
#define TCIC_ICSR 0x0C
|
||||
#define TCIC_IENA 0x0D
|
||||
#define TCIC_AUX 0x0E
|
||||
|
||||
#define TCIC_SS_SHFT 12
|
||||
#define TCIC_SS_MASK 0x7000
|
||||
|
||||
/* Flags for TCIC_ADDR */
|
||||
#define TCIC_ADR2_REG 0x8000
|
||||
#define TCIC_ADR2_INDREG 0x0800
|
||||
|
||||
#define TCIC_ADDR_REG 0x80000000
|
||||
#define TCIC_ADDR_SS_SHFT (TCIC_SS_SHFT+16)
|
||||
#define TCIC_ADDR_SS_MASK (TCIC_SS_MASK<<16)
|
||||
#define TCIC_ADDR_INDREG 0x08000000
|
||||
#define TCIC_ADDR_IO 0x04000000
|
||||
#define TCIC_ADDR_MASK 0x03ffffff
|
||||
|
||||
/* Flags for TCIC_SCTRL */
|
||||
#define TCIC_SCTRL_ENA 0x01
|
||||
#define TCIC_SCTRL_INCMODE 0x18
|
||||
#define TCIC_SCTRL_INCMODE_HOLD 0x00
|
||||
#define TCIC_SCTRL_INCMODE_WORD 0x08
|
||||
#define TCIC_SCTRL_INCMODE_REG 0x10
|
||||
#define TCIC_SCTRL_INCMODE_AUTO 0x18
|
||||
#define TCIC_SCTRL_EDCSUM 0x20
|
||||
#define TCIC_SCTRL_RESET 0x80
|
||||
|
||||
/* Flags for TCIC_SSTAT */
|
||||
#define TCIC_SSTAT_6US 0x01
|
||||
#define TCIC_SSTAT_10US 0x02
|
||||
#define TCIC_SSTAT_PROGTIME 0x04
|
||||
#define TCIC_SSTAT_LBAT1 0x08
|
||||
#define TCIC_SSTAT_LBAT2 0x10
|
||||
#define TCIC_SSTAT_RDY 0x20 /* Inverted */
|
||||
#define TCIC_SSTAT_WP 0x40
|
||||
#define TCIC_SSTAT_CD 0x80 /* Card detect */
|
||||
|
||||
/* Flags for TCIC_MODE */
|
||||
#define TCIC_MODE_PGMMASK 0x1f
|
||||
#define TCIC_MODE_NORMAL 0x00
|
||||
#define TCIC_MODE_PGMWR 0x01
|
||||
#define TCIC_MODE_PGMRD 0x02
|
||||
#define TCIC_MODE_PGMCE 0x04
|
||||
#define TCIC_MODE_PGMDBW 0x08
|
||||
#define TCIC_MODE_PGMWORD 0x10
|
||||
#define TCIC_MODE_AUXSEL_MASK 0xe0
|
||||
|
||||
/* Registers accessed through TCIC_AUX, by setting TCIC_MODE */
|
||||
#define TCIC_AUX_TCTL (0<<5)
|
||||
#define TCIC_AUX_PCTL (1<<5)
|
||||
#define TCIC_AUX_WCTL (2<<5)
|
||||
#define TCIC_AUX_EXTERN (3<<5)
|
||||
#define TCIC_AUX_PDATA (4<<5)
|
||||
#define TCIC_AUX_SYSCFG (5<<5)
|
||||
#define TCIC_AUX_ILOCK (6<<5)
|
||||
#define TCIC_AUX_TEST (7<<5)
|
||||
|
||||
/* Flags for TCIC_PWR */
|
||||
#define TCIC_PWR_VCC(sock) (0x01<<(sock))
|
||||
#define TCIC_PWR_VCC_MASK 0x03
|
||||
#define TCIC_PWR_VPP(sock) (0x08<<(sock))
|
||||
#define TCIC_PWR_VPP_MASK 0x18
|
||||
#define TCIC_PWR_CLIMENA 0x40
|
||||
#define TCIC_PWR_CLIMSTAT 0x80
|
||||
|
||||
/* Flags for TCIC_ICSR */
|
||||
#define TCIC_ICSR_CLEAR 0x01
|
||||
#define TCIC_ICSR_SET 0x02
|
||||
#define TCIC_ICSR_JAM (TCIC_ICSR_CLEAR|TCIC_ICSR_SET)
|
||||
#define TCIC_ICSR_STOPCPU 0x04
|
||||
#define TCIC_ICSR_ILOCK 0x08
|
||||
#define TCIC_ICSR_PROGTIME 0x10
|
||||
#define TCIC_ICSR_ERR 0x20
|
||||
#define TCIC_ICSR_CDCHG 0x40
|
||||
#define TCIC_ICSR_IOCHK 0x80
|
||||
|
||||
/* Flags for TCIC_IENA */
|
||||
#define TCIC_IENA_CFG_MASK 0x03
|
||||
#define TCIC_IENA_CFG_OFF 0x00 /* disabled */
|
||||
#define TCIC_IENA_CFG_OD 0x01 /* active low, open drain */
|
||||
#define TCIC_IENA_CFG_LOW 0x02 /* active low, totem pole */
|
||||
#define TCIC_IENA_CFG_HIGH 0x03 /* active high, totem pole */
|
||||
#define TCIC_IENA_ILOCK 0x08
|
||||
#define TCIC_IENA_PROGTIME 0x10
|
||||
#define TCIC_IENA_ERR 0x20 /* overcurrent or iochk */
|
||||
#define TCIC_IENA_CDCHG 0x40
|
||||
|
||||
/* Flags for TCIC_AUX_WCTL */
|
||||
#define TCIC_WAIT_COUNT_MASK 0x001f
|
||||
#define TCIC_WAIT_ASYNC 0x0020
|
||||
#define TCIC_WAIT_SENSE 0x0040
|
||||
#define TCIC_WAIT_SRC 0x0080
|
||||
#define TCIC_WCTL_WR 0x0100
|
||||
#define TCIC_WCTL_RD 0x0200
|
||||
#define TCIC_WCTL_CE 0x0400
|
||||
#define TCIC_WCTL_LLBAT1 0x0800
|
||||
#define TCIC_WCTL_LLBAT2 0x1000
|
||||
#define TCIC_WCTL_LRDY 0x2000
|
||||
#define TCIC_WCTL_LWP 0x4000
|
||||
#define TCIC_WCTL_LCD 0x8000
|
||||
|
||||
/* Flags for TCIC_AUX_SYSCFG */
|
||||
#define TCIC_SYSCFG_IRQ_MASK 0x000f
|
||||
#define TCIC_SYSCFG_MCSFULL 0x0010
|
||||
#define TCIC_SYSCFG_IO1723 0x0020
|
||||
#define TCIC_SYSCFG_MCSXB 0x0040
|
||||
#define TCIC_SYSCFG_ICSXB 0x0080
|
||||
#define TCIC_SYSCFG_NOPDN 0x0100
|
||||
#define TCIC_SYSCFG_MPSEL_SHFT 9
|
||||
#define TCIC_SYSCFG_MPSEL_MASK 0x0e00
|
||||
#define TCIC_SYSCFG_MPSENSE 0x2000
|
||||
#define TCIC_SYSCFG_AUTOBUSY 0x4000
|
||||
#define TCIC_SYSCFG_ACC 0x8000
|
||||
|
||||
#define TCIC_ILOCK_OUT 0x01
|
||||
#define TCIC_ILOCK_SENSE 0x02
|
||||
#define TCIC_ILOCK_CRESET 0x04
|
||||
#define TCIC_ILOCK_CRESENA 0x08
|
||||
#define TCIC_ILOCK_CWAIT 0x10
|
||||
#define TCIC_ILOCK_CWAITSNS 0x20
|
||||
#define TCIC_ILOCK_HOLD_MASK 0xc0
|
||||
#define TCIC_ILOCK_HOLD_CCLK 0xc0
|
||||
|
||||
#define TCIC_ILOCKTEST_ID_SH 8
|
||||
#define TCIC_ILOCKTEST_ID_MASK 0x7f00
|
||||
#define TCIC_ILOCKTEST_MCIC_1 0x8000
|
||||
|
||||
#define TCIC_ID_DB86082 0x02
|
||||
#define TCIC_ID_DB86082A 0x03
|
||||
#define TCIC_ID_DB86084 0x04
|
||||
#define TCIC_ID_DB86084A 0x08
|
||||
#define TCIC_ID_DB86072 0x15
|
||||
#define TCIC_ID_DB86184 0x14
|
||||
#define TCIC_ID_DB86082B 0x17
|
||||
|
||||
#define TCIC_TEST_DIAG 0x8000
|
||||
|
||||
/*
|
||||
* Indirectly addressed registers
|
||||
*/
|
||||
|
||||
#define TCIC_SCF1(sock) ((sock)<<3)
|
||||
#define TCIC_SCF2(sock) (((sock)<<3)+2)
|
||||
|
||||
/* Flags for SCF1 */
|
||||
#define TCIC_SCF1_IRQ_MASK 0x000f
|
||||
#define TCIC_SCF1_IRQ_OFF 0x0000
|
||||
#define TCIC_SCF1_IRQOC 0x0010
|
||||
#define TCIC_SCF1_PCVT 0x0020
|
||||
#define TCIC_SCF1_IRDY 0x0040
|
||||
#define TCIC_SCF1_ATA 0x0080
|
||||
#define TCIC_SCF1_DMA_SHIFT 8
|
||||
#define TCIC_SCF1_DMA_MASK 0x0700
|
||||
#define TCIC_SCF1_DMA_OFF 0
|
||||
#define TCIC_SCF1_DREQ2 2
|
||||
#define TCIC_SCF1_IOSTS 0x0800
|
||||
#define TCIC_SCF1_SPKR 0x1000
|
||||
#define TCIC_SCF1_FINPACK 0x2000
|
||||
#define TCIC_SCF1_DELWR 0x4000
|
||||
#define TCIC_SCF1_HD7IDE 0x8000
|
||||
|
||||
/* Flags for SCF2 */
|
||||
#define TCIC_SCF2_RI 0x0001
|
||||
#define TCIC_SCF2_IDBR 0x0002
|
||||
#define TCIC_SCF2_MDBR 0x0004
|
||||
#define TCIC_SCF2_MLBAT1 0x0008
|
||||
#define TCIC_SCF2_MLBAT2 0x0010
|
||||
#define TCIC_SCF2_MRDY 0x0020
|
||||
#define TCIC_SCF2_MWP 0x0040
|
||||
#define TCIC_SCF2_MCD 0x0080
|
||||
#define TCIC_SCF2_MALL 0x00f8
|
||||
|
||||
/* Indirect addresses for memory window registers */
|
||||
#define TCIC_MWIN(sock,map) (0x100+(((map)+((sock)<<2))<<3))
|
||||
#define TCIC_MBASE_X 2
|
||||
#define TCIC_MMAP_X 4
|
||||
#define TCIC_MCTL_X 6
|
||||
|
||||
#define TCIC_MBASE_4K_BIT 0x4000
|
||||
#define TCIC_MBASE_HA_SHFT 12
|
||||
#define TCIC_MBASE_HA_MASK 0x0fff
|
||||
|
||||
#define TCIC_MMAP_REG 0x8000
|
||||
#define TCIC_MMAP_CA_SHFT 12
|
||||
#define TCIC_MMAP_CA_MASK 0x3fff
|
||||
|
||||
#define TCIC_MCTL_WSCNT_MASK 0x001f
|
||||
#define TCIC_MCTL_WCLK 0x0020
|
||||
#define TCIC_MCTL_WCLK_CCLK 0x0000
|
||||
#define TCIC_MCTL_WCLK_BCLK 0x0020
|
||||
#define TCIC_MCTL_QUIET 0x0040
|
||||
#define TCIC_MCTL_WP 0x0080
|
||||
#define TCIC_MCTL_ACC 0x0100
|
||||
#define TCIC_MCTL_KE 0x0200
|
||||
#define TCIC_MCTL_EDC 0x0400
|
||||
#define TCIC_MCTL_B8 0x0800
|
||||
#define TCIC_MCTL_SS_SHFT TCIC_SS_SHFT
|
||||
#define TCIC_MCTL_SS_MASK TCIC_SS_MASK
|
||||
#define TCIC_MCTL_ENA 0x8000
|
||||
|
||||
/* Indirect addresses for I/O window registers */
|
||||
#define TCIC_IWIN(sock,map) (0x200+(((map)+((sock)<<1))<<2))
|
||||
#define TCIC_IBASE_X 0
|
||||
#define TCIC_ICTL_X 2
|
||||
|
||||
#define TCIC_ICTL_WSCNT_MASK TCIC_MCTL_WSCNT_MASK
|
||||
#define TCIC_ICTL_QUIET TCIC_MCTL_QUIET
|
||||
#define TCIC_ICTL_1K 0x0080
|
||||
#define TCIC_ICTL_PASS16 0x0100
|
||||
#define TCIC_ICTL_ACC TCIC_MCTL_ACC
|
||||
#define TCIC_ICTL_TINY 0x0200
|
||||
#define TCIC_ICTL_B16 0x0400
|
||||
#define TCIC_ICTL_B8 TCIC_MCTL_B8
|
||||
#define TCIC_ICTL_BW_MASK (TCIC_ICTL_B16|TCIC_ICTL_B8)
|
||||
#define TCIC_ICTL_BW_DYN 0
|
||||
#define TCIC_ICTL_BW_8 TCIC_ICTL_B8
|
||||
#define TCIC_ICTL_BW_16 TCIC_ICTL_B16
|
||||
#define TCIC_ICTL_BW_ATA (TCIC_ICTL_B16|TCIC_ICTL_B8)
|
||||
#define TCIC_ICTL_SS_SHFT TCIC_SS_SHFT
|
||||
#define TCIC_ICTL_SS_MASK TCIC_SS_MASK
|
||||
#define TCIC_ICTL_ENA TCIC_MCTL_ENA
|
||||
|
||||
#endif /* _LINUX_TCIC_H */
|
||||
|
|
@ -674,9 +674,8 @@ static int yenta_search_res(struct yenta_socket *socket, struct resource *res,
|
|||
u32 min)
|
||||
{
|
||||
struct resource *root;
|
||||
int i;
|
||||
|
||||
pci_bus_for_each_resource(socket->dev->bus, root, i) {
|
||||
pci_bus_for_each_resource(socket->dev->bus, root) {
|
||||
if (!root)
|
||||
continue;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue