diff options
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.patch | 1174 |
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) |