aboutsummaryrefslogtreecommitdiff
path: root/drivers/bluetooth/btuart_cs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/bluetooth/btuart_cs.c')
-rw-r--r--drivers/bluetooth/btuart_cs.c413
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);