mirror of
https://github.com/opnsense/src.git
synced 2026-06-10 09:11:07 -04:00
Andrew McRae's pcmcia/pccard code, the kernel part.
This is still very green, but I have managed to get my modem working. Lots of work still to do, but now at least we can commit it. /phk Reviewed by: phk Submitted by: Andrew McRae <andrew@mega.com.au>
This commit is contained in:
parent
07b1c6b3c9
commit
0d2966d3f2
11 changed files with 3102 additions and 3 deletions
|
|
@ -31,7 +31,7 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
|
||||
* $Id: sio.c,v 1.109 1995/07/31 21:10:36 bde Exp $
|
||||
* $Id: sio.c,v 1.110 1995/08/13 07:49:35 bde Exp $
|
||||
*/
|
||||
|
||||
#include "sio.h"
|
||||
|
|
@ -41,6 +41,9 @@
|
|||
* Mostly rewritten to use pseudo-DMA.
|
||||
* Works for National Semiconductor NS8250-NS16550AF UARTs.
|
||||
* COM driver, based on HP dca driver.
|
||||
*
|
||||
* Changes for PC-Card integration:
|
||||
* - Added PC-Card driver table and handlers
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
|
@ -93,6 +96,12 @@
|
|||
|
||||
#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
|
||||
|
||||
#include "crd.h"
|
||||
#if NCRD > 0
|
||||
#include <pccard/card.h>
|
||||
#include <pccard/slot.h>
|
||||
#endif /* NCRD > 0 */
|
||||
|
||||
/*
|
||||
* Input buffer watermarks.
|
||||
* The external device is asked to stop sending when the buffer exactly reaches
|
||||
|
|
@ -351,6 +360,103 @@ static struct kern_devconf kdc_sio[NSIO] = { {
|
|||
"RS-232 serial port",
|
||||
DC_CLS_SERIAL /* class */
|
||||
} };
|
||||
#if NCRD > 0
|
||||
/*
|
||||
* PC-Card (PCMCIA) specific code.
|
||||
*/
|
||||
static int card_intr(struct pccard_dev *); /* Interrupt handler */
|
||||
void siounload(struct pccard_dev *); /* Disable driver */
|
||||
void siosuspend(struct pccard_dev *); /* Suspend driver */
|
||||
static int sioinit(struct pccard_dev *, int); /* init device */
|
||||
|
||||
static struct pccard_drv sio_info =
|
||||
{
|
||||
"sio",
|
||||
card_intr,
|
||||
siounload,
|
||||
siosuspend,
|
||||
sioinit,
|
||||
0, /* Attributes - presently unused */
|
||||
&tty_imask /* Interrupt mask for device */
|
||||
/* This should also include net_imask?? */
|
||||
};
|
||||
/*
|
||||
* Called when a power down is wanted. Shuts down the
|
||||
* device and configures the device as unavailable (but
|
||||
* still loaded...). A resume is done by calling
|
||||
* sioinit with first=0. This is called when the user suspends
|
||||
* the system, or the APM code suspends the system.
|
||||
*/
|
||||
void
|
||||
siosuspend(struct pccard_dev *dp)
|
||||
{
|
||||
printf("sio%d: suspending\n", dp->isahd.id_unit);
|
||||
}
|
||||
/*
|
||||
* Initialize the device - called from Slot manager.
|
||||
* if first is set, then initially check for
|
||||
* the device's existence before initialising it.
|
||||
* Once initialised, the device table may be set up.
|
||||
*/
|
||||
int
|
||||
sioinit(struct pccard_dev *dp, int first)
|
||||
{
|
||||
/*
|
||||
* validate unit number.
|
||||
*/
|
||||
if (first)
|
||||
{
|
||||
if (dp->isahd.id_unit >= NSIO)
|
||||
return(ENODEV);
|
||||
/*
|
||||
* Make sure it isn't already probed.
|
||||
*/
|
||||
if (com_addr(dp->isahd.id_unit))
|
||||
return(EBUSY);
|
||||
/*
|
||||
* Probe the device. If a value is returned, the
|
||||
* device was found at the location.
|
||||
*/
|
||||
if (sioprobe(&dp->isahd)==0)
|
||||
return(ENXIO);
|
||||
if (sioattach(&dp->isahd)==0)
|
||||
return(ENXIO);
|
||||
}
|
||||
/*
|
||||
* XXX TODO:
|
||||
* If it was already inited before, the device structure
|
||||
* should be already initialised. Here we should
|
||||
* reset (and possibly restart) the hardware, but
|
||||
* I am not sure of the best way to do this...
|
||||
*/
|
||||
return(0);
|
||||
}
|
||||
/*
|
||||
* siounload - unload the driver and clear the table.
|
||||
* XXX TODO:
|
||||
* This is called usually when the card is ejected, but
|
||||
* can be caused by the modunload of a controller driver.
|
||||
* The idea is reset the driver's view of the device
|
||||
* and ensure that any driver entry points such as
|
||||
* read and write do not hang.
|
||||
*/
|
||||
void
|
||||
siounload(struct pccard_dev *dp)
|
||||
{
|
||||
printf("sio%d: unload\n", dp->isahd.id_unit);
|
||||
}
|
||||
|
||||
/*
|
||||
* card_intr - Shared interrupt called from
|
||||
* front end of PC-Card handler.
|
||||
*/
|
||||
static int
|
||||
card_intr(struct pccard_dev *dp)
|
||||
{
|
||||
siointr1(com_addr(dp->isahd.id_unit));
|
||||
return(1);
|
||||
}
|
||||
#endif /* NCRD > 0 */
|
||||
|
||||
static void
|
||||
sioregisterdev(id)
|
||||
|
|
@ -359,6 +465,11 @@ sioregisterdev(id)
|
|||
int unit;
|
||||
|
||||
unit = id->id_unit;
|
||||
/*
|
||||
* If already registered, don't try to re-register.
|
||||
*/
|
||||
if (kdc_sio[unit].kdc_isa)
|
||||
return;
|
||||
if (unit != 0)
|
||||
kdc_sio[unit] = kdc_sio[0];
|
||||
kdc_sio[unit].kdc_unit = unit;
|
||||
|
|
@ -393,6 +504,13 @@ sioprobe(dev)
|
|||
/ sizeof likely_com_ports[0]];
|
||||
++com_ptr)
|
||||
outb(*com_ptr + com_mcr, 0);
|
||||
#if NCRD > 0
|
||||
/*
|
||||
* If PC-Card probe required, then register driver with
|
||||
* slot manager.
|
||||
*/
|
||||
pccard_add_driver(&sio_info);
|
||||
#endif /* NCRD > 0 */
|
||||
already_init = TRUE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
|
||||
* $Id: sio.c,v 1.109 1995/07/31 21:10:36 bde Exp $
|
||||
* $Id: sio.c,v 1.110 1995/08/13 07:49:35 bde Exp $
|
||||
*/
|
||||
|
||||
#include "sio.h"
|
||||
|
|
@ -41,6 +41,9 @@
|
|||
* Mostly rewritten to use pseudo-DMA.
|
||||
* Works for National Semiconductor NS8250-NS16550AF UARTs.
|
||||
* COM driver, based on HP dca driver.
|
||||
*
|
||||
* Changes for PC-Card integration:
|
||||
* - Added PC-Card driver table and handlers
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
|
@ -93,6 +96,12 @@
|
|||
|
||||
#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
|
||||
|
||||
#include "crd.h"
|
||||
#if NCRD > 0
|
||||
#include <pccard/card.h>
|
||||
#include <pccard/slot.h>
|
||||
#endif /* NCRD > 0 */
|
||||
|
||||
/*
|
||||
* Input buffer watermarks.
|
||||
* The external device is asked to stop sending when the buffer exactly reaches
|
||||
|
|
@ -351,6 +360,103 @@ static struct kern_devconf kdc_sio[NSIO] = { {
|
|||
"RS-232 serial port",
|
||||
DC_CLS_SERIAL /* class */
|
||||
} };
|
||||
#if NCRD > 0
|
||||
/*
|
||||
* PC-Card (PCMCIA) specific code.
|
||||
*/
|
||||
static int card_intr(struct pccard_dev *); /* Interrupt handler */
|
||||
void siounload(struct pccard_dev *); /* Disable driver */
|
||||
void siosuspend(struct pccard_dev *); /* Suspend driver */
|
||||
static int sioinit(struct pccard_dev *, int); /* init device */
|
||||
|
||||
static struct pccard_drv sio_info =
|
||||
{
|
||||
"sio",
|
||||
card_intr,
|
||||
siounload,
|
||||
siosuspend,
|
||||
sioinit,
|
||||
0, /* Attributes - presently unused */
|
||||
&tty_imask /* Interrupt mask for device */
|
||||
/* This should also include net_imask?? */
|
||||
};
|
||||
/*
|
||||
* Called when a power down is wanted. Shuts down the
|
||||
* device and configures the device as unavailable (but
|
||||
* still loaded...). A resume is done by calling
|
||||
* sioinit with first=0. This is called when the user suspends
|
||||
* the system, or the APM code suspends the system.
|
||||
*/
|
||||
void
|
||||
siosuspend(struct pccard_dev *dp)
|
||||
{
|
||||
printf("sio%d: suspending\n", dp->isahd.id_unit);
|
||||
}
|
||||
/*
|
||||
* Initialize the device - called from Slot manager.
|
||||
* if first is set, then initially check for
|
||||
* the device's existence before initialising it.
|
||||
* Once initialised, the device table may be set up.
|
||||
*/
|
||||
int
|
||||
sioinit(struct pccard_dev *dp, int first)
|
||||
{
|
||||
/*
|
||||
* validate unit number.
|
||||
*/
|
||||
if (first)
|
||||
{
|
||||
if (dp->isahd.id_unit >= NSIO)
|
||||
return(ENODEV);
|
||||
/*
|
||||
* Make sure it isn't already probed.
|
||||
*/
|
||||
if (com_addr(dp->isahd.id_unit))
|
||||
return(EBUSY);
|
||||
/*
|
||||
* Probe the device. If a value is returned, the
|
||||
* device was found at the location.
|
||||
*/
|
||||
if (sioprobe(&dp->isahd)==0)
|
||||
return(ENXIO);
|
||||
if (sioattach(&dp->isahd)==0)
|
||||
return(ENXIO);
|
||||
}
|
||||
/*
|
||||
* XXX TODO:
|
||||
* If it was already inited before, the device structure
|
||||
* should be already initialised. Here we should
|
||||
* reset (and possibly restart) the hardware, but
|
||||
* I am not sure of the best way to do this...
|
||||
*/
|
||||
return(0);
|
||||
}
|
||||
/*
|
||||
* siounload - unload the driver and clear the table.
|
||||
* XXX TODO:
|
||||
* This is called usually when the card is ejected, but
|
||||
* can be caused by the modunload of a controller driver.
|
||||
* The idea is reset the driver's view of the device
|
||||
* and ensure that any driver entry points such as
|
||||
* read and write do not hang.
|
||||
*/
|
||||
void
|
||||
siounload(struct pccard_dev *dp)
|
||||
{
|
||||
printf("sio%d: unload\n", dp->isahd.id_unit);
|
||||
}
|
||||
|
||||
/*
|
||||
* card_intr - Shared interrupt called from
|
||||
* front end of PC-Card handler.
|
||||
*/
|
||||
static int
|
||||
card_intr(struct pccard_dev *dp)
|
||||
{
|
||||
siointr1(com_addr(dp->isahd.id_unit));
|
||||
return(1);
|
||||
}
|
||||
#endif /* NCRD > 0 */
|
||||
|
||||
static void
|
||||
sioregisterdev(id)
|
||||
|
|
@ -359,6 +465,11 @@ sioregisterdev(id)
|
|||
int unit;
|
||||
|
||||
unit = id->id_unit;
|
||||
/*
|
||||
* If already registered, don't try to re-register.
|
||||
*/
|
||||
if (kdc_sio[unit].kdc_isa)
|
||||
return;
|
||||
if (unit != 0)
|
||||
kdc_sio[unit] = kdc_sio[0];
|
||||
kdc_sio[unit].kdc_unit = unit;
|
||||
|
|
@ -393,6 +504,13 @@ sioprobe(dev)
|
|||
/ sizeof likely_com_ports[0]];
|
||||
++com_ptr)
|
||||
outb(*com_ptr + com_mcr, 0);
|
||||
#if NCRD > 0
|
||||
/*
|
||||
* If PC-Card probe required, then register driver with
|
||||
* slot manager.
|
||||
*/
|
||||
pccard_add_driver(&sio_info);
|
||||
#endif /* NCRD > 0 */
|
||||
already_init = TRUE;
|
||||
}
|
||||
|
||||
|
|
|
|||
120
sys/isa/sio.c
120
sys/isa/sio.c
|
|
@ -31,7 +31,7 @@
|
|||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)com.c 7.5 (Berkeley) 5/16/91
|
||||
* $Id: sio.c,v 1.109 1995/07/31 21:10:36 bde Exp $
|
||||
* $Id: sio.c,v 1.110 1995/08/13 07:49:35 bde Exp $
|
||||
*/
|
||||
|
||||
#include "sio.h"
|
||||
|
|
@ -41,6 +41,9 @@
|
|||
* Mostly rewritten to use pseudo-DMA.
|
||||
* Works for National Semiconductor NS8250-NS16550AF UARTs.
|
||||
* COM driver, based on HP dca driver.
|
||||
*
|
||||
* Changes for PC-Card integration:
|
||||
* - Added PC-Card driver table and handlers
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
|
|
@ -93,6 +96,12 @@
|
|||
|
||||
#define com_scr 7 /* scratch register for 16450-16550 (R/W) */
|
||||
|
||||
#include "crd.h"
|
||||
#if NCRD > 0
|
||||
#include <pccard/card.h>
|
||||
#include <pccard/slot.h>
|
||||
#endif /* NCRD > 0 */
|
||||
|
||||
/*
|
||||
* Input buffer watermarks.
|
||||
* The external device is asked to stop sending when the buffer exactly reaches
|
||||
|
|
@ -351,6 +360,103 @@ static struct kern_devconf kdc_sio[NSIO] = { {
|
|||
"RS-232 serial port",
|
||||
DC_CLS_SERIAL /* class */
|
||||
} };
|
||||
#if NCRD > 0
|
||||
/*
|
||||
* PC-Card (PCMCIA) specific code.
|
||||
*/
|
||||
static int card_intr(struct pccard_dev *); /* Interrupt handler */
|
||||
void siounload(struct pccard_dev *); /* Disable driver */
|
||||
void siosuspend(struct pccard_dev *); /* Suspend driver */
|
||||
static int sioinit(struct pccard_dev *, int); /* init device */
|
||||
|
||||
static struct pccard_drv sio_info =
|
||||
{
|
||||
"sio",
|
||||
card_intr,
|
||||
siounload,
|
||||
siosuspend,
|
||||
sioinit,
|
||||
0, /* Attributes - presently unused */
|
||||
&tty_imask /* Interrupt mask for device */
|
||||
/* This should also include net_imask?? */
|
||||
};
|
||||
/*
|
||||
* Called when a power down is wanted. Shuts down the
|
||||
* device and configures the device as unavailable (but
|
||||
* still loaded...). A resume is done by calling
|
||||
* sioinit with first=0. This is called when the user suspends
|
||||
* the system, or the APM code suspends the system.
|
||||
*/
|
||||
void
|
||||
siosuspend(struct pccard_dev *dp)
|
||||
{
|
||||
printf("sio%d: suspending\n", dp->isahd.id_unit);
|
||||
}
|
||||
/*
|
||||
* Initialize the device - called from Slot manager.
|
||||
* if first is set, then initially check for
|
||||
* the device's existence before initialising it.
|
||||
* Once initialised, the device table may be set up.
|
||||
*/
|
||||
int
|
||||
sioinit(struct pccard_dev *dp, int first)
|
||||
{
|
||||
/*
|
||||
* validate unit number.
|
||||
*/
|
||||
if (first)
|
||||
{
|
||||
if (dp->isahd.id_unit >= NSIO)
|
||||
return(ENODEV);
|
||||
/*
|
||||
* Make sure it isn't already probed.
|
||||
*/
|
||||
if (com_addr(dp->isahd.id_unit))
|
||||
return(EBUSY);
|
||||
/*
|
||||
* Probe the device. If a value is returned, the
|
||||
* device was found at the location.
|
||||
*/
|
||||
if (sioprobe(&dp->isahd)==0)
|
||||
return(ENXIO);
|
||||
if (sioattach(&dp->isahd)==0)
|
||||
return(ENXIO);
|
||||
}
|
||||
/*
|
||||
* XXX TODO:
|
||||
* If it was already inited before, the device structure
|
||||
* should be already initialised. Here we should
|
||||
* reset (and possibly restart) the hardware, but
|
||||
* I am not sure of the best way to do this...
|
||||
*/
|
||||
return(0);
|
||||
}
|
||||
/*
|
||||
* siounload - unload the driver and clear the table.
|
||||
* XXX TODO:
|
||||
* This is called usually when the card is ejected, but
|
||||
* can be caused by the modunload of a controller driver.
|
||||
* The idea is reset the driver's view of the device
|
||||
* and ensure that any driver entry points such as
|
||||
* read and write do not hang.
|
||||
*/
|
||||
void
|
||||
siounload(struct pccard_dev *dp)
|
||||
{
|
||||
printf("sio%d: unload\n", dp->isahd.id_unit);
|
||||
}
|
||||
|
||||
/*
|
||||
* card_intr - Shared interrupt called from
|
||||
* front end of PC-Card handler.
|
||||
*/
|
||||
static int
|
||||
card_intr(struct pccard_dev *dp)
|
||||
{
|
||||
siointr1(com_addr(dp->isahd.id_unit));
|
||||
return(1);
|
||||
}
|
||||
#endif /* NCRD > 0 */
|
||||
|
||||
static void
|
||||
sioregisterdev(id)
|
||||
|
|
@ -359,6 +465,11 @@ sioregisterdev(id)
|
|||
int unit;
|
||||
|
||||
unit = id->id_unit;
|
||||
/*
|
||||
* If already registered, don't try to re-register.
|
||||
*/
|
||||
if (kdc_sio[unit].kdc_isa)
|
||||
return;
|
||||
if (unit != 0)
|
||||
kdc_sio[unit] = kdc_sio[0];
|
||||
kdc_sio[unit].kdc_unit = unit;
|
||||
|
|
@ -393,6 +504,13 @@ sioprobe(dev)
|
|||
/ sizeof likely_com_ports[0]];
|
||||
++com_ptr)
|
||||
outb(*com_ptr + com_mcr, 0);
|
||||
#if NCRD > 0
|
||||
/*
|
||||
* If PC-Card probe required, then register driver with
|
||||
* slot manager.
|
||||
*/
|
||||
pccard_add_driver(&sio_info);
|
||||
#endif /* NCRD > 0 */
|
||||
already_init = TRUE;
|
||||
}
|
||||
|
||||
|
|
|
|||
134
sys/pccard/card.h
Normal file
134
sys/pccard/card.h
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Include file for PCMCIA user process interface
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 1995 Andrew McRae. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#define PIOCGSTATE _IOR('P', 1, struct slotstate) /* Get slot state */
|
||||
#define PIOCGMEM _IOWR('P', 2, struct mem_desc) /* Get memory map */
|
||||
#define PIOCSMEM _IOW('P', 3, struct mem_desc) /* Set memory map */
|
||||
#define PIOCGIO _IOWR('P', 4, struct io_desc) /* Get I/O map */
|
||||
#define PIOCSIO _IOW('P', 5, struct io_desc) /* Set I/O map */
|
||||
#define PIOCSDRV _IOW('P', 6, struct drv_desc) /* Set driver */
|
||||
#define PIOCRWFLAG _IOW('P', 7, int) /* Set flags for drv use */
|
||||
#define PIOCRWMEM _IOWR('P', 8, unsigned long) /* Set mem for drv use */
|
||||
#define PIOCSPOW _IOW('P', 9, struct power) /* Set power structure */
|
||||
/*
|
||||
* Debug codes.
|
||||
*/
|
||||
#define PIOCGREG _IOWR('P',100, struct pcic_reg) /* get reg */
|
||||
#define PIOCSREG _IOW('P', 101, struct pcic_reg) /* Set reg */
|
||||
|
||||
|
||||
/*
|
||||
* Slot states for PIOCGSTATE
|
||||
*/
|
||||
enum cardstate { noslot, empty, filled };
|
||||
|
||||
/*
|
||||
* Descriptor structure for memory map.
|
||||
*/
|
||||
struct mem_desc
|
||||
{
|
||||
int window; /* Memory map window number (0-4) */
|
||||
int flags; /* Flags - see below */
|
||||
caddr_t start; /* System memory start */
|
||||
int size; /* Size of memory area */
|
||||
unsigned long card; /* Card memory address */
|
||||
};
|
||||
|
||||
#define MDF_16BITS 0x01 /* Memory is 16 bits wide */
|
||||
#define MDF_ZEROWS 0x02 /* Set no wait states for memory */
|
||||
#define MDF_WS0 0x04 /* Wait state flags */
|
||||
#define MDF_WS1 0x08
|
||||
#define MDF_ATTR 0x10 /* Memory is attribute memory */
|
||||
#define MDF_WP 0x20 /* Write protect memory */
|
||||
#define MDF_ACTIVE 0x40 /* Context active (read-only) */
|
||||
|
||||
/*
|
||||
* Descriptor structure for I/O map
|
||||
*/
|
||||
struct io_desc
|
||||
{
|
||||
int window; /* I/O map number (0-1) */
|
||||
int flags; /* Flags - see below */
|
||||
int start; /* I/O port start */
|
||||
int size; /* Number of port addresses */
|
||||
};
|
||||
|
||||
#define IODF_WS 0x01 /* Set wait states for 16 bit I/O access */
|
||||
#define IODF_16BIT 0x02 /* I/O access are 16 bit */
|
||||
#define IODF_CS16 0x04 /* Allow card selection of 16 bit access */
|
||||
#define IODF_ZEROWS 0x08 /* No wait states for 8 bit I/O */
|
||||
#define IODF_ACTIVE 0x10 /* Context active (read-only) */
|
||||
|
||||
/*
|
||||
* Device descriptor for allocation of driver.
|
||||
*/
|
||||
struct drv_desc
|
||||
{
|
||||
char name[16]; /* Driver name */
|
||||
int unit; /* Driver unit number */
|
||||
unsigned long mem; /* Memory address of driver */
|
||||
int memsize; /* Memory size (if used) */
|
||||
int iobase; /* base of I/O ports */
|
||||
int irqmask; /* Interrupt number(s) to allocate */
|
||||
int flags; /* Device flags */
|
||||
};
|
||||
|
||||
struct pcic_reg
|
||||
{
|
||||
unsigned char reg;
|
||||
unsigned char value;
|
||||
};
|
||||
/*
|
||||
* Slot information. Used to read current status of slot.
|
||||
*/
|
||||
struct slotstate
|
||||
{
|
||||
enum cardstate state; /* Current state of slot */
|
||||
int maxmem; /* Max allowed memory windows */
|
||||
int maxio; /* Max allowed I/O windows */
|
||||
int irqs; /* Bitmap of IRQs allowed */
|
||||
int flags; /* Capability flags */
|
||||
};
|
||||
|
||||
/*
|
||||
* The power values are in volts * 10, e.g. 5V is 50, 3.3V is 33.
|
||||
*/
|
||||
struct power
|
||||
{
|
||||
int vcc;
|
||||
int vpp;
|
||||
};
|
||||
|
||||
/*
|
||||
* Other system limits
|
||||
*/
|
||||
#define MAXSLOT 16
|
||||
#define NUM_MEM_WINDOWS 10
|
||||
#define NUM_IO_WINDOWS 6
|
||||
#define CARD_DEVICE "/dev/card%d" /* String for sprintf */
|
||||
134
sys/pccard/cardinfo.h
Normal file
134
sys/pccard/cardinfo.h
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Include file for PCMCIA user process interface
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 1995 Andrew McRae. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#define PIOCGSTATE _IOR('P', 1, struct slotstate) /* Get slot state */
|
||||
#define PIOCGMEM _IOWR('P', 2, struct mem_desc) /* Get memory map */
|
||||
#define PIOCSMEM _IOW('P', 3, struct mem_desc) /* Set memory map */
|
||||
#define PIOCGIO _IOWR('P', 4, struct io_desc) /* Get I/O map */
|
||||
#define PIOCSIO _IOW('P', 5, struct io_desc) /* Set I/O map */
|
||||
#define PIOCSDRV _IOW('P', 6, struct drv_desc) /* Set driver */
|
||||
#define PIOCRWFLAG _IOW('P', 7, int) /* Set flags for drv use */
|
||||
#define PIOCRWMEM _IOWR('P', 8, unsigned long) /* Set mem for drv use */
|
||||
#define PIOCSPOW _IOW('P', 9, struct power) /* Set power structure */
|
||||
/*
|
||||
* Debug codes.
|
||||
*/
|
||||
#define PIOCGREG _IOWR('P',100, struct pcic_reg) /* get reg */
|
||||
#define PIOCSREG _IOW('P', 101, struct pcic_reg) /* Set reg */
|
||||
|
||||
|
||||
/*
|
||||
* Slot states for PIOCGSTATE
|
||||
*/
|
||||
enum cardstate { noslot, empty, filled };
|
||||
|
||||
/*
|
||||
* Descriptor structure for memory map.
|
||||
*/
|
||||
struct mem_desc
|
||||
{
|
||||
int window; /* Memory map window number (0-4) */
|
||||
int flags; /* Flags - see below */
|
||||
caddr_t start; /* System memory start */
|
||||
int size; /* Size of memory area */
|
||||
unsigned long card; /* Card memory address */
|
||||
};
|
||||
|
||||
#define MDF_16BITS 0x01 /* Memory is 16 bits wide */
|
||||
#define MDF_ZEROWS 0x02 /* Set no wait states for memory */
|
||||
#define MDF_WS0 0x04 /* Wait state flags */
|
||||
#define MDF_WS1 0x08
|
||||
#define MDF_ATTR 0x10 /* Memory is attribute memory */
|
||||
#define MDF_WP 0x20 /* Write protect memory */
|
||||
#define MDF_ACTIVE 0x40 /* Context active (read-only) */
|
||||
|
||||
/*
|
||||
* Descriptor structure for I/O map
|
||||
*/
|
||||
struct io_desc
|
||||
{
|
||||
int window; /* I/O map number (0-1) */
|
||||
int flags; /* Flags - see below */
|
||||
int start; /* I/O port start */
|
||||
int size; /* Number of port addresses */
|
||||
};
|
||||
|
||||
#define IODF_WS 0x01 /* Set wait states for 16 bit I/O access */
|
||||
#define IODF_16BIT 0x02 /* I/O access are 16 bit */
|
||||
#define IODF_CS16 0x04 /* Allow card selection of 16 bit access */
|
||||
#define IODF_ZEROWS 0x08 /* No wait states for 8 bit I/O */
|
||||
#define IODF_ACTIVE 0x10 /* Context active (read-only) */
|
||||
|
||||
/*
|
||||
* Device descriptor for allocation of driver.
|
||||
*/
|
||||
struct drv_desc
|
||||
{
|
||||
char name[16]; /* Driver name */
|
||||
int unit; /* Driver unit number */
|
||||
unsigned long mem; /* Memory address of driver */
|
||||
int memsize; /* Memory size (if used) */
|
||||
int iobase; /* base of I/O ports */
|
||||
int irqmask; /* Interrupt number(s) to allocate */
|
||||
int flags; /* Device flags */
|
||||
};
|
||||
|
||||
struct pcic_reg
|
||||
{
|
||||
unsigned char reg;
|
||||
unsigned char value;
|
||||
};
|
||||
/*
|
||||
* Slot information. Used to read current status of slot.
|
||||
*/
|
||||
struct slotstate
|
||||
{
|
||||
enum cardstate state; /* Current state of slot */
|
||||
int maxmem; /* Max allowed memory windows */
|
||||
int maxio; /* Max allowed I/O windows */
|
||||
int irqs; /* Bitmap of IRQs allowed */
|
||||
int flags; /* Capability flags */
|
||||
};
|
||||
|
||||
/*
|
||||
* The power values are in volts * 10, e.g. 5V is 50, 3.3V is 33.
|
||||
*/
|
||||
struct power
|
||||
{
|
||||
int vcc;
|
||||
int vpp;
|
||||
};
|
||||
|
||||
/*
|
||||
* Other system limits
|
||||
*/
|
||||
#define MAXSLOT 16
|
||||
#define NUM_MEM_WINDOWS 10
|
||||
#define NUM_IO_WINDOWS 6
|
||||
#define CARD_DEVICE "/dev/card%d" /* String for sprintf */
|
||||
250
sys/pccard/cis.h
Normal file
250
sys/pccard/cis.h
Normal file
|
|
@ -0,0 +1,250 @@
|
|||
|
||||
/*
|
||||
* PCMCIA card structures and defines.
|
||||
* These defines relate to the user level
|
||||
* structures and card information, not
|
||||
* driver/process communication.
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 1995 Andrew McRae. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Card Information Structure tuples definitions
|
||||
* The structure of a tuple is basically:
|
||||
*
|
||||
* Tuple_code
|
||||
* Tuple_data_length
|
||||
* Tuple_data ...
|
||||
*
|
||||
* Tuples are contiguous in attribute memory, and
|
||||
* are terminated with a 0xFF for the tuple code or
|
||||
* the tuple length.
|
||||
*/
|
||||
#define CIS_NULL 0 /* Empty tuple */
|
||||
#define CIS_MEM_COMMON 0x01 /* Device descriptor, common memory */
|
||||
#define CIS_CHECKSUM 0x10 /* Checksum */
|
||||
#define CIS_LONGLINK_A 0x11 /* Link to Attribute memory */
|
||||
#define CIS_LONGLINK_C 0x12 /* Link to Common memory */
|
||||
#define CIS_LINKTARGET 0x13 /* Linked tuple must start with this. */
|
||||
#define CIS_NOLINK 0x14 /* Assume no common memory link tuple. */
|
||||
#define CIS_INFO_V1 0x15 /* Card info data, version 1 */
|
||||
#define CIS_ALTSTR 0x16 /* Alternate language string tuple. */
|
||||
#define CIS_MEM_ATTR 0x17 /* Device descriptor, Attribute memory */
|
||||
#define CIS_JEDEC_C 0x18 /* JEDEC descr for common memory */
|
||||
#define CIS_JEDEC_A 0x19 /* JEDEC descr for Attribute memory */
|
||||
#define CIS_CONF_MAP 0x1A /* Card Configuration map */
|
||||
#define CIS_CONFIG 0x1B /* Card Configuration entry */
|
||||
#define CIS_DEVICE_OC 0x1C /* Other conditions info - common memory */
|
||||
#define CIS_DEVICE_OA 0x1D /* Other conditions info - attribute memory */
|
||||
#define CIS_DEVICEGEO 0x1E /* Geometry info for common memory */
|
||||
#define CIS_DEVICEGEO_A 0x1F /* Geometry info for attribute memory */
|
||||
#define CIS_MANUF_ID 0x20 /* Card manufacturer's ID */
|
||||
#define CIS_FUNC_ID 0x21 /* Function of card */
|
||||
#define CIS_FUNC_EXT 0x22 /* Functional extension */
|
||||
/*
|
||||
* Data recording format tuples.
|
||||
*/
|
||||
#define CIS_SW_INTERLV 0x23 /* Software interleave */
|
||||
#define CIS_VERS_2 0x40 /* Card info data, version 2 */
|
||||
#define CIS_FORMAT 0x41 /* Memory card format */
|
||||
#define CIS_GEOMETRY 0x42 /* Disk sector layout */
|
||||
#define CIS_BYTEORDER 0x43 /* Byte order of memory data */
|
||||
#define CIS_DATE 0x44 /* Format data/time */
|
||||
#define CIS_BATTERY 0x45 /* Battery replacement date */
|
||||
#define CIS_ORG 0x46 /* Organisation of data on card */
|
||||
#define CIS_END 0xFF /* Termination code */
|
||||
|
||||
/*
|
||||
* Internal tuple definitions.
|
||||
*
|
||||
* Device descriptor for memory (CIS_MEM_ATTR, CIS_MEM_COMMON)
|
||||
*
|
||||
* Byte 1:
|
||||
* 0xF0 - Device type
|
||||
* 0x08 - Write protect switch
|
||||
* 0x07 - Speed index (7 = extended speed)
|
||||
* Byte 2: Extended speed (bit 7 = another follows)
|
||||
* Byte 3: (ignored if 0xFF)
|
||||
* 0xF8 - Addressable units (0's numbered)
|
||||
* 0x07 - Unit size
|
||||
* The three byte sequence is repeated until byte 1 == 0xFF
|
||||
*/
|
||||
|
||||
/*
|
||||
* CIS_INFO_V1 - Version one card information.
|
||||
*
|
||||
* Byte 1: Major version number (should be 4)
|
||||
* Byte 2: Minor version number (should be 1)
|
||||
* Byte 3-x: Null terminated Manufacturer name
|
||||
* Byte x-x: Null terminated product name
|
||||
* Byte x-x: Null terminated additional info 1
|
||||
* Byte x-x: Null terminated additional info 2
|
||||
* Byte x: final byte must be 0xFF
|
||||
*/
|
||||
#define CIS_MAJOR_VERSION 4
|
||||
#define CIS_MINOR_VERSION 1
|
||||
|
||||
/*
|
||||
* CIS_CONF_MAP - Provides an address map for the card
|
||||
* configuration register(s), and a max value
|
||||
* identifying the last configuration tuple.
|
||||
*
|
||||
* Byte 1:
|
||||
* 0x3C - Register mask size (0's numbered)
|
||||
* 0x03 - Register address size (0's numbered)
|
||||
* Byte 2:
|
||||
* 0x3F - ID of last configuration.
|
||||
* Byte 3-n: Card register address (size is determined by
|
||||
* the value in byte 1).
|
||||
* Byte x-x: Card register masks (size determined by the
|
||||
* value in byte 1)
|
||||
*/
|
||||
|
||||
/*
|
||||
* CIS_CONFIG - Card configuration entry. Multiple tuples may
|
||||
* exist of this type, each one describing a different
|
||||
* memory/I-O map that can be used to address this card.
|
||||
* The first one usually has extra config data about the
|
||||
* card features. The final configuration tuple number
|
||||
* is stored in the CIS_CONF_MAP tuple so that the complete
|
||||
* list can be scanned.
|
||||
*
|
||||
* Byte 1:
|
||||
* 0x3F - Configuration ID number.
|
||||
* 0x40 - Indicates this is the default configuration
|
||||
* 0x80 - Interface byte exists
|
||||
* Byte 2: (exists only if bit 0x80 set in byte 1)
|
||||
* 0x0F - Interface type value
|
||||
* 0x10 - Battery voltage detect
|
||||
* 0x20 - Write protect active
|
||||
* 0x40 - RdyBsy active bit
|
||||
* 0x80 - Wait signal required
|
||||
* Byte 3: (features byte)
|
||||
* 0x03 - Power sub-tuple(s) exists
|
||||
* 0x04 - Timing sub-tuple exists
|
||||
* 0x08 - I/O space sub-tuple exists
|
||||
* 0x10 - IRQ sub-tuple exists
|
||||
* 0x60 - Memory space sub-tuple(s) exists
|
||||
* 0x80 - Miscellaneous sub-tuple exists
|
||||
*/
|
||||
#define CIS_FEAT_POWER(x) ((x) & 0x3)
|
||||
#define CIS_FEAT_TIMING 0x4
|
||||
#define CIS_FEAT_I_O 0x8
|
||||
#define CIS_FEAT_IRQ 0x10
|
||||
#define CIS_FEAT_MEMORY(x) (((x) >> 5) & 0x3)
|
||||
#define CIS_FEAT_MISC 0x80
|
||||
/*
|
||||
* Depending on whether the "features" byte has the corresponding
|
||||
* bit set, a number of sub-tuples follow. Some features have
|
||||
* more than one sub-tuple, depending on the count within the
|
||||
* features byte (e.g power feature bits allows up to 3 sub-tuples).
|
||||
*
|
||||
* Power structure sub-tuple:
|
||||
* Byte 1: parameter exists - Each bit (starting from 0x01) indicates
|
||||
* that a parameter block exists - up to 8 parameter blocks
|
||||
* are therefore allowed).
|
||||
* Byte 2:
|
||||
* 0x7F - Parameter data
|
||||
* 0x80 - More bytes follow (0 = last byte)
|
||||
*
|
||||
* Timing sub-tuple
|
||||
* Byte 1:
|
||||
* 0x03 - Wait scale
|
||||
* 0x1C - Ready scale
|
||||
* 0xE0 - Reserved scale
|
||||
* Byte 2: extended wait scale if wait scale != 3
|
||||
* Byte 3: extended ready scale if ready scale != 7
|
||||
* Byte 4: extended reserved scale if reserved scale != 7
|
||||
*/
|
||||
#define CIS_WAIT_SCALE(x) ((x) & 0x3)
|
||||
#define CIS_READY_SCALE(x) (((x)>>2) & 0x7)
|
||||
#define CIS_RESERVED_SCALE(x) (((x)>>5) & 0x7)
|
||||
/*
|
||||
* I/O mapping sub-tuple:
|
||||
* Byte 1:
|
||||
* 0x1F - I/O address lines
|
||||
* 0x20 - 8 bit I/O
|
||||
* 0x40 - 16 bit I/O
|
||||
* 0x80 - I/O range??
|
||||
* Byte 2:
|
||||
* 0x0F - 0's numbered count of I/O block subtuples following.
|
||||
* 0x30 - Size of I/O address value within subtuple. Values
|
||||
* can be 1 (8 bits), 2 (16 bits) or 3 (32 bits).
|
||||
* 0xC0 - Size of I/O port block size value within subtuple.
|
||||
* I/O block sub-tuples, count from previous block:
|
||||
* Byte 1-n: I/O start address
|
||||
* Byte x-x: Size of I/O port block.
|
||||
*/
|
||||
#define CIS_IO_ADDR(x) ((x) & 0x1F)
|
||||
#define CIS_IO_8BIT 0x20
|
||||
#define CIS_IO_16BIT 0x40
|
||||
#define CIS_IO_RANGE 0x80
|
||||
#define CIS_IO_BLKS(x) ((x) & 0xF)
|
||||
#define CIS_IO_ADSZ(x) (((x)>>4) & 3)
|
||||
#define CIS_IO_BLKSZ(x) (((x)>>6) & 3)
|
||||
/*
|
||||
* IRQ sub-tuple.
|
||||
* Byte 1:
|
||||
* 0x0F - Irq number or mask bits
|
||||
* 0x10 - IRQ mask values exist
|
||||
* 0x20 - Level triggered interrupts
|
||||
* 0x40 - Pulse triggered requests
|
||||
* 0x80 - Interrupt sharing.
|
||||
* Byte 2-3: Interrupt req mask (if 0x10 of byte 1 set).
|
||||
*/
|
||||
#define CIS_IRQ_IRQN(x) ((x) & 0xF)
|
||||
#define CIS_IRQ_MASK 0x10
|
||||
#define CIS_IRQ_LEVEL 0x20
|
||||
#define CIS_IRQ_PULSE 0x40
|
||||
#define CIS_IRQ_SHARING 0x80
|
||||
/*
|
||||
* Memory block subtuple. Depending on the features bits, the
|
||||
* following subtuples are used:
|
||||
* mem features == 1
|
||||
* Byte 1-2: upper 16 bits of 24 bit memory length.
|
||||
* mem features == 2
|
||||
* Byte 1-2: upper 16 bits of 24 bit memory length.
|
||||
* Byte 3-4: upper 16 bits of 24 bit memory address.
|
||||
* mem_features == 3
|
||||
* Byte 1:
|
||||
* 0x07 - 0's numbered count of memory sub-tuples
|
||||
* 0x18 - Memory length size (1's numbered)
|
||||
* 0x60 - Memory address size (1's numbered)
|
||||
* 0x80 - Host address value exists
|
||||
* Memory sub-tuples follow:
|
||||
* Byte 1-n: Memory length value (<< 8)
|
||||
* Byte n-n: Memory card address value (<< 8)
|
||||
* Byte n-n: Memory host address value (<< 8)
|
||||
*/
|
||||
#define CIS_FEAT_MEM_NONE 0 /* No memory config */
|
||||
#define CIS_FEAT_MEM_LEN 1 /* Just length */
|
||||
#define CIS_FEAT_MEM_ADDR 2 /* Card address & length */
|
||||
#define CIS_FEAT_MEM_WIN 3 /* Multiple windows */
|
||||
|
||||
#define CIS_MEM_WINS(x) (((x) & 0x7)+1)
|
||||
#define CIS_MEM_LENSZ(x) (((x) >> 3) & 0x3)
|
||||
#define CIS_MEM_ADDRSZ(x) (((x) >> 5) & 0x3)
|
||||
#define CIS_MEM_HOST 0x80
|
||||
207
sys/pccard/i82365.h
Normal file
207
sys/pccard/i82365.h
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* i82365.h - Definitions for Intel 82365 PCIC
|
||||
* PCMCIA Card Interface Controller
|
||||
*
|
||||
* originally by Barry Jaspan; hacked over by Keith Moore
|
||||
* hacked to unrecognisability by Andrew McRae (andrew@mega.com.au)
|
||||
*
|
||||
* Updated 3/3/95 to include Cirrus Logic stuff.
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 1995 Andrew McRae. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#define PCIC_I82365 0 /* Intel chip */
|
||||
#define PCIC_IBM 1 /* IBM clone */
|
||||
#define PCIC_VLSI 2 /* VLSI chip */
|
||||
#define PCIC_PD672X 3 /* Cirrus logic 627x */
|
||||
#define PCIC_PD6710 4
|
||||
#define PCIC_CL6729 5
|
||||
#define PCIC_VG468 6
|
||||
/*
|
||||
* Address of the controllers. Each controller can manage
|
||||
* two PCMCIA slots. Up to 8 slots are supported in total.
|
||||
* The PCIC controller is accessed via an index port and a
|
||||
* data port. The index port has the 8 bit address of the
|
||||
* register accessed via the data port. How I long for
|
||||
* real memory mapped I/O!
|
||||
* The top two bits of the index address are used to
|
||||
* identify the port number, and the lower 6 bits
|
||||
* select one of the 64 possible data registers.
|
||||
*/
|
||||
#define PCIC_INDEX_0 0x3E0 /* index reg, chips 0 and 1 */
|
||||
#define PCIC_DATA_0 0x3E1 /* data register, chips 0 and 1 */
|
||||
#define PCIC_INDEX_1 0x3E2 /* index reg, chips 2 and 3 */
|
||||
#define PCIC_DATA_1 0x3E3 /* data register, chips 2 and 3 */
|
||||
/*
|
||||
* Register index addresses.
|
||||
*/
|
||||
#define PCIC_ID_REV 0x00 /* Identification and Revision */
|
||||
#define PCIC_STATUS 0x01 /* Interface Status */
|
||||
#define PCIC_POWER 0x02 /* Power and RESETDRV control */
|
||||
#define PCIC_INT_GEN 0x03 /* Interrupt and General Control */
|
||||
#define PCIC_STAT_CHG 0x04 /* Card Status Change */
|
||||
#define PCIC_STAT_INT 0x05 /* Card Status Change Interrupt Config */
|
||||
#define PCIC_ADDRWINE 0x06 /* Address Window Enable */
|
||||
#define PCIC_IOCTL 0x07 /* I/O Control */
|
||||
#define PCIC_IO0 0x08 /* I/O Address 0 */
|
||||
#define PCIC_IO1 0x0c /* I/O Address 1 */
|
||||
#define PCIC_MEMBASE 0x10 /* Base of memory window registers */
|
||||
#define PCIC_CDGC 0x16 /* Card Detect and General Control */
|
||||
#define PCIC_GLO_CTRL 0x1e /* Global Control Register */
|
||||
|
||||
#define PCIC_TIME_SETUP0 0x3a
|
||||
#define PCIC_TIME_CMD0 0x3b
|
||||
#define PCIC_TIME_RECOV0 0x3c
|
||||
#define PCIC_TIME_SETUP1 0x3d
|
||||
#define PCIC_TIME_CMD1 0x3e
|
||||
#define PCIC_TIME_RECOV1 0x3f
|
||||
|
||||
#define PCIC_SLOT_SIZE 0x40 /* Size of register set for one slot */
|
||||
|
||||
/* Now register bits, ordered by reg # */
|
||||
|
||||
/* For Identification and Revision (PCIC_ID_REV) */
|
||||
#define PCIC_INTEL0 0x82 /* Intel 82365SL Rev. 0; Both Memory and I/O */
|
||||
#define PCIC_INTEL1 0x83 /* Intel 82365SL Rev. 1; Both Memory and I/O */
|
||||
#define PCIC_IBM1 0x88 /* IBM PCIC clone; Both Memory and I/O */
|
||||
#define PCIC_IBM2 0x89 /* IBM PCIC clone; Both Memory and I/O */
|
||||
|
||||
/* For Interface Status register (PCIC_STATUS) */
|
||||
#define PCIC_VPPV 0x80 /* Vpp_valid */
|
||||
#define PCIC_POW 0x40 /* PC Card power active */
|
||||
#define PCIC_READY 0x20 /* Ready/~Busy */
|
||||
#define PCIC_MWP 0x10 /* Memory Write Protect */
|
||||
#define PCIC_CD 0x0C /* Both card detect bits */
|
||||
#define PCIC_BVD 0x03 /* Both Battery Voltage Detect bits */
|
||||
|
||||
/* For the Power and RESETDRV register (PCIC_POWER) */
|
||||
#define PCIC_OUTENA 0x80 /* Output Enable */
|
||||
#define PCIC_DISRST 0x40 /* Disable RESETDRV */
|
||||
#define PCIC_APSENA 0x20 /* Auto Pwer Switch Enable */
|
||||
#define PCIC_VCC 0x18 /* Vcc control bits */
|
||||
#define PCIC_VCC_5V 0x10 /* 5 volts */
|
||||
#define PCIC_VCC_3V 0x18 /* 3 volts */
|
||||
#define PCIC_VPP 0x0C /* Vpp control bits */
|
||||
#define PCIC_VPP_5V 0x01 /* 5 volts */
|
||||
#define PCIC_VPP_12V 0x02 /* 12 volts */
|
||||
|
||||
/* For the Interrupt and General Control register (PCIC_INT_GEN) */
|
||||
#define PCIC_CARDTYPE 0x20 /* Card Type 0 = memory, 1 = I/O */
|
||||
#define PCIC_IOCARD 0x20
|
||||
#define PCIC_MEMCARD 0x00
|
||||
#define PCIC_CARDRESET 0x40 /* Card reset 0 = Reset, 1 = Normal */
|
||||
#define PCIC_INTR_ENA 0x10 /* Interrupt enable */
|
||||
|
||||
/* For the Card Status Change register (PCIC_STAT_CHG) */
|
||||
#define PCIC_CDTCH 0x08 /* Card Detect Change */
|
||||
#define PCIC_RDYCH 0x04 /* Ready Change */
|
||||
#define PCIC_BATWRN 0x02 /* Battery Warning */
|
||||
#define PCIC_BATDED 0x01 /* Battery Dead */
|
||||
|
||||
/*
|
||||
* For the Address Window Enable Register (PCIC_ADDRWINE)
|
||||
* The lower 6 bits contain enable bits for the memory
|
||||
* windows (LSB = memory window 0).
|
||||
*/
|
||||
#define PCIC_MEMCS16 0x20 /* ~MEMCS16 Decode A23-A12 */
|
||||
#define PCIC_IO0_EN 0x40 /* I/O Window 0 Enable */
|
||||
#define PCIC_IO1_EN 0x80 /* I/O Window 1 Enable */
|
||||
|
||||
/*
|
||||
* For the I/O Control Register (PCIC_IOCTL)
|
||||
* The lower nybble is the flags for I/O window 0
|
||||
* The upper nybble is the flags for I/O window 1
|
||||
*/
|
||||
#define PCIC_IO_16BIT 0x01 /* I/O to this segment is 16 bit */
|
||||
#define PCIC_IO_CS16 0x02 /* I/O cs16 source is the card */
|
||||
#define PCIC_IO_0WS 0x04 /* zero wait states added on 8 bit cycles */
|
||||
#define PCIC_IO_WS 0x08 /* Wait states added for 16 bit cycles */
|
||||
|
||||
/*
|
||||
* The memory window registers contain the start and end
|
||||
* physical host address that the PCIC maps to the card,
|
||||
* and an offset calculated from the card memory address.
|
||||
* All values are shifted down 12 bits, so allocation is
|
||||
* done in 4Kb blocks. Only 12 bits of each value is
|
||||
* stored, limiting the range to the ISA address size of
|
||||
* 24 bits. The upper 4 bits of the most significant byte
|
||||
* within the values are used for various flags.
|
||||
*
|
||||
* The layout is:
|
||||
*
|
||||
* base+0 : lower 8 bits of system memory start address
|
||||
* base+1 : upper 4 bits of system memory start address + flags
|
||||
* base+2 : lower 8 bits of system memory end address
|
||||
* base+3 : upper 4 bits of system memory end address + flags
|
||||
* base+4 : lower 8 bits of offset to card address
|
||||
* base+5 : upper 4 bits of offset to card address + flags
|
||||
*
|
||||
* The following two bytes are reserved for other use.
|
||||
*/
|
||||
#define PCIC_MEMSIZE 8
|
||||
/*
|
||||
* Flags for system memory start address upper byte
|
||||
*/
|
||||
#define PCIC_ZEROWS 0x40 /* Zero wait states */
|
||||
#define PCIC_DATA16 0x80 /* Data width is 16 bits */
|
||||
|
||||
/*
|
||||
* Flags for system memory end address upper byte
|
||||
*/
|
||||
#define PCIC_MW0 0x40 /* Wait state bit 0 */
|
||||
#define PCIC_MW1 0x80 /* Wait state bit 1 */
|
||||
|
||||
/*
|
||||
* Flags for card offset upper byte
|
||||
*/
|
||||
#define PCIC_REG 0x40 /* Attribute/Common select (why called Reg?) */
|
||||
#define PCIC_WP 0x80 /* Write-protect this window */
|
||||
|
||||
/* For Card Detect and General Control register (PCIC_CDGC) */
|
||||
#define PCIC_16_DL_INH 0x01 /* 16-bit memory delay inhibit */
|
||||
#define PCIC_CNFG_RST_EN 0x02 /* configuration reset enable */
|
||||
#define PCIC_GPI_EN 0x04 /* GPI Enable */
|
||||
#define PCIC_GPI_TRANS 0x08 /* GPI Transition Control */
|
||||
#define PCIC_CDRES_EN 0x10 /* card detect resume enable */
|
||||
#define PCIC_SW_CD_INT 0x20 /* s/w card detect interrupt */
|
||||
|
||||
/* For Global Control register (PCIC_GLO_CTRL) */
|
||||
#define PCIC_PWR_DOWN 0x01 /* power down */
|
||||
#define PCIC_LVL_MODE 0x02 /* level mode interrupt enable */
|
||||
#define PCIC_WB_CSCINT 0x04 /* explicit write-back csc intr */
|
||||
#define PCIC_IRQ0_LEVEL 0x08 /* irq 14 pulse mode enable */
|
||||
#define PCIC_IRQ1_LEVEL 0x10
|
||||
|
||||
/*
|
||||
* Mask of allowable interrupts.
|
||||
* Ints are 3,4,5,7,9,10,11,12,14,15
|
||||
*/
|
||||
#define PCIC_INT_MASK_ALLOWED 0xDEB8
|
||||
|
||||
#define PCIC_IO_WIN 2
|
||||
#define PCIC_MEM_WIN 5
|
||||
|
||||
#define PCIC_MAX_SLOTS 8
|
||||
942
sys/pccard/pccard.c
Normal file
942
sys/pccard/pccard.c
Normal file
|
|
@ -0,0 +1,942 @@
|
|||
/*
|
||||
* pccard.c - Interface code for PC-CARD controllers.
|
||||
*
|
||||
* June 1995, Andrew McRae (andrew@mega.com.au)
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 1995 Andrew McRae. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "crd.h"
|
||||
#if NCRD > 0
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/devconf.h>
|
||||
#include <sys/malloc.h>
|
||||
|
||||
#include <i386/isa/isa.h>
|
||||
#include <i386/isa/isa_device.h>
|
||||
#include <i386/isa/icu.h>
|
||||
|
||||
#include "apm.h"
|
||||
#if NAPM > 0
|
||||
#include <machine/apm_bios.h>
|
||||
#endif /* NAPM > 0 */
|
||||
|
||||
#include <pccard/card.h>
|
||||
#include <pccard/slot.h>
|
||||
|
||||
#define PCCARD_MEMSIZE (4*1024)
|
||||
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
|
||||
/*
|
||||
* cdevsw entry points
|
||||
*/
|
||||
int crdopen __P((dev_t dev, int oflags, int devtype,
|
||||
struct proc *p));
|
||||
int crdclose __P((dev_t dev, int fflag, int devtype,
|
||||
struct proc *p));
|
||||
int crdread __P((dev_t dev, struct uio *uio, int ioflag));
|
||||
int crdwrite __P((dev_t dev, struct uio *uio, int ioflag));
|
||||
int crdioctl __P((dev_t dev, int cmd, caddr_t data,
|
||||
int fflag, struct proc *p));
|
||||
int crdselect __P((dev_t dev, int rw, struct proc *p));
|
||||
|
||||
static int allocate_driver(struct slot *, struct drv_desc *);
|
||||
static void inserted(void *);
|
||||
static void disable_slot(struct slot *);
|
||||
static int invalid_io_memory(unsigned long, int);
|
||||
static struct pccard_drv *find_driver(char *);
|
||||
static void remove_device(struct pccard_dev *);
|
||||
static void slot_irq_handler(int);
|
||||
#if NAPM > 0
|
||||
/*
|
||||
* For the APM stuff, the apmhook structure is kept
|
||||
* separate from the slot structure so that the slot
|
||||
* drivers do not need to know about the hooks (or the
|
||||
* data structures).
|
||||
*/
|
||||
static int slot_suspend(struct slot *sp);
|
||||
static int slot_resume(struct slot *sp);
|
||||
static struct apmhook s_hook[MAXSLOT]; /* APM suspend */
|
||||
static struct apmhook r_hook[MAXSLOT]; /* APM resume */
|
||||
#endif /* NAPM > 0 */
|
||||
|
||||
void pcic_probe();
|
||||
|
||||
static struct slot *pccard_slots[MAXSLOT]; /* slot entries */
|
||||
static struct slot *slot_list;
|
||||
static struct slot_cont *cont_list;
|
||||
static struct pccard_drv *drivers; /* Card drivers */
|
||||
/*
|
||||
* The driver interface for read/write uses a block
|
||||
* of memory in the ISA I/O memory space allocated via
|
||||
* an ioctl setting.
|
||||
*/
|
||||
static unsigned long pccard_mem; /* Physical memory */
|
||||
static unsigned char *pccard_kmem; /* Kernel virtual address */
|
||||
/*
|
||||
* pccard_configure - called by autoconf code.
|
||||
* Probes for various PC-CARD controllers, and
|
||||
* initialises data structures to point to the
|
||||
* various slots.
|
||||
*
|
||||
* Each controller indicates the number of slots
|
||||
* that it sees, and these are mapped to a master
|
||||
* slot number accessed via the character device entries.
|
||||
*/
|
||||
void
|
||||
pccard_configure()
|
||||
{
|
||||
struct slot_cont *cp;
|
||||
struct slot *sp;
|
||||
|
||||
#include "pcic.h"
|
||||
#if NPCIC > 0
|
||||
pcic_probe();
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
* pccard_add_driver - Add a new driver to the list of
|
||||
* drivers available for allocation.
|
||||
*/
|
||||
void
|
||||
pccard_add_driver(struct pccard_drv *dp)
|
||||
{
|
||||
/*
|
||||
* If already loaded, then reject the driver.
|
||||
*/
|
||||
if (find_driver(dp->name))
|
||||
{
|
||||
printf("Driver %s already loaded\n", dp->name);
|
||||
return;
|
||||
}
|
||||
dp->next = drivers;
|
||||
drivers = dp;
|
||||
}
|
||||
/*
|
||||
* pccard_remove_driver - called to unlink driver
|
||||
* from devices. Usually called when drivers are
|
||||
* are unloaded from kernel.
|
||||
*/
|
||||
void
|
||||
pccard_remove_driver(struct pccard_drv *dp)
|
||||
{
|
||||
struct slot *sp;
|
||||
struct pccard_dev *devp, *next;
|
||||
struct pccard_drv *drvp;
|
||||
|
||||
for (sp = slot_list; sp; sp = sp->next)
|
||||
for (devp = sp->devices; devp; devp = next)
|
||||
{
|
||||
next = devp->next;
|
||||
if (devp->drv == dp)
|
||||
remove_device(devp);
|
||||
}
|
||||
/*
|
||||
* Once all the devices belonging to this driver have been
|
||||
* freed, then remove the driver from the list
|
||||
* of registered drivers.
|
||||
*/
|
||||
if (drivers == dp)
|
||||
drivers = dp->next;
|
||||
else
|
||||
for (drvp = drivers; drvp->next; drvp = drvp->next)
|
||||
if (drvp->next == dp)
|
||||
{
|
||||
drvp->next = dp->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* pccard_remove_controller - Called when the slot
|
||||
* driver is unloaded. The plan is to unload
|
||||
* drivers from the slots, and then remove the
|
||||
* slots from the slot list, and then finally
|
||||
* remove the controller structure. Messy...
|
||||
*/
|
||||
void
|
||||
pccard_remove_controller(struct slot_cont *cp)
|
||||
{
|
||||
struct slot *sp, *next, *last = 0;
|
||||
struct slot_cont *cl;
|
||||
struct pccard_dev *dp;
|
||||
|
||||
for (sp = slot_list; sp; sp = next)
|
||||
{
|
||||
next = sp->next;
|
||||
/*
|
||||
* If this slot belongs to this controller,
|
||||
* remove this slot.
|
||||
*/
|
||||
if (sp->cinfo == cp)
|
||||
{
|
||||
pccard_slots[sp->slot] = 0;
|
||||
if (sp->insert_timeout)
|
||||
untimeout(inserted, (void *)sp);
|
||||
/*
|
||||
* Unload the drivers attached to this slot.
|
||||
*/
|
||||
while (dp = sp->devices)
|
||||
remove_device(dp);
|
||||
/*
|
||||
* Disable the slot and unlink the slot from the slot list.
|
||||
*/
|
||||
disable_slot(sp);
|
||||
if (last)
|
||||
last->next = next;
|
||||
else
|
||||
slot_list = next;
|
||||
#if NAPM > 0
|
||||
apm_hook_disestablish(APM_HOOK_SUSPEND,
|
||||
&s_hook[sp->slot]);
|
||||
apm_hook_disestablish(APM_HOOK_RESUME,
|
||||
&r_hook[sp->slot]);
|
||||
#endif
|
||||
if (cp->extra && sp->cdata)
|
||||
FREE(sp->cdata, M_DEVBUF);
|
||||
FREE(sp, M_DEVBUF);
|
||||
/*
|
||||
* xx Can't use sp after we have freed it.
|
||||
*/
|
||||
}
|
||||
else
|
||||
last = sp;
|
||||
}
|
||||
/*
|
||||
* Unlink controller structure from controller list.
|
||||
*/
|
||||
if (cont_list == cp)
|
||||
cont_list = cp->next;
|
||||
else
|
||||
for (cl = cont_list; cl->next; cl = cl->next)
|
||||
if (cl->next == cp)
|
||||
{
|
||||
cl->next = cp->next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* disable_slot - Disables the slot by removing
|
||||
* the power and unmapping the I/O
|
||||
*/
|
||||
static void
|
||||
disable_slot(struct slot *sp)
|
||||
{
|
||||
int i;
|
||||
struct pccard_dev *devp;
|
||||
/*
|
||||
* Unload all the drivers on this slot. Note we can't
|
||||
* call remove_device from here, because this may be called
|
||||
* from the event routine, which is called from the slot
|
||||
* controller's ISR, and this could remove the device
|
||||
* structure out in the middle of some driver activity.
|
||||
*
|
||||
* Note that a race condition is possible here; if a
|
||||
* driver is accessing the device and it is removed, then
|
||||
* all bets are off...
|
||||
*/
|
||||
for (devp = sp->devices; devp; devp = devp->next)
|
||||
{
|
||||
devp->drv->unload(devp);
|
||||
devp->running = 0;
|
||||
}
|
||||
/*
|
||||
* Power off the slot.
|
||||
*/
|
||||
sp->cinfo->disable(sp);
|
||||
/*
|
||||
* De-activate all contexts.
|
||||
*/
|
||||
for (i = 0; i < sp->cinfo->maxmem; i++)
|
||||
if (sp->mem[i].flags & MDF_ACTIVE)
|
||||
{
|
||||
sp->mem[i].flags = 0;
|
||||
(void)sp->cinfo->mapmem(sp, i);
|
||||
}
|
||||
for (i = 0; i < sp->cinfo->maxio; i++)
|
||||
if (sp->io[i].flags & IODF_ACTIVE)
|
||||
{
|
||||
sp->io[i].flags = 0;
|
||||
(void)sp->cinfo->mapio(sp, i);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* APM hooks for suspending and resuming.
|
||||
*/
|
||||
#if NAPM > 0
|
||||
static int
|
||||
slot_suspend(struct slot *sp)
|
||||
{
|
||||
struct pccard_dev *dp;
|
||||
|
||||
for (dp = sp->devices; dp; dp = dp->next)
|
||||
(void)dp->drv->suspend(dp);
|
||||
sp->cinfo->disable(sp);
|
||||
return(0);
|
||||
}
|
||||
static int
|
||||
slot_resume(struct slot *sp)
|
||||
{
|
||||
struct pccard_dev *dp;
|
||||
|
||||
sp->cinfo->power(sp);
|
||||
if (sp->irq)
|
||||
sp->cinfo->mapirq(sp, sp->irq);
|
||||
for (dp = sp->devices; dp; dp = dp->next)
|
||||
(void)dp->drv->init(dp, 0);
|
||||
return(0);
|
||||
}
|
||||
#endif /* NAPM > 0 */
|
||||
/*
|
||||
* pccard_alloc_slot - Called from controller probe
|
||||
* routine, this function allocates a new PC-CARD slot
|
||||
* and initialises the data structures using the data provided.
|
||||
* It returns the allocated structure to the probe routine
|
||||
* to allow the controller specific data to be initialised.
|
||||
*/
|
||||
struct slot *
|
||||
pccard_alloc_slot(struct slot_cont *cp)
|
||||
{
|
||||
struct slot *sp;
|
||||
int slotno;
|
||||
|
||||
for (slotno = 0; slotno < MAXSLOT; slotno++)
|
||||
if (pccard_slots[slotno] == 0)
|
||||
break;
|
||||
if (slotno >= MAXSLOT)
|
||||
return(0);
|
||||
MALLOC(sp, struct slot *, sizeof(*sp), M_DEVBUF, M_WAITOK);
|
||||
bzero(sp, sizeof(*sp));
|
||||
if (cp->extra)
|
||||
{
|
||||
MALLOC(sp->cdata, void *, cp->extra, M_DEVBUF, M_WAITOK);
|
||||
bzero(sp->cdata, cp->extra);
|
||||
}
|
||||
sp->cinfo = cp;
|
||||
sp->slot = slotno;
|
||||
pccard_slots[slotno] = sp;
|
||||
sp->next = slot_list;
|
||||
slot_list = sp;
|
||||
/*
|
||||
* If this controller hasn't been seen before, then
|
||||
* link it into the list of controllers.
|
||||
*/
|
||||
if (cp->slots++ == 0)
|
||||
{
|
||||
cp->next = cont_list;
|
||||
cont_list = cp;
|
||||
if (cp->maxmem > NUM_MEM_WINDOWS)
|
||||
cp->maxmem = NUM_MEM_WINDOWS;
|
||||
if (cp->maxio > NUM_IO_WINDOWS)
|
||||
cp->maxio = NUM_IO_WINDOWS;
|
||||
printf("PC-Card %s (%d mem & %d I/O windows)\n",
|
||||
cp->name, cp->maxmem, cp->maxio);
|
||||
}
|
||||
#if NAPM > 0
|
||||
{
|
||||
struct apmhook *ap;
|
||||
|
||||
ap = &s_hook[sp->slot];
|
||||
ap->ah_fun = slot_suspend;
|
||||
ap->ah_arg = (void *) sp;
|
||||
ap->ah_name = cp->name;
|
||||
ap->ah_order = APM_MID_ORDER;
|
||||
apm_hook_establish(APM_HOOK_SUSPEND, ap);
|
||||
ap = &r_hook[sp->slot];
|
||||
ap->ah_fun = slot_resume;
|
||||
ap->ah_arg = (void *) sp;
|
||||
ap->ah_name = cp->name;
|
||||
ap->ah_order = APM_MID_ORDER;
|
||||
apm_hook_establish(APM_HOOK_RESUME, ap);
|
||||
}
|
||||
#endif /* NAPM > 0 */
|
||||
return(sp);
|
||||
}
|
||||
/*
|
||||
* pccard_alloc_intr - allocate an interrupt from the
|
||||
* free interrupts and return its number. The interrupts
|
||||
* allowed are passed as a mask.
|
||||
*/
|
||||
int
|
||||
pccard_alloc_intr(int imask, inthand2_t *hand, int unit, int *maskp)
|
||||
{
|
||||
int rv, irq;
|
||||
unsigned int mask;
|
||||
|
||||
for (irq = 1; irq < 16; irq++)
|
||||
{
|
||||
mask = 1ul << irq;
|
||||
if ((mask & imask) &&
|
||||
register_intr(irq, 0, 0, hand, maskp, unit)==0)
|
||||
{
|
||||
if (maskp)
|
||||
INTRMASK (*maskp, mask);
|
||||
|
||||
update_intr_masks();
|
||||
|
||||
INTREN (mask);
|
||||
return(irq);
|
||||
}
|
||||
}
|
||||
return(-1);
|
||||
}
|
||||
/*
|
||||
* allocate_driver - Create a new device entry for this
|
||||
* slot, and attach a driver to it.
|
||||
*/
|
||||
static int
|
||||
allocate_driver(struct slot *sp, struct drv_desc *drvp)
|
||||
{
|
||||
struct pccard_dev *devp;
|
||||
struct pccard_drv *dp;
|
||||
int err, irq = 0, s;
|
||||
|
||||
dp = find_driver(drvp->name);
|
||||
if (dp == 0)
|
||||
return(ENXIO);
|
||||
/*
|
||||
* If an instance of this driver is already installed,
|
||||
* but not running, then remove it. If it is running,
|
||||
* then reject the request.
|
||||
*/
|
||||
for (devp = sp->devices; devp; devp = devp->next)
|
||||
if (devp->drv == dp && devp->isahd.id_unit == drvp->unit)
|
||||
{
|
||||
if (devp->running)
|
||||
return(EBUSY);
|
||||
remove_device(devp);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* If an interrupt mask has been given, then check it
|
||||
* against the slot interrupt (if one has been allocated).
|
||||
*/
|
||||
if (drvp->irqmask && dp->imask)
|
||||
{
|
||||
if ((sp->cinfo->irqs & drvp->irqmask)==0)
|
||||
return(EINVAL);
|
||||
if (sp->irq)
|
||||
{
|
||||
if (((1 << sp->irq)&drvp->irqmask)==0)
|
||||
return(EINVAL);
|
||||
sp->irqref++;
|
||||
irq = sp->irq;
|
||||
}
|
||||
/*
|
||||
* Attempt to allocate an interrupt. XXX We lose at the moment
|
||||
* if the second device relies on a different interrupt mask.
|
||||
*/
|
||||
else
|
||||
{
|
||||
irq = pccard_alloc_intr(drvp->irqmask,
|
||||
slot_irq_handler, (int)sp, dp->imask);
|
||||
if (irq < 0)
|
||||
return(EINVAL);
|
||||
sp->irq = irq;
|
||||
sp->irqref = 1;
|
||||
sp->cinfo->mapirq(sp, sp->irq);
|
||||
}
|
||||
}
|
||||
MALLOC(devp, struct pccard_dev *, sizeof(*devp), M_DEVBUF, M_WAITOK);
|
||||
bzero(devp, sizeof(*devp));
|
||||
/*
|
||||
* Create an entry for the device under this slot.
|
||||
*/
|
||||
devp->drv = dp;
|
||||
devp->sp = sp;
|
||||
devp->isahd.id_unit = drvp->unit;
|
||||
devp->isahd.id_msize = drvp->memsize;
|
||||
devp->isahd.id_iobase = drvp->iobase;
|
||||
if (irq)
|
||||
devp->isahd.id_irq = 1 << irq;
|
||||
devp->isahd.id_flags = drvp->flags;
|
||||
/*
|
||||
* Convert the memory to kernel space.
|
||||
*/
|
||||
if (drvp->mem)
|
||||
devp->isahd.id_maddr = (caddr_t)(drvp->mem + atdevbase - 0xA0000);
|
||||
else
|
||||
devp->isahd.id_maddr = 0;
|
||||
devp->next = sp->devices;
|
||||
sp->devices = devp;
|
||||
s = splhigh();
|
||||
err = dp->init(devp, 1);
|
||||
splx(s);
|
||||
/*
|
||||
* If the init functions returns no error, then the
|
||||
* device has been successfully installed. If so, then
|
||||
* attach it to the slot, otherwise free it and return
|
||||
* the error.
|
||||
*/
|
||||
if (err)
|
||||
remove_device(devp);
|
||||
else
|
||||
devp->running = 1;
|
||||
return(err);
|
||||
}
|
||||
static void
|
||||
remove_device(struct pccard_dev *dp)
|
||||
{
|
||||
struct slot *sp = dp->sp;
|
||||
struct pccard_dev *list;
|
||||
int s;
|
||||
|
||||
/*
|
||||
* If an interrupt is enabled on this slot,
|
||||
* then unregister it if no-one else is using it.
|
||||
*/
|
||||
s = splhigh();
|
||||
if (dp->running)
|
||||
dp->drv->unload(dp);
|
||||
if (dp->isahd.id_irq && --sp->irqref == 0)
|
||||
{
|
||||
sp->cinfo->mapirq(sp, 0);
|
||||
unregister_intr(sp->irq, slot_irq_handler);
|
||||
sp->irq = 0;
|
||||
}
|
||||
splx(s);
|
||||
/*
|
||||
* Remove from device list on this slot.
|
||||
*/
|
||||
if (sp->devices == dp)
|
||||
sp->devices = dp->next;
|
||||
else
|
||||
for (list = sp->devices; list->next; list = list->next)
|
||||
if (list->next == dp)
|
||||
{
|
||||
list->next = dp->next;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Finally, free the memory space.
|
||||
*/
|
||||
FREE(dp, M_DEVBUF);
|
||||
}
|
||||
/*
|
||||
* card insert routine - Called from a timeout to debounce
|
||||
* insertion events.
|
||||
*/
|
||||
static void
|
||||
inserted(void *arg)
|
||||
{
|
||||
struct slot *sp = arg;
|
||||
|
||||
sp->insert_timeout = 0;
|
||||
sp->state = filled;
|
||||
/*
|
||||
* Enable 5V to the card so that the CIS can be read.
|
||||
*/
|
||||
sp->pwr.vcc = 50;
|
||||
sp->pwr.vpp = 0;
|
||||
sp->cinfo->power(sp);
|
||||
printf("Card inserted, slot %d\n", sp->slot);
|
||||
/*
|
||||
* Now reset the card.
|
||||
*/
|
||||
sp->cinfo->reset(sp);
|
||||
}
|
||||
/*
|
||||
* Card event callback. Called at splhigh to prevent
|
||||
* device interrupts from interceding.
|
||||
*/
|
||||
void
|
||||
pccard_event(struct slot *sp, enum card_event event)
|
||||
{
|
||||
int s;
|
||||
|
||||
if (sp->insert_timeout)
|
||||
{
|
||||
sp->insert_timeout = 0;
|
||||
untimeout(inserted, (void *)sp);
|
||||
}
|
||||
switch(event)
|
||||
{
|
||||
/*
|
||||
* The slot and devices are disabled, but the
|
||||
* data structures are not unlinked.
|
||||
*/
|
||||
case card_removed:
|
||||
if (sp->state == filled)
|
||||
{
|
||||
s = splhigh();
|
||||
disable_slot(sp);
|
||||
sp->state = empty;
|
||||
splx(s);
|
||||
printf("Card removed, slot %d\n", sp->slot);
|
||||
}
|
||||
break;
|
||||
case card_inserted:
|
||||
sp->insert_timeout = 1;
|
||||
timeout(inserted, (void *)sp, hz/4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* slot_irq_handler - Interrupt handler for shared irq devices.
|
||||
*/
|
||||
static void
|
||||
slot_irq_handler(int sp)
|
||||
{
|
||||
struct pccard_dev *dp;
|
||||
|
||||
/*
|
||||
* For each device that has the shared interrupt,
|
||||
* call the interrupt handler. If the interrupt was
|
||||
* caught, the handler returns true.
|
||||
*/
|
||||
for (dp = ((struct slot *)sp)->devices; dp; dp = dp->next)
|
||||
if (dp->isahd.id_irq && dp->running && dp->drv->handler(dp))
|
||||
return;
|
||||
printf("Slot %d, unfielded interrupt (%d)\n",
|
||||
((struct slot *)sp)->slot, ((struct slot *)sp)->irq);
|
||||
}
|
||||
/*
|
||||
* Device driver interface.
|
||||
*/
|
||||
int
|
||||
crdopen(dev_t dev, int oflags, int devtype, struct proc *p)
|
||||
{
|
||||
struct slot *sp;
|
||||
|
||||
if (minor(dev) >= MAXSLOT)
|
||||
return(ENXIO);
|
||||
sp = pccard_slots[minor(dev)];
|
||||
if (sp==0)
|
||||
return(ENXIO);
|
||||
if (sp->rwmem == 0)
|
||||
sp->rwmem = MDF_ATTR;
|
||||
return(0);
|
||||
}
|
||||
/*
|
||||
* Close doesn't de-allocate any resources, since
|
||||
* slots may be assigned to drivers already.
|
||||
*/
|
||||
int
|
||||
crdclose(dev_t dev, int fflag, int devtype, struct proc *p)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
/*
|
||||
* read interface. Map memory at lseek offset,
|
||||
* then transfer to user space.
|
||||
*/
|
||||
int
|
||||
crdread(dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
struct slot *sp = pccard_slots[minor(dev)];
|
||||
unsigned char *p;
|
||||
int error = 0, win, count;
|
||||
struct mem_desc *mp, oldmap;
|
||||
unsigned int offs;
|
||||
|
||||
if (sp == 0 || sp->state != filled)
|
||||
return(ENXIO);
|
||||
if (pccard_mem == 0)
|
||||
return(ENOMEM);
|
||||
for (win = 0; win < sp->cinfo->maxmem; win++)
|
||||
if ((sp->mem[win].flags & MDF_ACTIVE)==0)
|
||||
break;
|
||||
if (win >= sp->cinfo->maxmem)
|
||||
return(EBUSY);
|
||||
mp = &sp->mem[win];
|
||||
oldmap = *mp;
|
||||
mp->flags = sp->rwmem|MDF_ACTIVE;
|
||||
#if 0
|
||||
printf("Rd at offs %d, size %d\n", (int)uio->uio_offset,
|
||||
uio->uio_resid);
|
||||
#endif
|
||||
while (uio->uio_resid && error == 0)
|
||||
{
|
||||
mp->card = uio->uio_offset;
|
||||
mp->size = PCCARD_MEMSIZE;
|
||||
mp->start = (caddr_t)pccard_mem;
|
||||
if (error = sp->cinfo->mapmem(sp, win))
|
||||
break;
|
||||
offs = (unsigned int)uio->uio_offset & (PCCARD_MEMSIZE - 1);
|
||||
p = pccard_kmem + offs;
|
||||
count = MIN(PCCARD_MEMSIZE - offs, uio->uio_resid);
|
||||
error = uiomove(p, count, uio);
|
||||
}
|
||||
/*
|
||||
* Restore original map.
|
||||
*/
|
||||
*mp = oldmap;
|
||||
sp->cinfo->mapmem(sp, win);
|
||||
|
||||
return(error);
|
||||
}
|
||||
/*
|
||||
* crdwrite - Write data to card memory.
|
||||
* Handles wrap around so that only one memory
|
||||
* window is used.
|
||||
*/
|
||||
int
|
||||
crdwrite(dev_t dev, struct uio *uio, int ioflag)
|
||||
{
|
||||
struct slot *sp = pccard_slots[minor(dev)];
|
||||
unsigned char *p, c;
|
||||
int error = 0, win, count;
|
||||
struct mem_desc *mp, oldmap;
|
||||
unsigned int offs;
|
||||
|
||||
if (sp == 0 || sp->state != filled)
|
||||
return(ENXIO);
|
||||
if (pccard_mem == 0)
|
||||
return(ENOMEM);
|
||||
for (win = 0; win < sp->cinfo->maxmem; win++)
|
||||
if ((sp->mem[win].flags & MDF_ACTIVE)==0)
|
||||
break;
|
||||
if (win >= sp->cinfo->maxmem)
|
||||
return(EBUSY);
|
||||
mp = &sp->mem[win];
|
||||
oldmap = *mp;
|
||||
mp->flags = sp->rwmem|MDF_ACTIVE;
|
||||
#if 0
|
||||
printf("Wr at offs %d, size %d\n", (int)uio->uio_offset,
|
||||
uio->uio_resid);
|
||||
#endif
|
||||
while (uio->uio_resid && error == 0)
|
||||
{
|
||||
mp->card = uio->uio_offset;
|
||||
mp->size = PCCARD_MEMSIZE;
|
||||
mp->start = (caddr_t)pccard_mem;
|
||||
if (error = sp->cinfo->mapmem(sp, win))
|
||||
break;
|
||||
offs = (unsigned int)uio->uio_offset & (PCCARD_MEMSIZE - 1);
|
||||
p = pccard_kmem + offs;
|
||||
count = MIN(PCCARD_MEMSIZE - offs, uio->uio_resid);
|
||||
#if 0
|
||||
printf("Writing %d bytes to address 0x%x\n", count, p);
|
||||
#endif
|
||||
error = uiomove(p, count, uio);
|
||||
}
|
||||
/*
|
||||
* Restore original map.
|
||||
*/
|
||||
*mp = oldmap;
|
||||
sp->cinfo->mapmem(sp, win);
|
||||
|
||||
return(error);
|
||||
}
|
||||
/*
|
||||
* ioctl calls - allows setting/getting of memory and I/O
|
||||
* descriptors, and assignment of drivers.
|
||||
*/
|
||||
int
|
||||
crdioctl(dev_t dev, int cmd, caddr_t data, int fflag, struct proc *p)
|
||||
{
|
||||
int s;
|
||||
struct slot *sp = pccard_slots[minor(dev)];
|
||||
struct mem_desc *mp;
|
||||
struct io_desc *ip;
|
||||
|
||||
if (sp == 0 && cmd != PIOCRWMEM)
|
||||
return(ENXIO);
|
||||
switch(cmd)
|
||||
{
|
||||
default:
|
||||
if (sp->cinfo->ioctl)
|
||||
return(sp->cinfo->ioctl(sp, cmd, data));
|
||||
return(EINVAL);
|
||||
case PIOCGSTATE:
|
||||
s = splhigh();
|
||||
((struct slotstate *)data)->state = sp->state;
|
||||
sp->laststate = sp->state;
|
||||
splx(s);
|
||||
((struct slotstate *)data)->maxmem = sp->cinfo->maxmem;
|
||||
((struct slotstate *)data)->maxio = sp->cinfo->maxio;
|
||||
((struct slotstate *)data)->irqs = sp->cinfo->irqs;
|
||||
break;
|
||||
/*
|
||||
* Get memory context.
|
||||
*/
|
||||
case PIOCGMEM:
|
||||
s = ((struct mem_desc *)data)->window;
|
||||
if (s < 0 || s >= sp->cinfo->maxmem)
|
||||
return(EINVAL);
|
||||
mp = &sp->mem[s];
|
||||
((struct mem_desc *)data)->flags = mp->flags;
|
||||
((struct mem_desc *)data)->start = mp->start;
|
||||
((struct mem_desc *)data)->size = mp->size;
|
||||
((struct mem_desc *)data)->card = mp->card;
|
||||
break;
|
||||
/*
|
||||
* Set memory context. If context already active, then unmap it.
|
||||
* It is hard to see how the parameters can be checked.
|
||||
* At the very least, we only allow root to set the context.
|
||||
*/
|
||||
case PIOCSMEM:
|
||||
if (suser(p->p_ucred, &p->p_acflag))
|
||||
return(EPERM);
|
||||
if (sp->state != filled)
|
||||
return(ENXIO);
|
||||
s = ((struct mem_desc *)data)->window;
|
||||
if (s < 0 || s >= sp->cinfo->maxmem)
|
||||
return(EINVAL);
|
||||
sp->mem[s] = *((struct mem_desc *)data);
|
||||
return(sp->cinfo->mapmem(sp, s));
|
||||
/*
|
||||
* Get I/O port context.
|
||||
*/
|
||||
case PIOCGIO:
|
||||
s = ((struct io_desc *)data)->window;
|
||||
if (s < 0 || s >= sp->cinfo->maxio)
|
||||
return(EINVAL);
|
||||
ip = &sp->io[s];
|
||||
((struct io_desc *)data)->flags = ip->flags;
|
||||
((struct io_desc *)data)->start = ip->start;
|
||||
((struct io_desc *)data)->size = ip->size;
|
||||
break;
|
||||
/*
|
||||
* Set I/O port context.
|
||||
*/
|
||||
case PIOCSIO:
|
||||
if (suser(p->p_ucred, &p->p_acflag))
|
||||
return(EPERM);
|
||||
if (sp->state != filled)
|
||||
return(ENXIO);
|
||||
s = ((struct io_desc *)data)->window;
|
||||
if (s < 0 || s >= sp->cinfo->maxio)
|
||||
return(EINVAL);
|
||||
sp->io[s] = *((struct io_desc *)data);
|
||||
return(sp->cinfo->mapio(sp, s));
|
||||
break;
|
||||
/*
|
||||
* Set memory window flags for read/write interface.
|
||||
*/
|
||||
case PIOCRWFLAG:
|
||||
sp->rwmem = *(int *)data;
|
||||
break;
|
||||
/*
|
||||
* Set the memory window to be used for the read/write
|
||||
* interface.
|
||||
*/
|
||||
case PIOCRWMEM:
|
||||
if (*(unsigned long *)data == 0)
|
||||
{
|
||||
if (pccard_mem)
|
||||
*(unsigned long *)data = pccard_mem;
|
||||
break;
|
||||
}
|
||||
if (suser(p->p_ucred, &p->p_acflag))
|
||||
return(EPERM);
|
||||
/*
|
||||
* Validate the memory by checking it against the
|
||||
* I/O memory range. It must also start on an aligned block size.
|
||||
*/
|
||||
if (invalid_io_memory(*(unsigned long *)data, PCCARD_MEMSIZE))
|
||||
return(EINVAL);
|
||||
if (*(unsigned long *)data & (PCCARD_MEMSIZE-1))
|
||||
return(EINVAL);
|
||||
/*
|
||||
* Map it to kernel VM.
|
||||
*/
|
||||
pccard_mem = *(unsigned long *)data;
|
||||
pccard_kmem = (unsigned char *)(pccard_mem
|
||||
+ atdevbase - 0xA0000);
|
||||
break;
|
||||
/*
|
||||
* Set power values
|
||||
*/
|
||||
case PIOCSPOW:
|
||||
sp->pwr = *(struct power *)data;
|
||||
return(sp->cinfo->power(sp));
|
||||
/*
|
||||
* Allocate a driver to this slot.
|
||||
*/
|
||||
case PIOCSDRV:
|
||||
if (suser(p->p_ucred, &p->p_acflag))
|
||||
return(EPERM);
|
||||
return(allocate_driver(sp, (struct drv_desc *)data));
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/*
|
||||
* select - Selects on exceptions will return true
|
||||
* when a change in card status occurs.
|
||||
*/
|
||||
int
|
||||
crdselect(dev_t dev, int rw, struct proc *p)
|
||||
{
|
||||
int s;
|
||||
struct slot *sp = pccard_slots[minor(dev)];
|
||||
|
||||
switch (rw) {
|
||||
case FREAD:
|
||||
return 1;
|
||||
case FWRITE:
|
||||
return 1;
|
||||
/*
|
||||
* select for exception - card event.
|
||||
*/
|
||||
case 0:
|
||||
s = splhigh();
|
||||
if (sp == 0 || sp->laststate != sp->state)
|
||||
{
|
||||
splx(s);
|
||||
return(1);
|
||||
}
|
||||
selrecord(p, &sp->selp);
|
||||
splx(s);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/*
|
||||
* invalid_io_memory - verify that the ISA I/O memory block
|
||||
* is a valid and unallocated address.
|
||||
* A simple check of the range is done, and then a
|
||||
* search of the current devices is done to check for
|
||||
* overlapping regions.
|
||||
*/
|
||||
static int
|
||||
invalid_io_memory(unsigned long adr, int size)
|
||||
{
|
||||
if (adr < 0xC0000 || (adr+size) > 0x100000)
|
||||
return(1);
|
||||
return(0);
|
||||
}
|
||||
static struct pccard_drv *
|
||||
find_driver(char *name)
|
||||
{
|
||||
struct pccard_drv *dp;
|
||||
|
||||
for (dp = drivers; dp; dp = dp->next)
|
||||
if (strcmp(dp->name, name)==0)
|
||||
return(dp);
|
||||
return(0);
|
||||
}
|
||||
|
||||
#endif /* NCRD */
|
||||
761
sys/pccard/pcic.c
Normal file
761
sys/pccard/pcic.c
Normal file
|
|
@ -0,0 +1,761 @@
|
|||
/*
|
||||
* Intel PCIC or compatible Controller driver
|
||||
* May be built using LKM to make a loadable module.
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 1995 Andrew McRae. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef LKM
|
||||
#define NPCIC 1
|
||||
#else
|
||||
#include "pcic.h"
|
||||
#endif
|
||||
|
||||
#if NPCIC > 0
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/sysent.h>
|
||||
#include <sys/exec.h>
|
||||
#include <sys/lkm.h>
|
||||
|
||||
#include <machine/clock.h>
|
||||
|
||||
#include <i386/isa/isa.h>
|
||||
#include <i386/isa/isa_device.h>
|
||||
#include <i386/isa/icu.h>
|
||||
|
||||
#include <pccard/i82365.h>
|
||||
#include <pccard/card.h>
|
||||
#include <pccard/slot.h>
|
||||
|
||||
/*
|
||||
* Prototypes for interrupt handler.
|
||||
*/
|
||||
static void pcicintr __P((int unit));
|
||||
static int pcic_ioctl __P((struct slot *, int, caddr_t));
|
||||
static int pcic_power __P((struct slot *));
|
||||
static void pcic_reset __P((struct slot *));
|
||||
static void pcic_disable __P((struct slot *));
|
||||
static void pcic_mapirq __P((struct slot *, int));
|
||||
|
||||
/*
|
||||
* Per-slot data table.
|
||||
*/
|
||||
static struct pcic_slot
|
||||
{
|
||||
int slot; /* My slot number */
|
||||
int index; /* Index register */
|
||||
int data; /* Data register */
|
||||
int offset; /* Offset value for index */
|
||||
char controller; /* Device type */
|
||||
char revision; /* Device Revision */
|
||||
struct slot *sp; /* Back ptr to slot */
|
||||
} pcic_slots[PCIC_MAX_SLOTS];
|
||||
static int pcic_irq;
|
||||
static unsigned long pcic_imask;
|
||||
static struct slot_cont cinfo;
|
||||
|
||||
static int pcic_memory(struct slot *, int);
|
||||
static int pcic_io(struct slot *, int);
|
||||
int pcic_probe();
|
||||
|
||||
/*
|
||||
* Internal inline functions for accessing the PCIC.
|
||||
*/
|
||||
/*
|
||||
* Read a register from the PCIC.
|
||||
*/
|
||||
static inline unsigned char
|
||||
getb (struct pcic_slot *sp, int reg)
|
||||
{
|
||||
outb (sp->index, sp->offset + reg);
|
||||
return inb (sp->data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a register on the PCIC
|
||||
*/
|
||||
static inline void
|
||||
putb (struct pcic_slot *sp, int reg, unsigned char val)
|
||||
{
|
||||
outb (sp->index, sp->offset + reg);
|
||||
outb (sp->data, val);
|
||||
}
|
||||
/*
|
||||
* Clear bit(s) of a register.
|
||||
*/
|
||||
static inline void
|
||||
clrb(struct pcic_slot *sp, int reg, unsigned char mask)
|
||||
{
|
||||
putb (sp, reg, getb (sp, reg) & ~mask);
|
||||
}
|
||||
/*
|
||||
* Set bit(s) of a register
|
||||
*/
|
||||
static inline void
|
||||
setb(struct pcic_slot *sp, int reg, unsigned char mask)
|
||||
{
|
||||
putb (sp, reg, getb (sp, reg) | mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write a 16 bit value to 2 adjacent PCIC registers
|
||||
*/
|
||||
static inline void
|
||||
putw (struct pcic_slot *sp, int reg, unsigned short word)
|
||||
{
|
||||
putb (sp, reg, word & 0xFF);
|
||||
putb (sp, reg + 1, (word >> 8) & 0xff);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get a 16 bit value
|
||||
*/
|
||||
static unsigned short
|
||||
getw (struct pcic_slot *sp, int reg)
|
||||
{
|
||||
return (getb(sp, reg) | (getb(sp, reg+1) << 8));
|
||||
}
|
||||
/*
|
||||
* Loadable kernel module interface.
|
||||
*/
|
||||
#ifdef LKM
|
||||
/*
|
||||
* This defines the lkm_misc module use by modload
|
||||
* to define the module name.
|
||||
*/
|
||||
MOD_MISC( "pcic")
|
||||
|
||||
|
||||
static int pcic_unload();
|
||||
/*
|
||||
* Module handler that processes loads and unloads.
|
||||
* Once the module is loaded, the probe routine
|
||||
* is called to install the slots (if any).
|
||||
*/
|
||||
|
||||
static int
|
||||
pcic_handle( lkmtp, cmd)
|
||||
struct lkm_table *lkmtp;
|
||||
int cmd;
|
||||
{
|
||||
int i;
|
||||
struct lkm_misc *args = lkmtp->private.lkm_misc;
|
||||
int err = 0; /* default = success*/
|
||||
|
||||
switch( cmd) {
|
||||
case LKM_E_LOAD:
|
||||
|
||||
/*
|
||||
* Don't load twice! (lkmexists() is exported by kern_lkm.c)
|
||||
*/
|
||||
if( lkmexists( lkmtp))
|
||||
return( EEXIST);
|
||||
/*
|
||||
* Call the probe routine to find the slots. If
|
||||
* no slots exist, then don't bother loading the module.
|
||||
*/
|
||||
if (pcic_probe() == 0)
|
||||
return(ENODEV);
|
||||
break; /* Success*/
|
||||
/*
|
||||
* Attempt to unload the slot driver.
|
||||
*/
|
||||
case LKM_E_UNLOAD:
|
||||
printf("Unloading PCIC driver\n");
|
||||
err = pcic_unload();
|
||||
break; /* Success*/
|
||||
|
||||
default: /* we only understand load/unload*/
|
||||
err = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return( err);
|
||||
}
|
||||
|
||||
/*
|
||||
* External entry point; should generally match name of .o file. The
|
||||
* arguments are always the same for all loaded modules. The "load",
|
||||
* "unload", and "stat" functions in "DISPATCH" will be called under
|
||||
* their respective circumstances unless their value is "nosys". If
|
||||
* called, they are called with the same arguments (cmd is included to
|
||||
* allow the use of a single function, ver is included for version
|
||||
* matching between modules and the kernel loader for the modules).
|
||||
*
|
||||
* Since we expect to link in the kernel and add external symbols to
|
||||
* the kernel symbol name space in a future version, generally all
|
||||
* functions used in the implementation of a particular module should
|
||||
* be static unless they are expected to be seen in other modules or
|
||||
* to resolve unresolved symbols alread existing in the kernel (the
|
||||
* second case is not likely to ever occur).
|
||||
*
|
||||
* The entry point should return 0 unless it is refusing load (in which
|
||||
* case it should return an errno from errno.h).
|
||||
*/
|
||||
int
|
||||
lkm_pcic(lkmtp, cmd, ver)
|
||||
struct lkm_table *lkmtp;
|
||||
int cmd;
|
||||
int ver;
|
||||
{
|
||||
DISPATCH(lkmtp,cmd,ver,pcic_handle,pcic_handle,nosys)
|
||||
}
|
||||
/*
|
||||
* pcic_unload - Called when unloading a LKM.
|
||||
* Disables interrupts and resets PCIC.
|
||||
*/
|
||||
static int
|
||||
pcic_unload()
|
||||
{
|
||||
int slot;
|
||||
struct pcic_slot *cp = pcic_slots;
|
||||
|
||||
if (pcic_irq)
|
||||
{
|
||||
for (slot = 0; slot < PCIC_MAX_SLOTS; slot++, cp++)
|
||||
if (cp->sp)
|
||||
putb(cp, PCIC_STAT_INT, 0);
|
||||
unregister_intr(pcic_irq, pcicintr);
|
||||
}
|
||||
pccard_remove_controller(&cinfo);
|
||||
return(0);
|
||||
}
|
||||
#endif LKM
|
||||
|
||||
static void
|
||||
pcic_print_regs (struct pcic_slot *sp)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < PCIC_SLOT_SIZE; i += 16) {
|
||||
for (j = 0; j < 16; ++j)
|
||||
printf ("%02x ", getb (sp, i + j));
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
static void
|
||||
pcic_dump_attributes (unsigned char *scratch, int maxlen)
|
||||
{
|
||||
int i,j,k;
|
||||
|
||||
i = 0;
|
||||
while (scratch[i] != 0xff && i < maxlen) {
|
||||
unsigned char link = scratch[i+2];
|
||||
|
||||
/*
|
||||
* Dump attribute memory
|
||||
*/
|
||||
if (scratch[i])
|
||||
{
|
||||
printf ("[%02x] ", i);
|
||||
for (j = 0; j < 2 * link + 4 && j < 128; j += 2)
|
||||
printf ("%02x ", scratch[j + i]);
|
||||
printf ("\n");
|
||||
}
|
||||
i += 4 + 2 * link;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* entry point from main code to map/unmap memory context.
|
||||
*/
|
||||
static int
|
||||
pcic_memory(struct slot *sp, int win)
|
||||
{
|
||||
struct pcic_slot *cp = sp->cdata;
|
||||
struct mem_desc *mp = &sp->mem[win];
|
||||
int reg = mp->window * PCIC_MEMSIZE + PCIC_MEMBASE;
|
||||
|
||||
if (mp->flags & MDF_ACTIVE)
|
||||
{
|
||||
unsigned long sys_addr = (unsigned long)mp->start >> 12;
|
||||
/*
|
||||
* Write the addresses, card offsets and length.
|
||||
* The values are all stored as the upper 12 bits of the
|
||||
* 24 bit address i.e everything is allocated as 4 Kb chunks.
|
||||
*/
|
||||
putw (cp, reg, sys_addr & 0xFFF);
|
||||
putw (cp, reg+2, (sys_addr + (mp->size >> 12) - 1) & 0xFFF);
|
||||
putw (cp, reg+4, ((mp->card >> 12) - sys_addr) & 0x3FFF);
|
||||
#if 0
|
||||
printf("card offs = 0x%x, sys_addr = 0x%x\n", ((mp->card >> 12) - sys_addr) & 0x3FFF, sys_addr);
|
||||
#endif
|
||||
/*
|
||||
* Each 16 bit register has some flags in the upper bits.
|
||||
*/
|
||||
if (mp->flags & MDF_16BITS)
|
||||
setb(cp, reg+1, PCIC_DATA16);
|
||||
if (mp->flags & MDF_ZEROWS)
|
||||
setb(cp, reg+1, PCIC_ZEROWS);
|
||||
if (mp->flags & MDF_WS0)
|
||||
setb(cp, reg+3, PCIC_MW0);
|
||||
if (mp->flags & MDF_WS1)
|
||||
setb(cp, reg+3, PCIC_MW1);
|
||||
if (mp->flags & MDF_ATTR)
|
||||
setb(cp, reg+5, PCIC_REG);
|
||||
if (mp->flags & MDF_WP)
|
||||
setb(cp, reg+5, PCIC_WP);
|
||||
#if 0
|
||||
printf("Slot number %d, reg 0x%x, offs 0x%x\n",
|
||||
cp->slot, reg, cp->offset);
|
||||
printf("Map window to sys addr 0x%x for %d bytes, card 0x%x\n",
|
||||
mp->start, mp->size, mp->card);
|
||||
printf("regs are: 0x%02x%02x 0x%02x%02x 0x%02x%02x flags 0x%x\n",
|
||||
getb(cp, reg), getb(cp, reg+1),
|
||||
getb(cp, reg+2), getb(cp, reg+3),
|
||||
getb(cp, reg+4), getb(cp, reg+5),
|
||||
mp->flags);
|
||||
#endif
|
||||
/*
|
||||
* Enable the memory window. By experiment, we need a delay.
|
||||
*/
|
||||
setb (cp, PCIC_ADDRWINE, (1<<win) | PCIC_MEMCS16);
|
||||
DELAY(50);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 0
|
||||
printf("Unmapping window %d\n", win);
|
||||
#endif
|
||||
clrb (cp, PCIC_ADDRWINE, 1<<win);
|
||||
putw (cp, reg, 0);
|
||||
putw (cp, reg+2, 0);
|
||||
putw (cp, reg+4, 0);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/*
|
||||
* pcic_io - map or unmap I/O context
|
||||
*/
|
||||
static int
|
||||
pcic_io(struct slot *sp, int win)
|
||||
{
|
||||
int mask, reg;
|
||||
struct pcic_slot *cp = sp->cdata;
|
||||
struct io_desc *ip = &sp->io[win];
|
||||
|
||||
if (win)
|
||||
{
|
||||
mask = PCIC_IO0_EN;
|
||||
reg = PCIC_IO0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask = PCIC_IO1_EN;
|
||||
reg = PCIC_IO1;
|
||||
}
|
||||
if (ip->flags & IODF_ACTIVE)
|
||||
{
|
||||
unsigned char x = 0;
|
||||
|
||||
putw (cp, reg, ip->start);
|
||||
putw (cp, reg+2, ip->start+ip->size-1);
|
||||
if (ip->flags & IODF_ZEROWS)
|
||||
x = PCIC_IO_0WS;
|
||||
if (ip->flags & IODF_WS)
|
||||
x |= PCIC_IO_WS;
|
||||
if (ip->flags & IODF_CS16)
|
||||
x |= PCIC_IO_CS16;
|
||||
else if (ip->flags & IODF_16BIT)
|
||||
x |= PCIC_IO_16BIT;
|
||||
/*
|
||||
* Extract the current flags and merge with new flags.
|
||||
* Flags for window 0 in lower nybble, and in upper nybble
|
||||
* for window 1.
|
||||
*/
|
||||
if (win)
|
||||
putb(cp, PCIC_IOCTL, (x << 4) |
|
||||
(getb(cp, PCIC_IOCTL) & 0xF));
|
||||
else
|
||||
putb(cp, PCIC_IOCTL, x | (getb(cp, PCIC_IOCTL) & 0xF0));
|
||||
setb (cp, PCIC_ADDRWINE, mask);
|
||||
DELAY(100);
|
||||
}
|
||||
else
|
||||
{
|
||||
clrb (cp, PCIC_ADDRWINE, mask);
|
||||
putw (cp, reg, 0);
|
||||
putw (cp, reg + 2, 0);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/*
|
||||
* Look for an Intel PCIC (or compatible).
|
||||
* For each available slot, allocate a PC-CARD slot.
|
||||
*/
|
||||
|
||||
int
|
||||
pcic_probe ()
|
||||
{
|
||||
int slot, i, validslots = 0;
|
||||
struct slot *sp;
|
||||
struct pcic_slot *cp;
|
||||
unsigned char c;
|
||||
|
||||
/*
|
||||
* Initialise controller information structure.
|
||||
*/
|
||||
cinfo.mapmem = pcic_memory;
|
||||
cinfo.mapio = pcic_io;
|
||||
cinfo.ioctl = pcic_ioctl;
|
||||
cinfo.power = pcic_power;
|
||||
cinfo.mapirq = pcic_mapirq;
|
||||
cinfo.reset = pcic_reset;
|
||||
cinfo.disable = pcic_disable;
|
||||
cinfo.maxmem = PCIC_MEM_WIN;
|
||||
cinfo.maxio = PCIC_IO_WIN;
|
||||
cinfo.irqs = PCIC_INT_MASK_ALLOWED;
|
||||
|
||||
#ifdef LKM
|
||||
bzero(pcic_slots, sizeof(pcic_slots));
|
||||
#endif
|
||||
cp = pcic_slots;
|
||||
for (slot = 0; slot < PCIC_MAX_SLOTS; slot++, cp++) {
|
||||
/*
|
||||
* Initialise the PCIC slot table.
|
||||
*/
|
||||
if (slot < 4)
|
||||
{
|
||||
cp->index = PCIC_INDEX_0;
|
||||
cp->data = PCIC_DATA_0;
|
||||
cp->offset = slot * PCIC_SLOT_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
cp->index = PCIC_INDEX_1;
|
||||
cp->data = PCIC_DATA_1;
|
||||
cp->offset = (slot - 4) * PCIC_SLOT_SIZE;
|
||||
}
|
||||
/*
|
||||
* see if there's a PCMCIA controller here
|
||||
* Intel PCMCIA controllers use 0x82 and 0x83
|
||||
* IBM clone chips use 0x88 and 0x89, apparently
|
||||
*/
|
||||
c = getb (cp, PCIC_ID_REV);
|
||||
cp->revision = -1;
|
||||
switch(c)
|
||||
{
|
||||
/*
|
||||
* 82365 or clones.
|
||||
*/
|
||||
case 0x82:
|
||||
case 0x83:
|
||||
cp->controller = PCIC_I82365;
|
||||
cp->revision = c & 1;
|
||||
/*
|
||||
* Now check for VADEM chips.
|
||||
*/
|
||||
outb(cp->index, 0x0E);
|
||||
outb(cp->index, 0x37);
|
||||
setb(cp, 0x3A, 0x40);
|
||||
c = getb (cp, PCIC_ID_REV);
|
||||
if (c & 0x08)
|
||||
{
|
||||
cp->controller = PCIC_VG468;
|
||||
cp->revision = c & 7;
|
||||
clrb(cp, 0x3A, 0x40);
|
||||
}
|
||||
break;
|
||||
/*
|
||||
* VLSI chips.
|
||||
*/
|
||||
case 0x84:
|
||||
cp->controller = PCIC_VLSI;
|
||||
break;
|
||||
case 0x88:
|
||||
case 0x89:
|
||||
cp->controller = PCIC_IBM;
|
||||
cp->revision = c & 1;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
* Check for Cirrus logic chips.
|
||||
*/
|
||||
putb(cp, 0x1F, 0);
|
||||
c = getb(cp, 0x1F);
|
||||
if ((c & 0xC0) == 0xC0)
|
||||
{
|
||||
c = getb(cp, 0x1F);
|
||||
if ((c & 0xC0) == 0)
|
||||
{
|
||||
if (c & 0x20)
|
||||
cp->controller = PCIC_PD672X;
|
||||
else
|
||||
cp->controller = PCIC_PD6710;
|
||||
cp->revision = 8 - ((c & 0x1F) >> 2);
|
||||
}
|
||||
}
|
||||
switch(cp->controller)
|
||||
{
|
||||
case PCIC_I82365:
|
||||
cinfo.name = "Intel 82365";
|
||||
break;
|
||||
case PCIC_IBM:
|
||||
cinfo.name = "IBM PCIC";
|
||||
break;
|
||||
case PCIC_PD672X:
|
||||
cinfo.name = "Cirrus Logic PD672X";
|
||||
break;
|
||||
case PCIC_PD6710:
|
||||
cinfo.name = "Cirrus Logic PD6710";
|
||||
break;
|
||||
case PCIC_VG468:
|
||||
cinfo.name = "Vadem 468";
|
||||
break;
|
||||
default:
|
||||
cinfo.name = "Unknown!";
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* clear out the registers.
|
||||
*/
|
||||
for (i = 2; i < 0x40; i++)
|
||||
putb(cp, i, 0);
|
||||
/*
|
||||
* OK it seems we have a PCIC or lookalike.
|
||||
* Allocate a slot and initialise the data structures.
|
||||
*/
|
||||
validslots++;
|
||||
cp->slot = slot;
|
||||
sp = pccard_alloc_slot(&cinfo);
|
||||
if (sp == 0)
|
||||
continue;
|
||||
sp->cdata = cp;
|
||||
cp->sp = sp;
|
||||
/*
|
||||
* If we haven't allocated an interrupt for the controller,
|
||||
* then attempt to get one.
|
||||
*/
|
||||
if (pcic_irq == 0)
|
||||
{
|
||||
pcic_irq = pccard_alloc_intr(PCIC_INT_MASK_ALLOWED,
|
||||
pcicintr, 0, &pcic_imask);
|
||||
#if 0
|
||||
for (try = 0; try < 16; try++)
|
||||
if (((1 << try) & PCIC_INT_MASK_ALLOWED) &&
|
||||
!pccard_alloc_intr(try, pcicintr, 0, &tty_imask))
|
||||
{
|
||||
pcic_irq = try;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (pcic_irq < 0)
|
||||
printf("pcic: failed to allocate IRQ\n");
|
||||
}
|
||||
/*
|
||||
* Check for a card in this slot.
|
||||
*/
|
||||
setb (cp, PCIC_POWER, PCIC_APSENA | PCIC_DISRST);
|
||||
if ((getb (cp, PCIC_STATUS) & PCIC_CD) != PCIC_CD)
|
||||
sp->laststate = sp->state = empty;
|
||||
else
|
||||
{
|
||||
sp->laststate = sp->state = filled;
|
||||
pccard_event(cp->sp, card_inserted);
|
||||
}
|
||||
/*
|
||||
* Assign IRQ for slot changes
|
||||
*/
|
||||
if (pcic_irq > 0)
|
||||
putb(cp, PCIC_STAT_INT, (pcic_irq << 4) | 0xF);
|
||||
}
|
||||
return(validslots);
|
||||
}
|
||||
/*
|
||||
* ioctl calls - Controller specific ioctls
|
||||
*/
|
||||
static int
|
||||
pcic_ioctl(struct slot *sp, int cmd, caddr_t data)
|
||||
{
|
||||
int s;
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
default:
|
||||
return(EINVAL);
|
||||
/*
|
||||
* Get/set PCIC registers
|
||||
*/
|
||||
case PIOCGREG:
|
||||
((struct pcic_reg *)data)->value =
|
||||
getb(sp->cdata, ((struct pcic_reg *)data)->reg);
|
||||
break;
|
||||
case PIOCSREG:
|
||||
putb(sp->cdata, ((struct pcic_reg *)data)->reg,
|
||||
((struct pcic_reg *)data)->value);
|
||||
break;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
/*
|
||||
* pcic_power - Enable the power of the slot according to
|
||||
* the parameters in the power structure(s).
|
||||
*/
|
||||
static int
|
||||
pcic_power(struct slot *slotp)
|
||||
{
|
||||
unsigned char reg = PCIC_DISRST|PCIC_APSENA;
|
||||
struct pcic_slot *sp = slotp->cdata;
|
||||
|
||||
switch(sp->controller)
|
||||
{
|
||||
case PCIC_PD672X:
|
||||
case PCIC_PD6710:
|
||||
switch(slotp->pwr.vpp)
|
||||
{
|
||||
default:
|
||||
return(EINVAL);
|
||||
case 0:
|
||||
break;
|
||||
case 50:
|
||||
case 33:
|
||||
reg |= PCIC_VPP_5V;
|
||||
break;
|
||||
case 120:
|
||||
reg |= PCIC_VPP_12V;
|
||||
break;
|
||||
}
|
||||
switch(slotp->pwr.vcc)
|
||||
{
|
||||
default:
|
||||
return(EINVAL);
|
||||
case 0:
|
||||
break;
|
||||
case 33:
|
||||
reg |= PCIC_VCC_5V;
|
||||
setb(sp, 0x16, 0x02);
|
||||
break;
|
||||
case 50:
|
||||
reg |= PCIC_VCC_5V;
|
||||
clrb(sp, 0x16, 0x02);
|
||||
break;
|
||||
}
|
||||
}
|
||||
putb (sp, PCIC_POWER, reg);
|
||||
DELAY(300*1000);
|
||||
if (slotp->pwr.vcc)
|
||||
{
|
||||
reg |= PCIC_OUTENA;
|
||||
putb (sp, PCIC_POWER, reg);
|
||||
DELAY (100*000);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* tell the PCIC which irq we want to use. only the following are legal:
|
||||
* 3, 4, 5, 7, 9, 10, 11, 12, 14, 15
|
||||
*/
|
||||
static void
|
||||
pcic_mapirq (struct slot *slotp, int irq)
|
||||
{
|
||||
struct pcic_slot *sp = slotp->cdata;
|
||||
|
||||
if (irq == 0)
|
||||
clrb(sp, PCIC_INT_GEN, 0xF);
|
||||
else
|
||||
putb (sp, PCIC_INT_GEN, (getb (sp, PCIC_INT_GEN) & 0xF0) | irq);
|
||||
}
|
||||
/*
|
||||
* pcic_reset - Reset the card and enable initial power.
|
||||
* Allow
|
||||
*/
|
||||
static void
|
||||
pcic_reset(struct slot *slotp)
|
||||
{
|
||||
struct pcic_slot *sp = slotp->cdata;
|
||||
|
||||
clrb (sp, PCIC_INT_GEN, PCIC_CARDRESET);
|
||||
DELAY (200*1000);
|
||||
setb (sp, PCIC_INT_GEN, PCIC_CARDRESET|PCIC_IOCARD);
|
||||
DELAY (200*1000);
|
||||
if (sp->controller == PCIC_PD672X ||
|
||||
sp->controller == PCIC_PD6710)
|
||||
{
|
||||
putb(sp, PCIC_TIME_SETUP0, 0x1);
|
||||
putb(sp, PCIC_TIME_CMD0, 0x6);
|
||||
putb(sp, PCIC_TIME_RECOV0, 0x0);
|
||||
putb(sp, PCIC_TIME_SETUP1, 1);
|
||||
putb(sp, PCIC_TIME_CMD1, 0x5F);
|
||||
putb(sp, PCIC_TIME_RECOV1, 0);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* pcic_disable - Disable the slot.
|
||||
*/
|
||||
static void
|
||||
pcic_disable(struct slot *slotp)
|
||||
{
|
||||
struct pcic_slot *sp = slotp->cdata;
|
||||
|
||||
putb(sp, PCIC_INT_GEN, 0);
|
||||
putb(sp, PCIC_POWER, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* PCIC Interrupt handler.
|
||||
* Check each slot in turn, and read the card status change
|
||||
* register. If this is non-zero, then a change has occurred
|
||||
* on this card, so send an event to the main code.
|
||||
*/
|
||||
static void
|
||||
pcicintr(int unit)
|
||||
{
|
||||
int slot, s;
|
||||
unsigned char chg;
|
||||
struct pcic_slot *cp = pcic_slots;
|
||||
|
||||
s = splhigh();
|
||||
for (slot = 0; slot < PCIC_MAX_SLOTS; slot++, cp++)
|
||||
if (cp->sp)
|
||||
if (chg = getb(cp, PCIC_STAT_CHG))
|
||||
if (chg & PCIC_CDTCH)
|
||||
{
|
||||
if ((getb(cp, PCIC_STATUS) & PCIC_CD) ==
|
||||
PCIC_CD)
|
||||
pccard_event(cp->sp,
|
||||
card_inserted);
|
||||
else
|
||||
pccard_event(cp->sp,
|
||||
card_removed);
|
||||
}
|
||||
splx(s);
|
||||
}
|
||||
#endif
|
||||
189
sys/pccard/skel.c
Normal file
189
sys/pccard/skel.c
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* Loadable kernel module skeleton driver
|
||||
* 11 July 1995 Andrew McRae
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 1995 Andrew McRae. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/sysent.h>
|
||||
#include <sys/exec.h>
|
||||
#include <sys/lkm.h>
|
||||
#include <sys/errno.h>
|
||||
|
||||
#include <pccard/card.h>
|
||||
#include <pccard/slot.h>
|
||||
|
||||
/*
|
||||
* This defines the lkm_misc module use by modload
|
||||
* to define the module name.
|
||||
*/
|
||||
MOD_MISC( "skel")
|
||||
|
||||
|
||||
static int skelintr(struct pccard_dev *); /* Interrupt handler */
|
||||
static void skelunload(struct pccard_dev *); /* Disable driver */
|
||||
static void skelsuspend(struct pccard_dev *); /* Suspend driver */
|
||||
static int skelinit(struct pccard_dev *, int); /* init device */
|
||||
|
||||
static struct pccard_drv skel_info =
|
||||
{
|
||||
"skel",
|
||||
skelintr,
|
||||
skelunload,
|
||||
skelsuspend,
|
||||
skelinit,
|
||||
};
|
||||
static int opened; /* Rather minimal device state... */
|
||||
|
||||
/*
|
||||
* Module handler that processes loads and unloads.
|
||||
* Once the module is loaded, the add driver routine is called
|
||||
* to register the driver.
|
||||
* If an unload is requested the remove driver routine is
|
||||
* called to deregister the driver before unloading.
|
||||
*/
|
||||
static int
|
||||
skel_handle( lkmtp, cmd)
|
||||
struct lkm_table *lkmtp;
|
||||
int cmd;
|
||||
{
|
||||
int i;
|
||||
struct lkm_misc *args = lkmtp->private.lkm_misc;
|
||||
int err = 0; /* default = success*/
|
||||
|
||||
switch( cmd) {
|
||||
case LKM_E_LOAD:
|
||||
|
||||
/*
|
||||
* Don't load twice! (lkmexists() is exported by kern_lkm.c)
|
||||
*/
|
||||
if( lkmexists( lkmtp))
|
||||
return( EEXIST);
|
||||
/*
|
||||
* Now register the driver
|
||||
*/
|
||||
pccard_add_driver(&skel_info);
|
||||
break; /* Success*/
|
||||
/*
|
||||
* Attempt to deregister the driver.
|
||||
*/
|
||||
case LKM_E_UNLOAD:
|
||||
pccard_remove_driver(&skel_info);
|
||||
break; /* Success*/
|
||||
|
||||
default: /* we only understand load/unload*/
|
||||
err = EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return( err);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* External entry point; should generally match name of .o file. The
|
||||
* arguments are always the same for all loaded modules. The "load",
|
||||
* "unload", and "stat" functions in "DISPATCH" will be called under
|
||||
* their respective circumstances unless their value is "nosys". If
|
||||
* called, they are called with the same arguments (cmd is included to
|
||||
* allow the use of a single function, ver is included for version
|
||||
* matching between modules and the kernel loader for the modules).
|
||||
*
|
||||
* Since we expect to link in the kernel and add external symbols to
|
||||
* the kernel symbol name space in a future version, generally all
|
||||
* functions used in the implementation of a particular module should
|
||||
* be static unless they are expected to be seen in other modules or
|
||||
* to resolve unresolved symbols alread existing in the kernel (the
|
||||
* second case is not likely to ever occur).
|
||||
*
|
||||
* The entry point should return 0 unless it is refusing load (in which
|
||||
* case it should return an errno from errno.h).
|
||||
*/
|
||||
int
|
||||
lkm_skel(lkmtp, cmd, ver)
|
||||
struct lkm_table *lkmtp;
|
||||
int cmd;
|
||||
int ver;
|
||||
{
|
||||
DISPATCH(lkmtp,cmd,ver,skel_handle,skel_handle,nosys)
|
||||
}
|
||||
/*
|
||||
* Skeleton driver entry points for PCCARD configuration.
|
||||
*/
|
||||
/*
|
||||
* The device entry is being removed. Shut it down,
|
||||
* and turn off interrupts etc. Not called unless
|
||||
* the device was successfully installed.
|
||||
*/
|
||||
static void
|
||||
skelunload(struct pccard_dev *dp)
|
||||
{
|
||||
printf("skel%d: unload\n", dp->unit);
|
||||
opened &= ~(1 << dp->unit);
|
||||
}
|
||||
/*
|
||||
* Called when a power down is wanted. Shuts down the
|
||||
* device and configures the device as unavailable (but
|
||||
* still loaded...). A resume is done by calling
|
||||
* skelinit with first=0.
|
||||
*/
|
||||
static void
|
||||
skelsuspend(struct pccard_dev *dp)
|
||||
{
|
||||
printf("skel%d: suspending\n", dp->unit);
|
||||
}
|
||||
/*
|
||||
* Initialize the device.
|
||||
* if first is set, then initially check for
|
||||
* the device's existence before initialising it.
|
||||
* Once initialised, the device table may be set up.
|
||||
*/
|
||||
static int
|
||||
skelinit(struct pccard_dev *dp, int first)
|
||||
{
|
||||
if (first && ((1 << dp->unit)&opened))
|
||||
return(EBUSY);
|
||||
if (first)
|
||||
opened |= 1 << dp->unit;
|
||||
printf("skel%d: init, first = %d\n", dp->unit, first);
|
||||
printf("iomem = 0x%x, iobase = 0x%x\n", dp->memory, dp->ioaddr);
|
||||
return(0);
|
||||
}
|
||||
/*
|
||||
* Interrupt handler.
|
||||
* Returns true if the interrupt is for us.
|
||||
*/
|
||||
static int
|
||||
skelintr(struct pccard_dev *dp)
|
||||
{
|
||||
return(0);
|
||||
}
|
||||
128
sys/pccard/slot.h
Normal file
128
sys/pccard/slot.h
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Slot structures for PC-CARD interface.
|
||||
* Each slot has a controller specific structure
|
||||
* attached to it. A slot number allows
|
||||
* mapping from the character device to the
|
||||
* slot structure. This is separate to the
|
||||
* controller slot number to allow multiple controllers
|
||||
* to be accessed.
|
||||
*-------------------------------------------------------------------------
|
||||
*
|
||||
* Copyright (c) 1995 Andrew McRae. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
/*
|
||||
* Controller data - Specific to each slot controller.
|
||||
*/
|
||||
struct slot_cont
|
||||
{
|
||||
int (*mapmem)(); /* Map memory */
|
||||
int (*mapio)(); /* Map io */
|
||||
void (*reset)(); /* init */
|
||||
void (*disable)(); /* Disable slot */
|
||||
int (*power)(); /* Set power values */
|
||||
int (*ioctl)(); /* ioctl to lower level */
|
||||
void (*mapirq)(); /* Map interrupt number */
|
||||
int extra; /* Controller specific size */
|
||||
int maxmem; /* Number of allowed memory windows */
|
||||
int maxio; /* Number of allowed I/O windows */
|
||||
int irqs; /* IRQ's that are allowed */
|
||||
char *name; /* controller name */
|
||||
/*
|
||||
* The rest is maintained by the mainline PC-CARD code.
|
||||
*/
|
||||
|
||||
struct slot_cont *next; /* Allows linked list of controllers */
|
||||
int slots; /* Slots available */
|
||||
};
|
||||
/*
|
||||
* Driver structure - each driver registers itself
|
||||
* with the mainline PC-CARD code. These drivers are
|
||||
* then available for linking to the devices.
|
||||
*/
|
||||
struct pccard_dev;
|
||||
|
||||
struct pccard_drv
|
||||
{
|
||||
char *name; /* Driver name */
|
||||
int (*handler)(struct pccard_dev *); /* Interrupt handler */
|
||||
void (*unload)(struct pccard_dev *); /* Disable driver */
|
||||
void (*suspend)(struct pccard_dev *); /* Suspend driver */
|
||||
int (*init)(struct pccard_dev *, int); /* init device */
|
||||
int attr; /* driver attributes */
|
||||
unsigned int *imask; /* Interrupt mask ptr */
|
||||
|
||||
struct pccard_drv *next;
|
||||
};
|
||||
/*
|
||||
* Device structure for cards. Each card may have one
|
||||
* or more drivers attached to it; each driver is assumed
|
||||
* to require at most one interrupt handler, one I/O block
|
||||
* and one memory block. This structure is used to link the different
|
||||
* devices together.
|
||||
*/
|
||||
struct pccard_dev
|
||||
{
|
||||
struct pccard_dev *next; /* List of drivers */
|
||||
struct isa_device isahd; /* Device details */
|
||||
struct pccard_drv *drv;
|
||||
void *arg; /* Device argument */
|
||||
struct slot *sp; /* Back pointer to slot */
|
||||
int running; /* Current state of driver */
|
||||
};
|
||||
|
||||
/*
|
||||
* Per-slot structure.
|
||||
*/
|
||||
struct slot
|
||||
{
|
||||
struct slot *next; /* Master list */
|
||||
int slot; /* Slot number */
|
||||
int flags; /* Slot flags (see below) */
|
||||
int rwmem; /* Read/write flags */
|
||||
int ex_sel; /* PID for select */
|
||||
int irq; /* IRQ allocated (0 = none) */
|
||||
int irqref; /* Reference count of driver IRQs */
|
||||
struct pccard_dev *devices; /* List of drivers attached */
|
||||
/*
|
||||
* flags.
|
||||
*/
|
||||
unsigned int insert_timeout:1; /* Insert timeout active */
|
||||
|
||||
enum cardstate state, laststate; /* Current/last card states */
|
||||
struct selinfo selp; /* Info for select */
|
||||
struct mem_desc mem[NUM_MEM_WINDOWS]; /* Memory windows */
|
||||
struct io_desc io[NUM_IO_WINDOWS]; /* I/O windows */
|
||||
struct power pwr; /* Power values */
|
||||
struct slot_cont *cinfo; /* Per-controller data */
|
||||
void *cdata; /* Controller specific data */
|
||||
};
|
||||
|
||||
enum card_event { card_removed, card_inserted };
|
||||
|
||||
struct slot *pccard_alloc_slot(struct slot_cont *);
|
||||
void pccard_event(struct slot *, enum card_event);
|
||||
void pccard_remove_controller(struct slot_cont *);
|
||||
int pccard_alloc_intr();
|
||||
void pccard_add_driver(struct pccard_drv *);
|
||||
Loading…
Reference in a new issue