📄 bt3c_cs.c
字号:
if (!hdev) { BT_ERR("Frame for unknown HCI device (hdev=NULL)"); return -ENODEV; } info = (bt3c_info_t *) (hdev->driver_data); switch (bt_cb(skb)->pkt_type) { case HCI_COMMAND_PKT: hdev->stat.cmd_tx++; break; case HCI_ACLDATA_PKT: hdev->stat.acl_tx++; break; case HCI_SCODATA_PKT: hdev->stat.sco_tx++; break; }; /* Prepend skb with frame type */ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); skb_queue_tail(&(info->txq), skb); spin_lock_irqsave(&(info->lock), flags); bt3c_write_wakeup(info); spin_unlock_irqrestore(&(info->lock), flags); return 0;}static void bt3c_hci_destruct(struct hci_dev *hdev){}static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg){ return -ENOIOCTLCMD;}/* ======================== Card services HCI interaction ======================== */static int bt3c_load_firmware(bt3c_info_t *info, unsigned char *firmware, int count){ char *ptr = (char *) firmware; char b[9]; unsigned int iobase, size, addr, fcs, tmp; int i, err = 0; iobase = info->p_dev->io.BasePort1; /* Reset */ bt3c_io_write(iobase, 0x8040, 0x0404); bt3c_io_write(iobase, 0x8040, 0x0400); udelay(1); bt3c_io_write(iobase, 0x8040, 0x0404); udelay(17); /* Load */ while (count) { if (ptr[0] != 'S') { BT_ERR("Bad address in firmware"); err = -EFAULT; goto error; } memset(b, 0, sizeof(b)); memcpy(b, ptr + 2, 2); size = simple_strtol(b, NULL, 16); memset(b, 0, sizeof(b)); memcpy(b, ptr + 4, 8); addr = simple_strtol(b, NULL, 16); memset(b, 0, sizeof(b)); memcpy(b, ptr + (size * 2) + 2, 2); fcs = simple_strtol(b, NULL, 16); memset(b, 0, sizeof(b)); for (tmp = 0, i = 0; i < size; i++) { memcpy(b, ptr + (i * 2) + 2, 2); tmp += simple_strtol(b, NULL, 16); } if (((tmp + fcs) & 0xff) != 0xff) { BT_ERR("Checksum error in firmware"); err = -EILSEQ; goto error; } if (ptr[1] == '3') { bt3c_address(iobase, addr); memset(b, 0, sizeof(b)); for (i = 0; i < (size - 4) / 2; i++) { memcpy(b, ptr + (i * 4) + 12, 4); tmp = simple_strtol(b, NULL, 16); bt3c_put(iobase, tmp); } } ptr += (size * 2) + 6; count -= (size * 2) + 6; } udelay(17); /* Boot */ bt3c_address(iobase, 0x3000); outb(inb(iobase + CONTROL) | 0x40, iobase + CONTROL);error: udelay(17); /* Clear */ bt3c_io_write(iobase, 0x7006, 0x0000); bt3c_io_write(iobase, 0x7005, 0x0000); bt3c_io_write(iobase, 0x7001, 0x0000); return err;}static int bt3c_open(bt3c_info_t *info){ const struct firmware *firmware; struct hci_dev *hdev; int err; spin_lock_init(&(info->lock)); skb_queue_head_init(&(info->txq)); info->rx_state = RECV_WAIT_PACKET_TYPE; info->rx_count = 0; info->rx_skb = NULL; /* Initialize HCI device */ hdev = hci_alloc_dev(); if (!hdev) { BT_ERR("Can't allocate HCI device"); return -ENOMEM; } info->hdev = hdev; hdev->type = HCI_PCCARD; hdev->driver_data = info; SET_HCIDEV_DEV(hdev, &info->p_dev->dev); hdev->open = bt3c_hci_open; hdev->close = bt3c_hci_close; hdev->flush = bt3c_hci_flush; hdev->send = bt3c_hci_send_frame; hdev->destruct = bt3c_hci_destruct; hdev->ioctl = bt3c_hci_ioctl; hdev->owner = THIS_MODULE; /* Load firmware */ err = request_firmware(&firmware, "BT3CPCC.bin", &info->p_dev->dev); if (err < 0) { BT_ERR("Firmware request failed"); goto error; } err = bt3c_load_firmware(info, firmware->data, firmware->size); release_firmware(firmware); if (err < 0) { BT_ERR("Firmware loading failed"); goto error; } /* Timeout before it is safe to send the first HCI packet */ msleep(1000); /* Register HCI device */ err = hci_register_dev(hdev); if (err < 0) { BT_ERR("Can't register HCI device"); goto error; } return 0;error: info->hdev = NULL; hci_free_dev(hdev); return err;}static int bt3c_close(bt3c_info_t *info){ struct hci_dev *hdev = info->hdev; if (!hdev) return -ENODEV; bt3c_hci_close(hdev); if (hci_unregister_dev(hdev) < 0) BT_ERR("Can't unregister HCI device %s", hdev->name); hci_free_dev(hdev); return 0;}static int bt3c_probe(struct pcmcia_device *link){ bt3c_info_t *info; /* Create new info device */ info = kzalloc(sizeof(*info), GFP_KERNEL); if (!info) return -ENOMEM; info->p_dev = link; link->priv = info; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.NumPorts1 = 8; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = bt3c_interrupt; link->irq.Instance = info; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; return bt3c_config(link);}static void bt3c_detach(struct pcmcia_device *link){ bt3c_info_t *info = link->priv; bt3c_release(link); kfree(info);}static int get_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse){ int i; i = pcmcia_get_tuple_data(handle, tuple); if (i != CS_SUCCESS) return i; return pcmcia_parse_tuple(handle, tuple, parse);}static int first_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse){ if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS) return CS_NO_MORE_ITEMS; return get_tuple(handle, tuple, parse);}static int next_tuple(struct pcmcia_device *handle, tuple_t *tuple, cisparse_t *parse){ if (pcmcia_get_next_tuple(handle, tuple) != CS_SUCCESS) return CS_NO_MORE_ITEMS; return get_tuple(handle, tuple, parse);}static int bt3c_config(struct pcmcia_device *link){ static kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; bt3c_info_t *info = link->priv; tuple_t tuple; u_short buf[256]; cisparse_t parse; cistpl_cftable_entry_t *cf = &parse.cftable_entry; int i, j, try, last_ret, last_fn; tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; /* Get configuration register information */ tuple.DesiredTuple = CISTPL_CONFIG; last_ret = first_tuple(link, &tuple, &parse); if (last_ret != CS_SUCCESS) { last_fn = ParseTuple; goto cs_failed; } link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; /* First pass: look for a config entry that looks normal. */ tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; /* Two tries: without IO aliases, then with aliases */ for (try = 0; try < 2; try++) { i = first_tuple(link, &tuple, &parse); while (i != CS_NO_MORE_ITEMS) { if (i != CS_SUCCESS) goto next_entry; if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) link->conf.Vpp = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) { link->conf.ConfigIndex = cf->index; link->io.BasePort1 = cf->io.win[0].base; link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) goto found_port; }next_entry: i = next_tuple(link, &tuple, &parse); } } /* Second pass: try to find an entry that isn't picky about its base address, then try to grab any standard serial port address, and finally try to get any free port. */ i = first_tuple(link, &tuple, &parse); while (i != CS_NO_MORE_ITEMS) { if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { link->conf.ConfigIndex = cf->index; for (j = 0; j < 5; j++) { link->io.BasePort1 = base[j]; link->io.IOAddrLines = base[j] ? 16 : 3; i = pcmcia_request_io(link, &link->io); if (i == CS_SUCCESS) goto found_port; } } i = next_tuple(link, &tuple, &parse); }found_port: if (i != CS_SUCCESS) { BT_ERR("No usable port range found"); cs_error(link, RequestIO, i); goto failed; } i = pcmcia_request_irq(link, &link->irq); if (i != CS_SUCCESS) { cs_error(link, RequestIRQ, i); link->irq.AssignedIRQ = 0; } i = pcmcia_request_configuration(link, &link->conf); if (i != CS_SUCCESS) { cs_error(link, RequestConfiguration, i); goto failed; } if (bt3c_open(info) != 0) goto failed; strcpy(info->node.dev_name, info->hdev->name); link->dev_node = &info->node; return 0;cs_failed: cs_error(link, last_fn, last_ret);failed: bt3c_release(link); return -ENODEV;}static void bt3c_release(struct pcmcia_device *link){ bt3c_info_t *info = link->priv; bt3c_close(info); pcmcia_disable_device(link);}static struct pcmcia_device_id bt3c_ids[] = { PCMCIA_DEVICE_PROD_ID13("3COM", "Bluetooth PC Card", 0xefce0a31, 0xd4ce9b02), PCMCIA_DEVICE_NULL};MODULE_DEVICE_TABLE(pcmcia, bt3c_ids);static struct pcmcia_driver bt3c_driver = { .owner = THIS_MODULE, .drv = { .name = "bt3c_cs", }, .probe = bt3c_probe, .remove = bt3c_detach, .id_table = bt3c_ids,};static int __init init_bt3c_cs(void){ return pcmcia_register_driver(&bt3c_driver);}static void __exit exit_bt3c_cs(void){ pcmcia_unregister_driver(&bt3c_driver);}module_init(init_bt3c_cs);module_exit(exit_bt3c_cs);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -