1 /* Copyright (C) 2011 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 ** GNU General Public License for more details.
11 */
12 #include "android/utils/panic.h"
13 #include "android/utils/system.h"
14 #include "hw/android/goldfish/pipe.h"
15 #include "hw/android/goldfish/device.h"
16 #include "hw/android/goldfish/vmem.h"
17 #include "qemu/timer.h"
18
19 #define DEBUG 0
20
21 /* Set to 1 to debug i/o register reads/writes */
22 #define DEBUG_REGS 0
23
24 #if DEBUG >= 1
25 # define D(...) fprintf(stderr, __VA_ARGS__), fprintf(stderr, "\n")
26 #else
27 # define D(...) (void)0
28 #endif
29
30 #if DEBUG >= 2
31 # define DD(...) fprintf(stderr, __VA_ARGS__), fprintf(stderr, "\n")
32 #else
33 # define DD(...) (void)0
34 #endif
35
36 #if DEBUG_REGS >= 1
37 # define DR(...) D(__VA_ARGS__)
38 #else
39 # define DR(...) (void)0
40 #endif
41
42 #define E(...) fprintf(stderr, "ERROR:" __VA_ARGS__), fprintf(stderr, "\n")
43
44 /* Set to 1 to enable the 'zero' pipe type, useful for debugging */
45 #define DEBUG_ZERO_PIPE 1
46
47 /* Set to 1 to enable the 'pingpong' pipe type, useful for debugging */
48 #define DEBUG_PINGPONG_PIPE 1
49
50 /* Set to 1 to enable the 'throttle' pipe type, useful for debugging */
51 #define DEBUG_THROTTLE_PIPE 1
52
53 /* Maximum length of pipe service name, in characters (excluding final 0) */
54 #define MAX_PIPE_SERVICE_NAME_SIZE 255
55
56 #define GOLDFISH_PIPE_SAVE_VERSION 3
57
58 // Up to Tools r22.6, the emulator saved with this version number.
59 #define GOLDFISH_PIPE_SAVE_VERSION_LEGACY 2
60
61 /***********************************************************************
62 ***********************************************************************
63 *****
64 ***** P I P E S E R V I C E R E G I S T R A T I O N
65 *****
66 *****/
67
68 #define MAX_PIPE_SERVICES 8
69 typedef struct {
70 const char* name;
71 void* opaque;
72 GoldfishPipeFuncs funcs;
73 } PipeService;
74
75 typedef struct {
76 int count;
77 PipeService services[MAX_PIPE_SERVICES];
78 } PipeServices;
79
80 static PipeServices _pipeServices[1];
81
82 void
goldfish_pipe_add_type(const char * pipeName,void * pipeOpaque,const GoldfishPipeFuncs * pipeFuncs)83 goldfish_pipe_add_type(const char* pipeName,
84 void* pipeOpaque,
85 const GoldfishPipeFuncs* pipeFuncs )
86 {
87 PipeServices* list = _pipeServices;
88 int count = list->count;
89
90 if (count >= MAX_PIPE_SERVICES) {
91 APANIC("Too many goldfish pipe services (%d)", count);
92 }
93
94 if (strlen(pipeName) > MAX_PIPE_SERVICE_NAME_SIZE) {
95 APANIC("Pipe service name too long: '%s'", pipeName);
96 }
97
98 list->services[count].name = pipeName;
99 list->services[count].opaque = pipeOpaque;
100 list->services[count].funcs = pipeFuncs[0];
101
102 list->count++;
103 }
104
105 static const PipeService*
goldfish_pipe_find_type(const char * pipeName)106 goldfish_pipe_find_type(const char* pipeName)
107 {
108 PipeServices* list = _pipeServices;
109 int count = list->count;
110 int nn;
111
112 for (nn = 0; nn < count; nn++) {
113 if (!strcmp(list->services[nn].name, pipeName)) {
114 return &list->services[nn];
115 }
116 }
117 return NULL;
118 }
119
120
121 /***********************************************************************
122 ***********************************************************************
123 *****
124 ***** P I P E C O N N E C T I O N S
125 *****
126 *****/
127
128 typedef struct PipeDevice PipeDevice;
129
130 typedef struct Pipe {
131 struct Pipe* next;
132 struct Pipe* next_waked;
133 PipeDevice* device;
134 uint64_t channel;
135 void* opaque;
136 const GoldfishPipeFuncs* funcs;
137 const PipeService* service;
138 char* args;
139 unsigned char wanted;
140 char closed;
141 } Pipe;
142
143 /* Forward */
144 static void* pipeConnector_new(Pipe* pipe);
145
146 static Pipe*
pipe_new0(PipeDevice * dev)147 pipe_new0(PipeDevice* dev)
148 {
149 Pipe* pipe;
150 ANEW0(pipe);
151 pipe->device = dev;
152 return pipe;
153 }
154
155 static Pipe*
pipe_new(uint64_t channel,PipeDevice * dev)156 pipe_new(uint64_t channel, PipeDevice* dev)
157 {
158 Pipe* pipe = pipe_new0(dev);
159 pipe->channel = channel;
160 pipe->opaque = pipeConnector_new(pipe);
161 return pipe;
162 }
163
164 static Pipe**
pipe_list_findp_channel(Pipe ** list,uint64_t channel)165 pipe_list_findp_channel( Pipe** list, uint64_t channel )
166 {
167 Pipe** pnode = list;
168 for (;;) {
169 Pipe* node = *pnode;
170 if (node == NULL || node->channel == channel) {
171 break;
172 }
173 pnode = &node->next;
174 }
175 return pnode;
176 }
177
178 #if 0
179 static Pipe**
180 pipe_list_findp_opaque( Pipe** list, void* opaque )
181 {
182 Pipe** pnode = list;
183 for (;;) {
184 Pipe* node = *pnode;
185 if (node == NULL || node->opaque == opaque) {
186 break;
187 }
188 pnode = &node->next;
189 }
190 return pnode;
191 }
192 #endif
193
194 static Pipe**
pipe_list_findp_waked(Pipe ** list,Pipe * pipe)195 pipe_list_findp_waked( Pipe** list, Pipe* pipe )
196 {
197 Pipe** pnode = list;
198 for (;;) {
199 Pipe* node = *pnode;
200 if (node == NULL || node == pipe) {
201 break;
202 }
203 pnode = &node->next_waked;
204 }
205 return pnode;
206 }
207
208
209 static void
pipe_list_remove_waked(Pipe ** list,Pipe * pipe)210 pipe_list_remove_waked( Pipe** list, Pipe* pipe )
211 {
212 Pipe** lookup = pipe_list_findp_waked(list, pipe);
213 Pipe* node = *lookup;
214
215 if (node != NULL) {
216 (*lookup) = node->next_waked;
217 node->next_waked = NULL;
218 }
219 }
220
221 static void
pipe_save(Pipe * pipe,QEMUFile * file)222 pipe_save( Pipe* pipe, QEMUFile* file )
223 {
224 if (pipe->service == NULL) {
225 /* pipe->service == NULL means we're still using a PipeConnector */
226 /* Write a zero to indicate this condition */
227 qemu_put_byte(file, 0);
228 } else {
229 /* Otherwise, write a '1' then the service name */
230 qemu_put_byte(file, 1);
231 qemu_put_string(file, pipe->service->name);
232 }
233
234 /* Now save other common data */
235 qemu_put_be64(file, pipe->channel);
236 qemu_put_byte(file, (int)pipe->wanted);
237 qemu_put_byte(file, (int)pipe->closed);
238
239 /* Write 1 + args, if any, or simply 0 otherwise */
240 if (pipe->args != NULL) {
241 qemu_put_byte(file, 1);
242 qemu_put_string(file, pipe->args);
243 } else {
244 qemu_put_byte(file, 0);
245 }
246
247 if (pipe->funcs->save) {
248 pipe->funcs->save(pipe->opaque, file);
249 }
250 }
251
252 static Pipe*
pipe_load(PipeDevice * dev,QEMUFile * file,int version_id)253 pipe_load( PipeDevice* dev, QEMUFile* file, int version_id )
254 {
255 Pipe* pipe;
256 const PipeService* service = NULL;
257 int state = qemu_get_byte(file);
258 uint64_t channel;
259
260 if (state != 0) {
261 /* Pipe is associated with a service. */
262 char* name = qemu_get_string(file);
263 if (name == NULL)
264 return NULL;
265
266 service = goldfish_pipe_find_type(name);
267 if (service == NULL) {
268 D("No QEMU pipe service named '%s'", name);
269 AFREE(name);
270 return NULL;
271 }
272 }
273
274 if (version_id == GOLDFISH_PIPE_SAVE_VERSION_LEGACY) {
275 channel = qemu_get_be32(file);
276 } else {
277 channel = qemu_get_be64(file);
278 }
279 pipe = pipe_new(channel, dev);
280 pipe->wanted = qemu_get_byte(file);
281 pipe->closed = qemu_get_byte(file);
282 if (qemu_get_byte(file) != 0) {
283 pipe->args = qemu_get_string(file);
284 }
285
286 pipe->service = service;
287 if (service != NULL) {
288 pipe->funcs = &service->funcs;
289 }
290
291 if (pipe->funcs->load) {
292 pipe->opaque = pipe->funcs->load(pipe, service ? service->opaque : NULL, pipe->args, file);
293 if (pipe->opaque == NULL) {
294 AFREE(pipe);
295 return NULL;
296 }
297 } else {
298 /* Force-close the pipe on load */
299 pipe->closed = 1;
300 }
301 return pipe;
302 }
303
304 static void
pipe_free(Pipe * pipe)305 pipe_free( Pipe* pipe )
306 {
307 /* Call close callback */
308 if (pipe->funcs->close) {
309 pipe->funcs->close(pipe->opaque);
310 }
311 /* Free stuff */
312 AFREE(pipe->args);
313 AFREE(pipe);
314 }
315
316 /***********************************************************************
317 ***********************************************************************
318 *****
319 ***** P I P E C O N N E C T O R S
320 *****
321 *****/
322
323 /* These are used to handle the initial connection attempt, where the
324 * client is going to write the name of the pipe service it wants to
325 * connect to, followed by a terminating zero.
326 */
327 typedef struct {
328 Pipe* pipe;
329 char buffer[128];
330 int buffpos;
331 } PipeConnector;
332
333 static const GoldfishPipeFuncs pipeConnector_funcs; // forward
334
335 void*
pipeConnector_new(Pipe * pipe)336 pipeConnector_new(Pipe* pipe)
337 {
338 PipeConnector* pcon;
339
340 ANEW0(pcon);
341 pcon->pipe = pipe;
342 pipe->funcs = &pipeConnector_funcs;
343 return pcon;
344 }
345
346 static void
pipeConnector_close(void * opaque)347 pipeConnector_close( void* opaque )
348 {
349 PipeConnector* pcon = opaque;
350 AFREE(pcon);
351 }
352
353 static int
pipeConnector_sendBuffers(void * opaque,const GoldfishPipeBuffer * buffers,int numBuffers)354 pipeConnector_sendBuffers( void* opaque, const GoldfishPipeBuffer* buffers, int numBuffers )
355 {
356 PipeConnector* pcon = opaque;
357 const GoldfishPipeBuffer* buffers_limit = buffers + numBuffers;
358 int ret = 0;
359
360 DD("%s: channel=0x%llx numBuffers=%d", __FUNCTION__,
361 (unsigned long long)pcon->pipe->channel,
362 numBuffers);
363
364 while (buffers < buffers_limit) {
365 int avail;
366
367 DD("%s: buffer data (%3d bytes): '%.*s'", __FUNCTION__,
368 buffers[0].size, buffers[0].size, buffers[0].data);
369
370 if (buffers[0].size == 0) {
371 buffers++;
372 continue;
373 }
374
375 avail = sizeof(pcon->buffer) - pcon->buffpos;
376 if (avail > buffers[0].size)
377 avail = buffers[0].size;
378
379 if (avail > 0) {
380 memcpy(pcon->buffer + pcon->buffpos, buffers[0].data, avail);
381 pcon->buffpos += avail;
382 ret += avail;
383 }
384 buffers++;
385 }
386
387 /* Now check that our buffer contains a zero-terminated string */
388 if (memchr(pcon->buffer, '\0', pcon->buffpos) != NULL) {
389 /* Acceptable formats for the connection string are:
390 *
391 * pipe:<name>
392 * pipe:<name>:<arguments>
393 */
394 char* pipeName;
395 char* pipeArgs;
396
397 D("%s: connector: '%s'", __FUNCTION__, pcon->buffer);
398
399 if (memcmp(pcon->buffer, "pipe:", 5) != 0) {
400 /* Nope, we don't handle these for now. */
401 D("%s: Unknown pipe connection: '%s'", __FUNCTION__, pcon->buffer);
402 return PIPE_ERROR_INVAL;
403 }
404
405 pipeName = pcon->buffer + 5;
406 pipeArgs = strchr(pipeName, ':');
407
408 if (pipeArgs != NULL) {
409 *pipeArgs++ = '\0';
410 if (!*pipeArgs)
411 pipeArgs = NULL;
412 }
413
414 Pipe* pipe = pcon->pipe;
415 const PipeService* svc = goldfish_pipe_find_type(pipeName);
416 if (svc == NULL) {
417 D("%s: Unknown server!", __FUNCTION__);
418 return PIPE_ERROR_INVAL;
419 }
420
421 void* peer = svc->funcs.init(pipe, svc->opaque, pipeArgs);
422 if (peer == NULL) {
423 D("%s: Initialization failed!", __FUNCTION__);
424 return PIPE_ERROR_INVAL;
425 }
426
427 /* Do the evil switch now */
428 pipe->opaque = peer;
429 pipe->service = svc;
430 pipe->funcs = &svc->funcs;
431 pipe->args = ASTRDUP(pipeArgs);
432 AFREE(pcon);
433 }
434
435 return ret;
436 }
437
438 static int
pipeConnector_recvBuffers(void * opaque,GoldfishPipeBuffer * buffers,int numBuffers)439 pipeConnector_recvBuffers( void* opaque, GoldfishPipeBuffer* buffers, int numBuffers )
440 {
441 return PIPE_ERROR_IO;
442 }
443
444 static unsigned
pipeConnector_poll(void * opaque)445 pipeConnector_poll( void* opaque )
446 {
447 return PIPE_POLL_OUT;
448 }
449
450 static void
pipeConnector_wakeOn(void * opaque,int flags)451 pipeConnector_wakeOn( void* opaque, int flags )
452 {
453 /* nothing, really should never happen */
454 }
455
456 static void
pipeConnector_save(void * pipe,QEMUFile * file)457 pipeConnector_save( void* pipe, QEMUFile* file )
458 {
459 PipeConnector* pcon = pipe;
460 qemu_put_sbe32(file, pcon->buffpos);
461 qemu_put_sbuffer(file, (const int8_t*)pcon->buffer, pcon->buffpos);
462 }
463
464 static void*
pipeConnector_load(void * hwpipe,void * pipeOpaque,const char * args,QEMUFile * file)465 pipeConnector_load( void* hwpipe, void* pipeOpaque, const char* args, QEMUFile* file )
466 {
467 PipeConnector* pcon;
468
469 int len = qemu_get_sbe32(file);
470 if (len < 0 || len > sizeof(pcon->buffer)) {
471 return NULL;
472 }
473 pcon = pipeConnector_new(hwpipe);
474 pcon->buffpos = len;
475 if (qemu_get_buffer(file, (uint8_t*)pcon->buffer, pcon->buffpos) != pcon->buffpos) {
476 AFREE(pcon);
477 return NULL;
478 }
479 return pcon;
480 }
481
482 static const GoldfishPipeFuncs pipeConnector_funcs = {
483 NULL, /* init */
484 pipeConnector_close, /* should rarely happen */
485 pipeConnector_sendBuffers, /* the interesting stuff */
486 pipeConnector_recvBuffers, /* should not happen */
487 pipeConnector_poll, /* should not happen */
488 pipeConnector_wakeOn, /* should not happen */
489 pipeConnector_save,
490 pipeConnector_load,
491 };
492
493 /***********************************************************************
494 ***********************************************************************
495 *****
496 ***** Z E R O P I P E S
497 *****
498 *****/
499
500 /* A simple pipe service that mimics /dev/zero, you can write anything to
501 * it, and you can always read any number of zeros from it. Useful for debugging
502 * the kernel driver.
503 */
504 #if DEBUG_ZERO_PIPE
505
506 typedef struct {
507 void* hwpipe;
508 } ZeroPipe;
509
510 static void*
zeroPipe_init(void * hwpipe,void * svcOpaque,const char * args)511 zeroPipe_init( void* hwpipe, void* svcOpaque, const char* args )
512 {
513 ZeroPipe* zpipe;
514
515 D("%s: hwpipe=%p", __FUNCTION__, hwpipe);
516 ANEW0(zpipe);
517 zpipe->hwpipe = hwpipe;
518 return zpipe;
519 }
520
521 static void
zeroPipe_close(void * opaque)522 zeroPipe_close( void* opaque )
523 {
524 ZeroPipe* zpipe = opaque;
525
526 D("%s: hwpipe=%p", __FUNCTION__, zpipe->hwpipe);
527 AFREE(zpipe);
528 }
529
530 static int
zeroPipe_sendBuffers(void * opaque,const GoldfishPipeBuffer * buffers,int numBuffers)531 zeroPipe_sendBuffers( void* opaque, const GoldfishPipeBuffer* buffers, int numBuffers )
532 {
533 int ret = 0;
534 while (numBuffers > 0) {
535 ret += buffers[0].size;
536 buffers++;
537 numBuffers--;
538 }
539 return ret;
540 }
541
542 static int
zeroPipe_recvBuffers(void * opaque,GoldfishPipeBuffer * buffers,int numBuffers)543 zeroPipe_recvBuffers( void* opaque, GoldfishPipeBuffer* buffers, int numBuffers )
544 {
545 int ret = 0;
546 while (numBuffers > 0) {
547 ret += buffers[0].size;
548 memset(buffers[0].data, 0, buffers[0].size);
549 buffers++;
550 numBuffers--;
551 }
552 return ret;
553 }
554
555 static unsigned
zeroPipe_poll(void * opaque)556 zeroPipe_poll( void* opaque )
557 {
558 return PIPE_POLL_IN | PIPE_POLL_OUT;
559 }
560
561 static void
zeroPipe_wakeOn(void * opaque,int flags)562 zeroPipe_wakeOn( void* opaque, int flags )
563 {
564 /* nothing to do here */
565 }
566
567 static const GoldfishPipeFuncs zeroPipe_funcs = {
568 zeroPipe_init,
569 zeroPipe_close,
570 zeroPipe_sendBuffers,
571 zeroPipe_recvBuffers,
572 zeroPipe_poll,
573 zeroPipe_wakeOn,
574 };
575
576 #endif /* DEBUG_ZERO */
577
578 /***********************************************************************
579 ***********************************************************************
580 *****
581 ***** P I N G P O N G P I P E S
582 *****
583 *****/
584
585 /* Similar debug service that sends back anything it receives */
586 /* All data is kept in a circular dynamic buffer */
587
588 #if DEBUG_PINGPONG_PIPE
589
590 /* Initial buffer size */
591 #define PINGPONG_SIZE 1024
592
593 typedef struct {
594 void* hwpipe;
595 uint8_t* buffer;
596 size_t size;
597 size_t pos;
598 size_t count;
599 unsigned flags;
600 } PingPongPipe;
601
602 static void
pingPongPipe_init0(PingPongPipe * pipe,void * hwpipe,void * svcOpaque)603 pingPongPipe_init0( PingPongPipe* pipe, void* hwpipe, void* svcOpaque )
604 {
605 pipe->hwpipe = hwpipe;
606 pipe->size = PINGPONG_SIZE;
607 pipe->buffer = malloc(pipe->size);
608 pipe->pos = 0;
609 pipe->count = 0;
610 }
611
612 static void*
pingPongPipe_init(void * hwpipe,void * svcOpaque,const char * args)613 pingPongPipe_init( void* hwpipe, void* svcOpaque, const char* args )
614 {
615 PingPongPipe* ppipe;
616
617 D("%s: hwpipe=%p", __FUNCTION__, hwpipe);
618 ANEW0(ppipe);
619 pingPongPipe_init0(ppipe, hwpipe, svcOpaque);
620 return ppipe;
621 }
622
623 static void
pingPongPipe_close(void * opaque)624 pingPongPipe_close( void* opaque )
625 {
626 PingPongPipe* ppipe = opaque;
627
628 D("%s: hwpipe=%p (pos=%d count=%d size=%d)", __FUNCTION__,
629 ppipe->hwpipe, ppipe->pos, ppipe->count, ppipe->size);
630 free(ppipe->buffer);
631 AFREE(ppipe);
632 }
633
634 static int
pingPongPipe_sendBuffers(void * opaque,const GoldfishPipeBuffer * buffers,int numBuffers)635 pingPongPipe_sendBuffers( void* opaque, const GoldfishPipeBuffer* buffers, int numBuffers )
636 {
637 PingPongPipe* pipe = opaque;
638 int ret = 0;
639 int count;
640 const GoldfishPipeBuffer* buff = buffers;
641 const GoldfishPipeBuffer* buffEnd = buff + numBuffers;
642
643 count = 0;
644 for ( ; buff < buffEnd; buff++ )
645 count += buff->size;
646
647 /* Do we need to grow the pingpong buffer? */
648 while (count > pipe->size - pipe->count) {
649 size_t newsize = pipe->size*2;
650 uint8_t* newbuff = realloc(pipe->buffer, newsize);
651 int wpos = pipe->pos + pipe->count;
652 if (newbuff == NULL) {
653 break;
654 }
655 if (wpos > pipe->size) {
656 wpos -= pipe->size;
657 memcpy(newbuff + pipe->size, newbuff, wpos);
658 }
659 pipe->buffer = newbuff;
660 pipe->size = newsize;
661 D("pingpong buffer is now %d bytes", newsize);
662 }
663
664 for ( buff = buffers; buff < buffEnd; buff++ ) {
665 int avail = pipe->size - pipe->count;
666 if (avail <= 0) {
667 if (ret == 0)
668 ret = PIPE_ERROR_AGAIN;
669 break;
670 }
671 if (avail > buff->size) {
672 avail = buff->size;
673 }
674
675 int wpos = pipe->pos + pipe->count;
676 if (wpos >= pipe->size) {
677 wpos -= pipe->size;
678 }
679 if (wpos + avail <= pipe->size) {
680 memcpy(pipe->buffer + wpos, buff->data, avail);
681 } else {
682 int avail2 = pipe->size - wpos;
683 memcpy(pipe->buffer + wpos, buff->data, avail2);
684 memcpy(pipe->buffer, buff->data + avail2, avail - avail2);
685 }
686 pipe->count += avail;
687 ret += avail;
688 }
689
690 /* Wake up any waiting readers if we wrote something */
691 if (pipe->count > 0 && (pipe->flags & PIPE_WAKE_READ)) {
692 goldfish_pipe_wake(pipe->hwpipe, PIPE_WAKE_READ);
693 }
694
695 return ret;
696 }
697
698 static int
pingPongPipe_recvBuffers(void * opaque,GoldfishPipeBuffer * buffers,int numBuffers)699 pingPongPipe_recvBuffers( void* opaque, GoldfishPipeBuffer* buffers, int numBuffers )
700 {
701 PingPongPipe* pipe = opaque;
702 int ret = 0;
703
704 while (numBuffers > 0) {
705 int avail = pipe->count;
706 if (avail <= 0) {
707 if (ret == 0)
708 ret = PIPE_ERROR_AGAIN;
709 break;
710 }
711 if (avail > buffers[0].size) {
712 avail = buffers[0].size;
713 }
714
715 int rpos = pipe->pos;
716
717 if (rpos + avail <= pipe->size) {
718 memcpy(buffers[0].data, pipe->buffer + rpos, avail);
719 } else {
720 int avail2 = pipe->size - rpos;
721 memcpy(buffers[0].data, pipe->buffer + rpos, avail2);
722 memcpy(buffers[0].data + avail2, pipe->buffer, avail - avail2);
723 }
724 pipe->count -= avail;
725 pipe->pos += avail;
726 if (pipe->pos >= pipe->size) {
727 pipe->pos -= pipe->size;
728 }
729 ret += avail;
730 numBuffers--;
731 buffers++;
732 }
733
734 /* Wake up any waiting readers if we wrote something */
735 if (pipe->count < PINGPONG_SIZE && (pipe->flags & PIPE_WAKE_WRITE)) {
736 goldfish_pipe_wake(pipe->hwpipe, PIPE_WAKE_WRITE);
737 }
738
739 return ret;
740 }
741
742 static unsigned
pingPongPipe_poll(void * opaque)743 pingPongPipe_poll( void* opaque )
744 {
745 PingPongPipe* pipe = opaque;
746 unsigned ret = 0;
747
748 if (pipe->count < pipe->size)
749 ret |= PIPE_POLL_OUT;
750
751 if (pipe->count > 0)
752 ret |= PIPE_POLL_IN;
753
754 return ret;
755 }
756
757 static void
pingPongPipe_wakeOn(void * opaque,int flags)758 pingPongPipe_wakeOn( void* opaque, int flags )
759 {
760 PingPongPipe* pipe = opaque;
761 pipe->flags |= (unsigned)flags;
762 }
763
764 static const GoldfishPipeFuncs pingPongPipe_funcs = {
765 pingPongPipe_init,
766 pingPongPipe_close,
767 pingPongPipe_sendBuffers,
768 pingPongPipe_recvBuffers,
769 pingPongPipe_poll,
770 pingPongPipe_wakeOn,
771 };
772
773 #endif /* DEBUG_PINGPONG_PIPE */
774
775 /***********************************************************************
776 ***********************************************************************
777 *****
778 ***** T H R O T T L E P I P E S
779 *****
780 *****/
781
782 /* Similar to PingPongPipe, but will throttle the bandwidth to test
783 * blocking I/O.
784 */
785
786 #ifdef DEBUG_THROTTLE_PIPE
787
788 typedef struct {
789 PingPongPipe pingpong;
790 double sendRate;
791 int64_t sendExpiration;
792 double recvRate;
793 int64_t recvExpiration;
794 QEMUTimer* timer;
795 } ThrottlePipe;
796
797 /* forward declaration */
798 static void throttlePipe_timerFunc( void* opaque );
799
800 static void*
throttlePipe_init(void * hwpipe,void * svcOpaque,const char * args)801 throttlePipe_init( void* hwpipe, void* svcOpaque, const char* args )
802 {
803 ThrottlePipe* pipe;
804
805 ANEW0(pipe);
806 pingPongPipe_init0(&pipe->pingpong, hwpipe, svcOpaque);
807 pipe->timer = timer_new(QEMU_CLOCK_VIRTUAL, SCALE_NS, throttlePipe_timerFunc, pipe);
808 /* For now, limit to 500 KB/s in both directions */
809 pipe->sendRate = 1e9 / (500*1024*8);
810 pipe->recvRate = pipe->sendRate;
811 return pipe;
812 }
813
814 static void
throttlePipe_close(void * opaque)815 throttlePipe_close( void* opaque )
816 {
817 ThrottlePipe* pipe = opaque;
818
819 timer_del(pipe->timer);
820 timer_free(pipe->timer);
821 pingPongPipe_close(&pipe->pingpong);
822 }
823
824 static void
throttlePipe_rearm(ThrottlePipe * pipe)825 throttlePipe_rearm( ThrottlePipe* pipe )
826 {
827 int64_t minExpiration = 0;
828
829 DD("%s: sendExpiration=%lld recvExpiration=%lld\n", __FUNCTION__, pipe->sendExpiration, pipe->recvExpiration);
830
831 if (pipe->sendExpiration) {
832 if (minExpiration == 0 || pipe->sendExpiration < minExpiration)
833 minExpiration = pipe->sendExpiration;
834 }
835
836 if (pipe->recvExpiration) {
837 if (minExpiration == 0 || pipe->recvExpiration < minExpiration)
838 minExpiration = pipe->recvExpiration;
839 }
840
841 if (minExpiration != 0) {
842 DD("%s: Arming for %lld\n", __FUNCTION__, minExpiration);
843 timer_mod(pipe->timer, minExpiration);
844 }
845 }
846
847 static void
throttlePipe_timerFunc(void * opaque)848 throttlePipe_timerFunc( void* opaque )
849 {
850 ThrottlePipe* pipe = opaque;
851 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
852
853 DD("%s: TICK! now=%lld sendExpiration=%lld recvExpiration=%lld\n",
854 __FUNCTION__, now, pipe->sendExpiration, pipe->recvExpiration);
855
856 /* Timer has expired, signal wake up if needed */
857 int flags = 0;
858
859 if (pipe->sendExpiration && now > pipe->sendExpiration) {
860 flags |= PIPE_WAKE_WRITE;
861 pipe->sendExpiration = 0;
862 }
863 if (pipe->recvExpiration && now > pipe->recvExpiration) {
864 flags |= PIPE_WAKE_READ;
865 pipe->recvExpiration = 0;
866 }
867 flags &= pipe->pingpong.flags;
868 if (flags != 0) {
869 DD("%s: WAKE %d\n", __FUNCTION__, flags);
870 goldfish_pipe_wake(pipe->pingpong.hwpipe, flags);
871 }
872
873 throttlePipe_rearm(pipe);
874 }
875
876 static int
throttlePipe_sendBuffers(void * opaque,const GoldfishPipeBuffer * buffers,int numBuffers)877 throttlePipe_sendBuffers( void* opaque, const GoldfishPipeBuffer* buffers, int numBuffers )
878 {
879 ThrottlePipe* pipe = opaque;
880 int ret;
881
882 if (pipe->sendExpiration > 0) {
883 return PIPE_ERROR_AGAIN;
884 }
885
886 ret = pingPongPipe_sendBuffers(&pipe->pingpong, buffers, numBuffers);
887 if (ret > 0) {
888 /* Compute next send expiration time */
889 pipe->sendExpiration = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ret*pipe->sendRate;
890 throttlePipe_rearm(pipe);
891 }
892 return ret;
893 }
894
895 static int
throttlePipe_recvBuffers(void * opaque,GoldfishPipeBuffer * buffers,int numBuffers)896 throttlePipe_recvBuffers( void* opaque, GoldfishPipeBuffer* buffers, int numBuffers )
897 {
898 ThrottlePipe* pipe = opaque;
899 int ret;
900
901 if (pipe->recvExpiration > 0) {
902 return PIPE_ERROR_AGAIN;
903 }
904
905 ret = pingPongPipe_recvBuffers(&pipe->pingpong, buffers, numBuffers);
906 if (ret > 0) {
907 pipe->recvExpiration = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + ret*pipe->recvRate;
908 throttlePipe_rearm(pipe);
909 }
910 return ret;
911 }
912
913 static unsigned
throttlePipe_poll(void * opaque)914 throttlePipe_poll( void* opaque )
915 {
916 ThrottlePipe* pipe = opaque;
917 unsigned ret = pingPongPipe_poll(&pipe->pingpong);
918
919 if (pipe->sendExpiration > 0)
920 ret &= ~PIPE_POLL_OUT;
921
922 if (pipe->recvExpiration > 0)
923 ret &= ~PIPE_POLL_IN;
924
925 return ret;
926 }
927
928 static void
throttlePipe_wakeOn(void * opaque,int flags)929 throttlePipe_wakeOn( void* opaque, int flags )
930 {
931 ThrottlePipe* pipe = opaque;
932 pingPongPipe_wakeOn(&pipe->pingpong, flags);
933 }
934
935 static const GoldfishPipeFuncs throttlePipe_funcs = {
936 throttlePipe_init,
937 throttlePipe_close,
938 throttlePipe_sendBuffers,
939 throttlePipe_recvBuffers,
940 throttlePipe_poll,
941 throttlePipe_wakeOn,
942 };
943
944 #endif /* DEBUG_THROTTLE_PIPE */
945
946 /***********************************************************************
947 ***********************************************************************
948 *****
949 ***** G O L D F I S H P I P E D E V I C E
950 *****
951 *****/
952
953 struct PipeDevice {
954 struct goldfish_device dev;
955
956 /* the list of all pipes */
957 Pipe* pipes;
958
959 /* the list of signalled pipes */
960 Pipe* signaled_pipes;
961
962 /* i/o registers */
963 uint64_t address;
964 uint32_t size;
965 uint32_t status;
966 uint64_t channel;
967 uint32_t wakes;
968 uint64_t params_addr;
969 };
970
971 static void
pipeDevice_doCommand(PipeDevice * dev,uint32_t command)972 pipeDevice_doCommand( PipeDevice* dev, uint32_t command )
973 {
974 Pipe** lookup = pipe_list_findp_channel(&dev->pipes, dev->channel);
975 Pipe* pipe = *lookup;
976 CPUOldState* env = cpu_single_env;
977
978 /* Check that we're referring a known pipe channel */
979 if (command != PIPE_CMD_OPEN && pipe == NULL) {
980 dev->status = PIPE_ERROR_INVAL;
981 return;
982 }
983
984 /* If the pipe is closed by the host, return an error */
985 if (pipe != NULL && pipe->closed && command != PIPE_CMD_CLOSE) {
986 dev->status = PIPE_ERROR_IO;
987 return;
988 }
989
990 switch (command) {
991 case PIPE_CMD_OPEN:
992 DD("%s: CMD_OPEN channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
993 if (pipe != NULL) {
994 dev->status = PIPE_ERROR_INVAL;
995 break;
996 }
997 pipe = pipe_new(dev->channel, dev);
998 pipe->next = dev->pipes;
999 dev->pipes = pipe;
1000 dev->status = 0;
1001 break;
1002
1003 case PIPE_CMD_CLOSE:
1004 DD("%s: CMD_CLOSE channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
1005 /* Remove from device's lists */
1006 *lookup = pipe->next;
1007 pipe->next = NULL;
1008 pipe_list_remove_waked(&dev->signaled_pipes, pipe);
1009 pipe_free(pipe);
1010 break;
1011
1012 case PIPE_CMD_POLL:
1013 dev->status = pipe->funcs->poll(pipe->opaque);
1014 DD("%s: CMD_POLL > status=%d", __FUNCTION__, dev->status);
1015 break;
1016
1017 case PIPE_CMD_READ_BUFFER: {
1018 /* Translate virtual address into physical one, into emulator memory. */
1019 GoldfishPipeBuffer buffer;
1020 target_ulong address = dev->address;
1021 target_ulong page = address & TARGET_PAGE_MASK;
1022 hwaddr phys;
1023 phys = safe_get_phys_page_debug(ENV_GET_CPU(env), page);
1024 #ifdef TARGET_X86_64
1025 phys = phys & TARGET_PTE_MASK;
1026 #endif
1027 buffer.data = qemu_get_ram_ptr(phys) + (address - page);
1028 buffer.size = dev->size;
1029 dev->status = pipe->funcs->recvBuffers(pipe->opaque, &buffer, 1);
1030 DD("%s: CMD_READ_BUFFER channel=0x%llx address=0x%16llx size=%d > status=%d",
1031 __FUNCTION__, (unsigned long long)dev->channel, (unsigned long long)dev->address,
1032 dev->size, dev->status);
1033 break;
1034 }
1035
1036 case PIPE_CMD_WRITE_BUFFER: {
1037 /* Translate virtual address into physical one, into emulator memory. */
1038 GoldfishPipeBuffer buffer;
1039 target_ulong address = dev->address;
1040 target_ulong page = address & TARGET_PAGE_MASK;
1041 hwaddr phys;
1042 phys = safe_get_phys_page_debug(ENV_GET_CPU(env), page);
1043 #ifdef TARGET_X86_64
1044 phys = phys & TARGET_PTE_MASK;
1045 #endif
1046 buffer.data = qemu_get_ram_ptr(phys) + (address - page);
1047 buffer.size = dev->size;
1048 dev->status = pipe->funcs->sendBuffers(pipe->opaque, &buffer, 1);
1049 DD("%s: CMD_WRITE_BUFFER channel=0x%llx address=0x%16llx size=%d > status=%d",
1050 __FUNCTION__, (unsigned long long)dev->channel, (unsigned long long)dev->address,
1051 dev->size, dev->status);
1052 break;
1053 }
1054
1055 case PIPE_CMD_WAKE_ON_READ:
1056 DD("%s: CMD_WAKE_ON_READ channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
1057 if ((pipe->wanted & PIPE_WAKE_READ) == 0) {
1058 pipe->wanted |= PIPE_WAKE_READ;
1059 pipe->funcs->wakeOn(pipe->opaque, pipe->wanted);
1060 }
1061 dev->status = 0;
1062 break;
1063
1064 case PIPE_CMD_WAKE_ON_WRITE:
1065 DD("%s: CMD_WAKE_ON_WRITE channel=0x%llx", __FUNCTION__, (unsigned long long)dev->channel);
1066 if ((pipe->wanted & PIPE_WAKE_WRITE) == 0) {
1067 pipe->wanted |= PIPE_WAKE_WRITE;
1068 pipe->funcs->wakeOn(pipe->opaque, pipe->wanted);
1069 }
1070 dev->status = 0;
1071 break;
1072
1073 default:
1074 D("%s: command=%d (0x%x)\n", __FUNCTION__, command, command);
1075 }
1076 }
1077
pipe_dev_write(void * opaque,hwaddr offset,uint32_t value)1078 static void pipe_dev_write(void *opaque, hwaddr offset, uint32_t value)
1079 {
1080 PipeDevice *s = (PipeDevice *)opaque;
1081
1082 switch (offset) {
1083 case PIPE_REG_COMMAND:
1084 DR("%s: command=%d (0x%x)", __FUNCTION__, value, value);
1085 pipeDevice_doCommand(s, value);
1086 break;
1087
1088 case PIPE_REG_SIZE:
1089 DR("%s: size=%d (0x%x)", __FUNCTION__, value, value);
1090 s->size = value;
1091 break;
1092
1093 case PIPE_REG_ADDRESS:
1094 DR("%s: address=%d (0x%x)", __FUNCTION__, value, value);
1095 uint64_set_low(&s->address, value);
1096 break;
1097
1098 case PIPE_REG_ADDRESS_HIGH:
1099 DR("%s: address_high=%d (0x%x)", __FUNCTION__, value, value);
1100 uint64_set_high(&s->address, value);
1101 break;
1102
1103 case PIPE_REG_CHANNEL:
1104 DR("%s: channel=%d (0x%x)", __FUNCTION__, value, value);
1105 uint64_set_low(&s->channel, value);
1106 break;
1107
1108 case PIPE_REG_CHANNEL_HIGH:
1109 DR("%s: channel_high=%d (0x%x)", __FUNCTION__, value, value);
1110 uint64_set_high(&s->channel, value);
1111 break;
1112
1113 case PIPE_REG_PARAMS_ADDR_HIGH:
1114 s->params_addr = (s->params_addr & ~(0xFFFFFFFFULL << 32) ) |
1115 ((uint64_t)value << 32);
1116 break;
1117
1118 case PIPE_REG_PARAMS_ADDR_LOW:
1119 s->params_addr = (s->params_addr & ~(0xFFFFFFFFULL) ) | value;
1120 break;
1121
1122 case PIPE_REG_ACCESS_PARAMS:
1123 {
1124 struct access_params aps;
1125 struct access_params_64 aps64;
1126 uint32_t cmd;
1127
1128 /* Don't touch aps.result if anything wrong */
1129 if (s->params_addr == 0)
1130 break;
1131
1132 if (goldfish_guest_is_64bit()) {
1133 cpu_physical_memory_read(s->params_addr, (void*)&aps64,
1134 sizeof(aps64));
1135 } else {
1136 cpu_physical_memory_read(s->params_addr, (void*)&aps,
1137 sizeof(aps));
1138 }
1139 /* sync pipe device state from batch buffer */
1140 if (goldfish_guest_is_64bit()) {
1141 s->channel = aps64.channel;
1142 s->size = aps64.size;
1143 s->address = aps64.address;
1144 cmd = aps64.cmd;
1145 } else {
1146 s->channel = aps.channel;
1147 s->size = aps.size;
1148 s->address = aps.address;
1149 cmd = aps.cmd;
1150 }
1151 if ((cmd != PIPE_CMD_READ_BUFFER) && (cmd != PIPE_CMD_WRITE_BUFFER))
1152 break;
1153
1154 pipeDevice_doCommand(s, cmd);
1155 if (goldfish_guest_is_64bit()) {
1156 aps64.result = s->status;
1157 cpu_physical_memory_write(s->params_addr, (void*)&aps64,
1158 sizeof(aps64));
1159 } else {
1160 aps.result = s->status;
1161 cpu_physical_memory_write(s->params_addr, (void*)&aps,
1162 sizeof(aps));
1163 }
1164 }
1165 break;
1166
1167 default:
1168 D("%s: offset=%d (0x%x) value=%d (0x%x)\n", __FUNCTION__, offset,
1169 offset, value, value);
1170 break;
1171 }
1172 }
1173
1174 /* I/O read */
pipe_dev_read(void * opaque,hwaddr offset)1175 static uint32_t pipe_dev_read(void *opaque, hwaddr offset)
1176 {
1177 PipeDevice *dev = (PipeDevice *)opaque;
1178
1179 switch (offset) {
1180 case PIPE_REG_STATUS:
1181 DR("%s: REG_STATUS status=%d (0x%x)", __FUNCTION__, dev->status, dev->status);
1182 return dev->status;
1183
1184 case PIPE_REG_CHANNEL:
1185 if (dev->signaled_pipes != NULL) {
1186 Pipe* pipe = dev->signaled_pipes;
1187 DR("%s: channel=0x%llx wanted=%d", __FUNCTION__,
1188 (unsigned long long)pipe->channel, pipe->wanted);
1189 dev->wakes = pipe->wanted;
1190 pipe->wanted = 0;
1191 dev->signaled_pipes = pipe->next_waked;
1192 pipe->next_waked = NULL;
1193 if (dev->signaled_pipes == NULL) {
1194 goldfish_device_set_irq(&dev->dev, 0, 0);
1195 DD("%s: lowering IRQ", __FUNCTION__);
1196 }
1197 return (uint32_t)(pipe->channel & 0xFFFFFFFFUL);
1198 }
1199 DR("%s: no signaled channels", __FUNCTION__);
1200 return 0;
1201
1202 case PIPE_REG_CHANNEL_HIGH:
1203 if (dev->signaled_pipes != NULL) {
1204 Pipe* pipe = dev->signaled_pipes;
1205 DR("%s: channel_high=0x%llx wanted=%d", __FUNCTION__,
1206 (unsigned long long)pipe->channel, pipe->wanted);
1207 return (uint32_t)(pipe->channel >> 32);
1208 }
1209 DR("%s: no signaled channels", __FUNCTION__);
1210 return 0;
1211
1212 case PIPE_REG_WAKES:
1213 DR("%s: wakes %d", __FUNCTION__, dev->wakes);
1214 return dev->wakes;
1215
1216 case PIPE_REG_PARAMS_ADDR_HIGH:
1217 return (uint32_t)(dev->params_addr >> 32);
1218
1219 case PIPE_REG_PARAMS_ADDR_LOW:
1220 return (uint32_t)(dev->params_addr & 0xFFFFFFFFUL);
1221
1222 default:
1223 D("%s: offset=%d (0x%x)\n", __FUNCTION__, offset, offset);
1224 }
1225 return 0;
1226 }
1227
1228 static CPUReadMemoryFunc *pipe_dev_readfn[] = {
1229 pipe_dev_read,
1230 pipe_dev_read,
1231 pipe_dev_read
1232 };
1233
1234 static CPUWriteMemoryFunc *pipe_dev_writefn[] = {
1235 pipe_dev_write,
1236 pipe_dev_write,
1237 pipe_dev_write
1238 };
1239
1240 static void
goldfish_pipe_save(QEMUFile * file,void * opaque)1241 goldfish_pipe_save( QEMUFile* file, void* opaque )
1242 {
1243 PipeDevice* dev = opaque;
1244 Pipe* pipe;
1245
1246 qemu_put_be64(file, dev->address);
1247 qemu_put_be32(file, dev->size);
1248 qemu_put_be32(file, dev->status);
1249 qemu_put_be64(file, dev->channel);
1250 qemu_put_be32(file, dev->wakes);
1251 qemu_put_be64(file, dev->params_addr);
1252
1253 /* Count the number of pipe connections */
1254 int count = 0;
1255 for ( pipe = dev->pipes; pipe; pipe = pipe->next )
1256 count++;
1257
1258 qemu_put_sbe32(file, count);
1259
1260 /* Now save each pipe one after the other */
1261 for ( pipe = dev->pipes; pipe; pipe = pipe->next ) {
1262 pipe_save(pipe, file);
1263 }
1264 }
1265
1266 static int
goldfish_pipe_load(QEMUFile * file,void * opaque,int version_id)1267 goldfish_pipe_load( QEMUFile* file, void* opaque, int version_id )
1268 {
1269 PipeDevice* dev = opaque;
1270 Pipe* pipe;
1271
1272 if ((version_id != GOLDFISH_PIPE_SAVE_VERSION) &&
1273 (version_id != GOLDFISH_PIPE_SAVE_VERSION_LEGACY)) {
1274 return -EINVAL;
1275 }
1276 if (version_id == GOLDFISH_PIPE_SAVE_VERSION_LEGACY) {
1277 dev->address = (uint64_t)qemu_get_be32(file);
1278 } else {
1279 dev->address = qemu_get_be64(file);
1280 }
1281 dev->size = qemu_get_be32(file);
1282 dev->status = qemu_get_be32(file);
1283 if (version_id == GOLDFISH_PIPE_SAVE_VERSION_LEGACY) {
1284 dev->channel = (uint64_t)qemu_get_be32(file);
1285 } else {
1286 dev->channel = qemu_get_be64(file);
1287 }
1288 dev->wakes = qemu_get_be32(file);
1289 dev->params_addr = qemu_get_be64(file);
1290
1291 /* Count the number of pipe connections */
1292 int count = qemu_get_sbe32(file);
1293
1294 /* Load all pipe connections */
1295 for ( ; count > 0; count-- ) {
1296 pipe = pipe_load(dev, file, version_id);
1297 if (pipe == NULL) {
1298 return -EIO;
1299 }
1300 pipe->next = dev->pipes;
1301 dev->pipes = pipe;
1302 }
1303
1304 /* Now we need to wake/close all relevant pipes */
1305 for ( pipe = dev->pipes; pipe; pipe = pipe->next ) {
1306 if (pipe->wanted != 0)
1307 goldfish_pipe_wake(pipe, pipe->wanted);
1308 if (pipe->closed != 0)
1309 goldfish_pipe_close(pipe);
1310 }
1311 return 0;
1312 }
1313
1314 /* initialize the trace device */
pipe_dev_init(bool newDeviceNaming)1315 void pipe_dev_init(bool newDeviceNaming)
1316 {
1317 PipeDevice *s;
1318
1319 s = (PipeDevice *) g_malloc0(sizeof(*s));
1320
1321 s->dev.name = newDeviceNaming ? "goldfish_pipe" : "qemu_pipe";
1322 s->dev.id = -1;
1323 s->dev.base = 0; // will be allocated dynamically
1324 s->dev.size = 0x2000;
1325 s->dev.irq = 0;
1326 s->dev.irq_count = 1;
1327
1328 goldfish_device_add(&s->dev, pipe_dev_readfn, pipe_dev_writefn, s);
1329
1330 register_savevm(NULL,
1331 "goldfish_pipe",
1332 0,
1333 GOLDFISH_PIPE_SAVE_VERSION,
1334 goldfish_pipe_save,
1335 goldfish_pipe_load,
1336 s);
1337
1338 #if DEBUG_ZERO_PIPE
1339 goldfish_pipe_add_type("zero", NULL, &zeroPipe_funcs);
1340 #endif
1341 #if DEBUG_PINGPONG_PIPE
1342 goldfish_pipe_add_type("pingpong", NULL, &pingPongPipe_funcs);
1343 #endif
1344 #if DEBUG_THROTTLE_PIPE
1345 goldfish_pipe_add_type("throttle", NULL, &throttlePipe_funcs);
1346 #endif
1347 }
1348
1349 void
goldfish_pipe_wake(void * hwpipe,unsigned flags)1350 goldfish_pipe_wake( void* hwpipe, unsigned flags )
1351 {
1352 Pipe* pipe = hwpipe;
1353 Pipe** lookup;
1354 PipeDevice* dev = pipe->device;
1355
1356 DD("%s: channel=0x%llx flags=%d", __FUNCTION__, (unsigned long long)pipe->channel, flags);
1357
1358 /* If not already there, add to the list of signaled pipes */
1359 lookup = pipe_list_findp_waked(&dev->signaled_pipes, pipe);
1360 if (!*lookup) {
1361 pipe->next_waked = dev->signaled_pipes;
1362 dev->signaled_pipes = pipe;
1363 }
1364 pipe->wanted |= (unsigned)flags;
1365
1366 /* Raise IRQ to indicate there are items on our list ! */
1367 goldfish_device_set_irq(&dev->dev, 0, 1);
1368 DD("%s: raising IRQ", __FUNCTION__);
1369 }
1370
1371 void
goldfish_pipe_close(void * hwpipe)1372 goldfish_pipe_close( void* hwpipe )
1373 {
1374 Pipe* pipe = hwpipe;
1375
1376 D("%s: channel=0x%llx (closed=%d)", __FUNCTION__, (unsigned long long)pipe->channel, pipe->closed);
1377
1378 if (!pipe->closed) {
1379 pipe->closed = 1;
1380 goldfish_pipe_wake( hwpipe, PIPE_WAKE_CLOSED );
1381 }
1382 }
1383