summaryrefslogtreecommitdiff
path: root/packages/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bt950_cs.patch
diff options
context:
space:
mode:
Diffstat (limited to 'packages/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bt950_cs.patch')
-rw-r--r--packages/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bt950_cs.patch1174
1 files changed, 1174 insertions, 0 deletions
diff --git a/packages/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bt950_cs.patch b/packages/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bt950_cs.patch
index e69de29bb2..c29f0d02f2 100644
--- a/packages/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bt950_cs.patch
+++ b/packages/linux/openzaurus-pxa-2.4.18-rmk7-pxa3-embedix20031107/bt950_cs.patch
@@ -0,0 +1,1174 @@
+diff -Nur linux-orig/drivers/bluetooth/bt950_cs.c linux/drivers/bluetooth/bt950_cs.c
+--- linux-orig/drivers/bluetooth/bt950_cs.c 1970-01-01 03:00:00.000000000 +0300
++++ linux/drivers/bluetooth/bt950_cs.c 2004-02-04 09:55:04.000000000 +0300
+@@ -0,0 +1,1133 @@
++/*
++ *
++ * Driver for Bluetooth cards with OXCF950 UART interface
++ *
++ * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org>
++ * Albert Rybalkin <albertr@iral.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation;
++ *
++ * Software distributed under the License is distributed on an "AS
++ * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
++ * implied. See the License for the specific language governing
++ * rights and limitations under the License.
++ *
++ * The initial developer of the original code is David A. Hinds
++ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
++ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
++ *
++ */
++
++#include <linux/config.h>
++
++#ifdef CONFIG_MODVERSIONS
++#ifndef MODVERSIONS
++#define MODVERSIONS
++#endif
++#include <linux/modversions.h>
++#endif
++
++#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/timer.h>
++#include <linux/errno.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/spinlock.h>
++#include <linux/delay.h>
++
++#include <linux/skbuff.h>
++#include <linux/string.h>
++#include <linux/serial.h>
++#include <linux/serial_reg.h>
++#include <asm/system.h>
++#include <asm/bitops.h>
++#include <asm/io.h>
++
++#include <pcmcia/version.h>
++#include <pcmcia/cs_types.h>
++#include <pcmcia/cs.h>
++#include <pcmcia/cistpl.h>
++#include <pcmcia/ciscode.h>
++#include <pcmcia/ds.h>
++#include <pcmcia/cisreg.h>
++
++#include <net/bluetooth/bluetooth.h>
++#include <net/bluetooth/hci_core.h>
++
++/* Default baud rate: 57600, 115200, 230400 or 460800 */
++#define DEFAULT_BAUD_RATE 460800
++
++
++/* ======================== Module parameters ======================== */
++
++
++/* Bit map of interrupts to choose from */
++static u_int irq_mask = 0x86bc;
++static int irq_list[4] = { -1 };
++static long baud_rate = DEFAULT_BAUD_RATE;
++
++MODULE_PARM(irq_mask, "i");
++MODULE_PARM(irq_list, "1-4i");
++MODULE_PARM(baud_rate, "l");
++
++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Albert Rybalkin <albertr@iral.com>");
++MODULE_DESCRIPTION("BlueZ driver for Bluetooth cards with OXCF950 UART interface");
++MODULE_LICENSE("GPL");
++
++
++
++/* ======================== Local structures ======================== */
++
++
++typedef struct bt950_info_t {
++ dev_link_t link;
++ dev_node_t node;
++
++ struct hci_dev hdev;
++
++ spinlock_t lock; /* For serializing operations */
++
++ struct sk_buff_head txq;
++ unsigned long tx_state;
++
++ unsigned long rx_state;
++ unsigned long rx_count;
++ struct sk_buff *rx_skb;
++} bt950_info_t;
++
++
++static void bt950_config(dev_link_t *link);
++static void bt950_release(u_long arg);
++static int bt950_event(event_t event, int priority, event_callback_args_t *args);
++
++static dev_info_t dev_info = "bt950_cs";
++
++static dev_link_t *bt950_attach(void);
++static void bt950_detach(dev_link_t *);
++
++static dev_link_t *dev_list = NULL;
++
++/* Transmit states */
++#define XMIT_SENDING 1
++#define XMIT_WAKEUP 2
++#define XMIT_WAITING 8
++
++/* Receiver states */
++#define RECV_WAIT_PACKET_TYPE 0
++#define RECV_WAIT_EVENT_HEADER 1
++#define RECV_WAIT_ACL_HEADER 2
++#define RECV_WAIT_SCO_HEADER 3
++#define RECV_WAIT_DATA 4
++
++/* Special packet types */
++#define PKT_BAUD_RATE_57600 0x80
++#define PKT_BAUD_RATE_115200 0x81
++#define PKT_BAUD_RATE_230400 0x82
++#define PKT_BAUD_RATE_460800 0x83
++
++/* 950-specific stuff */
++#define MAX_WAIT 0xFFFF
++#define FIFO_SIZE 128
++
++#define TR_TX_INT 0x10 /* TTL: TX interrupt trigger level (0-127) */
++#define TR_RX_INT 0x40 /* RTL: RX interrupt trigger level (1-127) */
++#define TR_CTL_LO 0x08 /* FCL: auto flow control LOWER trigger level (0-127) */
++#define TR_CTL_HI 0x60 /* FCH: auto flow control HIGH trigger level (1-127) */
++
++/* 950-specific registers and values we use. It should
++ * eventually go to include/linux/serial_reg.h */
++#define UART_IER_CTS 0x80 /* enable CTS interrupt */
++#define UART_IER_RTS 0x40 /* enable RTS interrupt */
++#define UART_IER_SLP 0x10 /* enable sleep mode */
++#define UART_LCR_650 0xBF /* enable 650-compatible registers access */
++#define UART_LSR_DE 0x80 /* data error */
++#define UART_LSR_ERR (UART_LSR_OE|UART_LSR_PE|UART_LSR_FE|UART_LSR_BI|UART_LSR_DE)
++#define UART_IIR_RXTOUT 0x0C /* RX timeout interrupt */
++#define UART_IIR_CTSRTS 0x20 /* CTS or RTS change interrupt */
++#define UART_IIR_RTS 0x40
++#define UART_IIR_CTS 0x80
++#define UART_IIR_MASK 0x3E /* interrupt mask */
++#define UART_SRT 0x0D /* soft reset register */
++
++
++
++/* ======================== Interrupt handling ======================== */
++
++
++static int bt950_write(unsigned int iobase, int fifo_size, const unsigned char *buf, int len)
++{
++ int i, actual = 0;
++
++ /* Activate DTR and RTS */
++ outb(UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2, iobase + UART_MCR);
++
++ /* Wait for CTS flow control */
++ for (i = MAX_WAIT; i; i--)
++ if (inb(iobase + UART_MSR) & UART_MSR_CTS)
++ break;
++
++ if (!i) {
++ printk(KERN_WARNING "bt950_cs: Timeout waiting for CTS on write.\n");
++ return 0;
++ }
++
++ /* The TX FIFO should be empty */
++ for (i = MAX_WAIT; i; i--)
++ if (inb(iobase + UART_LSR) & UART_LSR_THRE)
++ break;
++
++ if (!i) {
++ printk(KERN_WARNING "bt950_cs: Timeout waiting for empty TX FIFO on write.\n");
++ return 0;
++ }
++
++ /* Fill FIFO with current frame */
++ while ((fifo_size-- > 0) && (actual < len)) {
++ /* Transmit next byte */
++ outb(buf[actual], iobase + UART_TX);
++ actual++;
++ }
++
++ return actual;
++}
++
++
++static void bt950_write_wakeup(bt950_info_t *info)
++{
++ unsigned char lcr;
++ unsigned int divisor;
++
++ if (!info) {
++ printk(KERN_WARNING "bt950_cs: Call of write_wakeup for unknown device.\n");
++ return;
++ }
++
++ if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) {
++ set_bit(XMIT_WAKEUP, &(info->tx_state));
++ return;
++ }
++
++ do {
++ register unsigned int iobase = info->link.io.BasePort1;
++ register struct sk_buff *skb;
++ register int len;
++
++ clear_bit(XMIT_WAKEUP, &(info->tx_state));
++
++ if (!(info->link.state & DEV_PRESENT))
++ return;
++
++ if (!(skb = skb_dequeue(&(info->txq))))
++ break;
++
++ if (skb->pkt_type & 0x80) {
++ /* Disable RTS */
++ outb((inb(iobase + UART_MCR) & ~UART_MCR_RTS), iobase + UART_MCR);
++ }
++
++ /* Send frame */
++ len = bt950_write(iobase, FIFO_SIZE, skb->data, skb->len);
++
++ set_bit(XMIT_WAKEUP, &(info->tx_state));
++
++ if (skb->pkt_type & 0x80) {
++
++ wait_queue_head_t wait;
++
++ switch (skb->pkt_type) {
++
++ case PKT_BAUD_RATE_460800:
++ divisor = 1;
++ break;
++
++ case PKT_BAUD_RATE_230400:
++ divisor = 2;
++ break;
++
++ case PKT_BAUD_RATE_115200:
++ divisor = 4;
++ break;
++
++ case PKT_BAUD_RATE_57600:
++ /* Fall through... */
++
++ default:
++ divisor = 8;
++ break;
++ }
++
++ /* Wait until the command reaches the baseband */
++ init_waitqueue_head(&wait);
++ interruptible_sleep_on_timeout(&wait, HZ / 10);
++
++ /* Set baud on baseband */
++ /* Enable divisor latch access */
++ lcr = inb(iobase + UART_LCR) & 0x3F;
++ outb(lcr | UART_LCR_DLAB, iobase + UART_LCR);
++
++ /* Setup divisor latch */
++ outb(divisor & 0x00FF, iobase + UART_DLL); /* divisor latch LOW byte */
++ outb((divisor & 0xFF00) >> 8, iobase + UART_DLM); /* divisor latch HI byte */
++
++ /* Disable divisor latch access */
++ outb(lcr, iobase + UART_LCR);
++
++ /* Enable RTS */
++ outb((inb(iobase + UART_MCR) | UART_MCR_RTS), iobase + UART_MCR);
++
++ /* Wait before the next HCI packet can be send */
++ interruptible_sleep_on_timeout(&wait, HZ);
++
++ }
++
++ if (len == skb->len) {
++ kfree_skb(skb);
++ } else {
++ skb_pull(skb, len);
++ skb_queue_head(&(info->txq), skb);
++ }
++
++ info->hdev.stat.byte_tx += len;
++
++ } while (test_bit(XMIT_WAKEUP, &(info->tx_state)));
++
++ clear_bit(XMIT_SENDING, &(info->tx_state));
++}
++
++
++static inline void bt950_receive(bt950_info_t *info)
++{
++ unsigned int iobase;
++ int boguscount = 0;
++
++ if (!info) {
++ printk(KERN_ERR "bt950_cs: Call of receive for unknown device.\n");
++ return;
++ }
++
++ iobase = info->link.io.BasePort1;
++
++ /* Fixme: BUG? */
++ inb(iobase + UART_MCR);
++
++ do {
++ info->hdev.stat.byte_rx++;
++
++ /* Allocate packet */
++ if (info->rx_skb == NULL) {
++ info->rx_state = RECV_WAIT_PACKET_TYPE;
++ info->rx_count = 0;
++ if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
++ printk(KERN_ERR "bt950_cs: Can't allocate mem for new packet.\n");
++ return;
++ }
++ }
++
++ if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
++
++ info->rx_skb->dev = (void *)&(info->hdev);
++ info->rx_skb->pkt_type = inb(iobase + UART_RX);
++
++ switch (info->rx_skb->pkt_type) {
++
++ case HCI_EVENT_PKT:
++ info->rx_state = RECV_WAIT_EVENT_HEADER;
++ info->rx_count = HCI_EVENT_HDR_SIZE;
++ break;
++
++ case HCI_ACLDATA_PKT:
++ info->rx_state = RECV_WAIT_ACL_HEADER;
++ info->rx_count = HCI_ACL_HDR_SIZE;
++ break;
++
++ case HCI_SCODATA_PKT:
++ info->rx_state = RECV_WAIT_SCO_HEADER;
++ info->rx_count = HCI_SCO_HDR_SIZE;
++ break;
++
++ default:
++ /* Unknown packet */
++ printk(KERN_WARNING "bt950_cs: Unknown HCI packet with type 0x%02X received.\n", info->rx_skb->pkt_type);
++ info->hdev.stat.err_rx++;
++
++ kfree_skb(info->rx_skb);
++ info->rx_skb = NULL;
++ break;
++
++ }
++
++ } else {
++
++ *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX);
++ info->rx_count--;
++
++ if (info->rx_count == 0) {
++
++ int dlen;
++ hci_event_hdr *eh;
++ hci_acl_hdr *ah;
++ hci_sco_hdr *sh;
++
++
++ switch (info->rx_state) {
++
++ case RECV_WAIT_EVENT_HEADER:
++ eh = (hci_event_hdr *)(info->rx_skb->data);
++ info->rx_state = RECV_WAIT_DATA;
++ info->rx_count = eh->plen;
++ break;
++
++ case RECV_WAIT_ACL_HEADER:
++ ah = (hci_acl_hdr *)(info->rx_skb->data);
++ dlen = __le16_to_cpu(ah->dlen);
++ info->rx_state = RECV_WAIT_DATA;
++ info->rx_count = dlen;
++ break;
++
++ case RECV_WAIT_SCO_HEADER:
++ sh = (hci_sco_hdr *)(info->rx_skb->data);
++ info->rx_state = RECV_WAIT_DATA;
++ info->rx_count = sh->dlen;
++ break;
++
++ case RECV_WAIT_DATA:
++ hci_recv_frame(info->rx_skb);
++ info->rx_skb = NULL;
++ break;
++
++ }
++
++ }
++
++ }
++
++ /* Make sure we don't stay here too long */
++ if (boguscount++ > 16)
++ break;
++
++ } while (inb(iobase + UART_LSR) & UART_LSR_DR);
++}
++
++
++static void bt950_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
++{
++ bt950_info_t *info = dev_inst;
++ unsigned int iobase;
++ int boguscount = 0;
++ int iir, lsr;
++
++ if (!info) {
++ printk(KERN_ERR "bt950_cs: Call of irq %d for unknown device.\n", irq);
++ return;
++ }
++
++ iobase = info->link.io.BasePort1;
++
++ spin_lock(&(info->lock));
++
++ iir = inb(iobase + UART_IIR);
++
++ while (!(iir & UART_IIR_NO_INT)) {
++
++ switch (iir & UART_IIR_ID) {
++ case UART_IIR_RLSI:
++ /* Clear RLSI interrupt */
++ lsr = inb(iobase + UART_LSR);
++ printk(KERN_NOTICE "bt950_cs: RLSI interrupt, LSR=%#x\n", lsr);
++ /* Fixme: we need to process errors ... */
++ break;
++ case UART_IIR_RDI:
++ /* Receive interrupt */
++ bt950_receive(info);
++ break;
++ case UART_IIR_THRI:
++ /* Transmitter ready for data */
++ bt950_write_wakeup(info);
++ break;
++ default:
++ printk(KERN_NOTICE "bt950_cs: Unhandled IIR=%#x\n", iir);
++ break;
++ }
++
++ /* Make sure we don't stay here too long */
++ if (boguscount++ > 100)
++ break;
++
++ iir = inb(iobase + UART_IIR);
++
++ }
++
++ spin_unlock(&(info->lock));
++}
++
++/* ======================== Device specific HCI commands ======================== */
++
++
++static int bt950_hci_set_baud_rate(struct hci_dev *hdev, int baud)
++{
++ bt950_info_t *info = (bt950_info_t *)(hdev->driver_data);
++ struct sk_buff *skb;
++
++ /* Ericsson baud rate command */
++ unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 };
++
++ if (!(skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
++ printk(KERN_WARNING "bt950_cs: Can't allocate mem for new packet.\n");
++ return -1;
++ }
++
++ switch (baud) {
++ case 460800:
++ cmd[4] = 0x00;
++ skb->pkt_type = PKT_BAUD_RATE_460800;
++ break;
++ case 230400:
++ cmd[4] = 0x01;
++ skb->pkt_type = PKT_BAUD_RATE_230400;
++ break;
++ case 115200:
++ cmd[4] = 0x02;
++ skb->pkt_type = PKT_BAUD_RATE_115200;
++ break;
++ case 57600:
++ /* Fall through... */
++ default:
++ baud = 57600;
++ cmd[4] = 0x03;
++ skb->pkt_type = PKT_BAUD_RATE_57600;
++ break;
++ }
++
++ memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd));
++
++ skb_queue_tail(&(info->txq), skb);
++
++ printk(KERN_WARNING "bt950_cs: setting baud rate: %d.\n", baud);
++
++ bt950_write_wakeup(info);
++
++ return 0;
++}
++
++
++/* ======================== HCI interface ======================== */
++
++
++static int bt950_hci_flush(struct hci_dev *hdev)
++{
++ bt950_info_t *info = (bt950_info_t *)(hdev->driver_data);
++
++ /* Drop TX queue */
++ skb_queue_purge(&(info->txq));
++
++ return 0;
++}
++
++
++static int bt950_hci_open(struct hci_dev *hdev)
++{
++ bt950_hci_set_baud_rate(hdev, baud_rate);
++ set_bit(HCI_RUNNING, &(hdev->flags));
++
++ return 0;
++}
++
++
++static int bt950_hci_close(struct hci_dev *hdev)
++{
++ if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags)))
++ return 0;
++
++ bt950_hci_flush(hdev);
++
++ return 0;
++}
++
++
++static int bt950_hci_send_frame(struct sk_buff *skb)
++{
++ bt950_info_t *info;
++ struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
++
++ if (!hdev) {
++ printk(KERN_ERR "bt950_cs: Frame for unknown HCI device (hdev=NULL).");
++ return -ENODEV;
++ }
++
++ info = (bt950_info_t *)(hdev->driver_data);
++
++ switch (skb->pkt_type) {
++ case HCI_COMMAND_PKT:
++ hdev->stat.cmd_tx++;
++ break;
++ case HCI_ACLDATA_PKT:
++ hdev->stat.acl_tx++;
++ break;
++ case HCI_SCODATA_PKT:
++ hdev->stat.sco_tx++;
++ break;
++ };
++
++ /* Prepend skb with frame type */
++ memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
++ skb_queue_tail(&(info->txq), skb);
++
++ bt950_write_wakeup(info);
++
++ return 0;
++}
++
++
++static void bt950_hci_destruct(struct hci_dev *hdev)
++{
++}
++
++
++static int bt950_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
++{
++ return -ENOIOCTLCMD;
++}
++
++
++
++/* ======================== Card services HCI interaction ======================== */
++
++
++static int bt950_setup_uart(bt950_info_t *info)
++{
++ unsigned long flags;
++ unsigned int iobase = info->link.io.BasePort1;
++ unsigned char lcr, ier = UART_IER_RDI | UART_IER_RLSI | UART_IER_SLP;
++ unsigned int divisor = 8; /* Fixme: divisor == 0x0c ??? */
++ unsigned char id1, id2, id3, rev;
++ register int i;
++
++ spin_lock_irqsave(&(info->lock), flags);
++
++ /* Disable interrupts */
++ outb(0, iobase + UART_IER);
++
++ /* Activate RTS and OUT2 */
++ /* Fixme: is OUT2 used to enable interrupts? */
++ outb(UART_MCR_RTS | UART_MCR_OUT2, iobase + UART_MCR);
++
++ /* Setup the FIFO's */
++ outb(0, iobase + UART_FCR);
++ inb(iobase + UART_RX);
++ outb(UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR |
++ UART_FCR_CLEAR_XMIT | UART_FCR_TRIGGER_14, iobase + UART_FCR);
++
++ /* Disable divisor latch access */
++ lcr = inb(iobase + UART_LCR) & 0x3F; /* mask out UART_LCR_DLAB and UART_LCR_SBC */
++ outb(lcr, iobase + UART_LCR);
++
++ /* Read up to 4 bytes from RX FIFO */
++ for (i = 0; i < 4; i++) {
++ inb(iobase + UART_RX);
++ if (!(inb(iobase + UART_LSR) & UART_LSR_DR))
++ break;
++ }
++
++ /* Wait if CTS/DSR/DCD changing */
++ for (i = 1; i < 0x3E8; i++) {
++ if (!(inb(iobase + UART_MSR) & UART_MSR_ANY_DELTA))
++ break;
++ }
++
++ /* Enable divisor latch access */
++ outb(lcr | UART_LCR_DLAB, iobase + UART_LCR);
++
++ /* Setup divisor latch */
++ outb(divisor & 0x00FF, iobase + UART_DLL); /* divisor latch LOW byte */
++ outb((divisor & 0xFF00) >> 8, iobase + UART_DLM); /* divisor latch HIGH byte */
++
++ /* Disable divisor latch access */
++ outb(lcr, iobase + UART_LCR);
++
++ /* Setup interrupts, enable sleep mode */
++ outb(ier, iobase + UART_IER); /* we don't want to handle TX interrupts */
++
++ /* Skip pending interrupts */
++ for (i = 0; i < 4; i++) {
++ if (inb(iobase + UART_IIR) & UART_IIR_NO_INT)
++ break;
++ }
++
++ /* 8N1 */
++ lcr = UART_LCR_WLEN8;
++ outb(lcr, iobase + UART_LCR);
++
++ /* Setup CTS/RTS flow control and 950 enhanced mode */
++ outb(UART_LCR_650, iobase + UART_LCR);
++ outb(UART_EFR_CTS | UART_EFR_RTS | UART_EFR_ECB,
++ iobase + UART_EFR);
++ outb(lcr, iobase + UART_LCR);
++
++ /* Read core id and revision */
++ outb(UART_ACR, iobase + UART_EMSR);
++ outb(UART_ACR_ICRRD, iobase + UART_LSR); /* enable ICR read access, we don't need to save the old value of ACR */
++
++ outb(UART_ID1, iobase + UART_EMSR);
++ id1 = inb(iobase + UART_LSR);
++
++ outb(UART_ID2, iobase + UART_EMSR);
++ id2 = inb(iobase + UART_LSR);
++
++ outb(UART_ID3, iobase + UART_EMSR);
++ id3 = inb(iobase + UART_LSR);
++
++ outb(UART_REV, iobase + UART_EMSR);
++ rev = inb(iobase + UART_LSR);
++
++ if (id1 != 0x16 || id2 != 0xC9 || id3 != 0x50) {
++ printk(KERN_ERR "bt950_cs: Unknown UART core %02X%02X%02X found.\n", id1, id2, id3);
++ spin_unlock_irqrestore(&(info->lock), flags);
++ return -ENODEV;
++ }
++
++
++ /* Init ICR registers */
++ outb(UART_TTL, iobase + UART_EMSR);
++ outb(TR_TX_INT, iobase + UART_LSR); /* TX interrupt trigger level (0-127) */
++
++ outb(UART_RTL, iobase + UART_EMSR);
++ outb(TR_RX_INT, iobase + UART_LSR); /* RX interrupt trigger level (1-127) */
++
++ outb(UART_FCL, iobase + UART_EMSR);
++ outb(TR_CTL_LO, iobase + UART_LSR); /* auto flow control LOWER trigger level (0-127) */
++
++ outb(UART_FCH, iobase + UART_EMSR);
++ outb(TR_CTL_HI, iobase + UART_LSR); /* auto flow control HIGH trigger level (1-127) */
++
++ outb(UART_ACR, iobase + UART_EMSR);
++ outb(UART_ACR_TLENB, iobase + UART_LSR); /* disable ICR read access, enable trigger levels */
++
++ spin_unlock_irqrestore(&(info->lock), flags);
++
++ return 0;
++}
++
++
++static void bt950_stop_uart(bt950_info_t *info)
++{
++ unsigned long flags;
++ unsigned int iobase = info->link.io.BasePort1;
++
++ spin_lock_irqsave(&(info->lock), flags);
++
++ /* Disable interrupts */
++ outb(0, iobase + UART_IER);
++
++ /* Set RTS and OUT2 low */
++ outb(0, iobase + UART_MCR);
++
++ spin_unlock_irqrestore(&(info->lock), flags);
++}
++
++
++static int bt950_open(bt950_info_t *info)
++{
++ struct hci_dev *hdev;
++ int err;
++
++ spin_lock_init(&(info->lock));
++
++ skb_queue_head_init(&(info->txq));
++
++ info->rx_state = RECV_WAIT_PACKET_TYPE;
++ info->rx_count = 0;
++ info->rx_skb = NULL;
++
++ /* Setup hardware */
++ if ((err = bt950_setup_uart(info)) < 0)
++ return err;
++
++ /* Timeout before it is safe to send the first HCI packet */
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(HZ);
++
++
++ /* Initialize and register HCI device */
++
++ hdev = &(info->hdev);
++
++ hdev->type = HCI_PCCARD;
++ hdev->driver_data = info;
++
++ hdev->open = bt950_hci_open;
++ hdev->close = bt950_hci_close;
++ hdev->flush = bt950_hci_flush;
++ hdev->send = bt950_hci_send_frame;
++ hdev->destruct = bt950_hci_destruct;
++ hdev->ioctl = bt950_hci_ioctl;
++
++ if (hci_register_dev(hdev) < 0) {
++ printk(KERN_ERR "bt950_cs: Can't register HCI device %s.\n", hdev->name);
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++
++static int bt950_close(bt950_info_t *info)
++{
++ struct hci_dev *hdev = &(info->hdev);
++
++ bt950_hci_close(hdev);
++
++ /* Stop hardware */
++ bt950_stop_uart(info);
++
++ if (hci_unregister_dev(hdev) < 0)
++ printk(KERN_ERR "bt950_cs: Can't unregister HCI device %s.\n", hdev->name);
++
++ return 0;
++}
++
++
++
++/* ======================== Card services ======================== */
++
++
++static void cs_error(client_handle_t handle, int func, int ret)
++{
++ error_info_t err = { func, ret };
++
++ CardServices(ReportError, handle, &err);
++}
++
++
++static dev_link_t *bt950_attach(void)
++{
++ bt950_info_t *info;
++ client_reg_t client_reg;
++ dev_link_t *link;
++ int i, ret;
++
++ /* Create new info device */
++ info = kmalloc(sizeof(*info), GFP_KERNEL);
++ if (!info)
++ return NULL;
++ memset(info, 0, sizeof(*info));
++
++ link = &info->link;
++ link->priv = info;
++
++ link->release.function = &bt950_release;
++ link->release.data = (u_long)link;
++ link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
++ link->io.NumPorts1 = 8;
++ link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
++ link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
++
++ if (irq_list[0] == -1)
++ link->irq.IRQInfo2 = irq_mask;
++ else
++ for (i = 0; i < 4; i++)
++ link->irq.IRQInfo2 |= 1 << irq_list[i];
++
++ link->irq.Handler = bt950_interrupt;
++ link->irq.Instance = info;
++
++ link->conf.Attributes = CONF_ENABLE_IRQ;
++ link->conf.IntType = INT_MEMORY_AND_IO;
++ link->conf.Present =
++ PRESENT_OPTION | PRESENT_STATUS | PRESENT_PIN_REPLACE |
++ PRESENT_COPY;
++
++ /* Register with Card Services */
++ link->next = dev_list;
++ dev_list = link;
++ client_reg.dev_info = &dev_info;
++ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
++ client_reg.EventMask =
++ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
++ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
++ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
++ client_reg.event_handler = &bt950_event;
++ client_reg.Version = 0x0210;
++ client_reg.event_callback_args.client_data = link;
++
++ ret = CardServices(RegisterClient, &link->handle, &client_reg);
++ if (ret != CS_SUCCESS) {
++ cs_error(link->handle, RegisterClient, ret);
++ bt950_detach(link);
++ return NULL;
++ }
++
++ return link;
++}
++
++
++static void bt950_detach(dev_link_t *link)
++{
++ bt950_info_t *info = link->priv;
++ dev_link_t **linkp;
++ int ret;
++
++ /* Locate device structure */
++ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
++ if (*linkp == link)
++ break;
++
++ if (*linkp == NULL)
++ return;
++
++ del_timer(&link->release);
++ if (link->state & DEV_CONFIG)
++ bt950_release((u_long) link);
++
++ if (link->handle) {
++ ret = CardServices(DeregisterClient, link->handle);
++ if (ret != CS_SUCCESS)
++ cs_error(link->handle, DeregisterClient, ret);
++ }
++
++ /* Unlink device structure, free bits */
++ *linkp = link->next;
++
++ kfree(info);
++}
++
++
++static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
++{
++ int i;
++
++ i = CardServices(fn, handle, tuple);
++ if (i != CS_SUCCESS)
++ return CS_NO_MORE_ITEMS;
++
++ i = CardServices(GetTupleData, handle, tuple);
++ if (i != CS_SUCCESS)
++ return i;
++
++ return CardServices(ParseTuple, handle, tuple, parse);
++}
++
++
++#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
++#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
++
++static void bt950_config(dev_link_t *link)
++{
++ static ioaddr_t base[4] = { 0x2f8, 0x3e8, 0x2e8, 0x0 };
++ client_handle_t handle = link->handle;
++ bt950_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 = CardServices(GetConfigurationInfo, 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 = CardServices(RequestIO, link->handle, &link->io);
++ if (i == CS_SUCCESS)
++ goto found_port;
++ }
++next_entry:
++ i = next_tuple(handle, &tuple, &parse);
++ }
++ }
++
++ /* Second pass: try to find an entry that isn't picky about
++ its base address, then try to grab any standard serial port
++ address, and finally try to get any free port. */
++ i = first_tuple(handle, &tuple, &parse);
++ while (i != CS_NO_MORE_ITEMS) {
++ if ((i == CS_SUCCESS) && (cf->io.nwin > 0)
++ && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
++ link->conf.ConfigIndex = cf->index;
++ for (j = 0; j < 5; j++) {
++ link->io.BasePort1 = base[j];
++ link->io.IOAddrLines = base[j] ? 16 : 3;
++ i = CardServices(RequestIO, link->handle, &link->io);
++ if (i == CS_SUCCESS)
++ goto found_port;
++ }
++ }
++ i = next_tuple(handle, &tuple, &parse);
++ }
++
++found_port:
++ if (i != CS_SUCCESS) {
++ printk(KERN_ERR "bt950_cs: No usable port range found. Giving up.\n");
++ cs_error(link->handle, RequestIO, i);
++ goto failed;
++ }
++
++ i = CardServices(RequestIRQ, link->handle, &link->irq);
++ if (i != CS_SUCCESS) {
++ cs_error(link->handle, RequestIRQ, i);
++ link->irq.AssignedIRQ = 0;
++ }
++
++ i = CardServices(RequestConfiguration, link->handle, &link->conf);
++ if (i != CS_SUCCESS) {
++ cs_error(link->handle, RequestConfiguration, i);
++ goto failed;
++ }
++
++ MOD_INC_USE_COUNT;
++
++ if (bt950_open(info) != 0)
++ goto failed;
++
++ strcpy(info->node.dev_name, info->hdev.name);
++ link->dev = &info->node;
++ link->state &= ~DEV_CONFIG_PENDING;
++
++ return;
++
++cs_failed:
++ cs_error(link->handle, last_fn, last_ret);
++
++failed:
++ bt950_release((u_long)link);
++ link->state &= ~DEV_CONFIG_PENDING;
++}
++
++
++static void bt950_release(u_long arg)
++{
++ dev_link_t *link = (dev_link_t *) arg;
++ bt950_info_t *info = link->priv;
++
++ if (link->state & DEV_PRESENT)
++ bt950_close(info);
++
++ MOD_DEC_USE_COUNT;
++
++ link->dev = NULL;
++
++ CardServices(ReleaseConfiguration, link->handle);
++ CardServices(ReleaseIO, link->handle, &link->io);
++ CardServices(ReleaseIRQ, link->handle, &link->irq);
++
++ link->state &= ~DEV_CONFIG;
++}
++
++
++static int bt950_event(event_t event, int priority, event_callback_args_t *args)
++{
++ dev_link_t *link = args->client_data;
++ bt950_info_t *info = link->priv;
++
++ switch (event) {
++ case CS_EVENT_CARD_REMOVAL:
++ link->state &= ~DEV_PRESENT;
++ if (link->state & DEV_CONFIG) {
++ bt950_close(info);
++ link->state |= DEV_RELEASE_PENDING;
++ mod_timer(&link->release, jiffies + HZ / 20);
++ }
++ break;
++ case CS_EVENT_CARD_INSERTION:
++ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
++ bt950_config(link);
++ break;
++ case CS_EVENT_PM_SUSPEND:
++ link->state |= DEV_SUSPEND;
++ /* Fall through... */
++ case CS_EVENT_RESET_PHYSICAL:
++ if (link->state & DEV_CONFIG) {
++ bt950_stop_uart(info);
++ CardServices(ReleaseConfiguration, link->handle);
++ }
++ break;
++ case CS_EVENT_PM_RESUME:
++ link->state &= ~DEV_SUSPEND;
++ /* Fall through... */
++ case CS_EVENT_CARD_RESET:
++ if (link->state & DEV_CONFIG) {
++ CardServices(RequestConfiguration, link->handle, &link->conf);
++ bt950_setup_uart(info);
++ }
++ break;
++ }
++
++ return 0;
++}
++
++
++
++/* ======================== Module initialization ======================== */
++
++
++int __init init_bt950_cs(void)
++{
++ servinfo_t serv;
++ int err;
++
++ CardServices(GetCardServicesInfo, &serv);
++ if (serv.Revision != CS_RELEASE_CODE) {
++ printk(KERN_NOTICE "bt950_cs: Card Services release does not match!\n");
++// return -1;
++ }
++
++ err = register_pccard_driver(&dev_info, &bt950_attach, &bt950_detach);
++
++ return err;
++}
++
++
++void __exit exit_bt950_cs(void)
++{
++ unregister_pccard_driver(&dev_info);
++
++ while (dev_list != NULL)
++ bt950_detach(dev_list);
++}
++
++
++module_init(init_bt950_cs);
++module_exit(exit_bt950_cs);
++
++EXPORT_NO_SYMBOLS;
+diff -Nur linux-orig/drivers/bluetooth/Config.in linux/drivers/bluetooth/Config.in
+--- linux-orig/drivers/bluetooth/Config.in 2004-02-16 08:45:33.000000000 +0300
++++ linux/drivers/bluetooth/Config.in 2004-02-16 08:50:36.000000000 +0300
+@@ -21,7 +21,7 @@
+
+ dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ
+
+-dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ
++# dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ
+
+ dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ
+
+@@ -29,5 +29,7 @@
+
+ dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
+
++dep_tristate 'HCI BT950 (BT950 device) driver' CONFIG_BLUEZ_BT950 $CONFIG_BLUEZ
++
+ endmenu
+
+diff -Nur linux-orig/drivers/bluetooth/Makefile linux/drivers/bluetooth/Makefile
+--- linux-orig/drivers/bluetooth/Makefile 2004-02-16 08:45:33.000000000 +0300
++++ linux/drivers/bluetooth/Makefile 2004-02-16 08:50:47.000000000 +0300
+@@ -17,10 +17,12 @@
+ obj-$(CONFIG_BLUEZ_HCIBFUSB) += bfusb.o
+
+ obj-$(CONFIG_BLUEZ_HCIDTL1) += dtl1_cs.o
+-obj-$(CONFIG_BLUEZ_HCIBT3C) += bt3c_cs.o
++# obj-$(CONFIG_BLUEZ_HCIBT3C) += bt3c_cs.o
+ obj-$(CONFIG_BLUEZ_HCIBLUECARD) += bluecard_cs.o
+ obj-$(CONFIG_BLUEZ_HCIBTUART) += btuart_cs.o
+
++obj-$(CONFIG_BLUEZ_BT950) += bt950_cs.o
++
+ include $(TOPDIR)/Rules.make
+
+ hci_uart.o: $(uart-y)