diff options
Diffstat (limited to 'drivers/bluetooth/btuart_cs.c')
| -rw-r--r-- | drivers/bluetooth/btuart_cs.c | 413 |
1 files changed, 104 insertions, 309 deletions
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 89486ea7a02..fb948f02eda 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -20,14 +20,12 @@ * */ -#include <linux/config.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/types.h> -#include <linux/sched.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/ptrace.h> @@ -40,11 +38,8 @@ #include <linux/serial.h> #include <linux/serial_reg.h> #include <linux/bitops.h> -#include <asm/system.h> #include <asm/io.h> -#include <pcmcia/cs_types.h> -#include <pcmcia/cs.h> #include <pcmcia/cistpl.h> #include <pcmcia/ciscode.h> #include <pcmcia/ds.h> @@ -68,8 +63,7 @@ MODULE_LICENSE("GPL"); typedef struct btuart_info_t { - dev_link_t link; - dev_node_t node; + struct pcmcia_device *p_dev; struct hci_dev *hdev; @@ -84,16 +78,10 @@ typedef struct btuart_info_t { } btuart_info_t; -static void btuart_config(dev_link_t *link); -static void btuart_release(dev_link_t *link); -static int btuart_event(event_t event, int priority, event_callback_args_t *args); +static int btuart_config(struct pcmcia_device *link); +static void btuart_release(struct pcmcia_device *link); -static dev_info_t dev_info = "btuart_cs"; - -static dev_link_t *btuart_attach(void); -static void btuart_detach(dev_link_t *); - -static dev_link_t *dev_list = NULL; +static void btuart_detach(struct pcmcia_device *p_dev); /* Maximum baud rate */ @@ -152,16 +140,17 @@ static void btuart_write_wakeup(btuart_info_t *info) } do { - register unsigned int iobase = info->link.io.BasePort1; + unsigned int iobase = info->p_dev->resource[0]->start; register struct sk_buff *skb; - register int len; + int len; clear_bit(XMIT_WAKEUP, &(info->tx_state)); - if (!(info->link.state & DEV_PRESENT)) + if (!pcmcia_dev_present(info->p_dev)) return; - if (!(skb = skb_dequeue(&(info->txq)))) + skb = skb_dequeue(&(info->txq)); + if (!skb) break; /* Send frame */ @@ -193,7 +182,7 @@ static void btuart_receive(btuart_info_t *info) return; } - iobase = info->link.io.BasePort1; + iobase = info->p_dev->resource[0]->start; do { info->hdev->stat.byte_rx++; @@ -202,7 +191,8 @@ static void btuart_receive(btuart_info_t *info) if (info->rx_skb == NULL) { info->rx_state = RECV_WAIT_PACKET_TYPE; info->rx_count = 0; - if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); + if (!info->rx_skb) { BT_ERR("Can't allocate mem for new packet"); return; } @@ -210,7 +200,6 @@ static void btuart_receive(btuart_info_t *info) if (info->rx_state == RECV_WAIT_PACKET_TYPE) { - info->rx_skb->dev = (void *) info->hdev; bt_cb(info->rx_skb)->pkt_type = inb(iobase + UART_RX); switch (bt_cb(info->rx_skb)->pkt_type) { @@ -258,26 +247,26 @@ static void btuart_receive(btuart_info_t *info) switch (info->rx_state) { case RECV_WAIT_EVENT_HEADER: - eh = (struct hci_event_hdr *)(info->rx_skb->data); + eh = hci_event_hdr(info->rx_skb); info->rx_state = RECV_WAIT_DATA; info->rx_count = eh->plen; break; case RECV_WAIT_ACL_HEADER: - ah = (struct hci_acl_hdr *)(info->rx_skb->data); + ah = hci_acl_hdr(info->rx_skb); dlen = __le16_to_cpu(ah->dlen); info->rx_state = RECV_WAIT_DATA; info->rx_count = dlen; break; case RECV_WAIT_SCO_HEADER: - sh = (struct hci_sco_hdr *)(info->rx_skb->data); + sh = hci_sco_hdr(info->rx_skb); info->rx_state = RECV_WAIT_DATA; info->rx_count = sh->dlen; break; case RECV_WAIT_DATA: - hci_recv_frame(info->rx_skb); + hci_recv_frame(info->hdev, info->rx_skb); info->rx_skb = NULL; break; @@ -295,24 +284,25 @@ static void btuart_receive(btuart_info_t *info) } -static irqreturn_t btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs) +static irqreturn_t btuart_interrupt(int irq, void *dev_inst) { btuart_info_t *info = dev_inst; unsigned int iobase; int boguscount = 0; int iir, lsr; + irqreturn_t r = IRQ_NONE; - if (!info || !info->hdev) { - BT_ERR("Call of irq %d for unknown device", irq); + if (!info || !info->hdev) + /* our irq handler is shared */ return IRQ_NONE; - } - iobase = info->link.io.BasePort1; + iobase = info->p_dev->resource[0]->start; spin_lock(&(info->lock)); iir = inb(iobase + UART_IIR) & UART_IIR_ID; while (iir) { + r = IRQ_HANDLED; /* Clear interrupt */ lsr = inb(iobase + UART_LSR); @@ -346,7 +336,7 @@ static irqreturn_t btuart_interrupt(int irq, void *dev_inst, struct pt_regs *reg spin_unlock(&(info->lock)); - return IRQ_HANDLED; + return r; } @@ -363,7 +353,7 @@ static void btuart_change_speed(btuart_info_t *info, unsigned int speed) return; } - iobase = info->link.io.BasePort1; + iobase = info->p_dev->resource[0]->start; spin_lock_irqsave(&(info->lock), flags); @@ -394,7 +384,7 @@ static void btuart_change_speed(btuart_info_t *info, unsigned int speed) outb(lcr, iobase + UART_LCR); /* Set 8N1 */ outb(fcr, iobase + UART_FCR); /* Enable FIFO's */ - /* Turn on interrups */ + /* Turn on interrupts */ outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); spin_unlock_irqrestore(&(info->lock), flags); @@ -407,7 +397,7 @@ static void btuart_change_speed(btuart_info_t *info, unsigned int speed) static int btuart_hci_flush(struct hci_dev *hdev) { - btuart_info_t *info = (btuart_info_t *)(hdev->driver_data); + btuart_info_t *info = hci_get_drvdata(hdev); /* Drop TX queue */ skb_queue_purge(&(info->txq)); @@ -435,17 +425,9 @@ static int btuart_hci_close(struct hci_dev *hdev) } -static int btuart_hci_send_frame(struct sk_buff *skb) +static int btuart_hci_send_frame(struct hci_dev *hdev, 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); + btuart_info_t *info = hci_get_drvdata(hdev); switch (bt_cb(skb)->pkt_type) { case HCI_COMMAND_PKT: @@ -457,7 +439,7 @@ static int btuart_hci_send_frame(struct sk_buff *skb) 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); @@ -469,17 +451,6 @@ static int btuart_hci_send_frame(struct sk_buff *skb) } -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 ======================== */ @@ -487,7 +458,7 @@ static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned lon static int btuart_open(btuart_info_t *info) { unsigned long flags; - unsigned int iobase = info->link.io.BasePort1; + unsigned int iobase = info->p_dev->resource[0]->start; struct hci_dev *hdev; spin_lock_init(&(info->lock)); @@ -507,17 +478,14 @@ static int btuart_open(btuart_info_t *info) 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->bus = HCI_PCCARD; + hci_set_drvdata(hdev, info); + SET_HCIDEV_DEV(hdev, &info->p_dev->dev); - hdev->owner = THIS_MODULE; + hdev->open = btuart_hci_open; + hdev->close = btuart_hci_close; + hdev->flush = btuart_hci_flush; + hdev->send = btuart_hci_send_frame; spin_lock_irqsave(&(info->lock), flags); @@ -556,7 +524,7 @@ static int btuart_open(btuart_info_t *info) static int btuart_close(btuart_info_t *info) { unsigned long flags; - unsigned int iobase = info->link.io.BasePort1; + unsigned int iobase = info->p_dev->resource[0]->start; struct hci_dev *hdev = info->hdev; if (!hdev) @@ -574,282 +542,126 @@ static int btuart_close(btuart_info_t *info) spin_unlock_irqrestore(&(info->lock), flags); - if (hci_unregister_dev(hdev) < 0) - BT_ERR("Can't unregister HCI device %s", hdev->name); - + hci_unregister_dev(hdev); hci_free_dev(hdev); return 0; } -static dev_link_t *btuart_attach(void) +static int btuart_probe(struct pcmcia_device *link) { btuart_info_t *info; - client_reg_t client_reg; - dev_link_t *link; - int ret; /* Create new info device */ - info = kmalloc(sizeof(*info), GFP_KERNEL); + info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL); if (!info) - return NULL; - memset(info, 0, sizeof(*info)); + return -ENOMEM; - link = &info->link; + 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.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.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; - } + link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP | + CONF_AUTO_SET_IO; - return link; + return btuart_config(link); } -static void btuart_detach(dev_link_t *link) +static void btuart_detach(struct pcmcia_device *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; + btuart_release(link); +} - if (*linkp == NULL) - return; +static int btuart_check_config(struct pcmcia_device *p_dev, void *priv_data) +{ + int *try = priv_data; - if (link->state & DEV_CONFIG) - btuart_release(link); + if (!try) + p_dev->io_lines = 16; - if (link->handle) { - ret = pcmcia_deregister_client(link->handle); - if (ret != CS_SUCCESS) - cs_error(link->handle, DeregisterClient, ret); - } + if ((p_dev->resource[0]->end != 8) || (p_dev->resource[0]->start == 0)) + return -EINVAL; - /* Unlink device structure, free bits */ - *linkp = link->next; + p_dev->resource[0]->end = 8; + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; - kfree(info); + return pcmcia_request_io(p_dev); } -static int get_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +static int btuart_check_config_notpicky(struct pcmcia_device *p_dev, + void *priv_data) { - int i; - - i = pcmcia_get_tuple_data(handle, tuple); - if (i != CS_SUCCESS) - return i; + static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; + int j; - return pcmcia_parse_tuple(handle, tuple, parse); -} + if (p_dev->io_lines > 3) + return -ENODEV; -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); -} + p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; + p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8; + p_dev->resource[0]->end = 8; -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); + for (j = 0; j < 5; j++) { + p_dev->resource[0]->start = base[j]; + p_dev->io_lines = base[j] ? 16 : 3; + if (!pcmcia_request_io(p_dev)) + return 0; + } + return -ENODEV; } -static void btuart_config(dev_link_t *link) +static int btuart_config(struct pcmcia_device *link) { - static kio_addr_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); - } - } + int i; + int 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, btuart_check_config, &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. */ - 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); - } + if (!pcmcia_loop_config(link, btuart_check_config_notpicky, NULL)) + goto found_port; + + BT_ERR("No usable port range found"); + goto failed; found_port: - if (i != CS_SUCCESS) { - BT_ERR("No usable port range found"); - cs_error(link->handle, RequestIO, i); + i = pcmcia_request_irq(link, btuart_interrupt); + if (i != 0) 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); + i = pcmcia_enable_device(link); + if (i != 0) 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); + return 0; failed: btuart_release(link); + return -ENODEV; } -static 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; -} - - -static int btuart_event(event_t event, int priority, event_callback_args_t *args) +static void btuart_release(struct pcmcia_device *link) { - 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; - } + btuart_close(info); - return 0; + pcmcia_disable_device(link); } -static struct pcmcia_device_id btuart_ids[] = { +static const struct pcmcia_device_id btuart_ids[] = { /* don't use this driver. Use serial_cs + hci_uart instead */ PCMCIA_DEVICE_NULL }; @@ -857,26 +669,9 @@ MODULE_DEVICE_TABLE(pcmcia, btuart_ids); static struct pcmcia_driver btuart_driver = { .owner = THIS_MODULE, - .drv = { - .name = "btuart_cs", - }, - .attach = btuart_attach, - .event = btuart_event, - .detach = btuart_detach, + .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); - BUG_ON(dev_list != NULL); -} - -module_init(init_btuart_cs); -module_exit(exit_btuart_cs); +module_pcmcia_driver(btuart_driver); |
