Merge branch 'topic/asoc' into for-linus
[linux-2.6] / drivers / staging / meilhaus / medlock.c
1 /**
2  * @file medlock.c
3  *
4  * @brief Implements the device lock class.
5  * @note Copyright (C) 2006 Meilhaus Electronic GmbH (support@meilhaus.de)
6  * @author Guenter Gebhardt
7  */
8
9 /*
10  * Copyright (C) 2007 Meilhaus Electronic GmbH (support@meilhaus.de)
11  *
12  * This file is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  */
26
27 #include <linux/spinlock.h>
28
29 #include "medefines.h"
30 #include "meerror.h"
31
32 #include "medebug.h"
33 #include "meslist.h"
34 #include "mesubdevice.h"
35 #include "medlock.h"
36
37 int me_dlock_enter(struct me_dlock *dlock, struct file *filep)
38 {
39         PDEBUG_LOCKS("executed.\n");
40
41         spin_lock(&dlock->spin_lock);
42
43         if ((dlock->filep) != NULL && (dlock->filep != filep)) {
44                 PERROR("Device is locked by another process.\n");
45                 spin_unlock(&dlock->spin_lock);
46                 return ME_ERRNO_LOCKED;
47         }
48
49         dlock->count++;
50
51         spin_unlock(&dlock->spin_lock);
52
53         return ME_ERRNO_SUCCESS;
54 }
55
56 int me_dlock_exit(struct me_dlock *dlock, struct file *filep)
57 {
58         PDEBUG_LOCKS("executed.\n");
59
60         spin_lock(&dlock->spin_lock);
61         dlock->count--;
62         spin_unlock(&dlock->spin_lock);
63
64         return ME_ERRNO_SUCCESS;
65 }
66
67 int me_dlock_lock(struct me_dlock *dlock,
68                   struct file *filep, int lock, int flags, me_slist_t *slist)
69 {
70         int err = ME_ERRNO_SUCCESS;
71         int i;
72         me_subdevice_t *subdevice;
73
74         PDEBUG_LOCKS("executed.\n");
75
76         spin_lock(&dlock->spin_lock);
77
78         switch (lock) {
79
80         case ME_LOCK_RELEASE:
81                 if ((dlock->filep == filep) || (dlock->filep == NULL)) {
82                         dlock->filep = NULL;
83
84                         /* Unlock all possibly locked subdevices. */
85
86                         for (i = 0; i < me_slist_get_number_subdevices(slist);
87                              i++) {
88                                 subdevice = me_slist_get_subdevice(slist, i);
89
90                                 if (subdevice)
91                                         err =
92                                             subdevice->
93                                             me_subdevice_lock_subdevice
94                                             (subdevice, filep, ME_LOCK_RELEASE,
95                                              flags);
96                                 else
97                                         err = ME_ERRNO_INTERNAL;
98                         }
99                 }
100
101                 break;
102
103         case ME_LOCK_SET:
104                 if (dlock->count) {
105                         PERROR("Device is used by another process.\n");
106                         err = ME_ERRNO_USED;
107                 } else if ((dlock->filep != NULL) && (dlock->filep != filep)) {
108                         PERROR("Device is locked by another process.\n");
109                         err = ME_ERRNO_LOCKED;
110                 } else if (dlock->filep == NULL) {
111                         /* Check any subdevice is locked by another process. */
112
113                         for (i = 0; i < me_slist_get_number_subdevices(slist);
114                              i++) {
115                                 subdevice = me_slist_get_subdevice(slist, i);
116
117                                 if (subdevice) {
118                                         if ((err =
119                                              subdevice->
120                                              me_subdevice_lock_subdevice
121                                              (subdevice, filep, ME_LOCK_CHECK,
122                                               flags))) {
123                                                 PERROR
124                                                     ("A subdevice is locked by another process.\n");
125                                                 break;
126                                         }
127                                 } else {
128                                         err = ME_ERRNO_INTERNAL;
129                                 }
130                         }
131
132                         /* If no subdevices are locked by other processes,
133                            we can take ownership of the device. Otherwise we jump ahead. */
134                         if (!err)
135                                 dlock->filep = filep;
136                 }
137
138                 break;
139
140         case ME_LOCK_CHECK:
141                 if (dlock->count) {
142                         err = ME_ERRNO_USED;
143                 } else if ((dlock->filep != NULL) && (dlock->filep != filep)) {
144                         err = ME_ERRNO_LOCKED;
145                 } else if (dlock->filep == NULL) {
146                         for (i = 0; i < me_slist_get_number_subdevices(slist);
147                              i++) {
148                                 subdevice = me_slist_get_subdevice(slist, i);
149
150                                 if (subdevice) {
151                                         if ((err =
152                                              subdevice->
153                                              me_subdevice_lock_subdevice
154                                              (subdevice, filep, ME_LOCK_CHECK,
155                                               flags))) {
156                                                 PERROR
157                                                     ("A subdevice is locked by another process.\n");
158                                                 break;
159                                         }
160                                 } else {
161                                         err = ME_ERRNO_INTERNAL;
162                                 }
163                         }
164                 }
165
166                 break;
167
168         default:
169                 PERROR("Invalid lock.\n");
170
171                 err = ME_ERRNO_INVALID_LOCK;
172
173                 break;
174         }
175
176         spin_unlock(&dlock->spin_lock);
177
178         return err;
179 }
180
181 void me_dlock_deinit(struct me_dlock *dlock)
182 {
183         PDEBUG_LOCKS("executed.\n");
184 }
185
186 int me_dlock_init(me_dlock_t *dlock)
187 {
188         PDEBUG_LOCKS("executed.\n");
189
190         dlock->filep = NULL;
191         dlock->count = 0;
192         spin_lock_init(&dlock->spin_lock);
193
194         return 0;
195 }