diff options
Diffstat (limited to 'arch/arm/plat-omap/mailbox.c')
-rw-r--r-- | arch/arm/plat-omap/mailbox.c | 291 |
1 files changed, 58 insertions, 233 deletions
diff --git a/arch/arm/plat-omap/mailbox.c b/arch/arm/plat-omap/mailbox.c index 40424edae939..08a2df766289 100644 --- a/arch/arm/plat-omap/mailbox.c +++ b/arch/arm/plat-omap/mailbox.c | |||
@@ -25,56 +25,15 @@ | |||
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/device.h> | 26 | #include <linux/device.h> |
27 | #include <linux/delay.h> | 27 | #include <linux/delay.h> |
28 | #include <linux/slab.h> | ||
28 | 29 | ||
29 | #include <mach/mailbox.h> | 30 | #include <plat/mailbox.h> |
30 | |||
31 | static int enable_seq_bit; | ||
32 | module_param(enable_seq_bit, bool, 0); | ||
33 | MODULE_PARM_DESC(enable_seq_bit, "Enable sequence bit checking."); | ||
34 | 31 | ||
32 | static struct workqueue_struct *mboxd; | ||
35 | static struct omap_mbox *mboxes; | 33 | static struct omap_mbox *mboxes; |
36 | static DEFINE_RWLOCK(mboxes_lock); | 34 | static DEFINE_RWLOCK(mboxes_lock); |
37 | 35 | ||
38 | /* | 36 | static int mbox_configured; |
39 | * Mailbox sequence bit API | ||
40 | */ | ||
41 | |||
42 | /* seq_rcv should be initialized with any value other than | ||
43 | * 0 and 1 << 31, to allow either value for the first | ||
44 | * message. */ | ||
45 | static inline void mbox_seq_init(struct omap_mbox *mbox) | ||
46 | { | ||
47 | if (!enable_seq_bit) | ||
48 | return; | ||
49 | |||
50 | /* any value other than 0 and 1 << 31 */ | ||
51 | mbox->seq_rcv = 0xffffffff; | ||
52 | } | ||
53 | |||
54 | static inline void mbox_seq_toggle(struct omap_mbox *mbox, mbox_msg_t * msg) | ||
55 | { | ||
56 | if (!enable_seq_bit) | ||
57 | return; | ||
58 | |||
59 | /* add seq_snd to msg */ | ||
60 | *msg = (*msg & 0x7fffffff) | mbox->seq_snd; | ||
61 | /* flip seq_snd */ | ||
62 | mbox->seq_snd ^= 1 << 31; | ||
63 | } | ||
64 | |||
65 | static inline int mbox_seq_test(struct omap_mbox *mbox, mbox_msg_t msg) | ||
66 | { | ||
67 | mbox_msg_t seq; | ||
68 | |||
69 | if (!enable_seq_bit) | ||
70 | return 0; | ||
71 | |||
72 | seq = msg & (1 << 31); | ||
73 | if (seq == mbox->seq_rcv) | ||
74 | return -1; | ||
75 | mbox->seq_rcv = seq; | ||
76 | return 0; | ||
77 | } | ||
78 | 37 | ||
79 | /* Mailbox FIFO handle functions */ | 38 | /* Mailbox FIFO handle functions */ |
80 | static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) | 39 | static inline mbox_msg_t mbox_fifo_read(struct omap_mbox *mbox) |
@@ -95,14 +54,6 @@ static inline int mbox_fifo_full(struct omap_mbox *mbox) | |||
95 | } | 54 | } |
96 | 55 | ||
97 | /* Mailbox IRQ handle functions */ | 56 | /* Mailbox IRQ handle functions */ |
98 | static inline void enable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | ||
99 | { | ||
100 | mbox->ops->enable_irq(mbox, irq); | ||
101 | } | ||
102 | static inline void disable_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | ||
103 | { | ||
104 | mbox->ops->disable_irq(mbox, irq); | ||
105 | } | ||
106 | static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | 57 | static inline void ack_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) |
107 | { | 58 | { |
108 | if (mbox->ops->ack_irq) | 59 | if (mbox->ops->ack_irq) |
@@ -113,17 +64,10 @@ static inline int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq) | |||
113 | return mbox->ops->is_irq(mbox, irq); | 64 | return mbox->ops->is_irq(mbox, irq); |
114 | } | 65 | } |
115 | 66 | ||
116 | /* Mailbox Sequence Bit function */ | ||
117 | void omap_mbox_init_seq(struct omap_mbox *mbox) | ||
118 | { | ||
119 | mbox_seq_init(mbox); | ||
120 | } | ||
121 | EXPORT_SYMBOL(omap_mbox_init_seq); | ||
122 | |||
123 | /* | 67 | /* |
124 | * message sender | 68 | * message sender |
125 | */ | 69 | */ |
126 | static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg) | 70 | static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) |
127 | { | 71 | { |
128 | int ret = 0, i = 1000; | 72 | int ret = 0, i = 1000; |
129 | 73 | ||
@@ -134,89 +78,49 @@ static int __mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void *arg) | |||
134 | return -1; | 78 | return -1; |
135 | udelay(1); | 79 | udelay(1); |
136 | } | 80 | } |
137 | |||
138 | if (arg && mbox->txq->callback) { | ||
139 | ret = mbox->txq->callback(arg); | ||
140 | if (ret) | ||
141 | goto out; | ||
142 | } | ||
143 | |||
144 | mbox_seq_toggle(mbox, &msg); | ||
145 | mbox_fifo_write(mbox, msg); | 81 | mbox_fifo_write(mbox, msg); |
146 | out: | ||
147 | return ret; | 82 | return ret; |
148 | } | 83 | } |
149 | 84 | ||
150 | struct omap_msg_tx_data { | ||
151 | mbox_msg_t msg; | ||
152 | void *arg; | ||
153 | }; | ||
154 | 85 | ||
155 | static void omap_msg_tx_end_io(struct request *rq, int error) | 86 | int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg) |
156 | { | 87 | { |
157 | kfree(rq->special); | ||
158 | __blk_put_request(rq->q, rq); | ||
159 | } | ||
160 | 88 | ||
161 | int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg, void* arg) | ||
162 | { | ||
163 | struct omap_msg_tx_data *tx_data; | ||
164 | struct request *rq; | 89 | struct request *rq; |
165 | struct request_queue *q = mbox->txq->queue; | 90 | struct request_queue *q = mbox->txq->queue; |
166 | 91 | ||
167 | tx_data = kmalloc(sizeof(*tx_data), GFP_ATOMIC); | ||
168 | if (unlikely(!tx_data)) | ||
169 | return -ENOMEM; | ||
170 | |||
171 | rq = blk_get_request(q, WRITE, GFP_ATOMIC); | 92 | rq = blk_get_request(q, WRITE, GFP_ATOMIC); |
172 | if (unlikely(!rq)) { | 93 | if (unlikely(!rq)) |
173 | kfree(tx_data); | ||
174 | return -ENOMEM; | 94 | return -ENOMEM; |
175 | } | ||
176 | 95 | ||
177 | tx_data->msg = msg; | 96 | blk_insert_request(q, rq, 0, (void *) msg); |
178 | tx_data->arg = arg; | 97 | tasklet_schedule(&mbox->txq->tasklet); |
179 | rq->end_io = omap_msg_tx_end_io; | ||
180 | blk_insert_request(q, rq, 0, tx_data); | ||
181 | 98 | ||
182 | schedule_work(&mbox->txq->work); | ||
183 | return 0; | 99 | return 0; |
184 | } | 100 | } |
185 | EXPORT_SYMBOL(omap_mbox_msg_send); | 101 | EXPORT_SYMBOL(omap_mbox_msg_send); |
186 | 102 | ||
187 | static void mbox_tx_work(struct work_struct *work) | 103 | static void mbox_tx_tasklet(unsigned long tx_data) |
188 | { | 104 | { |
189 | int ret; | 105 | int ret; |
190 | struct request *rq; | 106 | struct request *rq; |
191 | struct omap_mbox_queue *mq = container_of(work, | 107 | struct omap_mbox *mbox = (struct omap_mbox *)tx_data; |
192 | struct omap_mbox_queue, work); | ||
193 | struct omap_mbox *mbox = mq->queue->queuedata; | ||
194 | struct request_queue *q = mbox->txq->queue; | 108 | struct request_queue *q = mbox->txq->queue; |
195 | 109 | ||
196 | while (1) { | 110 | while (1) { |
197 | struct omap_msg_tx_data *tx_data; | ||
198 | 111 | ||
199 | spin_lock(q->queue_lock); | ||
200 | rq = blk_fetch_request(q); | 112 | rq = blk_fetch_request(q); |
201 | spin_unlock(q->queue_lock); | ||
202 | 113 | ||
203 | if (!rq) | 114 | if (!rq) |
204 | break; | 115 | break; |
205 | 116 | ||
206 | tx_data = rq->special; | 117 | ret = __mbox_msg_send(mbox, (mbox_msg_t)rq->special); |
207 | |||
208 | ret = __mbox_msg_send(mbox, tx_data->msg, tx_data->arg); | ||
209 | if (ret) { | 118 | if (ret) { |
210 | enable_mbox_irq(mbox, IRQ_TX); | 119 | omap_mbox_enable_irq(mbox, IRQ_TX); |
211 | spin_lock(q->queue_lock); | ||
212 | blk_requeue_request(q, rq); | 120 | blk_requeue_request(q, rq); |
213 | spin_unlock(q->queue_lock); | ||
214 | return; | 121 | return; |
215 | } | 122 | } |
216 | 123 | blk_end_request_all(rq, 0); | |
217 | spin_lock(q->queue_lock); | ||
218 | __blk_end_request_all(rq, 0); | ||
219 | spin_unlock(q->queue_lock); | ||
220 | } | 124 | } |
221 | } | 125 | } |
222 | 126 | ||
@@ -233,11 +137,6 @@ static void mbox_rx_work(struct work_struct *work) | |||
233 | mbox_msg_t msg; | 137 | mbox_msg_t msg; |
234 | unsigned long flags; | 138 | unsigned long flags; |
235 | 139 | ||
236 | if (mbox->rxq->callback == NULL) { | ||
237 | sysfs_notify(&mbox->dev->kobj, NULL, "mbox"); | ||
238 | return; | ||
239 | } | ||
240 | |||
241 | while (1) { | 140 | while (1) { |
242 | spin_lock_irqsave(q->queue_lock, flags); | 141 | spin_lock_irqsave(q->queue_lock, flags); |
243 | rq = blk_fetch_request(q); | 142 | rq = blk_fetch_request(q); |
@@ -254,19 +153,19 @@ static void mbox_rx_work(struct work_struct *work) | |||
254 | /* | 153 | /* |
255 | * Mailbox interrupt handler | 154 | * Mailbox interrupt handler |
256 | */ | 155 | */ |
257 | static void mbox_txq_fn(struct request_queue * q) | 156 | static void mbox_txq_fn(struct request_queue *q) |
258 | { | 157 | { |
259 | } | 158 | } |
260 | 159 | ||
261 | static void mbox_rxq_fn(struct request_queue * q) | 160 | static void mbox_rxq_fn(struct request_queue *q) |
262 | { | 161 | { |
263 | } | 162 | } |
264 | 163 | ||
265 | static void __mbox_tx_interrupt(struct omap_mbox *mbox) | 164 | static void __mbox_tx_interrupt(struct omap_mbox *mbox) |
266 | { | 165 | { |
267 | disable_mbox_irq(mbox, IRQ_TX); | 166 | omap_mbox_disable_irq(mbox, IRQ_TX); |
268 | ack_mbox_irq(mbox, IRQ_TX); | 167 | ack_mbox_irq(mbox, IRQ_TX); |
269 | schedule_work(&mbox->txq->work); | 168 | tasklet_schedule(&mbox->txq->tasklet); |
270 | } | 169 | } |
271 | 170 | ||
272 | static void __mbox_rx_interrupt(struct omap_mbox *mbox) | 171 | static void __mbox_rx_interrupt(struct omap_mbox *mbox) |
@@ -275,8 +174,6 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox) | |||
275 | mbox_msg_t msg; | 174 | mbox_msg_t msg; |
276 | struct request_queue *q = mbox->rxq->queue; | 175 | struct request_queue *q = mbox->rxq->queue; |
277 | 176 | ||
278 | disable_mbox_irq(mbox, IRQ_RX); | ||
279 | |||
280 | while (!mbox_fifo_empty(mbox)) { | 177 | while (!mbox_fifo_empty(mbox)) { |
281 | rq = blk_get_request(q, WRITE, GFP_ATOMIC); | 178 | rq = blk_get_request(q, WRITE, GFP_ATOMIC); |
282 | if (unlikely(!rq)) | 179 | if (unlikely(!rq)) |
@@ -284,11 +181,6 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox) | |||
284 | 181 | ||
285 | msg = mbox_fifo_read(mbox); | 182 | msg = mbox_fifo_read(mbox); |
286 | 183 | ||
287 | if (unlikely(mbox_seq_test(mbox, msg))) { | ||
288 | pr_info("mbox: Illegal seq bit!(%08x)\n", msg); | ||
289 | if (mbox->err_notify) | ||
290 | mbox->err_notify(); | ||
291 | } | ||
292 | 184 | ||
293 | blk_insert_request(q, rq, 0, (void *)msg); | 185 | blk_insert_request(q, rq, 0, (void *)msg); |
294 | if (mbox->ops->type == OMAP_MBOX_TYPE1) | 186 | if (mbox->ops->type == OMAP_MBOX_TYPE1) |
@@ -297,9 +189,8 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox) | |||
297 | 189 | ||
298 | /* no more messages in the fifo. clear IRQ source. */ | 190 | /* no more messages in the fifo. clear IRQ source. */ |
299 | ack_mbox_irq(mbox, IRQ_RX); | 191 | ack_mbox_irq(mbox, IRQ_RX); |
300 | enable_mbox_irq(mbox, IRQ_RX); | ||
301 | nomem: | 192 | nomem: |
302 | schedule_work(&mbox->rxq->work); | 193 | queue_work(mboxd, &mbox->rxq->work); |
303 | } | 194 | } |
304 | 195 | ||
305 | static irqreturn_t mbox_interrupt(int irq, void *p) | 196 | static irqreturn_t mbox_interrupt(int irq, void *p) |
@@ -315,76 +206,10 @@ static irqreturn_t mbox_interrupt(int irq, void *p) | |||
315 | return IRQ_HANDLED; | 206 | return IRQ_HANDLED; |
316 | } | 207 | } |
317 | 208 | ||
318 | /* | ||
319 | * sysfs files | ||
320 | */ | ||
321 | static ssize_t | ||
322 | omap_mbox_write(struct device *dev, struct device_attribute *attr, | ||
323 | const char * buf, size_t count) | ||
324 | { | ||
325 | int ret; | ||
326 | mbox_msg_t *p = (mbox_msg_t *)buf; | ||
327 | struct omap_mbox *mbox = dev_get_drvdata(dev); | ||
328 | |||
329 | for (; count >= sizeof(mbox_msg_t); count -= sizeof(mbox_msg_t)) { | ||
330 | ret = omap_mbox_msg_send(mbox, be32_to_cpu(*p), NULL); | ||
331 | if (ret) | ||
332 | return -EAGAIN; | ||
333 | p++; | ||
334 | } | ||
335 | |||
336 | return (size_t)((char *)p - buf); | ||
337 | } | ||
338 | |||
339 | static ssize_t | ||
340 | omap_mbox_read(struct device *dev, struct device_attribute *attr, char *buf) | ||
341 | { | ||
342 | unsigned long flags; | ||
343 | struct request *rq; | ||
344 | mbox_msg_t *p = (mbox_msg_t *) buf; | ||
345 | struct omap_mbox *mbox = dev_get_drvdata(dev); | ||
346 | struct request_queue *q = mbox->rxq->queue; | ||
347 | |||
348 | while (1) { | ||
349 | spin_lock_irqsave(q->queue_lock, flags); | ||
350 | rq = blk_fetch_request(q); | ||
351 | spin_unlock_irqrestore(q->queue_lock, flags); | ||
352 | |||
353 | if (!rq) | ||
354 | break; | ||
355 | |||
356 | *p = (mbox_msg_t)rq->special; | ||
357 | |||
358 | blk_end_request_all(rq, 0); | ||
359 | |||
360 | if (unlikely(mbox_seq_test(mbox, *p))) { | ||
361 | pr_info("mbox: Illegal seq bit!(%08x) ignored\n", *p); | ||
362 | continue; | ||
363 | } | ||
364 | p++; | ||
365 | } | ||
366 | |||
367 | pr_debug("%02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3]); | ||
368 | |||
369 | return (size_t) ((char *)p - buf); | ||
370 | } | ||
371 | |||
372 | static DEVICE_ATTR(mbox, S_IRUGO | S_IWUSR, omap_mbox_read, omap_mbox_write); | ||
373 | |||
374 | static ssize_t mbox_show(struct class *class, char *buf) | ||
375 | { | ||
376 | return sprintf(buf, "mbox"); | ||
377 | } | ||
378 | |||
379 | static CLASS_ATTR(mbox, S_IRUGO, mbox_show, NULL); | ||
380 | |||
381 | static struct class omap_mbox_class = { | ||
382 | .name = "omap-mailbox", | ||
383 | }; | ||
384 | |||
385 | static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, | 209 | static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, |
386 | request_fn_proc * proc, | 210 | request_fn_proc *proc, |
387 | void (*work) (struct work_struct *)) | 211 | void (*work) (struct work_struct *), |
212 | void (*tasklet)(unsigned long)) | ||
388 | { | 213 | { |
389 | struct request_queue *q; | 214 | struct request_queue *q; |
390 | struct omap_mbox_queue *mq; | 215 | struct omap_mbox_queue *mq; |
@@ -401,8 +226,11 @@ static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox, | |||
401 | q->queuedata = mbox; | 226 | q->queuedata = mbox; |
402 | mq->queue = q; | 227 | mq->queue = q; |
403 | 228 | ||
404 | INIT_WORK(&mq->work, work); | 229 | if (work) |
230 | INIT_WORK(&mq->work, work); | ||
405 | 231 | ||
232 | if (tasklet) | ||
233 | tasklet_init(&mq->tasklet, tasklet, (unsigned long)mbox); | ||
406 | return mq; | 234 | return mq; |
407 | error: | 235 | error: |
408 | kfree(mq); | 236 | kfree(mq); |
@@ -415,18 +243,25 @@ static void mbox_queue_free(struct omap_mbox_queue *q) | |||
415 | kfree(q); | 243 | kfree(q); |
416 | } | 244 | } |
417 | 245 | ||
418 | static int omap_mbox_init(struct omap_mbox *mbox) | 246 | static int omap_mbox_startup(struct omap_mbox *mbox) |
419 | { | 247 | { |
420 | int ret; | 248 | int ret = 0; |
421 | struct omap_mbox_queue *mq; | 249 | struct omap_mbox_queue *mq; |
422 | 250 | ||
423 | if (likely(mbox->ops->startup)) { | 251 | if (likely(mbox->ops->startup)) { |
424 | ret = mbox->ops->startup(mbox); | 252 | write_lock(&mboxes_lock); |
425 | if (unlikely(ret)) | 253 | if (!mbox_configured) |
254 | ret = mbox->ops->startup(mbox); | ||
255 | |||
256 | if (unlikely(ret)) { | ||
257 | write_unlock(&mboxes_lock); | ||
426 | return ret; | 258 | return ret; |
259 | } | ||
260 | mbox_configured++; | ||
261 | write_unlock(&mboxes_lock); | ||
427 | } | 262 | } |
428 | 263 | ||
429 | ret = request_irq(mbox->irq, mbox_interrupt, IRQF_DISABLED, | 264 | ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED, |
430 | mbox->name, mbox); | 265 | mbox->name, mbox); |
431 | if (unlikely(ret)) { | 266 | if (unlikely(ret)) { |
432 | printk(KERN_ERR | 267 | printk(KERN_ERR |
@@ -434,14 +269,14 @@ static int omap_mbox_init(struct omap_mbox *mbox) | |||
434 | goto fail_request_irq; | 269 | goto fail_request_irq; |
435 | } | 270 | } |
436 | 271 | ||
437 | mq = mbox_queue_alloc(mbox, mbox_txq_fn, mbox_tx_work); | 272 | mq = mbox_queue_alloc(mbox, mbox_txq_fn, NULL, mbox_tx_tasklet); |
438 | if (!mq) { | 273 | if (!mq) { |
439 | ret = -ENOMEM; | 274 | ret = -ENOMEM; |
440 | goto fail_alloc_txq; | 275 | goto fail_alloc_txq; |
441 | } | 276 | } |
442 | mbox->txq = mq; | 277 | mbox->txq = mq; |
443 | 278 | ||
444 | mq = mbox_queue_alloc(mbox, mbox_rxq_fn, mbox_rx_work); | 279 | mq = mbox_queue_alloc(mbox, mbox_rxq_fn, mbox_rx_work, NULL); |
445 | if (!mq) { | 280 | if (!mq) { |
446 | ret = -ENOMEM; | 281 | ret = -ENOMEM; |
447 | goto fail_alloc_rxq; | 282 | goto fail_alloc_rxq; |
@@ -468,8 +303,14 @@ static void omap_mbox_fini(struct omap_mbox *mbox) | |||
468 | 303 | ||
469 | free_irq(mbox->irq, mbox); | 304 | free_irq(mbox->irq, mbox); |
470 | 305 | ||
471 | if (unlikely(mbox->ops->shutdown)) | 306 | if (unlikely(mbox->ops->shutdown)) { |
472 | mbox->ops->shutdown(mbox); | 307 | write_lock(&mboxes_lock); |
308 | if (mbox_configured > 0) | ||
309 | mbox_configured--; | ||
310 | if (!mbox_configured) | ||
311 | mbox->ops->shutdown(mbox); | ||
312 | write_unlock(&mboxes_lock); | ||
313 | } | ||
473 | } | 314 | } |
474 | 315 | ||
475 | static struct omap_mbox **find_mboxes(const char *name) | 316 | static struct omap_mbox **find_mboxes(const char *name) |
@@ -498,7 +339,7 @@ struct omap_mbox *omap_mbox_get(const char *name) | |||
498 | 339 | ||
499 | read_unlock(&mboxes_lock); | 340 | read_unlock(&mboxes_lock); |
500 | 341 | ||
501 | ret = omap_mbox_init(mbox); | 342 | ret = omap_mbox_startup(mbox); |
502 | if (ret) | 343 | if (ret) |
503 | return ERR_PTR(-ENODEV); | 344 | return ERR_PTR(-ENODEV); |
504 | 345 | ||
@@ -522,15 +363,6 @@ int omap_mbox_register(struct device *parent, struct omap_mbox *mbox) | |||
522 | if (mbox->next) | 363 | if (mbox->next) |
523 | return -EBUSY; | 364 | return -EBUSY; |
524 | 365 | ||
525 | mbox->dev = device_create(&omap_mbox_class, | ||
526 | parent, 0, mbox, "%s", mbox->name); | ||
527 | if (IS_ERR(mbox->dev)) | ||
528 | return PTR_ERR(mbox->dev); | ||
529 | |||
530 | ret = device_create_file(mbox->dev, &dev_attr_mbox); | ||
531 | if (ret) | ||
532 | goto err_sysfs; | ||
533 | |||
534 | write_lock(&mboxes_lock); | 366 | write_lock(&mboxes_lock); |
535 | tmp = find_mboxes(mbox->name); | 367 | tmp = find_mboxes(mbox->name); |
536 | if (*tmp) { | 368 | if (*tmp) { |
@@ -544,9 +376,6 @@ int omap_mbox_register(struct device *parent, struct omap_mbox *mbox) | |||
544 | return 0; | 376 | return 0; |
545 | 377 | ||
546 | err_find: | 378 | err_find: |
547 | device_remove_file(mbox->dev, &dev_attr_mbox); | ||
548 | err_sysfs: | ||
549 | device_unregister(mbox->dev); | ||
550 | return ret; | 379 | return ret; |
551 | } | 380 | } |
552 | EXPORT_SYMBOL(omap_mbox_register); | 381 | EXPORT_SYMBOL(omap_mbox_register); |
@@ -562,8 +391,6 @@ int omap_mbox_unregister(struct omap_mbox *mbox) | |||
562 | *tmp = mbox->next; | 391 | *tmp = mbox->next; |
563 | mbox->next = NULL; | 392 | mbox->next = NULL; |
564 | write_unlock(&mboxes_lock); | 393 | write_unlock(&mboxes_lock); |
565 | device_remove_file(mbox->dev, &dev_attr_mbox); | ||
566 | device_unregister(mbox->dev); | ||
567 | return 0; | 394 | return 0; |
568 | } | 395 | } |
569 | tmp = &(*tmp)->next; | 396 | tmp = &(*tmp)->next; |
@@ -574,23 +401,21 @@ int omap_mbox_unregister(struct omap_mbox *mbox) | |||
574 | } | 401 | } |
575 | EXPORT_SYMBOL(omap_mbox_unregister); | 402 | EXPORT_SYMBOL(omap_mbox_unregister); |
576 | 403 | ||
577 | static int __init omap_mbox_class_init(void) | 404 | static int __init omap_mbox_init(void) |
578 | { | 405 | { |
579 | int ret = class_register(&omap_mbox_class); | 406 | mboxd = create_workqueue("mboxd"); |
580 | if (!ret) | 407 | if (!mboxd) |
581 | ret = class_create_file(&omap_mbox_class, &class_attr_mbox); | 408 | return -ENOMEM; |
582 | 409 | ||
583 | return ret; | 410 | return 0; |
584 | } | 411 | } |
412 | module_init(omap_mbox_init); | ||
585 | 413 | ||
586 | static void __exit omap_mbox_class_exit(void) | 414 | static void __exit omap_mbox_exit(void) |
587 | { | 415 | { |
588 | class_remove_file(&omap_mbox_class, &class_attr_mbox); | 416 | destroy_workqueue(mboxd); |
589 | class_unregister(&omap_mbox_class); | ||
590 | } | 417 | } |
591 | 418 | module_exit(omap_mbox_exit); | |
592 | subsys_initcall(omap_mbox_class_init); | ||
593 | module_exit(omap_mbox_class_exit); | ||
594 | 419 | ||
595 | MODULE_LICENSE("GPL v2"); | 420 | MODULE_LICENSE("GPL v2"); |
596 | MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging"); | 421 | MODULE_DESCRIPTION("omap mailbox: interrupt driven messaging"); |