Blame view
arch/mips/kernel/rtlx.c
12.2 KB
e01402b11 More AP / SP bits... |
1 2 |
/* * Copyright (C) 2005 MIPS Technologies, Inc. All rights reserved. |
a84c96e20 [MIPS] RTLX compi... |
3 |
* Copyright (C) 2005, 06 Ralf Baechle (ralf@linux-mips.org) |
e01402b11 More AP / SP bits... |
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
* * This program is free software; you can distribute it and/or modify it * under the terms of the GNU General Public License (Version 2) as * published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. * */ |
bb3d7c7ff [MIPS] RTLX: Spri... |
19 |
#include <linux/device.h> |
e01402b11 More AP / SP bits... |
20 |
#include <linux/kernel.h> |
e01402b11 More AP / SP bits... |
21 22 |
#include <linux/fs.h> #include <linux/init.h> |
2600990e6 [MIPS] kpsd and o... |
23 |
#include <asm/uaccess.h> |
2600990e6 [MIPS] kpsd and o... |
24 25 26 27 28 29 |
#include <linux/list.h> #include <linux/vmalloc.h> #include <linux/elf.h> #include <linux/seq_file.h> #include <linux/syscalls.h> #include <linux/moduleloader.h> |
a84c96e20 [MIPS] RTLX compi... |
30 |
#include <linux/interrupt.h> |
e01402b11 More AP / SP bits... |
31 32 33 34 |
#include <linux/poll.h> #include <linux/sched.h> #include <linux/wait.h> #include <asm/mipsmtregs.h> |
bb3d7c7ff [MIPS] RTLX: Spri... |
35 |
#include <asm/mips_mt.h> |
2600990e6 [MIPS] kpsd and o... |
36 |
#include <asm/cacheflush.h> |
60063497a atomic: use <linu... |
37 |
#include <linux/atomic.h> |
e01402b11 More AP / SP bits... |
38 39 |
#include <asm/cpu.h> #include <asm/processor.h> |
2600990e6 [MIPS] kpsd and o... |
40 41 |
#include <asm/system.h> #include <asm/vpe.h> |
e01402b11 More AP / SP bits... |
42 |
#include <asm/rtlx.h> |
afc4841d8 Turn rtlx upside ... |
43 |
static struct rtlx_info *rtlx; |
e01402b11 More AP / SP bits... |
44 45 |
static int major; static char module_name[] = "rtlx"; |
e01402b11 More AP / SP bits... |
46 47 48 49 |
static struct chan_waitqueues { wait_queue_head_t rt_queue; wait_queue_head_t lx_queue; |
c4c4018b0 [MIPS] RTLX, VPE:... |
50 |
atomic_t in_open; |
bc4809e93 [MIPS] RTLX: Prot... |
51 |
struct mutex mutex; |
e01402b11 More AP / SP bits... |
52 |
} channel_wqs[RTLX_CHANNELS]; |
2600990e6 [MIPS] kpsd and o... |
53 |
static struct vpe_notifications notify; |
982f6ffee MIPS: Remove usel... |
54 |
static int sp_stopping; |
2600990e6 [MIPS] kpsd and o... |
55 |
|
e01402b11 More AP / SP bits... |
56 |
extern void *vpe_get_shared(int index); |
937a80157 [MIPS] Complete f... |
57 |
static void rtlx_dispatch(void) |
e01402b11 More AP / SP bits... |
58 |
{ |
97dcb82de [MIPS] Define MIP... |
59 |
do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ); |
e01402b11 More AP / SP bits... |
60 |
} |
2600990e6 [MIPS] kpsd and o... |
61 62 63 64 |
/* Interrupt handler may be called before rtlx_init has otherwise had a chance to run. */ |
937a80157 [MIPS] Complete f... |
65 |
static irqreturn_t rtlx_interrupt(int irq, void *dev_id) |
e01402b11 More AP / SP bits... |
66 |
{ |
1bbfc20d0 MIPS: VPE: Get ri... |
67 68 |
unsigned int vpeflags; unsigned long flags; |
e01402b11 More AP / SP bits... |
69 |
int i; |
1928cc84a [MIPS] MT: Functi... |
70 71 72 73 74 75 76 77 |
/* Ought not to be strictly necessary for SMTC builds */ local_irq_save(flags); vpeflags = dvpe(); set_c0_status(0x100 << MIPS_CPU_RTLX_IRQ); irq_enable_hazard(); evpe(vpeflags); local_irq_restore(flags); |
e01402b11 More AP / SP bits... |
78 79 |
for (i = 0; i < RTLX_CHANNELS; i++) { |
2600990e6 [MIPS] kpsd and o... |
80 81 |
wake_up(&channel_wqs[i].lx_queue); wake_up(&channel_wqs[i].rt_queue); |
e01402b11 More AP / SP bits... |
82 |
} |
afc4841d8 Turn rtlx upside ... |
83 |
return IRQ_HANDLED; |
e01402b11 More AP / SP bits... |
84 |
} |
f5dbeaf5e [MIPS] Replace __... |
85 |
static void __used dump_rtlx(void) |
e01402b11 More AP / SP bits... |
86 87 |
{ int i; |
2600990e6 [MIPS] kpsd and o... |
88 89 |
printk("id 0x%lx state %d ", rtlx->id, rtlx->state); |
e01402b11 More AP / SP bits... |
90 |
|
e01402b11 More AP / SP bits... |
91 |
for (i = 0; i < RTLX_CHANNELS; i++) { |
2600990e6 [MIPS] kpsd and o... |
92 |
struct rtlx_channel *chan = &rtlx->channel[i]; |
e01402b11 More AP / SP bits... |
93 |
|
2600990e6 [MIPS] kpsd and o... |
94 95 96 |
printk(" rt_state %d lx_state %d buffer_size %d ", chan->rt_state, chan->lx_state, chan->buffer_size); |
e01402b11 More AP / SP bits... |
97 |
|
2600990e6 [MIPS] kpsd and o... |
98 99 100 |
printk(" rt_read %d rt_write %d ", chan->rt_read, chan->rt_write); |
e01402b11 More AP / SP bits... |
101 |
|
2600990e6 [MIPS] kpsd and o... |
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
printk(" lx_read %d lx_write %d ", chan->lx_read, chan->lx_write); printk(" rt_buffer <%s> ", chan->rt_buffer); printk(" lx_buffer <%s> ", chan->lx_buffer); } } /* call when we have the address of the shared structure from the SP side. */ static int rtlx_init(struct rtlx_info *rtlxi) { if (rtlxi->id != RTLX_ID) { |
1928cc84a [MIPS] MT: Functi... |
117 118 119 |
printk(KERN_ERR "no valid RTLX id at 0x%p 0x%lx ", rtlxi, rtlxi->id); |
2600990e6 [MIPS] kpsd and o... |
120 121 |
return -ENOEXEC; } |
e01402b11 More AP / SP bits... |
122 123 |
rtlx = rtlxi; |
afc4841d8 Turn rtlx upside ... |
124 125 |
return 0; |
e01402b11 More AP / SP bits... |
126 |
} |
2600990e6 [MIPS] kpsd and o... |
127 128 |
/* notifications */ static void starting(int vpe) |
e01402b11 More AP / SP bits... |
129 |
{ |
2600990e6 [MIPS] kpsd and o... |
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
int i; sp_stopping = 0; /* force a reload of rtlx */ rtlx=NULL; /* wake up any sleeping rtlx_open's */ for (i = 0; i < RTLX_CHANNELS; i++) wake_up_interruptible(&channel_wqs[i].lx_queue); } static void stopping(int vpe) { int i; sp_stopping = 1; for (i = 0; i < RTLX_CHANNELS; i++) wake_up_interruptible(&channel_wqs[i].lx_queue); } int rtlx_open(int index, int can_sleep) { |
9e3468202 [MIPS] RTLX: Don'... |
153 |
struct rtlx_info **p; |
67e2cccec [MIPS] RTLX: Hand... |
154 |
struct rtlx_channel *chan; |
c4c4018b0 [MIPS] RTLX, VPE:... |
155 |
enum rtlx_state state; |
67e2cccec [MIPS] RTLX: Hand... |
156 |
int ret = 0; |
e01402b11 More AP / SP bits... |
157 |
|
2600990e6 [MIPS] kpsd and o... |
158 159 160 161 162 |
if (index >= RTLX_CHANNELS) { printk(KERN_DEBUG "rtlx_open index out of range "); return -ENOSYS; } |
c4c4018b0 [MIPS] RTLX, VPE:... |
163 164 165 166 167 168 |
if (atomic_inc_return(&channel_wqs[index].in_open) > 1) { printk(KERN_DEBUG "rtlx_open channel %d already opened ", index); ret = -EBUSY; goto out_fail; |
2600990e6 [MIPS] kpsd and o... |
169 |
} |
e01402b11 More AP / SP bits... |
170 |
if (rtlx == NULL) { |
07cc0c9e6 [MIPS] MT: Enable... |
171 |
if( (p = vpe_get_shared(tclimit)) == NULL) { |
1928cc84a [MIPS] MT: Functi... |
172 173 174 175 |
if (can_sleep) { __wait_event_interruptible(channel_wqs[index].lx_queue, (p = vpe_get_shared(tclimit)), ret); if (ret) |
67e2cccec [MIPS] RTLX: Hand... |
176 |
goto out_fail; |
1928cc84a [MIPS] MT: Functi... |
177 178 179 180 181 182 183 |
} else { printk(KERN_DEBUG "No SP program loaded, and device " "opened with O_NONBLOCK "); ret = -ENOSYS; goto out_fail; } |
e01402b11 More AP / SP bits... |
184 |
} |
9e3468202 [MIPS] RTLX: Don'... |
185 |
smp_rmb(); |
e01402b11 More AP / SP bits... |
186 |
if (*p == NULL) { |
2600990e6 [MIPS] kpsd and o... |
187 |
if (can_sleep) { |
9e3468202 [MIPS] RTLX: Don'... |
188 189 190 |
DEFINE_WAIT(wait); for (;;) { |
1928cc84a [MIPS] MT: Functi... |
191 192 193 |
prepare_to_wait( &channel_wqs[index].lx_queue, &wait, TASK_INTERRUPTIBLE); |
9e3468202 [MIPS] RTLX: Don'... |
194 195 196 197 198 199 200 201 |
smp_rmb(); if (*p != NULL) break; if (!signal_pending(current)) { schedule(); continue; } ret = -ERESTARTSYS; |
67e2cccec [MIPS] RTLX: Hand... |
202 |
goto out_fail; |
9e3468202 [MIPS] RTLX: Don'... |
203 204 |
} finish_wait(&channel_wqs[index].lx_queue, &wait); |
67e2cccec [MIPS] RTLX: Hand... |
205 |
} else { |
1928cc84a [MIPS] MT: Functi... |
206 |
pr_err(" *vpe_get_shared is NULL. " |
2600990e6 [MIPS] kpsd and o... |
207 208 |
"Has an SP program been loaded? "); |
67e2cccec [MIPS] RTLX: Hand... |
209 210 |
ret = -ENOSYS; goto out_fail; |
2600990e6 [MIPS] kpsd and o... |
211 212 213 214 |
} } if ((unsigned int)*p < KSEG0) { |
1928cc84a [MIPS] MT: Functi... |
215 216 217 218 |
printk(KERN_WARNING "vpe_get_shared returned an " "invalid pointer maybe an error code %d ", (int)*p); |
67e2cccec [MIPS] RTLX: Hand... |
219 220 |
ret = -ENOSYS; goto out_fail; |
e01402b11 More AP / SP bits... |
221 |
} |
c4c4018b0 [MIPS] RTLX, VPE:... |
222 223 |
if ((ret = rtlx_init(*p)) < 0) goto out_ret; |
e01402b11 More AP / SP bits... |
224 |
} |
2600990e6 [MIPS] kpsd and o... |
225 |
chan = &rtlx->channel[index]; |
e01402b11 More AP / SP bits... |
226 |
|
c4c4018b0 [MIPS] RTLX, VPE:... |
227 228 229 230 231 |
state = xchg(&chan->lx_state, RTLX_STATE_OPENED); if (state == RTLX_STATE_OPENED) { ret = -EBUSY; goto out_fail; } |
67e2cccec [MIPS] RTLX: Hand... |
232 233 |
out_fail: |
c4c4018b0 [MIPS] RTLX, VPE:... |
234 235 236 |
smp_mb(); atomic_dec(&channel_wqs[index].in_open); smp_mb(); |
67e2cccec [MIPS] RTLX: Hand... |
237 |
|
c4c4018b0 [MIPS] RTLX, VPE:... |
238 |
out_ret: |
67e2cccec [MIPS] RTLX: Hand... |
239 |
return ret; |
e01402b11 More AP / SP bits... |
240 |
} |
2600990e6 [MIPS] kpsd and o... |
241 |
int rtlx_release(int index) |
e01402b11 More AP / SP bits... |
242 |
{ |
1928cc84a [MIPS] MT: Functi... |
243 244 245 246 247 |
if (rtlx == NULL) { pr_err("rtlx_release() with null rtlx "); return 0; } |
2600990e6 [MIPS] kpsd and o... |
248 |
rtlx->channel[index].lx_state = RTLX_STATE_UNUSED; |
afc4841d8 Turn rtlx upside ... |
249 |
return 0; |
e01402b11 More AP / SP bits... |
250 |
} |
2600990e6 [MIPS] kpsd and o... |
251 |
unsigned int rtlx_read_poll(int index, int can_sleep) |
e01402b11 More AP / SP bits... |
252 |
{ |
2600990e6 [MIPS] kpsd and o... |
253 |
struct rtlx_channel *chan; |
e01402b11 More AP / SP bits... |
254 |
|
2600990e6 [MIPS] kpsd and o... |
255 256 |
if (rtlx == NULL) return 0; |
e01402b11 More AP / SP bits... |
257 |
|
2600990e6 [MIPS] kpsd and o... |
258 |
chan = &rtlx->channel[index]; |
e01402b11 More AP / SP bits... |
259 260 |
/* data available to read? */ |
2600990e6 [MIPS] kpsd and o... |
261 262 |
if (chan->lx_read == chan->lx_write) { if (can_sleep) { |
67e2cccec [MIPS] RTLX: Hand... |
263 |
int ret = 0; |
e01402b11 More AP / SP bits... |
264 |
|
67e2cccec [MIPS] RTLX: Hand... |
265 |
__wait_event_interruptible(channel_wqs[index].lx_queue, |
1928cc84a [MIPS] MT: Functi... |
266 267 |
(chan->lx_read != chan->lx_write) || sp_stopping, ret); |
67e2cccec [MIPS] RTLX: Hand... |
268 269 |
if (ret) return ret; |
e01402b11 More AP / SP bits... |
270 |
|
67e2cccec [MIPS] RTLX: Hand... |
271 272 273 |
if (sp_stopping) return 0; } else |
2600990e6 [MIPS] kpsd and o... |
274 275 276 277 278 |
return 0; } return (chan->lx_write + chan->buffer_size - chan->lx_read) % chan->buffer_size; |
e01402b11 More AP / SP bits... |
279 |
} |
2600990e6 [MIPS] kpsd and o... |
280 |
static inline int write_spacefree(int read, int write, int size) |
e01402b11 More AP / SP bits... |
281 |
{ |
2600990e6 [MIPS] kpsd and o... |
282 283 284 285 286 287 288 |
if (read == write) { /* * Never fill the buffer completely, so indexes are always * equal if empty and only empty, or !equal if data available */ return size - 1; } |
e01402b11 More AP / SP bits... |
289 |
|
2600990e6 [MIPS] kpsd and o... |
290 291 |
return ((read + size - write) % size) - 1; } |
e01402b11 More AP / SP bits... |
292 |
|
2600990e6 [MIPS] kpsd and o... |
293 294 295 |
unsigned int rtlx_write_poll(int index) { struct rtlx_channel *chan = &rtlx->channel[index]; |
1928cc84a [MIPS] MT: Functi... |
296 297 298 |
return write_spacefree(chan->rt_read, chan->rt_write, chan->buffer_size); |
2600990e6 [MIPS] kpsd and o... |
299 |
} |
e01402b11 More AP / SP bits... |
300 |
|
7f5a7716d [MIPS] Fix AP/SP ... |
301 |
ssize_t rtlx_read(int index, void __user *buff, size_t count) |
2600990e6 [MIPS] kpsd and o... |
302 |
{ |
61dcc6f4d [MIPS] RTLX: Hard... |
303 |
size_t lx_write, fl = 0L; |
2600990e6 [MIPS] kpsd and o... |
304 |
struct rtlx_channel *lx; |
46230aa6e [MIPS] RTLX: Hand... |
305 |
unsigned long failed; |
e01402b11 More AP / SP bits... |
306 |
|
2600990e6 [MIPS] kpsd and o... |
307 308 309 310 |
if (rtlx == NULL) return -ENOSYS; lx = &rtlx->channel[index]; |
e01402b11 More AP / SP bits... |
311 |
|
bc4809e93 [MIPS] RTLX: Prot... |
312 |
mutex_lock(&channel_wqs[index].mutex); |
61dcc6f4d [MIPS] RTLX: Hard... |
313 314 |
smp_rmb(); lx_write = lx->lx_write; |
e01402b11 More AP / SP bits... |
315 |
/* find out how much in total */ |
afc4841d8 Turn rtlx upside ... |
316 |
count = min(count, |
61dcc6f4d [MIPS] RTLX: Hard... |
317 |
(size_t)(lx_write + lx->buffer_size - lx->lx_read) |
2600990e6 [MIPS] kpsd and o... |
318 |
% lx->buffer_size); |
e01402b11 More AP / SP bits... |
319 320 |
/* then how much from the read pointer onwards */ |
61dcc6f4d [MIPS] RTLX: Hard... |
321 |
fl = min(count, (size_t)lx->buffer_size - lx->lx_read); |
e01402b11 More AP / SP bits... |
322 |
|
46230aa6e [MIPS] RTLX: Hand... |
323 324 325 |
failed = copy_to_user(buff, lx->lx_buffer + lx->lx_read, fl); if (failed) goto out; |
e01402b11 More AP / SP bits... |
326 327 |
/* and if there is anything left at the beginning of the buffer */ |
61dcc6f4d [MIPS] RTLX: Hard... |
328 |
if (count - fl) |
46230aa6e [MIPS] RTLX: Hand... |
329 330 331 332 |
failed = copy_to_user(buff + fl, lx->lx_buffer, count - fl); out: count -= failed; |
e01402b11 More AP / SP bits... |
333 |
|
61dcc6f4d [MIPS] RTLX: Hard... |
334 335 336 |
smp_wmb(); lx->lx_read = (lx->lx_read + count) % lx->buffer_size; smp_wmb(); |
bc4809e93 [MIPS] RTLX: Prot... |
337 |
mutex_unlock(&channel_wqs[index].mutex); |
e01402b11 More AP / SP bits... |
338 |
|
afc4841d8 Turn rtlx upside ... |
339 |
return count; |
e01402b11 More AP / SP bits... |
340 |
} |
7f5a7716d [MIPS] Fix AP/SP ... |
341 |
ssize_t rtlx_write(int index, const void __user *buffer, size_t count) |
2600990e6 [MIPS] kpsd and o... |
342 343 |
{ struct rtlx_channel *rt; |
7f5a7716d [MIPS] Fix AP/SP ... |
344 |
unsigned long failed; |
61dcc6f4d [MIPS] RTLX: Hard... |
345 |
size_t rt_read; |
2600990e6 [MIPS] kpsd and o... |
346 347 348 349 350 351 |
size_t fl; if (rtlx == NULL) return(-ENOSYS); rt = &rtlx->channel[index]; |
bc4809e93 [MIPS] RTLX: Prot... |
352 |
mutex_lock(&channel_wqs[index].mutex); |
61dcc6f4d [MIPS] RTLX: Hard... |
353 354 |
smp_rmb(); rt_read = rt->rt_read; |
2600990e6 [MIPS] kpsd and o... |
355 |
/* total number of bytes to copy */ |
1928cc84a [MIPS] MT: Functi... |
356 357 |
count = min(count, (size_t)write_spacefree(rt_read, rt->rt_write, rt->buffer_size)); |
2600990e6 [MIPS] kpsd and o... |
358 359 360 |
/* first bit from write pointer to the end of the buffer, or count */ fl = min(count, (size_t) rt->buffer_size - rt->rt_write); |
46230aa6e [MIPS] RTLX: Hand... |
361 362 363 |
failed = copy_from_user(rt->rt_buffer + rt->rt_write, buffer, fl); if (failed) goto out; |
2600990e6 [MIPS] kpsd and o... |
364 365 |
/* if there's any left copy to the beginning of the buffer */ |
46230aa6e [MIPS] RTLX: Hand... |
366 367 368 369 370 |
if (count - fl) { failed = copy_from_user(rt->rt_buffer, buffer + fl, count - fl); } out: |
7f5a7716d [MIPS] Fix AP/SP ... |
371 |
count -= failed; |
2600990e6 [MIPS] kpsd and o... |
372 |
|
61dcc6f4d [MIPS] RTLX: Hard... |
373 374 375 |
smp_wmb(); rt->rt_write = (rt->rt_write + count) % rt->buffer_size; smp_wmb(); |
bc4809e93 [MIPS] RTLX: Prot... |
376 |
mutex_unlock(&channel_wqs[index].mutex); |
2600990e6 [MIPS] kpsd and o... |
377 |
|
61dcc6f4d [MIPS] RTLX: Hard... |
378 |
return count; |
2600990e6 [MIPS] kpsd and o... |
379 380 381 382 383 |
} static int file_open(struct inode *inode, struct file *filp) { |
1bbfc20d0 MIPS: VPE: Get ri... |
384 |
return rtlx_open(iminor(inode), (filp->f_flags & O_NONBLOCK) ? 0 : 1); |
2600990e6 [MIPS] kpsd and o... |
385 386 387 388 |
} static int file_release(struct inode *inode, struct file *filp) { |
1bbfc20d0 MIPS: VPE: Get ri... |
389 |
return rtlx_release(iminor(inode)); |
2600990e6 [MIPS] kpsd and o... |
390 391 392 393 394 395 |
} static unsigned int file_poll(struct file *file, poll_table * wait) { int minor; unsigned int mask = 0; |
1b04fe9a8 [PATCH] struct pa... |
396 |
minor = iminor(file->f_path.dentry->d_inode); |
2600990e6 [MIPS] kpsd and o... |
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 |
poll_wait(file, &channel_wqs[minor].rt_queue, wait); poll_wait(file, &channel_wqs[minor].lx_queue, wait); if (rtlx == NULL) return 0; /* data available to read? */ if (rtlx_read_poll(minor, 0)) mask |= POLLIN | POLLRDNORM; /* space to write */ if (rtlx_write_poll(minor)) mask |= POLLOUT | POLLWRNORM; return mask; } static ssize_t file_read(struct file *file, char __user * buffer, size_t count, loff_t * ppos) { |
1b04fe9a8 [PATCH] struct pa... |
418 |
int minor = iminor(file->f_path.dentry->d_inode); |
2600990e6 [MIPS] kpsd and o... |
419 420 421 422 423 |
/* data available? */ if (!rtlx_read_poll(minor, (file->f_flags & O_NONBLOCK) ? 0 : 1)) { return 0; // -EAGAIN makes cat whinge } |
46230aa6e [MIPS] RTLX: Hand... |
424 |
return rtlx_read(minor, buffer, count); |
2600990e6 [MIPS] kpsd and o... |
425 426 427 |
} static ssize_t file_write(struct file *file, const char __user * buffer, |
e01402b11 More AP / SP bits... |
428 429 430 431 |
size_t count, loff_t * ppos) { int minor; struct rtlx_channel *rt; |
e01402b11 More AP / SP bits... |
432 |
|
1b04fe9a8 [PATCH] struct pa... |
433 |
minor = iminor(file->f_path.dentry->d_inode); |
e01402b11 More AP / SP bits... |
434 435 436 |
rt = &rtlx->channel[minor]; /* any space left... */ |
2600990e6 [MIPS] kpsd and o... |
437 |
if (!rtlx_write_poll(minor)) { |
67e2cccec [MIPS] RTLX: Hand... |
438 |
int ret = 0; |
e01402b11 More AP / SP bits... |
439 440 |
if (file->f_flags & O_NONBLOCK) |
afc4841d8 Turn rtlx upside ... |
441 |
return -EAGAIN; |
e01402b11 More AP / SP bits... |
442 |
|
67e2cccec [MIPS] RTLX: Hand... |
443 444 445 446 447 |
__wait_event_interruptible(channel_wqs[minor].rt_queue, rtlx_write_poll(minor), ret); if (ret) return ret; |
e01402b11 More AP / SP bits... |
448 |
} |
46230aa6e [MIPS] RTLX: Hand... |
449 |
return rtlx_write(minor, buffer, count); |
e01402b11 More AP / SP bits... |
450 |
} |
5dfe4c964 [PATCH] mark stru... |
451 |
static const struct file_operations rtlx_fops = { |
2600990e6 [MIPS] kpsd and o... |
452 453 454 455 456 |
.owner = THIS_MODULE, .open = file_open, .release = file_release, .write = file_write, .read = file_read, |
6038f373a llseek: automatic... |
457 458 |
.poll = file_poll, .llseek = noop_llseek, |
e01402b11 More AP / SP bits... |
459 |
}; |
2600990e6 [MIPS] kpsd and o... |
460 461 |
static struct irqaction rtlx_irq = { .handler = rtlx_interrupt, |
2600990e6 [MIPS] kpsd and o... |
462 463 |
.name = "RTLX", }; |
97dcb82de [MIPS] Define MIP... |
464 |
static int rtlx_irq_num = MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ; |
2600990e6 [MIPS] kpsd and o... |
465 |
|
afc4841d8 Turn rtlx upside ... |
466 467 468 |
static char register_chrdev_failed[] __initdata = KERN_ERR "rtlx_module_init: unable to register device "; |
9d5a3f5fa [MIPS] rtlx: Fix ... |
469 |
static int __init rtlx_module_init(void) |
e01402b11 More AP / SP bits... |
470 |
{ |
bb3d7c7ff [MIPS] RTLX: Spri... |
471 472 |
struct device *dev; int i, err; |
2600990e6 [MIPS] kpsd and o... |
473 |
|
07cc0c9e6 [MIPS] MT: Enable... |
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 |
if (!cpu_has_mipsmt) { printk("VPE loader: not a MIPS MT capable processor "); return -ENODEV; } if (tclimit == 0) { printk(KERN_WARNING "No TCs reserved for AP/SP, not " "initializing RTLX. Pass maxtcs=<n> argument as kernel " "argument "); return -ENODEV; } |
afc4841d8 Turn rtlx upside ... |
489 490 491 492 |
major = register_chrdev(0, module_name, &rtlx_fops); if (major < 0) { printk(register_chrdev_failed); return major; |
e01402b11 More AP / SP bits... |
493 |
} |
2600990e6 [MIPS] kpsd and o... |
494 495 496 497 |
/* initialise the wait queues */ for (i = 0; i < RTLX_CHANNELS; i++) { init_waitqueue_head(&channel_wqs[i].rt_queue); init_waitqueue_head(&channel_wqs[i].lx_queue); |
c4c4018b0 [MIPS] RTLX, VPE:... |
498 |
atomic_set(&channel_wqs[i].in_open, 0); |
bc4809e93 [MIPS] RTLX: Prot... |
499 |
mutex_init(&channel_wqs[i].mutex); |
bb3d7c7ff [MIPS] RTLX: Spri... |
500 |
|
a9b12619f device create: mi... |
501 502 |
dev = device_create(mt_class, NULL, MKDEV(major, i), NULL, "%s%d", module_name, i); |
bb3d7c7ff [MIPS] RTLX: Spri... |
503 504 505 506 |
if (IS_ERR(dev)) { err = PTR_ERR(dev); goto out_chrdev; } |
2600990e6 [MIPS] kpsd and o... |
507 508 509 510 511 |
} /* set up notifiers */ notify.start = starting; notify.stop = stopping; |
07cc0c9e6 [MIPS] MT: Enable... |
512 |
vpe_notify(tclimit, ¬ify); |
2600990e6 [MIPS] kpsd and o... |
513 514 515 |
if (cpu_has_vint) set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch); |
1928cc84a [MIPS] MT: Functi... |
516 517 518 519 520 521 |
else { pr_err("APRP RTLX init on non-vectored-interrupt processor "); err = -ENODEV; goto out_chrdev; } |
2600990e6 [MIPS] kpsd and o... |
522 523 524 |
rtlx_irq.dev_id = rtlx; setup_irq(rtlx_irq_num, &rtlx_irq); |
afc4841d8 Turn rtlx upside ... |
525 |
return 0; |
bb3d7c7ff [MIPS] RTLX: Spri... |
526 527 528 529 530 531 |
out_chrdev: for (i = 0; i < RTLX_CHANNELS; i++) device_destroy(mt_class, MKDEV(major, i)); return err; |
e01402b11 More AP / SP bits... |
532 |
} |
afc4841d8 Turn rtlx upside ... |
533 |
static void __exit rtlx_module_exit(void) |
e01402b11 More AP / SP bits... |
534 |
{ |
bb3d7c7ff [MIPS] RTLX: Spri... |
535 536 537 538 |
int i; for (i = 0; i < RTLX_CHANNELS; i++) device_destroy(mt_class, MKDEV(major, i)); |
e01402b11 More AP / SP bits... |
539 540 541 542 543 |
unregister_chrdev(major, module_name); } module_init(rtlx_module_init); module_exit(rtlx_module_exit); |
afc4841d8 Turn rtlx upside ... |
544 |
|
e01402b11 More AP / SP bits... |
545 |
MODULE_DESCRIPTION("MIPS RTLX"); |
2600990e6 [MIPS] kpsd and o... |
546 |
MODULE_AUTHOR("Elizabeth Oldham, MIPS Technologies, Inc."); |
e01402b11 More AP / SP bits... |
547 |
MODULE_LICENSE("GPL"); |