?? bt3c_cs.c
字號:
}static int bt3c_hci_close(struct hci_dev *hdev){ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) return 0; bt3c_hci_flush(hdev); return 0;}static int bt3c_hci_send_frame(struct sk_buff *skb){ bt3c_info_t *info; struct hci_dev *hdev = (struct hci_dev *)(skb->dev); unsigned long flags; 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, const 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_strtoul(b, NULL, 16); memset(b, 0, sizeof(b)); memcpy(b, ptr + 4, 8); addr = simple_strtoul(b, NULL, 16); memset(b, 0, sizeof(b)); memcpy(b, ptr + (size * 2) + 2, 2); fcs = simple_strtoul(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_strtoul(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_DYNAMIC_SHARING | 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 bt3c_check_config(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cf, cistpl_cftable_entry_t *dflt, unsigned int vcc, void *priv_data){ unsigned long try = (unsigned long) priv_data; if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) p_dev->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)) { p_dev->io.BasePort1 = cf->io.win[0].base; p_dev->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; if (!pcmcia_request_io(p_dev, &p_dev->io)) return 0; } return -ENODEV;}static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev, cistpl_cftable_entry_t *cf, cistpl_cftable_entry_t *dflt, unsigned int vcc, void *priv_data){ static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; int j; if ((cf->io.nwin > 0) && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { for (j = 0; j < 5; j++) { p_dev->io.BasePort1 = base[j]; p_dev->io.IOAddrLines = base[j] ? 16 : 3; if (!pcmcia_request_io(p_dev, &p_dev->io)) return 0; } } return -ENODEV;}static int bt3c_config(struct pcmcia_device *link){ bt3c_info_t *info = link->priv; int i; unsigned long try; /* First pass: look for a config entry that looks normal. Two tries: without IO aliases, then with aliases */ for (try = 0; try < 2; try++) if (!pcmcia_loop_config(link, bt3c_check_config, (void *) try)) goto found_port; /* 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. */ if (!pcmcia_loop_config(link, bt3c_check_config_notpicky, NULL)) goto found_port; BT_ERR("No usable port range found"); cs_error(link, RequestIO, -ENODEV); goto failed;found_port: i = pcmcia_request_irq(link, &link->irq); if (i != 0) { cs_error(link, RequestIRQ, i); link->irq.AssignedIRQ = 0; } i = pcmcia_request_configuration(link, &link->conf); if (i != 0) { 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;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 + -