SILI - Increase hard -> soft PM target delay to 5 seconds
[dragonfly.git] / sys / netbt / sco_socket.c
blobae748096eb173933db3ce3f1f8e52aafd9f72c80
1 /* $DragonFly: src/sys/netbt/sco_socket.c,v 1.3 2008/06/20 20:58:37 aggelos Exp $ */
2 /* $OpenBSD: sco_socket.c,v 1.1 2007/06/01 02:46:12 uwe Exp $ */
3 /* $NetBSD: sco_socket.c,v 1.9 2007/04/21 06:15:23 plunky Exp $ */
5 /*-
6 * Copyright (c) 2006 Itronix Inc.
7 * All rights reserved.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. The name of Itronix Inc. may not be used to endorse
18 * or promote products derived from this software without specific
19 * prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
28 * ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
34 #include <sys/cdefs.h>
36 /* load symbolic names */
37 #ifdef BLUETOOTH_DEBUG
38 #define PRUREQUESTS
39 #define PRCOREQUESTS
40 #endif
42 #include <sys/param.h>
43 #include <sys/domain.h>
44 #include <sys/kernel.h>
45 #include <sys/mbuf.h>
46 #include <sys/proc.h>
47 #include <sys/protosw.h>
48 #include <sys/socket.h>
49 #include <sys/socketvar.h>
50 #include <sys/systm.h>
51 #include <sys/bus.h>
53 #include <netbt/bluetooth.h>
54 #include <netbt/hci.h>
55 #include <netbt/sco.h>
57 /*******************************************************************************
59 * SCO SOCK_SEQPACKET sockets - low latency audio data
62 static void sco_connecting(void *);
63 static void sco_connected(void *);
64 static void sco_disconnected(void *, int);
65 static void *sco_newconn(void *, struct sockaddr_bt *, struct sockaddr_bt *);
66 static void sco_complete(void *, int);
67 static void sco_linkmode(void *, int);
68 static void sco_input(void *, struct mbuf *);
70 static const struct btproto sco_proto = {
71 sco_connecting,
72 sco_connected,
73 sco_disconnected,
74 sco_newconn,
75 sco_complete,
76 sco_linkmode,
77 sco_input,
80 int sco_sendspace = 4096;
81 int sco_recvspace = 4096;
84 * get/set socket options
86 int
87 sco_ctloutput(struct socket *so, struct sockopt *sopt)
89 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
90 struct mbuf *m;
91 int err = 0;
93 #ifdef notyet /* XXX */
94 DPRINTFN(2, "req %s\n", prcorequests[req]);
95 #endif
97 if (pcb == NULL)
98 return EINVAL;
100 if (sopt->sopt_level != BTPROTO_SCO)
101 return ENOPROTOOPT;
103 switch(sopt->sopt_dir) {
104 case PRCO_GETOPT:
105 m = m_get(MB_WAIT, MT_DATA);
106 m->m_len = sco_getopt(pcb, sopt->sopt_name, mtod(m, uint8_t *));
107 if (m->m_len == 0) {
108 m_freem(m);
109 m = NULL;
110 err = ENOPROTOOPT;
112 /* *opt = m; */
113 /* XXX There are possible memory leaks (Griffin) */
114 soopt_from_kbuf(sopt, mtod(m, void *), m->m_len);
115 break;
117 case PRCO_SETOPT:
118 m = m_get(M_WAITOK, MT_DATA);
119 KKASSERT(m != NULL);
120 err = soopt_to_kbuf(sopt, mtod(m,void*), m->m_len, m->m_len);
122 if (m->m_len == 0) {
123 m_freem(m);
124 m = NULL;
125 err = EIO;
128 err = sco_setopt(pcb, sopt->sopt_name, mtod(m, uint8_t *));
129 m_freem(m);
130 break;
132 default:
133 err = ENOPROTOOPT;
134 break;
137 return err;
140 /*****************************************************************************
142 * SCO Protocol socket callbacks
145 static void
146 sco_connecting(void *arg)
148 struct socket *so = arg;
150 DPRINTF("Connecting\n");
151 soisconnecting(so);
154 static void
155 sco_connected(void *arg)
157 struct socket *so = arg;
159 DPRINTF("Connected\n");
160 soisconnected(so);
163 static void
164 sco_disconnected(void *arg, int err)
166 struct socket *so = arg;
168 DPRINTF("Disconnected (%d)\n", err);
170 so->so_error = err;
171 soisdisconnected(so);
174 static void *
175 sco_newconn(void *arg, struct sockaddr_bt *laddr,
176 struct sockaddr_bt *raddr)
178 struct socket *so = arg;
180 DPRINTF("New Connection\n");
181 so = sonewconn(so, 0);
182 if (so == NULL)
183 return NULL;
185 soisconnecting(so);
186 return so->so_pcb;
189 static void
190 sco_complete(void *arg, int num)
192 struct socket *so = arg;
194 while (num-- > 0)
195 sbdroprecord(&so->so_snd.sb);
197 sowwakeup(so);
200 static void
201 sco_linkmode(void *arg, int mode)
205 static void
206 sco_input(void *arg, struct mbuf *m)
208 struct socket *so = arg;
211 * since this data is time sensitive, if the buffer
212 * is full we just dump data until the latest one
213 * will fit.
216 while (m->m_pkthdr.len > sbspace(&so->so_rcv))
217 sbdroprecord(&so->so_rcv.sb);
219 DPRINTFN(10, "received %d bytes\n", m->m_pkthdr.len);
221 sbappendrecord(&so->so_rcv.sb, m);
222 sorwakeup(so);
226 * Implementation of usrreqs.
228 static int
229 sco_sdetach(struct socket *so)
231 return sco_detach((struct sco_pcb **)&so->so_pcb);
234 static int
235 sco_sabort (struct socket *so)
237 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
239 sco_disconnect(pcb, 0);
240 soisdisconnected(so);
242 return sco_sdetach(so);
245 static int
246 sco_sdisconnect (struct socket *so)
248 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
250 soisdisconnecting(so);
252 return sco_disconnect(pcb, so->so_linger);
255 static int
256 sco_sattach (struct socket *so, int proto,
257 struct pru_attach_info *ai)
259 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
260 int err=0;
262 if (pcb)
263 return EINVAL;
265 err = soreserve(so, sco_sendspace, sco_recvspace,NULL);
266 if (err)
267 return err;
269 return sco_attach((struct sco_pcb **)&so->so_pcb,
270 &sco_proto, so);
273 static int
274 sco_sbind (struct socket *so, struct sockaddr *nam,
275 struct thread *td)
277 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
278 struct sockaddr_bt *sa;
280 KKASSERT(nam != NULL);
281 sa = (struct sockaddr_bt *)nam;
283 if (sa->bt_len != sizeof(struct sockaddr_bt))
284 return EINVAL;
286 if (sa->bt_family != AF_BLUETOOTH)
287 return EAFNOSUPPORT;
289 return sco_bind(pcb, sa);
292 static int
293 sco_sconnect (struct socket *so, struct sockaddr *nam,
294 struct thread *td)
296 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
297 struct sockaddr_bt *sa;
299 KKASSERT(nam != NULL);
300 sa = (struct sockaddr_bt *)nam;
302 if (sa->bt_len != sizeof(struct sockaddr_bt))
303 return EINVAL;
305 if (sa->bt_family != AF_BLUETOOTH)
306 return EAFNOSUPPORT;
308 soisconnecting(so);
309 return sco_connect(pcb, sa);
312 static int
313 sco_speeraddr (struct socket *so, struct sockaddr **nam)
315 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
316 struct sockaddr_bt *sa, ssa;
317 int e;
319 sa = &ssa;
320 bzero(sa, sizeof *sa);
321 sa->bt_len = sizeof(struct sockaddr_bt);
322 sa->bt_family = AF_BLUETOOTH;
323 e = sco_peeraddr(pcb, sa);
324 *nam = dup_sockaddr((struct sockaddr *)sa);
326 return (e);
329 static int
330 sco_ssockaddr (struct socket *so, struct sockaddr **nam)
332 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
333 struct sockaddr_bt *sa, ssa;
334 int e;
336 sa = &ssa;
337 bzero(sa, sizeof *sa);
338 sa->bt_len = sizeof(struct sockaddr_bt);
339 sa->bt_family = AF_BLUETOOTH;
340 e = sco_sockaddr(pcb, sa);
341 *nam = dup_sockaddr((struct sockaddr *)sa);
343 return (e);
346 static int
347 sco_sshutdown (struct socket *so)
349 socantsendmore(so);
350 return 0;
353 static int
354 sco_ssend (struct socket *so, int flags, struct mbuf *m,
355 struct sockaddr *addr, struct mbuf *control, struct thread *td)
357 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
358 struct mbuf *m0;
359 int err = 0;
361 KKASSERT(m != NULL);
362 if (m->m_pkthdr.len == 0)
363 goto error;
365 if (m->m_pkthdr.len > pcb->sp_mtu) {
366 err = EMSGSIZE;
367 goto error;
370 m0 = m_copym(m, 0, M_COPYALL, MB_DONTWAIT);
371 if (m0 == NULL) {
372 err = ENOMEM;
373 goto error;
376 if (control) /* no use for that */
377 m_freem(control);
379 sbappendrecord(&so->so_snd.sb, m);
380 return sco_send(pcb, m0);
382 error:
383 if (m) m_freem(m);
384 if (control) m_freem(control);
385 return err;
388 static int
389 sco_saccept(struct socket *so, struct sockaddr **nam)
391 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
392 struct sockaddr_bt *sa, ssa;
393 int e;
395 sa = &ssa;
396 bzero(sa, sizeof *sa);
397 sa->bt_len = sizeof(struct sockaddr_bt);
398 sa->bt_family = AF_BLUETOOTH;
399 e = sco_peeraddr(pcb, sa);
400 *nam = dup_sockaddr((struct sockaddr *)sa);
402 return (e);
405 static int
406 sco_slisten(struct socket *so, struct thread *td)
408 struct sco_pcb *pcb = (struct sco_pcb *)so->so_pcb;
409 return sco_listen(pcb);
413 struct pr_usrreqs sco_usrreqs = {
414 .pru_abort = sco_sabort,
415 .pru_accept = sco_saccept,
416 .pru_attach = sco_sattach,
417 .pru_bind = sco_sbind,
418 .pru_connect = sco_sconnect,
419 .pru_connect2 = pru_connect2_notsupp,
420 .pru_control = pru_control_notsupp,
421 .pru_detach = sco_sdetach,
422 .pru_disconnect = sco_sdisconnect,
423 .pru_listen = sco_slisten,
424 .pru_peeraddr = sco_speeraddr,
425 .pru_rcvd = pru_rcvd_notsupp,
426 .pru_rcvoob = pru_rcvoob_notsupp,
427 .pru_send = sco_ssend,
428 .pru_sense = pru_sense_null,
429 .pru_shutdown = sco_sshutdown,
430 .pru_sockaddr = sco_ssockaddr,
431 .pru_sosend = sosend,
432 .pru_soreceive = soreceive,
433 .pru_sopoll = sopoll