0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #define DEBUG
0012
0013 #include <linux/kernel.h> /* For printk. */
0014 #include <linux/string.h>
0015 #include <linux/module.h>
0016 #include <linux/moduleparam.h>
0017 #include <linux/ipmi_msgdefs.h> /* for completion codes */
0018 #include "ipmi_si_sm.h"
0019
0020 #define BT_DEBUG_OFF 0
0021 #define BT_DEBUG_ENABLE 1
0022 #define BT_DEBUG_MSG 2
0023 #define BT_DEBUG_STATES 4
0024
0025
0026
0027
0028
0029 static int bt_debug;
0030
0031 module_param(bt_debug, int, 0644);
0032 MODULE_PARM_DESC(bt_debug, "debug bitmask, 1=enable, 2=messages, 4=states");
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 #define BT_NORMAL_TIMEOUT 5
0043 #define BT_NORMAL_RETRY_LIMIT 2
0044 #define BT_RESET_DELAY 6
0045
0046
0047
0048
0049
0050
0051 enum bt_states {
0052 BT_STATE_IDLE = 0,
0053 BT_STATE_XACTION_START,
0054 BT_STATE_WRITE_BYTES,
0055 BT_STATE_WRITE_CONSUME,
0056 BT_STATE_READ_WAIT,
0057 BT_STATE_CLEAR_B2H,
0058 BT_STATE_READ_BYTES,
0059 BT_STATE_RESET1,
0060 BT_STATE_RESET2,
0061 BT_STATE_RESET3,
0062 BT_STATE_RESTART,
0063 BT_STATE_PRINTME,
0064 BT_STATE_LONG_BUSY
0065 };
0066
0067
0068
0069
0070
0071
0072 #define BT_STATE_CHANGE(X, Y) { bt->state = X; return Y; }
0073
0074 #define BT_SI_SM_RETURN(Y) { last_printed = BT_STATE_PRINTME; return Y; }
0075
0076 struct si_sm_data {
0077 enum bt_states state;
0078 unsigned char seq;
0079 struct si_sm_io *io;
0080 unsigned char write_data[IPMI_MAX_MSG_LENGTH + 2];
0081 int write_count;
0082 unsigned char read_data[IPMI_MAX_MSG_LENGTH + 2];
0083 int read_count;
0084 int truncated;
0085 long timeout;
0086 int error_retries;
0087 int nonzero_status;
0088 enum bt_states complete;
0089 long BT_CAP_req2rsp;
0090 int BT_CAP_retries;
0091 };
0092
0093 #define BT_CLR_WR_PTR 0x01
0094 #define BT_CLR_RD_PTR 0x02
0095 #define BT_H2B_ATN 0x04
0096 #define BT_B2H_ATN 0x08
0097 #define BT_SMS_ATN 0x10
0098 #define BT_OEM0 0x20
0099 #define BT_H_BUSY 0x40
0100 #define BT_B_BUSY 0x80
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110 #define BT_STATUS bt->io->inputb(bt->io, 0)
0111 #define BT_CONTROL(x) bt->io->outputb(bt->io, 0, x)
0112
0113 #define BMC2HOST bt->io->inputb(bt->io, 1)
0114 #define HOST2BMC(x) bt->io->outputb(bt->io, 1, x)
0115
0116 #define BT_INTMASK_R bt->io->inputb(bt->io, 2)
0117 #define BT_INTMASK_W(x) bt->io->outputb(bt->io, 2, x)
0118
0119
0120
0121
0122
0123
0124 static char *state2txt(unsigned char state)
0125 {
0126 switch (state) {
0127 case BT_STATE_IDLE: return("IDLE");
0128 case BT_STATE_XACTION_START: return("XACTION");
0129 case BT_STATE_WRITE_BYTES: return("WR_BYTES");
0130 case BT_STATE_WRITE_CONSUME: return("WR_CONSUME");
0131 case BT_STATE_READ_WAIT: return("RD_WAIT");
0132 case BT_STATE_CLEAR_B2H: return("CLEAR_B2H");
0133 case BT_STATE_READ_BYTES: return("RD_BYTES");
0134 case BT_STATE_RESET1: return("RESET1");
0135 case BT_STATE_RESET2: return("RESET2");
0136 case BT_STATE_RESET3: return("RESET3");
0137 case BT_STATE_RESTART: return("RESTART");
0138 case BT_STATE_LONG_BUSY: return("LONG_BUSY");
0139 }
0140 return("BAD STATE");
0141 }
0142 #define STATE2TXT state2txt(bt->state)
0143
0144 static char *status2txt(unsigned char status)
0145 {
0146
0147
0148
0149
0150
0151 static char buf[40];
0152
0153 strcpy(buf, "[ ");
0154 if (status & BT_B_BUSY)
0155 strcat(buf, "B_BUSY ");
0156 if (status & BT_H_BUSY)
0157 strcat(buf, "H_BUSY ");
0158 if (status & BT_OEM0)
0159 strcat(buf, "OEM0 ");
0160 if (status & BT_SMS_ATN)
0161 strcat(buf, "SMS ");
0162 if (status & BT_B2H_ATN)
0163 strcat(buf, "B2H ");
0164 if (status & BT_H2B_ATN)
0165 strcat(buf, "H2B ");
0166 strcat(buf, "]");
0167 return buf;
0168 }
0169 #define STATUS2TXT status2txt(status)
0170
0171
0172
0173 static unsigned int bt_init_data(struct si_sm_data *bt, struct si_sm_io *io)
0174 {
0175 memset(bt, 0, sizeof(struct si_sm_data));
0176 if (bt->io != io) {
0177
0178 bt->io = io;
0179 bt->seq = 0;
0180 }
0181 bt->state = BT_STATE_IDLE;
0182 bt->complete = BT_STATE_IDLE;
0183 bt->BT_CAP_req2rsp = BT_NORMAL_TIMEOUT * USEC_PER_SEC;
0184 bt->BT_CAP_retries = BT_NORMAL_RETRY_LIMIT;
0185 return 3;
0186 }
0187
0188
0189
0190 static void force_result(struct si_sm_data *bt, unsigned char completion_code)
0191 {
0192 bt->read_data[0] = 4;
0193 bt->read_data[1] = bt->write_data[1] | 4;
0194 bt->read_data[2] = bt->write_data[2];
0195 bt->read_data[3] = bt->write_data[3];
0196 bt->read_data[4] = completion_code;
0197 bt->read_count = 5;
0198 }
0199
0200
0201
0202 static int bt_start_transaction(struct si_sm_data *bt,
0203 unsigned char *data,
0204 unsigned int size)
0205 {
0206 unsigned int i;
0207
0208 if (size < 2)
0209 return IPMI_REQ_LEN_INVALID_ERR;
0210 if (size > IPMI_MAX_MSG_LENGTH)
0211 return IPMI_REQ_LEN_EXCEEDED_ERR;
0212
0213 if (bt->state == BT_STATE_LONG_BUSY)
0214 return IPMI_NODE_BUSY_ERR;
0215
0216 if (bt->state != BT_STATE_IDLE) {
0217 dev_warn(bt->io->dev, "BT in invalid state %d\n", bt->state);
0218 return IPMI_NOT_IN_MY_STATE_ERR;
0219 }
0220
0221 if (bt_debug & BT_DEBUG_MSG) {
0222 dev_dbg(bt->io->dev, "+++++++++++++++++ New command\n");
0223 dev_dbg(bt->io->dev, "NetFn/LUN CMD [%d data]:", size - 2);
0224 for (i = 0; i < size; i ++)
0225 pr_cont(" %02x", data[i]);
0226 pr_cont("\n");
0227 }
0228 bt->write_data[0] = size + 1;
0229 bt->write_data[1] = *data;
0230 bt->write_data[2] = bt->seq++;
0231 memcpy(bt->write_data + 3, data + 1, size - 1);
0232 bt->write_count = size + 2;
0233 bt->error_retries = 0;
0234 bt->nonzero_status = 0;
0235 bt->truncated = 0;
0236 bt->state = BT_STATE_XACTION_START;
0237 bt->timeout = bt->BT_CAP_req2rsp;
0238 force_result(bt, IPMI_ERR_UNSPECIFIED);
0239 return 0;
0240 }
0241
0242
0243
0244
0245
0246
0247 static int bt_get_result(struct si_sm_data *bt,
0248 unsigned char *data,
0249 unsigned int length)
0250 {
0251 int i, msg_len;
0252
0253 msg_len = bt->read_count - 2;
0254 if (msg_len < 3 || msg_len > IPMI_MAX_MSG_LENGTH) {
0255 force_result(bt, IPMI_ERR_UNSPECIFIED);
0256 msg_len = 3;
0257 }
0258 data[0] = bt->read_data[1];
0259 data[1] = bt->read_data[3];
0260 if (length < msg_len || bt->truncated) {
0261 data[2] = IPMI_ERR_MSG_TRUNCATED;
0262 msg_len = 3;
0263 } else
0264 memcpy(data + 2, bt->read_data + 4, msg_len - 2);
0265
0266 if (bt_debug & BT_DEBUG_MSG) {
0267 dev_dbg(bt->io->dev, "result %d bytes:", msg_len);
0268 for (i = 0; i < msg_len; i++)
0269 pr_cont(" %02x", data[i]);
0270 pr_cont("\n");
0271 }
0272 return msg_len;
0273 }
0274
0275
0276 #define BT_BMC_HWRST 0x80
0277
0278 static void reset_flags(struct si_sm_data *bt)
0279 {
0280 if (bt_debug)
0281 dev_dbg(bt->io->dev, "flag reset %s\n", status2txt(BT_STATUS));
0282 if (BT_STATUS & BT_H_BUSY)
0283 BT_CONTROL(BT_H_BUSY);
0284 BT_CONTROL(BT_CLR_WR_PTR);
0285 BT_CONTROL(BT_SMS_ATN);
0286 BT_INTMASK_W(BT_BMC_HWRST);
0287 }
0288
0289
0290
0291
0292
0293
0294 static void drain_BMC2HOST(struct si_sm_data *bt)
0295 {
0296 int i, size;
0297
0298 if (!(BT_STATUS & BT_B2H_ATN))
0299 return;
0300
0301 BT_CONTROL(BT_H_BUSY);
0302 BT_CONTROL(BT_B2H_ATN);
0303 BT_STATUS;
0304 BT_CONTROL(BT_B2H_ATN);
0305 BT_CONTROL(BT_CLR_RD_PTR);
0306 if (bt_debug)
0307 dev_dbg(bt->io->dev, "stale response %s; ",
0308 status2txt(BT_STATUS));
0309 size = BMC2HOST;
0310 for (i = 0; i < size ; i++)
0311 BMC2HOST;
0312 BT_CONTROL(BT_H_BUSY);
0313 if (bt_debug)
0314 pr_cont("drained %d bytes\n", size + 1);
0315 }
0316
0317 static inline void write_all_bytes(struct si_sm_data *bt)
0318 {
0319 int i;
0320
0321 if (bt_debug & BT_DEBUG_MSG) {
0322 dev_dbg(bt->io->dev, "write %d bytes seq=0x%02X",
0323 bt->write_count, bt->seq);
0324 for (i = 0; i < bt->write_count; i++)
0325 pr_cont(" %02x", bt->write_data[i]);
0326 pr_cont("\n");
0327 }
0328 for (i = 0; i < bt->write_count; i++)
0329 HOST2BMC(bt->write_data[i]);
0330 }
0331
0332 static inline int read_all_bytes(struct si_sm_data *bt)
0333 {
0334 unsigned int i;
0335
0336
0337
0338
0339
0340
0341 bt->read_data[0] = BMC2HOST;
0342 bt->read_count = bt->read_data[0];
0343
0344 if (bt->read_count < 4 || bt->read_count >= IPMI_MAX_MSG_LENGTH) {
0345 if (bt_debug & BT_DEBUG_MSG)
0346 dev_dbg(bt->io->dev,
0347 "bad raw rsp len=%d\n", bt->read_count);
0348 bt->truncated = 1;
0349 return 1;
0350 }
0351 for (i = 1; i <= bt->read_count; i++)
0352 bt->read_data[i] = BMC2HOST;
0353 bt->read_count++;
0354
0355 if (bt_debug & BT_DEBUG_MSG) {
0356 int max = bt->read_count;
0357
0358 dev_dbg(bt->io->dev,
0359 "got %d bytes seq=0x%02X", max, bt->read_data[2]);
0360 if (max > 16)
0361 max = 16;
0362 for (i = 0; i < max; i++)
0363 pr_cont(" %02x", bt->read_data[i]);
0364 pr_cont("%s\n", bt->read_count == max ? "" : " ...");
0365 }
0366
0367
0368 if ((bt->read_data[3] == bt->write_data[3]) &&
0369 (bt->read_data[2] == bt->write_data[2]) &&
0370 ((bt->read_data[1] & 0xF8) == (bt->write_data[1] & 0xF8)))
0371 return 1;
0372
0373 if (bt_debug & BT_DEBUG_MSG)
0374 dev_dbg(bt->io->dev,
0375 "IPMI BT: bad packet: want 0x(%02X, %02X, %02X) got (%02X, %02X, %02X)\n",
0376 bt->write_data[1] | 0x04, bt->write_data[2],
0377 bt->write_data[3],
0378 bt->read_data[1], bt->read_data[2], bt->read_data[3]);
0379 return 0;
0380 }
0381
0382
0383
0384 static enum si_sm_result error_recovery(struct si_sm_data *bt,
0385 unsigned char status,
0386 unsigned char cCode)
0387 {
0388 char *reason;
0389
0390 bt->timeout = bt->BT_CAP_req2rsp;
0391
0392 switch (cCode) {
0393 case IPMI_TIMEOUT_ERR:
0394 reason = "timeout";
0395 break;
0396 default:
0397 reason = "internal error";
0398 break;
0399 }
0400
0401 dev_warn(bt->io->dev, "IPMI BT: %s in %s %s ",
0402 reason, STATE2TXT, STATUS2TXT);
0403
0404
0405
0406
0407
0408 (bt->error_retries)++;
0409 if (bt->error_retries < bt->BT_CAP_retries) {
0410 pr_cont("%d retries left\n",
0411 bt->BT_CAP_retries - bt->error_retries);
0412 bt->state = BT_STATE_RESTART;
0413 return SI_SM_CALL_WITHOUT_DELAY;
0414 }
0415
0416 dev_warn(bt->io->dev, "failed %d retries, sending error response\n",
0417 bt->BT_CAP_retries);
0418 if (!bt->nonzero_status)
0419 dev_err(bt->io->dev, "stuck, try power cycle\n");
0420
0421
0422 else if (bt->seq <= (unsigned char)(bt->BT_CAP_retries & 0xFF)) {
0423 dev_warn(bt->io->dev, "BT reset (takes 5 secs)\n");
0424 bt->state = BT_STATE_RESET1;
0425 return SI_SM_CALL_WITHOUT_DELAY;
0426 }
0427
0428
0429
0430
0431
0432
0433 bt->state = BT_STATE_IDLE;
0434 switch (cCode) {
0435 case IPMI_TIMEOUT_ERR:
0436 if (status & BT_B_BUSY) {
0437 cCode = IPMI_NODE_BUSY_ERR;
0438 bt->state = BT_STATE_LONG_BUSY;
0439 }
0440 break;
0441 default:
0442 break;
0443 }
0444 force_result(bt, cCode);
0445 return SI_SM_TRANSACTION_COMPLETE;
0446 }
0447
0448
0449
0450 static enum si_sm_result bt_event(struct si_sm_data *bt, long time)
0451 {
0452 unsigned char status;
0453 static enum bt_states last_printed = BT_STATE_PRINTME;
0454 int i;
0455
0456 status = BT_STATUS;
0457 bt->nonzero_status |= status;
0458 if ((bt_debug & BT_DEBUG_STATES) && (bt->state != last_printed)) {
0459 dev_dbg(bt->io->dev, "BT: %s %s TO=%ld - %ld\n",
0460 STATE2TXT,
0461 STATUS2TXT,
0462 bt->timeout,
0463 time);
0464 last_printed = bt->state;
0465 }
0466
0467
0468
0469
0470
0471
0472
0473
0474 if ((bt->state < BT_STATE_WRITE_BYTES) && (status & BT_B2H_ATN)) {
0475 drain_BMC2HOST(bt);
0476 BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
0477 }
0478
0479 if ((bt->state != BT_STATE_IDLE) &&
0480 (bt->state < BT_STATE_PRINTME)) {
0481
0482 bt->timeout -= time;
0483 if ((bt->timeout < 0) && (bt->state < BT_STATE_RESET1))
0484 return error_recovery(bt,
0485 status,
0486 IPMI_TIMEOUT_ERR);
0487 }
0488
0489 switch (bt->state) {
0490
0491
0492
0493
0494
0495
0496 case BT_STATE_IDLE:
0497 if (status & BT_SMS_ATN) {
0498 BT_CONTROL(BT_SMS_ATN);
0499 return SI_SM_ATTN;
0500 }
0501
0502 if (status & BT_H_BUSY)
0503 BT_CONTROL(BT_H_BUSY);
0504
0505 BT_SI_SM_RETURN(SI_SM_IDLE);
0506
0507 case BT_STATE_XACTION_START:
0508 if (status & (BT_B_BUSY | BT_H2B_ATN))
0509 BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
0510 if (BT_STATUS & BT_H_BUSY)
0511 BT_CONTROL(BT_H_BUSY);
0512 BT_STATE_CHANGE(BT_STATE_WRITE_BYTES,
0513 SI_SM_CALL_WITHOUT_DELAY);
0514
0515 case BT_STATE_WRITE_BYTES:
0516 if (status & BT_H_BUSY)
0517 BT_CONTROL(BT_H_BUSY);
0518 BT_CONTROL(BT_CLR_WR_PTR);
0519 write_all_bytes(bt);
0520 BT_CONTROL(BT_H2B_ATN);
0521 BT_STATE_CHANGE(BT_STATE_WRITE_CONSUME,
0522 SI_SM_CALL_WITHOUT_DELAY);
0523
0524 case BT_STATE_WRITE_CONSUME:
0525 if (status & (BT_B_BUSY | BT_H2B_ATN))
0526 BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
0527 BT_STATE_CHANGE(BT_STATE_READ_WAIT,
0528 SI_SM_CALL_WITHOUT_DELAY);
0529
0530
0531
0532 case BT_STATE_READ_WAIT:
0533 if (!(status & BT_B2H_ATN))
0534 BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
0535 BT_CONTROL(BT_H_BUSY);
0536
0537
0538
0539
0540
0541
0542
0543 BT_CONTROL(BT_B2H_ATN);
0544 BT_STATE_CHANGE(BT_STATE_CLEAR_B2H,
0545 SI_SM_CALL_WITHOUT_DELAY);
0546
0547 case BT_STATE_CLEAR_B2H:
0548 if (status & BT_B2H_ATN) {
0549
0550 BT_CONTROL(BT_B2H_ATN);
0551 BT_SI_SM_RETURN(SI_SM_CALL_WITH_DELAY);
0552 }
0553 BT_STATE_CHANGE(BT_STATE_READ_BYTES,
0554 SI_SM_CALL_WITHOUT_DELAY);
0555
0556 case BT_STATE_READ_BYTES:
0557 if (!(status & BT_H_BUSY))
0558
0559 BT_CONTROL(BT_H_BUSY);
0560 BT_CONTROL(BT_CLR_RD_PTR);
0561 i = read_all_bytes(bt);
0562 BT_CONTROL(BT_H_BUSY);
0563 if (!i)
0564 BT_STATE_CHANGE(BT_STATE_READ_WAIT,
0565 SI_SM_CALL_WITHOUT_DELAY);
0566 bt->state = bt->complete;
0567 return bt->state == BT_STATE_IDLE ?
0568 SI_SM_TRANSACTION_COMPLETE :
0569 SI_SM_CALL_WITHOUT_DELAY;
0570
0571 case BT_STATE_LONG_BUSY:
0572 if (!(status & BT_B_BUSY)) {
0573 reset_flags(bt);
0574 bt_init_data(bt, bt->io);
0575 }
0576 return SI_SM_CALL_WITH_DELAY;
0577
0578 case BT_STATE_RESET1:
0579 reset_flags(bt);
0580 drain_BMC2HOST(bt);
0581 BT_STATE_CHANGE(BT_STATE_RESET2,
0582 SI_SM_CALL_WITH_DELAY);
0583
0584 case BT_STATE_RESET2:
0585 BT_CONTROL(BT_CLR_WR_PTR);
0586 HOST2BMC(3);
0587 HOST2BMC(0x18);
0588 HOST2BMC(42);
0589 HOST2BMC(3);
0590 BT_CONTROL(BT_H2B_ATN);
0591 bt->timeout = BT_RESET_DELAY * USEC_PER_SEC;
0592 BT_STATE_CHANGE(BT_STATE_RESET3,
0593 SI_SM_CALL_WITH_DELAY);
0594
0595 case BT_STATE_RESET3:
0596 if (bt->timeout > 0)
0597 return SI_SM_CALL_WITH_DELAY;
0598 drain_BMC2HOST(bt);
0599 BT_STATE_CHANGE(BT_STATE_RESTART,
0600 SI_SM_CALL_WITH_DELAY);
0601
0602 case BT_STATE_RESTART:
0603 bt->read_count = 0;
0604 bt->nonzero_status = 0;
0605 bt->timeout = bt->BT_CAP_req2rsp;
0606 BT_STATE_CHANGE(BT_STATE_XACTION_START,
0607 SI_SM_CALL_WITH_DELAY);
0608
0609 default:
0610 return error_recovery(bt,
0611 status,
0612 IPMI_ERR_UNSPECIFIED);
0613 }
0614 return SI_SM_CALL_WITH_DELAY;
0615 }
0616
0617 static int bt_detect(struct si_sm_data *bt)
0618 {
0619 unsigned char GetBT_CAP[] = { 0x18, 0x36 };
0620 unsigned char BT_CAP[8];
0621 enum si_sm_result smi_result;
0622 int rv;
0623
0624
0625
0626
0627
0628
0629
0630
0631 if ((BT_STATUS == 0xFF) && (BT_INTMASK_R == 0xFF))
0632 return 1;
0633 reset_flags(bt);
0634
0635
0636
0637
0638 rv = bt_start_transaction(bt, GetBT_CAP, sizeof(GetBT_CAP));
0639 if (rv) {
0640 dev_warn(bt->io->dev,
0641 "Can't start capabilities transaction: %d\n", rv);
0642 goto out_no_bt_cap;
0643 }
0644
0645 smi_result = SI_SM_CALL_WITHOUT_DELAY;
0646 for (;;) {
0647 if (smi_result == SI_SM_CALL_WITH_DELAY ||
0648 smi_result == SI_SM_CALL_WITH_TICK_DELAY) {
0649 schedule_timeout_uninterruptible(1);
0650 smi_result = bt_event(bt, jiffies_to_usecs(1));
0651 } else if (smi_result == SI_SM_CALL_WITHOUT_DELAY) {
0652 smi_result = bt_event(bt, 0);
0653 } else
0654 break;
0655 }
0656
0657 rv = bt_get_result(bt, BT_CAP, sizeof(BT_CAP));
0658 bt_init_data(bt, bt->io);
0659 if (rv < 8) {
0660 dev_warn(bt->io->dev, "bt cap response too short: %d\n", rv);
0661 goto out_no_bt_cap;
0662 }
0663
0664 if (BT_CAP[2]) {
0665 dev_warn(bt->io->dev, "Error fetching bt cap: %x\n", BT_CAP[2]);
0666 out_no_bt_cap:
0667 dev_warn(bt->io->dev, "using default values\n");
0668 } else {
0669 bt->BT_CAP_req2rsp = BT_CAP[6] * USEC_PER_SEC;
0670 bt->BT_CAP_retries = BT_CAP[7];
0671 }
0672
0673 dev_info(bt->io->dev, "req2rsp=%ld secs retries=%d\n",
0674 bt->BT_CAP_req2rsp / USEC_PER_SEC, bt->BT_CAP_retries);
0675
0676 return 0;
0677 }
0678
0679 static void bt_cleanup(struct si_sm_data *bt)
0680 {
0681 }
0682
0683 static int bt_size(void)
0684 {
0685 return sizeof(struct si_sm_data);
0686 }
0687
0688 const struct si_sm_handlers bt_smi_handlers = {
0689 .init_data = bt_init_data,
0690 .start_transaction = bt_start_transaction,
0691 .get_result = bt_get_result,
0692 .event = bt_event,
0693 .detect = bt_detect,
0694 .cleanup = bt_cleanup,
0695 .size = bt_size,
0696 };