Annotation of qemu/bt-host.c, revision 1.1.1.6

1.1       root        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
1.1.1.2   root       17:  * with this program; if not, see <http://www.gnu.org/licenses/>.
1.1       root       18:  */
                     19: 
                     20: #include "qemu-common.h"
                     21: #include "qemu-char.h"
                     22: #include "net.h"
1.1.1.2   root       23: #include "bt-host.h"
1.1       root       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: 
1.1.1.2   root       53:     iv[0].iov_base = (void *)&pkt;
1.1       root       54:     iv[0].iov_len  = 1;
                     55:     iv[1].iov_base = (void *) data;
                     56:     iv[1].iov_len  = len;
                     57: 
1.1.1.3   root       58:     while (writev(s->fd, iv, 2) < 0) {
1.1       root       59:         if (errno != EAGAIN && errno != EINTR) {
                     60:             fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
                     61:                             errno);
                     62:             return;
                     63:         }
1.1.1.3   root       64:     }
1.1       root       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;
1.1.1.6 ! root      133:             break;
1.1       root      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);
1.1.1.2   root      167:         return NULL;
1.1       root      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: 
1.1.1.5   root      181:     s = g_malloc0(sizeof(struct bt_host_hci_s));
1.1       root      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: 
1.1.1.3   root      188:     qemu_set_fd_handler(s->fd, bt_host_read, NULL, s);
1.1       root      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