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

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 "sysemu.h"
                     23: #include "net.h"
1.1.1.2   root       24: #include "bt-host.h"
1.1       root       25: 
                     26: #ifndef _WIN32
                     27: # include <errno.h>
                     28: # include <sys/ioctl.h>
                     29: # include <sys/uio.h>
                     30: # ifdef CONFIG_BLUEZ
                     31: #  include <bluetooth/bluetooth.h>
                     32: #  include <bluetooth/hci.h>
                     33: #  include <bluetooth/hci_lib.h>
                     34: # else
                     35: #  include "hw/bt.h"
                     36: #  define HCI_MAX_FRAME_SIZE   1028
                     37: # endif
                     38: 
                     39: struct bt_host_hci_s {
                     40:     struct HCIInfo hci;
                     41:     int fd;
                     42: 
                     43:     uint8_t hdr[HCI_MAX_FRAME_SIZE];
                     44:     int len;
                     45: };
                     46: 
                     47: static void bt_host_send(struct HCIInfo *hci,
                     48:                 int type, const uint8_t *data, int len)
                     49: {
                     50:     struct bt_host_hci_s *s = (struct bt_host_hci_s *) hci;
                     51:     uint8_t pkt = type;
                     52:     struct iovec iv[2];
                     53: 
1.1.1.2   root       54:     iv[0].iov_base = (void *)&pkt;
1.1       root       55:     iv[0].iov_len  = 1;
                     56:     iv[1].iov_base = (void *) data;
                     57:     iv[1].iov_len  = len;
                     58: 
1.1.1.3 ! root       59:     while (writev(s->fd, iv, 2) < 0) {
1.1       root       60:         if (errno != EAGAIN && errno != EINTR) {
                     61:             fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
                     62:                             errno);
                     63:             return;
                     64:         }
1.1.1.3 ! root       65:     }
1.1       root       66: }
                     67: 
                     68: static void bt_host_cmd(struct HCIInfo *hci, const uint8_t *data, int len)
                     69: {
                     70:     bt_host_send(hci, HCI_COMMAND_PKT, data, len);
                     71: }
                     72: 
                     73: static void bt_host_acl(struct HCIInfo *hci, const uint8_t *data, int len)
                     74: {
                     75:     bt_host_send(hci, HCI_ACLDATA_PKT, data, len);
                     76: }
                     77: 
                     78: static void bt_host_sco(struct HCIInfo *hci, const uint8_t *data, int len)
                     79: {
                     80:     bt_host_send(hci, HCI_SCODATA_PKT, data, len);
                     81: }
                     82: 
                     83: static void bt_host_read(void *opaque)
                     84: {
                     85:     struct bt_host_hci_s *s = (struct bt_host_hci_s *) opaque;
                     86:     uint8_t *pkt;
                     87:     int pktlen;
                     88: 
                     89:     /* Seems that we can't read only the header first and then the amount
                     90:      * of data indicated in the header because Linux will discard everything
                     91:      * that's not been read in one go.  */
                     92:     s->len = read(s->fd, s->hdr, sizeof(s->hdr));
                     93: 
                     94:     if (s->len < 0) {
                     95:         fprintf(stderr, "qemu: error %i reading HCI frame\n", errno);
                     96:         return;
                     97:     }
                     98: 
                     99:     pkt = s->hdr;
                    100:     while (s->len --)
                    101:         switch (*pkt ++) {
                    102:         case HCI_EVENT_PKT:
                    103:             if (s->len < 2)
                    104:                 goto bad_pkt;
                    105: 
                    106:             pktlen = MIN(pkt[1] + 2, s->len);
                    107:             s->hci.evt_recv(s->hci.opaque, pkt, pktlen);
                    108:             s->len -= pktlen;
                    109:             pkt += pktlen;
                    110: 
                    111:             /* TODO: if this is an Inquiry Result event, it's also
                    112:              * interpreted by Linux kernel before we received it, possibly
                    113:              * we should clean the kernel Inquiry cache through
                    114:              * ioctl(s->fd, HCI_INQUIRY, ...).  */
                    115:             break;
                    116: 
                    117:         case HCI_ACLDATA_PKT:
                    118:             if (s->len < 4)
                    119:                 goto bad_pkt;
                    120: 
                    121:             pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len);
                    122:             s->hci.acl_recv(s->hci.opaque, pkt, pktlen);
                    123:             s->len -= pktlen;
                    124:             pkt += pktlen;
                    125:             break;
                    126: 
                    127:         case HCI_SCODATA_PKT:
                    128:             if (s->len < 3)
                    129:                 goto bad_pkt;
                    130: 
                    131:             pktlen = MIN(pkt[2] + 3, s->len);
                    132:             s->len -= pktlen;
                    133:             pkt += pktlen;
                    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: 
                    181:     s = qemu_mallocz(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: 
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