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