4 * Description: Universal AMP API
6 * Copyright (C) 1999-2011, Broadcom Corporation
8 * Unless you and Broadcom execute a separate written software license
9 * agreement governing use of this software, this software is licensed to you
10 * under the terms of the GNU General Public License version 2 (the "GPL"),
11 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
12 * following added to such license:
14 * As a special exception, the copyright holders of this software give you
15 * permission to link this software with independent modules, and to copy and
16 * distribute the resulting executable under terms of your choice, provided that
17 * you also meet, for each linked independent module, the terms and conditions of
18 * the license of that module. An independent module is a module which is not
19 * derived from this software. The special exception does not apply to any
20 * modifications of the software.
22 * Notwithstanding the above, under no circumstances may you combine this
23 * software in any way with any other Broadcom software provided under a license
24 * other than the GPL, without Broadcom's express prior written consent.
26 * $Id: uamp_linux.c,v 1.2.110.1 2011-02-05 00:22:40 $
30 /* ---- Include Files ---------------------------------------------------- */
34 #include "bcmendian.h"
38 #include "proto/bt_amp_hci.h"
39 #include "proto/bcmevent.h"
40 #include "proto/802.11_bta.h"
50 #include <sys/types.h>
51 #include <sys/socket.h>
52 #include <arpa/inet.h>
53 #include <sys/ioctl.h>
55 #include <linux/if_packet.h>
58 #include <linux/if_ether.h>
61 #include <linux/sockios.h>
62 #include <linux/ethtool.h>
65 /* ---- Public Variables ------------------------------------------------- */
66 /* ---- Private Constants and Types -------------------------------------- */
70 #define DEV_TYPE_LEN 3 /* length for devtype 'wl'/'et' */
72 #define UAMP_EVT_Q_STR "/uamp_evt_q"
73 #define UAMP_PKT_RX_Q_STR "/uamp_pkt_rx_q"
76 #define UAMP_PRINT(a) printf a
77 #define UAMP_TRACE(a) printf a
78 #define UAMP_ERROR(a) printf a
80 #define UAMP_PRINT(a) printf a
82 #define UAMP_ERROR(a) printf a
85 #if ((BRCM_BLUETOOTH_HOST == 1) && (UAMP_IS_GKI_AWARE == 1))
87 #define UAMP_ALLOC(a) GKI_getbuf(a+sizeof(BT_HDR))
88 #define UAMP_FREE(a) GKI_freebuf(a)
90 #define UAMP_ALLOC(a) malloc(a)
91 #define UAMP_FREE(a) free(a)
92 #endif /* BRCM_BLUETOOTH_HOST && UAMP_IS_GKI_AWARE */
94 #define GET_UAMP_FROM_ID(id) (((id) == 0) ? &g_uamp_mgr.uamp : NULL)
96 #define MAX_IOVAR_LEN 2096
99 /* State associated with a single universal AMP. */
100 typedef struct UAMP_STATE
102 /* Unique universal AMP identifier. */
105 /* Event/data queues. */
109 /* Event file descriptors. */
114 /* Packet rx descriptors. */
116 int pkt_rx_fd_pipe[2];
118 /* Storage buffers for recieved events and packets. */
119 uint32 event_data[WLC_IOCTL_SMLEN/4];
120 uint32 pkt_data[MAX_IOVAR_LEN/4];
125 /* State associated with collection of univerisal AMPs. */
126 typedef struct UAMP_MGR
128 /* Event/data callback. */
129 tUAMP_CBACK callback;
131 /* WLAN interface. */
134 /* UAMP state. Only support a single AMP currently. */
140 /* ---- Private Variables ------------------------------------------------ */
142 static UAMP_MGR g_uamp_mgr;
145 /* ---- Private Function Prototypes -------------------------------------- */
147 static void usage(void);
148 static int uamp_accept_test(void);
149 static int uamp_create_test(void);
150 static UINT16 uamp_write_cmd(uint16 opcode, uint8 *params, uint8 len,
151 amp_hci_cmd_t *cmd, unsigned int max_len);
152 static UINT16 uamp_write_data(uint16 handle, uint8 *data, uint8 len,
153 amp_hci_ACL_data_t *pkt, unsigned int max_len);
155 static int ioctl_get(int cmd, void *buf, int len);
156 static int ioctl_set(int cmd, void *buf, int len);
157 static int iovar_set(const char *iovar, void *param, int paramlen);
158 static int iovar_setbuf(const char *iovar, void *param, int paramlen, void *bufptr,
160 static int iovar_mkbuf(const char *name, char *data, uint datalen, char *iovar_buf,
161 uint buflen, int *perr);
162 static int wl_ioctl(int cmd, void *buf, int len, bool set);
163 static void wl_get_interface_name(struct ifreq *ifr);
164 static int wl_get_dev_type(char *name, void *buf, int len);
165 static void syserr(char *s);
167 static int init_event_rx(UAMP_STATE *uamp);
168 static void deinit_event_rx(UAMP_STATE *uamp);
169 static void* event_thread(void *param);
170 static void handle_event(UAMP_STATE *uamp);
172 static int init_pkt_rx(UAMP_STATE *uamp);
173 static void deinit_pkt_rx(UAMP_STATE *uamp);
174 static void* packet_rx_thread(void *param);
175 static void handle_rx_pkt(UAMP_STATE *uamp);
178 #if (BRCM_BLUETOOTH_HOST == 1)
179 #if (UAMP_IS_GKI_AWARE == 1)
180 void wl_event_gki_callback(wl_event_msg_t* event, void* event_data);
181 int wl_btamp_rx_gki_pkt_callback(wl_drv_netif_pkt pkt, unsigned int len);
182 #endif /* UAMP_IS_GKI_AWARE */
183 static void *uamp_get_acl_buf(unsigned int len);
184 void *hcisu_amp_get_acl_buf(int len); /* Get GKI buffer from ACL pool */
185 void hcisu_handle_amp_data_buf(void *pkt, unsigned int len); /* Send GKI buffer to BTU task */
186 void hcisu_handle_amp_evt_buf(void* evt, unsigned int len);
187 int wl_is_drv_init_done(void);
188 #endif /* BRCM_BLUETOOTH_HOST */
190 /* ---- Functions -------------------------------------------------------- */
192 /* ------------------------------------------------------------------------- */
193 BT_API BOOLEAN UAMP_Init(tUAMP_CBACK p_cback)
195 memset(&g_uamp_mgr, 0, sizeof(g_uamp_mgr));
196 g_uamp_mgr.callback = p_cback;
198 wl_get_interface_name(&g_uamp_mgr.ifr);
204 /* ------------------------------------------------------------------------- */
205 BT_API BOOLEAN UAMP_Open(tUAMP_ID amp_id)
207 UAMP_STATE *uamp = GET_UAMP_FROM_ID(amp_id);
209 #if (BRCM_BLUETOOTH_HOST == 1)
210 if (!wl_is_drv_init_done()) {
211 UAMP_ERROR(("%s: WLAN driver is not initialized! \n", __FUNCTION__));
214 #endif /* BRCM_BLUETOOTH_HOST */
216 /* Setup event receive. */
217 if ((init_event_rx(uamp)) < 0) {
221 /* Setup packet receive. */
222 if ((init_pkt_rx(uamp)) < 0) {
230 /* ------------------------------------------------------------------------- */
231 BT_API void UAMP_Close(tUAMP_ID amp_id)
233 UAMP_STATE *uamp = GET_UAMP_FROM_ID(amp_id);
235 #if (BRCM_BLUETOOTH_HOST == 1)
236 if (!wl_is_drv_init_done()) {
237 UAMP_ERROR(("%s: WLAN driver is not initialized! \n", __FUNCTION__));
240 #endif /* BRCM_BLUETOOTH_HOST */
242 /* Cleanup packet and event receive. */
244 deinit_event_rx(uamp);
247 /* ------------------------------------------------------------------------- */
248 BT_API UINT16 UAMP_Write(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 num_bytes, tUAMP_CH channel)
251 UINT16 num_bytes_written = num_bytes;
253 UNUSED_PARAMETER(amp_id);
255 #if (BRCM_BLUETOOTH_HOST == 1)
256 if (!wl_is_drv_init_done()) {
257 UAMP_ERROR(("%s: WLAN driver is not initialized! \n", __FUNCTION__));
260 #endif /* BRCM_BLUETOOTH_HOST */
262 if (channel == UAMP_CH_HCI_CMD) {
263 ret = iovar_set("HCI_cmd", p_buf, num_bytes);
265 else if (channel == UAMP_CH_HCI_DATA) {
266 ret = iovar_set("HCI_ACL_data", p_buf, num_bytes);
270 num_bytes_written = 0;
271 UAMP_ERROR(("UAMP_Write error: %i ( 0=success )\n", ret));
274 return (num_bytes_written);
278 /* ------------------------------------------------------------------------- */
279 BT_API UINT16 UAMP_Read(tUAMP_ID amp_id, UINT8 *p_buf, UINT16 buf_size, tUAMP_CH channel)
281 UAMP_STATE *uamp = GET_UAMP_FROM_ID(amp_id);
283 unsigned int msg_prio;
285 #if (BRCM_BLUETOOTH_HOST == 1)
286 if (!wl_is_drv_init_done()) {
287 UAMP_ERROR(("%s: WLAN driver is not initialized! \n", __FUNCTION__));
290 #endif /* BRCM_BLUETOOTH_HOST */
293 if (channel == UAMP_CH_HCI_EVT) {
295 num_bytes = mq_receive(uamp->evt_q, (char *)p_buf, buf_size, &msg_prio);
296 if (num_bytes == -1) {
297 UAMP_ERROR(("%s: Event queue receive error!\n", __FUNCTION__));
303 else if (channel == UAMP_CH_HCI_DATA) {
304 /* Dequeue rx packet. */
305 num_bytes = mq_receive(uamp->pkt_rx_q, (char *)p_buf, buf_size, &msg_prio);
306 if (num_bytes == -1) {
307 UAMP_ERROR(("%s: Pkt queue receive error!\n", __FUNCTION__));
319 * Get IOCTL given the parameter buffer.
322 ioctl_get(int cmd, void *buf, int len)
324 return wl_ioctl(cmd, buf, len, FALSE);
329 * Set IOCTL given the parameter buffer.
332 ioctl_set(int cmd, void *buf, int len)
334 return wl_ioctl(cmd, buf, len, TRUE);
339 * Set named iovar given the parameter buffer.
342 iovar_set(const char *iovar, void *param, int paramlen)
344 static char smbuf[MAX_IOVAR_LEN];
346 memset(smbuf, 0, sizeof(smbuf));
348 return iovar_setbuf(iovar, param, paramlen, smbuf, sizeof(smbuf));
352 * Set named iovar providing both parameter and i/o buffers.
355 iovar_setbuf(const char *iovar,
356 void *param, int paramlen, void *bufptr, int buflen)
361 iolen = iovar_mkbuf(iovar, param, paramlen, bufptr, buflen, &err);
365 return ioctl_set(DHD_SET_VAR, bufptr, iolen);
370 * Format an iovar buffer.
373 iovar_mkbuf(const char *name, char *data, uint datalen, char *iovar_buf, uint buflen, int *perr)
377 iovar_len = strlen(name) + 1;
379 /* check for overflow */
380 if ((iovar_len + datalen) > buflen) {
385 /* copy data to the buffer past the end of the iovar name string */
387 memmove(&iovar_buf[iovar_len], data, datalen);
389 /* copy the name to the beginning of the buffer */
390 strcpy(iovar_buf, name);
393 return (iovar_len + datalen);
398 * Send IOCTL to WLAN driver.
401 wl_ioctl(int cmd, void *buf, int len, bool set)
408 memset(&ifr, 0, sizeof(ifr));
409 strncpy(ifr.ifr_name, g_uamp_mgr.ifr.ifr_name, sizeof(ifr.ifr_name));
411 /* open socket to kernel */
412 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
422 ioc.driver = DHD_IOCTL_MAGIC;
423 ifr.ifr_data = (caddr_t) &ioc;
424 if ((ret = ioctl(s, SIOCDEVPRIVATE, &ifr)) < 0) {
435 wl_get_dev_type(char *name, void *buf, int len)
440 struct ethtool_drvinfo info;
442 /* open socket to kernel */
443 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
446 /* get device type */
447 memset(&info, 0, sizeof(info));
448 info.cmd = ETHTOOL_GDRVINFO;
449 ifr.ifr_data = (caddr_t)&info;
450 strncpy(ifr.ifr_name, name, IFNAMSIZ);
451 if ((ret = ioctl(s, SIOCETHTOOL, &ifr)) < 0) {
453 /* print a good diagnostic if not superuser */
455 syserr("wl_get_dev_type");
459 strncpy(buf, info.driver, len);
468 wl_get_interface_name(struct ifreq *ifr)
470 char proc_net_dev[] = "/proc/net/dev";
472 char buf[1000], *c, *name;
473 char dev_type[DEV_TYPE_LEN];
476 ifr->ifr_name[0] = '\0';
478 if (!(fp = fopen(proc_net_dev, "r")))
481 /* eat first two lines */
482 if (!fgets(buf, sizeof(buf), fp) ||
483 !fgets(buf, sizeof(buf), fp)) {
488 while (fgets(buf, sizeof(buf), fp)) {
492 if (!(name = strsep(&c, ":")))
494 strncpy(ifr->ifr_name, name, IFNAMSIZ);
495 if (wl_get_dev_type(name, dev_type, DEV_TYPE_LEN) >= 0 &&
496 (!strncmp(dev_type, "wl", 2) || !strncmp(dev_type, "dhd", 3)))
501 ifr->ifr_name[0] = '\0';
511 fprintf(stderr, "uamp_linux:");
517 #if (BRCM_BLUETOOTH_HOST == 1)
518 static void *uamp_get_acl_buf(unsigned int len)
520 return (hcisu_amp_get_acl_buf(len));
522 #endif /* BRCM_BLUETOOTH_HOST */
526 * Setup packet receive.
529 init_pkt_rx(UAMP_STATE *uamp)
533 struct sockaddr_ll local;
535 int fd_pipe[2] = {-1, -1};
539 memset(&ifr, 0, sizeof(ifr));
540 wl_get_interface_name(&ifr);
542 /* Create and bind socket to receive packets. */
543 fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_802_2));
545 UAMP_ERROR(("%s: Cannot open socket", __FUNCTION__));
549 err = ioctl(fd, SIOCGIFINDEX, &ifr);
551 UAMP_ERROR(("%s: Cannot get index %d\n", __FUNCTION__, err));
556 memset(&local, 0, sizeof(local));
557 local.sll_family = PF_PACKET;
558 local.sll_protocol = htons(ETH_P_802_2);
559 local.sll_ifindex = ifr.ifr_ifindex;
561 if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
562 UAMP_ERROR(("%s: Cannot bind socket", __FUNCTION__));
568 /* Create pipe used to terminate receive packet thread. */
569 if (pipe(fd_pipe) != 0) {
570 UAMP_ERROR(("%s: pipe failed\n", __FUNCTION__));
574 /* Save in instance memory. */
575 uamp->pkt_rx_fd = fd;
576 uamp->pkt_rx_fd_pipe[0] = fd_pipe[0];
577 uamp->pkt_rx_fd_pipe[1] = fd_pipe[1];
580 /* Create message queue for received packets. */
582 uamp->pkt_rx_q = mq_open(UAMP_PKT_RX_Q_STR, O_RDWR | O_CREAT, 0666, NULL);
586 /* Spawn packet handling thread. */
587 pthread_create(&h, NULL, packet_rx_thread, uamp);
592 if (-1 != fd) close(fd);
593 if (-1 != fd_pipe[0]) close(fd_pipe[0]);
594 if (-1 != fd_pipe[1]) close(fd_pipe[1]);
600 * Cleanup packet receive.
603 deinit_pkt_rx(UAMP_STATE *uamp)
605 /* Cleanup the message queue. */
606 mq_close(uamp->pkt_rx_q);
607 mq_unlink(UAMP_PKT_RX_Q_STR);
609 /* Kill the receive thread. */
610 write(uamp->pkt_rx_fd_pipe[1], NULL, 0);
611 close(uamp->pkt_rx_fd_pipe[1]);
616 * Packet receive thread.
619 packet_rx_thread(void *param)
621 UAMP_STATE *uamp = (UAMP_STATE *) param;
623 UAMP_PRINT(("Start packet rx wait loop\n"));
626 fd_set rfds; /* fds for select */
631 FD_SET(uamp->pkt_rx_fd_pipe[0], &rfds);
632 FD_SET(uamp->pkt_rx_fd, &rfds);
633 last_fd = MAX(uamp->pkt_rx_fd_pipe[0], uamp->pkt_rx_fd);
635 /* Wait on stop pipe or rx packet socket */
636 ret = select(last_fd+1, &rfds, NULL, NULL, NULL);
638 /* Error processing */
640 UAMP_ERROR(("%s: Unhandled signal on pkt rx socket\n", __FUNCTION__));
644 /* Stop processing */
645 if (FD_ISSET(uamp->pkt_rx_fd_pipe[0], &rfds)) {
646 UAMP_PRINT(("%s: stop rcvd on dispatcher pipe\n", __FUNCTION__));
650 /* Packet processing */
651 if (FD_ISSET(uamp->pkt_rx_fd, &rfds)) {
657 UAMP_PRINT(("%s: End packet rx wait loop\n", __FUNCTION__));
659 close(uamp->pkt_rx_fd);
660 close(uamp->pkt_rx_fd_pipe[0]);
662 UAMP_TRACE(("Exit %s\n", __FUNCTION__));
667 * Process received packet.
670 handle_rx_pkt(UAMP_STATE *uamp)
673 struct dot11_llc_snap_header *lsh;
674 amp_hci_ACL_data_t *acl_data;
677 bytes = recv(uamp->pkt_rx_fd, uamp->pkt_data, sizeof(uamp->pkt_data), MSG_DONTWAIT);
679 /* Error handling. */
681 if (errno != EINTR && errno != EAGAIN) {
682 UAMP_ERROR(("%s: Error reading packet rx socket: %s\n",
683 __FUNCTION__, strerror(errno)));
689 UAMP_ERROR(("%s: EOF on packet rx socket", __FUNCTION__));
694 /* Verify that this is an HCI data packet. */
695 lsh = (struct dot11_llc_snap_header *)uamp->pkt_data;
696 if (bcmp(lsh, BT_SIG_SNAP_MPROT, DOT11_LLC_SNAP_HDR_LEN - 2) != 0 ||
697 ntoh16(lsh->type) != BTA_PROT_L2CAP) {
703 UAMP_TRACE(("%s: received packet!\n", __FUNCTION__));
705 acl_data = (amp_hci_ACL_data_t *) &lsh[1];
706 bytes -= DOT11_LLC_SNAP_HDR_LEN;
708 #if (BRCM_BLUETOOTH_HOST == 1)
709 hcisu_handle_amp_data_buf(acl_data, bytes);
712 tUAMP_EVT_DATA uamp_evt_data;
713 #if (UAMP_DEBUG == 1)
714 /* Debug - dump rx packet data. */
717 uint8 *data = acl_data->data;
718 UAMP_TRACE(("data(%d): ", bytes));
719 for (i = 0; i < bytes; i++) {
720 UAMP_TRACE(("0x%x ", data[i]));
724 #endif /* UAMP_DEBUG */
726 /* Post packet to queue. Stack will de-queue it with call to UAMP_Read(). */
727 if (mq_send(uamp->pkt_rx_q, (const char *)acl_data, bytes, 0) != 0) {
728 /* Unable to queue packet */
729 UAMP_ERROR(("%s: Unable to queue rx packet data!\n", __FUNCTION__));
734 /* Inform application stack of received packet. */
735 memset(&uamp_evt_data, 0, sizeof(uamp_evt_data));
736 uamp_evt_data.channel = UAMP_CH_HCI_DATA;
737 g_uamp_mgr.callback(0, UAMP_EVT_RX_READY, &uamp_evt_data);
739 #endif /* BRCM_BLUETOOTH_HOST */
744 * Setup event receive.
747 init_event_rx(UAMP_STATE *uamp)
751 struct sockaddr_ll local;
753 int fd_pipe[2] = {-1, -1};
756 memset(&ifr, 0, sizeof(ifr));
757 wl_get_interface_name(&ifr);
758 UAMP_PRINT(("ifr_name (%s)\n", ifr.ifr_name));
760 /* Create and bind socket to receive packets. */
761 fd = socket(PF_PACKET, SOCK_RAW, htons(ETHER_TYPE_BRCM));
763 UAMP_ERROR(("%s: Cannot open socket", __FUNCTION__));
767 err = ioctl(fd, SIOCGIFINDEX, &ifr);
769 UAMP_ERROR(("%s: Cannot get index %d\n", __FUNCTION__, err));
774 memset(&local, 0, sizeof(local));
775 local.sll_family = AF_PACKET;
776 local.sll_protocol = htons(ETHER_TYPE_BRCM);
777 local.sll_ifindex = ifr.ifr_ifindex;
779 if (bind(fd, (struct sockaddr*)&local, sizeof(local)) < 0) {
780 UAMP_ERROR(("%s: Cannot bind event socket", __FUNCTION__));
786 /* Create pipe used to terminate receive packet thread. */
787 if (pipe(fd_pipe) != 0) {
788 UAMP_ERROR(("%s: pipe failed\n", __FUNCTION__));
792 /* Save in instance memory. */
794 uamp->evt_fd_pipe[0] = fd_pipe[0];
795 uamp->evt_fd_pipe[1] = fd_pipe[1];
798 /* Create message queue for received events. */
800 uamp->evt_q = mq_open(UAMP_EVT_Q_STR, O_RDWR | O_CREAT, 0666, NULL);
801 UAMP_PRINT(("evt_q(0x%x)\n", (int)uamp->evt_q));
805 /* Spawn event handling thread. */
806 pthread_create(&h, NULL, event_thread, uamp);
811 if (-1 != fd) close(fd);
812 if (-1 != fd_pipe[0]) close(fd_pipe[0]);
813 if (-1 != fd_pipe[1]) close(fd_pipe[1]);
819 * Cleanup event receive.
822 deinit_event_rx(UAMP_STATE *uamp)
824 /* Cleanup the message queue. */
825 mq_close(uamp->evt_q);
826 mq_unlink(UAMP_EVT_Q_STR);
828 /* Kill the receive thread. */
829 write(uamp->evt_fd_pipe[1], NULL, 0);
830 close(uamp->evt_fd_pipe[1]);
834 * Event receive thread.
837 event_thread(void *param)
839 UAMP_STATE *uamp = (UAMP_STATE *) param;
841 UAMP_PRINT(("Start event wait loop\n"));
844 fd_set rfds; /* fds for select */
849 FD_SET(uamp->evt_fd_pipe[0], &rfds);
850 FD_SET(uamp->evt_fd, &rfds);
851 last_fd = MAX(uamp->evt_fd_pipe[0], uamp->evt_fd);
853 /* Wait on stop pipe or brcm event socket. */
854 ret = select(last_fd+1, &rfds, NULL, NULL, NULL);
856 /* Error processing */
858 UAMP_ERROR(("%s: Unhandled signal on brcm event socket\n", __FUNCTION__));
862 /* Stop processing. */
863 if (FD_ISSET(uamp->evt_fd_pipe[0], &rfds)) {
864 UAMP_PRINT(("%s: stop rcvd on dispatcher pipe\n", __FUNCTION__));
868 /* Event processing. */
869 if (FD_ISSET(uamp->evt_fd, &rfds)) {
875 UAMP_PRINT(("%s: End event wait loop\n", __FUNCTION__));
878 close(uamp->evt_fd_pipe[0]);
880 UAMP_TRACE(("Exit %s\n", __FUNCTION__));
886 * Process received event.
889 handle_event(UAMP_STATE *uamp)
892 bcm_event_t *bcm_event;
893 wl_event_msg_t *wl_event;
898 bytes = recv(uamp->evt_fd, uamp->event_data, sizeof(uamp->event_data), MSG_DONTWAIT);
900 /* Error handling. */
902 if (errno != EINTR && errno != EAGAIN) {
903 UAMP_ERROR(("%s: Error reading event socket: %s\n",
904 __FUNCTION__, strerror(errno)));
910 UAMP_ERROR(("%s: EOF on event socket", __FUNCTION__));
915 /* We're only interested in HCI events. */
916 bcm_event = (bcm_event_t *)uamp->event_data;
917 if (ntoh32(bcm_event->event.event_type) != WLC_E_BTA_HCI_EVENT) {
921 UAMP_TRACE(("%s: received event!\n", __FUNCTION__));
924 wl_event = &bcm_event->event;
925 wl_evt_data = (uint8 *)&wl_event[1];
926 datalen = ntoh32(wl_event->datalen);
928 #if (BRCM_BLUETOOTH_HOST == 1)
929 hcisu_handle_amp_evt_buf(wl_evt_data, datalen);
932 tUAMP_EVT_DATA uamp_evt_data;
934 #if (UAMP_DEBUG == 1)
935 /* Debug - dump event data. */
938 UAMP_TRACE(("data(%d): ", datalen));
939 for (i = 0; i < datalen; i++)
941 UAMP_TRACE(("0x%x ", wl_evt_data[i]));
945 #endif /* UAMP_DEBUG */
947 /* Post event to queue. Stack will de-queue it with call to UAMP_Read(). */
948 if (mq_send(uamp->evt_q, (const char *)wl_evt_data, datalen, 0) != 0) {
949 /* Unable to queue packet */
950 UAMP_ERROR(("%s: Unable to queue event packet!\n", __FUNCTION__));
955 /* Inform application stack of received event. */
956 memset(&uamp_evt_data, 0, sizeof(uamp_evt_data));
957 uamp_evt_data.channel = UAMP_CH_HCI_EVT;
958 g_uamp_mgr.callback(0, UAMP_EVT_RX_READY, &uamp_evt_data);
960 #endif /* BRCM_BLUETOOTH_HOST */
968 main(int argc, char **argv)
972 printf("Hello, world!\n");
979 if (strcmp(argv[1], "-a") == 0) {
980 ret = uamp_accept_test();
982 else if (strcmp(argv[1], "-c") == 0) {
983 ret = uamp_create_test();
997 static void usage(void)
999 UAMP_PRINT(("Usage:\n"));
1000 UAMP_PRINT(("\t uamp [-a | -c]\n"));
1001 UAMP_PRINT(("\t\t -a: acceptor\n"));
1002 UAMP_PRINT(("\t\t -c: creator\n"));
1005 #define WAIT_FOR_KEY(delay) \
1007 usleep(1000*delay); \
1008 UAMP_PRINT(("Press key to continue\n")); \
1015 * Application callback for received events and packets.
1017 static void uamp_callback(tUAMP_ID amp_id, tUAMP_EVT amp_evt, tUAMP_EVT_DATA *p_amp_evt_data)
1020 amp_hci_ACL_data_t *data;
1021 amp_hci_event_t *evt;
1025 UNUSED_PARAMETER(amp_evt);
1027 num_bytes = UAMP_Read(amp_id, buf, sizeof(buf), p_amp_evt_data->channel);
1028 if (num_bytes != 0) {
1029 if (p_amp_evt_data->channel == UAMP_CH_HCI_EVT) {
1030 evt = (amp_hci_event_t *) buf;
1031 UAMP_PRINT(("%s: evt - ecode(%d) plen(%d)\n",
1032 __FUNCTION__, evt->ecode, evt->plen));
1034 for (i = 0; i < evt->plen; i++) {
1035 UAMP_PRINT(("0x%x ", evt->parms[i]));
1039 else if (p_amp_evt_data->channel == UAMP_CH_HCI_DATA) {
1040 data = (amp_hci_ACL_data_t *) buf;
1041 UAMP_PRINT(("%s: data - dlen(%d)\n", __FUNCTION__, data->dlen));
1043 for (i = 0; i < data->dlen; i++) {
1044 UAMP_PRINT(("0x%x ", data->data[i]));
1050 UAMP_PRINT(("%s: UAMP_Read error\n", __FUNCTION__));
1055 /* This client is 00:90:4c:c6:02:5b. Remote is 00:90:4c:c5:06:79. */
1056 static int uamp_accept_test(void)
1058 uint8 set_event_mask_page_2_data[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
1059 uint8 read_local_amp_assoc_data[] = {0, 0, 0};
1060 uint8 accept_physical_link_request_data[] = {0x11, 32, 3, 0x00, 0x01, 0x02,
1061 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
1062 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
1063 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f};
1064 uint8 write_remote_amp_assoc_data[] = {0x11, 0x0, 0x0, 0x24, 0x00, 0x04,
1065 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x05, 0x00, 0x01, 0x0f,
1066 0x00, 0x10, 0x09, 0x01, 0x06, 0x00, 0x00, 0x90, 0x4c, 0xc5, 0x06,
1067 0x79, 0x02, 0x09, 0x00, 0x55, 0x53, 0x20, 0xc9, 0x0c, 0x00, 0x01,
1069 uint8 accept_logical_link_data[] = {0x11, 0x01, 0x01, 0xff, 0xff, 0xff,
1070 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1071 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1072 0xff, 0xff, 0xff, 0xff, 0xff};
1073 uint8 tx_data[] = {7, 6, 5, 4, 3, 2, 1, 0};
1074 uint8 disconnect_logical_link_data[] = {0};
1075 uint8 disconnect_physical_link_data[] = {0x11, 0};
1078 amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)buf;
1079 amp_hci_ACL_data_t *pkt = (amp_hci_ACL_data_t *)buf;
1082 UAMP_PRINT(("UAMP acceptor test\n"));
1085 UAMP_Init(uamp_callback);
1089 /* HCI_Set_Event_Mask_Page_2 */
1090 uamp_write_cmd(HCI_Set_Event_Mask_Page_2, set_event_mask_page_2_data,
1091 sizeof(set_event_mask_page_2_data), cmd, sizeof(buf));
1093 /* Read_Local_AMP_ASSOC */
1094 uamp_write_cmd(HCI_Read_Local_AMP_ASSOC, read_local_amp_assoc_data,
1095 sizeof(read_local_amp_assoc_data), cmd, sizeof(buf));
1098 /* Accept_Physical_Link_Request */
1099 uamp_write_cmd(HCI_Accept_Physical_Link_Request, accept_physical_link_request_data,
1100 sizeof(accept_physical_link_request_data), cmd, sizeof(buf));
1103 /* This is specific to info obtained from the remote client. */
1104 /* Write_Remote_AMP_ASSOC */
1105 uamp_write_cmd(HCI_Write_Remote_AMP_ASSOC, write_remote_amp_assoc_data,
1106 sizeof(write_remote_amp_assoc_data), cmd, sizeof(buf));
1109 /* Accept_Logical_Link */
1110 uamp_write_cmd(HCI_Accept_Logical_Link, accept_logical_link_data,
1111 sizeof(accept_logical_link_data), cmd, sizeof(buf));
1115 uamp_write_data(0 | HCI_ACL_DATA_BC_FLAGS | HCI_ACL_DATA_PB_FLAGS, tx_data,
1116 sizeof(tx_data), pkt, sizeof(buf));
1119 /* Disconnect_Logical_Link */
1120 uamp_write_cmd(HCI_Disconnect_Logical_Link, disconnect_logical_link_data,
1121 sizeof(disconnect_logical_link_data), cmd, sizeof(buf));
1123 /* Disconnect_Physical_Link */
1124 uamp_write_cmd(HCI_Disconnect_Physical_Link, disconnect_physical_link_data,
1125 sizeof(disconnect_physical_link_data), cmd, sizeof(buf));
1130 UAMP_PRINT(("UAMP acceptor test done!\n"));
1136 /* This client is 00:90:4c:c5:06:79. Remote is 00:90:4c:c6:02:5b. */
1137 static int uamp_create_test(void)
1139 uint8 set_event_mask_page_2_data[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
1140 uint8 create_physical_link_data[] = {0x10, 32, 3, 0x00, 0x01, 0x02, 0x03,
1141 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
1142 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
1143 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f};
1144 uint8 write_remote_amp_assoc_data[] = {0x10, 0x0, 0x0, 0x21, 0x00, 0x04,
1145 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x05, 0x05, 0x00, 0x01, 0x0f,
1146 0x00, 0x10, 0x09, 0x01, 0x06, 0x00, 0x00, 0x90, 0x4c, 0xc6, 0x02,
1147 0x5b, 0x02, 0x06, 0x00, 0x55, 0x53, 0x20, 0xc9, 0x0c, 0x00};
1148 uint8 read_local_amp_assoc_data[] = {0x10, 0, 0, 100, 0};
1149 uint8 create_logical_link_data[] = {0x10, 0x01, 0x01, 0xff, 0xff, 0xff,
1150 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1151 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
1152 0xff, 0xff, 0xff, 0xff, 0xff};
1153 uint8 disconnect_logical_link_data[] = {0};
1154 uint8 disconnect_physical_link_data[] = {0x10, 0};
1155 uint8 tx_data[] = {0, 1, 2, 3, 4, 5, 6, 7};
1158 amp_hci_cmd_t *cmd = (amp_hci_cmd_t *)buf;
1159 amp_hci_ACL_data_t *pkt = (amp_hci_ACL_data_t *)buf;
1161 UAMP_PRINT(("UAMP creator test\n"));
1164 UAMP_Init(uamp_callback);
1168 /* HCI_Set_Event_Mask_Page_2 */
1169 uamp_write_cmd(HCI_Set_Event_Mask_Page_2, set_event_mask_page_2_data,
1170 sizeof(set_event_mask_page_2_data), cmd, sizeof(buf));
1172 /* Read_Local_AMP_Info */
1173 uamp_write_cmd(HCI_Read_Local_AMP_Info, NULL, 0, cmd, sizeof(buf));
1176 /* Create_Physical_Link */
1177 uamp_write_cmd(HCI_Create_Physical_Link, create_physical_link_data,
1178 sizeof(create_physical_link_data), cmd, sizeof(buf));
1180 /* This is specific to info obtained from the remote client. */
1181 /* Write_Remote_AMP_ASSOC */
1182 uamp_write_cmd(HCI_Write_Remote_AMP_ASSOC, write_remote_amp_assoc_data,
1183 sizeof(write_remote_amp_assoc_data), cmd, sizeof(buf));
1186 /* Spin for a bit. */
1190 /* Read_Local_AMP_ASSOC */
1191 uamp_write_cmd(HCI_Read_Local_AMP_ASSOC, read_local_amp_assoc_data,
1192 sizeof(read_local_amp_assoc_data), cmd, sizeof(buf));
1195 /* Create_Logical_Link */
1196 uamp_write_cmd(HCI_Create_Logical_Link, create_logical_link_data,
1197 sizeof(create_logical_link_data), cmd, sizeof(buf));
1201 uamp_write_data(0 | HCI_ACL_DATA_BC_FLAGS | HCI_ACL_DATA_PB_FLAGS, tx_data,
1202 sizeof(tx_data), pkt, sizeof(buf));
1205 /* Disconnect_Logical_Link */
1206 uamp_write_cmd(HCI_Disconnect_Logical_Link, disconnect_logical_link_data,
1207 sizeof(disconnect_logical_link_data), cmd, sizeof(buf));
1209 /* Disconnect_Physical_Link */
1210 uamp_write_cmd(HCI_Disconnect_Physical_Link, disconnect_physical_link_data,
1211 sizeof(disconnect_physical_link_data), cmd, sizeof(buf));
1216 UAMP_PRINT(("UAMP creator test done!\n"));
1223 * Send UAMP command.
1225 static UINT16 uamp_write_cmd(uint16 opcode, uint8 *params, uint8 len,
1226 amp_hci_cmd_t *cmd, unsigned int max_len)
1228 memset(cmd, 0, sizeof(amp_hci_cmd_t));
1230 cmd->opcode = opcode;
1231 assert(HCI_CMD_PREAMBLE_SIZE + len <= max_len);
1234 memcpy(cmd->parms, params, len);
1237 return (UAMP_Write(0, (UINT8 *)cmd, HCI_CMD_PREAMBLE_SIZE + len, UAMP_CH_HCI_CMD));
1244 static UINT16 uamp_write_data(uint16 handle, uint8 *data, uint8 len,
1245 amp_hci_ACL_data_t *pkt, unsigned int max_len)
1247 memset(pkt, 0, sizeof(amp_hci_ACL_data_t));
1248 pkt->handle = handle;
1250 assert(HCI_ACL_DATA_PREAMBLE_SIZE + len <= max_len);
1253 memcpy(pkt->data, data, len);
1256 return (UAMP_Write(0, (UINT8 *)pkt, HCI_ACL_DATA_PREAMBLE_SIZE + len, UAMP_CH_HCI_DATA));
1258 #endif /* UAMP_TEST */