11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds *
31da177e4SLinus Torvalds * Driver for the 3Com Bluetooth PCMCIA card
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 2001-2002 Marcel Holtmann <marcel@holtmann.org>
61da177e4SLinus Torvalds * Jose Orlando Pereira <jop@di.uminho.pt>
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds *
91da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify
101da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2 as
111da177e4SLinus Torvalds * published by the Free Software Foundation;
121da177e4SLinus Torvalds *
131da177e4SLinus Torvalds * Software distributed under the License is distributed on an "AS
141da177e4SLinus Torvalds * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
151da177e4SLinus Torvalds * implied. See the License for the specific language governing
161da177e4SLinus Torvalds * rights and limitations under the License.
171da177e4SLinus Torvalds *
181da177e4SLinus Torvalds * The initial developer of the original code is David A. Hinds
191da177e4SLinus Torvalds * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
201da177e4SLinus Torvalds * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
211da177e4SLinus Torvalds *
221da177e4SLinus Torvalds */
231da177e4SLinus Torvalds
241da177e4SLinus Torvalds #include <linux/module.h>
251da177e4SLinus Torvalds
261da177e4SLinus Torvalds #include <linux/kernel.h>
271da177e4SLinus Torvalds #include <linux/init.h>
281da177e4SLinus Torvalds #include <linux/slab.h>
291da177e4SLinus Torvalds #include <linux/types.h>
301da177e4SLinus Torvalds #include <linux/delay.h>
311da177e4SLinus Torvalds #include <linux/errno.h>
321da177e4SLinus Torvalds #include <linux/ptrace.h>
331da177e4SLinus Torvalds #include <linux/ioport.h>
341da177e4SLinus Torvalds #include <linux/spinlock.h>
351da177e4SLinus Torvalds #include <linux/moduleparam.h>
361da177e4SLinus Torvalds
371da177e4SLinus Torvalds #include <linux/skbuff.h>
381da177e4SLinus Torvalds #include <linux/string.h>
391da177e4SLinus Torvalds #include <linux/serial.h>
401da177e4SLinus Torvalds #include <linux/serial_reg.h>
411da177e4SLinus Torvalds #include <linux/bitops.h>
421da177e4SLinus Torvalds #include <asm/io.h>
431da177e4SLinus Torvalds
441da177e4SLinus Torvalds #include <linux/device.h>
451da177e4SLinus Torvalds #include <linux/firmware.h>
461da177e4SLinus Torvalds
471da177e4SLinus Torvalds #include <pcmcia/cistpl.h>
481da177e4SLinus Torvalds #include <pcmcia/ciscode.h>
491da177e4SLinus Torvalds #include <pcmcia/ds.h>
501da177e4SLinus Torvalds #include <pcmcia/cisreg.h>
511da177e4SLinus Torvalds
521da177e4SLinus Torvalds #include <net/bluetooth/bluetooth.h>
531da177e4SLinus Torvalds #include <net/bluetooth/hci_core.h>
541da177e4SLinus Torvalds
551da177e4SLinus Torvalds
561da177e4SLinus Torvalds
571da177e4SLinus Torvalds /* ======================== Module parameters ======================== */
581da177e4SLinus Torvalds
591da177e4SLinus Torvalds
6063fbd24eSMarcel Holtmann MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
611da177e4SLinus Torvalds MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card");
621da177e4SLinus Torvalds MODULE_LICENSE("GPL");
632312119aSMarcel Holtmann MODULE_FIRMWARE("BT3CPCC.bin");
641da177e4SLinus Torvalds
651da177e4SLinus Torvalds
661da177e4SLinus Torvalds
671da177e4SLinus Torvalds /* ======================== Local structures ======================== */
681da177e4SLinus Torvalds
691da177e4SLinus Torvalds
703bbaf812SHimangi Saraogi struct bt3c_info {
71fd238232SDominik Brodowski struct pcmcia_device *p_dev;
721da177e4SLinus Torvalds
731da177e4SLinus Torvalds struct hci_dev *hdev;
741da177e4SLinus Torvalds
751da177e4SLinus Torvalds spinlock_t lock; /* For serializing operations */
761da177e4SLinus Torvalds
771da177e4SLinus Torvalds struct sk_buff_head txq;
781da177e4SLinus Torvalds unsigned long tx_state;
791da177e4SLinus Torvalds
801da177e4SLinus Torvalds unsigned long rx_state;
811da177e4SLinus Torvalds unsigned long rx_count;
821da177e4SLinus Torvalds struct sk_buff *rx_skb;
833bbaf812SHimangi Saraogi };
841da177e4SLinus Torvalds
851da177e4SLinus Torvalds
8615b99ac1SDominik Brodowski static int bt3c_config(struct pcmcia_device *link);
87fba395eeSDominik Brodowski static void bt3c_release(struct pcmcia_device *link);
881da177e4SLinus Torvalds
89cc3b4866SDominik Brodowski static void bt3c_detach(struct pcmcia_device *p_dev);
901da177e4SLinus Torvalds
911da177e4SLinus Torvalds
921da177e4SLinus Torvalds /* Transmit states */
931da177e4SLinus Torvalds #define XMIT_SENDING 1
941da177e4SLinus Torvalds #define XMIT_WAKEUP 2
951da177e4SLinus Torvalds #define XMIT_WAITING 8
961da177e4SLinus Torvalds
971da177e4SLinus Torvalds /* Receiver states */
981da177e4SLinus Torvalds #define RECV_WAIT_PACKET_TYPE 0
991da177e4SLinus Torvalds #define RECV_WAIT_EVENT_HEADER 1
1001da177e4SLinus Torvalds #define RECV_WAIT_ACL_HEADER 2
1011da177e4SLinus Torvalds #define RECV_WAIT_SCO_HEADER 3
1021da177e4SLinus Torvalds #define RECV_WAIT_DATA 4
1031da177e4SLinus Torvalds
1041da177e4SLinus Torvalds
1051da177e4SLinus Torvalds
1061da177e4SLinus Torvalds /* ======================== Special I/O functions ======================== */
1071da177e4SLinus Torvalds
1081da177e4SLinus Torvalds
1091da177e4SLinus Torvalds #define DATA_L 0
1101da177e4SLinus Torvalds #define DATA_H 1
1111da177e4SLinus Torvalds #define ADDR_L 2
1121da177e4SLinus Torvalds #define ADDR_H 3
1131da177e4SLinus Torvalds #define CONTROL 4
1141da177e4SLinus Torvalds
1151da177e4SLinus Torvalds
bt3c_address(unsigned int iobase,unsigned short addr)1161da177e4SLinus Torvalds static inline void bt3c_address(unsigned int iobase, unsigned short addr)
1171da177e4SLinus Torvalds {
1181da177e4SLinus Torvalds outb(addr & 0xff, iobase + ADDR_L);
1191da177e4SLinus Torvalds outb((addr >> 8) & 0xff, iobase + ADDR_H);
1201da177e4SLinus Torvalds }
1211da177e4SLinus Torvalds
1221da177e4SLinus Torvalds
bt3c_put(unsigned int iobase,unsigned short value)1231da177e4SLinus Torvalds static inline void bt3c_put(unsigned int iobase, unsigned short value)
1241da177e4SLinus Torvalds {
1251da177e4SLinus Torvalds outb(value & 0xff, iobase + DATA_L);
1261da177e4SLinus Torvalds outb((value >> 8) & 0xff, iobase + DATA_H);
1271da177e4SLinus Torvalds }
1281da177e4SLinus Torvalds
1291da177e4SLinus Torvalds
bt3c_io_write(unsigned int iobase,unsigned short addr,unsigned short value)1301da177e4SLinus Torvalds static inline void bt3c_io_write(unsigned int iobase, unsigned short addr, unsigned short value)
1311da177e4SLinus Torvalds {
1321da177e4SLinus Torvalds bt3c_address(iobase, addr);
1331da177e4SLinus Torvalds bt3c_put(iobase, value);
1341da177e4SLinus Torvalds }
1351da177e4SLinus Torvalds
1361da177e4SLinus Torvalds
bt3c_get(unsigned int iobase)1371da177e4SLinus Torvalds static inline unsigned short bt3c_get(unsigned int iobase)
1381da177e4SLinus Torvalds {
1391da177e4SLinus Torvalds unsigned short value = inb(iobase + DATA_L);
1401da177e4SLinus Torvalds
1411da177e4SLinus Torvalds value |= inb(iobase + DATA_H) << 8;
1421da177e4SLinus Torvalds
1431da177e4SLinus Torvalds return value;
1441da177e4SLinus Torvalds }
1451da177e4SLinus Torvalds
1461da177e4SLinus Torvalds
bt3c_read(unsigned int iobase,unsigned short addr)1471da177e4SLinus Torvalds static inline unsigned short bt3c_read(unsigned int iobase, unsigned short addr)
1481da177e4SLinus Torvalds {
1491da177e4SLinus Torvalds bt3c_address(iobase, addr);
1501da177e4SLinus Torvalds
1511da177e4SLinus Torvalds return bt3c_get(iobase);
1521da177e4SLinus Torvalds }
1531da177e4SLinus Torvalds
1541da177e4SLinus Torvalds
1551da177e4SLinus Torvalds
1561da177e4SLinus Torvalds /* ======================== Interrupt handling ======================== */
1571da177e4SLinus Torvalds
1581da177e4SLinus Torvalds
bt3c_write(unsigned int iobase,int fifo_size,__u8 * buf,int len)1591da177e4SLinus Torvalds static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
1601da177e4SLinus Torvalds {
1611da177e4SLinus Torvalds int actual = 0;
1621da177e4SLinus Torvalds
1631da177e4SLinus Torvalds bt3c_address(iobase, 0x7080);
1641da177e4SLinus Torvalds
1651da177e4SLinus Torvalds /* Fill FIFO with current frame */
1661da177e4SLinus Torvalds while (actual < len) {
1671da177e4SLinus Torvalds /* Transmit next byte */
1681da177e4SLinus Torvalds bt3c_put(iobase, buf[actual]);
1691da177e4SLinus Torvalds actual++;
1701da177e4SLinus Torvalds }
1711da177e4SLinus Torvalds
1721da177e4SLinus Torvalds bt3c_io_write(iobase, 0x7005, actual);
1731da177e4SLinus Torvalds
1741da177e4SLinus Torvalds return actual;
1751da177e4SLinus Torvalds }
1761da177e4SLinus Torvalds
1771da177e4SLinus Torvalds
bt3c_write_wakeup(struct bt3c_info * info)1783bbaf812SHimangi Saraogi static void bt3c_write_wakeup(struct bt3c_info *info)
1791da177e4SLinus Torvalds {
1801da177e4SLinus Torvalds if (!info) {
1811da177e4SLinus Torvalds BT_ERR("Unknown device");
1821da177e4SLinus Torvalds return;
1831da177e4SLinus Torvalds }
1841da177e4SLinus Torvalds
1851da177e4SLinus Torvalds if (test_and_set_bit(XMIT_SENDING, &(info->tx_state)))
1861da177e4SLinus Torvalds return;
1871da177e4SLinus Torvalds
1881da177e4SLinus Torvalds do {
189fc5fef61SGustavo Padovan unsigned int iobase = info->p_dev->resource[0]->start;
1901da177e4SLinus Torvalds register struct sk_buff *skb;
191fc5fef61SGustavo Padovan int len;
1921da177e4SLinus Torvalds
193e2d40963SDominik Brodowski if (!pcmcia_dev_present(info->p_dev))
1941da177e4SLinus Torvalds break;
1951da177e4SLinus Torvalds
196a08b15e6SValentin Ilie skb = skb_dequeue(&(info->txq));
197a08b15e6SValentin Ilie if (!skb) {
1981da177e4SLinus Torvalds clear_bit(XMIT_SENDING, &(info->tx_state));
1991da177e4SLinus Torvalds break;
2001da177e4SLinus Torvalds }
2011da177e4SLinus Torvalds
2021da177e4SLinus Torvalds /* Send frame */
2031da177e4SLinus Torvalds len = bt3c_write(iobase, 256, skb->data, skb->len);
2041da177e4SLinus Torvalds
205aebcecccSPrasanna Karthik if (len != skb->len)
2061da177e4SLinus Torvalds BT_ERR("Very strange");
2071da177e4SLinus Torvalds
2081da177e4SLinus Torvalds kfree_skb(skb);
2091da177e4SLinus Torvalds
2101da177e4SLinus Torvalds info->hdev->stat.byte_tx += len;
2111da177e4SLinus Torvalds
2121da177e4SLinus Torvalds } while (0);
2131da177e4SLinus Torvalds }
2141da177e4SLinus Torvalds
2151da177e4SLinus Torvalds
bt3c_receive(struct bt3c_info * info)2163bbaf812SHimangi Saraogi static void bt3c_receive(struct bt3c_info *info)
2171da177e4SLinus Torvalds {
2181da177e4SLinus Torvalds unsigned int iobase;
2191da177e4SLinus Torvalds int size = 0, avail;
2201da177e4SLinus Torvalds
2211da177e4SLinus Torvalds if (!info) {
2221da177e4SLinus Torvalds BT_ERR("Unknown device");
2231da177e4SLinus Torvalds return;
2241da177e4SLinus Torvalds }
2251da177e4SLinus Torvalds
2269a017a91SDominik Brodowski iobase = info->p_dev->resource[0]->start;
2271da177e4SLinus Torvalds
2281da177e4SLinus Torvalds avail = bt3c_read(iobase, 0x7006);
2291da177e4SLinus Torvalds
2301da177e4SLinus Torvalds bt3c_address(iobase, 0x7480);
2311da177e4SLinus Torvalds while (size < avail) {
2321da177e4SLinus Torvalds size++;
2331da177e4SLinus Torvalds info->hdev->stat.byte_rx++;
2341da177e4SLinus Torvalds
2351da177e4SLinus Torvalds /* Allocate packet */
2367a1dc788SPrasanna Karthik if (!info->rx_skb) {
2371da177e4SLinus Torvalds info->rx_state = RECV_WAIT_PACKET_TYPE;
2381da177e4SLinus Torvalds info->rx_count = 0;
239a08b15e6SValentin Ilie info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
240a08b15e6SValentin Ilie if (!info->rx_skb) {
2411da177e4SLinus Torvalds BT_ERR("Can't allocate mem for new packet");
2421da177e4SLinus Torvalds return;
2431da177e4SLinus Torvalds }
2441da177e4SLinus Torvalds }
2451da177e4SLinus Torvalds
2461da177e4SLinus Torvalds
2471da177e4SLinus Torvalds if (info->rx_state == RECV_WAIT_PACKET_TYPE) {
2481da177e4SLinus Torvalds
249618e8bc2SMarcel Holtmann hci_skb_pkt_type(info->rx_skb) = inb(iobase + DATA_L);
2501da177e4SLinus Torvalds inb(iobase + DATA_H);
2511da177e4SLinus Torvalds
252618e8bc2SMarcel Holtmann switch (hci_skb_pkt_type(info->rx_skb)) {
2531da177e4SLinus Torvalds
2541da177e4SLinus Torvalds case HCI_EVENT_PKT:
2551da177e4SLinus Torvalds info->rx_state = RECV_WAIT_EVENT_HEADER;
2561da177e4SLinus Torvalds info->rx_count = HCI_EVENT_HDR_SIZE;
2571da177e4SLinus Torvalds break;
2581da177e4SLinus Torvalds
2591da177e4SLinus Torvalds case HCI_ACLDATA_PKT:
2601da177e4SLinus Torvalds info->rx_state = RECV_WAIT_ACL_HEADER;
2611da177e4SLinus Torvalds info->rx_count = HCI_ACL_HDR_SIZE;
2621da177e4SLinus Torvalds break;
2631da177e4SLinus Torvalds
2641da177e4SLinus Torvalds case HCI_SCODATA_PKT:
2651da177e4SLinus Torvalds info->rx_state = RECV_WAIT_SCO_HEADER;
2661da177e4SLinus Torvalds info->rx_count = HCI_SCO_HDR_SIZE;
2671da177e4SLinus Torvalds break;
2681da177e4SLinus Torvalds
2691da177e4SLinus Torvalds default:
2701da177e4SLinus Torvalds /* Unknown packet */
271618e8bc2SMarcel Holtmann BT_ERR("Unknown HCI packet with type 0x%02x received",
272618e8bc2SMarcel Holtmann hci_skb_pkt_type(info->rx_skb));
2731da177e4SLinus Torvalds info->hdev->stat.err_rx++;
2741da177e4SLinus Torvalds
2751da177e4SLinus Torvalds kfree_skb(info->rx_skb);
2761da177e4SLinus Torvalds info->rx_skb = NULL;
2771da177e4SLinus Torvalds break;
2781da177e4SLinus Torvalds
2791da177e4SLinus Torvalds }
2801da177e4SLinus Torvalds
2811da177e4SLinus Torvalds } else {
2821da177e4SLinus Torvalds
2831da177e4SLinus Torvalds __u8 x = inb(iobase + DATA_L);
2841da177e4SLinus Torvalds
285634fef61SJohannes Berg skb_put_u8(info->rx_skb, x);
2861da177e4SLinus Torvalds inb(iobase + DATA_H);
2871da177e4SLinus Torvalds info->rx_count--;
2881da177e4SLinus Torvalds
2891da177e4SLinus Torvalds if (info->rx_count == 0) {
2901da177e4SLinus Torvalds
2911da177e4SLinus Torvalds int dlen;
2921da177e4SLinus Torvalds struct hci_event_hdr *eh;
2931da177e4SLinus Torvalds struct hci_acl_hdr *ah;
2941da177e4SLinus Torvalds struct hci_sco_hdr *sh;
2951da177e4SLinus Torvalds
2961da177e4SLinus Torvalds switch (info->rx_state) {
2971da177e4SLinus Torvalds
2981da177e4SLinus Torvalds case RECV_WAIT_EVENT_HEADER:
2992a123b86SArnaldo Carvalho de Melo eh = hci_event_hdr(info->rx_skb);
3001da177e4SLinus Torvalds info->rx_state = RECV_WAIT_DATA;
3011da177e4SLinus Torvalds info->rx_count = eh->plen;
3021da177e4SLinus Torvalds break;
3031da177e4SLinus Torvalds
3041da177e4SLinus Torvalds case RECV_WAIT_ACL_HEADER:
3052a123b86SArnaldo Carvalho de Melo ah = hci_acl_hdr(info->rx_skb);
3061da177e4SLinus Torvalds dlen = __le16_to_cpu(ah->dlen);
3071da177e4SLinus Torvalds info->rx_state = RECV_WAIT_DATA;
3081da177e4SLinus Torvalds info->rx_count = dlen;
3091da177e4SLinus Torvalds break;
3101da177e4SLinus Torvalds
3111da177e4SLinus Torvalds case RECV_WAIT_SCO_HEADER:
3122a123b86SArnaldo Carvalho de Melo sh = hci_sco_hdr(info->rx_skb);
3131da177e4SLinus Torvalds info->rx_state = RECV_WAIT_DATA;
3141da177e4SLinus Torvalds info->rx_count = sh->dlen;
3151da177e4SLinus Torvalds break;
3161da177e4SLinus Torvalds
3171da177e4SLinus Torvalds case RECV_WAIT_DATA:
318e1a26170SMarcel Holtmann hci_recv_frame(info->hdev, info->rx_skb);
3191da177e4SLinus Torvalds info->rx_skb = NULL;
3201da177e4SLinus Torvalds break;
3211da177e4SLinus Torvalds
3221da177e4SLinus Torvalds }
3231da177e4SLinus Torvalds
3241da177e4SLinus Torvalds }
3251da177e4SLinus Torvalds
3261da177e4SLinus Torvalds }
3271da177e4SLinus Torvalds
3281da177e4SLinus Torvalds }
3291da177e4SLinus Torvalds
3301da177e4SLinus Torvalds bt3c_io_write(iobase, 0x7006, 0x0000);
3311da177e4SLinus Torvalds }
3321da177e4SLinus Torvalds
3331da177e4SLinus Torvalds
bt3c_interrupt(int irq,void * dev_inst)3347d12e780SDavid Howells static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
3351da177e4SLinus Torvalds {
3363bbaf812SHimangi Saraogi struct bt3c_info *info = dev_inst;
3371da177e4SLinus Torvalds unsigned int iobase;
3381da177e4SLinus Torvalds int iir;
339aafcf998SAlan Cox irqreturn_t r = IRQ_NONE;
3401da177e4SLinus Torvalds
3417427847dSMike Frysinger if (!info || !info->hdev)
3427427847dSMike Frysinger /* our irq handler is shared */
3437427847dSMike Frysinger return IRQ_NONE;
3441da177e4SLinus Torvalds
3459a017a91SDominik Brodowski iobase = info->p_dev->resource[0]->start;
3461da177e4SLinus Torvalds
3471da177e4SLinus Torvalds spin_lock(&(info->lock));
3481da177e4SLinus Torvalds
3491da177e4SLinus Torvalds iir = inb(iobase + CONTROL);
3501da177e4SLinus Torvalds if (iir & 0x80) {
3511da177e4SLinus Torvalds int stat = bt3c_read(iobase, 0x7001);
3521da177e4SLinus Torvalds
3531da177e4SLinus Torvalds if ((stat & 0xff) == 0x7f) {
3541da177e4SLinus Torvalds BT_ERR("Very strange (stat=0x%04x)", stat);
3551da177e4SLinus Torvalds } else if ((stat & 0xff) != 0xff) {
3561da177e4SLinus Torvalds if (stat & 0x0020) {
35734a55edaSAndre Haupt int status = bt3c_read(iobase, 0x7002) & 0x10;
3582064ee33SMarcel Holtmann bt_dev_info(info->hdev, "Antenna %s",
35934a55edaSAndre Haupt status ? "out" : "in");
3601da177e4SLinus Torvalds }
3611da177e4SLinus Torvalds if (stat & 0x0001)
3621da177e4SLinus Torvalds bt3c_receive(info);
3631da177e4SLinus Torvalds if (stat & 0x0002) {
3641da177e4SLinus Torvalds clear_bit(XMIT_SENDING, &(info->tx_state));
3651da177e4SLinus Torvalds bt3c_write_wakeup(info);
3661da177e4SLinus Torvalds }
3671da177e4SLinus Torvalds
3681da177e4SLinus Torvalds bt3c_io_write(iobase, 0x7001, 0x0000);
3691da177e4SLinus Torvalds
3701da177e4SLinus Torvalds outb(iir, iobase + CONTROL);
3711da177e4SLinus Torvalds }
372aafcf998SAlan Cox r = IRQ_HANDLED;
3731da177e4SLinus Torvalds }
3741da177e4SLinus Torvalds
3751da177e4SLinus Torvalds spin_unlock(&(info->lock));
3761da177e4SLinus Torvalds
377aafcf998SAlan Cox return r;
3781da177e4SLinus Torvalds }
3791da177e4SLinus Torvalds
3801da177e4SLinus Torvalds
3811da177e4SLinus Torvalds
3821da177e4SLinus Torvalds /* ======================== HCI interface ======================== */
3831da177e4SLinus Torvalds
3841da177e4SLinus Torvalds
bt3c_hci_flush(struct hci_dev * hdev)3851da177e4SLinus Torvalds static int bt3c_hci_flush(struct hci_dev *hdev)
3861da177e4SLinus Torvalds {
3873bbaf812SHimangi Saraogi struct bt3c_info *info = hci_get_drvdata(hdev);
3881da177e4SLinus Torvalds
3891da177e4SLinus Torvalds /* Drop TX queue */
3901da177e4SLinus Torvalds skb_queue_purge(&(info->txq));
3911da177e4SLinus Torvalds
3921da177e4SLinus Torvalds return 0;
3931da177e4SLinus Torvalds }
3941da177e4SLinus Torvalds
3951da177e4SLinus Torvalds
bt3c_hci_open(struct hci_dev * hdev)3961da177e4SLinus Torvalds static int bt3c_hci_open(struct hci_dev *hdev)
3971da177e4SLinus Torvalds {
3981da177e4SLinus Torvalds return 0;
3991da177e4SLinus Torvalds }
4001da177e4SLinus Torvalds
4011da177e4SLinus Torvalds
bt3c_hci_close(struct hci_dev * hdev)4021da177e4SLinus Torvalds static int bt3c_hci_close(struct hci_dev *hdev)
4031da177e4SLinus Torvalds {
4041da177e4SLinus Torvalds bt3c_hci_flush(hdev);
4051da177e4SLinus Torvalds
4061da177e4SLinus Torvalds return 0;
4071da177e4SLinus Torvalds }
4081da177e4SLinus Torvalds
4091da177e4SLinus Torvalds
bt3c_hci_send_frame(struct hci_dev * hdev,struct sk_buff * skb)4107bd8f09fSMarcel Holtmann static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
4111da177e4SLinus Torvalds {
4123bbaf812SHimangi Saraogi struct bt3c_info *info = hci_get_drvdata(hdev);
4131da177e4SLinus Torvalds unsigned long flags;
4141da177e4SLinus Torvalds
415618e8bc2SMarcel Holtmann switch (hci_skb_pkt_type(skb)) {
4161da177e4SLinus Torvalds case HCI_COMMAND_PKT:
4171da177e4SLinus Torvalds hdev->stat.cmd_tx++;
4181da177e4SLinus Torvalds break;
4191da177e4SLinus Torvalds case HCI_ACLDATA_PKT:
4201da177e4SLinus Torvalds hdev->stat.acl_tx++;
4211da177e4SLinus Torvalds break;
4221da177e4SLinus Torvalds case HCI_SCODATA_PKT:
4231da177e4SLinus Torvalds hdev->stat.sco_tx++;
4241da177e4SLinus Torvalds break;
425f104f06cSPrasanna Karthik }
4261da177e4SLinus Torvalds
4271da177e4SLinus Torvalds /* Prepend skb with frame type */
428618e8bc2SMarcel Holtmann memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
4291da177e4SLinus Torvalds skb_queue_tail(&(info->txq), skb);
4301da177e4SLinus Torvalds
4311da177e4SLinus Torvalds spin_lock_irqsave(&(info->lock), flags);
4321da177e4SLinus Torvalds
4331da177e4SLinus Torvalds bt3c_write_wakeup(info);
4341da177e4SLinus Torvalds
4351da177e4SLinus Torvalds spin_unlock_irqrestore(&(info->lock), flags);
4361da177e4SLinus Torvalds
4371da177e4SLinus Torvalds return 0;
4381da177e4SLinus Torvalds }
4391da177e4SLinus Torvalds
4401da177e4SLinus Torvalds
4411da177e4SLinus Torvalds
4421da177e4SLinus Torvalds /* ======================== Card services HCI interaction ======================== */
4431da177e4SLinus Torvalds
4441da177e4SLinus Torvalds
bt3c_load_firmware(struct bt3c_info * info,const unsigned char * firmware,int count)4453bbaf812SHimangi Saraogi static int bt3c_load_firmware(struct bt3c_info *info,
4463bbaf812SHimangi Saraogi const unsigned char *firmware,
4478187b4fbSDavid Woodhouse int count)
4481da177e4SLinus Torvalds {
4491da177e4SLinus Torvalds char *ptr = (char *) firmware;
4501da177e4SLinus Torvalds char b[9];
451*38561350SDing Xiang unsigned int iobase, tmp, tn;
45210bd9731SPrasanna Karthik unsigned long size, addr, fcs;
4531da177e4SLinus Torvalds int i, err = 0;
4541da177e4SLinus Torvalds
4559a017a91SDominik Brodowski iobase = info->p_dev->resource[0]->start;
4561da177e4SLinus Torvalds
4571da177e4SLinus Torvalds /* Reset */
4581da177e4SLinus Torvalds bt3c_io_write(iobase, 0x8040, 0x0404);
4591da177e4SLinus Torvalds bt3c_io_write(iobase, 0x8040, 0x0400);
4601da177e4SLinus Torvalds
4611da177e4SLinus Torvalds udelay(1);
4621da177e4SLinus Torvalds
4631da177e4SLinus Torvalds bt3c_io_write(iobase, 0x8040, 0x0404);
4641da177e4SLinus Torvalds
4651da177e4SLinus Torvalds udelay(17);
4661da177e4SLinus Torvalds
4671da177e4SLinus Torvalds /* Load */
4681da177e4SLinus Torvalds while (count) {
4691da177e4SLinus Torvalds if (ptr[0] != 'S') {
4701da177e4SLinus Torvalds BT_ERR("Bad address in firmware");
4711da177e4SLinus Torvalds err = -EFAULT;
4721da177e4SLinus Torvalds goto error;
4731da177e4SLinus Torvalds }
4741da177e4SLinus Torvalds
4751da177e4SLinus Torvalds memset(b, 0, sizeof(b));
4761da177e4SLinus Torvalds memcpy(b, ptr + 2, 2);
47710bd9731SPrasanna Karthik if (kstrtoul(b, 16, &size) < 0)
47810bd9731SPrasanna Karthik return -EINVAL;
4791da177e4SLinus Torvalds
4801da177e4SLinus Torvalds memset(b, 0, sizeof(b));
4811da177e4SLinus Torvalds memcpy(b, ptr + 4, 8);
48210bd9731SPrasanna Karthik if (kstrtoul(b, 16, &addr) < 0)
48310bd9731SPrasanna Karthik return -EINVAL;
4841da177e4SLinus Torvalds
4851da177e4SLinus Torvalds memset(b, 0, sizeof(b));
4861da177e4SLinus Torvalds memcpy(b, ptr + (size * 2) + 2, 2);
48710bd9731SPrasanna Karthik if (kstrtoul(b, 16, &fcs) < 0)
48810bd9731SPrasanna Karthik return -EINVAL;
4891da177e4SLinus Torvalds
4901da177e4SLinus Torvalds memset(b, 0, sizeof(b));
4911da177e4SLinus Torvalds for (tmp = 0, i = 0; i < size; i++) {
4921da177e4SLinus Torvalds memcpy(b, ptr + (i * 2) + 2, 2);
493*38561350SDing Xiang if (kstrtouint(b, 16, &tn))
494*38561350SDing Xiang return -EINVAL;
495*38561350SDing Xiang tmp += tn;
4961da177e4SLinus Torvalds }
4971da177e4SLinus Torvalds
4981da177e4SLinus Torvalds if (((tmp + fcs) & 0xff) != 0xff) {
4991da177e4SLinus Torvalds BT_ERR("Checksum error in firmware");
5001da177e4SLinus Torvalds err = -EILSEQ;
5011da177e4SLinus Torvalds goto error;
5021da177e4SLinus Torvalds }
5031da177e4SLinus Torvalds
5041da177e4SLinus Torvalds if (ptr[1] == '3') {
5051da177e4SLinus Torvalds bt3c_address(iobase, addr);
5061da177e4SLinus Torvalds
5071da177e4SLinus Torvalds memset(b, 0, sizeof(b));
5081da177e4SLinus Torvalds for (i = 0; i < (size - 4) / 2; i++) {
5091da177e4SLinus Torvalds memcpy(b, ptr + (i * 4) + 12, 4);
510*38561350SDing Xiang if (kstrtouint(b, 16, &tmp))
511*38561350SDing Xiang return -EINVAL;
5121da177e4SLinus Torvalds bt3c_put(iobase, tmp);
5131da177e4SLinus Torvalds }
5141da177e4SLinus Torvalds }
5151da177e4SLinus Torvalds
5161da177e4SLinus Torvalds ptr += (size * 2) + 6;
5171da177e4SLinus Torvalds count -= (size * 2) + 6;
5181da177e4SLinus Torvalds }
5191da177e4SLinus Torvalds
5201da177e4SLinus Torvalds udelay(17);
5211da177e4SLinus Torvalds
5221da177e4SLinus Torvalds /* Boot */
5231da177e4SLinus Torvalds bt3c_address(iobase, 0x3000);
5241da177e4SLinus Torvalds outb(inb(iobase + CONTROL) | 0x40, iobase + CONTROL);
5251da177e4SLinus Torvalds
5261da177e4SLinus Torvalds error:
5271da177e4SLinus Torvalds udelay(17);
5281da177e4SLinus Torvalds
5291da177e4SLinus Torvalds /* Clear */
5301da177e4SLinus Torvalds bt3c_io_write(iobase, 0x7006, 0x0000);
5311da177e4SLinus Torvalds bt3c_io_write(iobase, 0x7005, 0x0000);
5321da177e4SLinus Torvalds bt3c_io_write(iobase, 0x7001, 0x0000);
5331da177e4SLinus Torvalds
5341da177e4SLinus Torvalds return err;
5351da177e4SLinus Torvalds }
5361da177e4SLinus Torvalds
5371da177e4SLinus Torvalds
bt3c_open(struct bt3c_info * info)5383bbaf812SHimangi Saraogi static int bt3c_open(struct bt3c_info *info)
5391da177e4SLinus Torvalds {
5401da177e4SLinus Torvalds const struct firmware *firmware;
5411da177e4SLinus Torvalds struct hci_dev *hdev;
5421da177e4SLinus Torvalds int err;
5431da177e4SLinus Torvalds
5441da177e4SLinus Torvalds spin_lock_init(&(info->lock));
5451da177e4SLinus Torvalds
5461da177e4SLinus Torvalds skb_queue_head_init(&(info->txq));
5471da177e4SLinus Torvalds
5481da177e4SLinus Torvalds info->rx_state = RECV_WAIT_PACKET_TYPE;
5491da177e4SLinus Torvalds info->rx_count = 0;
5501da177e4SLinus Torvalds info->rx_skb = NULL;
5511da177e4SLinus Torvalds
5521da177e4SLinus Torvalds /* Initialize HCI device */
5531da177e4SLinus Torvalds hdev = hci_alloc_dev();
5541da177e4SLinus Torvalds if (!hdev) {
5551da177e4SLinus Torvalds BT_ERR("Can't allocate HCI device");
5561da177e4SLinus Torvalds return -ENOMEM;
5571da177e4SLinus Torvalds }
5581da177e4SLinus Torvalds
5591da177e4SLinus Torvalds info->hdev = hdev;
5601da177e4SLinus Torvalds
561c13854ceSMarcel Holtmann hdev->bus = HCI_PCCARD;
562155961e8SDavid Herrmann hci_set_drvdata(hdev, info);
56327d35284SMarcel Holtmann SET_HCIDEV_DEV(hdev, &info->p_dev->dev);
5641da177e4SLinus Torvalds
5651da177e4SLinus Torvalds hdev->open = bt3c_hci_open;
5661da177e4SLinus Torvalds hdev->close = bt3c_hci_close;
5671da177e4SLinus Torvalds hdev->flush = bt3c_hci_flush;
5681da177e4SLinus Torvalds hdev->send = bt3c_hci_send_frame;
5691da177e4SLinus Torvalds
5701da177e4SLinus Torvalds /* Load firmware */
571fd238232SDominik Brodowski err = request_firmware(&firmware, "BT3CPCC.bin", &info->p_dev->dev);
5721da177e4SLinus Torvalds if (err < 0) {
5731da177e4SLinus Torvalds BT_ERR("Firmware request failed");
5741da177e4SLinus Torvalds goto error;
5751da177e4SLinus Torvalds }
5761da177e4SLinus Torvalds
5771da177e4SLinus Torvalds err = bt3c_load_firmware(info, firmware->data, firmware->size);
5781da177e4SLinus Torvalds
5791da177e4SLinus Torvalds release_firmware(firmware);
5801da177e4SLinus Torvalds
5811da177e4SLinus Torvalds if (err < 0) {
5821da177e4SLinus Torvalds BT_ERR("Firmware loading failed");
5831da177e4SLinus Torvalds goto error;
5841da177e4SLinus Torvalds }
5851da177e4SLinus Torvalds
5861da177e4SLinus Torvalds /* Timeout before it is safe to send the first HCI packet */
5871da177e4SLinus Torvalds msleep(1000);
5881da177e4SLinus Torvalds
5891da177e4SLinus Torvalds /* Register HCI device */
5901da177e4SLinus Torvalds err = hci_register_dev(hdev);
5911da177e4SLinus Torvalds if (err < 0) {
5921da177e4SLinus Torvalds BT_ERR("Can't register HCI device");
5931da177e4SLinus Torvalds goto error;
5941da177e4SLinus Torvalds }
5951da177e4SLinus Torvalds
5961da177e4SLinus Torvalds return 0;
5971da177e4SLinus Torvalds
5981da177e4SLinus Torvalds error:
5991da177e4SLinus Torvalds info->hdev = NULL;
6001da177e4SLinus Torvalds hci_free_dev(hdev);
6011da177e4SLinus Torvalds return err;
6021da177e4SLinus Torvalds }
6031da177e4SLinus Torvalds
6041da177e4SLinus Torvalds
bt3c_close(struct bt3c_info * info)6053bbaf812SHimangi Saraogi static int bt3c_close(struct bt3c_info *info)
6061da177e4SLinus Torvalds {
6071da177e4SLinus Torvalds struct hci_dev *hdev = info->hdev;
6081da177e4SLinus Torvalds
6091da177e4SLinus Torvalds if (!hdev)
6101da177e4SLinus Torvalds return -ENODEV;
6111da177e4SLinus Torvalds
6121da177e4SLinus Torvalds bt3c_hci_close(hdev);
6131da177e4SLinus Torvalds
61413ea4015SDavid Herrmann hci_unregister_dev(hdev);
6151da177e4SLinus Torvalds hci_free_dev(hdev);
6161da177e4SLinus Torvalds
6171da177e4SLinus Torvalds return 0;
6181da177e4SLinus Torvalds }
6191da177e4SLinus Torvalds
bt3c_probe(struct pcmcia_device * link)62015b99ac1SDominik Brodowski static int bt3c_probe(struct pcmcia_device *link)
6211da177e4SLinus Torvalds {
6223bbaf812SHimangi Saraogi struct bt3c_info *info;
6231da177e4SLinus Torvalds
6241da177e4SLinus Torvalds /* Create new info device */
6254f61cb18SSachin Kamat info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
6261da177e4SLinus Torvalds if (!info)
627f8cfa618SDominik Brodowski return -ENOMEM;
6281da177e4SLinus Torvalds
629fba395eeSDominik Brodowski info->p_dev = link;
6301da177e4SLinus Torvalds link->priv = info;
6311da177e4SLinus Torvalds
63200990e7cSDominik Brodowski link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_VPP |
63300990e7cSDominik Brodowski CONF_AUTO_SET_IO;
6341da177e4SLinus Torvalds
63515b99ac1SDominik Brodowski return bt3c_config(link);
6361da177e4SLinus Torvalds }
6371da177e4SLinus Torvalds
6381da177e4SLinus Torvalds
bt3c_detach(struct pcmcia_device * link)639fba395eeSDominik Brodowski static void bt3c_detach(struct pcmcia_device *link)
6401da177e4SLinus Torvalds {
6411da177e4SLinus Torvalds bt3c_release(link);
6421da177e4SLinus Torvalds }
6431da177e4SLinus Torvalds
bt3c_check_config(struct pcmcia_device * p_dev,void * priv_data)64400990e7cSDominik Brodowski static int bt3c_check_config(struct pcmcia_device *p_dev, void *priv_data)
6451da177e4SLinus Torvalds {
64600990e7cSDominik Brodowski int *try = priv_data;
64790abdc3bSDominik Brodowski
648510df251SAndrei Emeltchenko if (!try)
64900990e7cSDominik Brodowski p_dev->io_lines = 16;
65000990e7cSDominik Brodowski
65100990e7cSDominik Brodowski if ((p_dev->resource[0]->end != 8) || (p_dev->resource[0]->start == 0))
65200990e7cSDominik Brodowski return -EINVAL;
65300990e7cSDominik Brodowski
65400990e7cSDominik Brodowski p_dev->resource[0]->end = 8;
65500990e7cSDominik Brodowski p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
65600990e7cSDominik Brodowski p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
65700990e7cSDominik Brodowski
65800990e7cSDominik Brodowski return pcmcia_request_io(p_dev);
6591da177e4SLinus Torvalds }
6601da177e4SLinus Torvalds
bt3c_check_config_notpicky(struct pcmcia_device * p_dev,void * priv_data)661ed58872aSDominik Brodowski static int bt3c_check_config_notpicky(struct pcmcia_device *p_dev,
662ed58872aSDominik Brodowski void *priv_data)
6631da177e4SLinus Torvalds {
664ed58872aSDominik Brodowski static unsigned int base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
665ed58872aSDominik Brodowski int j;
6661da177e4SLinus Torvalds
66700990e7cSDominik Brodowski if (p_dev->io_lines > 3)
66800990e7cSDominik Brodowski return -ENODEV;
66900990e7cSDominik Brodowski
67000990e7cSDominik Brodowski p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
67100990e7cSDominik Brodowski p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_8;
67200990e7cSDominik Brodowski p_dev->resource[0]->end = 8;
67300990e7cSDominik Brodowski
674ed58872aSDominik Brodowski for (j = 0; j < 5; j++) {
67590abdc3bSDominik Brodowski p_dev->resource[0]->start = base[j];
67690abdc3bSDominik Brodowski p_dev->io_lines = base[j] ? 16 : 3;
67790abdc3bSDominik Brodowski if (!pcmcia_request_io(p_dev))
678ed58872aSDominik Brodowski return 0;
679ed58872aSDominik Brodowski }
680ed58872aSDominik Brodowski return -ENODEV;
6811da177e4SLinus Torvalds }
6821da177e4SLinus Torvalds
bt3c_config(struct pcmcia_device * link)68315b99ac1SDominik Brodowski static int bt3c_config(struct pcmcia_device *link)
6841da177e4SLinus Torvalds {
6853bbaf812SHimangi Saraogi struct bt3c_info *info = link->priv;
686ed58872aSDominik Brodowski int i;
687ed58872aSDominik Brodowski unsigned long try;
6881da177e4SLinus Torvalds
689ed58872aSDominik Brodowski /* First pass: look for a config entry that looks normal.
690d98422cbSDerek Robson * Two tries: without IO aliases, then with aliases
691d98422cbSDerek Robson */
692ed58872aSDominik Brodowski for (try = 0; try < 2; try++)
693ed58872aSDominik Brodowski if (!pcmcia_loop_config(link, bt3c_check_config, (void *) try))
6941da177e4SLinus Torvalds goto found_port;
6951da177e4SLinus Torvalds
6961da177e4SLinus Torvalds /* Second pass: try to find an entry that isn't picky about
697d98422cbSDerek Robson * its base address, then try to grab any standard serial port
698d98422cbSDerek Robson * address, and finally try to get any free port.
699d98422cbSDerek Robson */
700ed58872aSDominik Brodowski if (!pcmcia_loop_config(link, bt3c_check_config_notpicky, NULL))
7011da177e4SLinus Torvalds goto found_port;
702ed58872aSDominik Brodowski
703ed58872aSDominik Brodowski BT_ERR("No usable port range found");
704ed58872aSDominik Brodowski goto failed;
7051da177e4SLinus Torvalds
7061da177e4SLinus Torvalds found_port:
707eb14120fSDominik Brodowski i = pcmcia_request_irq(link, &bt3c_interrupt);
7089ac3e58cSDominik Brodowski if (i != 0)
709eb14120fSDominik Brodowski goto failed;
7101da177e4SLinus Torvalds
7111ac71e5aSDominik Brodowski i = pcmcia_enable_device(link);
7129ac3e58cSDominik Brodowski if (i != 0)
7131da177e4SLinus Torvalds goto failed;
7141da177e4SLinus Torvalds
7151da177e4SLinus Torvalds if (bt3c_open(info) != 0)
7161da177e4SLinus Torvalds goto failed;
7171da177e4SLinus Torvalds
71815b99ac1SDominik Brodowski return 0;
7191da177e4SLinus Torvalds
7201da177e4SLinus Torvalds failed:
7211da177e4SLinus Torvalds bt3c_release(link);
72215b99ac1SDominik Brodowski return -ENODEV;
7231da177e4SLinus Torvalds }
7241da177e4SLinus Torvalds
7251da177e4SLinus Torvalds
bt3c_release(struct pcmcia_device * link)726fba395eeSDominik Brodowski static void bt3c_release(struct pcmcia_device *link)
7271da177e4SLinus Torvalds {
7283bbaf812SHimangi Saraogi struct bt3c_info *info = link->priv;
7291da177e4SLinus Torvalds
7301da177e4SLinus Torvalds bt3c_close(info);
7311da177e4SLinus Torvalds
732fba395eeSDominik Brodowski pcmcia_disable_device(link);
7331da177e4SLinus Torvalds }
7341da177e4SLinus Torvalds
7351da177e4SLinus Torvalds
73625f8f54fSJoe Perches static const struct pcmcia_device_id bt3c_ids[] = {
737a01c3ed4SDominik Brodowski PCMCIA_DEVICE_PROD_ID13("3COM", "Bluetooth PC Card", 0xefce0a31, 0xd4ce9b02),
738a01c3ed4SDominik Brodowski PCMCIA_DEVICE_NULL
739a01c3ed4SDominik Brodowski };
740a01c3ed4SDominik Brodowski MODULE_DEVICE_TABLE(pcmcia, bt3c_ids);
741a01c3ed4SDominik Brodowski
7421da177e4SLinus Torvalds static struct pcmcia_driver bt3c_driver = {
7431da177e4SLinus Torvalds .owner = THIS_MODULE,
7441da177e4SLinus Torvalds .name = "bt3c_cs",
74515b99ac1SDominik Brodowski .probe = bt3c_probe,
746cc3b4866SDominik Brodowski .remove = bt3c_detach,
747a01c3ed4SDominik Brodowski .id_table = bt3c_ids,
7481da177e4SLinus Torvalds };
749e0c005f4SH Hartley Sweeten module_pcmcia_driver(bt3c_driver);
750