1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 Copyright (C) 2006 Sebastien Granjoux
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "data_buffer.h"
23 #include "anjuta-marshal.h"
26 #include <libanjuta/anjuta-debug.h>
29 #include <glib/gprintf.h>
33 DMA_DATA_BUFFER_PAGE_SIZE
= 512,
34 DMA_DATA_BUFFER_LAST_LEVEL_SIZE
= 8,
35 DMA_DATA_BUFFER_LEVEL_SIZE
= 16,
36 DMA_DATA_BUFFER_LEVEL
= 6
41 DMA_DATA_UNDEFINED
= 0,
42 DMA_DATA_MODIFIED
= 1,
46 typedef struct _DmaDataBufferPage DmaDataBufferPage
;
47 typedef struct _DmaDataBufferNode DmaDataBufferNode
;
48 typedef struct _DmaDataBufferLastNode DmaDataBufferLastNode
;
50 struct _DmaDataBufferPage
52 gchar data
[DMA_DATA_BUFFER_PAGE_SIZE
];
53 gchar tag
[DMA_DATA_BUFFER_PAGE_SIZE
];
57 struct _DmaDataBufferNode
59 DmaDataBufferNode
*child
[DMA_DATA_BUFFER_LEVEL_SIZE
];
62 struct _DmaDataBufferLastNode
64 DmaDataBufferPage
*child
[DMA_DATA_BUFFER_LAST_LEVEL_SIZE
];
74 DmaDataBufferReadFunc read
;
75 DmaDataBufferWriteFunc write
;
79 DmaDataBufferNode
*top
;
82 struct _DmaDataBufferClass
86 void (*changed_notify
) (DmaDataBuffer
*buffer
, gulong lower
, gulong upper
);
89 static GObjectClass
*parent_class
= NULL
;
91 typedef gchar
* (*DmaDisplayDataFunc
) (gchar
*string
, const char *data
, const char *tag
);
99 static guint signals
[LAST_SIGNAL
] = {0};
103 *---------------------------------------------------------------------------*/
106 display_in_octal (gchar
*string
, const gchar
*data
, const gchar
*tag
)
108 if ((data
== NULL
) || (*tag
== DMA_DATA_UNDEFINED
))
110 memcpy(string
, "??? ", 4);
114 g_sprintf (string
, "%03o ", ((unsigned)*data
) & 0xFFU
);
121 display_in_decimal (gchar
*string
, const gchar
*data
, const gchar
*tag
)
123 if ((data
== NULL
) || (*tag
== DMA_DATA_UNDEFINED
))
125 memcpy(string
, "??? ", 4);
129 g_sprintf (string
, "% 3u ", ((unsigned)*data
) & 0xFFU
);
136 display_in_hexadecimal (gchar
*string
, const gchar
*data
, const gchar
*tag
)
138 if ((data
== NULL
) || (*tag
== DMA_DATA_UNDEFINED
))
140 memcpy(string
, "?? ", 3);
144 g_sprintf (string
, "%02X ", ((unsigned)*data
) & 0xFFU
);
151 display_in_ascii (gchar
*string
, const gchar
*data
, const gchar
*tag
)
153 if ((data
== NULL
) || (*tag
== DMA_DATA_UNDEFINED
))
157 else if (g_ascii_isprint (*data
))
169 /* DmaBufferNode functions
170 *---------------------------------------------------------------------------*/
172 static DmaDataBufferNode
**
173 dma_data_buffer_find_node (DmaDataBuffer
*buffer
, gulong address
)
175 DmaDataBufferNode
**node
;
179 address
/= DMA_DATA_BUFFER_PAGE_SIZE
;
180 for (i
= DMA_DATA_BUFFER_LEVEL
- 1; i
>= 0; --i
)
186 *node
= (DmaDataBufferNode
*)g_new0 (DmaDataBufferLastNode
, 1);
190 *node
= g_new0 (DmaDataBufferNode
, 1);
193 node
= &((*node
)->child
[address
% (i
== 0 ? DMA_DATA_BUFFER_LAST_LEVEL_SIZE
: DMA_DATA_BUFFER_LEVEL_SIZE
)]);
194 address
/= DMA_DATA_BUFFER_LEVEL_SIZE
;
201 static DmaDataBufferPage
*
202 dma_data_buffer_get_page (DmaDataBuffer
*buffer
, gulong address
)
204 DmaDataBufferNode
**node
;
206 node
= dma_data_buffer_find_node (buffer
, address
);
208 return (DmaDataBufferPage
*)*node
;
212 static DmaDataBufferPage
*
213 dma_data_buffer_add_page (DmaDataBuffer
*buffer
, gulong address
)
215 DmaDataBufferNode
**node
;
216 DmaDataBufferPage
*page
;
218 node
= dma_data_buffer_find_node (buffer
, address
);
222 *node
= (DmaDataBufferNode
*)g_new0 (DmaDataBufferPage
, 1);
223 page
= (DmaDataBufferPage
*)*node
;
224 page
->validation
= buffer
->validation
- 1;
228 page
= (DmaDataBufferPage
*)*node
;
234 static DmaDataBufferPage
*
235 dma_data_buffer_read_page (DmaDataBuffer
*buffer
, gulong address
)
237 DmaDataBufferPage
*page
;
239 page
= dma_data_buffer_add_page (buffer
, address
);
241 if ((page
== NULL
) || (page
->validation
!= buffer
->validation
))
243 if (page
!= NULL
) page
->validation
= buffer
->validation
;
244 /* Data need to be refresh */
245 if (buffer
->read
!= NULL
);
246 buffer
->read (address
- (address
% DMA_DATA_BUFFER_PAGE_SIZE
), DMA_DATA_BUFFER_PAGE_SIZE
, buffer
->user_data
);
256 dma_data_buffer_free_node (DmaDataBufferNode
*node
, gint level
)
260 for (i
= (level
== 0 ? DMA_DATA_BUFFER_LAST_LEVEL_SIZE
: DMA_DATA_BUFFER_LEVEL_SIZE
) - 1; i
>= 0; --i
)
262 if (node
->child
[i
] != NULL
)
266 dma_data_buffer_free_node (node
->child
[i
], level
- 1);
268 g_free (node
->child
[i
]);
274 *---------------------------------------------------------------------------*/
278 dma_data_buffer_changed_notify (DmaDataBuffer
*buffer
, gulong lower
, gulong upper
)
283 *---------------------------------------------------------------------------*/
286 dma_data_buffer_remove_all_page (DmaDataBuffer
*buffer
)
288 if (buffer
->top
!= NULL
)
290 dma_data_buffer_free_node (buffer
->top
, DMA_DATA_BUFFER_LEVEL
- 1);
291 g_free (buffer
->top
);
297 dma_data_buffer_get_lower (const DmaDataBuffer
*buffer
)
299 return buffer
->lower
;
303 dma_data_buffer_get_upper (const DmaDataBuffer
*buffer
)
305 return buffer
->upper
;
309 dma_data_buffer_get_address (DmaDataBuffer
*buffer
, gulong lower
, guint length
, guint step
, guint size
)
315 line
= (length
+ step
- 1) / step
;
317 data
= g_strnfill (line
* (size
+ 1), ' ');
318 for (ptr
= data
; line
!= 0; --line
)
320 g_sprintf (ptr
, "%0*lx\n", size
, lower
);
330 dma_data_buffer_get_data (DmaDataBuffer
*buffer
, gulong lower
, guint length
, guint step
, gint base
)
332 static const DmaDisplayDataFunc format_table
[] = {display_in_octal
,
334 display_in_hexadecimal
,
340 DmaDisplayDataFunc display
;
347 line
= (length
+ step
- 1) / step
;
349 switch (base
& DMA_DATA_BASE
)
352 case DMA_DECIMAL_BASE
:
353 case DMA_HEXADECIMAL_BASE
:
355 display
= format_table
[base
& DMA_DATA_BASE
];
358 display
= format_table
[DMA_HEXADECIMAL_BASE
];
362 /* Dummy call of display function to know the increment */
363 ptr
= display (dummy
, NULL
, NULL
);
366 text
= g_strnfill (line
* (step
* inc
+ 1), ' ');
368 for (ptr
= text
; line
!= 0; --line
)
370 for (col
= step
; col
!= 0; --col
)
374 DmaDataBufferPage
*node
;
376 node
= dma_data_buffer_read_page (buffer
, lower
);
384 data
= &(node
->data
[lower
% DMA_DATA_BUFFER_PAGE_SIZE
]);
385 tag
= &(node
->tag
[lower
% DMA_DATA_BUFFER_PAGE_SIZE
]);
387 len
= DMA_DATA_BUFFER_PAGE_SIZE
- (lower
% DMA_DATA_BUFFER_PAGE_SIZE
);
389 ptr
= display (ptr
, data
, tag
);
398 if (inc
!= 1) --ptr
; /* Remove last space */
401 *(ptr
- 1) = '\0'; /* Remove last carriage return */
407 dma_data_buffer_invalidate (DmaDataBuffer
*buffer
)
409 buffer
->validation
++;
413 dma_data_buffer_set_data (DmaDataBuffer
*buffer
, gulong address
, gulong length
, const gchar
*data
)
418 if (length
== 0) return;
420 upper
= address
+ length
-1UL;
425 DmaDataBufferPage
*page
;
428 page
= dma_data_buffer_add_page (buffer
, address
);
429 len
= DMA_DATA_BUFFER_PAGE_SIZE
- (address
% DMA_DATA_BUFFER_PAGE_SIZE
);
430 if (len
> length
) len
= length
;
431 memcpy (&page
->data
[address
% DMA_DATA_BUFFER_PAGE_SIZE
], data
, len
);
432 memset (&page
->tag
[address
% DMA_DATA_BUFFER_PAGE_SIZE
], DMA_DATA_MODIFIED
, len
);
433 page
->validation
= buffer
->validation
;
438 g_signal_emit (buffer
, signals
[CHANGED_NOTIFY
], 0, lower
, upper
);
442 *---------------------------------------------------------------------------*/
444 /* Used in dispose and finalize */
446 /* dispose is the first destruction step. It is used to unref object created
447 * with instance_init in order to break reference counting cycles. This
448 * function could be called several times. All function should still work
449 * after this call. It has to called its parents.*/
452 dma_data_buffer_dispose (GObject
*object
)
454 /*DmaDataBuffer *this = DMA_DATA_BUFFER (object);*/
456 (* parent_class
->dispose
) (object
);
459 /* finalize is the last destruction step. It must free all memory allocated
460 * with instance_init. It is called only one time just before releasing all
464 dma_data_buffer_finalize (GObject
*object
)
466 DmaDataBuffer
*buffer
= DMA_DATA_BUFFER (object
);
468 dma_data_buffer_remove_all_page (buffer
);
470 (* parent_class
->finalize
) (object
);
473 /* instance_init is the constructor. All functions should work after this
477 dma_data_buffer_instance_init (DmaDataBuffer
*this)
484 /* class_init intialize the class itself not the instance */
487 dma_data_buffer_class_init (DmaDataBufferClass
* klass
)
489 GObjectClass
*object_class
;
491 g_return_if_fail (klass
!= NULL
);
493 parent_class
= G_OBJECT_CLASS (g_type_class_peek_parent (klass
));
495 object_class
= G_OBJECT_CLASS (klass
);
496 object_class
->dispose
= dma_data_buffer_dispose
;
497 object_class
->finalize
= dma_data_buffer_finalize
;
499 klass
->changed_notify
= dma_data_buffer_changed_notify
;
501 signals
[CHANGED_NOTIFY
] = g_signal_new ("changed_notify",
502 G_OBJECT_CLASS_TYPE (object_class
),
504 G_STRUCT_OFFSET (DmaDataBufferClass
, changed_notify
),
506 anjuta_marshal_VOID__ULONG_ULONG
,
514 dma_data_buffer_get_type (void)
516 static GType type
= 0;
520 static const GTypeInfo type_info
=
522 sizeof (DmaDataBufferClass
),
523 (GBaseInitFunc
) NULL
,
524 (GBaseFinalizeFunc
) NULL
,
525 (GClassInitFunc
) dma_data_buffer_class_init
,
526 (GClassFinalizeFunc
) NULL
,
527 NULL
, /* class_data */
528 sizeof (DmaDataBuffer
),
530 (GInstanceInitFunc
) dma_data_buffer_instance_init
,
531 NULL
/* value_table */
534 type
= g_type_register_static (G_TYPE_OBJECT
,
535 "DmaDataBuffer", &type_info
, 0);
541 /* Creation and Destruction
542 *---------------------------------------------------------------------------*/
545 dma_data_buffer_new (gulong lower
, gulong upper
, DmaDataBufferReadFunc read
, DmaDataBufferWriteFunc write
, gpointer user_data
)
547 DmaDataBuffer
*buffer
;
549 buffer
= g_object_new (DMA_DATA_BUFFER_TYPE
, NULL
);
550 g_assert (buffer
!= NULL
);
552 buffer
->lower
= lower
;
553 buffer
->upper
= upper
;
555 buffer
->write
= write
;
556 buffer
->user_data
= user_data
;
562 dma_data_buffer_free (DmaDataBuffer
*buffer
)
564 g_object_unref (buffer
);