Mercurial > ecos
diff packages/devs/pcmcia/arm/assabet/current/src/assabet_pcmcia.c @ 115:6ed91473a1cd ecos-sw-2000-08-21
Merge from eCos master repository on 2000-08-21-22:40:54-BST
| author | jlarmour |
|---|---|
| date | Fri, 25 Aug 2000 17:32:38 +0000 |
| parents | |
| children | bd1a71e3e476 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/devs/pcmcia/arm/assabet/current/src/assabet_pcmcia.c @@ -0,0 +1,238 @@ +//========================================================================== +// +// devs/pcmcia/assabet/assabet_pcmcia.c +// +// PCMCIA support (Card Services) +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Red Hat eCos Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.redhat.com/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Configurable Operating System, +// released September 30, 1998. +// +// The Initial Developer of the Original Code is Red Hat. +// Portions created by Red Hat are +// Copyright (C) 1998, 1999, 2000 Red Hat, Inc. +// All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): gthomas +// Contributors: gthomas +// Date: 2000-07-06 +// Purpose: PCMCIA support +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#include <pkgconf/io_pcmcia.h> + +#include <cyg/hal/hal_io.h> // IO macros +#include <cyg/hal/hal_arch.h> // Register state info +#include <cyg/hal/hal_intr.h> // HAL interrupt macros + +#ifdef CYGPKG_KERNEL +#include <pkgconf/kernel.h> // Configuration header +#include <cyg/kernel/kapi.h> +#else +#include <cyg/hal/hal_if.h> +#endif + +#include <cyg/io/pcmcia.h> +#include <cyg/infra/diag.h> + +#include <cyg/hal/hal_sa11x0.h> // Board definitions +#include <cyg/hal/assabet.h> + +#ifdef CYGPKG_KERNEL +static cyg_interrupt cf_detect_interrupt; +static cyg_handle_t cf_detect_interrupt_handle; +static cyg_interrupt cf_irq_interrupt; +static cyg_handle_t cf_irq_interrupt_handle; + +// This ISR is called when a CompactFlash board is inserted +static int +cf_detect_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs) +{ + cyg_interrupt_mask(SA1110_CF_DETECT); + return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Run the DSR +} + +// This DSR handles the board insertion +static void +cf_detect_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + unsigned long new_state = *SA11X0_GPIO_PIN_LEVEL; + struct cf_slot *slot = (struct cf_slot *)data; + if ((new_state & SA1110_GPIO_CF_DETECT) == SA1110_GPIO_CF_PRESENT) { + slot->state = CF_SLOT_STATE_Inserted; + } else { + slot->state = CF_SLOT_STATE_Removed; // Implies powered up, etc. + } + cyg_interrupt_acknowledge(SA1110_CF_DETECT); + cyg_interrupt_unmask(SA1110_CF_DETECT); +} + +// This ISR is called when the card interrupt occurs +static int +cf_irq_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs) +{ + cyg_drv_interrupt_mask(SA1110_CF_IRQ); + return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Run the DSR +} + +// This DSR handles the card interrupt +static void +cf_irq_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + struct cf_slot *slot = (struct cf_slot *)data; + // Clear interrupt [edge indication] + cyg_drv_interrupt_acknowledge(SA1110_CF_IRQ); + // Process interrupt + (slot->irq_handler.handler)(slot->irq_handler.param); + // Allow interrupts to happen again + cyg_drv_interrupt_unmask(SA1110_CF_IRQ); +} +#endif + +// +// Fill in the details of a PCMCIA slot and initialize the device +// +void +cf_hwr_init(struct cf_slot *slot) +{ + static int int_init = 0; + unsigned long new_state = *SA11X0_GPIO_PIN_LEVEL; + if (!int_init) { + int_init = 1; +#ifdef CYGPKG_KERNEL + // Set up interrupts + cyg_interrupt_create(SA1110_CF_DETECT, + 99, // Priority - what goes here? + (cyg_addrword_t) slot, // Data item passed to interrupt handler + (cyg_ISR_t *)cf_detect_isr, + (cyg_DSR_t *)cf_detect_dsr, + &cf_detect_interrupt_handle, + &cf_detect_interrupt); + cyg_interrupt_attach(cf_detect_interrupt_handle); + cyg_interrupt_configure(SA1110_CF_DETECT, true, true); // Detect either edge + cyg_interrupt_acknowledge(SA1110_CF_DETECT); + cyg_interrupt_unmask(SA1110_CF_DETECT); + cyg_interrupt_create(SA1110_CF_IRQ, + 99, // Priority - what goes here? + (cyg_addrword_t) slot, // Data item passed to interrupt handler + (cyg_ISR_t *)cf_irq_isr, + (cyg_DSR_t *)cf_irq_dsr, + &cf_irq_interrupt_handle, + &cf_irq_interrupt); + cyg_interrupt_attach(cf_irq_interrupt_handle); + cyg_interrupt_configure(SA1110_CF_IRQ, false, false); // Falling edge + cyg_interrupt_acknowledge(SA1110_CF_IRQ); + cyg_interrupt_unmask(SA1110_CF_IRQ); +#endif + } + slot->attr = (unsigned char *)0x38000000; + slot->attr_length = 0x200; + slot->io = (unsigned char *)0x30000000; + slot->io_length = 0x04000000; + slot->mem = (unsigned char *)0x3C000000; + slot->mem_length = 0x04000000; + slot->int_num = SA1110_CF_IRQ; + // Disable CF bus & power (idle/off) + assabet_BCR(SA1110_BCR_CF_POWER | + SA1110_BCR_CF_RESET | + SA1110_BCR_CF_BUS, + SA1110_BCR_CF_POWER_OFF | + SA1110_BCR_CF_RESET_DISABLE | + SA1110_BCR_CF_BUS_OFF); + if ((new_state & SA1110_GPIO_CF_DETECT) == SA1110_GPIO_CF_PRESENT) { + slot->state = CF_SLOT_STATE_Inserted; + } else { + slot->state = CF_SLOT_STATE_Empty; + } +} + +void +cf_hwr_poll(struct cf_slot *slot) +{ + unsigned long new_state = *SA11X0_GPIO_PIN_LEVEL; + if ((new_state & SA1110_GPIO_CF_DETECT) == SA1110_GPIO_CF_PRESENT) { + slot->state = CF_SLOT_STATE_Inserted; + } else { + slot->state = CF_SLOT_STATE_Empty; + } +} + +static void +do_delay(int ticks) +{ +#ifdef CYGPKG_KERNEL + cyg_thread_delay(ticks); +#else + CYGACC_CALL_IF_DELAY_US(10000*ticks); +#endif +} + +// +// Transition the card/slot to a new state +// note: currently only supports transitions to Ready, Empty +// +bool +cf_hwr_change_state(struct cf_slot *slot, int new_state) +{ + int i, ptr, len; + unsigned char buf[64]; + + if (new_state == CF_SLOT_STATE_Ready) { + if (slot->state == CF_SLOT_STATE_Inserted) { + assabet_BCR(SA1110_BCR_CF_POWER | + SA1110_BCR_CF_RESET | + SA1110_BCR_CF_BUS, + SA1110_BCR_CF_POWER_ON | + SA1110_BCR_CF_RESET_DISABLE | + SA1110_BCR_CF_BUS_OFF); + do_delay(30); // At least 300 ms + slot->state = CF_SLOT_STATE_Powered; + assabet_BCR(SA1110_BCR_CF_POWER | + SA1110_BCR_CF_RESET | + SA1110_BCR_CF_BUS, + SA1110_BCR_CF_POWER_ON | + SA1110_BCR_CF_RESET_ENABLE | + SA1110_BCR_CF_BUS_ON); + do_delay(1); // At least 10 us + slot->state = CF_SLOT_STATE_Reset; + assabet_BCR(SA1110_BCR_CF_POWER | + SA1110_BCR_CF_RESET | + SA1110_BCR_CF_BUS, + SA1110_BCR_CF_POWER_ON | + SA1110_BCR_CF_RESET_DISABLE | + SA1110_BCR_CF_BUS_ON); + do_delay(5); // At least 20 ms + // Wait until the card is ready to talk + for (i = 0; i < 10; i++) { + ptr = 0; + if (cf_get_CIS(slot, CF_CISTPL_MANFID, buf, &len, &ptr)) { + slot->state = CF_SLOT_STATE_Ready; + break; + } + do_delay(10); + } + } + } +}
