Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
03286272
Commit
03286272
authored
Jun 03, 2003
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://kernel.bkbits.net/acme/net-2.5
into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents
ec55bbd7
7407b976
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
224 additions
and
262 deletions
+224
-262
drivers/char/n_hdlc.c
drivers/char/n_hdlc.c
+224
-262
No files found.
drivers/char/n_hdlc.c
View file @
03286272
...
@@ -6,7 +6,8 @@
...
@@ -6,7 +6,8 @@
* Microgate and SyncLink are registered trademarks of Microgate Corporation
* Microgate and SyncLink are registered trademarks of Microgate Corporation
*
*
* Adapted from ppp.c, written by Michael Callahan <callahan@maths.ox.ac.uk>,
* Adapted from ppp.c, written by Michael Callahan <callahan@maths.ox.ac.uk>,
* Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
* Al Longyear <longyear@netcom.com>,
* Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
*
*
* Original release 01/11/99
* Original release 01/11/99
* $Id: n_hdlc.c,v 4.8 2003/05/06 21:18:51 paulkf Exp $
* $Id: n_hdlc.c,v 4.8 2003/05/06 21:18:51 paulkf Exp $
...
@@ -96,32 +97,19 @@
...
@@ -96,32 +97,19 @@
#include <linux/poll.h>
#include <linux/poll.h>
#include <linux/in.h>
#include <linux/in.h>
#include <linux/ioctl.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/tty.h>
#include <linux/tty.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/string.h>
/* used in new tty drivers */
#include <linux/string.h>
/* used in new tty drivers */
#include <linux/signal.h>
/* used in new tty drivers */
#include <linux/signal.h>
/* used in new tty drivers */
#include <linux/if.h>
#include <asm/system.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/bitops.h>
#include <asm/termios.h>
#include <asm/termios.h>
#include <linux/if.h>
#include <linux/ioctl.h>
#ifdef CONFIG_KERNELD
#include <linux/kerneld.h>
#endif
#define GET_USER(error,value,addr) error = get_user(value,addr)
#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
#define PUT_USER(error,value,addr) error = put_user(value,addr)
#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
#include <asm/uaccess.h>
#include <asm/uaccess.h>
typedef
ssize_t
rw_ret_t
;
typedef
size_t
rw_count_t
;
/*
/*
* Buffers for individual HDLC frames
* Buffers for individual HDLC frames
*/
*/
...
@@ -130,91 +118,90 @@ typedef size_t rw_count_t;
...
@@ -130,91 +118,90 @@ typedef size_t rw_count_t;
#define MAX_RX_BUF_COUNT 60
#define MAX_RX_BUF_COUNT 60
#define DEFAULT_TX_BUF_COUNT 1
#define DEFAULT_TX_BUF_COUNT 1
struct
n_hdlc_buf
{
struct
n_hdlc_buf
*
link
;
int
count
;
char
buf
[
1
];
};
typedef
struct
_n_hdlc_buf
#define N_HDLC_BUF_SIZE (sizeof(struct n_hdlc_buf) + maxframe)
{
struct
_n_hdlc_buf
*
link
;
int
count
;
char
buf
[
1
];
}
N_HDLC_BUF
;
#define N_HDLC_BUF_SIZE (sizeof(N_HDLC_BUF)+maxframe)
typedef
struct
_n_hdlc_buf_list
struct
n_hdlc_buf_list
{
{
struct
n_hdlc_buf
*
head
;
N_HDLC_BUF
*
head
;
struct
n_hdlc_buf
*
tail
;
N_HDLC_BUF
*
tail
;
int
count
;
int
count
;
spinlock_t
spinlock
;
spinlock_t
spinlock
;
};
}
N_HDLC_BUF_LIST
;
/*
/**
* Per device instance data structure
* struct n_hdlc - per device instance data structure
* @magic - magic value for structure
* @flags - miscellaneous control flags
* @tty - ptr to TTY structure
* @backup_tty - TTY to use if tty gets closed
* @tbusy - reentrancy flag for tx wakeup code
* @woke_up - FIXME: describe this field
* @tbuf - currently transmitting tx buffer
* @tx_buf_list - list of pending transmit frame buffers
* @rx_buf_list - list of received frame buffers
* @tx_free_buf_list - list unused transmit frame buffers
* @rx_free_buf_list - list unused received frame buffers
*/
*/
struct
n_hdlc
{
struct
n_hdlc
{
int
magic
;
/* magic value for structure */
int
magic
;
__u32
flags
;
/* miscellaneous control flags */
__u32
flags
;
struct
tty_struct
*
tty
;
struct
tty_struct
*
tty
;
/* ptr to TTY structure */
struct
tty_struct
*
backup_tty
;
struct
tty_struct
*
backup_tty
;
/* TTY to use if tty gets closed */
int
tbusy
;
int
woke_up
;
int
tbusy
;
/* reentrancy flag for tx wakeup code */
struct
n_hdlc_buf
*
tbuf
;
int
woke_up
;
struct
n_hdlc_buf_list
tx_buf_list
;
N_HDLC_BUF
*
tbuf
;
/* currently transmitting tx buffer */
struct
n_hdlc_buf_list
rx_buf_list
;
N_HDLC_BUF_LIST
tx_buf_list
;
/* list of pending transmit frame buffers */
struct
n_hdlc_buf_list
tx_free_buf_list
;
N_HDLC_BUF_LIST
rx_buf_list
;
/* list of received frame buffers */
struct
n_hdlc_buf_list
rx_free_buf_list
;
N_HDLC_BUF_LIST
tx_free_buf_list
;
/* list unused transmit frame buffers */
N_HDLC_BUF_LIST
rx_free_buf_list
;
/* list unused received frame buffers */
};
};
/*
/*
* HDLC buffer list manipulation functions
* HDLC buffer list manipulation functions
*/
*/
static
void
n_hdlc_buf_list_init
(
N_HDLC_BUF_LIST
*
list
);
static
void
n_hdlc_buf_list_init
(
struct
n_hdlc_buf_list
*
list
);
static
void
n_hdlc_buf_put
(
N_HDLC_BUF_LIST
*
list
,
N_HDLC_BUF
*
buf
);
static
void
n_hdlc_buf_put
(
struct
n_hdlc_buf_list
*
list
,
static
N_HDLC_BUF
*
n_hdlc_buf_get
(
N_HDLC_BUF_LIST
*
list
);
struct
n_hdlc_buf
*
buf
);
static
struct
n_hdlc_buf
*
n_hdlc_buf_get
(
struct
n_hdlc_buf_list
*
list
);
/* Local functions */
/* Local functions */
static
struct
n_hdlc
*
n_hdlc_alloc
(
void
);
static
struct
n_hdlc
*
n_hdlc_alloc
(
void
);
MODULE_PARM
(
debuglevel
,
"i"
);
MODULE_PARM
(
maxframe
,
"i"
);
/* debug level can be set by insmod for debugging purposes */
/* debug level can be set by insmod for debugging purposes */
#define DEBUG_LEVEL_INFO 1
#define DEBUG_LEVEL_INFO 1
static
int
debuglevel
;
static
int
debuglevel
;
/* max frame size for memory allocations */
/* max frame size for memory allocations */
static
ssize_t
maxframe
=
4096
;
static
ssize_t
maxframe
=
4096
;
/* TTY callbacks */
/* TTY callbacks */
static
rw_ret_t
n_hdlc_tty_read
(
struct
tty_struct
*
,
static
int
n_hdlc_tty_read
(
struct
tty_struct
*
tty
,
struct
file
*
file
,
struct
file
*
,
__u8
*
,
rw_count_t
);
__u8
*
buf
,
size_t
nr
);
static
rw_ret_t
n_hdlc_tty_write
(
struct
tty_struct
*
,
static
int
n_hdlc_tty_write
(
struct
tty_struct
*
tty
,
struct
file
*
file
,
struct
file
*
,
const
__u8
*
,
rw_count_t
);
const
__u8
*
buf
,
size_t
nr
);
static
int
n_hdlc_tty_ioctl
(
struct
tty_struct
*
,
static
int
n_hdlc_tty_ioctl
(
struct
tty_struct
*
tty
,
struct
file
*
file
,
struct
file
*
,
unsigned
int
,
unsigned
lon
g
);
unsigned
int
cmd
,
unsigned
long
ar
g
);
static
unsigned
int
n_hdlc_tty_poll
(
struct
tty_struct
*
tty
,
struct
file
*
filp
,
static
unsigned
int
n_hdlc_tty_poll
(
struct
tty_struct
*
tty
,
struct
file
*
filp
,
poll_table
*
wait
);
poll_table
*
wait
);
static
int
n_hdlc_tty_open
(
struct
tty_struct
*
);
static
int
n_hdlc_tty_open
(
struct
tty_struct
*
tty
);
static
void
n_hdlc_tty_close
(
struct
tty_struct
*
);
static
void
n_hdlc_tty_close
(
struct
tty_struct
*
tty
);
static
int
n_hdlc_tty_room
(
struct
tty_struct
*
tty
);
static
int
n_hdlc_tty_room
(
struct
tty_struct
*
tty
);
static
void
n_hdlc_tty_receive
(
struct
tty_struct
*
tty
,
static
void
n_hdlc_tty_receive
(
struct
tty_struct
*
tty
,
const
__u8
*
cp
,
const
__u8
*
cp
,
char
*
fp
,
int
count
);
char
*
fp
,
int
count
);
static
void
n_hdlc_tty_wakeup
(
struct
tty_struct
*
tty
);
static
void
n_hdlc_tty_wakeup
(
struct
tty_struct
*
tty
);
#define bset(p,b) ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
#define bset(p,b) ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
#define tty2n_hdlc(tty) ((struct n_hdlc *) ((tty)->disc_data))
#define tty2n_hdlc(tty) ((struct n_hdlc *) ((tty)->disc_data))
#define n_hdlc2tty(n_hdlc) ((n_hdlc)->tty)
#define n_hdlc2tty(n_hdlc) ((n_hdlc)->tty)
/* Define this string only once for all macro invocations */
static
char
szVersion
[]
=
HDLC_VERSION
;
static
struct
tty_ldisc
n_hdlc_ldisc
=
{
static
struct
tty_ldisc
n_hdlc_ldisc
=
{
.
owner
=
THIS_MODULE
,
.
owner
=
THIS_MODULE
,
.
magic
=
TTY_LDISC_MAGIC
,
.
magic
=
TTY_LDISC_MAGIC
,
...
@@ -230,15 +217,14 @@ static struct tty_ldisc n_hdlc_ldisc = {
...
@@ -230,15 +217,14 @@ static struct tty_ldisc n_hdlc_ldisc = {
.
write_wakeup
=
n_hdlc_tty_wakeup
,
.
write_wakeup
=
n_hdlc_tty_wakeup
,
};
};
/* n_hdlc_release()
/**
*
* n_hdlc_release - release an n_hdlc per device line discipline info structure
* release an n_hdlc per device line discipline info structure
* @n_hdlc - per device line discipline info structure
*
*/
*/
static
void
n_hdlc_release
(
struct
n_hdlc
*
n_hdlc
)
static
void
n_hdlc_release
(
struct
n_hdlc
*
n_hdlc
)
{
{
struct
tty_struct
*
tty
=
n_hdlc2tty
(
n_hdlc
);
struct
tty_struct
*
tty
=
n_hdlc2tty
(
n_hdlc
);
N_HDLC_BUF
*
buf
;
struct
n_hdlc_buf
*
buf
;
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
printk
(
"%s(%d)n_hdlc_release() called
\n
"
,
__FILE__
,
__LINE__
);
printk
(
"%s(%d)n_hdlc_release() called
\n
"
,
__FILE__
,
__LINE__
);
...
@@ -285,10 +271,12 @@ static void n_hdlc_release (struct n_hdlc *n_hdlc)
...
@@ -285,10 +271,12 @@ static void n_hdlc_release (struct n_hdlc *n_hdlc)
}
/* end of n_hdlc_release() */
}
/* end of n_hdlc_release() */
/* n_hdlc_tty_close()
/**
* n_hdlc_tty_close - line discipline close
* @tty - pointer to tty info structure
*
*
*
Called when the line discipline is changed to something
*
Called when the line discipline is changed to something
*
else, the tty is closed, or the tty detects a hangup.
*
else, the tty is closed, or the tty detects a hangup.
*/
*/
static
void
n_hdlc_tty_close
(
struct
tty_struct
*
tty
)
static
void
n_hdlc_tty_close
(
struct
tty_struct
*
tty
)
{
{
...
@@ -322,12 +310,11 @@ static void n_hdlc_tty_close(struct tty_struct *tty)
...
@@ -322,12 +310,11 @@ static void n_hdlc_tty_close(struct tty_struct *tty)
}
/* end of n_hdlc_tty_close() */
}
/* end of n_hdlc_tty_close() */
/* n_hdlc_tty_open
/**
*
* n_hdlc_tty_open - called when line discipline changed to n_hdlc
* called when line discipline changed to n_hdlc
* @tty - pointer to tty info structure
*
*
* Arguments: tty pointer to tty info structure
* Returns 0 if success, otherwise error code
* Return Value: 0 if success, otherwise error code
*/
*/
static
int
n_hdlc_tty_open
(
struct
tty_struct
*
tty
)
static
int
n_hdlc_tty_open
(
struct
tty_struct
*
tty
)
{
{
...
@@ -373,22 +360,20 @@ static int n_hdlc_tty_open (struct tty_struct *tty)
...
@@ -373,22 +360,20 @@ static int n_hdlc_tty_open (struct tty_struct *tty)
}
/* end of n_tty_hdlc_open() */
}
/* end of n_tty_hdlc_open() */
/* n_hdlc_send_frames()
/**
*
* n_hdlc_send_frames - send frames on pending send buffer list
* send frames on pending send buffer list until the
* @n_hdlc - pointer to ldisc instance data
* driver does not accept a frame (busy)
* @tty - pointer to tty instance data
* this function is called after adding a frame to the
*
* send buffer list and by the tty wakeup callback
* Send frames on pending send buffer list until the driver does not accept a
*
* frame (busy) this function is called after adding a frame to the send buffer
* Arguments: n_hdlc pointer to ldisc instance data
* list and by the tty wakeup callback.
* tty pointer to tty instance data
* Return Value: None
*/
*/
static
void
n_hdlc_send_frames
(
struct
n_hdlc
*
n_hdlc
,
struct
tty_struct
*
tty
)
static
void
n_hdlc_send_frames
(
struct
n_hdlc
*
n_hdlc
,
struct
tty_struct
*
tty
)
{
{
register
int
actual
;
register
int
actual
;
unsigned
long
flags
;
unsigned
long
flags
;
N_HDLC_BUF
*
tbuf
;
struct
n_hdlc_buf
*
tbuf
;
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
printk
(
"%s(%d)n_hdlc_send_frames() called
\n
"
,
__FILE__
,
__LINE__
);
printk
(
"%s(%d)n_hdlc_send_frames() called
\n
"
,
__FILE__
,
__LINE__
);
...
@@ -431,7 +416,7 @@ static void n_hdlc_send_frames (struct n_hdlc *n_hdlc, struct tty_struct *tty)
...
@@ -431,7 +416,7 @@ static void n_hdlc_send_frames (struct n_hdlc *n_hdlc, struct tty_struct *tty)
__FILE__
,
__LINE__
,
tbuf
);
__FILE__
,
__LINE__
,
tbuf
);
/* free current transmit buffer */
/* free current transmit buffer */
n_hdlc_buf_put
(
&
n_hdlc
->
tx_free_buf_list
,
tbuf
);
n_hdlc_buf_put
(
&
n_hdlc
->
tx_free_buf_list
,
tbuf
);
/* this tx buffer is done */
/* this tx buffer is done */
n_hdlc
->
tbuf
=
NULL
;
n_hdlc
->
tbuf
=
NULL
;
...
@@ -469,17 +454,15 @@ static void n_hdlc_send_frames (struct n_hdlc *n_hdlc, struct tty_struct *tty)
...
@@ -469,17 +454,15 @@ static void n_hdlc_send_frames (struct n_hdlc *n_hdlc, struct tty_struct *tty)
}
/* end of n_hdlc_send_frames() */
}
/* end of n_hdlc_send_frames() */
/* n_hdlc_tty_wakeup()
/**
* n_hdlc_tty_wakeup - Callback for transmit wakeup
* @tty - pointer to associated tty instance data
*
*
* Callback for transmit wakeup. Called when low level
* Called when low level device driver can accept more send data.
* device driver can accept more send data.
*
* Arguments: tty pointer to associated tty instance data
* Return Value: None
*/
*/
static
void
n_hdlc_tty_wakeup
(
struct
tty_struct
*
tty
)
static
void
n_hdlc_tty_wakeup
(
struct
tty_struct
*
tty
)
{
{
struct
n_hdlc
*
n_hdlc
=
tty2n_hdlc
(
tty
);
struct
n_hdlc
*
n_hdlc
=
tty2n_hdlc
(
tty
);
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
printk
(
"%s(%d)n_hdlc_tty_wakeup() called
\n
"
,
__FILE__
,
__LINE__
);
printk
(
"%s(%d)n_hdlc_tty_wakeup() called
\n
"
,
__FILE__
,
__LINE__
);
...
@@ -496,16 +479,14 @@ static void n_hdlc_tty_wakeup (struct tty_struct *tty)
...
@@ -496,16 +479,14 @@ static void n_hdlc_tty_wakeup (struct tty_struct *tty)
}
/* end of n_hdlc_tty_wakeup() */
}
/* end of n_hdlc_tty_wakeup() */
/* n_hdlc_tty_room()
/**
*
* n_hdlc_tty_room - Return the amount of space left in the receiver's buffer
* Callback function from tty driver. Return the amount of
* @tty - pointer to associated tty instance data
* space left in the receiver's buffer to decide if remote
* transmitter is to be throttled.
*
*
*
Arguments: tty pointer to associated tty instance data
*
Callback function from tty driver. Return the amount of space left in the
*
Return Value: number of bytes left in receive buffer
*
receiver's buffer to decide if remote transmitter is to be throttled.
*/
*/
static
int
n_hdlc_tty_room
(
struct
tty_struct
*
tty
)
static
int
n_hdlc_tty_room
(
struct
tty_struct
*
tty
)
{
{
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
printk
(
"%s(%d)n_hdlc_tty_room() called
\n
"
,
__FILE__
,
__LINE__
);
printk
(
"%s(%d)n_hdlc_tty_room() called
\n
"
,
__FILE__
,
__LINE__
);
...
@@ -514,23 +495,21 @@ static int n_hdlc_tty_room (struct tty_struct *tty)
...
@@ -514,23 +495,21 @@ static int n_hdlc_tty_room (struct tty_struct *tty)
return
65536
;
return
65536
;
}
/* end of n_hdlc_tty_root() */
}
/* end of n_hdlc_tty_root() */
/* n_hdlc_tty_receive()
/**
*
* n_hdlc_tty_receive - Called by tty driver when receive data is available
* Called by tty low level driver when receive data is
* @tty - pointer to tty instance data
* available. Data is interpreted as one HDLC frame.
* @data - pointer to received data
*
* @flags - pointer to flags for data
* Arguments: tty pointer to tty isntance data
* @count - count of received data in bytes
* data pointer to received data
*
* flags pointer to flags for data
* Called by tty low level driver when receive data is available. Data is
* count count of received data in bytes
* interpreted as one HDLC frame.
*
* Return Value: None
*/
*/
static
void
n_hdlc_tty_receive
(
struct
tty_struct
*
tty
,
static
void
n_hdlc_tty_receive
(
struct
tty_struct
*
tty
,
const
__u8
*
data
,
const
__u8
*
data
,
char
*
flags
,
int
count
)
char
*
flags
,
int
count
)
{
{
register
struct
n_hdlc
*
n_hdlc
=
tty2n_hdlc
(
tty
);
register
struct
n_hdlc
*
n_hdlc
=
tty2n_hdlc
(
tty
);
register
N_HDLC_BUF
*
buf
;
register
struct
n_hdlc_buf
*
buf
;
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
printk
(
"%s(%d)n_hdlc_tty_receive() called count=%d
\n
"
,
printk
(
"%s(%d)n_hdlc_tty_receive() called count=%d
\n
"
,
...
@@ -560,7 +539,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty,
...
@@ -560,7 +539,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty,
/* no buffers in free list, attempt to allocate another rx buffer */
/* no buffers in free list, attempt to allocate another rx buffer */
/* unless the maximum count has been reached */
/* unless the maximum count has been reached */
if
(
n_hdlc
->
rx_buf_list
.
count
<
MAX_RX_BUF_COUNT
)
if
(
n_hdlc
->
rx_buf_list
.
count
<
MAX_RX_BUF_COUNT
)
buf
=
(
N_HDLC_BUF
*
)
kmalloc
(
N_HDLC_BUF_SIZE
,
GFP_ATOMIC
);
buf
=
kmalloc
(
N_HDLC_BUF_SIZE
,
GFP_ATOMIC
);
}
}
if
(
!
buf
)
{
if
(
!
buf
)
{
...
@@ -575,7 +554,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty,
...
@@ -575,7 +554,7 @@ static void n_hdlc_tty_receive(struct tty_struct *tty,
buf
->
count
=
count
;
buf
->
count
=
count
;
/* add HDLC buffer to list of received frames */
/* add HDLC buffer to list of received frames */
n_hdlc_buf_put
(
&
n_hdlc
->
rx_buf_list
,
buf
);
n_hdlc_buf_put
(
&
n_hdlc
->
rx_buf_list
,
buf
);
/* wake up any blocked reads and perform async signalling */
/* wake up any blocked reads and perform async signalling */
wake_up_interruptible
(
&
tty
->
read_wait
);
wake_up_interruptible
(
&
tty
->
read_wait
);
...
@@ -584,28 +563,22 @@ static void n_hdlc_tty_receive(struct tty_struct *tty,
...
@@ -584,28 +563,22 @@ static void n_hdlc_tty_receive(struct tty_struct *tty,
}
/* end of n_hdlc_tty_receive() */
}
/* end of n_hdlc_tty_receive() */
/* n_hdlc_tty_read()
/**
*
* n_hdlc_tty_read - Called to retreive one frame of data (if available)
* Called to retreive one frame of data (if available)
* @tty - pointer to tty instance data
* @file - pointer to open file object
* @buf - pointer to returned data buffer
* @nr - size of returned data buffer
*
*
* Arguments:
* Returns the number of bytes returned or error code.
*
* tty pointer to tty instance data
* file pointer to open file object
* buf pointer to returned data buffer
* nr size of returned data buffer
*
* Return Value:
*
* Number of bytes returned or error code
*/
*/
static
rw_ret_t
n_hdlc_tty_read
(
struct
tty_struct
*
tty
,
static
int
n_hdlc_tty_read
(
struct
tty_struct
*
tty
,
struct
file
*
file
,
struct
file
*
file
,
__u8
*
buf
,
rw_count
_t
nr
)
__u8
*
buf
,
size
_t
nr
)
{
{
struct
n_hdlc
*
n_hdlc
=
tty2n_hdlc
(
tty
);
struct
n_hdlc
*
n_hdlc
=
tty2n_hdlc
(
tty
);
int
error
;
int
error
;
rw_ret_
t
ret
;
in
t
ret
;
N_HDLC_BUF
*
rbuf
;
struct
n_hdlc_buf
*
rbuf
;
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
printk
(
"%s(%d)n_hdlc_tty_read() called
\n
"
,
__FILE__
,
__LINE__
);
printk
(
"%s(%d)n_hdlc_tty_read() called
\n
"
,
__FILE__
,
__LINE__
);
...
@@ -644,16 +617,15 @@ static rw_ret_t n_hdlc_tty_read (struct tty_struct *tty,
...
@@ -644,16 +617,15 @@ static rw_ret_t n_hdlc_tty_read (struct tty_struct *tty,
return
-
EINTR
;
return
-
EINTR
;
}
}
if
(
rbuf
->
count
>
nr
)
{
if
(
rbuf
->
count
>
nr
)
/* frame too large for caller's buffer (discard frame) */
/* frame too large for caller's buffer (discard frame) */
ret
=
(
rw_ret_t
)
-
EOVERFLOW
;
ret
=
-
EOVERFLOW
;
}
else
{
else
{
/* Copy the data to the caller's buffer */
/* Copy the data to the caller's buffer */
COPY_TO_USER
(
error
,
buf
,
rbuf
->
buf
,
rbuf
->
count
);
if
(
copy_to_user
(
buf
,
rbuf
->
buf
,
rbuf
->
count
))
if
(
error
)
ret
=
-
EFAULT
;
ret
=
(
rw_ret_t
)
error
;
else
else
ret
=
(
rw_ret_t
)
rbuf
->
count
;
ret
=
rbuf
->
count
;
}
}
/* return HDLC buffer to free list unless the free list */
/* return HDLC buffer to free list unless the free list */
...
@@ -668,24 +640,22 @@ static rw_ret_t n_hdlc_tty_read (struct tty_struct *tty,
...
@@ -668,24 +640,22 @@ static rw_ret_t n_hdlc_tty_read (struct tty_struct *tty,
}
/* end of n_hdlc_tty_read() */
}
/* end of n_hdlc_tty_read() */
/* n_hdlc_tty_write()
/**
*
* n_hdlc_tty_write - write a single frame of data to device
* write a single frame of data to device
* @tty - pointer to associated tty device instance data
*
* @file - pointer to file object data
* Arguments: tty pointer to associated tty device instance data
* @data - pointer to transmit data (one frame)
* file pointer to file object data
* @count - size of transmit frame in bytes
* data pointer to transmit data (one frame)
* count size of transmit frame in bytes
*
*
* Return
Value: number of bytes written (or error code)
* Return
s the number of bytes written (or error code).
*/
*/
static
rw_ret_t
n_hdlc_tty_write
(
struct
tty_struct
*
tty
,
struct
file
*
file
,
static
int
n_hdlc_tty_write
(
struct
tty_struct
*
tty
,
struct
file
*
file
,
const
__u8
*
data
,
rw_count
_t
count
)
const
__u8
*
data
,
size
_t
count
)
{
{
struct
n_hdlc
*
n_hdlc
=
tty2n_hdlc
(
tty
);
struct
n_hdlc
*
n_hdlc
=
tty2n_hdlc
(
tty
);
int
error
=
0
;
int
error
=
0
;
DECLARE_WAITQUEUE
(
wait
,
current
);
DECLARE_WAITQUEUE
(
wait
,
current
);
N_HDLC_BUF
*
tbuf
;
struct
n_hdlc_buf
*
tbuf
;
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
printk
(
"%s(%d)n_hdlc_tty_write() called count=%d
\n
"
,
printk
(
"%s(%d)n_hdlc_tty_write() called count=%d
\n
"
,
...
@@ -735,10 +705,10 @@ static rw_ret_t n_hdlc_tty_write (struct tty_struct *tty, struct file *file,
...
@@ -735,10 +705,10 @@ static rw_ret_t n_hdlc_tty_write (struct tty_struct *tty, struct file *file,
if
(
!
error
)
{
if
(
!
error
)
{
/* Retrieve the user's buffer */
/* Retrieve the user's buffer */
COPY_FROM_USER
(
error
,
tbuf
->
buf
,
data
,
count
);
if
(
copy_from_user
(
tbuf
->
buf
,
data
,
count
))
{
if
(
error
)
{
/* return tx buffer to free list */
/* return tx buffer to free list */
n_hdlc_buf_put
(
&
n_hdlc
->
tx_free_buf_list
,
tbuf
);
n_hdlc_buf_put
(
&
n_hdlc
->
tx_free_buf_list
,
tbuf
);
error
=
-
EFAULT
;
}
else
{
}
else
{
/* Send the data */
/* Send the data */
tbuf
->
count
=
error
=
count
;
tbuf
->
count
=
error
=
count
;
...
@@ -751,21 +721,17 @@ static rw_ret_t n_hdlc_tty_write (struct tty_struct *tty, struct file *file,
...
@@ -751,21 +721,17 @@ static rw_ret_t n_hdlc_tty_write (struct tty_struct *tty, struct file *file,
}
/* end of n_hdlc_tty_write() */
}
/* end of n_hdlc_tty_write() */
/* n_hdlc_tty_ioctl()
/**
* n_hdlc_tty_ioctl - process IOCTL system call for the tty device.
* @tty - pointer to tty instance data
* @file - pointer to open file object for device
* @cmd - IOCTL command code
* @arg - argument for IOCTL call (cmd dependent)
*
*
* Process IOCTL system call for the tty device.
* Returns command dependent result.
*
* Arguments:
*
* tty pointer to tty instance data
* file pointer to open file object for device
* cmd IOCTL command code
* arg argument for IOCTL call (cmd dependent)
*
* Return Value: Command dependent
*/
*/
static
int
n_hdlc_tty_ioctl
(
struct
tty_struct
*
tty
,
struct
file
*
file
,
static
int
n_hdlc_tty_ioctl
(
struct
tty_struct
*
tty
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
unsigned
int
cmd
,
unsigned
long
arg
)
{
{
struct
n_hdlc
*
n_hdlc
=
tty2n_hdlc
(
tty
);
struct
n_hdlc
*
n_hdlc
=
tty2n_hdlc
(
tty
);
int
error
=
0
;
int
error
=
0
;
...
@@ -790,7 +756,7 @@ static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file,
...
@@ -790,7 +756,7 @@ static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file,
else
else
count
=
0
;
count
=
0
;
spin_unlock_irqrestore
(
&
n_hdlc
->
rx_buf_list
.
spinlock
,
flags
);
spin_unlock_irqrestore
(
&
n_hdlc
->
rx_buf_list
.
spinlock
,
flags
);
PUT_USER
(
error
,
count
,
(
int
*
)
arg
);
error
=
put_user
(
count
,
(
int
*
)
arg
);
break
;
break
;
case
TIOCOUTQ
:
case
TIOCOUTQ
:
...
@@ -802,7 +768,7 @@ static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file,
...
@@ -802,7 +768,7 @@ static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file,
if
(
n_hdlc
->
tx_buf_list
.
head
)
if
(
n_hdlc
->
tx_buf_list
.
head
)
count
+=
n_hdlc
->
tx_buf_list
.
head
->
count
;
count
+=
n_hdlc
->
tx_buf_list
.
head
->
count
;
spin_unlock_irqrestore
(
&
n_hdlc
->
tx_buf_list
.
spinlock
,
flags
);
spin_unlock_irqrestore
(
&
n_hdlc
->
tx_buf_list
.
spinlock
,
flags
);
PUT_USER
(
error
,
count
,
(
int
*
)
arg
);
error
=
put_user
(
count
,
(
int
*
)
arg
);
break
;
break
;
default:
default:
...
@@ -813,24 +779,18 @@ static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file,
...
@@ -813,24 +779,18 @@ static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file,
}
/* end of n_hdlc_tty_ioctl() */
}
/* end of n_hdlc_tty_ioctl() */
/* n_hdlc_tty_poll()
/**
*
* n_hdlc_tty_poll - TTY callback for poll system call
* TTY callback for poll system call. Determine which
* @tty - pointer to tty instance data
* operations (read/write) will not block and return
* @filp - pointer to open file object for device
* info to caller.
* @poll_table - wait queue for operations
*
* Arguments:
*
*
* tty pointer to tty instance data
* Determine which operations (read/write) will not block and return info
* filp pointer to open file object for device
* to caller.
* poll_table wait queue for operations
* Returns a bit mask containing info on which ops will not block.
*
* Return Value:
*
* bit mask containing info on which ops will not block
*/
*/
static
unsigned
int
n_hdlc_tty_poll
(
struct
tty_struct
*
tty
,
static
unsigned
int
n_hdlc_tty_poll
(
struct
tty_struct
*
tty
,
struct
file
*
filp
,
struct
file
*
filp
,
poll_table
*
wait
)
poll_table
*
wait
)
{
{
struct
n_hdlc
*
n_hdlc
=
tty2n_hdlc
(
tty
);
struct
n_hdlc
*
n_hdlc
=
tty2n_hdlc
(
tty
);
unsigned
int
mask
=
0
;
unsigned
int
mask
=
0
;
...
@@ -858,20 +818,17 @@ static unsigned int n_hdlc_tty_poll (struct tty_struct *tty,
...
@@ -858,20 +818,17 @@ static unsigned int n_hdlc_tty_poll (struct tty_struct *tty,
return
mask
;
return
mask
;
}
/* end of n_hdlc_tty_poll() */
}
/* end of n_hdlc_tty_poll() */
/* n_hdlc_alloc()
/**
*
* n_hdlc_alloc - allocate an n_hdlc instance data structure
* Allocate an n_hdlc instance data structure
*
*
* Arguments: None
* Returns a pointer to newly created structure if success, otherwise %NULL
* Return Value: pointer to structure if success, otherwise 0
*/
*/
static
struct
n_hdlc
*
n_hdlc_alloc
(
void
)
static
struct
n_hdlc
*
n_hdlc_alloc
(
void
)
{
{
struct
n_hdlc
*
n_hdlc
;
struct
n_hdlc_buf
*
buf
;
N_HDLC_BUF
*
buf
;
int
i
;
int
i
;
struct
n_hdlc
*
n_hdlc
=
kmalloc
(
sizeof
(
*
n_hdlc
),
GFP_KERNEL
);
n_hdlc
=
(
struct
n_hdlc
*
)
kmalloc
(
sizeof
(
struct
n_hdlc
),
GFP_KERNEL
);
if
(
!
n_hdlc
)
if
(
!
n_hdlc
)
return
0
;
return
0
;
...
@@ -884,7 +841,7 @@ static struct n_hdlc *n_hdlc_alloc (void)
...
@@ -884,7 +841,7 @@ static struct n_hdlc *n_hdlc_alloc (void)
/* allocate free rx buffer list */
/* allocate free rx buffer list */
for
(
i
=
0
;
i
<
DEFAULT_RX_BUF_COUNT
;
i
++
)
{
for
(
i
=
0
;
i
<
DEFAULT_RX_BUF_COUNT
;
i
++
)
{
buf
=
(
N_HDLC_BUF
*
)
kmalloc
(
N_HDLC_BUF_SIZE
,
GFP_KERNEL
);
buf
=
kmalloc
(
N_HDLC_BUF_SIZE
,
GFP_KERNEL
);
if
(
buf
)
if
(
buf
)
n_hdlc_buf_put
(
&
n_hdlc
->
rx_free_buf_list
,
buf
);
n_hdlc_buf_put
(
&
n_hdlc
->
rx_free_buf_list
,
buf
);
else
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
else
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
...
@@ -893,7 +850,7 @@ static struct n_hdlc *n_hdlc_alloc (void)
...
@@ -893,7 +850,7 @@ static struct n_hdlc *n_hdlc_alloc (void)
/* allocate free tx buffer list */
/* allocate free tx buffer list */
for
(
i
=
0
;
i
<
DEFAULT_TX_BUF_COUNT
;
i
++
)
{
for
(
i
=
0
;
i
<
DEFAULT_TX_BUF_COUNT
;
i
++
)
{
buf
=
(
N_HDLC_BUF
*
)
kmalloc
(
N_HDLC_BUF_SIZE
,
GFP_KERNEL
);
buf
=
kmalloc
(
N_HDLC_BUF_SIZE
,
GFP_KERNEL
);
if
(
buf
)
if
(
buf
)
n_hdlc_buf_put
(
&
n_hdlc
->
tx_free_buf_list
,
buf
);
n_hdlc_buf_put
(
&
n_hdlc
->
tx_free_buf_list
,
buf
);
else
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
else
if
(
debuglevel
>=
DEBUG_LEVEL_INFO
)
...
@@ -908,31 +865,23 @@ static struct n_hdlc *n_hdlc_alloc (void)
...
@@ -908,31 +865,23 @@ static struct n_hdlc *n_hdlc_alloc (void)
}
/* end of n_hdlc_alloc() */
}
/* end of n_hdlc_alloc() */
/* n_hdlc_buf_list_init()
/**
*
* n_hdlc_buf_list_init - initialize specified HDLC buffer list
* initialize specified HDLC buffer list
* @list - pointer to buffer list
*
* Arguments: list pointer to buffer list
* Return Value: None
*/
*/
static
void
n_hdlc_buf_list_init
(
N_HDLC_BUF_LIST
*
list
)
static
void
n_hdlc_buf_list_init
(
struct
n_hdlc_buf_list
*
list
)
{
{
memset
(
list
,
0
,
sizeof
(
N_HDLC_BUF_LIST
));
memset
(
list
,
0
,
sizeof
(
*
list
));
spin_lock_init
(
&
list
->
spinlock
);
spin_lock_init
(
&
list
->
spinlock
);
}
/* end of n_hdlc_buf_list_init() */
}
/* end of n_hdlc_buf_list_init() */
/* n_hdlc_buf_put()
/**
*
* n_hdlc_buf_put - add specified HDLC buffer to tail of specified list
* add specified HDLC buffer to tail of specified list
* @list - pointer to buffer list
*
* @buf - pointer to buffer
* Arguments:
*
* list pointer to buffer list
* buf pointer to buffer
*
* Return Value: None
*/
*/
static
void
n_hdlc_buf_put
(
N_HDLC_BUF_LIST
*
list
,
N_HDLC_BUF
*
buf
)
static
void
n_hdlc_buf_put
(
struct
n_hdlc_buf_list
*
list
,
struct
n_hdlc_buf
*
buf
)
{
{
unsigned
long
flags
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
list
->
spinlock
,
flags
);
spin_lock_irqsave
(
&
list
->
spinlock
,
flags
);
...
@@ -949,23 +898,18 @@ static void n_hdlc_buf_put(N_HDLC_BUF_LIST *list,N_HDLC_BUF *buf)
...
@@ -949,23 +898,18 @@ static void n_hdlc_buf_put(N_HDLC_BUF_LIST *list,N_HDLC_BUF *buf)
}
/* end of n_hdlc_buf_put() */
}
/* end of n_hdlc_buf_put() */
/* n_hdlc_buf_get()
/**
* n_hdlc_buf_get - remove and return an HDLC buffer from list
* @list - pointer to HDLC buffer list
*
*
* remove and return an HDLC buffer from the
* Remove and return an HDLC buffer from the head of the specified HDLC buffer
* head of the specified HDLC buffer list
* list.
*
* Returns a pointer to HDLC buffer if available, otherwise %NULL.
* Arguments:
*
* list pointer to HDLC buffer list
*
* Return Value:
*
* pointer to HDLC buffer if available, otherwise NULL
*/
*/
static
N_HDLC_BUF
*
n_hdlc_buf_get
(
N_HDLC_BUF_LIST
*
list
)
static
struct
n_hdlc_buf
*
n_hdlc_buf_get
(
struct
n_hdlc_buf_list
*
list
)
{
{
unsigned
long
flags
;
unsigned
long
flags
;
N_HDLC_BUF
*
buf
;
struct
n_hdlc_buf
*
buf
;
spin_lock_irqsave
(
&
list
->
spinlock
,
flags
);
spin_lock_irqsave
(
&
list
->
spinlock
,
flags
);
buf
=
list
->
head
;
buf
=
list
->
head
;
...
@@ -981,42 +925,60 @@ static N_HDLC_BUF* n_hdlc_buf_get(N_HDLC_BUF_LIST *list)
...
@@ -981,42 +925,60 @@ static N_HDLC_BUF* n_hdlc_buf_get(N_HDLC_BUF_LIST *list)
}
/* end of n_hdlc_buf_get() */
}
/* end of n_hdlc_buf_get() */
static
char
hdlc_banner
[]
__initdata
=
KERN_INFO
"HDLC line discipline: version "
HDLC_VERSION
", maxframe=%u
\n
"
;
static
char
hdlc_register_ok
[]
__initdata
=
KERN_INFO
"N_HDLC line discipline registered.
\n
"
;
static
char
hdlc_register_fail
[]
__initdata
=
KERN_ERR
"error registering line discipline: %d
\n
"
;
static
char
hdlc_init_fail
[]
__initdata
=
KERN_INFO
"N_HDLC: init failure %d
\n
"
;
static
int
__init
n_hdlc_init
(
void
)
static
int
__init
n_hdlc_init
(
void
)
{
{
int
status
;
int
status
;
/* range check maxframe arg */
/* range check maxframe arg */
if
(
maxframe
<
4096
)
if
(
maxframe
<
4096
)
maxframe
=
4096
;
maxframe
=
4096
;
else
if
(
maxframe
>
65535
)
else
if
(
maxframe
>
65535
)
maxframe
=
65535
;
maxframe
=
65535
;
printk
(
"HDLC line discipline: version %s, maxframe=%u
\n
"
,
printk
(
hdlc_banner
,
maxframe
);
szVersion
,
maxframe
);
status
=
tty_register_ldisc
(
N_HDLC
,
&
n_hdlc_ldisc
);
status
=
tty_register_ldisc
(
N_HDLC
,
&
n_hdlc_ldisc
);
if
(
!
status
)
if
(
!
status
)
printk
(
KERN_INFO
"N_HDLC line discipline registered.
\n
"
);
printk
(
hdlc_register_ok
);
else
else
printk
(
KERN_ERR
"error registering line discipline: %d
\n
"
,
status
);
printk
(
hdlc_register_fail
,
status
);
if
(
status
)
if
(
status
)
printk
(
KERN_INFO
"N_HDLC: init failure %d
\n
"
,
status
);
printk
(
hdlc_init_fail
,
status
);
return
(
status
)
;
return
status
;
}
/* end of init_module() */
}
/* end of init_module() */
static
char
hdlc_unregister_ok
[]
__exitdata
=
KERN_INFO
"N_HDLC: line discipline unregistered
\n
"
;
static
char
hdlc_unregister_fail
[]
__exitdata
=
KERN_ERR
"N_HDLC: can't unregister line discipline (err = %d)
\n
"
;
static
void
__exit
n_hdlc_exit
(
void
)
static
void
__exit
n_hdlc_exit
(
void
)
{
{
int
status
;
/* Release tty registration of line discipline */
/* Release tty registration of line discipline */
if
((
status
=
tty_register_ldisc
(
N_HDLC
,
NULL
)))
int
status
=
tty_register_ldisc
(
N_HDLC
,
NULL
);
printk
(
"N_HDLC: can't unregister line discipline (err = %d)
\n
"
,
status
);
if
(
status
)
printk
(
hdlc_unregister_fail
,
status
);
else
else
printk
(
"N_HDLC: line discipline unregistered
\n
"
);
printk
(
hdlc_unregister_ok
);
}
}
module_init
(
n_hdlc_init
);
module_init
(
n_hdlc_init
);
module_exit
(
n_hdlc_exit
);
module_exit
(
n_hdlc_exit
);
MODULE_LICENSE
(
"GPL"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_AUTHOR
(
"Paul Fulghum paulkf@microgate.com"
);
MODULE_PARM
(
debuglevel
,
"i"
);
MODULE_PARM
(
maxframe
,
"i"
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment