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