^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * HP i8042-based System Device Controller driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (c) 2001 Brian S. Julin
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Redistribution and use in source and binary forms, with or without
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * modification, are permitted provided that the following conditions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * are met:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * 1. Redistributions of source code must retain the above copyright
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * notice, this list of conditions, and the following disclaimer,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) * without modification.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * 2. The name of the author may not be used to endorse or promote products
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * derived from this software without specific prior written permission.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Alternatively, this software may be distributed under the terms of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * GNU General Public License ("GPL").
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) * References:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) * System Device Controller Microprocessor Firmware Theory of Operation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * for Part Number 1820-4784 Revision B. Dwg No. A-1820-4784-2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * Helge Deller's original hilkbd.c port for PA-RISC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * Driver theory of operation:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * hp_sdc_put does all writing to the SDC. ISR can run on a different
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * CPU than hp_sdc_put, but only one CPU runs hp_sdc_put at a time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * (it cannot really benefit from SMP anyway.) A tasket fit this perfectly.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * All data coming back from the SDC is sent via interrupt and can be read
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * fully in the ISR, so there are no latency/throughput problems there.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * The problem is with output, due to the slow clock speed of the SDC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) * compared to the CPU. This should not be too horrible most of the time,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * but if used with HIL devices that support the multibyte transfer command,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * keeping outbound throughput flowing at the 6500KBps that the HIL is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * capable of is more than can be done at HZ=100.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * Busy polling for IBF clear wastes CPU cycles and bus cycles. hp_sdc.ibf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * is set to 0 when the IBF flag in the status register has cleared. ISR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * may do this, and may also access the parts of queued transactions related
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * to reading data back from the SDC, but otherwise will not touch the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * hp_sdc state. Whenever a register is written hp_sdc.ibf is set to 1.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * The i8042 write index and the values in the 4-byte input buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * starting at 0x70 are kept track of in hp_sdc.wi, and .r7[], respectively,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * to minimize the amount of IO needed to the SDC. However these values
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * do not need to be locked since they are only ever accessed by hp_sdc_put.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * A timer task schedules the tasklet once per second just to make
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) * sure it doesn't freeze up and to allow for bad reads to time out.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #include <linux/hp_sdc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #include <linux/time.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #include <linux/semaphore.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) #include <linux/hil.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) #include <asm/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) /* Machine-specific abstraction */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) #if defined(__hppa__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) # include <asm/parisc-device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) # define sdc_readb(p) gsc_readb(p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) # define sdc_writeb(v,p) gsc_writeb((v),(p))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) #elif defined(__mc68000__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) # define sdc_readb(p) in_8(p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) # define sdc_writeb(v,p) out_8((p),(v))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) # error "HIL is not supported on this platform"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #define PREFIX "HP SDC: "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) MODULE_DESCRIPTION("HP i8042-based SDC Driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) MODULE_LICENSE("Dual BSD/GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) EXPORT_SYMBOL(hp_sdc_request_timer_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) EXPORT_SYMBOL(hp_sdc_request_hil_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) EXPORT_SYMBOL(hp_sdc_request_cooked_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) EXPORT_SYMBOL(hp_sdc_release_timer_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) EXPORT_SYMBOL(hp_sdc_release_hil_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) EXPORT_SYMBOL(hp_sdc_release_cooked_irq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) EXPORT_SYMBOL(__hp_sdc_enqueue_transaction);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) EXPORT_SYMBOL(hp_sdc_enqueue_transaction);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) EXPORT_SYMBOL(hp_sdc_dequeue_transaction);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static bool hp_sdc_disabled;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) module_param_named(no_hpsdc, hp_sdc_disabled, bool, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) MODULE_PARM_DESC(no_hpsdc, "Do not enable HP SDC driver.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) static hp_i8042_sdc hp_sdc; /* All driver state is kept in here. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /*************** primitives for use in any context *********************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static inline uint8_t hp_sdc_status_in8(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) uint8_t status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) write_lock_irqsave(&hp_sdc.ibf_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) status = sdc_readb(hp_sdc.status_io);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (!(status & HP_SDC_STATUS_IBF))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) hp_sdc.ibf = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) return status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static inline uint8_t hp_sdc_data_in8(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) return sdc_readb(hp_sdc.data_io);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) static inline void hp_sdc_status_out8(uint8_t val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) write_lock_irqsave(&hp_sdc.ibf_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) hp_sdc.ibf = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) if ((val & 0xf0) == 0xe0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) hp_sdc.wi = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) sdc_writeb(val, hp_sdc.status_io);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) static inline void hp_sdc_data_out8(uint8_t val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) write_lock_irqsave(&hp_sdc.ibf_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) hp_sdc.ibf = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) sdc_writeb(val, hp_sdc.data_io);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /* Care must be taken to only invoke hp_sdc_spin_ibf when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) * absolutely needed, or in rarely invoked subroutines.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) * Not only does it waste CPU cycles, it also wastes bus cycles.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static inline void hp_sdc_spin_ibf(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) rwlock_t *lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) lock = &hp_sdc.ibf_lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) read_lock_irqsave(lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) if (!hp_sdc.ibf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) read_unlock_irqrestore(lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) read_unlock(lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) write_lock(lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) while (sdc_readb(hp_sdc.status_io) & HP_SDC_STATUS_IBF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) hp_sdc.ibf = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) write_unlock_irqrestore(lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) /************************ Interrupt context functions ************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) static void hp_sdc_take(int irq, void *dev_id, uint8_t status, uint8_t data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) hp_sdc_transaction *curr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) read_lock(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) if (hp_sdc.rcurr < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) read_unlock(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) curr = hp_sdc.tq[hp_sdc.rcurr];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) read_unlock(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) curr->seq[curr->idx++] = status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) curr->seq[curr->idx++] = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) hp_sdc.rqty -= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) hp_sdc.rtime = ktime_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) if (hp_sdc.rqty <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) /* All data has been gathered. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (curr->seq[curr->actidx] & HP_SDC_ACT_SEMAPHORE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) if (curr->act.semaphore)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) up(curr->act.semaphore);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) if (curr->seq[curr->actidx] & HP_SDC_ACT_CALLBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) if (curr->act.irqhook)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) curr->act.irqhook(irq, dev_id, status, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) curr->actidx = curr->idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) curr->idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) /* Return control of this transaction */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) write_lock(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) hp_sdc.rcurr = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) hp_sdc.rqty = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) write_unlock(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) tasklet_schedule(&hp_sdc.task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) static irqreturn_t hp_sdc_isr(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) uint8_t status, data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) status = hp_sdc_status_in8();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) /* Read data unconditionally to advance i8042. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) data = hp_sdc_data_in8();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) /* For now we are ignoring these until we get the SDC to behave. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (((status & 0xf1) == 0x51) && data == 0x82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) switch (status & HP_SDC_STATUS_IRQMASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) case 0: /* This case is not documented. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) case HP_SDC_STATUS_USERTIMER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) case HP_SDC_STATUS_PERIODIC:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) case HP_SDC_STATUS_TIMER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) read_lock(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) if (hp_sdc.timer != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) hp_sdc.timer(irq, dev_id, status, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) read_unlock(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) case HP_SDC_STATUS_REG:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) hp_sdc_take(irq, dev_id, status, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) case HP_SDC_STATUS_HILCMD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) case HP_SDC_STATUS_HILDATA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) read_lock(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) if (hp_sdc.hil != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) hp_sdc.hil(irq, dev_id, status, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) read_unlock(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) case HP_SDC_STATUS_PUP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) read_lock(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) if (hp_sdc.pup != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) hp_sdc.pup(irq, dev_id, status, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) printk(KERN_INFO PREFIX "HP SDC reports successful PUP.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) read_unlock(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) read_lock(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) if (hp_sdc.cooked != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) hp_sdc.cooked(irq, dev_id, status, data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) read_unlock(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) status = hp_sdc_status_in8();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) printk(KERN_WARNING PREFIX "NMI !\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) #if 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) if (status & HP_SDC_NMISTATUS_FHS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) read_lock(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) if (hp_sdc.timer != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) hp_sdc.timer(irq, dev_id, status, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) read_unlock(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) /* TODO: pass this on to the HIL handler, or do SAK here? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) printk(KERN_WARNING PREFIX "HIL NMI\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) return IRQ_HANDLED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) /***************** Kernel (tasklet) context functions ****************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) unsigned long hp_sdc_put(void);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) static void hp_sdc_tasklet(unsigned long foo)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) write_lock_irq(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) if (hp_sdc.rcurr >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) ktime_t now = ktime_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) if (ktime_after(now, ktime_add_us(hp_sdc.rtime,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) HP_SDC_MAX_REG_DELAY))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) hp_sdc_transaction *curr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) uint8_t tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) curr = hp_sdc.tq[hp_sdc.rcurr];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) /* If this turns out to be a normal failure mode
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) * we'll need to figure out a way to communicate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) * it back to the application. and be less verbose.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) printk(KERN_WARNING PREFIX "read timeout (%lldus)!\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) ktime_us_delta(now, hp_sdc.rtime));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) curr->idx += hp_sdc.rqty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) hp_sdc.rqty = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) tmp = curr->seq[curr->actidx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) curr->seq[curr->actidx] |= HP_SDC_ACT_DEAD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) if (tmp & HP_SDC_ACT_SEMAPHORE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) if (curr->act.semaphore)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) up(curr->act.semaphore);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) if (tmp & HP_SDC_ACT_CALLBACK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) /* Note this means that irqhooks may be called
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) * in tasklet/bh context.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) if (curr->act.irqhook)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) curr->act.irqhook(0, NULL, 0, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) curr->actidx = curr->idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) curr->idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) hp_sdc.rcurr = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) write_unlock_irq(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) hp_sdc_put();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) unsigned long hp_sdc_put(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) hp_sdc_transaction *curr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) uint8_t act;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) int idx, curridx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) int limit = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) write_lock(&hp_sdc.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) /* If i8042 buffers are full, we cannot do anything that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) requires output, so we skip to the administrativa. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) if (hp_sdc.ibf) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) hp_sdc_status_in8();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) if (hp_sdc.ibf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) goto finish;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) anew:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) /* See if we are in the middle of a sequence. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) if (hp_sdc.wcurr < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) hp_sdc.wcurr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) read_lock_irq(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) if (hp_sdc.rcurr == hp_sdc.wcurr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) hp_sdc.wcurr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) read_unlock_irq(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) hp_sdc.wcurr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) curridx = hp_sdc.wcurr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) if (hp_sdc.tq[curridx] != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) goto start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) while (++curridx != hp_sdc.wcurr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) if (curridx >= HP_SDC_QUEUE_LEN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) curridx = -1; /* Wrap to top */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) read_lock_irq(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) if (hp_sdc.rcurr == curridx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) read_unlock_irq(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) read_unlock_irq(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) if (hp_sdc.tq[curridx] != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) break; /* Found one. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) if (curridx == hp_sdc.wcurr) { /* There's nothing queued to do. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) curridx = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) hp_sdc.wcurr = curridx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) start:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) /* Check to see if the interrupt mask needs to be set. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) if (hp_sdc.set_im) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) hp_sdc_status_out8(hp_sdc.im | HP_SDC_CMD_SET_IM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) hp_sdc.set_im = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) goto finish;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) if (hp_sdc.wcurr == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) goto done;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) curr = hp_sdc.tq[curridx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) idx = curr->actidx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) if (curr->actidx >= curr->endidx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) hp_sdc.tq[curridx] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) /* Interleave outbound data between the transactions. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) hp_sdc.wcurr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) hp_sdc.wcurr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) goto finish;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) act = curr->seq[idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) if (curr->idx >= curr->endidx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) if (act & HP_SDC_ACT_DEALLOC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) kfree(curr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) hp_sdc.tq[curridx] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) /* Interleave outbound data between the transactions. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) hp_sdc.wcurr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) hp_sdc.wcurr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) goto finish;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) while (act & HP_SDC_ACT_PRECMD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) if (curr->idx != idx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) act &= ~HP_SDC_ACT_PRECMD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) hp_sdc_status_out8(curr->seq[idx]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) curr->idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) /* act finished? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_PRECMD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) goto actdone;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) /* skip quantity field if data-out sequence follows. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) if (act & HP_SDC_ACT_DATAOUT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) curr->idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) goto finish;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) if (act & HP_SDC_ACT_DATAOUT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) int qty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) qty = curr->seq[idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) if (curr->idx - idx < qty) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) hp_sdc_data_out8(curr->seq[curr->idx]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) curr->idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) /* act finished? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) if (curr->idx - idx >= qty &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) (act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAOUT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) goto actdone;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) goto finish;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) idx += qty;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) act &= ~HP_SDC_ACT_DATAOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) while (act & HP_SDC_ACT_DATAREG) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) int mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) uint8_t w7[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) mask = curr->seq[idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) if (idx != curr->idx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) idx += !!(mask & 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) idx += !!(mask & 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) idx += !!(mask & 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) idx += !!(mask & 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) act &= ~HP_SDC_ACT_DATAREG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) w7[0] = (mask & 1) ? curr->seq[++idx] : hp_sdc.r7[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) w7[1] = (mask & 2) ? curr->seq[++idx] : hp_sdc.r7[1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) w7[2] = (mask & 4) ? curr->seq[++idx] : hp_sdc.r7[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) w7[3] = (mask & 8) ? curr->seq[++idx] : hp_sdc.r7[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) if (hp_sdc.wi > 0x73 || hp_sdc.wi < 0x70 ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) w7[hp_sdc.wi - 0x70] == hp_sdc.r7[hp_sdc.wi - 0x70]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) /* Need to point the write index register */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) while (i < 4 && w7[i] == hp_sdc.r7[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) if (i < 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) hp_sdc_status_out8(HP_SDC_CMD_SET_D0 + i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) hp_sdc.wi = 0x70 + i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) goto finish;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAREG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) goto actdone;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) curr->idx = idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) act &= ~HP_SDC_ACT_DATAREG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) hp_sdc_data_out8(w7[hp_sdc.wi - 0x70]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) hp_sdc.r7[hp_sdc.wi - 0x70] = w7[hp_sdc.wi - 0x70];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) hp_sdc.wi++; /* write index register autoincrements */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) int i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) while ((i < 4) && w7[i] == hp_sdc.r7[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) if (i >= 4) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) curr->idx = idx + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) if ((act & HP_SDC_ACT_DURING) ==
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) HP_SDC_ACT_DATAREG)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) goto actdone;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) goto finish;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) /* We don't go any further in the command if there is a pending read,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) because we don't want interleaved results. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) read_lock_irq(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) if (hp_sdc.rcurr >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) read_unlock_irq(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) goto finish;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) read_unlock_irq(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) if (act & HP_SDC_ACT_POSTCMD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) uint8_t postcmd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) /* curr->idx should == idx at this point. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) postcmd = curr->seq[idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) curr->idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) if (act & HP_SDC_ACT_DATAIN) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) /* Start a new read */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) hp_sdc.rqty = curr->seq[curr->idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) hp_sdc.rtime = ktime_get();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) curr->idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) /* Still need to lock here in case of spurious irq. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) write_lock_irq(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) hp_sdc.rcurr = curridx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) write_unlock_irq(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) hp_sdc_status_out8(postcmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) goto finish;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) hp_sdc_status_out8(postcmd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) goto actdone;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) actdone:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) if (act & HP_SDC_ACT_SEMAPHORE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) up(curr->act.semaphore);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) else if (act & HP_SDC_ACT_CALLBACK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) curr->act.irqhook(0,NULL,0,0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) if (curr->idx >= curr->endidx) { /* This transaction is over. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) if (act & HP_SDC_ACT_DEALLOC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) kfree(curr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) hp_sdc.tq[curridx] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) curr->actidx = idx + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) curr->idx = idx + 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) /* Interleave outbound data between the transactions. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) hp_sdc.wcurr++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) hp_sdc.wcurr = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) finish:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) /* If by some quirk IBF has cleared and our ISR has run to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) see that that has happened, do it all again. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) if (!hp_sdc.ibf && limit++ < 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) goto anew;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) done:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) if (hp_sdc.wcurr >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) tasklet_schedule(&hp_sdc.task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) write_unlock(&hp_sdc.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) /******* Functions called in either user or kernel context ****/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) int __hp_sdc_enqueue_transaction(hp_sdc_transaction *this)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) if (this == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) BUG();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) /* Can't have same transaction on queue twice */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) if (hp_sdc.tq[i] == this)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) this->actidx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) this->idx = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) /* Search for empty slot */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) if (hp_sdc.tq[i] == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) hp_sdc.tq[i] = this;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) tasklet_schedule(&hp_sdc.task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) printk(KERN_WARNING PREFIX "No free slot to add transaction.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) write_lock_irqsave(&hp_sdc.lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) ret = __hp_sdc_enqueue_transaction(this);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) write_unlock_irqrestore(&hp_sdc.lock,flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) int hp_sdc_dequeue_transaction(hp_sdc_transaction *this)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) write_lock_irqsave(&hp_sdc.lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) /* TODO: don't remove it if it's not done. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) if (hp_sdc.tq[i] == this)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) hp_sdc.tq[i] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) write_unlock_irqrestore(&hp_sdc.lock, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) /********************** User context functions **************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) if (callback == NULL || hp_sdc.dev == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) write_lock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) if (hp_sdc.timer != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) write_unlock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) hp_sdc.timer = callback;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) /* Enable interrupts from the timers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) hp_sdc.im &= ~HP_SDC_IM_FH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) hp_sdc.im &= ~HP_SDC_IM_PT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) hp_sdc.im &= ~HP_SDC_IM_TIMERS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) hp_sdc.set_im = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) write_unlock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) tasklet_schedule(&hp_sdc.task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) if (callback == NULL || hp_sdc.dev == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) write_lock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) if (hp_sdc.hil != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) write_unlock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) hp_sdc.hil = callback;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) hp_sdc.im &= ~(HP_SDC_IM_HIL | HP_SDC_IM_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) hp_sdc.set_im = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) write_unlock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) tasklet_schedule(&hp_sdc.task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) if (callback == NULL || hp_sdc.dev == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) write_lock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) if (hp_sdc.cooked != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) write_unlock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) /* Enable interrupts from the HIL MLC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) hp_sdc.cooked = callback;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) hp_sdc.im &= ~(HP_SDC_IM_HIL | HP_SDC_IM_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) hp_sdc.set_im = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) write_unlock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) tasklet_schedule(&hp_sdc.task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) write_lock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) if ((callback != hp_sdc.timer) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) (hp_sdc.timer == NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) write_unlock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) /* Disable interrupts from the timers */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) hp_sdc.timer = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) hp_sdc.im |= HP_SDC_IM_TIMERS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) hp_sdc.im |= HP_SDC_IM_FH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) hp_sdc.im |= HP_SDC_IM_PT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) hp_sdc.set_im = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) write_unlock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) tasklet_schedule(&hp_sdc.task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) write_lock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) if ((callback != hp_sdc.hil) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) (hp_sdc.hil == NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) write_unlock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) hp_sdc.hil = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) /* Disable interrupts from HIL only if there is no cooked driver. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) if(hp_sdc.cooked == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) hp_sdc.im |= (HP_SDC_IM_HIL | HP_SDC_IM_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) hp_sdc.set_im = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) write_unlock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) tasklet_schedule(&hp_sdc.task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) write_lock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) if ((callback != hp_sdc.cooked) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) (hp_sdc.cooked == NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) write_unlock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) hp_sdc.cooked = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) /* Disable interrupts from HIL only if there is no raw HIL driver. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) if(hp_sdc.hil == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) hp_sdc.im |= (HP_SDC_IM_HIL | HP_SDC_IM_RESET);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) hp_sdc.set_im = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) write_unlock_irq(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) tasklet_schedule(&hp_sdc.task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) /************************* Keepalive timer task *********************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) static void hp_sdc_kicker(struct timer_list *unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) tasklet_schedule(&hp_sdc.task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) /* Re-insert the periodic task. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) mod_timer(&hp_sdc.kicker, jiffies + HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) /************************** Module Initialization ***************************/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) #if defined(__hppa__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) static const struct parisc_device_id hp_sdc_tbl[] __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) .hw_type = HPHW_FIO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) .hversion_rev = HVERSION_REV_ANY_ID,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) .hversion = HVERSION_ANY_ID,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) .sversion = 0x73,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) { 0, }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) MODULE_DEVICE_TABLE(parisc, hp_sdc_tbl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) static int __init hp_sdc_init_hppa(struct parisc_device *d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) static struct delayed_work moduleloader_work;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) static struct parisc_driver hp_sdc_driver __refdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) .name = "hp_sdc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) .id_table = hp_sdc_tbl,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) .probe = hp_sdc_init_hppa,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) #endif /* __hppa__ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) static int __init hp_sdc_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) char *errstr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) hp_sdc_transaction t_sync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832) uint8_t ts_sync[6];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) struct semaphore s_sync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) rwlock_init(&hp_sdc.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) rwlock_init(&hp_sdc.ibf_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) rwlock_init(&hp_sdc.rtq_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) rwlock_init(&hp_sdc.hook_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) hp_sdc.timer = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) hp_sdc.hil = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) hp_sdc.pup = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) hp_sdc.cooked = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) hp_sdc.im = HP_SDC_IM_MASK; /* Mask maskable irqs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) hp_sdc.set_im = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) hp_sdc.wi = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) hp_sdc.r7[0] = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) hp_sdc.r7[1] = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) hp_sdc.r7[2] = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) hp_sdc.r7[3] = 0xff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) hp_sdc.ibf = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) memset(&hp_sdc.tq, 0, sizeof(hp_sdc.tq));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) hp_sdc.wcurr = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) hp_sdc.rcurr = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) hp_sdc.rqty = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) hp_sdc.dev_err = -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) errstr = "IO not found for";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) if (!hp_sdc.base_io)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) goto err0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) errstr = "IRQ not found for";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) if (!hp_sdc.irq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) goto err0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) hp_sdc.dev_err = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) #if defined(__hppa__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) errstr = "IO not available for";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) goto err0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) errstr = "IRQ not available for";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) if (request_irq(hp_sdc.irq, &hp_sdc_isr, IRQF_SHARED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) "HP SDC", &hp_sdc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) goto err1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) errstr = "NMI not available for";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, IRQF_SHARED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) "HP SDC NMI", &hp_sdc))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) goto err2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) pr_info(PREFIX "HP SDC at 0x%08lx, IRQ %d (NMI IRQ %d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) hp_sdc_status_in8();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) hp_sdc_data_in8();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) tasklet_init(&hp_sdc.task, hp_sdc_tasklet, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) /* Sync the output buffer registers, thus scheduling hp_sdc_tasklet. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) t_sync.actidx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) t_sync.idx = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) t_sync.endidx = 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) t_sync.seq = ts_sync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) ts_sync[0] = HP_SDC_ACT_DATAREG | HP_SDC_ACT_SEMAPHORE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901) ts_sync[1] = 0x0f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) ts_sync[2] = ts_sync[3] = ts_sync[4] = ts_sync[5] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) t_sync.act.semaphore = &s_sync;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) sema_init(&s_sync, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) hp_sdc_enqueue_transaction(&t_sync);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) down(&s_sync); /* Wait for t_sync to complete */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) /* Create the keepalive task */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) timer_setup(&hp_sdc.kicker, hp_sdc_kicker, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) hp_sdc.kicker.expires = jiffies + HZ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) add_timer(&hp_sdc.kicker);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) hp_sdc.dev_err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) err2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) free_irq(hp_sdc.irq, &hp_sdc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) err1:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) release_region(hp_sdc.data_io, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) err0:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) printk(KERN_WARNING PREFIX ": %s SDC IO=0x%p IRQ=0x%x NMI=0x%x\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) errstr, (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) hp_sdc.dev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) return hp_sdc.dev_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) #if defined(__hppa__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) static void request_module_delayed(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) request_module("hp_sdc_mlc");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) static int __init hp_sdc_init_hppa(struct parisc_device *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) if (!d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) if (hp_sdc.dev != NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) return 1; /* We only expect one SDC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) hp_sdc.dev = d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) hp_sdc.irq = d->irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) hp_sdc.nmi = d->aux_irq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) hp_sdc.base_io = d->hpa.start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) hp_sdc.data_io = d->hpa.start + 0x800;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) hp_sdc.status_io = d->hpa.start + 0x801;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) INIT_DELAYED_WORK(&moduleloader_work, request_module_delayed);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) ret = hp_sdc_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) /* after successful initialization give SDC some time to settle
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) * and then load the hp_sdc_mlc upper layer driver */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) schedule_delayed_work(&moduleloader_work,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) msecs_to_jiffies(2000));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) #endif /* __hppa__ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) static void hp_sdc_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) /* do nothing if we don't have a SDC */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) if (!hp_sdc.dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) write_lock_irq(&hp_sdc.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) /* Turn off all maskable "sub-function" irq's. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) hp_sdc_spin_ibf();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) sdc_writeb(HP_SDC_CMD_SET_IM | HP_SDC_IM_MASK, hp_sdc.status_io);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) /* Wait until we know this has been processed by the i8042 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) hp_sdc_spin_ibf();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) free_irq(hp_sdc.nmi, &hp_sdc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) free_irq(hp_sdc.irq, &hp_sdc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) write_unlock_irq(&hp_sdc.lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) del_timer_sync(&hp_sdc.kicker);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) tasklet_kill(&hp_sdc.task);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) #if defined(__hppa__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) cancel_delayed_work_sync(&moduleloader_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) if (unregister_parisc_driver(&hp_sdc_driver))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) printk(KERN_WARNING PREFIX "Error unregistering HP SDC");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) static int __init hp_sdc_register(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) hp_sdc_transaction tq_init;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) uint8_t tq_init_seq[5];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) struct semaphore tq_init_sem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) #if defined(__mc68000__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) unsigned char i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) if (hp_sdc_disabled) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) printk(KERN_WARNING PREFIX "HP SDC driver disabled by no_hpsdc=1.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) hp_sdc.dev = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) hp_sdc.dev_err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) #if defined(__hppa__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011) if (register_parisc_driver(&hp_sdc_driver)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) printk(KERN_WARNING PREFIX "Error registering SDC with system bus tree.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) #elif defined(__mc68000__)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) if (!MACH_IS_HP300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) hp_sdc.irq = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) hp_sdc.nmi = 7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) hp_sdc.base_io = (unsigned long) 0xf0428000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) hp_sdc.data_io = (unsigned long) hp_sdc.base_io + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) hp_sdc.status_io = (unsigned long) hp_sdc.base_io + 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) if (!copy_from_kernel_nofault(&i, (unsigned char *)hp_sdc.data_io, 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) hp_sdc.dev = (void *)1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) hp_sdc.dev_err = hp_sdc_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) if (hp_sdc.dev == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) printk(KERN_WARNING PREFIX "No SDC found.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) return hp_sdc.dev_err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) sema_init(&tq_init_sem, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) tq_init.actidx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) tq_init.idx = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) tq_init.endidx = 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) tq_init.seq = tq_init_seq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) tq_init.act.semaphore = &tq_init_sem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) tq_init_seq[0] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) tq_init_seq[1] = HP_SDC_CMD_READ_KCC;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) tq_init_seq[2] = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) tq_init_seq[3] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) tq_init_seq[4] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) hp_sdc_enqueue_transaction(&tq_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) down(&tq_init_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) up(&tq_init_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) printk(KERN_WARNING PREFIX "Error reading config byte.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) hp_sdc_exit();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) hp_sdc.r11 = tq_init_seq[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) if (hp_sdc.r11 & HP_SDC_CFG_NEW) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) const char *str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) printk(KERN_INFO PREFIX "New style SDC\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) tq_init_seq[1] = HP_SDC_CMD_READ_XTD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) tq_init.actidx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) tq_init.idx = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) down(&tq_init_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) hp_sdc_enqueue_transaction(&tq_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067) down(&tq_init_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) up(&tq_init_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070) printk(KERN_WARNING PREFIX "Error reading extended config byte.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) hp_sdc.r7e = tq_init_seq[4];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) HP_SDC_XTD_REV_STRINGS(hp_sdc.r7e & HP_SDC_XTD_REV, str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) printk(KERN_INFO PREFIX "Revision: %s\n", str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) if (hp_sdc.r7e & HP_SDC_XTD_BEEPER)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) printk(KERN_INFO PREFIX "TI SN76494 beeper present\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078) if (hp_sdc.r7e & HP_SDC_XTD_BBRTC)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) printk(KERN_INFO PREFIX "OKI MSM-58321 BBRTC present\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) printk(KERN_INFO PREFIX "Spunking the self test register to force PUP "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) "on next firmware reset.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) tq_init_seq[0] = HP_SDC_ACT_PRECMD |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) tq_init_seq[1] = HP_SDC_CMD_SET_STR;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) tq_init_seq[2] = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) tq_init_seq[3] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) tq_init.actidx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) tq_init.idx = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) tq_init.endidx = 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) down(&tq_init_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) hp_sdc_enqueue_transaction(&tq_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) down(&tq_init_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) up(&tq_init_sem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) (hp_sdc.r11 & HP_SDC_CFG_REV) ? "3300" : "2564/3087");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) module_init(hp_sdc_register);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) module_exit(hp_sdc_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) /* Timing notes: These measurements taken on my 64MHz 7100-LC (715/64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) * cycles cycles-adj time
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) * between two consecutive mfctl(16)'s: 4 n/a 63ns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) * hp_sdc_spin_ibf when idle: 119 115 1.7us
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) * gsc_writeb status register: 83 79 1.2us
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) * IBF to clear after sending SET_IM: 6204 6006 93us
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) * IBF to clear after sending LOAD_RT: 4467 4352 68us
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) * IBF to clear after sending two LOAD_RTs: 18974 18859 295us
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) * READ_T1, read status/data, IRQ, call handler: 35564 n/a 556us
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) * cmd to ~IBF READ_T1 2nd time right after: 5158403 n/a 81ms
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) * between IRQ received and ~IBF for above: 2578877 n/a 40ms
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) * Performance stats after a run of this module configuring HIL and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) * receiving a few mouse events:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) * status in8 282508 cycles 7128 calls
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) * status out8 8404 cycles 341 calls
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) * data out8 1734 cycles 78 calls
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) * isr 174324 cycles 617 calls (includes take)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) * take 1241 cycles 2 calls
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) * put 1411504 cycles 6937 calls
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) * task 1655209 cycles 6937 calls (includes put)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) */