lkml.org 
[lkml]   [2004]   [Feb]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patches in this message
    /
    SubjectRe: [PATCH 2.6.0] Cirrus PD6729 PCI-to-PCMCIA Bridge support for2.6.x kernel
    From
    Date
    Dear all

    I updated the pd6729 driver for 2.6.x.

    *pd6729_pci_remove => remove resources properly.

    Please see the following patch.

    Best Regards
    Komuro



    diff -ruN linux/drivers/pcmcia.orig/Kconfig linux/drivers/pcmcia/Kconfig
    --- linux/drivers/pcmcia.orig/Kconfig 2004-01-09 15:59:48.000000000
    +0900
    +++ linux/drivers/pcmcia/Kconfig 2004-01-13 21:28:09.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 2004-01-09 15:59:55.000000000
    +0900
    +++ linux/drivers/pcmcia/Makefile 2004-01-13 21:28:09.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 2004-02-01 11:40:35.893397648 +0900
    @@ -0,0 +1,759 @@
    +/*
    + * Driver for the Cirrus PD6729 PCI-PCMCIA bridge.
    + *
    + * Based on the i82092.c driver.
    + *
    + * This software may be used and distributed according to the terms of
    + * the GNU General Public License, incorporated herein by reference.
    + */
    +
    +#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)
    +{
    + int i;
    +
    + for (i = socket_count-1; i >=0 ; i--)
    + pcmcia_unregister_socket(&sockets[i].socket);
    +
    + free_irq(dev->irq, pd6729_interrupt);
    + pci_release_regions(dev);
    +}
    +
    +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 2004-01-13 21:28:09.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
    +


    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2005-03-22 14:00    [W:0.076 / U:0.388 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site