162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci *
362306a36Sopenharmony_ci *  Bluetooth driver for the Anycom BlueCard (LSE039/LSE041)
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (C) 2001-2002  Marcel Holtmann <marcel@holtmann.org>
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *  This program is free software; you can redistribute it and/or modify
962306a36Sopenharmony_ci *  it under the terms of the GNU General Public License version 2 as
1062306a36Sopenharmony_ci *  published by the Free Software Foundation;
1162306a36Sopenharmony_ci *
1262306a36Sopenharmony_ci *  Software distributed under the License is distributed on an "AS
1362306a36Sopenharmony_ci *  IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
1462306a36Sopenharmony_ci *  implied. See the License for the specific language governing
1562306a36Sopenharmony_ci *  rights and limitations under the License.
1662306a36Sopenharmony_ci *
1762306a36Sopenharmony_ci *  The initial developer of the original code is David A. Hinds
1862306a36Sopenharmony_ci *  <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
1962306a36Sopenharmony_ci *  are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci */
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include <linux/module.h>
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#include <linux/kernel.h>
2662306a36Sopenharmony_ci#include <linux/init.h>
2762306a36Sopenharmony_ci#include <linux/slab.h>
2862306a36Sopenharmony_ci#include <linux/types.h>
2962306a36Sopenharmony_ci#include <linux/sched.h>
3062306a36Sopenharmony_ci#include <linux/delay.h>
3162306a36Sopenharmony_ci#include <linux/timer.h>
3262306a36Sopenharmony_ci#include <linux/errno.h>
3362306a36Sopenharmony_ci#include <linux/ptrace.h>
3462306a36Sopenharmony_ci#include <linux/ioport.h>
3562306a36Sopenharmony_ci#include <linux/spinlock.h>
3662306a36Sopenharmony_ci#include <linux/moduleparam.h>
3762306a36Sopenharmony_ci#include <linux/wait.h>
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci#include <linux/skbuff.h>
4062306a36Sopenharmony_ci#include <linux/io.h>
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#include <pcmcia/cistpl.h>
4362306a36Sopenharmony_ci#include <pcmcia/ciscode.h>
4462306a36Sopenharmony_ci#include <pcmcia/ds.h>
4562306a36Sopenharmony_ci#include <pcmcia/cisreg.h>
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#include <net/bluetooth/bluetooth.h>
4862306a36Sopenharmony_ci#include <net/bluetooth/hci_core.h>
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci/* ======================== Module parameters ======================== */
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ciMODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
5662306a36Sopenharmony_ciMODULE_DESCRIPTION("Bluetooth driver for the Anycom BlueCard (LSE039/LSE041)");
5762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/* ======================== Local structures ======================== */
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistruct bluecard_info {
6562306a36Sopenharmony_ci	struct pcmcia_device *p_dev;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	struct hci_dev *hdev;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	spinlock_t lock;		/* For serializing operations */
7062306a36Sopenharmony_ci	struct timer_list timer;	/* For LED control */
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	struct sk_buff_head txq;
7362306a36Sopenharmony_ci	unsigned long tx_state;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	unsigned long rx_state;
7662306a36Sopenharmony_ci	unsigned long rx_count;
7762306a36Sopenharmony_ci	struct sk_buff *rx_skb;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	unsigned char ctrl_reg;
8062306a36Sopenharmony_ci	unsigned long hw_state;		/* Status of the hardware and LED control */
8162306a36Sopenharmony_ci};
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic int bluecard_config(struct pcmcia_device *link);
8562306a36Sopenharmony_cistatic void bluecard_release(struct pcmcia_device *link);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic void bluecard_detach(struct pcmcia_device *p_dev);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci/* Default baud rate: 57600, 115200, 230400 or 460800 */
9162306a36Sopenharmony_ci#define DEFAULT_BAUD_RATE  230400
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/* Hardware states */
9562306a36Sopenharmony_ci#define CARD_READY             1
9662306a36Sopenharmony_ci#define CARD_ACTIVITY	       2
9762306a36Sopenharmony_ci#define CARD_HAS_PCCARD_ID     4
9862306a36Sopenharmony_ci#define CARD_HAS_POWER_LED     5
9962306a36Sopenharmony_ci#define CARD_HAS_ACTIVITY_LED  6
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/* Transmit states  */
10262306a36Sopenharmony_ci#define XMIT_SENDING         1
10362306a36Sopenharmony_ci#define XMIT_WAKEUP          2
10462306a36Sopenharmony_ci#define XMIT_BUFFER_NUMBER   5	/* unset = buffer one, set = buffer two */
10562306a36Sopenharmony_ci#define XMIT_BUF_ONE_READY   6
10662306a36Sopenharmony_ci#define XMIT_BUF_TWO_READY   7
10762306a36Sopenharmony_ci#define XMIT_SENDING_READY   8
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci/* Receiver states */
11062306a36Sopenharmony_ci#define RECV_WAIT_PACKET_TYPE   0
11162306a36Sopenharmony_ci#define RECV_WAIT_EVENT_HEADER  1
11262306a36Sopenharmony_ci#define RECV_WAIT_ACL_HEADER    2
11362306a36Sopenharmony_ci#define RECV_WAIT_SCO_HEADER    3
11462306a36Sopenharmony_ci#define RECV_WAIT_DATA          4
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci/* Special packet types */
11762306a36Sopenharmony_ci#define PKT_BAUD_RATE_57600   0x80
11862306a36Sopenharmony_ci#define PKT_BAUD_RATE_115200  0x81
11962306a36Sopenharmony_ci#define PKT_BAUD_RATE_230400  0x82
12062306a36Sopenharmony_ci#define PKT_BAUD_RATE_460800  0x83
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/* These are the register offsets */
12462306a36Sopenharmony_ci#define REG_COMMAND     0x20
12562306a36Sopenharmony_ci#define REG_INTERRUPT   0x21
12662306a36Sopenharmony_ci#define REG_CONTROL     0x22
12762306a36Sopenharmony_ci#define REG_RX_CONTROL  0x24
12862306a36Sopenharmony_ci#define REG_CARD_RESET  0x30
12962306a36Sopenharmony_ci#define REG_LED_CTRL    0x30
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/* REG_COMMAND */
13262306a36Sopenharmony_ci#define REG_COMMAND_TX_BUF_ONE  0x01
13362306a36Sopenharmony_ci#define REG_COMMAND_TX_BUF_TWO  0x02
13462306a36Sopenharmony_ci#define REG_COMMAND_RX_BUF_ONE  0x04
13562306a36Sopenharmony_ci#define REG_COMMAND_RX_BUF_TWO  0x08
13662306a36Sopenharmony_ci#define REG_COMMAND_RX_WIN_ONE  0x00
13762306a36Sopenharmony_ci#define REG_COMMAND_RX_WIN_TWO  0x10
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci/* REG_CONTROL */
14062306a36Sopenharmony_ci#define REG_CONTROL_BAUD_RATE_57600   0x00
14162306a36Sopenharmony_ci#define REG_CONTROL_BAUD_RATE_115200  0x01
14262306a36Sopenharmony_ci#define REG_CONTROL_BAUD_RATE_230400  0x02
14362306a36Sopenharmony_ci#define REG_CONTROL_BAUD_RATE_460800  0x03
14462306a36Sopenharmony_ci#define REG_CONTROL_RTS               0x04
14562306a36Sopenharmony_ci#define REG_CONTROL_BT_ON             0x08
14662306a36Sopenharmony_ci#define REG_CONTROL_BT_RESET          0x10
14762306a36Sopenharmony_ci#define REG_CONTROL_BT_RES_PU         0x20
14862306a36Sopenharmony_ci#define REG_CONTROL_INTERRUPT         0x40
14962306a36Sopenharmony_ci#define REG_CONTROL_CARD_RESET        0x80
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci/* REG_RX_CONTROL */
15262306a36Sopenharmony_ci#define RTS_LEVEL_SHIFT_BITS  0x02
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci/* ======================== LED handling routines ======================== */
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic void bluecard_activity_led_timeout(struct timer_list *t)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	struct bluecard_info *info = from_timer(info, t, timer);
16262306a36Sopenharmony_ci	unsigned int iobase = info->p_dev->resource[0]->start;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	if (test_bit(CARD_ACTIVITY, &(info->hw_state))) {
16562306a36Sopenharmony_ci		/* leave LED in inactive state for HZ/10 for blink effect */
16662306a36Sopenharmony_ci		clear_bit(CARD_ACTIVITY, &(info->hw_state));
16762306a36Sopenharmony_ci		mod_timer(&(info->timer), jiffies + HZ / 10);
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	/* Disable activity LED, enable power LED */
17162306a36Sopenharmony_ci	outb(0x08 | 0x20, iobase + 0x30);
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic void bluecard_enable_activity_led(struct bluecard_info *info)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	unsigned int iobase = info->p_dev->resource[0]->start;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	/* don't disturb running blink timer */
18062306a36Sopenharmony_ci	if (timer_pending(&(info->timer)))
18162306a36Sopenharmony_ci		return;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	set_bit(CARD_ACTIVITY, &(info->hw_state));
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (test_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state))) {
18662306a36Sopenharmony_ci		/* Enable activity LED, keep power LED enabled */
18762306a36Sopenharmony_ci		outb(0x18 | 0x60, iobase + 0x30);
18862306a36Sopenharmony_ci	} else {
18962306a36Sopenharmony_ci		/* Disable power LED */
19062306a36Sopenharmony_ci		outb(0x00, iobase + 0x30);
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	/* Stop the LED after HZ/10 */
19462306a36Sopenharmony_ci	mod_timer(&(info->timer), jiffies + HZ / 10);
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci/* ======================== Interrupt handling ======================== */
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_cistatic int bluecard_write(unsigned int iobase, unsigned int offset, __u8 *buf, int len)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	int i, actual;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	actual = (len > 15) ? 15 : len;
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci	outb_p(actual, iobase + offset);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	for (i = 0; i < actual; i++)
21162306a36Sopenharmony_ci		outb_p(buf[i], iobase + offset + i + 1);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	return actual;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic void bluecard_write_wakeup(struct bluecard_info *info)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	if (!info) {
22062306a36Sopenharmony_ci		BT_ERR("Unknown device");
22162306a36Sopenharmony_ci		return;
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	if (!test_bit(XMIT_SENDING_READY, &(info->tx_state)))
22562306a36Sopenharmony_ci		return;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
22862306a36Sopenharmony_ci		set_bit(XMIT_WAKEUP, &(info->tx_state));
22962306a36Sopenharmony_ci		return;
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	do {
23362306a36Sopenharmony_ci		unsigned int iobase = info->p_dev->resource[0]->start;
23462306a36Sopenharmony_ci		unsigned int offset;
23562306a36Sopenharmony_ci		unsigned char command;
23662306a36Sopenharmony_ci		unsigned long ready_bit;
23762306a36Sopenharmony_ci		register struct sk_buff *skb;
23862306a36Sopenharmony_ci		int len;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci		clear_bit(XMIT_WAKEUP, &(info->tx_state));
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci		if (!pcmcia_dev_present(info->p_dev))
24362306a36Sopenharmony_ci			return;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci		if (test_bit(XMIT_BUFFER_NUMBER, &(info->tx_state))) {
24662306a36Sopenharmony_ci			if (!test_bit(XMIT_BUF_TWO_READY, &(info->tx_state)))
24762306a36Sopenharmony_ci				break;
24862306a36Sopenharmony_ci			offset = 0x10;
24962306a36Sopenharmony_ci			command = REG_COMMAND_TX_BUF_TWO;
25062306a36Sopenharmony_ci			ready_bit = XMIT_BUF_TWO_READY;
25162306a36Sopenharmony_ci		} else {
25262306a36Sopenharmony_ci			if (!test_bit(XMIT_BUF_ONE_READY, &(info->tx_state)))
25362306a36Sopenharmony_ci				break;
25462306a36Sopenharmony_ci			offset = 0x00;
25562306a36Sopenharmony_ci			command = REG_COMMAND_TX_BUF_ONE;
25662306a36Sopenharmony_ci			ready_bit = XMIT_BUF_ONE_READY;
25762306a36Sopenharmony_ci		}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci		skb = skb_dequeue(&(info->txq));
26062306a36Sopenharmony_ci		if (!skb)
26162306a36Sopenharmony_ci			break;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci		if (hci_skb_pkt_type(skb) & 0x80) {
26462306a36Sopenharmony_ci			/* Disable RTS */
26562306a36Sopenharmony_ci			info->ctrl_reg |= REG_CONTROL_RTS;
26662306a36Sopenharmony_ci			outb(info->ctrl_reg, iobase + REG_CONTROL);
26762306a36Sopenharmony_ci		}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci		/* Activate LED */
27062306a36Sopenharmony_ci		bluecard_enable_activity_led(info);
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci		/* Send frame */
27362306a36Sopenharmony_ci		len = bluecard_write(iobase, offset, skb->data, skb->len);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci		/* Tell the FPGA to send the data */
27662306a36Sopenharmony_ci		outb_p(command, iobase + REG_COMMAND);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci		/* Mark the buffer as dirty */
27962306a36Sopenharmony_ci		clear_bit(ready_bit, &(info->tx_state));
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci		if (hci_skb_pkt_type(skb) & 0x80) {
28262306a36Sopenharmony_ci			DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
28362306a36Sopenharmony_ci			DEFINE_WAIT(wait);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci			unsigned char baud_reg;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci			switch (hci_skb_pkt_type(skb)) {
28862306a36Sopenharmony_ci			case PKT_BAUD_RATE_460800:
28962306a36Sopenharmony_ci				baud_reg = REG_CONTROL_BAUD_RATE_460800;
29062306a36Sopenharmony_ci				break;
29162306a36Sopenharmony_ci			case PKT_BAUD_RATE_230400:
29262306a36Sopenharmony_ci				baud_reg = REG_CONTROL_BAUD_RATE_230400;
29362306a36Sopenharmony_ci				break;
29462306a36Sopenharmony_ci			case PKT_BAUD_RATE_115200:
29562306a36Sopenharmony_ci				baud_reg = REG_CONTROL_BAUD_RATE_115200;
29662306a36Sopenharmony_ci				break;
29762306a36Sopenharmony_ci			case PKT_BAUD_RATE_57600:
29862306a36Sopenharmony_ci			default:
29962306a36Sopenharmony_ci				baud_reg = REG_CONTROL_BAUD_RATE_57600;
30062306a36Sopenharmony_ci				break;
30162306a36Sopenharmony_ci			}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci			/* Wait until the command reaches the baseband */
30462306a36Sopenharmony_ci			mdelay(100);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci			/* Set baud on baseband */
30762306a36Sopenharmony_ci			info->ctrl_reg &= ~0x03;
30862306a36Sopenharmony_ci			info->ctrl_reg |= baud_reg;
30962306a36Sopenharmony_ci			outb(info->ctrl_reg, iobase + REG_CONTROL);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci			/* Enable RTS */
31262306a36Sopenharmony_ci			info->ctrl_reg &= ~REG_CONTROL_RTS;
31362306a36Sopenharmony_ci			outb(info->ctrl_reg, iobase + REG_CONTROL);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci			/* Wait before the next HCI packet can be send */
31662306a36Sopenharmony_ci			mdelay(1000);
31762306a36Sopenharmony_ci		}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci		if (len == skb->len) {
32062306a36Sopenharmony_ci			kfree_skb(skb);
32162306a36Sopenharmony_ci		} else {
32262306a36Sopenharmony_ci			skb_pull(skb, len);
32362306a36Sopenharmony_ci			skb_queue_head(&(info->txq), skb);
32462306a36Sopenharmony_ci		}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci		info->hdev->stat.byte_tx += len;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci		/* Change buffer */
32962306a36Sopenharmony_ci		change_bit(XMIT_BUFFER_NUMBER, &(info->tx_state));
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	} while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	clear_bit(XMIT_SENDING, &(info->tx_state));
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_cistatic int bluecard_read(unsigned int iobase, unsigned int offset, __u8 *buf, int size)
33862306a36Sopenharmony_ci{
33962306a36Sopenharmony_ci	int i, n, len;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	outb(REG_COMMAND_RX_WIN_ONE, iobase + REG_COMMAND);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	len = inb(iobase + offset);
34462306a36Sopenharmony_ci	n = 0;
34562306a36Sopenharmony_ci	i = 1;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	while (n < len) {
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci		if (i == 16) {
35062306a36Sopenharmony_ci			outb(REG_COMMAND_RX_WIN_TWO, iobase + REG_COMMAND);
35162306a36Sopenharmony_ci			i = 0;
35262306a36Sopenharmony_ci		}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci		buf[n] = inb(iobase + offset + i);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci		n++;
35762306a36Sopenharmony_ci		i++;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	return len;
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_cistatic void bluecard_receive(struct bluecard_info *info,
36662306a36Sopenharmony_ci			     unsigned int offset)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	unsigned int iobase;
36962306a36Sopenharmony_ci	unsigned char buf[31];
37062306a36Sopenharmony_ci	int i, len;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (!info) {
37362306a36Sopenharmony_ci		BT_ERR("Unknown device");
37462306a36Sopenharmony_ci		return;
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	iobase = info->p_dev->resource[0]->start;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	if (test_bit(XMIT_SENDING_READY, &(info->tx_state)))
38062306a36Sopenharmony_ci		bluecard_enable_activity_led(info);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	len = bluecard_read(iobase, offset, buf, sizeof(buf));
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	for (i = 0; i < len; i++) {
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci		/* Allocate packet */
38762306a36Sopenharmony_ci		if (!info->rx_skb) {
38862306a36Sopenharmony_ci			info->rx_state = RECV_WAIT_PACKET_TYPE;
38962306a36Sopenharmony_ci			info->rx_count = 0;
39062306a36Sopenharmony_ci			info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
39162306a36Sopenharmony_ci			if (!info->rx_skb) {
39262306a36Sopenharmony_ci				BT_ERR("Can't allocate mem for new packet");
39362306a36Sopenharmony_ci				return;
39462306a36Sopenharmony_ci			}
39562306a36Sopenharmony_ci		}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci		if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci			hci_skb_pkt_type(info->rx_skb) = buf[i];
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci			switch (hci_skb_pkt_type(info->rx_skb)) {
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci			case 0x00:
40462306a36Sopenharmony_ci				/* init packet */
40562306a36Sopenharmony_ci				if (offset != 0x00) {
40662306a36Sopenharmony_ci					set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
40762306a36Sopenharmony_ci					set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
40862306a36Sopenharmony_ci					set_bit(XMIT_SENDING_READY, &(info->tx_state));
40962306a36Sopenharmony_ci					bluecard_write_wakeup(info);
41062306a36Sopenharmony_ci				}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci				kfree_skb(info->rx_skb);
41362306a36Sopenharmony_ci				info->rx_skb = NULL;
41462306a36Sopenharmony_ci				break;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci			case HCI_EVENT_PKT:
41762306a36Sopenharmony_ci				info->rx_state = RECV_WAIT_EVENT_HEADER;
41862306a36Sopenharmony_ci				info->rx_count = HCI_EVENT_HDR_SIZE;
41962306a36Sopenharmony_ci				break;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci			case HCI_ACLDATA_PKT:
42262306a36Sopenharmony_ci				info->rx_state = RECV_WAIT_ACL_HEADER;
42362306a36Sopenharmony_ci				info->rx_count = HCI_ACL_HDR_SIZE;
42462306a36Sopenharmony_ci				break;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci			case HCI_SCODATA_PKT:
42762306a36Sopenharmony_ci				info->rx_state = RECV_WAIT_SCO_HEADER;
42862306a36Sopenharmony_ci				info->rx_count = HCI_SCO_HDR_SIZE;
42962306a36Sopenharmony_ci				break;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci			default:
43262306a36Sopenharmony_ci				/* unknown packet */
43362306a36Sopenharmony_ci				BT_ERR("Unknown HCI packet with type 0x%02x received",
43462306a36Sopenharmony_ci				       hci_skb_pkt_type(info->rx_skb));
43562306a36Sopenharmony_ci				info->hdev->stat.err_rx++;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci				kfree_skb(info->rx_skb);
43862306a36Sopenharmony_ci				info->rx_skb = NULL;
43962306a36Sopenharmony_ci				break;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci			}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci		} else {
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci			skb_put_u8(info->rx_skb, buf[i]);
44662306a36Sopenharmony_ci			info->rx_count--;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci			if (info->rx_count == 0) {
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci				int dlen;
45162306a36Sopenharmony_ci				struct hci_event_hdr *eh;
45262306a36Sopenharmony_ci				struct hci_acl_hdr *ah;
45362306a36Sopenharmony_ci				struct hci_sco_hdr *sh;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci				switch (info->rx_state) {
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci				case RECV_WAIT_EVENT_HEADER:
45862306a36Sopenharmony_ci					eh = hci_event_hdr(info->rx_skb);
45962306a36Sopenharmony_ci					info->rx_state = RECV_WAIT_DATA;
46062306a36Sopenharmony_ci					info->rx_count = eh->plen;
46162306a36Sopenharmony_ci					break;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci				case RECV_WAIT_ACL_HEADER:
46462306a36Sopenharmony_ci					ah = hci_acl_hdr(info->rx_skb);
46562306a36Sopenharmony_ci					dlen = __le16_to_cpu(ah->dlen);
46662306a36Sopenharmony_ci					info->rx_state = RECV_WAIT_DATA;
46762306a36Sopenharmony_ci					info->rx_count = dlen;
46862306a36Sopenharmony_ci					break;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci				case RECV_WAIT_SCO_HEADER:
47162306a36Sopenharmony_ci					sh = hci_sco_hdr(info->rx_skb);
47262306a36Sopenharmony_ci					info->rx_state = RECV_WAIT_DATA;
47362306a36Sopenharmony_ci					info->rx_count = sh->dlen;
47462306a36Sopenharmony_ci					break;
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci				case RECV_WAIT_DATA:
47762306a36Sopenharmony_ci					hci_recv_frame(info->hdev, info->rx_skb);
47862306a36Sopenharmony_ci					info->rx_skb = NULL;
47962306a36Sopenharmony_ci					break;
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci				}
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci			}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci		}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	info->hdev->stat.byte_rx += len;
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_cistatic irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
49562306a36Sopenharmony_ci{
49662306a36Sopenharmony_ci	struct bluecard_info *info = dev_inst;
49762306a36Sopenharmony_ci	unsigned int iobase;
49862306a36Sopenharmony_ci	unsigned char reg;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	if (!info || !info->hdev)
50162306a36Sopenharmony_ci		/* our irq handler is shared */
50262306a36Sopenharmony_ci		return IRQ_NONE;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	if (!test_bit(CARD_READY, &(info->hw_state)))
50562306a36Sopenharmony_ci		return IRQ_HANDLED;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	iobase = info->p_dev->resource[0]->start;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	spin_lock(&(info->lock));
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	/* Disable interrupt */
51262306a36Sopenharmony_ci	info->ctrl_reg &= ~REG_CONTROL_INTERRUPT;
51362306a36Sopenharmony_ci	outb(info->ctrl_reg, iobase + REG_CONTROL);
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	reg = inb(iobase + REG_INTERRUPT);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	if ((reg != 0x00) && (reg != 0xff)) {
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci		if (reg & 0x04) {
52062306a36Sopenharmony_ci			bluecard_receive(info, 0x00);
52162306a36Sopenharmony_ci			outb(0x04, iobase + REG_INTERRUPT);
52262306a36Sopenharmony_ci			outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND);
52362306a36Sopenharmony_ci		}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci		if (reg & 0x08) {
52662306a36Sopenharmony_ci			bluecard_receive(info, 0x10);
52762306a36Sopenharmony_ci			outb(0x08, iobase + REG_INTERRUPT);
52862306a36Sopenharmony_ci			outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND);
52962306a36Sopenharmony_ci		}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci		if (reg & 0x01) {
53262306a36Sopenharmony_ci			set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
53362306a36Sopenharmony_ci			outb(0x01, iobase + REG_INTERRUPT);
53462306a36Sopenharmony_ci			bluecard_write_wakeup(info);
53562306a36Sopenharmony_ci		}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci		if (reg & 0x02) {
53862306a36Sopenharmony_ci			set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
53962306a36Sopenharmony_ci			outb(0x02, iobase + REG_INTERRUPT);
54062306a36Sopenharmony_ci			bluecard_write_wakeup(info);
54162306a36Sopenharmony_ci		}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	}
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	/* Enable interrupt */
54662306a36Sopenharmony_ci	info->ctrl_reg |= REG_CONTROL_INTERRUPT;
54762306a36Sopenharmony_ci	outb(info->ctrl_reg, iobase + REG_CONTROL);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	spin_unlock(&(info->lock));
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	return IRQ_HANDLED;
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci/* ======================== Device specific HCI commands ======================== */
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_cistatic int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	struct bluecard_info *info = hci_get_drvdata(hdev);
56262306a36Sopenharmony_ci	struct sk_buff *skb;
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	/* Ericsson baud rate command */
56562306a36Sopenharmony_ci	unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 };
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_KERNEL);
56862306a36Sopenharmony_ci	if (!skb) {
56962306a36Sopenharmony_ci		BT_ERR("Can't allocate mem for new packet");
57062306a36Sopenharmony_ci		return -1;
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci	switch (baud) {
57462306a36Sopenharmony_ci	case 460800:
57562306a36Sopenharmony_ci		cmd[4] = 0x00;
57662306a36Sopenharmony_ci		hci_skb_pkt_type(skb) = PKT_BAUD_RATE_460800;
57762306a36Sopenharmony_ci		break;
57862306a36Sopenharmony_ci	case 230400:
57962306a36Sopenharmony_ci		cmd[4] = 0x01;
58062306a36Sopenharmony_ci		hci_skb_pkt_type(skb) = PKT_BAUD_RATE_230400;
58162306a36Sopenharmony_ci		break;
58262306a36Sopenharmony_ci	case 115200:
58362306a36Sopenharmony_ci		cmd[4] = 0x02;
58462306a36Sopenharmony_ci		hci_skb_pkt_type(skb) = PKT_BAUD_RATE_115200;
58562306a36Sopenharmony_ci		break;
58662306a36Sopenharmony_ci	case 57600:
58762306a36Sopenharmony_ci	default:
58862306a36Sopenharmony_ci		cmd[4] = 0x03;
58962306a36Sopenharmony_ci		hci_skb_pkt_type(skb) = PKT_BAUD_RATE_57600;
59062306a36Sopenharmony_ci		break;
59162306a36Sopenharmony_ci	}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci	skb_put_data(skb, cmd, sizeof(cmd));
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	skb_queue_tail(&(info->txq), skb);
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	bluecard_write_wakeup(info);
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci	return 0;
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci/* ======================== HCI interface ======================== */
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_cistatic int bluecard_hci_flush(struct hci_dev *hdev)
60862306a36Sopenharmony_ci{
60962306a36Sopenharmony_ci	struct bluecard_info *info = hci_get_drvdata(hdev);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	/* Drop TX queue */
61262306a36Sopenharmony_ci	skb_queue_purge(&(info->txq));
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	return 0;
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_cistatic int bluecard_hci_open(struct hci_dev *hdev)
61962306a36Sopenharmony_ci{
62062306a36Sopenharmony_ci	struct bluecard_info *info = hci_get_drvdata(hdev);
62162306a36Sopenharmony_ci	unsigned int iobase = info->p_dev->resource[0]->start;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state)))
62462306a36Sopenharmony_ci		bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	/* Enable power LED */
62762306a36Sopenharmony_ci	outb(0x08 | 0x20, iobase + 0x30);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	return 0;
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_cistatic int bluecard_hci_close(struct hci_dev *hdev)
63462306a36Sopenharmony_ci{
63562306a36Sopenharmony_ci	struct bluecard_info *info = hci_get_drvdata(hdev);
63662306a36Sopenharmony_ci	unsigned int iobase = info->p_dev->resource[0]->start;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	bluecard_hci_flush(hdev);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	/* Stop LED timer */
64162306a36Sopenharmony_ci	del_timer_sync(&(info->timer));
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	/* Disable power LED */
64462306a36Sopenharmony_ci	outb(0x00, iobase + 0x30);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	return 0;
64762306a36Sopenharmony_ci}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_cistatic int bluecard_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
65162306a36Sopenharmony_ci{
65262306a36Sopenharmony_ci	struct bluecard_info *info = hci_get_drvdata(hdev);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	switch (hci_skb_pkt_type(skb)) {
65562306a36Sopenharmony_ci	case HCI_COMMAND_PKT:
65662306a36Sopenharmony_ci		hdev->stat.cmd_tx++;
65762306a36Sopenharmony_ci		break;
65862306a36Sopenharmony_ci	case HCI_ACLDATA_PKT:
65962306a36Sopenharmony_ci		hdev->stat.acl_tx++;
66062306a36Sopenharmony_ci		break;
66162306a36Sopenharmony_ci	case HCI_SCODATA_PKT:
66262306a36Sopenharmony_ci		hdev->stat.sco_tx++;
66362306a36Sopenharmony_ci		break;
66462306a36Sopenharmony_ci	}
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	/* Prepend skb with frame type */
66762306a36Sopenharmony_ci	memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
66862306a36Sopenharmony_ci	skb_queue_tail(&(info->txq), skb);
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	bluecard_write_wakeup(info);
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	return 0;
67362306a36Sopenharmony_ci}
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci/* ======================== Card services HCI interaction ======================== */
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_cistatic int bluecard_open(struct bluecard_info *info)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	unsigned int iobase = info->p_dev->resource[0]->start;
68362306a36Sopenharmony_ci	struct hci_dev *hdev;
68462306a36Sopenharmony_ci	unsigned char id;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	spin_lock_init(&(info->lock));
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_ci	timer_setup(&info->timer, bluecard_activity_led_timeout, 0);
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci	skb_queue_head_init(&(info->txq));
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	info->rx_state = RECV_WAIT_PACKET_TYPE;
69362306a36Sopenharmony_ci	info->rx_count = 0;
69462306a36Sopenharmony_ci	info->rx_skb = NULL;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	/* Initialize HCI device */
69762306a36Sopenharmony_ci	hdev = hci_alloc_dev();
69862306a36Sopenharmony_ci	if (!hdev) {
69962306a36Sopenharmony_ci		BT_ERR("Can't allocate HCI device");
70062306a36Sopenharmony_ci		return -ENOMEM;
70162306a36Sopenharmony_ci	}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	info->hdev = hdev;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	hdev->bus = HCI_PCCARD;
70662306a36Sopenharmony_ci	hci_set_drvdata(hdev, info);
70762306a36Sopenharmony_ci	SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
70862306a36Sopenharmony_ci
70962306a36Sopenharmony_ci	hdev->open  = bluecard_hci_open;
71062306a36Sopenharmony_ci	hdev->close = bluecard_hci_close;
71162306a36Sopenharmony_ci	hdev->flush = bluecard_hci_flush;
71262306a36Sopenharmony_ci	hdev->send  = bluecard_hci_send_frame;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	id = inb(iobase + 0x30);
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci	if ((id & 0x0f) == 0x02)
71762306a36Sopenharmony_ci		set_bit(CARD_HAS_PCCARD_ID, &(info->hw_state));
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	if (id & 0x10)
72062306a36Sopenharmony_ci		set_bit(CARD_HAS_POWER_LED, &(info->hw_state));
72162306a36Sopenharmony_ci
72262306a36Sopenharmony_ci	if (id & 0x20)
72362306a36Sopenharmony_ci		set_bit(CARD_HAS_ACTIVITY_LED, &(info->hw_state));
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	/* Reset card */
72662306a36Sopenharmony_ci	info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET;
72762306a36Sopenharmony_ci	outb(info->ctrl_reg, iobase + REG_CONTROL);
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_ci	/* Turn FPGA off */
73062306a36Sopenharmony_ci	outb(0x80, iobase + 0x30);
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	/* Wait some time */
73362306a36Sopenharmony_ci	msleep(10);
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	/* Turn FPGA on */
73662306a36Sopenharmony_ci	outb(0x00, iobase + 0x30);
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci	/* Activate card */
73962306a36Sopenharmony_ci	info->ctrl_reg = REG_CONTROL_BT_ON | REG_CONTROL_BT_RES_PU;
74062306a36Sopenharmony_ci	outb(info->ctrl_reg, iobase + REG_CONTROL);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	/* Enable interrupt */
74362306a36Sopenharmony_ci	outb(0xff, iobase + REG_INTERRUPT);
74462306a36Sopenharmony_ci	info->ctrl_reg |= REG_CONTROL_INTERRUPT;
74562306a36Sopenharmony_ci	outb(info->ctrl_reg, iobase + REG_CONTROL);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	if ((id & 0x0f) == 0x03) {
74862306a36Sopenharmony_ci		/* Disable RTS */
74962306a36Sopenharmony_ci		info->ctrl_reg |= REG_CONTROL_RTS;
75062306a36Sopenharmony_ci		outb(info->ctrl_reg, iobase + REG_CONTROL);
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ci		/* Set baud rate */
75362306a36Sopenharmony_ci		info->ctrl_reg |= 0x03;
75462306a36Sopenharmony_ci		outb(info->ctrl_reg, iobase + REG_CONTROL);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci		/* Enable RTS */
75762306a36Sopenharmony_ci		info->ctrl_reg &= ~REG_CONTROL_RTS;
75862306a36Sopenharmony_ci		outb(info->ctrl_reg, iobase + REG_CONTROL);
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci		set_bit(XMIT_BUF_ONE_READY, &(info->tx_state));
76162306a36Sopenharmony_ci		set_bit(XMIT_BUF_TWO_READY, &(info->tx_state));
76262306a36Sopenharmony_ci		set_bit(XMIT_SENDING_READY, &(info->tx_state));
76362306a36Sopenharmony_ci	}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	/* Start the RX buffers */
76662306a36Sopenharmony_ci	outb(REG_COMMAND_RX_BUF_ONE, iobase + REG_COMMAND);
76762306a36Sopenharmony_ci	outb(REG_COMMAND_RX_BUF_TWO, iobase + REG_COMMAND);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	/* Signal that the hardware is ready */
77062306a36Sopenharmony_ci	set_bit(CARD_READY, &(info->hw_state));
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	/* Drop TX queue */
77362306a36Sopenharmony_ci	skb_queue_purge(&(info->txq));
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	/* Control the point at which RTS is enabled */
77662306a36Sopenharmony_ci	outb((0x0f << RTS_LEVEL_SHIFT_BITS) | 1, iobase + REG_RX_CONTROL);
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	/* Timeout before it is safe to send the first HCI packet */
77962306a36Sopenharmony_ci	msleep(1250);
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	/* Register HCI device */
78262306a36Sopenharmony_ci	if (hci_register_dev(hdev) < 0) {
78362306a36Sopenharmony_ci		BT_ERR("Can't register HCI device");
78462306a36Sopenharmony_ci		info->hdev = NULL;
78562306a36Sopenharmony_ci		hci_free_dev(hdev);
78662306a36Sopenharmony_ci		return -ENODEV;
78762306a36Sopenharmony_ci	}
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	return 0;
79062306a36Sopenharmony_ci}
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_cistatic int bluecard_close(struct bluecard_info *info)
79462306a36Sopenharmony_ci{
79562306a36Sopenharmony_ci	unsigned int iobase = info->p_dev->resource[0]->start;
79662306a36Sopenharmony_ci	struct hci_dev *hdev = info->hdev;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	if (!hdev)
79962306a36Sopenharmony_ci		return -ENODEV;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	bluecard_hci_close(hdev);
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	clear_bit(CARD_READY, &(info->hw_state));
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	/* Reset card */
80662306a36Sopenharmony_ci	info->ctrl_reg = REG_CONTROL_BT_RESET | REG_CONTROL_CARD_RESET;
80762306a36Sopenharmony_ci	outb(info->ctrl_reg, iobase + REG_CONTROL);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	/* Turn FPGA off */
81062306a36Sopenharmony_ci	outb(0x80, iobase + 0x30);
81162306a36Sopenharmony_ci
81262306a36Sopenharmony_ci	hci_unregister_dev(hdev);
81362306a36Sopenharmony_ci	hci_free_dev(hdev);
81462306a36Sopenharmony_ci
81562306a36Sopenharmony_ci	return 0;
81662306a36Sopenharmony_ci}
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_cistatic int bluecard_probe(struct pcmcia_device *link)
81962306a36Sopenharmony_ci{
82062306a36Sopenharmony_ci	struct bluecard_info *info;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	/* Create new info device */
82362306a36Sopenharmony_ci	info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
82462306a36Sopenharmony_ci	if (!info)
82562306a36Sopenharmony_ci		return -ENOMEM;
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	info->p_dev = link;
82862306a36Sopenharmony_ci	link->priv = info;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	link->config_flags |= CONF_ENABLE_IRQ;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	return bluecard_config(link);
83362306a36Sopenharmony_ci}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_cistatic void bluecard_detach(struct pcmcia_device *link)
83762306a36Sopenharmony_ci{
83862306a36Sopenharmony_ci	bluecard_release(link);
83962306a36Sopenharmony_ci}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_cistatic int bluecard_config(struct pcmcia_device *link)
84362306a36Sopenharmony_ci{
84462306a36Sopenharmony_ci	struct bluecard_info *info = link->priv;
84562306a36Sopenharmony_ci	int i, n;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_ci	link->config_index = 0x20;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	link->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
85062306a36Sopenharmony_ci	link->resource[0]->end = 64;
85162306a36Sopenharmony_ci	link->io_lines = 6;
85262306a36Sopenharmony_ci
85362306a36Sopenharmony_ci	for (n = 0; n < 0x400; n += 0x40) {
85462306a36Sopenharmony_ci		link->resource[0]->start = n ^ 0x300;
85562306a36Sopenharmony_ci		i = pcmcia_request_io(link);
85662306a36Sopenharmony_ci		if (i == 0)
85762306a36Sopenharmony_ci			break;
85862306a36Sopenharmony_ci	}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	if (i != 0)
86162306a36Sopenharmony_ci		goto failed;
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	i = pcmcia_request_irq(link, bluecard_interrupt);
86462306a36Sopenharmony_ci	if (i != 0)
86562306a36Sopenharmony_ci		goto failed;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	i = pcmcia_enable_device(link);
86862306a36Sopenharmony_ci	if (i != 0)
86962306a36Sopenharmony_ci		goto failed;
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	if (bluecard_open(info) != 0)
87262306a36Sopenharmony_ci		goto failed;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	return 0;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_cifailed:
87762306a36Sopenharmony_ci	bluecard_release(link);
87862306a36Sopenharmony_ci	return -ENODEV;
87962306a36Sopenharmony_ci}
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_cistatic void bluecard_release(struct pcmcia_device *link)
88362306a36Sopenharmony_ci{
88462306a36Sopenharmony_ci	struct bluecard_info *info = link->priv;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci	bluecard_close(info);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	del_timer_sync(&(info->timer));
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	pcmcia_disable_device(link);
89162306a36Sopenharmony_ci}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_cistatic const struct pcmcia_device_id bluecard_ids[] = {
89462306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("BlueCard", "LSE041", 0xbaf16fbf, 0x657cc15e),
89562306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("BTCFCARD", "LSE139", 0xe3987764, 0x2524b59c),
89662306a36Sopenharmony_ci	PCMCIA_DEVICE_PROD_ID12("WSS", "LSE039", 0x0a0736ec, 0x24e6dfab),
89762306a36Sopenharmony_ci	PCMCIA_DEVICE_NULL
89862306a36Sopenharmony_ci};
89962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pcmcia, bluecard_ids);
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_cistatic struct pcmcia_driver bluecard_driver = {
90262306a36Sopenharmony_ci	.owner		= THIS_MODULE,
90362306a36Sopenharmony_ci	.name		= "bluecard_cs",
90462306a36Sopenharmony_ci	.probe		= bluecard_probe,
90562306a36Sopenharmony_ci	.remove		= bluecard_detach,
90662306a36Sopenharmony_ci	.id_table	= bluecard_ids,
90762306a36Sopenharmony_ci};
90862306a36Sopenharmony_cimodule_pcmcia_driver(bluecard_driver);
909