From: Komuro <komujun@nifty.com>
To: majordomo@vger.kernel.org
Subject: [PATCH 2.6.0] Cirrus PD6729 PCI-to-PCMCIA Bridge support for 2.6.x kernel
Date: 11 Jan 2004 20:16:35 +0900 [thread overview]
Message-ID: <1073819401.2329.7.camel@localhost.localdomain> (raw)
Dear all
I made a Cirrus PD6729 PCI-to-PCMCIA Bridge for 2.6.x kernel.
Please see the following patch. ( sorry for big patch)
Best Regards
diff -ruN linux/drivers/pcmcia.orig/Kconfig linux/drivers/pcmcia/Kconfig
--- linux/drivers/pcmcia.orig/Kconfig 2003-12-18 11:59:16.000000000
+0900
+++ linux/drivers/pcmcia/Kconfig 2003-12-30 21:38:44.000000000 +0900
@@ -50,6 +50,13 @@
depends on YENTA
default y if YENTA
+config PD6729
+ tristate "Cirrus PD6729 compatible bridge support"
+ depends on PCMCIA && PCI
+ help
+ 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
diff -ruN linux/drivers/pcmcia.orig/Makefile
linux/drivers/pcmcia/Makefile
--- linux/drivers/pcmcia.orig/Makefile 2003-12-18 11:59:18.000000000
+0900
+++ linux/drivers/pcmcia/Makefile 2003-12-30 21:38:44.000000000 +0900
@@ -5,6 +5,7 @@
obj-$(CONFIG_PCMCIA) += pcmcia_core.o ds.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
diff -ruN linux/drivers/pcmcia.orig/pd6729.c
linux/drivers/pcmcia/pd6729.c
--- linux/drivers/pcmcia.orig/pd6729.c 1970-01-01 09:00:00.000000000
+0900
+++ linux/drivers/pcmcia/pd6729.c 2003-12-31 09:15:52.243963080 +0900
@@ -0,0 +1,756 @@
+/*
+ * Driver for the Cirrus PD6729 PCI-PCMCIA bridge.
+ *
+ * Based on the i82092.c driver.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/config.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/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "pd6729.h"
+#include "i82365.h"
+#include "cirrus.h"
+
+MODULE_LICENSE("GPL");
+
+/* PCI core routines */
+static struct pci_device_id pd6729_pci_ids[] = {
+ {
+ .vendor = PCI_VENDOR_ID_CIRRUS,
+ .device = PCI_DEVICE_ID_CIRRUS_6729,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(pci, pd6729_pci_ids);
+
+static int pd6729_socket_suspend (struct pci_dev *dev, u32 state)
+{
+ return pcmcia_socket_dev_suspend(&dev->dev, state);
+}
+
+static int pd6729_socket_resume (struct pci_dev *dev)
+{
+ return pcmcia_socket_dev_resume(&dev->dev);
+}
+
+static struct pci_driver pd6729_pci_drv = {
+ .name = "pd6729",
+ .id_table = pd6729_pci_ids,
+ .probe = pd6729_pci_probe,
+ .remove = __devexit_p(pd6729_pci_remove),
+ .suspend = pd6729_socket_suspend,
+ .resume = pd6729_socket_resume,
+};
+
+
+/* the pccard structure and its functions */
+static struct pccard_operations pd6729_operations = {
+ .init = pd6729_init,
+ .suspend = pd6729_suspend,
+ .get_status = pd6729_get_status,
+ .get_socket = pd6729_get_socket,
+ .set_socket = pd6729_set_socket,
+ .set_io_map = pd6729_set_io_map,
+ .set_mem_map = pd6729_set_mem_map,
+};
+
+/* The card can do upto 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 */
+ 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 __devinit pd6729_pci_probe(struct pci_dev *dev, const struct
pci_device_id *id)
+{
+ int i, ret;
+ char configbyte;
+
+ if ((ret = pci_enable_device(dev)))
+ return ret;
+
+ socket_count = 2;
+ printk(KERN_INFO "pd6729: Cirrus PD6729 PCI to PCMCIA Bridge.\n");
+ printk(KERN_INFO "pd6729: configured as a %d socket device.\n",
socket_count);
+ /* Since we have no memory BARs some firmware we may not
+ have had PCI_COMMAND_MEM enabled, yet the device needs
+ it. */
+ pci_read_config_byte(dev, PCI_COMMAND, &configbyte);
+ if (!(configbyte & PCI_COMMAND_MEMORY)) {
+ printk(KERN_DEBUG "pd6729: Enabling PCI_COMMAND_MEMORY.\n");
+ configbyte |= PCI_COMMAND_MEMORY;
+ pci_write_config_byte(dev, PCI_COMMAND, configbyte);
+ }
+
+ if (pci_request_regions(dev, "pd6729")) {
+ 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].socket.features |= SS_CAP_PAGE_REGS | 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.owner = THIS_MODULE;
+
+ sockets[i].number = i;
+
+ if (card_present(i)) {
+ sockets[i].card_state = 3;
+ dprintk(KERN_DEBUG "pd6729: slot %i is occupied\n",i);
+ } else {
+ dprintk(KERN_DEBUG "pd6729: slot %i is vacant\n",i);
+ }
+ }
+
+ /* Register the interrupt handler */
+ dprintk(KERN_DEBUG "Requesting interrupt %i \n",dev->irq);
+ if ((ret = request_irq(dev->irq, pd6729_interrupt, SA_SHIRQ, "pd6729",
pd6729_interrupt))) {
+ printk(KERN_ERR "pd6729: Failed to register IRQ %d, aborting\n",
dev->irq);
+ goto err_out_free_res;
+ }
+
+ pci_set_drvdata(dev, &sockets[i].socket);
+
+ for (i = 0; i<socket_count; i++) {
+ sockets[i].socket.dev.dev = &dev->dev;
+ sockets[i].socket.ops = &pd6729_operations;
+ 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, pd6729_interrupt);
+err_out_free_res:
+ pci_release_regions(dev);
+err_out_disable:
+ pci_disable_device(dev);
+ return ret;
+}
+
+static void __devexit pd6729_pci_remove(struct pci_dev *dev)
+{
+ struct pcmcia_socket *socket = pci_get_drvdata(dev);
+
+ free_irq(dev->irq, pd6729_interrupt);
+
+ if (socket)
+ pcmcia_unregister_socket(socket);
+}
+
+static spinlock_t port_lock = SPIN_LOCK_UNLOCKED;
+
+/* 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 unsigned short indirect_read16(int socket, unsigned short reg)
+{
+ unsigned short int port;
+ unsigned short tmp;
+ unsigned long flags;
+ spin_lock_irqsave(&port_lock,flags);
+ reg = reg + socket * 0x40;
+ port = sockets[socket].io_base;
+ outb(reg,port);
+ tmp = inb(port+1);
+ reg++;
+ outb(reg,port);
+ tmp = tmp | (inb(port+1)<<8);
+ spin_unlock_irqrestore(&port_lock,flags);
+ return tmp;
+}
+
+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 pd6729_interrupt(int irq, void *dev, struct pt_regs
*regs)
+{
+ int i;
+ int loopcount = 0;
+ int handled = 0;
+
+ unsigned int events, active=0;
+
+ while (1) {
+ loopcount++;
+ if (loopcount>20) {
+ printk(KERN_ERR "pd6729: infinite eventloop in interrupt \n");
+ break;
+ }
+
+ active = 0;
+
+ for (i=0;i<socket_count;i++) {
+ int csc;
+ if (sockets[i].card_state==0) /* Inactive socket, should not happen
*/
+ continue;
+
+ csc = indirect_read(i,I365_CSC); /* card status change register */
+
+ if (csc==0) /* no events on this socket */
+ continue;
+ handled = 1;
+ events = 0;
+
+ if (csc & I365_CSC_DETECT) {
+ events |= SS_DETECT;
+ dprintk("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" */
+ events |= (csc & I365_CSC_STSCHG) ? SS_STSCHG : 0;
+ } else {
+ /* Check for battery/ready events */
+ events |= (csc & I365_CSC_BVD1) ? SS_BATDEAD : 0;
+ events |= (csc & I365_CSC_BVD2) ? SS_BATWARN : 0;
+ events |= (csc & I365_CSC_READY) ? SS_READY : 0;
+ }
+
+ 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) {
+ dprintk("card_present 1");
+ return 1;
+ }
+
+ dprintk("card_present 0");
+ 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 pd6729_init(struct pcmcia_socket *sock)
+{
+ int i;
+ pccard_io_map io = { 0, 0, 0, 0, 1 };
+ pccard_mem_map mem = { 0, 0, 0, 0, 0, 0 };
+
+ mem.sys_stop = 0x0fff;
+ pd6729_set_socket(sock, &dead_socket);
+ for (i = 0; i < 2; i++) {
+ io.map = i;
+ pd6729_set_io_map(sock, &io);
+ }
+ for (i = 0; i < 5; i++) {
+ mem.map = i;
+ pd6729_set_mem_map(sock, &mem);
+ }
+
+ return 0;
+}
+
+static int pd6729_suspend(struct pcmcia_socket *sock)
+{
+ int retval;
+ retval = pd6729_set_socket(sock, &dead_socket);
+ return retval;
+}
+
+static int pd6729_get_status(struct pcmcia_socket *socket, u_int
*value)
+{
+ unsigned int sock = container_of(socket, struct socket_info,
socket)->number;
+ unsigned int status;
+ unsigned int data, t;
+
+ status = indirect_read(sock,I365_STATUS); /* Interface Status Register
*/
+ *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 */
+
+ t = (sock) ? sock : sock+1;
+ indirect_write(t, PD67_EXT_INDEX, PD67_EXTERN_DATA);
+ data = indirect_read16(t, PD67_EXT_DATA);
+ *value |= (data & PD67_EXD_VS1(sock)) ? 0 : SS_3VCARD; /* 3.3V card */
+
+ return 0;
+}
+
+
+static int pd6729_get_socket(struct pcmcia_socket *socket,
socket_state_t *state)
+{
+ unsigned int sock = container_of(socket, struct socket_info,
socket)->number;
+ unsigned char reg,vcc,vpp;
+
+ state->flags = 0;
+ state->Vcc = 0;
+ state->Vpp = 0;
+ state->io_irq = 0;
+ state->csc_mask = 0;
+
+ /* First the power status of the socket */
+ reg = indirect_read(sock,I365_POWER); /* PCTRL - Power Control
Register */
+
+ if (reg & I365_PWR_AUTO)
+ state->flags |= SS_PWR_AUTO; /* Automatic Power Switch */
+
+ if (reg & I365_PWR_OUT)
+ state->flags |= SS_OUTPUT_ENA; /* Output signals are enabled */
+
+ vcc = reg & I365_VCC_MASK; vpp = reg & I365_VPP1_MASK;
+
+ if (reg & I365_VCC_5V) {
+ state->Vcc = (indirect_read(sock, PD67_MISC_CTL_1) &
+ PD67_MC1_VCC_3V) ? 33 : 50;
+
+ if (vpp == I365_VPP1_5V) {
+ if (state->Vcc == 50) state->Vpp = 50;
+ else state->Vpp = 33;
+ }
+ if (vpp == I365_VPP1_12V)
+ state->Vpp = 120;
+
+ }
+
+ /* Now the IO card, RESET flags and IO interrupt */
+
+ reg = indirect_read(sock, I365_INTCTL); /* IGENC, Interrupt and
General Control */
+
+ if ((reg & I365_PC_RESET)==0)
+ state->flags |= SS_RESET;
+ if (reg & I365_PC_IOCARD)
+ state->flags |= SS_IOCARD; /* This is an IO card */
+
+ /* Set the IRQ number */
+ if (sockets[sock].dev!=NULL)
+ state->io_irq = sockets[sock].dev->irq;
+
+ /* Card status change */
+ reg = indirect_read(sock, I365_CSCINT); /* CSCICR, Card Status Change
Interrupt Configuration */
+
+ if (reg & I365_CSC_DETECT)
+ state->csc_mask |= SS_DETECT; /* Card detect is enabled */
+
+ if (state->flags & SS_IOCARD) {/* IO Cards behave different */
+ if (reg & I365_CSC_STSCHG)
+ state->csc_mask |= SS_STSCHG;
+ } else {
+ if (reg & I365_CSC_BVD1)
+ state->csc_mask |= SS_BATDEAD;
+ if (reg & I365_CSC_BVD2)
+ state->csc_mask |= SS_BATWARN;
+ if (reg & I365_CSC_READY)
+ state->csc_mask |= SS_READY;
+ }
+
+ return 0;
+}
+
+static int pd6729_set_socket(struct pcmcia_socket *socket,
socket_state_t *state)
+{
+ unsigned int sock = container_of(socket, struct socket_info,
socket)->number;
+ unsigned char reg;
+
+ /* First, set the global controller options */
+
+ set_bridge_state(sock);
+
+ /* Values for the IGENC register */
+
+ reg = 0;
+ if (!(state->flags & SS_RESET)) /* The reset bit has "inverse" logic
*/
+ reg = reg | I365_PC_RESET;
+ if (state->flags & SS_IOCARD)
+ reg = reg | I365_PC_IOCARD;
+
+ indirect_write(sock,I365_INTCTL,reg); /* IGENC, Interrupt and General
Control Register */
+
+ /* Power registers */
+
+ reg = I365_PWR_NORESET; /* default: disable resetdrv on resume */
+
+ if (state->flags & SS_PWR_AUTO) {
+ dprintk("Auto power\n");
+ reg |= I365_PWR_AUTO; /* automatic power mngmnt */
+ }
+ if (state->flags & SS_OUTPUT_ENA) {
+ dprintk("Power Enabled \n");
+ reg |= I365_PWR_OUT; /* enable power */
+ }
+
+ switch (state->Vcc) {
+ case 0:
+ break;
+ case 33:
+ dprintk("setting voltage to Vcc to 3.3V on socket %i\n",sock);
+ reg |= I365_VCC_5V;
+ indirect_setbit(sock,PD67_MISC_CTL_1,PD67_MC1_VCC_3V);
+ break;
+ case 50:
+ dprintk("setting voltage to Vcc to 5V on socket %i\n",sock);
+ reg |= I365_VCC_5V;
+ indirect_resetbit(sock,PD67_MISC_CTL_1,PD67_MC1_VCC_3V);
+ break;
+ default:
+ dprintk("pd6729: pd6729_set_socket called with invalid VCC power
value: %i ", state->Vcc);
+ return -EINVAL;
+ }
+
+ switch (state->Vpp) {
+ case 0:
+ dprintk("not setting Vpp on socket %i\n",sock);
+ break;
+ case 33:
+ case 50:
+ dprintk("setting Vpp to Vcc for socket %i\n",sock);
+ reg |= I365_VPP1_5V;
+ break;
+ case 120:
+ dprintk("setting Vpp to 12.0\n");
+ reg |= I365_VPP1_12V;
+ break;
+ default:
+ dprintk("pd6729: pd6729_set_socket called with invalid VPP power
value: %i ", state->Vpp);
+ return -EINVAL;
+ }
+
+ if (reg != indirect_read(sock,I365_POWER)) /* only write if changed */
+ indirect_write(sock,I365_POWER,reg);
+
+ /* Now, specifiy that all interrupts are to be done as PCI interrupts
*/
+ indirect_write(sock, PD67_EXT_INDEX, PD67_EXT_CTL_1);
+ indirect_write(sock, PD67_EXT_DATA, PD67_EC1_INV_MGMT_IRQ |
PD67_EC1_INV_CARD_IRQ);
+
+ /* 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;
+ }
+ reg |= 0x30; /* management IRQ: PCI INTA# = "irq 3" */
+ indirect_write(sock,I365_CSCINT,reg);
+
+ reg = indirect_read(sock,I365_INTCTL);
+ reg |= 0x03; /* card IRQ: PCI INTA# = "irq 3" */
+ indirect_write(sock,I365_INTCTL,reg);
+
+ /* now clear the (probably bogus) pending stuff by doing a dummy
read*/
+ (void)indirect_read(sock,I365_CSC);
+
+ return 0;
+}
+
+static int pd6729_set_io_map(struct pcmcia_socket *socket, struct
pccard_io_map *io)
+{
+ unsigned int sock = container_of(socket, struct socket_info,
socket)->number;
+ unsigned char map, ioctl;
+
+ map = io->map;
+
+ /* Check error conditions */
+ if (map > 1) {
+ dprintk("pd6729_set_io_map with invalid map");
+ return -EINVAL;
+ }
+ if ((io->start > 0xffff) || (io->stop > 0xffff) || (io->stop <
io->start)){
+ dprintk("pd6729_set_io_map with invalid io");
+ 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));
+
+/* printk("set_io_map: Setting range to %x - %x
\n",io->start,io->stop); */
+
+ /* 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_0WS) ioctl |= I365_IOCTL_0WS(map);
+ if (io->flags & MAP_16BIT) ioctl |= I365_IOCTL_16BIT(map);
+ if (io->flags & MAP_AUTOSZ) ioctl |= I365_IOCTL_IOCS16(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 pd6729_set_mem_map(struct pcmcia_socket *socket, struct
pccard_mem_map *mem)
+{
+ unsigned int sock = container_of(socket, struct socket_info,
socket)->number;
+ unsigned short base, i;
+ unsigned char map;
+
+ map = mem->map;
+ if (map > 4) {
+ printk("pd6729_set_mem_map: invalid map");
+ return -EINVAL;
+ }
+
+ if ( (mem->sys_start > mem->sys_stop) || (mem->speed > 1000) ) {
+ printk("pd6729_set_mem_map: invalid address / speed");
+ printk("invalid mem map for socket %i : %lx to %lx with a start of %x
\n",sock,mem->sys_start, mem->sys_stop, 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));
+
+/* printk("set_mem_map: Setting map %i range to %x - %x on socket %i,
speed is %i, active = %i \n",map,
mem->sys_start,mem->sys_stop,sock,mem->speed,mem->flags & MAP_ACTIVE);
*/
+
+ /* write the start address */
+ base = I365_MEM(map);
+ i = (mem->sys_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= (mem->sys_stop >> 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);
+
+ /* Take care of high byte */
+ indirect_write(sock, PD67_EXT_INDEX, PD67_MEM_PAGE(map));
+ indirect_write(sock, PD67_EXT_DATA, mem->sys_start >> 24);
+
+ /* card start */
+
+ i = ((mem->card_start - mem->sys_start) >> 12) & 0x3fff;
+ if (mem->flags & MAP_WRPROT)
+ i |= I365_MEM_WRPROT;
+ if (mem->flags & MAP_ATTRIB) {
+/* printk("requesting attribute memory for socket %i\n",sock);*/
+ i |= I365_MEM_REG;
+ } else {
+/* printk("requesting normal memory for socket %i\n",sock);*/
+ }
+ 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 pd6729_module_init(void)
+{
+ return pci_module_init (&pd6729_pci_drv);
+}
+
+static void pd6729_module_exit(void)
+{
+ pci_unregister_driver(&pd6729_pci_drv);
+}
+
+module_init(pd6729_module_init);
+module_exit(pd6729_module_exit);
+
diff -ruN linux/drivers/pcmcia.orig/pd6729.h
linux/drivers/pcmcia/pd6729.h
--- linux/drivers/pcmcia.orig/pd6729.h 1970-01-01 09:00:00.000000000
+0900
+++ linux/drivers/pcmcia/pd6729.h 2003-12-30 21:38:44.000000000 +0900
@@ -0,0 +1,42 @@
+#ifndef _INCLUDE_GUARD_PD6729_H_
+#define _INCLUDE_GUARD_PD6729_H_
+
+#include <linux/interrupt.h>
+
+
+/* Debuging defines */
+#ifdef NOTRACE
+#define enter(x) printk("Enter: %s, %s line
%i\n",x,__FILE__,__LINE__)
+#define leave(x) printk("Leave: %s, %s line
%i\n",x,__FILE__,__LINE__)
+#define dprintk(fmt, args...) printk(fmt , ## args)
+#else
+#define enter(x) do {} while (0)
+#define leave(x) do {} while (0)
+#define dprintk(fmt, args...) do {} while (0)
+#endif
+
+
+/* Flags for I365_GENCTL */
+#define I365_DF_VS1 0x40 /* DF-step Voltage Sense */
+#define I365_DF_VS2 0x80
+
+/* Fields in PD67_EXTERN_DATA */
+#define PD67_EXD_VS1(s) (0x01 << ((s)<<1))
+#define PD67_EXD_VS2(s) (0x02 << ((s)<<1))
+
+/* prototypes */
+
+static int pd6729_pci_probe(struct pci_dev *dev, const struct
pci_device_id *id);
+static void pd6729_pci_remove(struct pci_dev *dev);
+static int card_present(int socketno);
+static irqreturn_t pd6729_interrupt(int irq, void *dev, struct pt_regs
*regs);
+static int pd6729_get_status(struct pcmcia_socket *socket, u_int
*value);
+static int pd6729_get_socket(struct pcmcia_socket *socket,
socket_state_t *state);
+static int pd6729_set_socket(struct pcmcia_socket *socket,
socket_state_t *state);
+static int pd6729_set_io_map(struct pcmcia_socket *socket, struct
pccard_io_map *io);
+static int pd6729_set_mem_map(struct pcmcia_socket *socket, struct
pccard_mem_map *mem);
+static int pd6729_init(struct pcmcia_socket *socket);
+static int pd6729_suspend(struct pcmcia_socket *socket);
+
+#endif
+
next reply other threads:[~2004-01-11 11:17 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-01-11 11:16 Komuro [this message]
2004-01-11 11:50 ` [PATCH 2.6.0] Cirrus PD6729 PCI-to-PCMCIA Bridge support for 2.6.x kernel Arjan van de Ven
2004-01-11 11:52 ` Arjan van de Ven
[not found] ` <000f01c3d8a3$d23eb660$6c24dbdc@HQA02330>
2004-01-12 2:26 ` [PATCH 2.6.0] Cirrus PD6729 PCI-to-PCMCIA Bridge support for2.6.x kernel Komuro
2004-02-01 8:39 ` Komuro
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1073819401.2329.7.camel@localhost.localdomain \
--to=komujun@nifty.com \
--cc=majordomo@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.