1 /*- 2 * Copyright (c) 2016-2017 Ilya Bakulin 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD$ 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/ioctl.h> 33 #include <sys/stdint.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <sys/endian.h> 37 #include <sys/sbuf.h> 38 #include <sys/mman.h> 39 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 #include <inttypes.h> 45 #include <limits.h> 46 #include <fcntl.h> 47 #include <ctype.h> 48 #include <err.h> 49 #include <libutil.h> 50 #include <unistd.h> 51 52 #include <cam/cam.h> 53 #include <cam/cam_debug.h> 54 #include <cam/cam_ccb.h> 55 #include <cam/mmc/mmc_all.h> 56 #include <camlib.h> 57 58 struct cis_info { 59 uint16_t man_id; 60 uint16_t prod_id; 61 uint16_t max_block_size; 62 }; 63 64 static int sdio_rw_direct(struct cam_device *dev, 65 uint8_t func_number, 66 uint32_t addr, 67 uint8_t is_write, 68 uint8_t *data, 69 uint8_t *resp); 70 static uint8_t sdio_read_1(struct cam_device *dev, uint8_t func_number, uint32_t addr); 71 static void sdio_write_1(struct cam_device *dev, uint8_t func_number, uint32_t addr, uint8_t val); 72 static int sdio_is_func_ready(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab); 73 static int sdio_is_func_enabled(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab); 74 static int sdio_func_enable(struct cam_device *dev, uint8_t func_number, int enable); 75 static int sdio_is_func_intr_enabled(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab); 76 static int sdio_func_intr_enable(struct cam_device *dev, uint8_t func_number, int enable); 77 static void sdio_card_reset(struct cam_device *dev); 78 static uint32_t sdio_get_common_cis_addr(struct cam_device *dev); 79 static void probe_bcrm(struct cam_device *dev); 80 81 /* Use CMD52 to read or write a single byte */ 82 int 83 sdio_rw_direct(struct cam_device *dev, 84 uint8_t func_number, 85 uint32_t addr, 86 uint8_t is_write, 87 uint8_t *data, uint8_t *resp) { 88 union ccb *ccb; 89 uint32_t flags; 90 uint32_t arg; 91 int retval = 0; 92 93 ccb = cam_getccb(dev); 94 if (ccb == NULL) { 95 warnx("%s: error allocating CCB", __func__); 96 return (1); 97 } 98 bzero(&(&ccb->ccb_h)[1], 99 sizeof(union ccb) - sizeof(struct ccb_hdr)); 100 101 flags = MMC_RSP_R5 | MMC_CMD_AC; 102 arg = SD_IO_RW_FUNC(func_number) | SD_IO_RW_ADR(addr); 103 if (is_write) 104 arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*data); 105 106 cam_fill_mmcio(&ccb->mmcio, 107 /*retries*/ 0, 108 /*cbfcnp*/ NULL, 109 /*flags*/ CAM_DIR_NONE, 110 /*mmc_opcode*/ SD_IO_RW_DIRECT, 111 /*mmc_arg*/ arg, 112 /*mmc_flags*/ flags, 113 /*mmc_data*/ 0, 114 /*timeout*/ 5000); 115 116 if (((retval = cam_send_ccb(dev, ccb)) < 0) 117 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 118 const char warnstr[] = "error sending command"; 119 120 if (retval < 0) 121 warn(warnstr); 122 else 123 warnx(warnstr); 124 return (-1); 125 } 126 127 *resp = ccb->mmcio.cmd.resp[0] & 0xFF; 128 cam_freeccb(ccb); 129 return (retval); 130 } 131 132 #if 0 133 /* 134 * CMD53 -- IO_RW_EXTENDED 135 * Use to read or write memory blocks 136 * 137 * is_increment=1: FIFO mode 138 * blk_count > 0: block mode 139 */ 140 int 141 sdio_rw_extended(struct cam_device *dev, 142 uint8_t func_number, 143 uint32_t addr, 144 uint8_t is_write, 145 uint8_t *data, size_t datalen, 146 uint8_t is_increment, 147 uint16_t blk_count) { 148 union ccb *ccb; 149 uint32_t flags; 150 uint32_t arg; 151 int retval = 0; 152 153 if (blk_count != 0) { 154 warnx("%s: block mode is not supported yet", __func__); 155 return (1); 156 } 157 158 ccb = cam_getccb(dev); 159 if (ccb == NULL) { 160 warnx("%s: error allocating CCB", __func__); 161 return (1); 162 } 163 bzero(&(&ccb->ccb_h)[1], 164 sizeof(union ccb) - sizeof(struct ccb_hdr)); 165 166 flags = MMC_RSP_R5 | MMC_CMD_AC; 167 arg = SD_IO_RW_FUNC(func_number) | SD_IO_RW_ADR(addr); 168 if (is_write) 169 arg |= SD_IO_RW_WR; 170 171 cam_fill_mmcio(&ccb->mmcio, 172 /*retries*/ 0, 173 /*cbfcnp*/ NULL, 174 /*flags*/ CAM_DIR_NONE, 175 /*mmc_opcode*/ SD_IO_RW_DIRECT, 176 /*mmc_arg*/ arg, 177 /*mmc_flags*/ flags, 178 /*mmc_data*/ 0, 179 /*timeout*/ 5000); 180 181 if (((retval = cam_send_ccb(dev, ccb)) < 0) 182 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 183 const char warnstr[] = "error sending command"; 184 185 if (retval < 0) 186 warn(warnstr); 187 else 188 warnx(warnstr); 189 return (-1); 190 } 191 192 *resp = ccb->mmcio.cmd.resp[0] & 0xFF; 193 cam_freeccb(ccb); 194 return (retval); 195 } 196 #endif 197 198 static int 199 sdio_read_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t func_number, uint8_t *is_enab) { 200 uint8_t resp; 201 int ret; 202 203 ret = sdio_rw_direct(dev, 0, addr, 0, NULL, &resp); 204 if (ret < 0) 205 return ret; 206 207 *is_enab = (resp & (1 << func_number)) > 0 ? 1 : 0; 208 209 return (0); 210 } 211 212 static int 213 sdio_set_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t func_number, int enable) { 214 uint8_t resp; 215 int ret; 216 uint8_t is_enabled; 217 218 ret = sdio_rw_direct(dev, 0, addr, 0, NULL, &resp); 219 if (ret != 0) 220 return ret; 221 222 is_enabled = resp & (1 << func_number); 223 if ((is_enabled !=0 && enable == 1) || (is_enabled == 0 && enable == 0)) 224 return 0; 225 226 if (enable) 227 resp |= 1 << func_number; 228 else 229 resp &= ~ (1 << func_number); 230 231 ret = sdio_rw_direct(dev, 0, addr, 1, &resp, &resp); 232 233 return ret; 234 } 235 236 static uint8_t 237 sdio_read_1(struct cam_device *dev, uint8_t func_number, uint32_t addr) { 238 uint8_t val; 239 sdio_rw_direct(dev, func_number, addr, 0, NULL, &val); 240 return val; 241 } 242 243 __unused static void 244 sdio_write_1(struct cam_device *dev, uint8_t func_number, uint32_t addr, uint8_t val) { 245 uint8_t _val; 246 sdio_rw_direct(dev, func_number, addr, 0, &val, &_val); 247 } 248 249 static int 250 sdio_is_func_ready(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab) { 251 return sdio_read_bool_for_func(dev, SD_IO_CCCR_FN_READY, func_number, is_enab); 252 } 253 254 static int 255 sdio_is_func_enabled(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab) { 256 return sdio_read_bool_for_func(dev, SD_IO_CCCR_FN_ENABLE, func_number, is_enab); 257 } 258 259 static int 260 sdio_func_enable(struct cam_device *dev, uint8_t func_number, int enable) { 261 return sdio_set_bool_for_func(dev, SD_IO_CCCR_FN_ENABLE, func_number, enable); 262 } 263 264 static int 265 sdio_is_func_intr_enabled(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab) { 266 return sdio_read_bool_for_func(dev, SD_IO_CCCR_INT_ENABLE, func_number, is_enab); 267 } 268 269 static int 270 sdio_func_intr_enable(struct cam_device *dev, uint8_t func_number, int enable) { 271 return sdio_set_bool_for_func(dev, SD_IO_CCCR_INT_ENABLE, func_number, enable); 272 } 273 274 static int 275 sdio_card_set_bus_width(struct cam_device *dev, enum mmc_bus_width bw) { 276 int ret; 277 uint8_t ctl_val; 278 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_BUS_WIDTH, 0, NULL, &ctl_val); 279 if (ret < 0) { 280 warn("Error getting CCCR_BUS_WIDTH value"); 281 return ret; 282 } 283 ctl_val &= ~0x3; 284 switch (bw) { 285 case bus_width_1: 286 /* Already set to 1-bit */ 287 break; 288 case bus_width_4: 289 ctl_val |= CCCR_BUS_WIDTH_4; 290 break; 291 case bus_width_8: 292 warn("Cannot do 8-bit on SDIO yet"); 293 return -1; 294 break; 295 } 296 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_BUS_WIDTH, 1, &ctl_val, &ctl_val); 297 if (ret < 0) { 298 warn("Error setting CCCR_BUS_WIDTH value"); 299 return ret; 300 } 301 return ret; 302 } 303 304 static int 305 sdio_func_read_cis(struct cam_device *dev, uint8_t func_number, 306 uint32_t cis_addr, struct cis_info *info) { 307 uint8_t tuple_id, tuple_len, tuple_count; 308 uint32_t addr; 309 310 char *cis1_info[4]; 311 int start, i, ch, count; 312 char cis1_info_buf[256]; 313 314 tuple_count = 0; /* Use to prevent infinite loop in case of parse errors */ 315 memset(cis1_info_buf, 0, 256); 316 do { 317 addr = cis_addr; 318 tuple_id = sdio_read_1(dev, 0, addr++); 319 if (tuple_id == SD_IO_CISTPL_END) 320 break; 321 if (tuple_id == 0) { 322 cis_addr++; 323 continue; 324 } 325 tuple_len = sdio_read_1(dev, 0, addr++); 326 if (tuple_len == 0 && tuple_id != 0x00) { 327 warn("Parse error: 0-length tuple %02X\n", tuple_id); 328 return -1; 329 } 330 331 switch (tuple_id) { 332 case SD_IO_CISTPL_VERS_1: 333 addr += 2; 334 for (count = 0, start = 0, i = 0; 335 (count < 4) && ((i + 4) < 256); i++) { 336 ch = sdio_read_1(dev, 0, addr + i); 337 printf("count=%d, start=%d, i=%d, Got %c (0x%02x)\n", count, start, i, ch, ch); 338 if (ch == 0xff) 339 break; 340 cis1_info_buf[i] = ch; 341 if (ch == 0) { 342 cis1_info[count] = 343 cis1_info_buf + start; 344 start = i + 1; 345 count++; 346 } 347 } 348 printf("Card info:"); 349 for (i=0; i<4; i++) 350 if (cis1_info[i]) 351 printf(" %s", cis1_info[i]); 352 printf("\n"); 353 break; 354 case SD_IO_CISTPL_MANFID: 355 info->man_id = sdio_read_1(dev, 0, addr++); 356 info->man_id |= sdio_read_1(dev, 0, addr++) << 8; 357 358 info->prod_id = sdio_read_1(dev, 0, addr++); 359 info->prod_id |= sdio_read_1(dev, 0, addr++) << 8; 360 break; 361 case SD_IO_CISTPL_FUNCID: 362 /* not sure if we need to parse it? */ 363 break; 364 case SD_IO_CISTPL_FUNCE: 365 if (tuple_len < 4) { 366 printf("FUNCE is too short: %d\n", tuple_len); 367 break; 368 } 369 if (func_number == 0) { 370 /* skip extended_data */ 371 addr++; 372 info->max_block_size = sdio_read_1(dev, 0, addr++); 373 info->max_block_size |= sdio_read_1(dev, 0, addr++) << 8; 374 } else { 375 info->max_block_size = sdio_read_1(dev, 0, addr + 0xC); 376 info->max_block_size |= sdio_read_1(dev, 0, addr + 0xD) << 8; 377 } 378 break; 379 default: 380 printf("Skipping tuple ID %02X len %02X\n", tuple_id, tuple_len); 381 } 382 cis_addr += tuple_len + 2; 383 tuple_count++; 384 } while (tuple_count < 20); 385 386 return 0; 387 } 388 389 static uint32_t 390 sdio_get_common_cis_addr(struct cam_device *dev) { 391 uint32_t addr; 392 393 addr = sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR); 394 addr |= sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR + 1) << 8; 395 addr |= sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR + 2) << 16; 396 397 if (addr < SD_IO_CIS_START || addr > SD_IO_CIS_START + SD_IO_CIS_SIZE) { 398 warn("Bad CIS address: %04X\n", addr); 399 addr = 0; 400 } 401 402 return addr; 403 } 404 405 static void sdio_card_reset(struct cam_device *dev) { 406 int ret; 407 uint8_t ctl_val; 408 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_CTL, 0, NULL, &ctl_val); 409 if (ret < 0) 410 errx(1, "Error getting CCCR_CTL value"); 411 ctl_val |= CCCR_CTL_RES; 412 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_CTL, 1, &ctl_val, &ctl_val); 413 if (ret < 0) 414 errx(1, "Error setting CCCR_CTL value"); 415 } 416 417 /* 418 * How Linux driver works 419 * 420 * The probing begins by calling brcmf_ops_sdio_probe() which is defined as probe function in struct sdio_driver. http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c#L1126 421 * 422 * The driver does black magic by copying func struct for F2 and setting func number to zero there, to create an F0 func structure :) 423 * Driver state changes to BRCMF_SDIOD_DOWN. 424 * ops_sdio_probe() then calls brcmf_sdio_probe() -- at this point it has filled in sdiodev struct with the pointers to all three functions (F0, F1, F2). 425 * 426 * brcmf_sdiod_probe() sets block sizes for F1 and F2. It sets F1 block size to 64 and F2 to 512, not consulting the values stored in SDIO CCCR / FBR registers! 427 * Then it increases timeout for F2 (what is this?!) 428 * Then it enables F1 429 * Then it attaches "freezer" (without PM this is NOP) 430 * Finally it calls brcmf_sdio_probe() http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c#L4082 431 * 432 * Here high-level workqueues and sg tables are allocated. 433 * It then calls brcmf_sdio_probe_attach() 434 * 435 * Here at the beginning there is a pr_debug() call with brcmf_sdiod_regrl() inside to addr #define SI_ENUM_BASE 0x18000000. 436 * Return value is 0x16044330. 437 * Then turns off PLL: byte-write BRCMF_INIT_CLKCTL1 (0x28) -> SBSDIO_FUNC1_CHIPCLKCSR (0x1000E) 438 * Then it reads value back, should be 0xe8. 439 * Then calls brcmf_chip_attach() 440 * 441 * http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c#L1054 442 * This func enumerates and resets all the cores on the dongle. 443 * - brcmf_sdio_buscoreprep(): force clock to ALPAvail req only: 444 * SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ -> SBSDIO_FUNC1_CHIPCLKCSR 445 * Wait up to 15ms to !SBSDIO_ALPAV(clkval) of the value from CLKCSR. 446 * Force ALP: 447 * SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP (0x21)-> SBSDIO_FUNC1_CHIPCLKCSR 448 * Disaable SDIO pullups: 449 * byte 0 -> SBSDIO_FUNC1_SDIOPULLUP (0x0001000f) 450 * 451 * Calls brcmf_chip_recognition() 452 * http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c#L908 453 * Read 0x18000000. Get 0x16044330: chip 4330 rev 4 454 * AXI chip, call brcmf_chip_dmp_erom_scan() to get info about all cores. 455 * Then brcmf_chip_cores_check() to check that CPU and RAM are found, 456 * 457 * Setting cores to passive: not clear which of CR4/CA7/CM3 our chip has. 458 * Quite a few r/w calls to different parts of the chip to reset cores.... 459 * Finally get_raminfo() called to fill in RAM info: 460 * brcmf_chip_get_raminfo: RAM: base=0x0 size=294912 (0x48000) sr=0 (0x0) 461 * http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c#L700 462 * 463 * Then brcmf_chip_setup() is called, this prints and fills in chipcommon rev and PMU caps: 464 * brcmf_chip_setup: ccrev=39, pmurev=12, pmucaps=0x19583c0c 465 * http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c#L1015 466 * Bus-specific setup code is NOP for SDIO. 467 * 468 * brcmf_sdio_kso_init() is called. 469 * Here it first reads 0x1 from SBSDIO_FUNC1_SLEEPCSR 0x18000650 and then writes it back... WTF? 470 * 471 * brcmf_sdio_drivestrengthinit() is called 472 * http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c#L3630 473 * 474 * Set card control so an SDIO card reset does a WLAN backplane reset 475 * set PMUControl so a backplane reset does PMU state reload 476 * === end of brcmf_sdio_probe_attach === 477 478 **** Finished reading at http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c#L4152, line 2025 in the dump 479 480 * === How register reading works === 481 * http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c#L357 482 * The address to read from is written to three byte-sized registers of F1: 483 * - SBSDIO_FUNC1_SBADDRLOW 0x1000A 484 * - SBSDIO_FUNC1_SBADDRMID 0x1000B 485 * - SBSDIO_FUNC1_SBADDRHIGH 0x1000C 486 * If this is 32-bit read , a flag is set. The address is ANDed with SBSDIO_SB_OFT_ADDR_MASK which is 0x07FFF. 487 * Then brcmf_sdiod_regrw_helper() is called to read the reply. 488 * http://lxr.free-electrons.com/source/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c#L306 489 * Based on the address it figures out where to read it from (CCCR / FBR in F0, or somewhere in F1). 490 * Reads are retried three times. 491 * 1-byte IO is done with CMD52, more is read with CMD53 with address increment (not FIFO mode). 492 * http://lxr.free-electrons.com/source/drivers/mmc/core/sdio_io.c#L458 493 * ================================== 494 * 495 * 496 */ 497 __unused 498 static void 499 probe_bcrm(struct cam_device *dev) { 500 uint32_t cis_addr; 501 struct cis_info info; 502 503 sdio_card_set_bus_width(dev, bus_width_4); 504 cis_addr = sdio_get_common_cis_addr(dev); 505 printf("CIS address: %04X\n", cis_addr); 506 507 memset(&info, 0, sizeof(info)); 508 sdio_func_read_cis(dev, 0, cis_addr, &info); 509 printf("Vendor 0x%04X product 0x%04X\n", info.man_id, info.prod_id); 510 } 511 __unused 512 static uint8_t * 513 mmap_fw() { 514 const char fw_path[] = "/home/kibab/repos/fbsd-bbb/brcm-firmware/brcmfmac4330-sdio.bin"; 515 struct stat sb; 516 uint8_t *fw_ptr; 517 518 int fd = open(fw_path, O_RDONLY); 519 if (fd < 0) 520 errx(1, "Cannot open firmware file"); 521 if (fstat(fd, &sb) < 0) 522 errx(1, "Cannot get file stat"); 523 fw_ptr = mmap(NULL, sb.st_size, PROT_READ, 0, fd, 0); 524 if (fw_ptr == MAP_FAILED) 525 errx(1, "Cannot map the file"); 526 527 return fw_ptr; 528 } 529 530 static void 531 usage() { 532 printf("sdiotool -u <pass_dev_unit>\n"); 533 exit(0); 534 } 535 536 static void 537 get_sdio_card_info(struct cam_device *dev) { 538 uint32_t cis_addr; 539 uint32_t fbr_addr; 540 struct cis_info info; 541 542 cis_addr = sdio_get_common_cis_addr(dev); 543 544 memset(&info, 0, sizeof(info)); 545 sdio_func_read_cis(dev, 0, cis_addr, &info); 546 printf("F0: Vendor 0x%04X product 0x%04X max block size %d bytes\n", 547 info.man_id, info.prod_id, info.max_block_size); 548 for (int i = 1; i <= 2; i++) { 549 fbr_addr = SD_IO_FBR_START * i + 0x9; 550 cis_addr = sdio_read_1(dev, 0, fbr_addr++); 551 cis_addr |= sdio_read_1(dev, 0, fbr_addr++) << 8; 552 cis_addr |= sdio_read_1(dev, 0, fbr_addr++) << 16; 553 memset(&info, 0, sizeof(info)); 554 sdio_func_read_cis(dev, i, cis_addr, &info); 555 printf("F%d: Vendor 0x%04X product 0x%04X max block size %d bytes\n", 556 i, info.man_id, info.prod_id, info.max_block_size); 557 } 558 } 559 560 /* Test interrupt delivery when select() */ 561 __unused static int 562 sdio_signal_intr(struct cam_device *dev) { 563 uint8_t resp; 564 int ret; 565 566 ret = sdio_rw_direct(dev, 0, 0x666, 0, NULL, &resp); 567 if (ret < 0) 568 return ret; 569 return (0); 570 } 571 572 static void 573 do_intr_test(__unused struct cam_device *dev) { 574 } 575 576 int 577 main(int argc, char **argv) { 578 char device[] = "pass"; 579 int unit = 0; 580 int func = 0; 581 uint8_t resp; 582 uint8_t is_enab; 583 __unused uint8_t *fw_ptr; 584 int ch; 585 struct cam_device *cam_dev; 586 int is_intr_test = 0; 587 588 //fw_ptr = mmap_fw(); 589 590 while ((ch = getopt(argc, argv, "Iu:")) != -1) { 591 switch (ch) { 592 case 'u': 593 unit = (int) strtol(optarg, NULL, 10); 594 break; 595 case 'f': 596 func = (int) strtol(optarg, NULL, 10); 597 case 'I': 598 is_intr_test = 1; 599 case '?': 600 default: 601 usage(); 602 } 603 } 604 argc -= optind; 605 argv += optind; 606 607 if ((cam_dev = cam_open_spec_device(device, unit, O_RDWR, NULL)) == NULL) 608 errx(1, "Cannot open device"); 609 610 get_sdio_card_info(cam_dev); 611 if (is_intr_test > 0) 612 do_intr_test(cam_dev); 613 exit(0); 614 sdio_card_reset(cam_dev); 615 616 /* Read Addr 7 of func 0 */ 617 int ret = sdio_rw_direct(cam_dev, 0, 7, 0, NULL, &resp); 618 if (ret < 0) 619 errx(1, "Error sending CAM command"); 620 printf("Result: %02x\n", resp); 621 622 /* Check if func 1 is enabled */ 623 ret = sdio_is_func_enabled(cam_dev, 1, &is_enab); 624 if (ret < 0) 625 errx(1, "Cannot check if func is enabled"); 626 printf("F1 enabled: %d\n", is_enab); 627 ret = sdio_func_enable(cam_dev, 1, 1 - is_enab); 628 if (ret < 0) 629 errx(1, "Cannot enable/disable func"); 630 printf("F1 en/dis result: %d\n", ret); 631 632 /* Check if func 1 is ready */ 633 ret = sdio_is_func_ready(cam_dev, 1, &is_enab); 634 if (ret < 0) 635 errx(1, "Cannot check if func is ready"); 636 printf("F1 ready: %d\n", is_enab); 637 638 /* Check if interrupts are enabled */ 639 ret = sdio_is_func_intr_enabled(cam_dev, 1, &is_enab); 640 if (ret < 0) 641 errx(1, "Cannot check if func intr is enabled"); 642 printf("F1 intr enabled: %d\n", is_enab); 643 ret = sdio_func_intr_enable(cam_dev, 1, 1 - is_enab); 644 if (ret < 0) 645 errx(1, "Cannot enable/disable func intr"); 646 printf("F1 intr en/dis result: %d\n", ret); 647 648 cam_close_spec_device(cam_dev); 649 } 650