mirror of
https://github.com/torvalds/linux.git
synced 2024-12-31 15:21:46 +00:00
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
This commit is contained in:
commit
f6cd071891
@ -201,7 +201,7 @@ config BT_MRVL
|
||||
The core driver to support Marvell Bluetooth devices.
|
||||
|
||||
This driver is required if you want to support
|
||||
Marvell Bluetooth devices, such as 8688/8787/8797/8897.
|
||||
Marvell Bluetooth devices, such as 8688/8787/8797/8887/8897.
|
||||
|
||||
Say Y here to compile Marvell Bluetooth driver
|
||||
into the kernel or say M to compile it as module.
|
||||
@ -214,7 +214,7 @@ config BT_MRVL_SDIO
|
||||
The driver for Marvell Bluetooth chipsets with SDIO interface.
|
||||
|
||||
This driver is required if you want to use Marvell Bluetooth
|
||||
devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8897
|
||||
devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8887/SD8897
|
||||
chipsets are supported.
|
||||
|
||||
Say Y here to compile support for Marvell BT-over-SDIO driver
|
||||
|
@ -84,7 +84,27 @@ static const struct btmrvl_sdio_card_reg btmrvl_reg_87xx = {
|
||||
.int_read_to_clear = false,
|
||||
};
|
||||
|
||||
static const struct btmrvl_sdio_card_reg btmrvl_reg_88xx = {
|
||||
static const struct btmrvl_sdio_card_reg btmrvl_reg_8887 = {
|
||||
.cfg = 0x00,
|
||||
.host_int_mask = 0x08,
|
||||
.host_intstatus = 0x0C,
|
||||
.card_status = 0x5C,
|
||||
.sq_read_base_addr_a0 = 0x6C,
|
||||
.sq_read_base_addr_a1 = 0x6D,
|
||||
.card_revision = 0xC8,
|
||||
.card_fw_status0 = 0x88,
|
||||
.card_fw_status1 = 0x89,
|
||||
.card_rx_len = 0x8A,
|
||||
.card_rx_unit = 0x8B,
|
||||
.io_port_0 = 0xE4,
|
||||
.io_port_1 = 0xE5,
|
||||
.io_port_2 = 0xE6,
|
||||
.int_read_to_clear = true,
|
||||
.host_int_rsr = 0x04,
|
||||
.card_misc_cfg = 0xD8,
|
||||
};
|
||||
|
||||
static const struct btmrvl_sdio_card_reg btmrvl_reg_8897 = {
|
||||
.cfg = 0x00,
|
||||
.host_int_mask = 0x02,
|
||||
.host_intstatus = 0x03,
|
||||
@ -128,10 +148,18 @@ static const struct btmrvl_sdio_device btmrvl_sdio_sd8797 = {
|
||||
.sd_blksz_fw_dl = 256,
|
||||
};
|
||||
|
||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8887 = {
|
||||
.helper = NULL,
|
||||
.firmware = "mrvl/sd8887_uapsta.bin",
|
||||
.reg = &btmrvl_reg_8887,
|
||||
.support_pscan_win_report = true,
|
||||
.sd_blksz_fw_dl = 256,
|
||||
};
|
||||
|
||||
static const struct btmrvl_sdio_device btmrvl_sdio_sd8897 = {
|
||||
.helper = NULL,
|
||||
.firmware = "mrvl/sd8897_uapsta.bin",
|
||||
.reg = &btmrvl_reg_88xx,
|
||||
.reg = &btmrvl_reg_8897,
|
||||
.support_pscan_win_report = true,
|
||||
.sd_blksz_fw_dl = 256,
|
||||
};
|
||||
@ -149,6 +177,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = {
|
||||
/* Marvell SD8797 Bluetooth device */
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A),
|
||||
.driver_data = (unsigned long) &btmrvl_sdio_sd8797 },
|
||||
/* Marvell SD8887 Bluetooth device */
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x9136),
|
||||
.driver_data = (unsigned long)&btmrvl_sdio_sd8887 },
|
||||
/* Marvell SD8897 Bluetooth device */
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912E),
|
||||
.driver_data = (unsigned long) &btmrvl_sdio_sd8897 },
|
||||
@ -1280,4 +1311,5 @@ MODULE_FIRMWARE("mrvl/sd8688_helper.bin");
|
||||
MODULE_FIRMWARE("mrvl/sd8688.bin");
|
||||
MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
|
||||
MODULE_FIRMWARE("mrvl/sd8797_uapsta.bin");
|
||||
MODULE_FIRMWARE("mrvl/sd8887_uapsta.bin");
|
||||
MODULE_FIRMWARE("mrvl/sd8897_uapsta.bin");
|
||||
|
@ -268,8 +268,6 @@ struct btusb_data {
|
||||
struct usb_interface *intf;
|
||||
struct usb_interface *isoc;
|
||||
|
||||
spinlock_t lock;
|
||||
|
||||
unsigned long flags;
|
||||
|
||||
struct work_struct work;
|
||||
@ -2002,8 +2000,6 @@ static int btusb_probe(struct usb_interface *intf,
|
||||
data->udev = interface_to_usbdev(intf);
|
||||
data->intf = intf;
|
||||
|
||||
spin_lock_init(&data->lock);
|
||||
|
||||
INIT_WORK(&data->work, btusb_work);
|
||||
INIT_WORK(&data->waker, btusb_waker);
|
||||
init_usb_anchor(&data->deferred);
|
||||
|
@ -426,38 +426,33 @@ static void convert_dest_bdaddr(struct in6_addr *ip6_daddr,
|
||||
*addr_type = get_addr_type_from_eui64(addr->b[5]);
|
||||
}
|
||||
|
||||
static int header_create(struct sk_buff *skb, struct net_device *netdev,
|
||||
unsigned short type, const void *_daddr,
|
||||
const void *_saddr, unsigned int len)
|
||||
static int setup_header(struct sk_buff *skb, struct net_device *netdev,
|
||||
bdaddr_t *peer_addr, u8 *peer_addr_type)
|
||||
{
|
||||
struct ipv6hdr *hdr;
|
||||
struct in6_addr ipv6_daddr;
|
||||
struct lowpan_dev *dev;
|
||||
struct lowpan_peer *peer;
|
||||
bdaddr_t addr, *any = BDADDR_ANY;
|
||||
u8 *saddr, *daddr = any->b;
|
||||
u8 addr_type;
|
||||
|
||||
if (type != ETH_P_IPV6)
|
||||
return -EINVAL;
|
||||
|
||||
hdr = ipv6_hdr(skb);
|
||||
u8 *daddr = any->b;
|
||||
int err, status = 0;
|
||||
|
||||
dev = lowpan_dev(netdev);
|
||||
|
||||
if (ipv6_addr_is_multicast(&hdr->daddr)) {
|
||||
memcpy(&lowpan_cb(skb)->addr, &hdr->daddr,
|
||||
sizeof(struct in6_addr));
|
||||
memcpy(&ipv6_daddr, &lowpan_cb(skb)->addr, sizeof(ipv6_daddr));
|
||||
|
||||
if (ipv6_addr_is_multicast(&ipv6_daddr)) {
|
||||
lowpan_cb(skb)->chan = NULL;
|
||||
} else {
|
||||
unsigned long flags;
|
||||
u8 addr_type;
|
||||
|
||||
/* Get destination BT device from skb.
|
||||
* If there is no such peer then discard the packet.
|
||||
*/
|
||||
convert_dest_bdaddr(&hdr->daddr, &addr, &addr_type);
|
||||
convert_dest_bdaddr(&ipv6_daddr, &addr, &addr_type);
|
||||
|
||||
BT_DBG("dest addr %pMR type %d IP %pI6c", &addr,
|
||||
addr_type, &hdr->daddr);
|
||||
addr_type, &ipv6_daddr);
|
||||
|
||||
read_lock_irqsave(&devices_lock, flags);
|
||||
peer = peer_lookup_ba(dev, &addr, addr_type);
|
||||
@ -470,7 +465,7 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev,
|
||||
* the destination address.
|
||||
*/
|
||||
read_lock_irqsave(&devices_lock, flags);
|
||||
peer = peer_lookup_dst(dev, &hdr->daddr, skb);
|
||||
peer = peer_lookup_dst(dev, &ipv6_daddr, skb);
|
||||
read_unlock_irqrestore(&devices_lock, flags);
|
||||
if (!peer) {
|
||||
BT_DBG("no such peer %pMR found", &addr);
|
||||
@ -479,15 +474,37 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev,
|
||||
}
|
||||
|
||||
daddr = peer->eui64_addr;
|
||||
|
||||
memcpy(&lowpan_cb(skb)->addr, &hdr->daddr,
|
||||
sizeof(struct in6_addr));
|
||||
*peer_addr = addr;
|
||||
*peer_addr_type = addr_type;
|
||||
lowpan_cb(skb)->chan = peer->chan;
|
||||
|
||||
status = 1;
|
||||
}
|
||||
|
||||
saddr = dev->netdev->dev_addr;
|
||||
lowpan_header_compress(skb, netdev, ETH_P_IPV6, daddr,
|
||||
dev->netdev->dev_addr, skb->len);
|
||||
|
||||
return lowpan_header_compress(skb, netdev, type, daddr, saddr, len);
|
||||
err = dev_hard_header(skb, netdev, ETH_P_IPV6, NULL, NULL, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int header_create(struct sk_buff *skb, struct net_device *netdev,
|
||||
unsigned short type, const void *_daddr,
|
||||
const void *_saddr, unsigned int len)
|
||||
{
|
||||
struct ipv6hdr *hdr;
|
||||
|
||||
if (type != ETH_P_IPV6)
|
||||
return -EINVAL;
|
||||
|
||||
hdr = ipv6_hdr(skb);
|
||||
|
||||
memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, sizeof(struct in6_addr));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Packet to BT LE device */
|
||||
@ -529,11 +546,12 @@ static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb,
|
||||
return err;
|
||||
}
|
||||
|
||||
static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
|
||||
static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
|
||||
{
|
||||
struct sk_buff *local_skb;
|
||||
struct lowpan_dev *entry, *tmp;
|
||||
unsigned long flags;
|
||||
int err = 0;
|
||||
|
||||
read_lock_irqsave(&devices_lock, flags);
|
||||
|
||||
@ -547,57 +565,77 @@ static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
|
||||
dev = lowpan_dev(entry->netdev);
|
||||
|
||||
list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) {
|
||||
int ret;
|
||||
|
||||
local_skb = skb_clone(skb, GFP_ATOMIC);
|
||||
|
||||
send_pkt(pentry->chan, local_skb, netdev);
|
||||
BT_DBG("xmit %s to %pMR type %d IP %pI6c chan %p",
|
||||
netdev->name,
|
||||
&pentry->chan->dst, pentry->chan->dst_type,
|
||||
&pentry->peer_addr, pentry->chan);
|
||||
ret = send_pkt(pentry->chan, local_skb, netdev);
|
||||
if (ret < 0)
|
||||
err = ret;
|
||||
|
||||
kfree_skb(local_skb);
|
||||
}
|
||||
}
|
||||
|
||||
read_unlock_irqrestore(&devices_lock, flags);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
|
||||
{
|
||||
int err = 0;
|
||||
struct lowpan_dev *dev;
|
||||
struct lowpan_peer *peer;
|
||||
bdaddr_t addr;
|
||||
u8 addr_type;
|
||||
struct sk_buff *tmpskb;
|
||||
|
||||
if (ipv6_addr_is_multicast(&lowpan_cb(skb)->addr)) {
|
||||
/* We need to send the packet to every device
|
||||
* behind this interface.
|
||||
*/
|
||||
send_mcast_pkt(skb, netdev);
|
||||
} else {
|
||||
unsigned long flags;
|
||||
|
||||
convert_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type);
|
||||
dev = lowpan_dev(netdev);
|
||||
|
||||
read_lock_irqsave(&devices_lock, flags);
|
||||
peer = peer_lookup_ba(dev, &addr, addr_type);
|
||||
if (!peer)
|
||||
peer = peer_lookup_dst(dev, &lowpan_cb(skb)->addr, skb);
|
||||
read_unlock_irqrestore(&devices_lock, flags);
|
||||
|
||||
BT_DBG("xmit %s to %pMR type %d IP %pI6c peer %p",
|
||||
netdev->name, &addr, addr_type,
|
||||
&lowpan_cb(skb)->addr, peer);
|
||||
|
||||
if (peer && peer->chan)
|
||||
err = send_pkt(peer->chan, skb, netdev);
|
||||
else
|
||||
err = -ENOENT;
|
||||
/* We must take a copy of the skb before we modify/replace the ipv6
|
||||
* header as the header could be used elsewhere
|
||||
*/
|
||||
tmpskb = skb_unshare(skb, GFP_ATOMIC);
|
||||
if (!tmpskb) {
|
||||
kfree_skb(skb);
|
||||
return NET_XMIT_DROP;
|
||||
}
|
||||
skb = tmpskb;
|
||||
|
||||
/* Return values from setup_header()
|
||||
* <0 - error, packet is dropped
|
||||
* 0 - this is a multicast packet
|
||||
* 1 - this is unicast packet
|
||||
*/
|
||||
err = setup_header(skb, netdev, &addr, &addr_type);
|
||||
if (err < 0) {
|
||||
kfree_skb(skb);
|
||||
return NET_XMIT_DROP;
|
||||
}
|
||||
|
||||
if (err) {
|
||||
if (lowpan_cb(skb)->chan) {
|
||||
BT_DBG("xmit %s to %pMR type %d IP %pI6c chan %p",
|
||||
netdev->name, &addr, addr_type,
|
||||
&lowpan_cb(skb)->addr, lowpan_cb(skb)->chan);
|
||||
err = send_pkt(lowpan_cb(skb)->chan, skb, netdev);
|
||||
} else {
|
||||
err = -ENOENT;
|
||||
}
|
||||
} else {
|
||||
/* We need to send the packet to every device behind this
|
||||
* interface.
|
||||
*/
|
||||
err = send_mcast_pkt(skb, netdev);
|
||||
}
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
if (err)
|
||||
BT_DBG("ERROR: xmit failed (%d)", err);
|
||||
|
||||
return (err < 0) ? NET_XMIT_DROP : err;
|
||||
return err < 0 ? NET_XMIT_DROP : err;
|
||||
}
|
||||
|
||||
static const struct net_device_ops netdev_ops = {
|
||||
@ -617,7 +655,8 @@ static void netdev_setup(struct net_device *dev)
|
||||
dev->needed_tailroom = 0;
|
||||
dev->mtu = IPV6_MIN_MTU;
|
||||
dev->tx_queue_len = 0;
|
||||
dev->flags = IFF_RUNNING | IFF_POINTOPOINT;
|
||||
dev->flags = IFF_RUNNING | IFF_POINTOPOINT |
|
||||
IFF_MULTICAST;
|
||||
dev->watchdog_timeo = 0;
|
||||
|
||||
dev->netdev_ops = &netdev_ops;
|
||||
@ -950,6 +989,9 @@ static void chan_suspend_cb(struct l2cap_chan *chan)
|
||||
|
||||
BT_DBG("chan %p conn %p skb %p", chan, chan->conn, skb);
|
||||
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
lowpan_cb(skb)->status = -EAGAIN;
|
||||
}
|
||||
|
||||
@ -959,6 +1001,9 @@ static void chan_resume_cb(struct l2cap_chan *chan)
|
||||
|
||||
BT_DBG("chan %p conn %p skb %p", chan, chan->conn, skb);
|
||||
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
lowpan_cb(skb)->status = 0;
|
||||
}
|
||||
|
||||
|
@ -6980,8 +6980,6 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
|
||||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid &&
|
||||
chan->chan_type != L2CAP_CHAN_RAW) {
|
||||
err = -EINVAL;
|
||||
@ -7078,17 +7076,20 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
|
||||
goto done;
|
||||
}
|
||||
|
||||
mutex_lock(&conn->chan_lock);
|
||||
l2cap_chan_lock(chan);
|
||||
|
||||
if (cid && __l2cap_get_chan_by_dcid(conn, cid)) {
|
||||
hci_conn_drop(hcon);
|
||||
err = -EBUSY;
|
||||
goto done;
|
||||
goto chan_unlock;
|
||||
}
|
||||
|
||||
/* Update source addr of the socket */
|
||||
bacpy(&chan->src, &hcon->src);
|
||||
chan->src_type = bdaddr_type(hcon, hcon->src_type);
|
||||
|
||||
l2cap_chan_add(conn, chan);
|
||||
__l2cap_chan_add(conn, chan);
|
||||
|
||||
/* l2cap_chan_add takes its own ref so we can drop this one */
|
||||
hci_conn_drop(hcon);
|
||||
@ -7114,8 +7115,10 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
|
||||
|
||||
err = 0;
|
||||
|
||||
done:
|
||||
chan_unlock:
|
||||
l2cap_chan_unlock(chan);
|
||||
mutex_unlock(&conn->chan_lock);
|
||||
done:
|
||||
hci_dev_unlock(hdev);
|
||||
hci_dev_put(hdev);
|
||||
return err;
|
||||
|
Loading…
Reference in New Issue
Block a user