1 /*
2  * ntfy.h
3  *
4  * DSP-BIOS Bridge driver support functions for TI OMAP processors.
5  *
6  * Manage lists of notification events.
7  *
8  * Copyright (C) 2005-2006 Texas Instruments, Inc.
9  *
10  * This package is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License version 2 as
12  * published by the Free Software Foundation.
13  *
14  * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17  */
18 
19 #ifndef NTFY_
20 #define NTFY_
21 
22 #include <dspbridge/host_os.h>
23 #include <dspbridge/dbdefs.h>
24 #include <dspbridge/sync.h>
25 
26 /**
27  * ntfy_object - head structure to nofify dspbridge events
28  * @head:	List of notify objects
29  * @ntfy_lock:	lock for list access.
30  *
31  */
32 struct ntfy_object {
33 	struct raw_notifier_head head;/* List of notifier objects */
34 	spinlock_t ntfy_lock;	/* For critical sections */
35 };
36 
37 /**
38  * ntfy_event - structure store specify event to be notified
39  * @noti_block:	List of notify objects
40  * @event:	event that it respond
41  * @type: 	event type (only DSP_SIGNALEVENT supported)
42  * @sync_obj:	sync_event used to set the event
43  *
44  */
45 struct ntfy_event {
46 	struct notifier_block noti_block;
47 	u32 event;	/* Events to be notified about */
48 	u32 type;	/* Type of notification to be sent */
49 	struct sync_object sync_obj;
50 };
51 
52 
53 /**
54  * dsp_notifier_event() - callback function to nofity events
55  * @this:		pointer to itself struct notifier_block
56  * @event:	event to be notified.
57  * @data:		Currently not used.
58  *
59  */
60 int dsp_notifier_event(struct notifier_block *this, unsigned long event,
61 			   void *data);
62 
63 /**
64  * ntfy_init() - Set the initial state of the ntfy_object structure.
65  * @no:		pointer to ntfy_object structure.
66  *
67  * This function sets the initial state of the ntfy_object in order it
68  * can be used by the other ntfy functions.
69  */
70 
ntfy_init(struct ntfy_object * no)71 static inline void ntfy_init(struct ntfy_object *no)
72 {
73 	spin_lock_init(&no->ntfy_lock);
74 	RAW_INIT_NOTIFIER_HEAD(&no->head);
75 }
76 
77 /**
78  * ntfy_delete() - delete list of nofy events registered.
79  * @ntfy_obj:	Pointer to the ntfy object structure.
80  *
81  * This function is used to remove all the notify events  registered.
82  * unregister function is not needed in this function, to unregister
83  * a ntfy_event please look at ntfy_register function.
84  *
85  */
ntfy_delete(struct ntfy_object * ntfy_obj)86 static inline void ntfy_delete(struct ntfy_object *ntfy_obj)
87 {
88 	struct ntfy_event *ne;
89 	struct notifier_block *nb;
90 
91 	spin_lock_bh(&ntfy_obj->ntfy_lock);
92 	nb = ntfy_obj->head.head;
93 	while (nb) {
94 		ne = container_of(nb, struct ntfy_event, noti_block);
95 		nb = nb->next;
96 		kfree(ne);
97 	}
98 	spin_unlock_bh(&ntfy_obj->ntfy_lock);
99 }
100 
101 /**
102  * ntfy_notify() - nofity all event register for an specific event.
103  * @ntfy_obj:	Pointer to the ntfy_object structure.
104  * @event:	event to be notified.
105  *
106  * This function traverses all the ntfy events registers and
107  * set the event with mach with @event.
108  */
ntfy_notify(struct ntfy_object * ntfy_obj,u32 event)109 static inline void ntfy_notify(struct ntfy_object *ntfy_obj, u32 event)
110 {
111 	spin_lock_bh(&ntfy_obj->ntfy_lock);
112 	raw_notifier_call_chain(&ntfy_obj->head, event, NULL);
113 	spin_unlock_bh(&ntfy_obj->ntfy_lock);
114 }
115 
116 
117 
118 /**
119  * ntfy_init() - Create and initialize a ntfy_event structure.
120  * @event:	event that the ntfy event will respond
121  * @type		event type (only DSP_SIGNALEVENT supported)
122  *
123  * This function create a ntfy_event element and sets the event it will
124  * respond the ntfy_event in order it can be used by the other ntfy functions.
125  * In case of success it will return a pointer to the ntfy_event struct
126  * created. Otherwise it will return NULL;
127  */
128 
ntfy_event_create(u32 event,u32 type)129 static inline struct ntfy_event *ntfy_event_create(u32 event, u32 type)
130 {
131 	struct ntfy_event *ne;
132 	ne = kmalloc(sizeof(struct ntfy_event), GFP_KERNEL);
133 	if (ne) {
134 		sync_init_event(&ne->sync_obj);
135 		ne->noti_block.notifier_call = dsp_notifier_event;
136 		ne->event = event;
137 		ne->type = type;
138 	}
139 	return ne;
140 }
141 
142 /**
143  * ntfy_register() - register new ntfy_event into a given ntfy_object
144  * @ntfy_obj:	Pointer to the ntfy_object structure.
145  * @noti:		Pointer to the handle to be returned to the user space.
146  * @event	event that the ntfy event will respond
147  * @type		event type (only DSP_SIGNALEVENT supported)
148  *
149  * This function register a new ntfy_event into the ntfy_object list,
150  * which will respond to the @event passed.
151  * This function will return 0 in case of error.
152  * -EFAULT in case of bad pointers and
153  * DSP_EMemory in case of no memory to create ntfy_event.
154  */
ntfy_register(struct ntfy_object * ntfy_obj,struct dsp_notification * noti,u32 event,u32 type)155 static  inline int ntfy_register(struct ntfy_object *ntfy_obj,
156 			 struct dsp_notification *noti,
157 			 u32 event, u32 type)
158 {
159 	struct ntfy_event *ne;
160 	int status = 0;
161 
162 	if (!noti || !ntfy_obj) {
163 		status = -EFAULT;
164 		goto func_end;
165 	}
166 	if (!event) {
167 		status = -EINVAL;
168 		goto func_end;
169 	}
170 	ne = ntfy_event_create(event, type);
171 	if (!ne) {
172 		status = -ENOMEM;
173 		goto func_end;
174 	}
175 	noti->handle = &ne->sync_obj;
176 
177 	spin_lock_bh(&ntfy_obj->ntfy_lock);
178 	raw_notifier_chain_register(&ntfy_obj->head, &ne->noti_block);
179 	spin_unlock_bh(&ntfy_obj->ntfy_lock);
180 func_end:
181 	return status;
182 }
183 
184 /**
185  * ntfy_unregister() - unregister a ntfy_event from a given ntfy_object
186  * @ntfy_obj:	Pointer to the ntfy_object structure.
187  * @noti:		Pointer to the event that will be removed.
188  *
189  * This function unregister a ntfy_event from the ntfy_object list,
190  * @noti contains the event which is wanted to be removed.
191  * This function will return 0 in case of error.
192  * -EFAULT in case of bad pointers and
193  * DSP_EMemory in case of no memory to create ntfy_event.
194  */
ntfy_unregister(struct ntfy_object * ntfy_obj,struct dsp_notification * noti)195 static  inline int ntfy_unregister(struct ntfy_object *ntfy_obj,
196 			 struct dsp_notification *noti)
197 {
198 	int status = 0;
199 	struct ntfy_event *ne;
200 
201 	if (!noti || !ntfy_obj) {
202 		status = -EFAULT;
203 		goto func_end;
204 	}
205 
206 	ne = container_of((struct sync_object *)noti, struct ntfy_event,
207 								sync_obj);
208 	spin_lock_bh(&ntfy_obj->ntfy_lock);
209 	raw_notifier_chain_unregister(&ntfy_obj->head,
210 						&ne->noti_block);
211 	kfree(ne);
212 	spin_unlock_bh(&ntfy_obj->ntfy_lock);
213 func_end:
214 	return status;
215 }
216 
217 #endif				/* NTFY_ */
218