File:  [Qemu by Fabrice Bellard] / qemu / bt-host.c
Revision 1.1.1.6 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:33:31 2018 UTC (21 months, 3 weeks ago) by root
Branches: qemu, MAIN
CVS tags: qemu1101, HEAD
qemu 1.1.1

    1: /*
    2:  * Wrap a host Bluetooth HCI socket in a struct HCIInfo.
    3:  *
    4:  * Copyright (C) 2008 Andrzej Zaborowski  <balrog@zabor.org>
    5:  *
    6:  * This program is free software; you can redistribute it and/or
    7:  * modify it under the terms of the GNU General Public License as
    8:  * published by the Free Software Foundation; either version 2 or
    9:  * (at your option) version 3 of the License.
   10:  *
   11:  * This program is distributed in the hope that it will be useful,
   12:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14:  * GNU General Public License for more details.
   15:  *
   16:  * You should have received a copy of the GNU General Public License along
   17:  * with this program; if not, see <http://www.gnu.org/licenses/>.
   18:  */
   19: 
   20: #include "qemu-common.h"
   21: #include "qemu-char.h"
   22: #include "net.h"
   23: #include "bt-host.h"
   24: 
   25: #ifndef _WIN32
   26: # include <errno.h>
   27: # include <sys/ioctl.h>
   28: # include <sys/uio.h>
   29: # ifdef CONFIG_BLUEZ
   30: #  include <bluetooth/bluetooth.h>
   31: #  include <bluetooth/hci.h>
   32: #  include <bluetooth/hci_lib.h>
   33: # else
   34: #  include "hw/bt.h"
   35: #  define HCI_MAX_FRAME_SIZE	1028
   36: # endif
   37: 
   38: struct bt_host_hci_s {
   39:     struct HCIInfo hci;
   40:     int fd;
   41: 
   42:     uint8_t hdr[HCI_MAX_FRAME_SIZE];
   43:     int len;
   44: };
   45: 
   46: static void bt_host_send(struct HCIInfo *hci,
   47:                 int type, const uint8_t *data, int len)
   48: {
   49:     struct bt_host_hci_s *s = (struct bt_host_hci_s *) hci;
   50:     uint8_t pkt = type;
   51:     struct iovec iv[2];
   52: 
   53:     iv[0].iov_base = (void *)&pkt;
   54:     iv[0].iov_len  = 1;
   55:     iv[1].iov_base = (void *) data;
   56:     iv[1].iov_len  = len;
   57: 
   58:     while (writev(s->fd, iv, 2) < 0) {
   59:         if (errno != EAGAIN && errno != EINTR) {
   60:             fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
   61:                             errno);
   62:             return;
   63:         }
   64:     }
   65: }
   66: 
   67: static void bt_host_cmd(struct HCIInfo *hci, const uint8_t *data, int len)
   68: {
   69:     bt_host_send(hci, HCI_COMMAND_PKT, data, len);
   70: }
   71: 
   72: static void bt_host_acl(struct HCIInfo *hci, const uint8_t *data, int len)
   73: {
   74:     bt_host_send(hci, HCI_ACLDATA_PKT, data, len);
   75: }
   76: 
   77: static void bt_host_sco(struct HCIInfo *hci, const uint8_t *data, int len)
   78: {
   79:     bt_host_send(hci, HCI_SCODATA_PKT, data, len);
   80: }
   81: 
   82: static void bt_host_read(void *opaque)
   83: {
   84:     struct bt_host_hci_s *s = (struct bt_host_hci_s *) opaque;
   85:     uint8_t *pkt;
   86:     int pktlen;
   87: 
   88:     /* Seems that we can't read only the header first and then the amount
   89:      * of data indicated in the header because Linux will discard everything
   90:      * that's not been read in one go.  */
   91:     s->len = read(s->fd, s->hdr, sizeof(s->hdr));
   92: 
   93:     if (s->len < 0) {
   94:         fprintf(stderr, "qemu: error %i reading HCI frame\n", errno);
   95:         return;
   96:     }
   97: 
   98:     pkt = s->hdr;
   99:     while (s->len --)
  100:         switch (*pkt ++) {
  101:         case HCI_EVENT_PKT:
  102:             if (s->len < 2)
  103:                 goto bad_pkt;
  104: 
  105:             pktlen = MIN(pkt[1] + 2, s->len);
  106:             s->hci.evt_recv(s->hci.opaque, pkt, pktlen);
  107:             s->len -= pktlen;
  108:             pkt += pktlen;
  109: 
  110:             /* TODO: if this is an Inquiry Result event, it's also
  111:              * interpreted by Linux kernel before we received it, possibly
  112:              * we should clean the kernel Inquiry cache through
  113:              * ioctl(s->fd, HCI_INQUIRY, ...).  */
  114:             break;
  115: 
  116:         case HCI_ACLDATA_PKT:
  117:             if (s->len < 4)
  118:                 goto bad_pkt;
  119: 
  120:             pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len);
  121:             s->hci.acl_recv(s->hci.opaque, pkt, pktlen);
  122:             s->len -= pktlen;
  123:             pkt += pktlen;
  124:             break;
  125: 
  126:         case HCI_SCODATA_PKT:
  127:             if (s->len < 3)
  128:                 goto bad_pkt;
  129: 
  130:             pktlen = MIN(pkt[2] + 3, s->len);
  131:             s->len -= pktlen;
  132:             pkt += pktlen;
  133:             break;
  134: 
  135:         default:
  136:         bad_pkt:
  137:             fprintf(stderr, "qemu: bad HCI packet type %02x\n", pkt[-1]);
  138:         }
  139: }
  140: 
  141: static int bt_host_bdaddr_set(struct HCIInfo *hci, const uint8_t *bd_addr)
  142: {
  143:     return -ENOTSUP;
  144: }
  145: 
  146: struct HCIInfo *bt_host_hci(const char *id)
  147: {
  148:     struct bt_host_hci_s *s;
  149:     int fd = -1;
  150: # ifdef CONFIG_BLUEZ
  151:     int dev_id = hci_devid(id);
  152:     struct hci_filter flt;
  153: 
  154:     if (dev_id < 0) {
  155:         fprintf(stderr, "qemu: `%s' not available\n", id);
  156:         return 0;
  157:     }
  158: 
  159:     fd = hci_open_dev(dev_id);
  160: 
  161:     /* XXX: can we ensure nobody else has the device opened?  */
  162: # endif
  163: 
  164:     if (fd < 0) {
  165:         fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
  166:                         id, strerror(errno), errno);
  167:         return NULL;
  168:     }
  169: 
  170: # ifdef CONFIG_BLUEZ
  171:     hci_filter_clear(&flt);
  172:     hci_filter_all_ptypes(&flt);
  173:     hci_filter_all_events(&flt);
  174: 
  175:     if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
  176:         fprintf(stderr, "qemu: Can't set HCI filter on socket (%i)\n", errno);
  177:         return 0;
  178:     }
  179: # endif
  180: 
  181:     s = g_malloc0(sizeof(struct bt_host_hci_s));
  182:     s->fd = fd;
  183:     s->hci.cmd_send = bt_host_cmd;
  184:     s->hci.sco_send = bt_host_sco;
  185:     s->hci.acl_send = bt_host_acl;
  186:     s->hci.bdaddr_set = bt_host_bdaddr_set;
  187: 
  188:     qemu_set_fd_handler(s->fd, bt_host_read, NULL, s);
  189: 
  190:     return &s->hci;
  191: }
  192: #else
  193: struct HCIInfo *bt_host_hci(const char *id)
  194: {
  195:     fprintf(stderr, "qemu: bluetooth passthrough not supported (yet)\n");
  196: 
  197:     return 0;
  198: }
  199: #endif

unix.superglobalmegacorp.com