3 * Copyright 1999 Digi International (www.digi.com)
4 * James Puzzo <jamesp at digi dot com>
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, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
13 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
26 * Handle the file operations required for the "dpa" devices.
27 * Includes those functions required to register the "dpa" devices
36 #include <linux/module.h>
37 #include <linux/proc_fs.h>
38 #include <linux/tty.h>
39 #include <linux/poll.h>
40 #include <linux/cred.h>
41 #include <linux/sched.h>
42 #include <linux/ratelimit.h>
43 #include <asm/unaligned.h>
45 #include "dgrp_common.h"
47 /* File operation declarations */
48 static int dgrp_dpa_open(struct inode
*, struct file
*);
49 static int dgrp_dpa_release(struct inode
*, struct file
*);
50 static ssize_t
dgrp_dpa_read(struct file
*, char __user
*, size_t, loff_t
*);
51 static long dgrp_dpa_ioctl(struct file
*file
, unsigned int cmd
,
53 static unsigned int dgrp_dpa_select(struct file
*, struct poll_table_struct
*);
55 static const struct file_operations dpa_ops
= {
57 .read
= dgrp_dpa_read
,
58 .poll
= dgrp_dpa_select
,
59 .unlocked_ioctl
= dgrp_dpa_ioctl
,
60 .open
= dgrp_dpa_open
,
61 .release
= dgrp_dpa_release
,
64 static struct inode_operations dpa_inode_ops
= {
65 .permission
= dgrp_inode_permission
71 uint nd_state
; /* Node state: 1 = up, 0 = down. */
72 uint nd_chan_count
; /* Number of channels found */
73 uint nd_tx_byte
; /* Tx data count */
74 uint nd_rx_byte
; /* RX data count */
75 u8 nd_ps_desc
[MAX_DESC_LEN
]; /* Description from PS */
78 #define DIGI_GETNODE (('d'<<8) | 249) /* get board info */
82 uint ch_port
; /* Port number to get info on */
83 uint ch_open
; /* 1 if open, 0 if not */
84 uint ch_txcount
; /* TX data count */
85 uint ch_rxcount
; /* RX data count */
86 uint ch_s_brate
; /* Realport BRATE */
87 uint ch_s_estat
; /* Realport ELAST */
88 uint ch_s_cflag
; /* Realport CFLAG */
89 uint ch_s_iflag
; /* Realport IFLAG */
90 uint ch_s_oflag
; /* Realport OFLAG */
91 uint ch_s_xflag
; /* Realport XFLAG */
92 uint ch_s_mstat
; /* Realport MLAST */
95 #define DIGI_GETCHAN (('d'<<8) | 248) /* get channel info */
100 char vpd_data
[VPDSIZE
];
103 #define DIGI_GETVPD (('d'<<8) | 246) /* get VPD info */
111 #define DIGI_SETDEBUG (('d'<<8) | 247) /* set debug info */
114 void dgrp_register_dpa_hook(struct proc_dir_entry
*de
)
116 struct nd_struct
*node
= de
->data
;
118 de
->proc_iops
= &dpa_inode_ops
;
119 de
->proc_fops
= &dpa_ops
;
121 node
->nd_dpa_de
= de
;
122 spin_lock_init(&node
->nd_dpa_lock
);
126 * dgrp_dpa_open -- open the DPA device for a particular PortServer
128 static int dgrp_dpa_open(struct inode
*inode
, struct file
*file
)
130 struct nd_struct
*nd
;
133 struct proc_dir_entry
*de
;
135 rtn
= try_module_get(THIS_MODULE
);
141 if (!capable(CAP_SYS_ADMIN
)) {
147 * Make sure that the "private_data" field hasn't already been used.
149 if (file
->private_data
) {
155 * Get the node pointer, and fail if it doesn't exist.
162 nd
= (struct nd_struct
*)de
->data
;
168 file
->private_data
= (void *) nd
;
171 * Allocate the DPA buffer.
174 if (nd
->nd_dpa_buf
) {
177 nd
->nd_dpa_buf
= kmalloc(DPA_MAX
, GFP_KERNEL
);
179 if (!nd
->nd_dpa_buf
) {
184 nd
->nd_dpa_lbolt
= jiffies
;
191 module_put(THIS_MODULE
);
196 * dgrp_dpa_release -- close the DPA device for a particular PortServer
198 static int dgrp_dpa_release(struct inode
*inode
, struct file
*file
)
200 struct nd_struct
*nd
;
202 unsigned long lock_flags
;
205 * Get the node pointer, and quit if it doesn't exist.
207 nd
= (struct nd_struct
*)(file
->private_data
);
212 * Free the dpa buffer.
215 spin_lock_irqsave(&nd
->nd_dpa_lock
, lock_flags
);
217 buf
= nd
->nd_dpa_buf
;
219 nd
->nd_dpa_buf
= NULL
;
220 nd
->nd_dpa_out
= nd
->nd_dpa_in
;
223 * Wakeup any thread waiting for buffer space.
226 if (nd
->nd_dpa_flag
& DPA_WAIT_SPACE
) {
227 nd
->nd_dpa_flag
&= ~DPA_WAIT_SPACE
;
228 wake_up_interruptible(&nd
->nd_dpa_wqueue
);
231 spin_unlock_irqrestore(&nd
->nd_dpa_lock
, lock_flags
);
236 module_put(THIS_MODULE
);
237 file
->private_data
= NULL
;
244 * Copy data from the monitoring buffer to the user, freeing space
245 * in the monitoring buffer for more messages
247 static ssize_t
dgrp_dpa_read(struct file
*file
, char __user
*buf
, size_t count
,
250 struct nd_struct
*nd
;
256 unsigned long lock_flags
;
259 * Get the node pointer, and quit if it doesn't exist.
261 nd
= (struct nd_struct
*)(file
->private_data
);
266 * Wait for some data to appear in the buffer.
269 spin_lock_irqsave(&nd
->nd_dpa_lock
, lock_flags
);
272 n
= (nd
->nd_dpa_in
- nd
->nd_dpa_out
) & DPA_MASK
;
277 nd
->nd_dpa_flag
|= DPA_WAIT_DATA
;
279 spin_unlock_irqrestore(&nd
->nd_dpa_lock
, lock_flags
);
282 * Go to sleep waiting until the condition becomes true.
284 rtn
= wait_event_interruptible(nd
->nd_dpa_wqueue
,
285 ((nd
->nd_dpa_flag
& DPA_WAIT_DATA
) == 0));
290 spin_lock_irqsave(&nd
->nd_dpa_lock
, lock_flags
);
294 * Read whatever is there.
302 r
= DPA_MAX
- nd
->nd_dpa_out
;
306 spin_unlock_irqrestore(&nd
->nd_dpa_lock
, lock_flags
);
307 rtn
= copy_to_user((void __user
*)buf
,
308 nd
->nd_dpa_buf
+ nd
->nd_dpa_out
, r
);
309 spin_lock_irqsave(&nd
->nd_dpa_lock
, lock_flags
);
321 spin_unlock_irqrestore(&nd
->nd_dpa_lock
, lock_flags
);
322 rtn
= copy_to_user((void __user
*)buf
+ offset
,
323 nd
->nd_dpa_buf
+ nd
->nd_dpa_out
, n
);
324 spin_lock_irqsave(&nd
->nd_dpa_lock
, lock_flags
);
338 * Wakeup any thread waiting for buffer space.
341 n
= (nd
->nd_dpa_in
- nd
->nd_dpa_out
) & DPA_MASK
;
343 if (nd
->nd_dpa_flag
& DPA_WAIT_SPACE
&&
344 (DPA_MAX
- n
) > DPA_HIGH_WATER
) {
345 nd
->nd_dpa_flag
&= ~DPA_WAIT_SPACE
;
346 wake_up_interruptible(&nd
->nd_dpa_wqueue
);
350 spin_unlock_irqrestore(&nd
->nd_dpa_lock
, lock_flags
);
354 static unsigned int dgrp_dpa_select(struct file
*file
,
355 struct poll_table_struct
*table
)
357 unsigned int retval
= 0;
358 struct nd_struct
*nd
= file
->private_data
;
360 if (nd
->nd_dpa_out
!= nd
->nd_dpa_in
)
361 retval
|= POLLIN
| POLLRDNORM
; /* Conditionally readable */
363 retval
|= POLLOUT
| POLLWRNORM
; /* Always writeable */
368 static long dgrp_dpa_ioctl(struct file
*file
, unsigned int cmd
,
372 struct nd_struct
*nd
;
373 struct digi_chan getchan
;
374 struct digi_node getnode
;
375 struct ch_struct
*ch
;
376 struct digi_debug setdebug
;
379 void __user
*uarg
= (void __user
*) arg
;
381 nd
= file
->private_data
;
385 if (copy_from_user(&getchan
, uarg
, sizeof(struct digi_chan
)))
388 port
= getchan
.ch_port
;
390 if (port
> nd
->nd_chan_count
)
393 ch
= nd
->nd_chan
+ port
;
395 getchan
.ch_open
= (ch
->ch_open_count
> 0) ? 1 : 0;
396 getchan
.ch_txcount
= ch
->ch_txcount
;
397 getchan
.ch_rxcount
= ch
->ch_rxcount
;
398 getchan
.ch_s_brate
= ch
->ch_s_brate
;
399 getchan
.ch_s_estat
= ch
->ch_s_elast
;
400 getchan
.ch_s_cflag
= ch
->ch_s_cflag
;
401 getchan
.ch_s_iflag
= ch
->ch_s_iflag
;
402 getchan
.ch_s_oflag
= ch
->ch_s_oflag
;
403 getchan
.ch_s_xflag
= ch
->ch_s_xflag
;
404 getchan
.ch_s_mstat
= ch
->ch_s_mlast
;
406 if (copy_to_user(uarg
, &getchan
, sizeof(struct digi_chan
)))
412 getnode
.nd_state
= (nd
->nd_state
& NS_READY
) ? 1 : 0;
413 getnode
.nd_chan_count
= nd
->nd_chan_count
;
414 getnode
.nd_tx_byte
= nd
->nd_tx_byte
;
415 getnode
.nd_rx_byte
= nd
->nd_rx_byte
;
417 memset(&getnode
.nd_ps_desc
, 0, MAX_DESC_LEN
);
418 strncpy(getnode
.nd_ps_desc
, nd
->nd_ps_desc
, MAX_DESC_LEN
);
420 if (copy_to_user(uarg
, &getnode
, sizeof(struct digi_node
)))
426 if (copy_from_user(&setdebug
, uarg
, sizeof(struct digi_debug
)))
429 nd
->nd_dpa_debug
= setdebug
.onoff
;
430 nd
->nd_dpa_port
= setdebug
.port
;
435 if (nd
->nd_vpd_len
> 0) {
436 vpd
.vpd_len
= nd
->nd_vpd_len
;
437 memcpy(&vpd
.vpd_data
, &nd
->nd_vpd
, nd
->nd_vpd_len
);
442 if (copy_to_user(uarg
, &vpd
, sizeof(struct digi_vpd
)))
451 * dgrp_dpa() -- send data to the device monitor queue
452 * @nd: pointer to a node structure
453 * @buf: buffer of data to copy to the monitoring buffer
454 * @len: number of bytes to transfer to the buffer
456 * Called by the net device routines to send data to the device
457 * monitor queue. If the device monitor buffer is too full to
458 * accept the data, it waits until the buffer is ready.
460 static void dgrp_dpa(struct nd_struct
*nd
, u8
*buf
, int nbuf
)
464 unsigned long lock_flags
;
469 spin_lock_irqsave(&nd
->nd_dpa_lock
, lock_flags
);
472 * Loop while data remains.
474 while (nbuf
> 0 && nd
->nd_dpa_buf
!= NULL
) {
476 n
= (nd
->nd_dpa_out
- nd
->nd_dpa_in
- 1) & DPA_MASK
;
479 * Enforce flow control on the DPA device.
481 if (n
< (DPA_MAX
- DPA_HIGH_WATER
))
482 nd
->nd_dpa_flag
|= DPA_WAIT_SPACE
;
485 * This should never happen, as the flow control above
486 * should have stopped things before they got to this point.
489 spin_unlock_irqrestore(&nd
->nd_dpa_lock
, lock_flags
);
494 * Copy as much data as will fit.
500 r
= DPA_MAX
- nd
->nd_dpa_in
;
503 memcpy(nd
->nd_dpa_buf
+ nd
->nd_dpa_in
, buf
, r
);
513 memcpy(nd
->nd_dpa_buf
+ nd
->nd_dpa_in
, buf
, n
);
520 if (nd
->nd_dpa_in
>= DPA_MAX
)
521 pr_info_ratelimited("%s - nd->nd_dpa_in (%i) >= DPA_MAX\n",
522 __func__
, nd
->nd_dpa_in
);
525 * Wakeup any thread waiting for data
527 if (nd
->nd_dpa_flag
& DPA_WAIT_DATA
) {
528 nd
->nd_dpa_flag
&= ~DPA_WAIT_DATA
;
529 wake_up_interruptible(&nd
->nd_dpa_wqueue
);
534 * Release the DPA lock.
536 spin_unlock_irqrestore(&nd
->nd_dpa_lock
, lock_flags
);
540 * dgrp_monitor_data() -- builds a DPA data packet
541 * @nd: pointer to a node structure
542 * @type: type of message to be logged in the DPA buffer
543 * @buf: buffer of data to be logged in the DPA buffer
544 * @size -- number of bytes in the "buf" buffer
546 void dgrp_dpa_data(struct nd_struct
*nd
, int type
, u8
*buf
, int size
)
552 put_unaligned_be32(size
, header
+ 1);
554 dgrp_dpa(nd
, header
, sizeof(header
));
555 dgrp_dpa(nd
, buf
, size
);