3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2011-2014 Intel Corporation
6 * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
36 #include <sys/param.h>
37 #include <sys/epoll.h>
40 #include "lib/bluetooth.h"
43 #include "src/shared/mainloop.h"
47 #define uninitialized_var(x) x = x
50 enum serial_type type;
62 static void open_pty(struct serial *serial);
64 static void serial_destroy(void *user_data)
66 struct serial *serial = user_data;
68 btdev_destroy(serial->btdev);
75 static void serial_write_callback(const struct iovec *iov, int iovlen,
78 struct serial *serial = user_data;
81 written = writev(serial->fd, iov, iovlen);
86 static void serial_read_callback(int fd, uint32_t events, void *user_data)
88 struct serial *serial = user_data;
89 static uint8_t buf[4096];
94 if (events & (EPOLLERR | EPOLLHUP)) {
95 mainloop_remove_fd(serial->fd);
101 len = read(serial->fd, buf + serial->pkt_offset,
102 sizeof(buf) - serial->pkt_offset);
112 count = serial->pkt_offset + len;
115 hci_command_hdr *cmd_hdr;
117 if (!serial->pkt_data) {
118 serial->pkt_type = ptr[0];
120 switch (serial->pkt_type) {
121 case HCI_COMMAND_PKT:
122 if (count < HCI_COMMAND_HDR_SIZE + 1) {
123 serial->pkt_offset += len;
126 cmd_hdr = (hci_command_hdr *) (ptr + 1);
127 serial->pkt_expect = HCI_COMMAND_HDR_SIZE +
129 serial->pkt_data = malloc(serial->pkt_expect);
133 printf("packet error\n");
137 serial->pkt_offset = 0;
140 if (count >= serial->pkt_expect) {
141 memcpy(serial->pkt_data + serial->pkt_len,
142 ptr, serial->pkt_expect);
143 ptr += serial->pkt_expect;
144 count -= serial->pkt_expect;
146 btdev_receive_h4(serial->btdev, serial->pkt_data,
147 serial->pkt_len + serial->pkt_expect);
149 free(serial->pkt_data);
150 serial->pkt_data = NULL;
152 memcpy(serial->pkt_data + serial->pkt_len, ptr, count);
153 serial->pkt_len += count;
154 serial->pkt_expect -= count;
160 static void open_pty(struct serial *serial)
162 enum btdev_type uninitialized_var(type);
164 serial->fd = posix_openpt(O_RDWR | O_NOCTTY);
165 if (serial->fd < 0) {
166 perror("Failed to get master pseudo terminal");
170 if (grantpt(serial->fd) < 0) {
171 perror("Failed to grant slave pseudo terminal");
177 if (unlockpt(serial->fd) < 0) {
178 perror("Failed to unlock slave pseudo terminal");
184 ptsname_r(serial->fd, serial->path, sizeof(serial->path));
186 printf("Pseudo terminal at %s\n", serial->path);
188 switch (serial->type) {
189 case SERIAL_TYPE_BREDRLE:
190 type = BTDEV_TYPE_BREDRLE;
192 case SERIAL_TYPE_BREDR:
193 type = BTDEV_TYPE_BREDR;
196 type = BTDEV_TYPE_LE;
198 case SERIAL_TYPE_AMP:
199 type = BTDEV_TYPE_AMP;
203 serial->btdev = btdev_create(type, serial->id);
204 if (!serial->btdev) {
210 btdev_set_send_handler(serial->btdev, serial_write_callback, serial);
212 if (mainloop_add_fd(serial->fd, EPOLLIN, serial_read_callback,
213 serial, serial_destroy) < 0) {
214 btdev_destroy(serial->btdev);
215 serial->btdev = NULL;
222 struct serial *serial_open(enum serial_type type)
224 struct serial *serial;
225 enum btdev_type uninitialized_var(dev_type);
227 serial = malloc(sizeof(*serial));
231 memset(serial, 0, sizeof(*serial));
240 void serial_close(struct serial *serial)
245 mainloop_remove_fd(serial->fd);