File:  [Qemu by Fabrice Bellard] / qemu / bt-vhci.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:56:25 2018 UTC (3 years, 1 month ago) by root
Branches: qemu, MAIN
CVS tags: qemu1000, qemu0151, HEAD
qemu 0.15.1

    1: /*
    2:  * Support for host VHCIs inside qemu scatternets.
    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 "hw/bt.h"
   24: 
   25: #define VHCI_DEV	"/dev/vhci"
   26: #define VHCI_UDEV	"/dev/hci_vhci"
   27: 
   28: struct bt_vhci_s {
   29:     int fd;
   30:     struct HCIInfo *info;
   31: 
   32:     uint8_t hdr[4096];
   33:     int len;
   34: };
   35: 
   36: static void vhci_read(void *opaque)
   37: {
   38:     struct bt_vhci_s *s = (struct bt_vhci_s *) opaque;
   39:     uint8_t *pkt;
   40:     int pktlen;
   41: 
   42:     /* Seems that we can't read only the header first and then the amount
   43:      * of data indicated in the header because Linux will discard everything
   44:      * that's not been read in one go.  */
   45:     s->len = read(s->fd, s->hdr, sizeof(s->hdr));
   46: 
   47:     if (s->len < 0) {
   48:         fprintf(stderr, "qemu: error %i reading the PDU\n", errno);
   49:         return;
   50:     }
   51: 
   52:     pkt = s->hdr;
   53:     while (s->len --)
   54:         switch (*pkt ++) {
   55:         case HCI_COMMAND_PKT:
   56:             if (s->len < 3)
   57:                 goto bad_pkt;
   58: 
   59:             pktlen = MIN(pkt[2] + 3, s->len);
   60:             s->info->cmd_send(s->info, pkt, pktlen);
   61:             s->len -= pktlen;
   62:             pkt += pktlen;
   63:             break;
   64: 
   65:         case HCI_ACLDATA_PKT:
   66:             if (s->len < 4)
   67:                 goto bad_pkt;
   68: 
   69:             pktlen = MIN(((pkt[3] << 8) | pkt[2]) + 4, s->len);
   70:             s->info->acl_send(s->info, pkt, pktlen);
   71:             s->len -= pktlen;
   72:             pkt += pktlen;
   73:             break;
   74: 
   75:         case HCI_SCODATA_PKT:
   76:             if (s->len < 3)
   77:                 goto bad_pkt;
   78: 
   79:             pktlen = MIN(pkt[2] + 3, s->len);
   80:             s->info->sco_send(s->info, pkt, pktlen);
   81:             s->len -= pktlen;
   82:             pkt += pktlen;
   83:             break;
   84: 
   85:         default:
   86:         bad_pkt:
   87:             fprintf(stderr, "qemu: bad HCI packet type %02x\n", pkt[-1]);
   88:         }
   89: }
   90: 
   91: static void vhci_host_send(void *opaque,
   92:                 int type, const uint8_t *data, int len)
   93: {
   94:     struct bt_vhci_s *s = (struct bt_vhci_s *) opaque;
   95: #if 0
   96:     uint8_t pkt = type;
   97:     struct iovec iv[2];
   98: 
   99:     iv[0].iov_base = &pkt;
  100:     iv[0].iov_len  = 1;
  101:     iv[1].iov_base = (void *) data;
  102:     iv[1].iov_len  = len;
  103: 
  104:     while (writev(s->fd, iv, 2) < 0)
  105:         if (errno != EAGAIN && errno != EINTR) {
  106:             fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
  107:                             errno);
  108:             return;
  109:         }
  110: #else
  111:     /* Apparently VHCI wants us to write everything in one chunk :-(  */
  112:     static uint8_t buf[4096];
  113: 
  114:     buf[0] = type;
  115:     memcpy(buf + 1, data, len);
  116: 
  117:     while (write(s->fd, buf, len + 1) < 0)
  118:         if (errno != EAGAIN && errno != EINTR) {
  119:             fprintf(stderr, "qemu: error %i writing bluetooth packet.\n",
  120:                             errno);
  121:             return;
  122:         }
  123: #endif
  124: }
  125: 
  126: static void vhci_out_hci_packet_event(void *opaque,
  127:                 const uint8_t *data, int len)
  128: {
  129:     vhci_host_send(opaque, HCI_EVENT_PKT, data, len);
  130: }
  131: 
  132: static void vhci_out_hci_packet_acl(void *opaque,
  133:                 const uint8_t *data, int len)
  134: {
  135:     vhci_host_send(opaque, HCI_ACLDATA_PKT, data, len);
  136: }
  137: 
  138: void bt_vhci_init(struct HCIInfo *info)
  139: {
  140:     struct bt_vhci_s *s;
  141:     int err[2];
  142:     int fd;
  143: 
  144:     fd = open(VHCI_DEV, O_RDWR);
  145:     err[0] = errno;
  146:     if (fd < 0) {
  147:         fd = open(VHCI_UDEV, O_RDWR);
  148:         err[1] = errno;
  149:     }
  150: 
  151:     if (fd < 0) {
  152:         fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
  153:                         VHCI_DEV, strerror(err[0]), err[0]);
  154:         fprintf(stderr, "qemu: Can't open `%s': %s (%i)\n",
  155:                         VHCI_UDEV, strerror(err[1]), err[1]);
  156:         exit(-1);
  157:     }
  158: 
  159:     s = qemu_mallocz(sizeof(struct bt_vhci_s));
  160:     s->fd = fd;
  161:     s->info = info ?: qemu_next_hci();
  162:     s->info->opaque = s;
  163:     s->info->evt_recv = vhci_out_hci_packet_event;
  164:     s->info->acl_recv = vhci_out_hci_packet_acl;
  165: 
  166:     qemu_set_fd_handler(s->fd, vhci_read, NULL, s);
  167: }

unix.superglobalmegacorp.com