📄 btuart_cs.c
字号:
spin_unlock_irqrestore(&(info->lock), flags);}/* ======================== HCI interface ======================== */static int btuart_hci_flush(struct hci_dev *hdev){ btuart_info_t *info = (btuart_info_t *)(hdev->driver_data); /* Drop TX queue */ skb_queue_purge(&(info->txq)); return 0;}static int btuart_hci_open(struct hci_dev *hdev){ set_bit(HCI_RUNNING, &(hdev->flags)); return 0;}static int btuart_hci_close(struct hci_dev *hdev){ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) return 0; btuart_hci_flush(hdev); return 0;}static int btuart_hci_send_frame(struct sk_buff *skb){ btuart_info_t *info; struct hci_dev *hdev = (struct hci_dev *)(skb->dev); if (!hdev) { BT_ERR("Frame for unknown HCI device (hdev=NULL)"); return -ENODEV; } info = (btuart_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); btuart_write_wakeup(info); return 0;}static void btuart_hci_destruct(struct hci_dev *hdev){}static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg){ return -ENOIOCTLCMD;}/* ======================== Card services HCI interaction ======================== */static int btuart_open(btuart_info_t *info){ unsigned long flags; unsigned int iobase = info->p_dev->io.BasePort1; struct hci_dev *hdev; 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 = btuart_hci_open; hdev->close = btuart_hci_close; hdev->flush = btuart_hci_flush; hdev->send = btuart_hci_send_frame; hdev->destruct = btuart_hci_destruct; hdev->ioctl = btuart_hci_ioctl; hdev->owner = THIS_MODULE; spin_lock_irqsave(&(info->lock), flags); /* Reset UART */ outb(0, iobase + UART_MCR); /* Turn off interrupts */ outb(0, iobase + UART_IER); /* Initialize UART */ outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR); /* Turn on interrupts */ // outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); spin_unlock_irqrestore(&(info->lock), flags); btuart_change_speed(info, DEFAULT_BAUD_RATE); /* Timeout before it is safe to send the first HCI packet */ msleep(1000); /* Register HCI device */ if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); info->hdev = NULL; hci_free_dev(hdev); return -ENODEV; } return 0;}static int btuart_close(btuart_info_t *info){ unsigned long flags; unsigned int iobase = info->p_dev->io.BasePort1; struct hci_dev *hdev = info->hdev; if (!hdev) return -ENODEV; btuart_hci_close(hdev); spin_lock_irqsave(&(info->lock), flags); /* Reset UART */ outb(0, iobase + UART_MCR); /* Turn off interrupts */ outb(0, iobase + UART_IER); spin_unlock_irqrestore(&(info->lock), flags); if (hci_unregister_dev(hdev) < 0) BT_ERR("Can't unregister HCI device %s", hdev->name); hci_free_dev(hdev); return 0;}static int btuart_probe(struct pcmcia_device *link){ btuart_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 = btuart_interrupt; link->irq.Instance = info; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; return btuart_config(link);}static void btuart_detach(struct pcmcia_device *link){ btuart_info_t *info = link->priv; btuart_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 btuart_config(struct pcmcia_device *link){ static kio_addr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; btuart_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 (btuart_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: btuart_release(link); return -ENODEV;}static void btuart_release(struct pcmcia_device *link){ btuart_info_t *info = link->priv; btuart_close(info); pcmcia_disable_device(link);}static struct pcmcia_device_id btuart_ids[] = { /* don't use this driver. Use serial_cs + hci_uart instead */ PCMCIA_DEVICE_NULL};MODULE_DEVICE_TABLE(pcmcia, btuart_ids);static struct pcmcia_driver btuart_driver = { .owner = THIS_MODULE, .drv = { .name = "btuart_cs", }, .probe = btuart_probe, .remove = btuart_detach, .id_table = btuart_ids,};static int __init init_btuart_cs(void){ return pcmcia_register_driver(&btuart_driver);}static void __exit exit_btuart_cs(void){ pcmcia_unregister_driver(&btuart_driver);}module_init(init_btuart_cs);module_exit(exit_btuart_cs);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -