📄 btuart_cs.c
字号:
if (!hdev) { BT_ERR("Frame for unknown HCI device (hdev=NULL)"); return -ENODEV; } info = (btuart_info_t *)(hdev->driver_data); switch (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), &(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 ======================== */int btuart_open(btuart_info_t *info){ unsigned long flags; unsigned int iobase = info->link.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; 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;}int btuart_close(btuart_info_t *info){ unsigned long flags; unsigned int iobase = info->link.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;}dev_link_t *btuart_attach(void){ btuart_info_t *info; client_reg_t client_reg; dev_link_t *link; int i, ret; /* Create new info device */ info = kmalloc(sizeof(*info), GFP_KERNEL); if (!info) return NULL; memset(info, 0, sizeof(*info)); link = &info->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_INFO2_VALID | IRQ_LEVEL_ID; if (irq_list[0] == -1) link->irq.IRQInfo2 = irq_mask; else for (i = 0; i < 4; i++) link->irq.IRQInfo2 |= 1 << irq_list[i]; link->irq.Handler = btuart_interrupt; link->irq.Instance = info; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.Vcc = 50; link->conf.IntType = INT_MEMORY_AND_IO; /* Register with Card Services */ link->next = dev_list; dev_list = link; client_reg.dev_info = &dev_info; client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; client_reg.event_handler = &btuart_event; client_reg.Version = 0x0210; client_reg.event_callback_args.client_data = link; ret = pcmcia_register_client(&link->handle, &client_reg); if (ret != CS_SUCCESS) { cs_error(link->handle, RegisterClient, ret); btuart_detach(link); return NULL; } return link;}void btuart_detach(dev_link_t *link){ btuart_info_t *info = link->priv; dev_link_t **linkp; int ret; /* Locate device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) if (*linkp == link) break; if (*linkp == NULL) return; if (link->state & DEV_CONFIG) btuart_release(link); if (link->handle) { ret = pcmcia_deregister_client(link->handle); if (ret != CS_SUCCESS) cs_error(link->handle, DeregisterClient, ret); } /* Unlink device structure, free bits */ *linkp = link->next; kfree(info);}static int get_tuple(client_handle_t 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(client_handle_t 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(client_handle_t 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);}void btuart_config(dev_link_t *link){ static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; client_handle_t handle = link->handle; btuart_info_t *info = link->priv; tuple_t tuple; u_short buf[256]; cisparse_t parse; cistpl_cftable_entry_t *cf = &parse.cftable_entry; config_info_t config; 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(handle, &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]; /* Configure card */ link->state |= DEV_CONFIG; i = pcmcia_get_configuration_info(handle, &config); link->conf.Vcc = config.Vcc; /* 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(handle, &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.Vpp1 = link->conf.Vpp2 = 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->handle, &link->io); if (i == CS_SUCCESS) goto found_port; }next_entry: i = next_tuple(handle, &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(handle, &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->handle, &link->io); if (i == CS_SUCCESS) goto found_port; } } i = next_tuple(handle, &tuple, &parse); }found_port: if (i != CS_SUCCESS) { BT_ERR("No usable port range found"); cs_error(link->handle, RequestIO, i); goto failed; } i = pcmcia_request_irq(link->handle, &link->irq); if (i != CS_SUCCESS) { cs_error(link->handle, RequestIRQ, i); link->irq.AssignedIRQ = 0; } i = pcmcia_request_configuration(link->handle, &link->conf); if (i != CS_SUCCESS) { cs_error(link->handle, RequestConfiguration, i); goto failed; } if (btuart_open(info) != 0) goto failed; strcpy(info->node.dev_name, info->hdev->name); link->dev = &info->node; link->state &= ~DEV_CONFIG_PENDING; return;cs_failed: cs_error(link->handle, last_fn, last_ret);failed: btuart_release(link);}void btuart_release(dev_link_t *link){ btuart_info_t *info = link->priv; if (link->state & DEV_PRESENT) btuart_close(info); link->dev = NULL; pcmcia_release_configuration(link->handle); pcmcia_release_io(link->handle, &link->io); pcmcia_release_irq(link->handle, &link->irq); link->state &= ~DEV_CONFIG;}int btuart_event(event_t event, int priority, event_callback_args_t *args){ dev_link_t *link = args->client_data; btuart_info_t *info = link->priv; switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; if (link->state & DEV_CONFIG) { btuart_close(info); btuart_release(link); } break; case CS_EVENT_CARD_INSERTION: link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; btuart_config(link); break; case CS_EVENT_PM_SUSPEND: link->state |= DEV_SUSPEND; /* Fall through... */ case CS_EVENT_RESET_PHYSICAL: if (link->state & DEV_CONFIG) pcmcia_release_configuration(link->handle); break; case CS_EVENT_PM_RESUME: link->state &= ~DEV_SUSPEND; /* Fall through... */ case CS_EVENT_CARD_RESET: if (DEV_OK(link)) pcmcia_request_configuration(link->handle, &link->conf); break; } return 0;}static struct pcmcia_driver btuart_driver = { .owner = THIS_MODULE, .drv = { .name = "btuart_cs", }, .attach = btuart_attach, .detach = btuart_detach,};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); /* XXX: this really needs to move into generic code.. */ while (dev_list != NULL) btuart_detach(dev_list);}module_init(init_btuart_cs);module_exit(exit_btuart_cs);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -