11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FILE NAME 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * drivers/pcmcia/vrc4173_cardu.c 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * BRIEF MODULE DESCRIPTION 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NEC VRC4173 CARDU driver for Socket Services 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (This device doesn't support CardBus. it is supporting only 16bit PC Card.) 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9ada8e9514b5880f81cdbbd212d121380ceef7accYoichi Yuasa * Copyright 2002,2003 Yoichi Yuasa <yuasa@linux-mips.org> 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify it 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * under the terms of the GNU General Public License as published by the 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free Software Foundation; either version 2 of the License, or (at your 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * option) any later version. 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License along 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with this program; if not, write to the Free Software Foundation, Inc., 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 675 Mass Ave, Cambridge, MA 02139, USA. 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <pcmcia/ss.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "vrc4173_cardu.h" 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("NEC VRC4173 CARDU driver for Socket Services"); 44ada8e9514b5880f81cdbbd212d121380ceef7accYoichi YuasaMODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>"); 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int vrc4173_cardu_slots; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic vrc4173_socket_t cardu_sockets[CARDU_MAX_SOCKETS]; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern struct socket_info_t *pcmcia_register_socket (int slot, 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pccard_operations *vtable, 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int use_bus_pm); 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsextern void pcmcia_unregister_socket(struct socket_info_t *s); 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline uint8_t exca_readb(vrc4173_socket_t *socket, uint16_t offset) 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return readb(socket->base + EXCA_REGS_BASE + offset); 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline uint16_t exca_readw(vrc4173_socket_t *socket, uint16_t offset) 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint16_t val; 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = readb(socket->base + EXCA_REGS_BASE + offset); 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= (u16)readb(socket->base + EXCA_REGS_BASE + offset + 1) << 8; 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void exca_writeb(vrc4173_socket_t *socket, uint16_t offset, uint8_t val) 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb(val, socket->base + EXCA_REGS_BASE + offset); 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void exca_writew(vrc4173_socket_t *socket, uint8_t offset, uint16_t val) 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb((u8)val, socket->base + EXCA_REGS_BASE + offset); 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writeb((u8)(val >> 8), socket->base + EXCA_REGS_BASE + offset + 1); 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline uint32_t cardbus_socket_readl(vrc4173_socket_t *socket, u16 offset) 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return readl(socket->base + CARDBUS_SOCKET_REGS_BASE + offset); 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void cardbus_socket_writel(vrc4173_socket_t *socket, u16 offset, uint32_t val) 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds writel(val, socket->base + CARDBUS_SOCKET_REGS_BASE + offset); 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cardu_pciregs_init(struct pci_dev *dev) 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 syscnt; 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 brgcnt; 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 devcnt; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_dword(dev, 0x1c, 0x10000000); 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_dword(dev, 0x20, 0x17fff000); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_dword(dev, 0x2c, 0); 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_dword(dev, 0x30, 0xfffc); 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_word(dev, BRGCNT, &brgcnt); 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds brgcnt &= ~IREQ_INT; 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_word(dev, BRGCNT, brgcnt); 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_dword(dev, SYSCNT, &syscnt); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds syscnt &= ~(BAD_VCC_REQ_DISB|PCPCI_EN|CH_ASSIGN_MASK|SUB_ID_WR_EN|PCI_CLK_RIN); 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds syscnt |= (CH_ASSIGN_NODMA|ASYN_INT_MODE); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_dword(dev, SYSCNT, syscnt); 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_read_config_byte(dev, DEVCNT, &devcnt); 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devcnt &= ~(ZOOM_VIDEO_EN|SR_PCI_INT_SEL_MASK|PCI_INT_MODE|IRQ_MODE); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds devcnt |= (SR_PCI_INT_SEL_NONE|IFG); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_byte(dev, DEVCNT, devcnt); 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_byte(dev, CHIPCNT, S_PREF_DISB); 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_write_config_byte(dev, SERRDIS, 0); 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cardu_init(unsigned int slot) 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vrc4173_socket_t *socket = &cardu_sockets[slot]; 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardu_pciregs_init(socket->dev); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* CARD_SC bits are cleared by reading CARD_SC. */ 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exca_writeb(socket, GLO_CNT, 0); 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->cap.features |= SS_CAP_PCCARD | SS_CAP_PAGE_REGS; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->cap.irq_mask = 0; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->cap.map_size = 0x1000; 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->cap.pci_irq = socket->dev->irq; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->events = 0; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_init(socket->event_lock); 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enable PC Card status interrupts */ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exca_writeb(socket, CARD_SCI, CARD_DT_EN|RDY_EN|BAT_WAR_EN|BAT_DEAD_EN); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cardu_register_callback(unsigned int sock, 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void (*handler)(void *, unsigned int), 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds void * info) 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vrc4173_socket_t *socket = &cardu_sockets[sock]; 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->handler = handler; 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->info = info; 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cardu_inquire_socket(unsigned int sock, socket_cap_t *cap) 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vrc4173_socket_t *socket = &cardu_sockets[sock]; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *cap = socket->cap; 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cardu_get_status(unsigned int sock, u_int *value) 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vrc4173_socket_t *socket = &cardu_sockets[sock]; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t state; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t status; 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int val = 0; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = exca_readb(socket, IF_STATUS); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & CARD_PWR) val |= SS_POWERON; 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & READY) val |= SS_READY; 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & CARD_WP) val |= SS_WRPROT; 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status & (CARD_DETECT1|CARD_DETECT2)) == (CARD_DETECT1|CARD_DETECT2)) 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= SS_DETECT; 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (exca_readb(socket, INT_GEN_CNT) & CARD_TYPE_IO) { 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status & STSCHG) val |= SS_STSCHG; 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status &= BV_DETECT_MASK; 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status != BV_DETECT_GOOD) { 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status == BV_DETECT_WARN) val |= SS_BATWARN; 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else val |= SS_BATDEAD; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds state = cardbus_socket_readl(socket, SKT_PRE_STATE); 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (state & VOL_3V_CARD_DT) val |= SS_3VCARD; 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (state & VOL_XV_CARD_DT) val |= SS_XVCARD; 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (state & CB_CARD_DT) val |= SS_CARDBUS; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(state & 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (VOL_YV_CARD_DT|VOL_XV_CARD_DT|VOL_3V_CARD_DT|VOL_5V_CARD_DT|CCD20|CCD10))) 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= SS_PENDING; 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *value = val; 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline uint8_t set_Vcc_value(u_char Vcc) 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (Vcc) { 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 33: 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return VCC_3V; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 50: 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return VCC_5V; 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return VCC_0V; 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline uint8_t set_Vpp_value(u_char Vpp) 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (Vpp) { 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 33: 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 50: 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return VPP_VCC; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 120: 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return VPP_12V; 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return VPP_0V; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cardu_set_socket(unsigned int sock, socket_state_t *state) 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vrc4173_socket_t *socket = &cardu_sockets[sock]; 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t val; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((state->Vpp == 33) || (state->Vpp == 50)) && (state->Vpp != state->Vcc)) 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = set_Vcc_value(state->Vcc); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val |= set_Vpp_value(state->Vpp); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (state->flags & SS_OUTPUT_ENA) val |= CARD_OUT_EN; 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exca_writeb(socket, PWR_CNT, val); 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = exca_readb(socket, INT_GEN_CNT) & CARD_REST0; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (state->flags & SS_RESET) val &= ~CARD_REST0; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else val |= CARD_REST0; 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (state->flags & SS_IOCARD) val |= CARD_TYPE_IO; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exca_writeb(socket, INT_GEN_CNT, val); 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cardu_get_io_map(unsigned int sock, struct pccard_io_map *io) 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vrc4173_socket_t *socket = &cardu_sockets[sock]; 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t ioctl, window; 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char map; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map = io->map; 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (map > 1) 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds io->start = exca_readw(socket, IO_WIN_SA(map)); 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds io->stop = exca_readw(socket, IO_WIN_EA(map)); 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioctl = exca_readb(socket, IO_WIN_CNT); 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds window = exca_readb(socket, ADR_WIN_EN); 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds io->flags = (window & IO_WIN_EN(map)) ? MAP_ACTIVE : 0; 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ioctl & IO_WIN_DATA_AUTOSZ(map)) 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds io->flags |= MAP_AUTOSZ; 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (ioctl & IO_WIN_DATA_16BIT(map)) 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds io->flags |= MAP_16BIT; 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cardu_set_io_map(unsigned int sock, struct pccard_io_map *io) 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vrc4173_socket_t *socket = &cardu_sockets[sock]; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint16_t ioctl; 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t window, enable; 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char map; 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map = io->map; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (map > 1) 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds window = exca_readb(socket, ADR_WIN_EN); 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable = IO_WIN_EN(map); 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (window & enable) { 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds window &= ~enable; 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exca_writeb(socket, ADR_WIN_EN, window); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exca_writew(socket, IO_WIN_SA(map), io->start); 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exca_writew(socket, IO_WIN_EA(map), io->stop); 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ioctl = exca_readb(socket, IO_WIN_CNT) & ~IO_WIN_CNT_MASK(map); 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (io->flags & MAP_AUTOSZ) ioctl |= IO_WIN_DATA_AUTOSZ(map); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (io->flags & MAP_16BIT) ioctl |= IO_WIN_DATA_16BIT(map); 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exca_writeb(socket, IO_WIN_CNT, ioctl); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (io->flags & MAP_ACTIVE) 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exca_writeb(socket, ADR_WIN_EN, window | enable); 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cardu_get_mem_map(unsigned int sock, struct pccard_mem_map *mem) 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vrc4173_socket_t *socket = &cardu_sockets[sock]; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint32_t start, stop, offset, page; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t window; 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char map; 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map = mem->map; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (map > 4) 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds window = exca_readb(socket, ADR_WIN_EN); 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mem->flags = (window & MEM_WIN_EN(map)) ? MAP_ACTIVE : 0; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = exca_readw(socket, MEM_WIN_SA(map)); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mem->flags |= (start & MEM_WIN_DSIZE) ? MAP_16BIT : 0; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = (start & 0x0fff) << 12; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stop = exca_readw(socket, MEM_WIN_EA(map)); 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds stop = ((stop & 0x0fff) << 12) + 0x0fff; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = exca_readw(socket, MEM_WIN_OA(map)); 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mem->flags |= (offset & MEM_WIN_WP) ? MAP_WRPROT : 0; 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mem->flags |= (offset & MEM_WIN_REGSET) ? MAP_ATTRIB : 0; 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offset = ((offset & 0x3fff) << 12) + start; 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mem->card_start = offset & 0x03ffffff; 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds page = exca_readb(socket, MEM_WIN_SAU(map)) << 24; 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mem->sys_start = start + page; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mem->sys_stop = start + page; 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int cardu_set_mem_map(unsigned int sock, struct pccard_mem_map *mem) 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vrc4173_socket_t *socket = &cardu_sockets[sock]; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint16_t value; 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t window, enable; 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_long sys_start, sys_stop, card_start; 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char map; 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds map = mem->map; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sys_start = mem->sys_start; 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sys_stop = mem->sys_stop; 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds card_start = mem->card_start; 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (map > 4 || sys_start > sys_stop || ((sys_start ^ sys_stop) >> 24) || 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (card_start >> 26)) 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds window = exca_readb(socket, ADR_WIN_EN); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable = MEM_WIN_EN(map); 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (window & enable) { 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds window &= ~enable; 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exca_writeb(socket, ADR_WIN_EN, window); 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exca_writeb(socket, MEM_WIN_SAU(map), sys_start >> 24); 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = (sys_start >> 12) & 0x0fff; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mem->flags & MAP_16BIT) value |= MEM_WIN_DSIZE; 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exca_writew(socket, MEM_WIN_SA(map), value); 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = (sys_stop >> 12) & 0x0fff; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exca_writew(socket, MEM_WIN_EA(map), value); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds value = ((card_start - sys_start) >> 12) & 0x3fff; 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mem->flags & MAP_WRPROT) value |= MEM_WIN_WP; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mem->flags & MAP_ATTRIB) value |= MEM_WIN_REGSET; 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exca_writew(socket, MEM_WIN_OA(map), value); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mem->flags & MAP_ACTIVE) 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds exca_writeb(socket, ADR_WIN_EN, window | enable); 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cardu_proc_setup(unsigned int sock, struct proc_dir_entry *base) 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pccard_operations cardu_operations = { 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .init = cardu_init, 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .register_callback = cardu_register_callback, 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .inquire_socket = cardu_inquire_socket, 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_status = cardu_get_status, 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_socket = cardu_set_socket, 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_io_map = cardu_get_io_map, 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_io_map = cardu_set_io_map, 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .get_mem_map = cardu_get_mem_map, 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .set_mem_map = cardu_set_mem_map, 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .proc_setup = cardu_proc_setup, 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void cardu_bh(void *data) 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vrc4173_socket_t *socket = (vrc4173_socket_t *)data; 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint16_t events; 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock_irq(&socket->event_lock); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds events = socket->events; 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->events = 0; 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock_irq(&socket->event_lock); 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (socket->handler) 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->handler(socket->info, events); 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic uint16_t get_events(vrc4173_socket_t *socket) 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint16_t events = 0; 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint8_t csc, status; 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds status = exca_readb(socket, IF_STATUS); 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds csc = exca_readb(socket, CARD_SC); 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((csc & CARD_DT_CHG) && 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((status & (CARD_DETECT1|CARD_DETECT2)) == (CARD_DETECT1|CARD_DETECT2))) 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds events |= SS_DETECT; 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((csc & RDY_CHG) && (status & READY)) 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds events |= SS_READY; 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (exca_readb(socket, INT_GEN_CNT) & CARD_TYPE_IO) { 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((csc & BAT_DEAD_ST_CHG) && (status & STSCHG)) 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds events |= SS_STSCHG; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (csc & (BAT_WAR_CHG|BAT_DEAD_ST_CHG)) { 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((status & BV_DETECT_MASK) != BV_DETECT_GOOD) { 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (status == BV_DETECT_WARN) events |= SS_BATWARN; 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else events |= SS_BATDEAD; 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return events; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4437d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic void cardu_interrupt(int irq, void *dev_id) 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vrc4173_socket_t *socket = (vrc4173_socket_t *)dev_id; 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint16_t events; 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INIT_WORK(&socket->tq_work, cardu_bh, socket); 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds events = get_events(socket); 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (events) { 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_lock(&socket->event_lock); 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->events |= events; 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spin_unlock(&socket->event_lock); 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds schedule_work(&socket->tq_work); 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit vrc4173_cardu_probe(struct pci_dev *dev, 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const struct pci_device_id *ent) 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vrc4173_socket_t *socket; 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long start, len, flags; 4641ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar int slot, err, ret; 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slot = vrc4173_cardu_slots++; 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket = &cardu_sockets[slot]; 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (socket->noprobe != 0) 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EBUSY; 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sprintf(socket->name, "NEC VRC4173 CARDU%1d", slot+1); 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = pci_enable_device(dev)) < 0) 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds start = pci_resource_start(dev, 0); 4771ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar if (start == 0) { 4781ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar ret = -ENODEV; 4791ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar goto disable; 4801ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar } 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds len = pci_resource_len(dev, 0); 4831ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar if (len == 0) { 4841ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar ret = -ENODEV; 4851ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar goto disable; 4861ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar } 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4881ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar flags = pci_resource_flags(dev, 0); 4891ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar if ((flags & IORESOURCE_MEM) == 0) { 4901ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar ret = -EBUSY; 4911ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar goto disable; 4921ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar } 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4941ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar err = pci_request_regions(dev, socket->name); 4951ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar if (err < 0) { 4961ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar ret = err; 4971ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar goto disable; 4981ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar } 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->base = ioremap(start, len); 5011ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar if (socket->base == NULL) { 5021ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar ret = -ENODEV; 5031ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar goto release; 5041ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar } 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->dev = dev; 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds socket->pcmcia_socket = pcmcia_register_socket(slot, &cardu_operations, 1); 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (socket->pcmcia_socket == NULL) { 5101ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar ret = -ENOMEM; 5111ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar goto unmap; 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 514dace145374b8e39aeb920304c358ab5e220341abThomas Gleixner if (request_irq(dev->irq, cardu_interrupt, IRQF_SHARED, socket->name, socket) < 0) { 5151ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar ret = -EBUSY; 5161ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar goto unregister; 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk(KERN_INFO "%s at %#08lx, IRQ %d\n", socket->name, start, dev->irq); 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 5221ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar 5231ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikarunregister: 5241ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar pcmcia_unregister_socket(socket->pcmcia_socket); 5251ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar socket->pcmcia_socket = NULL; 5261ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikarunmap: 5271ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar iounmap(socket->base); 5281ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar socket->base = NULL; 5291ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikarrelease: 5301ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar pci_release_regions(dev); 5311ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikardisable: 5321ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar pci_disable_device(dev); 5331ab488de544b7f94b4f8e5aed2b178cac685802fRahul Ruikar return ret; 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit vrc4173_cardu_setup(char *options) 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (options == NULL || *options == '\0') 5399b41046cd0ee0a57f849d6e1363f7933e363cca9OGAWA Hirofumi return 1; 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strncmp(options, "cardu1:", 7) == 0) { 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds options += 7; 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*options != '\0') { 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strncmp(options, "noprobe", 7) == 0) { 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardu_sockets[CARDU1].noprobe = 1; 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds options += 7; 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*options != ',') 5509b41046cd0ee0a57f849d6e1363f7933e363cca9OGAWA Hirofumi return 1; 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 5529b41046cd0ee0a57f849d6e1363f7933e363cca9OGAWA Hirofumi return 1; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (strncmp(options, "cardu2:", 7) == 0) { 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds options += 7; 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((*options != '\0') && (strncmp(options, "noprobe", 7) == 0)) 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cardu_sockets[CARDU2].noprobe = 1; 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5619b41046cd0ee0a57f849d6e1363f7933e363cca9OGAWA Hirofumi return 1; 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("vrc4173_cardu=", vrc4173_cardu_setup); 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5662b2c5d8c1dff8ed42d6d841f56428c0ce2bd71b5Axel Linstatic DEFINE_PCI_DEVICE_TABLE(vrc4173_cardu_id_table) = { 5672b2c5d8c1dff8ed42d6d841f56428c0ce2bd71b5Axel Lin { PCI_DEVICE(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NAPCCARD) }, 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {0, } 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_driver vrc4173_cardu_driver = { 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "NEC VRC4173 CARDU", 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .probe = vrc4173_cardu_probe, 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .id_table = vrc4173_cardu_id_table, 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __devinit vrc4173_cardu_init(void) 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vrc4173_cardu_slots = 0; 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58193b47684f60cf25e8cefe19a21d94aa0257fdf36Richard Knutsson return pci_register_driver(&vrc4173_cardu_driver); 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __devexit vrc4173_cardu_exit(void) 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pci_unregister_driver(&vrc4173_cardu_driver); 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(vrc4173_cardu_init); 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(vrc4173_cardu_exit); 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(pci, vrc4173_cardu_id_table); 592