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