Commit | Line | Data |
---|---|---|
d10d6341 JW |
1 | /* |
2 | * Remote control driver for the TV-card based on bt829 | |
3 | * | |
4 | * by Leonid Froenchenko <lfroen@galileo.co.il> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | */ | |
20 | ||
21 | #include <linux/kernel.h> | |
22 | #include <linux/module.h> | |
23 | #include <linux/threads.h> | |
24 | #include <linux/sched.h> | |
25 | #include <linux/ioport.h> | |
26 | #include <linux/pci.h> | |
27 | #include <linux/delay.h> | |
28 | ||
29 | #include <media/lirc_dev.h> | |
30 | ||
31 | static int poll_main(void); | |
32 | static int atir_init_start(void); | |
33 | ||
34 | static void write_index(unsigned char index, unsigned int value); | |
35 | static unsigned int read_index(unsigned char index); | |
36 | ||
37 | static void do_i2c_start(void); | |
38 | static void do_i2c_stop(void); | |
39 | ||
40 | static void seems_wr_byte(unsigned char al); | |
41 | static unsigned char seems_rd_byte(void); | |
42 | ||
43 | static unsigned int read_index(unsigned char al); | |
44 | static void write_index(unsigned char ah, unsigned int edx); | |
45 | ||
46 | static void cycle_delay(int cycle); | |
47 | ||
48 | static void do_set_bits(unsigned char bl); | |
49 | static unsigned char do_get_bits(void); | |
50 | ||
51 | #define DATA_PCI_OFF 0x7FFC00 | |
52 | #define WAIT_CYCLE 20 | |
53 | ||
54 | #define DRIVER_NAME "lirc_bt829" | |
55 | ||
56 | static int debug; | |
57 | #define dprintk(fmt, args...) \ | |
58 | do { \ | |
59 | if (debug) \ | |
60 | printk(KERN_DEBUG DRIVER_NAME ": "fmt, ## args); \ | |
61 | } while (0) | |
62 | ||
63 | static int atir_minor; | |
64 | static unsigned long pci_addr_phys; | |
65 | static unsigned char *pci_addr_lin; | |
66 | ||
67 | static struct lirc_driver atir_driver; | |
68 | ||
69 | static struct pci_dev *do_pci_probe(void) | |
70 | { | |
71 | struct pci_dev *my_dev; | |
72 | my_dev = pci_get_device(PCI_VENDOR_ID_ATI, | |
73 | PCI_DEVICE_ID_ATI_264VT, NULL); | |
74 | if (my_dev) { | |
75 | printk(KERN_ERR DRIVER_NAME ": Using device: %s\n", | |
76 | pci_name(my_dev)); | |
77 | pci_addr_phys = 0; | |
78 | if (my_dev->resource[0].flags & IORESOURCE_MEM) { | |
79 | pci_addr_phys = my_dev->resource[0].start; | |
0f9313ad | 80 | printk(KERN_INFO DRIVER_NAME ": memory at 0x%08X\n", |
d10d6341 JW |
81 | (unsigned int)pci_addr_phys); |
82 | } | |
83 | if (pci_addr_phys == 0) { | |
84 | printk(KERN_ERR DRIVER_NAME ": no memory resource ?\n"); | |
85 | return NULL; | |
86 | } | |
87 | } else { | |
88 | printk(KERN_ERR DRIVER_NAME ": pci_probe failed\n"); | |
89 | return NULL; | |
90 | } | |
91 | return my_dev; | |
92 | } | |
93 | ||
94 | static int atir_add_to_buf(void *data, struct lirc_buffer *buf) | |
95 | { | |
96 | unsigned char key; | |
97 | int status; | |
98 | status = poll_main(); | |
99 | key = (status >> 8) & 0xFF; | |
100 | if (status & 0xFF) { | |
101 | dprintk("reading key %02X\n", key); | |
102 | lirc_buffer_write(buf, &key); | |
103 | return 0; | |
104 | } | |
105 | return -ENODATA; | |
106 | } | |
107 | ||
108 | static int atir_set_use_inc(void *data) | |
109 | { | |
110 | dprintk("driver is opened\n"); | |
111 | return 0; | |
112 | } | |
113 | ||
114 | static void atir_set_use_dec(void *data) | |
115 | { | |
116 | dprintk("driver is closed\n"); | |
117 | } | |
118 | ||
119 | int init_module(void) | |
120 | { | |
121 | struct pci_dev *pdev; | |
122 | ||
123 | pdev = do_pci_probe(); | |
124 | if (pdev == NULL) | |
125 | return 1; | |
126 | ||
127 | if (!atir_init_start()) | |
128 | return 1; | |
129 | ||
130 | strcpy(atir_driver.name, "ATIR"); | |
131 | atir_driver.minor = -1; | |
132 | atir_driver.code_length = 8; | |
133 | atir_driver.sample_rate = 10; | |
134 | atir_driver.data = 0; | |
135 | atir_driver.add_to_buf = atir_add_to_buf; | |
136 | atir_driver.set_use_inc = atir_set_use_inc; | |
137 | atir_driver.set_use_dec = atir_set_use_dec; | |
138 | atir_driver.dev = &pdev->dev; | |
139 | atir_driver.owner = THIS_MODULE; | |
140 | ||
141 | atir_minor = lirc_register_driver(&atir_driver); | |
142 | if (atir_minor < 0) { | |
143 | printk(KERN_ERR DRIVER_NAME ": failed to register driver!\n"); | |
144 | return atir_minor; | |
145 | } | |
146 | dprintk("driver is registered on minor %d\n", atir_minor); | |
147 | ||
148 | return 0; | |
149 | } | |
150 | ||
151 | ||
152 | void cleanup_module(void) | |
153 | { | |
154 | lirc_unregister_driver(atir_minor); | |
155 | } | |
156 | ||
157 | ||
158 | static int atir_init_start(void) | |
159 | { | |
160 | pci_addr_lin = ioremap(pci_addr_phys + DATA_PCI_OFF, 0x400); | |
161 | if (pci_addr_lin == 0) { | |
162 | printk(KERN_INFO DRIVER_NAME ": pci mem must be mapped\n"); | |
163 | return 0; | |
164 | } | |
165 | return 1; | |
166 | } | |
167 | ||
168 | static void cycle_delay(int cycle) | |
169 | { | |
170 | udelay(WAIT_CYCLE*cycle); | |
171 | } | |
172 | ||
173 | ||
174 | static int poll_main() | |
175 | { | |
176 | unsigned char status_high, status_low; | |
177 | ||
178 | do_i2c_start(); | |
179 | ||
180 | seems_wr_byte(0xAA); | |
181 | seems_wr_byte(0x01); | |
182 | ||
183 | do_i2c_start(); | |
184 | ||
185 | seems_wr_byte(0xAB); | |
186 | ||
187 | status_low = seems_rd_byte(); | |
188 | status_high = seems_rd_byte(); | |
189 | ||
190 | do_i2c_stop(); | |
191 | ||
192 | return (status_high << 8) | status_low; | |
193 | } | |
194 | ||
195 | static void do_i2c_start(void) | |
196 | { | |
197 | do_set_bits(3); | |
198 | cycle_delay(4); | |
199 | ||
200 | do_set_bits(1); | |
201 | cycle_delay(7); | |
202 | ||
203 | do_set_bits(0); | |
204 | cycle_delay(2); | |
205 | } | |
206 | ||
207 | static void do_i2c_stop(void) | |
208 | { | |
209 | unsigned char bits; | |
210 | bits = do_get_bits() & 0xFD; | |
211 | do_set_bits(bits); | |
212 | cycle_delay(1); | |
213 | ||
214 | bits |= 1; | |
215 | do_set_bits(bits); | |
216 | cycle_delay(2); | |
217 | ||
218 | bits |= 2; | |
219 | do_set_bits(bits); | |
220 | bits = 3; | |
221 | do_set_bits(bits); | |
222 | cycle_delay(2); | |
223 | } | |
224 | ||
225 | static void seems_wr_byte(unsigned char value) | |
226 | { | |
227 | int i; | |
228 | unsigned char reg; | |
229 | ||
230 | reg = do_get_bits(); | |
231 | for (i = 0; i < 8; i++) { | |
232 | if (value & 0x80) | |
233 | reg |= 0x02; | |
234 | else | |
235 | reg &= 0xFD; | |
236 | ||
237 | do_set_bits(reg); | |
238 | cycle_delay(1); | |
239 | ||
240 | reg |= 1; | |
241 | do_set_bits(reg); | |
242 | cycle_delay(1); | |
243 | ||
244 | reg &= 0xFE; | |
245 | do_set_bits(reg); | |
246 | cycle_delay(1); | |
247 | value <<= 1; | |
248 | } | |
249 | cycle_delay(2); | |
250 | ||
251 | reg |= 2; | |
252 | do_set_bits(reg); | |
253 | ||
254 | reg |= 1; | |
255 | do_set_bits(reg); | |
256 | ||
257 | cycle_delay(1); | |
258 | do_get_bits(); | |
259 | ||
260 | reg &= 0xFE; | |
261 | do_set_bits(reg); | |
262 | cycle_delay(3); | |
263 | } | |
264 | ||
265 | static unsigned char seems_rd_byte(void) | |
266 | { | |
267 | int i; | |
268 | int rd_byte; | |
269 | unsigned char bits_2, bits_1; | |
270 | ||
271 | bits_1 = do_get_bits() | 2; | |
272 | do_set_bits(bits_1); | |
273 | ||
274 | rd_byte = 0; | |
275 | for (i = 0; i < 8; i++) { | |
276 | bits_1 &= 0xFE; | |
277 | do_set_bits(bits_1); | |
278 | cycle_delay(2); | |
279 | ||
280 | bits_1 |= 1; | |
281 | do_set_bits(bits_1); | |
282 | cycle_delay(1); | |
283 | ||
284 | bits_2 = do_get_bits(); | |
285 | if (bits_2 & 2) | |
286 | rd_byte |= 1; | |
287 | ||
288 | rd_byte <<= 1; | |
289 | } | |
290 | ||
291 | bits_1 = 0; | |
292 | if (bits_2 == 0) | |
293 | bits_1 |= 2; | |
294 | ||
295 | do_set_bits(bits_1); | |
296 | cycle_delay(2); | |
297 | ||
298 | bits_1 |= 1; | |
299 | do_set_bits(bits_1); | |
300 | cycle_delay(3); | |
301 | ||
302 | bits_1 &= 0xFE; | |
303 | do_set_bits(bits_1); | |
304 | cycle_delay(2); | |
305 | ||
306 | rd_byte >>= 1; | |
307 | rd_byte &= 0xFF; | |
308 | return rd_byte; | |
309 | } | |
310 | ||
311 | static void do_set_bits(unsigned char new_bits) | |
312 | { | |
313 | int reg_val; | |
314 | reg_val = read_index(0x34); | |
315 | if (new_bits & 2) { | |
316 | reg_val &= 0xFFFFFFDF; | |
317 | reg_val |= 1; | |
318 | } else { | |
319 | reg_val &= 0xFFFFFFFE; | |
320 | reg_val |= 0x20; | |
321 | } | |
322 | reg_val |= 0x10; | |
323 | write_index(0x34, reg_val); | |
324 | ||
325 | reg_val = read_index(0x31); | |
326 | if (new_bits & 1) | |
327 | reg_val |= 0x1000000; | |
328 | else | |
329 | reg_val &= 0xFEFFFFFF; | |
330 | ||
331 | reg_val |= 0x8000000; | |
332 | write_index(0x31, reg_val); | |
333 | } | |
334 | ||
335 | static unsigned char do_get_bits(void) | |
336 | { | |
337 | unsigned char bits; | |
338 | int reg_val; | |
339 | ||
340 | reg_val = read_index(0x34); | |
341 | reg_val |= 0x10; | |
342 | reg_val &= 0xFFFFFFDF; | |
343 | write_index(0x34, reg_val); | |
344 | ||
345 | reg_val = read_index(0x34); | |
346 | bits = 0; | |
347 | if (reg_val & 8) | |
348 | bits |= 2; | |
349 | else | |
350 | bits &= 0xFD; | |
351 | ||
352 | reg_val = read_index(0x31); | |
353 | if (reg_val & 0x1000000) | |
354 | bits |= 1; | |
355 | else | |
356 | bits &= 0xFE; | |
357 | ||
358 | return bits; | |
359 | } | |
360 | ||
361 | static unsigned int read_index(unsigned char index) | |
362 | { | |
363 | unsigned char *addr; | |
364 | unsigned int value; | |
365 | /* addr = pci_addr_lin + DATA_PCI_OFF + ((index & 0xFF) << 2); */ | |
366 | addr = pci_addr_lin + ((index & 0xFF) << 2); | |
367 | value = readl(addr); | |
368 | return value; | |
369 | } | |
370 | ||
371 | static void write_index(unsigned char index, unsigned int reg_val) | |
372 | { | |
373 | unsigned char *addr; | |
374 | addr = pci_addr_lin + ((index & 0xFF) << 2); | |
375 | writel(reg_val, addr); | |
376 | } | |
377 | ||
378 | MODULE_AUTHOR("Froenchenko Leonid"); | |
379 | MODULE_DESCRIPTION("IR remote driver for bt829 based TV cards"); | |
380 | MODULE_LICENSE("GPL"); | |
381 | ||
382 | module_param(debug, bool, S_IRUGO | S_IWUSR); | |
383 | MODULE_PARM_DESC(debug, "Debug enabled or not"); |