/* sa1100_pcmcia_set_socket() * ^^^^^^^^^^^^^^^^^^^^^^^^^^ * Implements the set_socket() operation for the in-kernel PCMCIA * service (formerly SS_SetSocket in Card Services). We more or * less punt all of this work and let the kernel handle the details * of power configuration, reset, &c. We also record the value of * `state' in order to regurgitate it to the PCMCIA core later. * * Returns: 0 */ static int sa1100_pcmcia_set_socket(unsigned int sock, socket_state_t *state) { struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); struct pcmcia_configure conf; DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); DEBUG(3, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n", (state->csc_mask==0)?"<NONE>":"", (state->csc_mask&SS_DETECT)?"DETECT ":"", (state->csc_mask&SS_READY)?"READY ":"", (state->csc_mask&SS_BATDEAD)?"BATDEAD ":"", (state->csc_mask&SS_BATWARN)?"BATWARN ":"", (state->csc_mask&SS_STSCHG)?"STSCHG ":"", (state->flags==0)?"<NONE>":"", (state->flags&SS_PWR_AUTO)?"PWR_AUTO ":"", (state->flags&SS_IOCARD)?"IOCARD ":"", (state->flags&SS_RESET)?"RESET ":"", (state->flags&SS_SPKR_ENA)?"SPKR_ENA ":"", (state->flags&SS_OUTPUT_ENA)?"OUTPUT_ENA ":""); DEBUG(3, "\tVcc %d Vpp %d irq %d\n", state->Vcc, state->Vpp, state->io_irq); conf = sa1100_pcmcia_state_to_config(sock, state); if (pcmcia_low_level->configure_socket(&conf) < 0) { printk(KERN_ERR "sa1100_pcmcia: unable to configure socket %d\n", sock); return -1; } skt->cs_state = *state; return 0; } /* sa1100_pcmcia_set_socket() */
/* sa1100_pcmcia_set_io_map() * ^^^^^^^^^^^^^^^^^^^^^^^^^^ * Implements the set_io_map() operation for the in-kernel PCMCIA * service (formerly SS_SetIOMap in Card Services). We configure * the map speed as requested, but override the address ranges * supplied by Card Services. * * Returns: 0 on success, -1 on error */ static int sa1100_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map) { struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); DEBUG(3, "\tmap %u speed %u\n\tstart 0x%08x stop 0x%08x\n", map->map, map->speed, map->start, map->stop); DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n", (map->flags==0)?"<NONE>":"", (map->flags&MAP_ACTIVE)?"ACTIVE ":"", (map->flags&MAP_16BIT)?"16BIT ":"", (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", (map->flags&MAP_0WS)?"0WS ":"", (map->flags&MAP_WRPROT)?"WRPROT ":"", (map->flags&MAP_USE_WAIT)?"USE_WAIT ":"", (map->flags&MAP_PREFETCH)?"PREFETCH ":""); if (map->map >= MAX_IO_WIN) { printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, map->map); return -1; } if (map->flags & MAP_ACTIVE) { unsigned int clock, speed = map->speed; unsigned long mecr; if (speed == 0) speed = SA1100_PCMCIA_IO_ACCESS; clock = cpufreq_get(0); mecr = MECR; MECR_BSIO_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock)); skt->speed_io = speed; DEBUG(4, "%s(): FAST%u %lx BSM%u %lx BSA%u %lx BSIO%u %lx\n", __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock, MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), sock, MECR_BSIO_GET(mecr, sock)); MECR = mecr; } if (map->stop == 1) map->stop = PAGE_SIZE-1; map->stop -= map->start; map->stop += (unsigned long)skt->virt_io; map->start = (unsigned long)skt->virt_io; skt->io_map[map->map] = *map; return 0; } /* sa1100_pcmcia_set_io_map() */
/* sa1100_pcmcia_get_status() * ^^^^^^^^^^^^^^^^^^^^^^^^^^ * Implements the get_status() operation for the in-kernel PCMCIA * service (formerly SS_GetStatus in Card Services). Essentially just * fills in bits in `status' according to internal driver state or * the value of the voltage detect chipselect register. * * As a debugging note, during card startup, the PCMCIA core issues * three set_socket() commands in a row the first with RESET deasserted, * the second with RESET asserted, and the last with RESET deasserted * again. Following the third set_socket(), a get_status() command will * be issued. The kernel is looking for the SS_READY flag (see * setup_socket(), reset_socket(), and unreset_socket() in cs.c). * * Returns: 0 */ static int sa1100_pcmcia_get_status(unsigned int sock, unsigned int *status) { struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK]; struct pcmcia_state_array state_array; unsigned int stat; DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); state_array.size = sa1100_pcmcia_socket_count; state_array.state = state; memset(state, 0, sizeof(state)); if ((pcmcia_low_level->socket_state(&state_array)) < 0) { printk(KERN_ERR "sa1100_pcmcia: unable to get socket status\n"); return -1; } skt->k_state = state[sock]; stat = state[sock].detect ? SS_DETECT : 0; stat |= state[sock].ready ? SS_READY : 0; stat |= state[sock].vs_3v ? SS_3VCARD : 0; stat |= state[sock].vs_Xv ? SS_XVCARD : 0; /* The power status of individual sockets is not available * explicitly from the hardware, so we just remember the state * and regurgitate it upon request: */ stat |= skt->cs_state.Vcc ? SS_POWERON : 0; if (skt->cs_state.flags & SS_IOCARD) stat |= state[sock].bvd1 ? SS_STSCHG : 0; else { if (state[sock].bvd1 == 0) stat |= SS_BATDEAD; else if (state[sock].bvd2 == 0) stat |= SS_BATWARN; } DEBUG(3, "\tstatus: %s%s%s%s%s%s%s%s\n", stat & SS_DETECT ? "DETECT " : "", stat & SS_READY ? "READY " : "", stat & SS_BATDEAD ? "BATDEAD " : "", stat & SS_BATWARN ? "BATWARN " : "", stat & SS_POWERON ? "POWERON " : "", stat & SS_STSCHG ? "STSCHG " : "", stat & SS_3VCARD ? "3VCARD " : "", stat & SS_XVCARD ? "XVCARD " : ""); *status = stat; return 0; } /* sa1100_pcmcia_get_status() */
/* sa1100_pcmcia_get_socket() * ^^^^^^^^^^^^^^^^^^^^^^^^^^ * Implements the get_socket() operation for the in-kernel PCMCIA * service (formerly SS_GetSocket in Card Services). Not a very * exciting routine. * * Returns: 0 */ static int sa1100_pcmcia_get_socket(unsigned int sock, socket_state_t *state) { struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); *state = skt->cs_state; return 0; }
/* sa1100_pcmcia_get_mem_map() * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Implements the get_mem_map() operation for the in-kernel PCMCIA * service (formerly SS_GetMemMap in Card Services). Just returns a * memory map descriptor which was assigned earlier by a * set_mem_map() request. * * Returns: 0 on success, -1 if the map index was out of range */ static int sa1100_pcmcia_get_mem_map(unsigned int sock, struct pccard_mem_map *map) { struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); int ret = -1; DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); if (map->map < MAX_WIN) { *map = skt->mem_map[map->map]; ret = 0; } return ret; }
/* sa1100_pcmcia_init() * ^^^^^^^^^^^^^^^^^^^^ * * (Re-)Initialise the socket, turning on status interrupts * and PCMCIA bus. This must wait for power to stabilise * so that the card status signals report correctly. * * Returns: 0 */ static int sa1100_pcmcia_init(unsigned int sock) { struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); struct pcmcia_configure conf; DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock); skt->cs_state = dead_socket; conf = sa1100_pcmcia_state_to_config(sock, &dead_socket); pcmcia_low_level->configure_socket(&conf); return pcmcia_low_level->socket_init(sock); }
/* sa1100_pcmcia_register_callback() * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Implements the register_callback() operation for the in-kernel * PCMCIA service (formerly SS_RegisterCallback in Card Services). If * the function pointer `handler' is not NULL, remember the callback * location in the state for `sock', and increment the usage counter * for the driver module. (The callback is invoked from the interrupt * service routine, sa1100_pcmcia_interrupt(), to notify Card Services * of interesting events.) Otherwise, clear the callback pointer in the * socket state and decrement the module usage count. * * Returns: 0 */ static int sa1100_pcmcia_register_callback(unsigned int sock, void (*handler)(void *, unsigned int), void *info) { struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); if (handler == NULL) { skt->handler = NULL; MOD_DEC_USE_COUNT; } else { MOD_INC_USE_COUNT; skt->handler_info = info; skt->handler = handler; } return 0; }
/* * sa1100_pcmcia_suspend() * ^^^^^^^^^^^^^^^^^^^^^^^ * * Remove power on the socket, disable IRQs from the card. * Turn off status interrupts, and disable the PCMCIA bus. * * Returns: 0 */ static int sa1100_pcmcia_suspend(unsigned int sock) { struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); struct pcmcia_configure conf; int ret; DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, sock); conf = sa1100_pcmcia_state_to_config(sock, &dead_socket); ret = pcmcia_low_level->configure_socket(&conf); if (ret == 0) { skt->cs_state = dead_socket; ret = pcmcia_low_level->socket_suspend(sock); } return ret; }
/* sa1100_pcmcia_inquire_socket() * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Implements the inquire_socket() operation for the in-kernel PCMCIA * service (formerly SS_InquireSocket in Card Services). Of note is * the setting of the SS_CAP_PAGE_REGS bit in the `features' field of * `cap' to "trick" Card Services into tolerating large "I/O memory" * addresses. Also set is SS_CAP_STATIC_MAP, which disables the memory * resource database check. (Mapped memory is set up within the socket * driver itself.) * * In conjunction with the STATIC_MAP capability is a new field, * `io_offset', recommended by David Hinds. Rather than go through * the SetIOMap interface (which is not quite suited for communicating * window locations up from the socket driver), we just pass up * an offset which is applied to client-requested base I/O addresses * in alloc_io_space(). * * SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the * force_low argument to validate_mem() in rsrc_mgr.c -- since in * general, the mapped * addresses of the PCMCIA memory regions * will not be within 0xffff, setting force_low would be * undesirable. * * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory * resource database; we instead pass up physical address ranges * and allow other parts of Card Services to deal with remapping. * * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but * not 32-bit CardBus devices. * * Return value is irrelevant; the pcmcia subsystem ignores it. */ static int sa1100_pcmcia_inquire_socket(unsigned int sock, socket_cap_t *cap) { struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); int ret = -1; DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); if (sock < sa1100_pcmcia_socket_count) { cap->features = SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD; cap->irq_mask = 0; cap->map_size = PAGE_SIZE; cap->pci_irq = skt->irq; cap->io_offset = (unsigned long)skt->virt_io; ret = 0; } return ret; }
/* sa1100_pcmcia_task_handler() * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Processes serviceable socket events using the "eventd" thread context. * * Event processing (specifically, the invocation of the Card Services event * callback) occurs in this thread rather than in the actual interrupt * handler due to the use of scheduling operations in the PCMCIA core. */ static void sa1100_pcmcia_task_handler(void *data) { struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK]; struct pcmcia_state_array state_array; unsigned int all_events; DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__); state_array.size = sa1100_pcmcia_socket_count; state_array.state = state; do { unsigned int events; int ret, i; memset(state, 0, sizeof(state)); DEBUG(4, "%s(): interrogating low-level PCMCIA service\n", __FUNCTION__); ret = pcmcia_low_level->socket_state(&state_array); if (ret < 0) { printk(KERN_ERR "sa1100_pcmcia: unable to read socket status\n"); break; } all_events = 0; for (i = 0; i < state_array.size; i++, all_events |= events) { struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); events = sa1100_pcmcia_events(&state[i], &skt->k_state, skt->cs_state.csc_mask, skt->cs_state.flags); if (events && sa1100_pcmcia_socket[i].handler != NULL) skt->handler(skt->handler_info, events); } } while(all_events); } /* sa1100_pcmcia_task_handler() */
int au1x00_drv_pcmcia_remove(struct platform_device *dev) { struct skt_dev_info *sinfo = platform_get_drvdata(dev); int i; mutex_lock(&pcmcia_sockets_lock); platform_set_drvdata(dev, NULL); for (i = 0; i < sinfo->nskt; i++) { struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i); del_timer_sync(&skt->poll_timer); pcmcia_unregister_socket(&skt->socket); skt->ops->hw_shutdown(skt); au1x00_pcmcia_config_skt(skt, &dead_socket); iounmap(skt->virt_io + (u32)mips_io_port_base); skt->virt_io = NULL; } kfree(sinfo); mutex_unlock(&pcmcia_sockets_lock); return 0; }
int au1x00_drv_pcmcia_remove(struct device *dev) { struct skt_dev_info *sinfo = dev_get_drvdata(dev); int i; down(&pcmcia_sockets_lock); dev_set_drvdata(dev, NULL); for (i = 0; i < sinfo->nskt; i++) { struct au1000_pcmcia_socket *skt = PCMCIA_SOCKET(i); del_timer_sync(&skt->poll_timer); pcmcia_unregister_socket(&skt->socket); flush_scheduled_work(); skt->ops->hw_shutdown(skt); au1x00_pcmcia_config_skt(skt, &dead_socket); iounmap(skt->virt_io); skt->virt_io = NULL; } kfree(sinfo); up(&pcmcia_sockets_lock); return 0; }
int au1x00_pcmcia_socket_probe(struct device *dev, struct pcmcia_low_level *ops, int first, int nr) { struct skt_dev_info *sinfo; struct au1000_pcmcia_socket *skt; int ret, i; sinfo = kzalloc(sizeof(struct skt_dev_info), GFP_KERNEL); if (!sinfo) { ret = -ENOMEM; goto out; } sinfo->nskt = nr; /* * Initialise the per-socket structure. */ for (i = 0; i < nr; i++) { skt = PCMCIA_SOCKET(i); memset(skt, 0, sizeof(*skt)); skt->socket.resource_ops = &pccard_static_ops; skt->socket.ops = &au1x00_pcmcia_operations; skt->socket.owner = ops->owner; skt->socket.dev.parent = dev; init_timer(&skt->poll_timer); skt->poll_timer.function = au1x00_pcmcia_poll_event; skt->poll_timer.data = (unsigned long)skt; skt->poll_timer.expires = jiffies + AU1000_PCMCIA_POLL_PERIOD; skt->nr = first + i; skt->irq = 255; skt->dev = dev; skt->ops = ops; skt->res_skt.name = skt_names[skt->nr]; skt->res_io.name = "io"; skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY; skt->res_mem.name = "memory"; skt->res_mem.flags = IORESOURCE_MEM; skt->res_attr.name = "attribute"; skt->res_attr.flags = IORESOURCE_MEM; /* * PCMCIA client drivers use the inb/outb macros to access the * IO registers. Since mips_io_port_base is added to the * access address of the mips implementation of inb/outb, * we need to subtract it here because we want to access the * I/O or MEM address directly, without going through this * "mips_io_port_base" mechanism. */ if (i == 0) { skt->virt_io = (void *) (ioremap((phys_t)AU1X_SOCK0_IO, 0x1000) - (u32)mips_io_port_base); skt->phys_attr = AU1X_SOCK0_PHYS_ATTR; skt->phys_mem = AU1X_SOCK0_PHYS_MEM; } else { skt->virt_io = (void *) (ioremap((phys_t)AU1X_SOCK1_IO, 0x1000) - (u32)mips_io_port_base); skt->phys_attr = AU1X_SOCK1_PHYS_ATTR; skt->phys_mem = AU1X_SOCK1_PHYS_MEM; } pcmcia_base_vaddrs[i] = (u32 *)skt->virt_io; ret = ops->hw_init(skt); skt->socket.features = SS_CAP_STATIC_MAP|SS_CAP_PCCARD; skt->socket.irq_mask = 0; skt->socket.map_size = MAP_SIZE; skt->socket.pci_irq = skt->irq; skt->socket.io_offset = (unsigned long)skt->virt_io; skt->status = au1x00_pcmcia_skt_state(skt); ret = pcmcia_register_socket(&skt->socket); if (ret) goto out_err; WARN_ON(skt->socket.sock != i); add_timer(&skt->poll_timer); } dev_set_drvdata(dev, sinfo); return 0; out_err: flush_scheduled_work(); ops->hw_shutdown(skt); while (i-- > 0) { skt = PCMCIA_SOCKET(i); del_timer_sync(&skt->poll_timer); pcmcia_unregister_socket(&skt->socket); flush_scheduled_work(); if (i == 0) { iounmap(skt->virt_io + (u32)mips_io_port_base); skt->virt_io = NULL; } #ifndef CONFIG_MIPS_XXS1500 else { iounmap(skt->virt_io + (u32)mips_io_port_base); skt->virt_io = NULL; } #endif ops->hw_shutdown(skt); } kfree(sinfo); out: return ret; }
/* sa1100_pcmcia_proc_status() * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Implements the /proc/bus/pccard/??/status file. * * Returns: the number of characters added to the buffer */ static int sa1100_pcmcia_proc_status(char *buf, char **start, off_t pos, int count, int *eof, void *data) { unsigned int sock = (unsigned int)data; unsigned int clock = cpufreq_get(0); struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); unsigned long mecr = MECR; char *p = buf; p+=sprintf(p, "k_state : %s%s%s%s%s%s%s\n", skt->k_state.detect ? "detect " : "", skt->k_state.ready ? "ready " : "", skt->k_state.bvd1 ? "bvd1 " : "", skt->k_state.bvd2 ? "bvd2 " : "", skt->k_state.wrprot ? "wrprot " : "", skt->k_state.vs_3v ? "vs_3v " : "", skt->k_state.vs_Xv ? "vs_Xv " : ""); p+=sprintf(p, "status : %s%s%s%s%s%s%s%s%s\n", skt->k_state.detect ? "SS_DETECT " : "", skt->k_state.ready ? "SS_READY " : "", skt->cs_state.Vcc ? "SS_POWERON " : "", skt->cs_state.flags & SS_IOCARD ? "SS_IOCARD " : "", (skt->cs_state.flags & SS_IOCARD && skt->k_state.bvd1) ? "SS_STSCHG " : "", ((skt->cs_state.flags & SS_IOCARD)==0 && (skt->k_state.bvd1==0)) ? "SS_BATDEAD " : "", ((skt->cs_state.flags & SS_IOCARD)==0 && (skt->k_state.bvd2==0)) ? "SS_BATWARN " : "", skt->k_state.vs_3v ? "SS_3VCARD " : "", skt->k_state.vs_Xv ? "SS_XVCARD " : ""); p+=sprintf(p, "mask : %s%s%s%s%s\n", skt->cs_state.csc_mask & SS_DETECT ? "SS_DETECT " : "", skt->cs_state.csc_mask & SS_READY ? "SS_READY " : "", skt->cs_state.csc_mask & SS_BATDEAD ? "SS_BATDEAD " : "", skt->cs_state.csc_mask & SS_BATWARN ? "SS_BATWARN " : "", skt->cs_state.csc_mask & SS_STSCHG ? "SS_STSCHG " : ""); p+=sprintf(p, "cs_flags : %s%s%s%s%s\n", skt->cs_state.flags & SS_PWR_AUTO ? "SS_PWR_AUTO " : "", skt->cs_state.flags & SS_IOCARD ? "SS_IOCARD " : "", skt->cs_state.flags & SS_RESET ? "SS_RESET " : "", skt->cs_state.flags & SS_SPKR_ENA ? "SS_SPKR_ENA " : "", skt->cs_state.flags & SS_OUTPUT_ENA ? "SS_OUTPUT_ENA " : ""); p+=sprintf(p, "Vcc : %d\n", skt->cs_state.Vcc); p+=sprintf(p, "Vpp : %d\n", skt->cs_state.Vpp); p+=sprintf(p, "IRQ : %d\n", skt->cs_state.io_irq); p+=sprintf(p, "I/O : %u (%u)\n", skt->speed_io, sa1100_pcmcia_cmd_time(clock, MECR_BSIO_GET(mecr, sock))); p+=sprintf(p, "attribute: %u (%u)\n", skt->speed_attr, sa1100_pcmcia_cmd_time(clock, MECR_BSA_GET(mecr, sock))); p+=sprintf(p, "common : %u (%u)\n", skt->speed_mem, sa1100_pcmcia_cmd_time(clock, MECR_BSM_GET(mecr, sock))); return p-buf; }
/* sa1100_pcmcia_set_mem_map() * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ * Implements the set_mem_map() operation for the in-kernel PCMCIA * service (formerly SS_SetMemMap in Card Services). We configure * the map speed as requested, but override the address ranges * supplied by Card Services. * * Returns: 0 on success, -1 on error */ static int sa1100_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map) { struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(sock); unsigned long start; DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); DEBUG(3, "\tmap %u speed %u sys_start %08lx sys_stop %08lx card_start %08x\n", map->map, map->speed, map->sys_start, map->sys_stop, map->card_start); DEBUG(3, "\tflags: %s%s%s%s%s%s%s%s\n", (map->flags==0)?"<NONE>":"", (map->flags&MAP_ACTIVE)?"ACTIVE ":"", (map->flags&MAP_16BIT)?"16BIT ":"", (map->flags&MAP_AUTOSZ)?"AUTOSZ ":"", (map->flags&MAP_0WS)?"0WS ":"", (map->flags&MAP_WRPROT)?"WRPROT ":"", (map->flags&MAP_ATTRIB)?"ATTRIB ":"", (map->flags&MAP_USE_WAIT)?"USE_WAIT ":""); if (map->map >= MAX_WIN){ printk(KERN_ERR "%s(): map (%d) out of range\n", __FUNCTION__, map->map); return -1; } if (map->flags & MAP_ACTIVE) { unsigned int clock, speed = map->speed; unsigned long mecr; /* * When clients issue RequestMap, the access speed is not always * properly configured. Choose some sensible defaults. */ if (speed == 0) { if (skt->cs_state.Vcc == 33) speed = SA1100_PCMCIA_3V_MEM_ACCESS; else speed = SA1100_PCMCIA_5V_MEM_ACCESS; } clock = cpufreq_get(0); /* Fixme: MECR is not pre-empt safe. */ mecr = MECR; if (map->flags & MAP_ATTRIB) { MECR_BSA_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock)); skt->speed_attr = speed; } else { MECR_BSM_SET(mecr, sock, sa1100_pcmcia_mecr_bs(speed, clock)); skt->speed_mem = speed; } DEBUG(4, "%s(): FAST%u %lx BSM%u %lx BSA%u %lx BSIO%u %lx\n", __FUNCTION__, sock, MECR_FAST_GET(mecr, sock), sock, MECR_BSM_GET(mecr, sock), sock, MECR_BSA_GET(mecr, sock), sock, MECR_BSIO_GET(mecr, sock)); MECR = mecr; } start = (map->flags & MAP_ATTRIB) ? skt->phys_attr : skt->phys_mem; if (map->sys_stop == 0) map->sys_stop = PAGE_SIZE-1; map->sys_stop -= map->sys_start; map->sys_stop += start; map->sys_start = start; skt->mem_map[map->map] = *map; return 0; } /* sa1100_pcmcia_set_mem_map() */
/* sa1100_pcmcia_driver_init() * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ * * This routine performs a basic sanity check to ensure that this * kernel has been built with the appropriate board-specific low-level * PCMCIA support, performs low-level PCMCIA initialization, registers * this socket driver with Card Services, and then spawns the daemon * thread which is the real workhorse of the socket driver. * * Returns: 0 on success, -1 on error */ static int __init sa1100_pcmcia_driver_init(void) { servinfo_t info; struct pcmcia_init pcmcia_init; struct pcmcia_state state[SA1100_PCMCIA_MAX_SOCK]; struct pcmcia_state_array state_array; unsigned int i, clock; unsigned long mecr; int ret; printk(KERN_INFO "SA-1100 PCMCIA (CS release %s)\n", CS_RELEASE); CardServices(GetCardServicesInfo, &info); if (info.Revision != CS_RELEASE_CODE) { printk(KERN_ERR "Card Services release codes do not match\n"); return -EINVAL; } ret = sa1100_pcmcia_machine_init(); if (ret) return ret; pcmcia_init.handler = sa1100_pcmcia_interrupt; ret = pcmcia_low_level->init(&pcmcia_init); if (ret < 0) { printk(KERN_ERR "Unable to initialize kernel PCMCIA service (%d).\n", ret); return ret == -1 ? -EIO : ret; } sa1100_pcmcia_socket_count = ret; state_array.size = sa1100_pcmcia_socket_count; state_array.state = state; memset(state, 0, sizeof(state)); if (pcmcia_low_level->socket_state(&state_array) < 0) { pcmcia_low_level->shutdown(); printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); return -EIO; } /* * We initialize the MECR to default values here, because we are * not guaranteed to see a SetIOMap operation at runtime. */ mecr = MECR; clock = cpufreq_get(0); for (i = 0; i < sa1100_pcmcia_socket_count; i++) { struct sa1100_pcmcia_socket *skt = PCMCIA_SOCKET(i); struct pcmcia_irq_info irq_info; if (!request_mem_region(_PCMCIA(i), PCMCIASp, "PCMCIA")) { ret = -EBUSY; goto out_err; } irq_info.sock = i; irq_info.irq = -1; ret = pcmcia_low_level->get_irq_info(&irq_info); if (ret < 0) printk(KERN_ERR "Unable to get IRQ for socket %u (%d)\n", i, ret); skt->irq = irq_info.irq; skt->k_state = state[i]; skt->speed_io = SA1100_PCMCIA_IO_ACCESS; skt->speed_attr = SA1100_PCMCIA_5V_MEM_ACCESS; skt->speed_mem = SA1100_PCMCIA_5V_MEM_ACCESS; skt->phys_attr = _PCMCIAAttr(i); skt->phys_mem = _PCMCIAMem(i); skt->virt_io = ioremap(_PCMCIAIO(i), 0x10000); if (skt->virt_io == NULL) { ret = -ENOMEM; goto out_err; } MECR_FAST_SET(mecr, i, 0); MECR_BSIO_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_io, clock)); MECR_BSA_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_attr, clock)); MECR_BSM_SET(mecr, i, sa1100_pcmcia_mecr_bs(skt->speed_mem, clock)); } MECR = mecr; #ifdef CONFIG_CPU_FREQ ret = cpufreq_register_notifier(&sa1100_pcmcia_notifier_block); if (ret < 0) { printk(KERN_ERR "Unable to register CPU frequency change notifier (%d)\n", ret); goto out_err; } #endif /* Only advertise as many sockets as we can detect */ ret = register_ss_entry(sa1100_pcmcia_socket_count, &sa1100_pcmcia_operations); if (ret < 0) { printk(KERN_ERR "Unable to register sockets\n"); goto out_err; } /* * Start the event poll timer. It will reschedule by itself afterwards. */ sa1100_pcmcia_poll_event(0); return 0; out_err: for (i = 0; i < sa1100_pcmcia_socket_count; i++) { iounmap(sa1100_pcmcia_socket[i].virt_io); release_mem_region(_PCMCIA(i), PCMCIASp); } pcmcia_low_level->shutdown(); return ret; } /* sa1100_pcmcia_driver_init() */