0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064 #include <linux/hp_sdc.h>
0065 #include <linux/errno.h>
0066 #include <linux/init.h>
0067 #include <linux/module.h>
0068 #include <linux/ioport.h>
0069 #include <linux/time.h>
0070 #include <linux/semaphore.h>
0071 #include <linux/slab.h>
0072 #include <linux/hil.h>
0073 #include <asm/io.h>
0074
0075
0076
0077 #if defined(__hppa__)
0078 # include <asm/parisc-device.h>
0079 # define sdc_readb(p) gsc_readb(p)
0080 # define sdc_writeb(v,p) gsc_writeb((v),(p))
0081 #elif defined(__mc68000__)
0082 #include <linux/uaccess.h>
0083 # define sdc_readb(p) in_8(p)
0084 # define sdc_writeb(v,p) out_8((p),(v))
0085 #else
0086 # error "HIL is not supported on this platform"
0087 #endif
0088
0089 #define PREFIX "HP SDC: "
0090
0091 MODULE_AUTHOR("Brian S. Julin <bri@calyx.com>");
0092 MODULE_DESCRIPTION("HP i8042-based SDC Driver");
0093 MODULE_LICENSE("Dual BSD/GPL");
0094
0095 EXPORT_SYMBOL(hp_sdc_request_timer_irq);
0096 EXPORT_SYMBOL(hp_sdc_request_hil_irq);
0097 EXPORT_SYMBOL(hp_sdc_request_cooked_irq);
0098
0099 EXPORT_SYMBOL(hp_sdc_release_timer_irq);
0100 EXPORT_SYMBOL(hp_sdc_release_hil_irq);
0101 EXPORT_SYMBOL(hp_sdc_release_cooked_irq);
0102
0103 EXPORT_SYMBOL(__hp_sdc_enqueue_transaction);
0104 EXPORT_SYMBOL(hp_sdc_enqueue_transaction);
0105 EXPORT_SYMBOL(hp_sdc_dequeue_transaction);
0106
0107 static bool hp_sdc_disabled;
0108 module_param_named(no_hpsdc, hp_sdc_disabled, bool, 0);
0109 MODULE_PARM_DESC(no_hpsdc, "Do not enable HP SDC driver.");
0110
0111 static hp_i8042_sdc hp_sdc;
0112
0113
0114 static inline uint8_t hp_sdc_status_in8(void)
0115 {
0116 uint8_t status;
0117 unsigned long flags;
0118
0119 write_lock_irqsave(&hp_sdc.ibf_lock, flags);
0120 status = sdc_readb(hp_sdc.status_io);
0121 if (!(status & HP_SDC_STATUS_IBF))
0122 hp_sdc.ibf = 0;
0123 write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
0124
0125 return status;
0126 }
0127
0128 static inline uint8_t hp_sdc_data_in8(void)
0129 {
0130 return sdc_readb(hp_sdc.data_io);
0131 }
0132
0133 static inline void hp_sdc_status_out8(uint8_t val)
0134 {
0135 unsigned long flags;
0136
0137 write_lock_irqsave(&hp_sdc.ibf_lock, flags);
0138 hp_sdc.ibf = 1;
0139 if ((val & 0xf0) == 0xe0)
0140 hp_sdc.wi = 0xff;
0141 sdc_writeb(val, hp_sdc.status_io);
0142 write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
0143 }
0144
0145 static inline void hp_sdc_data_out8(uint8_t val)
0146 {
0147 unsigned long flags;
0148
0149 write_lock_irqsave(&hp_sdc.ibf_lock, flags);
0150 hp_sdc.ibf = 1;
0151 sdc_writeb(val, hp_sdc.data_io);
0152 write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);
0153 }
0154
0155
0156
0157
0158
0159 static inline void hp_sdc_spin_ibf(void)
0160 {
0161 unsigned long flags;
0162 rwlock_t *lock;
0163
0164 lock = &hp_sdc.ibf_lock;
0165
0166 read_lock_irqsave(lock, flags);
0167 if (!hp_sdc.ibf) {
0168 read_unlock_irqrestore(lock, flags);
0169 return;
0170 }
0171 read_unlock(lock);
0172 write_lock(lock);
0173 while (sdc_readb(hp_sdc.status_io) & HP_SDC_STATUS_IBF)
0174 { }
0175 hp_sdc.ibf = 0;
0176 write_unlock_irqrestore(lock, flags);
0177 }
0178
0179
0180
0181 static void hp_sdc_take(int irq, void *dev_id, uint8_t status, uint8_t data)
0182 {
0183 hp_sdc_transaction *curr;
0184
0185 read_lock(&hp_sdc.rtq_lock);
0186 if (hp_sdc.rcurr < 0) {
0187 read_unlock(&hp_sdc.rtq_lock);
0188 return;
0189 }
0190 curr = hp_sdc.tq[hp_sdc.rcurr];
0191 read_unlock(&hp_sdc.rtq_lock);
0192
0193 curr->seq[curr->idx++] = status;
0194 curr->seq[curr->idx++] = data;
0195 hp_sdc.rqty -= 2;
0196 hp_sdc.rtime = ktime_get();
0197
0198 if (hp_sdc.rqty <= 0) {
0199
0200 if (curr->seq[curr->actidx] & HP_SDC_ACT_SEMAPHORE)
0201 if (curr->act.semaphore)
0202 up(curr->act.semaphore);
0203
0204 if (curr->seq[curr->actidx] & HP_SDC_ACT_CALLBACK)
0205 if (curr->act.irqhook)
0206 curr->act.irqhook(irq, dev_id, status, data);
0207
0208 curr->actidx = curr->idx;
0209 curr->idx++;
0210
0211 write_lock(&hp_sdc.rtq_lock);
0212 hp_sdc.rcurr = -1;
0213 hp_sdc.rqty = 0;
0214 write_unlock(&hp_sdc.rtq_lock);
0215 tasklet_schedule(&hp_sdc.task);
0216 }
0217 }
0218
0219 static irqreturn_t hp_sdc_isr(int irq, void *dev_id)
0220 {
0221 uint8_t status, data;
0222
0223 status = hp_sdc_status_in8();
0224
0225 data = hp_sdc_data_in8();
0226
0227
0228 if (((status & 0xf1) == 0x51) && data == 0x82)
0229 return IRQ_HANDLED;
0230
0231 switch (status & HP_SDC_STATUS_IRQMASK) {
0232 case 0:
0233 break;
0234
0235 case HP_SDC_STATUS_USERTIMER:
0236 case HP_SDC_STATUS_PERIODIC:
0237 case HP_SDC_STATUS_TIMER:
0238 read_lock(&hp_sdc.hook_lock);
0239 if (hp_sdc.timer != NULL)
0240 hp_sdc.timer(irq, dev_id, status, data);
0241 read_unlock(&hp_sdc.hook_lock);
0242 break;
0243
0244 case HP_SDC_STATUS_REG:
0245 hp_sdc_take(irq, dev_id, status, data);
0246 break;
0247
0248 case HP_SDC_STATUS_HILCMD:
0249 case HP_SDC_STATUS_HILDATA:
0250 read_lock(&hp_sdc.hook_lock);
0251 if (hp_sdc.hil != NULL)
0252 hp_sdc.hil(irq, dev_id, status, data);
0253 read_unlock(&hp_sdc.hook_lock);
0254 break;
0255
0256 case HP_SDC_STATUS_PUP:
0257 read_lock(&hp_sdc.hook_lock);
0258 if (hp_sdc.pup != NULL)
0259 hp_sdc.pup(irq, dev_id, status, data);
0260 else
0261 printk(KERN_INFO PREFIX "HP SDC reports successful PUP.\n");
0262 read_unlock(&hp_sdc.hook_lock);
0263 break;
0264
0265 default:
0266 read_lock(&hp_sdc.hook_lock);
0267 if (hp_sdc.cooked != NULL)
0268 hp_sdc.cooked(irq, dev_id, status, data);
0269 read_unlock(&hp_sdc.hook_lock);
0270 break;
0271 }
0272
0273 return IRQ_HANDLED;
0274 }
0275
0276
0277 static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id)
0278 {
0279 int status;
0280
0281 status = hp_sdc_status_in8();
0282 printk(KERN_WARNING PREFIX "NMI !\n");
0283
0284 #if 0
0285 if (status & HP_SDC_NMISTATUS_FHS) {
0286 read_lock(&hp_sdc.hook_lock);
0287 if (hp_sdc.timer != NULL)
0288 hp_sdc.timer(irq, dev_id, status, 0);
0289 read_unlock(&hp_sdc.hook_lock);
0290 } else {
0291
0292 printk(KERN_WARNING PREFIX "HIL NMI\n");
0293 }
0294 #endif
0295
0296 return IRQ_HANDLED;
0297 }
0298
0299
0300
0301
0302 unsigned long hp_sdc_put(void);
0303
0304 static void hp_sdc_tasklet(unsigned long foo)
0305 {
0306 write_lock_irq(&hp_sdc.rtq_lock);
0307
0308 if (hp_sdc.rcurr >= 0) {
0309 ktime_t now = ktime_get();
0310
0311 if (ktime_after(now, ktime_add_us(hp_sdc.rtime,
0312 HP_SDC_MAX_REG_DELAY))) {
0313 hp_sdc_transaction *curr;
0314 uint8_t tmp;
0315
0316 curr = hp_sdc.tq[hp_sdc.rcurr];
0317
0318
0319
0320
0321 printk(KERN_WARNING PREFIX "read timeout (%lldus)!\n",
0322 ktime_us_delta(now, hp_sdc.rtime));
0323 curr->idx += hp_sdc.rqty;
0324 hp_sdc.rqty = 0;
0325 tmp = curr->seq[curr->actidx];
0326 curr->seq[curr->actidx] |= HP_SDC_ACT_DEAD;
0327 if (tmp & HP_SDC_ACT_SEMAPHORE)
0328 if (curr->act.semaphore)
0329 up(curr->act.semaphore);
0330
0331 if (tmp & HP_SDC_ACT_CALLBACK) {
0332
0333
0334
0335 if (curr->act.irqhook)
0336 curr->act.irqhook(0, NULL, 0, 0);
0337 }
0338
0339 curr->actidx = curr->idx;
0340 curr->idx++;
0341 hp_sdc.rcurr = -1;
0342 }
0343 }
0344 write_unlock_irq(&hp_sdc.rtq_lock);
0345 hp_sdc_put();
0346 }
0347
0348 unsigned long hp_sdc_put(void)
0349 {
0350 hp_sdc_transaction *curr;
0351 uint8_t act;
0352 int idx, curridx;
0353
0354 int limit = 0;
0355
0356 write_lock(&hp_sdc.lock);
0357
0358
0359
0360 if (hp_sdc.ibf) {
0361 hp_sdc_status_in8();
0362 if (hp_sdc.ibf)
0363 goto finish;
0364 }
0365
0366 anew:
0367
0368 if (hp_sdc.wcurr < 0)
0369 hp_sdc.wcurr = 0;
0370 read_lock_irq(&hp_sdc.rtq_lock);
0371 if (hp_sdc.rcurr == hp_sdc.wcurr)
0372 hp_sdc.wcurr++;
0373 read_unlock_irq(&hp_sdc.rtq_lock);
0374 if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
0375 hp_sdc.wcurr = 0;
0376 curridx = hp_sdc.wcurr;
0377
0378 if (hp_sdc.tq[curridx] != NULL)
0379 goto start;
0380
0381 while (++curridx != hp_sdc.wcurr) {
0382 if (curridx >= HP_SDC_QUEUE_LEN) {
0383 curridx = -1;
0384 continue;
0385 }
0386 read_lock_irq(&hp_sdc.rtq_lock);
0387 if (hp_sdc.rcurr == curridx) {
0388 read_unlock_irq(&hp_sdc.rtq_lock);
0389 continue;
0390 }
0391 read_unlock_irq(&hp_sdc.rtq_lock);
0392 if (hp_sdc.tq[curridx] != NULL)
0393 break;
0394 }
0395 if (curridx == hp_sdc.wcurr) {
0396 curridx = -1;
0397 }
0398 hp_sdc.wcurr = curridx;
0399
0400 start:
0401
0402
0403 if (hp_sdc.set_im) {
0404 hp_sdc_status_out8(hp_sdc.im | HP_SDC_CMD_SET_IM);
0405 hp_sdc.set_im = 0;
0406 goto finish;
0407 }
0408
0409 if (hp_sdc.wcurr == -1)
0410 goto done;
0411
0412 curr = hp_sdc.tq[curridx];
0413 idx = curr->actidx;
0414
0415 if (curr->actidx >= curr->endidx) {
0416 hp_sdc.tq[curridx] = NULL;
0417
0418 hp_sdc.wcurr++;
0419 if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
0420 hp_sdc.wcurr = 0;
0421 goto finish;
0422 }
0423
0424 act = curr->seq[idx];
0425 idx++;
0426
0427 if (curr->idx >= curr->endidx) {
0428 if (act & HP_SDC_ACT_DEALLOC)
0429 kfree(curr);
0430 hp_sdc.tq[curridx] = NULL;
0431
0432 hp_sdc.wcurr++;
0433 if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
0434 hp_sdc.wcurr = 0;
0435 goto finish;
0436 }
0437
0438 while (act & HP_SDC_ACT_PRECMD) {
0439 if (curr->idx != idx) {
0440 idx++;
0441 act &= ~HP_SDC_ACT_PRECMD;
0442 break;
0443 }
0444 hp_sdc_status_out8(curr->seq[idx]);
0445 curr->idx++;
0446
0447 if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_PRECMD)
0448 goto actdone;
0449
0450 if (act & HP_SDC_ACT_DATAOUT)
0451 curr->idx++;
0452 goto finish;
0453 }
0454 if (act & HP_SDC_ACT_DATAOUT) {
0455 int qty;
0456
0457 qty = curr->seq[idx];
0458 idx++;
0459 if (curr->idx - idx < qty) {
0460 hp_sdc_data_out8(curr->seq[curr->idx]);
0461 curr->idx++;
0462
0463 if (curr->idx - idx >= qty &&
0464 (act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAOUT)
0465 goto actdone;
0466 goto finish;
0467 }
0468 idx += qty;
0469 act &= ~HP_SDC_ACT_DATAOUT;
0470 } else
0471 while (act & HP_SDC_ACT_DATAREG) {
0472 int mask;
0473 uint8_t w7[4];
0474
0475 mask = curr->seq[idx];
0476 if (idx != curr->idx) {
0477 idx++;
0478 idx += !!(mask & 1);
0479 idx += !!(mask & 2);
0480 idx += !!(mask & 4);
0481 idx += !!(mask & 8);
0482 act &= ~HP_SDC_ACT_DATAREG;
0483 break;
0484 }
0485
0486 w7[0] = (mask & 1) ? curr->seq[++idx] : hp_sdc.r7[0];
0487 w7[1] = (mask & 2) ? curr->seq[++idx] : hp_sdc.r7[1];
0488 w7[2] = (mask & 4) ? curr->seq[++idx] : hp_sdc.r7[2];
0489 w7[3] = (mask & 8) ? curr->seq[++idx] : hp_sdc.r7[3];
0490
0491 if (hp_sdc.wi > 0x73 || hp_sdc.wi < 0x70 ||
0492 w7[hp_sdc.wi - 0x70] == hp_sdc.r7[hp_sdc.wi - 0x70]) {
0493 int i = 0;
0494
0495
0496 while (i < 4 && w7[i] == hp_sdc.r7[i])
0497 i++;
0498
0499 if (i < 4) {
0500 hp_sdc_status_out8(HP_SDC_CMD_SET_D0 + i);
0501 hp_sdc.wi = 0x70 + i;
0502 goto finish;
0503 }
0504
0505 idx++;
0506 if ((act & HP_SDC_ACT_DURING) == HP_SDC_ACT_DATAREG)
0507 goto actdone;
0508
0509 curr->idx = idx;
0510 act &= ~HP_SDC_ACT_DATAREG;
0511 break;
0512 }
0513
0514 hp_sdc_data_out8(w7[hp_sdc.wi - 0x70]);
0515 hp_sdc.r7[hp_sdc.wi - 0x70] = w7[hp_sdc.wi - 0x70];
0516 hp_sdc.wi++;
0517 {
0518 int i = 0;
0519
0520 while ((i < 4) && w7[i] == hp_sdc.r7[i])
0521 i++;
0522 if (i >= 4) {
0523 curr->idx = idx + 1;
0524 if ((act & HP_SDC_ACT_DURING) ==
0525 HP_SDC_ACT_DATAREG)
0526 goto actdone;
0527 }
0528 }
0529 goto finish;
0530 }
0531
0532
0533 read_lock_irq(&hp_sdc.rtq_lock);
0534 if (hp_sdc.rcurr >= 0) {
0535 read_unlock_irq(&hp_sdc.rtq_lock);
0536 goto finish;
0537 }
0538 read_unlock_irq(&hp_sdc.rtq_lock);
0539
0540
0541 if (act & HP_SDC_ACT_POSTCMD) {
0542 uint8_t postcmd;
0543
0544
0545 postcmd = curr->seq[idx];
0546 curr->idx++;
0547 if (act & HP_SDC_ACT_DATAIN) {
0548
0549
0550 hp_sdc.rqty = curr->seq[curr->idx];
0551 hp_sdc.rtime = ktime_get();
0552 curr->idx++;
0553
0554 write_lock_irq(&hp_sdc.rtq_lock);
0555 hp_sdc.rcurr = curridx;
0556 write_unlock_irq(&hp_sdc.rtq_lock);
0557 hp_sdc_status_out8(postcmd);
0558 goto finish;
0559 }
0560 hp_sdc_status_out8(postcmd);
0561 goto actdone;
0562 }
0563
0564 actdone:
0565 if (act & HP_SDC_ACT_SEMAPHORE)
0566 up(curr->act.semaphore);
0567 else if (act & HP_SDC_ACT_CALLBACK)
0568 curr->act.irqhook(0,NULL,0,0);
0569
0570 if (curr->idx >= curr->endidx) {
0571 if (act & HP_SDC_ACT_DEALLOC)
0572 kfree(curr);
0573 hp_sdc.tq[curridx] = NULL;
0574 } else {
0575 curr->actidx = idx + 1;
0576 curr->idx = idx + 2;
0577 }
0578
0579 hp_sdc.wcurr++;
0580 if (hp_sdc.wcurr >= HP_SDC_QUEUE_LEN)
0581 hp_sdc.wcurr = 0;
0582
0583 finish:
0584
0585
0586 if (!hp_sdc.ibf && limit++ < 20)
0587 goto anew;
0588
0589 done:
0590 if (hp_sdc.wcurr >= 0)
0591 tasklet_schedule(&hp_sdc.task);
0592 write_unlock(&hp_sdc.lock);
0593
0594 return 0;
0595 }
0596
0597
0598 int __hp_sdc_enqueue_transaction(hp_sdc_transaction *this)
0599 {
0600 int i;
0601
0602 if (this == NULL) {
0603 BUG();
0604 return -EINVAL;
0605 }
0606
0607
0608 for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
0609 if (hp_sdc.tq[i] == this)
0610 goto fail;
0611
0612 this->actidx = 0;
0613 this->idx = 1;
0614
0615
0616 for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
0617 if (hp_sdc.tq[i] == NULL) {
0618 hp_sdc.tq[i] = this;
0619 tasklet_schedule(&hp_sdc.task);
0620 return 0;
0621 }
0622
0623 printk(KERN_WARNING PREFIX "No free slot to add transaction.\n");
0624 return -EBUSY;
0625
0626 fail:
0627 printk(KERN_WARNING PREFIX "Transaction add failed: transaction already queued?\n");
0628 return -EINVAL;
0629 }
0630
0631 int hp_sdc_enqueue_transaction(hp_sdc_transaction *this) {
0632 unsigned long flags;
0633 int ret;
0634
0635 write_lock_irqsave(&hp_sdc.lock, flags);
0636 ret = __hp_sdc_enqueue_transaction(this);
0637 write_unlock_irqrestore(&hp_sdc.lock,flags);
0638
0639 return ret;
0640 }
0641
0642 int hp_sdc_dequeue_transaction(hp_sdc_transaction *this)
0643 {
0644 unsigned long flags;
0645 int i;
0646
0647 write_lock_irqsave(&hp_sdc.lock, flags);
0648
0649
0650
0651 for (i = 0; i < HP_SDC_QUEUE_LEN; i++)
0652 if (hp_sdc.tq[i] == this)
0653 hp_sdc.tq[i] = NULL;
0654
0655 write_unlock_irqrestore(&hp_sdc.lock, flags);
0656 return 0;
0657 }
0658
0659
0660
0661
0662 int hp_sdc_request_timer_irq(hp_sdc_irqhook *callback)
0663 {
0664 if (callback == NULL || hp_sdc.dev == NULL)
0665 return -EINVAL;
0666
0667 write_lock_irq(&hp_sdc.hook_lock);
0668 if (hp_sdc.timer != NULL) {
0669 write_unlock_irq(&hp_sdc.hook_lock);
0670 return -EBUSY;
0671 }
0672
0673 hp_sdc.timer = callback;
0674
0675 hp_sdc.im &= ~HP_SDC_IM_FH;
0676 hp_sdc.im &= ~HP_SDC_IM_PT;
0677 hp_sdc.im &= ~HP_SDC_IM_TIMERS;
0678 hp_sdc.set_im = 1;
0679 write_unlock_irq(&hp_sdc.hook_lock);
0680
0681 tasklet_schedule(&hp_sdc.task);
0682
0683 return 0;
0684 }
0685
0686 int hp_sdc_request_hil_irq(hp_sdc_irqhook *callback)
0687 {
0688 if (callback == NULL || hp_sdc.dev == NULL)
0689 return -EINVAL;
0690
0691 write_lock_irq(&hp_sdc.hook_lock);
0692 if (hp_sdc.hil != NULL) {
0693 write_unlock_irq(&hp_sdc.hook_lock);
0694 return -EBUSY;
0695 }
0696
0697 hp_sdc.hil = callback;
0698 hp_sdc.im &= ~(HP_SDC_IM_HIL | HP_SDC_IM_RESET);
0699 hp_sdc.set_im = 1;
0700 write_unlock_irq(&hp_sdc.hook_lock);
0701
0702 tasklet_schedule(&hp_sdc.task);
0703
0704 return 0;
0705 }
0706
0707 int hp_sdc_request_cooked_irq(hp_sdc_irqhook *callback)
0708 {
0709 if (callback == NULL || hp_sdc.dev == NULL)
0710 return -EINVAL;
0711
0712 write_lock_irq(&hp_sdc.hook_lock);
0713 if (hp_sdc.cooked != NULL) {
0714 write_unlock_irq(&hp_sdc.hook_lock);
0715 return -EBUSY;
0716 }
0717
0718
0719 hp_sdc.cooked = callback;
0720 hp_sdc.im &= ~(HP_SDC_IM_HIL | HP_SDC_IM_RESET);
0721 hp_sdc.set_im = 1;
0722 write_unlock_irq(&hp_sdc.hook_lock);
0723
0724 tasklet_schedule(&hp_sdc.task);
0725
0726 return 0;
0727 }
0728
0729 int hp_sdc_release_timer_irq(hp_sdc_irqhook *callback)
0730 {
0731 write_lock_irq(&hp_sdc.hook_lock);
0732 if ((callback != hp_sdc.timer) ||
0733 (hp_sdc.timer == NULL)) {
0734 write_unlock_irq(&hp_sdc.hook_lock);
0735 return -EINVAL;
0736 }
0737
0738
0739 hp_sdc.timer = NULL;
0740 hp_sdc.im |= HP_SDC_IM_TIMERS;
0741 hp_sdc.im |= HP_SDC_IM_FH;
0742 hp_sdc.im |= HP_SDC_IM_PT;
0743 hp_sdc.set_im = 1;
0744 write_unlock_irq(&hp_sdc.hook_lock);
0745 tasklet_schedule(&hp_sdc.task);
0746
0747 return 0;
0748 }
0749
0750 int hp_sdc_release_hil_irq(hp_sdc_irqhook *callback)
0751 {
0752 write_lock_irq(&hp_sdc.hook_lock);
0753 if ((callback != hp_sdc.hil) ||
0754 (hp_sdc.hil == NULL)) {
0755 write_unlock_irq(&hp_sdc.hook_lock);
0756 return -EINVAL;
0757 }
0758
0759 hp_sdc.hil = NULL;
0760
0761 if(hp_sdc.cooked == NULL) {
0762 hp_sdc.im |= (HP_SDC_IM_HIL | HP_SDC_IM_RESET);
0763 hp_sdc.set_im = 1;
0764 }
0765 write_unlock_irq(&hp_sdc.hook_lock);
0766 tasklet_schedule(&hp_sdc.task);
0767
0768 return 0;
0769 }
0770
0771 int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback)
0772 {
0773 write_lock_irq(&hp_sdc.hook_lock);
0774 if ((callback != hp_sdc.cooked) ||
0775 (hp_sdc.cooked == NULL)) {
0776 write_unlock_irq(&hp_sdc.hook_lock);
0777 return -EINVAL;
0778 }
0779
0780 hp_sdc.cooked = NULL;
0781
0782 if(hp_sdc.hil == NULL) {
0783 hp_sdc.im |= (HP_SDC_IM_HIL | HP_SDC_IM_RESET);
0784 hp_sdc.set_im = 1;
0785 }
0786 write_unlock_irq(&hp_sdc.hook_lock);
0787 tasklet_schedule(&hp_sdc.task);
0788
0789 return 0;
0790 }
0791
0792
0793
0794 static void hp_sdc_kicker(struct timer_list *unused)
0795 {
0796 tasklet_schedule(&hp_sdc.task);
0797
0798 mod_timer(&hp_sdc.kicker, jiffies + HZ);
0799 }
0800
0801
0802
0803 #if defined(__hppa__)
0804
0805 static const struct parisc_device_id hp_sdc_tbl[] __initconst = {
0806 {
0807 .hw_type = HPHW_FIO,
0808 .hversion_rev = HVERSION_REV_ANY_ID,
0809 .hversion = HVERSION_ANY_ID,
0810 .sversion = 0x73,
0811 },
0812 { 0, }
0813 };
0814
0815 MODULE_DEVICE_TABLE(parisc, hp_sdc_tbl);
0816
0817 static int __init hp_sdc_init_hppa(struct parisc_device *d);
0818 static struct delayed_work moduleloader_work;
0819
0820 static struct parisc_driver hp_sdc_driver __refdata = {
0821 .name = "hp_sdc",
0822 .id_table = hp_sdc_tbl,
0823 .probe = hp_sdc_init_hppa,
0824 };
0825
0826 #endif
0827
0828 static int __init hp_sdc_init(void)
0829 {
0830 char *errstr;
0831 hp_sdc_transaction t_sync;
0832 uint8_t ts_sync[6];
0833 struct semaphore s_sync;
0834
0835 rwlock_init(&hp_sdc.lock);
0836 rwlock_init(&hp_sdc.ibf_lock);
0837 rwlock_init(&hp_sdc.rtq_lock);
0838 rwlock_init(&hp_sdc.hook_lock);
0839
0840 hp_sdc.timer = NULL;
0841 hp_sdc.hil = NULL;
0842 hp_sdc.pup = NULL;
0843 hp_sdc.cooked = NULL;
0844 hp_sdc.im = HP_SDC_IM_MASK;
0845 hp_sdc.set_im = 1;
0846 hp_sdc.wi = 0xff;
0847 hp_sdc.r7[0] = 0xff;
0848 hp_sdc.r7[1] = 0xff;
0849 hp_sdc.r7[2] = 0xff;
0850 hp_sdc.r7[3] = 0xff;
0851 hp_sdc.ibf = 1;
0852
0853 memset(&hp_sdc.tq, 0, sizeof(hp_sdc.tq));
0854
0855 hp_sdc.wcurr = -1;
0856 hp_sdc.rcurr = -1;
0857 hp_sdc.rqty = 0;
0858
0859 hp_sdc.dev_err = -ENODEV;
0860
0861 errstr = "IO not found for";
0862 if (!hp_sdc.base_io)
0863 goto err0;
0864
0865 errstr = "IRQ not found for";
0866 if (!hp_sdc.irq)
0867 goto err0;
0868
0869 hp_sdc.dev_err = -EBUSY;
0870
0871 #if defined(__hppa__)
0872 errstr = "IO not available for";
0873 if (request_region(hp_sdc.data_io, 2, hp_sdc_driver.name))
0874 goto err0;
0875 #endif
0876
0877 errstr = "IRQ not available for";
0878 if (request_irq(hp_sdc.irq, &hp_sdc_isr, IRQF_SHARED,
0879 "HP SDC", &hp_sdc))
0880 goto err1;
0881
0882 errstr = "NMI not available for";
0883 if (request_irq(hp_sdc.nmi, &hp_sdc_nmisr, IRQF_SHARED,
0884 "HP SDC NMI", &hp_sdc))
0885 goto err2;
0886
0887 pr_info(PREFIX "HP SDC at 0x%08lx, IRQ %d (NMI IRQ %d)\n",
0888 hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
0889
0890 hp_sdc_status_in8();
0891 hp_sdc_data_in8();
0892
0893 tasklet_init(&hp_sdc.task, hp_sdc_tasklet, 0);
0894
0895
0896 t_sync.actidx = 0;
0897 t_sync.idx = 1;
0898 t_sync.endidx = 6;
0899 t_sync.seq = ts_sync;
0900 ts_sync[0] = HP_SDC_ACT_DATAREG | HP_SDC_ACT_SEMAPHORE;
0901 ts_sync[1] = 0x0f;
0902 ts_sync[2] = ts_sync[3] = ts_sync[4] = ts_sync[5] = 0;
0903 t_sync.act.semaphore = &s_sync;
0904 sema_init(&s_sync, 0);
0905 hp_sdc_enqueue_transaction(&t_sync);
0906 down(&s_sync);
0907
0908
0909 timer_setup(&hp_sdc.kicker, hp_sdc_kicker, 0);
0910 hp_sdc.kicker.expires = jiffies + HZ;
0911 add_timer(&hp_sdc.kicker);
0912
0913 hp_sdc.dev_err = 0;
0914 return 0;
0915 err2:
0916 free_irq(hp_sdc.irq, &hp_sdc);
0917 err1:
0918 release_region(hp_sdc.data_io, 2);
0919 err0:
0920 printk(KERN_WARNING PREFIX ": %s SDC IO=0x%p IRQ=0x%x NMI=0x%x\n",
0921 errstr, (void *)hp_sdc.base_io, hp_sdc.irq, hp_sdc.nmi);
0922 hp_sdc.dev = NULL;
0923
0924 return hp_sdc.dev_err;
0925 }
0926
0927 #if defined(__hppa__)
0928
0929 static void request_module_delayed(struct work_struct *work)
0930 {
0931 request_module("hp_sdc_mlc");
0932 }
0933
0934 static int __init hp_sdc_init_hppa(struct parisc_device *d)
0935 {
0936 int ret;
0937
0938 if (!d)
0939 return 1;
0940 if (hp_sdc.dev != NULL)
0941 return 1;
0942
0943 hp_sdc.dev = d;
0944 hp_sdc.irq = d->irq;
0945 hp_sdc.nmi = d->aux_irq;
0946 hp_sdc.base_io = d->hpa.start;
0947 hp_sdc.data_io = d->hpa.start + 0x800;
0948 hp_sdc.status_io = d->hpa.start + 0x801;
0949
0950 INIT_DELAYED_WORK(&moduleloader_work, request_module_delayed);
0951
0952 ret = hp_sdc_init();
0953
0954
0955 if (!ret)
0956 schedule_delayed_work(&moduleloader_work,
0957 msecs_to_jiffies(2000));
0958
0959 return ret;
0960 }
0961
0962 #endif
0963
0964 static void hp_sdc_exit(void)
0965 {
0966
0967 if (!hp_sdc.dev)
0968 return;
0969
0970 write_lock_irq(&hp_sdc.lock);
0971
0972
0973 hp_sdc_spin_ibf();
0974 sdc_writeb(HP_SDC_CMD_SET_IM | HP_SDC_IM_MASK, hp_sdc.status_io);
0975
0976
0977 hp_sdc_spin_ibf();
0978
0979 free_irq(hp_sdc.nmi, &hp_sdc);
0980 free_irq(hp_sdc.irq, &hp_sdc);
0981 write_unlock_irq(&hp_sdc.lock);
0982
0983 del_timer_sync(&hp_sdc.kicker);
0984
0985 tasklet_kill(&hp_sdc.task);
0986
0987 #if defined(__hppa__)
0988 cancel_delayed_work_sync(&moduleloader_work);
0989 if (unregister_parisc_driver(&hp_sdc_driver))
0990 printk(KERN_WARNING PREFIX "Error unregistering HP SDC");
0991 #endif
0992 }
0993
0994 static int __init hp_sdc_register(void)
0995 {
0996 hp_sdc_transaction tq_init;
0997 uint8_t tq_init_seq[5];
0998 struct semaphore tq_init_sem;
0999 #if defined(__mc68000__)
1000 unsigned char i;
1001 #endif
1002
1003 if (hp_sdc_disabled) {
1004 printk(KERN_WARNING PREFIX "HP SDC driver disabled by no_hpsdc=1.\n");
1005 return -ENODEV;
1006 }
1007
1008 hp_sdc.dev = NULL;
1009 hp_sdc.dev_err = 0;
1010 #if defined(__hppa__)
1011 if (register_parisc_driver(&hp_sdc_driver)) {
1012 printk(KERN_WARNING PREFIX "Error registering SDC with system bus tree.\n");
1013 return -ENODEV;
1014 }
1015 #elif defined(__mc68000__)
1016 if (!MACH_IS_HP300)
1017 return -ENODEV;
1018
1019 hp_sdc.irq = 1;
1020 hp_sdc.nmi = 7;
1021 hp_sdc.base_io = (unsigned long) 0xf0428000;
1022 hp_sdc.data_io = (unsigned long) hp_sdc.base_io + 1;
1023 hp_sdc.status_io = (unsigned long) hp_sdc.base_io + 3;
1024 if (!copy_from_kernel_nofault(&i, (unsigned char *)hp_sdc.data_io, 1))
1025 hp_sdc.dev = (void *)1;
1026 hp_sdc.dev_err = hp_sdc_init();
1027 #endif
1028 if (hp_sdc.dev == NULL) {
1029 printk(KERN_WARNING PREFIX "No SDC found.\n");
1030 return hp_sdc.dev_err;
1031 }
1032
1033 sema_init(&tq_init_sem, 0);
1034
1035 tq_init.actidx = 0;
1036 tq_init.idx = 1;
1037 tq_init.endidx = 5;
1038 tq_init.seq = tq_init_seq;
1039 tq_init.act.semaphore = &tq_init_sem;
1040
1041 tq_init_seq[0] =
1042 HP_SDC_ACT_POSTCMD | HP_SDC_ACT_DATAIN | HP_SDC_ACT_SEMAPHORE;
1043 tq_init_seq[1] = HP_SDC_CMD_READ_KCC;
1044 tq_init_seq[2] = 1;
1045 tq_init_seq[3] = 0;
1046 tq_init_seq[4] = 0;
1047
1048 hp_sdc_enqueue_transaction(&tq_init);
1049
1050 down(&tq_init_sem);
1051 up(&tq_init_sem);
1052
1053 if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) {
1054 printk(KERN_WARNING PREFIX "Error reading config byte.\n");
1055 hp_sdc_exit();
1056 return -ENODEV;
1057 }
1058 hp_sdc.r11 = tq_init_seq[4];
1059 if (hp_sdc.r11 & HP_SDC_CFG_NEW) {
1060 const char *str;
1061 printk(KERN_INFO PREFIX "New style SDC\n");
1062 tq_init_seq[1] = HP_SDC_CMD_READ_XTD;
1063 tq_init.actidx = 0;
1064 tq_init.idx = 1;
1065 down(&tq_init_sem);
1066 hp_sdc_enqueue_transaction(&tq_init);
1067 down(&tq_init_sem);
1068 up(&tq_init_sem);
1069 if ((tq_init_seq[0] & HP_SDC_ACT_DEAD) == HP_SDC_ACT_DEAD) {
1070 printk(KERN_WARNING PREFIX "Error reading extended config byte.\n");
1071 return -ENODEV;
1072 }
1073 hp_sdc.r7e = tq_init_seq[4];
1074 HP_SDC_XTD_REV_STRINGS(hp_sdc.r7e & HP_SDC_XTD_REV, str)
1075 printk(KERN_INFO PREFIX "Revision: %s\n", str);
1076 if (hp_sdc.r7e & HP_SDC_XTD_BEEPER)
1077 printk(KERN_INFO PREFIX "TI SN76494 beeper present\n");
1078 if (hp_sdc.r7e & HP_SDC_XTD_BBRTC)
1079 printk(KERN_INFO PREFIX "OKI MSM-58321 BBRTC present\n");
1080 printk(KERN_INFO PREFIX "Spunking the self test register to force PUP "
1081 "on next firmware reset.\n");
1082 tq_init_seq[0] = HP_SDC_ACT_PRECMD |
1083 HP_SDC_ACT_DATAOUT | HP_SDC_ACT_SEMAPHORE;
1084 tq_init_seq[1] = HP_SDC_CMD_SET_STR;
1085 tq_init_seq[2] = 1;
1086 tq_init_seq[3] = 0;
1087 tq_init.actidx = 0;
1088 tq_init.idx = 1;
1089 tq_init.endidx = 4;
1090 down(&tq_init_sem);
1091 hp_sdc_enqueue_transaction(&tq_init);
1092 down(&tq_init_sem);
1093 up(&tq_init_sem);
1094 } else
1095 printk(KERN_INFO PREFIX "Old style SDC (1820-%s).\n",
1096 (hp_sdc.r11 & HP_SDC_CFG_REV) ? "3300" : "2564/3087");
1097
1098 return 0;
1099 }
1100
1101 module_init(hp_sdc_register);
1102 module_exit(hp_sdc_exit);
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127