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
f2fd8c4f
Commit
f2fd8c4f
authored
May 20, 2003
by
Greg Kroah-Hartman
Browse files
Options
Browse Files
Download
Plain Diff
merge
parents
854d19a9
74265588
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
240 additions
and
400 deletions
+240
-400
drivers/usb/misc/speedtch.c
drivers/usb/misc/speedtch.c
+240
-400
No files found.
drivers/usb/misc/speedtch.c
View file @
f2fd8c4f
/******************************************************************************
/******************************************************************************
* speedtouch.c -
- Alcatel SpeedTouch USB xDSL modem driver.
* speedtouch.c -
Alcatel SpeedTouch USB xDSL modem driver
*
*
* Copyright (C) 2001, Alcatel
* Copyright (C) 2001, Alcatel
* Copyright (C) 2003, Duncan Sands
*
*
* This program is free software; you can redistribute it and/or modify it
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* under the terms of the GNU General Public License as published by the Free
...
@@ -40,7 +41,6 @@
...
@@ -40,7 +41,6 @@
* udsl_usb_send_data_context->urb to a pointer and adding code
* udsl_usb_send_data_context->urb to a pointer and adding code
* to alloc and free it
* to alloc and free it
* - remove_wait_queue() added to udsl_atm_processqueue_thread()
* - remove_wait_queue() added to udsl_atm_processqueue_thread()
* - Duncan Sands (duncan.sands@wanadoo.fr) is the new maintainer
*
*
* 1.5: - fixed memory leak when atmsar_decode_aal5 returned NULL.
* 1.5: - fixed memory leak when atmsar_decode_aal5 returned NULL.
* (reported by stephen.robinson@zen.co.uk)
* (reported by stephen.robinson@zen.co.uk)
...
@@ -97,48 +97,65 @@ static int udsl_print_packet (const unsigned char *data, int len);
...
@@ -97,48 +97,65 @@ static int udsl_print_packet (const unsigned char *data, int len);
#define DRIVER_DESC "Alcatel SpeedTouch USB driver"
#define DRIVER_DESC "Alcatel SpeedTouch USB driver"
#define DRIVER_VERSION "1.6"
#define DRIVER_VERSION "1.6"
static
const
char
udsl_driver_name
[]
=
"speedtch"
;
#define SPEEDTOUCH_VENDORID 0x06b9
#define SPEEDTOUCH_VENDORID 0x06b9
#define SPEEDTOUCH_PRODUCTID 0x4061
#define SPEEDTOUCH_PRODUCTID 0x4061
#define UDSL_NUMBER_RCV_URBS 1
#define UDSL_NUM_RCV_URBS 1
#define UDSL_NUMBER_SND_URBS 1
#define UDSL_NUM_SND_URBS 1
#define UDSL_NUMBER_SND_BUFS (2*UDSL_NUMBER_SND_URBS)
#define UDSL_NUM_RCV_BUFS (2*UDSL_NUM_RCV_URBS)
#define UDSL_RCV_BUFFER_SIZE (1*64)
/* ATM cells */
#define UDSL_NUM_SND_BUFS (2*UDSL_NUM_SND_URBS)
#define UDSL_SND_BUFFER_SIZE (1*64)
/* ATM cells */
#define UDSL_RCV_BUF_SIZE 32
/* ATM cells */
/* max should be (1500 IP mtu + 2 ppp bytes + 32 * 5 cellheader overhead) for
#define UDSL_SND_BUF_SIZE 64
/* ATM cells */
* PPPoA and (1500 + 14 + 32*5 cellheader overhead) for PPPoE */
#define UDSL_MAX_AAL5_MRU 2048
#define UDSL_IOCTL_START 1
#define UDSL_IOCTL_STOP 2
/* endpoint declarations */
#define UDSL_IOCTL_LINE_UP 1
#define UDSL_IOCTL_LINE_DOWN 2
#define UDSL_ENDPOINT_DATA_OUT 0x07
#define UDSL_ENDPOINT_DATA_OUT 0x07
#define UDSL_ENDPOINT_DATA_IN 0x87
#define UDSL_ENDPOINT_DATA_IN 0x87
#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
#define UDSL_NUM_CELLS(x) (((x) + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD)
#define hex2int(c) ( (c >= '0')&&(c <= '9') ? (c - '0') : ((c & 0xf)+9) )
#define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) )
/* usb_device_id struct */
static
struct
usb_device_id
udsl_usb_ids
[]
=
{
static
struct
usb_device_id
udsl_usb_ids
[]
=
{
{
USB_DEVICE
(
SPEEDTOUCH_VENDORID
,
SPEEDTOUCH_PRODUCTID
)
},
{
USB_DEVICE
(
SPEEDTOUCH_VENDORID
,
SPEEDTOUCH_PRODUCTID
)
},
{
}
/* Terminating entry */
{
}
};
};
MODULE_DEVICE_TABLE
(
usb
,
udsl_usb_ids
);
MODULE_DEVICE_TABLE
(
usb
,
udsl_usb_ids
);
/* context declarations */
/* receive */
struct
udsl_receive_buffer
{
struct
list_head
list
;
unsigned
char
*
base
;
unsigned
int
filled_cells
;
};
struct
udsl_receiver
{
struct
udsl_receiver
{
struct
list_head
list
;
struct
list_head
list
;
struct
sk_buff
*
skb
;
struct
udsl_receive_buffer
*
buffer
;
struct
urb
*
urb
;
struct
urb
*
urb
;
struct
udsl_instance_data
*
instance
;
struct
udsl_instance_data
*
instance
;
};
};
struct
udsl_vcc_data
{
/* vpi/vci lookup */
struct
list_head
list
;
short
vpi
;
int
vci
;
struct
atm_vcc
*
vcc
;
/* raw cell reassembly */
struct
sk_buff
*
skb
;
unsigned
int
max_pdu
;
};
/* send */
struct
udsl_send_buffer
{
struct
udsl_send_buffer
{
struct
list_head
list
;
struct
list_head
list
;
unsigned
char
*
base
;
unsigned
char
*
base
;
...
@@ -157,73 +174,55 @@ struct udsl_control {
...
@@ -157,73 +174,55 @@ struct udsl_control {
struct
atm_skb_data
atm_data
;
struct
atm_skb_data
atm_data
;
unsigned
int
num_cells
;
unsigned
int
num_cells
;
unsigned
int
num_entire
;
unsigned
int
num_entire
;
unsigned
char
cell_header
[
ATM_CELL_HEADER
];
unsigned
int
pdu_padding
;
unsigned
int
pdu_padding
;
unsigned
char
cell_header
[
ATM_CELL_HEADER
];
unsigned
char
aal5_trailer
[
ATM_AAL5_TRAILER
];
unsigned
char
aal5_trailer
[
ATM_AAL5_TRAILER
];
};
};
#define UDSL_SKB(x) ((struct udsl_control *)(x)->cb)
#define UDSL_SKB(x) ((struct udsl_control *)(x)->cb)
struct
udsl_vcc_data
{
/* main driver data */
/* vpi/vci lookup */
struct
list_head
list
;
short
vpi
;
int
vci
;
struct
atm_vcc
*
vcc
;
/* raw cell reassembly */
unsigned
short
mtu
;
struct
sk_buff
*
reasBuffer
;
};
/*
* UDSL main driver data
*/
struct
udsl_instance_data
{
struct
udsl_instance_data
{
struct
semaphore
serialize
;
struct
semaphore
serialize
;
/*
usb
device part */
/*
USB
device part */
struct
usb_device
*
usb_dev
;
struct
usb_device
*
usb_dev
;
char
description
[
64
];
char
description
[
64
];
int
firmware_loaded
;
int
firmware_loaded
;
/*
atm
device part */
/*
ATM
device part */
struct
atm_dev
*
atm_dev
;
struct
atm_dev
*
atm_dev
;
struct
list_head
vcc_list
;
struct
list_head
vcc_list
;
/* receiving */
/* receive */
struct
udsl_receiver
all_receivers
[
UDSL_NUMBER_RCV_URBS
];
struct
udsl_receiver
receivers
[
UDSL_NUM_RCV_URBS
];
struct
udsl_receive_buffer
receive_buffers
[
UDSL_NUM_RCV_BUFS
];
spinlock_t
spare_receivers
_lock
;
spinlock_t
receive
_lock
;
struct
list_head
spare_receivers
;
struct
list_head
spare_receivers
;
struct
list_head
filled_receive_buffers
;
spinlock_t
completed_receivers_lock
;
struct
list_head
completed_receivers
;
struct
tasklet_struct
receive_tasklet
;
struct
tasklet_struct
receive_tasklet
;
struct
list_head
spare_receive_buffers
;
/* send
ing
*/
/* send */
struct
udsl_sender
all_senders
[
UDSL_NUMBER
_SND_URBS
];
struct
udsl_sender
senders
[
UDSL_NUM
_SND_URBS
];
struct
udsl_send_buffer
all_buffers
[
UDSL_NUMBER
_SND_BUFS
];
struct
udsl_send_buffer
send_buffers
[
UDSL_NUM
_SND_BUFS
];
struct
sk_buff_head
sndqueue
;
struct
sk_buff_head
sndqueue
;
spinlock_t
send_lock
;
spinlock_t
send_lock
;
struct
list_head
spare_senders
;
struct
list_head
spare_senders
;
struct
list_head
spare_buffers
;
struct
list_head
spare_
send_
buffers
;
struct
tasklet_struct
send_tasklet
;
struct
tasklet_struct
send_tasklet
;
struct
sk_buff
*
current_skb
;
/* being emptied */
struct
sk_buff
*
current_skb
;
/* being emptied */
struct
udsl_send_buffer
*
current_buffer
;
/* being filled */
struct
udsl_send_buffer
*
current_buffer
;
/* being filled */
struct
list_head
filled_buffers
;
struct
list_head
filled_
send_
buffers
;
};
};
static
const
char
udsl_driver_name
[]
=
"speedtch"
;
/* ATM */
/*
* atm driver prototypes and structures
*/
static
void
udsl_atm_dev_close
(
struct
atm_dev
*
dev
);
static
void
udsl_atm_dev_close
(
struct
atm_dev
*
dev
);
static
int
udsl_atm_open
(
struct
atm_vcc
*
vcc
,
short
vpi
,
int
vci
);
static
int
udsl_atm_open
(
struct
atm_vcc
*
vcc
,
short
vpi
,
int
vci
);
...
@@ -241,11 +240,9 @@ static struct atmdev_ops udsl_atm_devops = {
...
@@ -241,11 +240,9 @@ static struct atmdev_ops udsl_atm_devops = {
.
proc_read
=
udsl_atm_proc_read
,
.
proc_read
=
udsl_atm_proc_read
,
};
};
/*
/* USB */
* usb driver prototypes and structures
*/
static
int
udsl_usb_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
);
static
int
udsl_usb_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
);
static
void
udsl_usb_disconnect
(
struct
usb_interface
*
intf
);
static
void
udsl_usb_disconnect
(
struct
usb_interface
*
intf
);
static
int
udsl_usb_ioctl
(
struct
usb_interface
*
intf
,
unsigned
int
code
,
void
*
user_data
);
static
int
udsl_usb_ioctl
(
struct
usb_interface
*
intf
,
unsigned
int
code
,
void
*
user_data
);
...
@@ -272,133 +269,47 @@ static inline struct udsl_vcc_data *udsl_find_vcc (struct udsl_instance_data *in
...
@@ -272,133 +269,47 @@ static inline struct udsl_vcc_data *udsl_find_vcc (struct udsl_instance_data *in
return
NULL
;
return
NULL
;
}
}
static
struct
sk_buff
*
udsl_decode_rawcell
(
struct
udsl_instance_data
*
instance
,
struct
sk_buff
*
skb
,
struct
udsl_vcc_data
**
ctx
)
static
void
udsl_extract_cells
(
struct
udsl_instance_data
*
instance
,
unsigned
char
*
source
,
unsigned
int
howmany
)
{
{
if
(
!
instance
||
!
skb
||
!
ctx
)
struct
udsl_vcc_data
*
cached_vcc
=
NULL
;
return
NULL
;
struct
atm_vcc
*
vcc
;
if
(
!
skb
->
data
||
!
skb
->
tail
)
struct
sk_buff
*
skb
;
return
NULL
;
struct
udsl_vcc_data
*
vcc_data
;
int
cached_vci
=
0
;
while
(
skb
->
len
)
{
unsigned
int
i
;
unsigned
char
*
cell
=
skb
->
data
;
unsigned
int
length
;
unsigned
char
*
cell_payload
;
unsigned
int
pdu_length
;
struct
udsl_vcc_data
*
vcc
;
int
pti
;
short
vpi
;
int
vci
;
int
vci
;
short
cached_vpi
=
0
;
short
vpi
;
vpi
=
((
cell
[
0
]
&
0x0f
)
<<
4
)
|
(
cell
[
1
]
>>
4
);
vci
=
((
cell
[
1
]
&
0x0f
)
<<
12
)
|
(
cell
[
2
]
<<
4
)
|
(
cell
[
3
]
>>
4
);
vdbg
(
"udsl_decode_rawcell (0x%p, 0x%p, 0x%p) called"
,
instance
,
skb
,
ctx
);
for
(
i
=
0
;
i
<
howmany
;
i
++
,
source
+=
ATM_CELL_SIZE
)
{
vdbg
(
"udsl_decode_rawcell skb->data %p, skb->tail %p"
,
skb
->
data
,
skb
->
tail
);
vpi
=
((
source
[
0
]
&
0x0f
)
<<
4
)
|
(
source
[
1
]
>>
4
);
vci
=
((
source
[
1
]
&
0x0f
)
<<
12
)
|
(
source
[
2
]
<<
4
)
|
(
source
[
3
]
>>
4
);
pti
=
(
source
[
3
]
&
0x2
)
!=
0
;
/* here should the header CRC check be... */
vdbg
(
"udsl_extract_cells: vpi %hd, vci %d, pti %d"
,
vpi
,
vci
,
pti
);
if
(
!
(
vcc
=
udsl_find_vcc
(
instance
,
vpi
,
vci
)))
{
if
(
cached_vcc
&&
(
vci
==
cached_vci
)
&&
(
vpi
==
cached_vpi
))
dbg
(
"udsl_decode_rawcell: no vcc found for packet on vpi %d, vci %d"
,
vpi
,
vci
);
vcc_data
=
cached_vcc
;
__skb_pull
(
skb
,
min
(
skb
->
len
,
(
unsigned
)
53
));
else
if
((
vcc_data
=
udsl_find_vcc
(
instance
,
vpi
,
vci
)))
{
cached_vcc
=
vcc_data
;
cached_vpi
=
vpi
;
cached_vci
=
vci
;
}
else
{
}
else
{
vdbg
(
"udsl_decode_rawcell found vcc %p for packet on vpi %d, vci %d"
,
vcc
,
vpi
,
vci
);
dbg
(
"udsl_extract_cells: unknown vpi/vci (%hd/%d)!"
,
vpi
,
vci
);
continue
;
if
(
skb
->
len
>=
53
)
{
cell_payload
=
cell
+
5
;
if
(
!
vcc
->
reasBuffer
)
vcc
->
reasBuffer
=
dev_alloc_skb
(
vcc
->
mtu
);
/* if alloc fails, we just drop the cell. it is possible that we can still
* receive cells on other vcc's
*/
if
(
vcc
->
reasBuffer
)
{
/* if (buffer overrun) discard received cells until now */
if
((
vcc
->
reasBuffer
->
len
)
>
(
vcc
->
mtu
-
48
))
skb_trim
(
vcc
->
reasBuffer
,
0
);
/* copy data */
memcpy
(
vcc
->
reasBuffer
->
tail
,
cell_payload
,
48
);
skb_put
(
vcc
->
reasBuffer
,
48
);
/* check for end of buffer */
if
(
cell
[
3
]
&
0x2
)
{
struct
sk_buff
*
tmp
;
/* the aal5 buffer ends here, cut the buffer. */
/* buffer will always have at least one whole cell, so */
/* don't need to check return from skb_pull */
skb_pull
(
skb
,
53
);
*
ctx
=
vcc
;
tmp
=
vcc
->
reasBuffer
;
vcc
->
reasBuffer
=
NULL
;
vdbg
(
"udsl_decode_rawcell returns ATM_AAL5 pdu 0x%p with length %d"
,
tmp
,
tmp
->
len
);
return
tmp
;
}
}
/* flush the cell */
/* buffer will always contain at least one whole cell, so don't */
/* need to check return value from skb_pull */
skb_pull
(
skb
,
53
);
}
else
{
/* If data is corrupt and skb doesn't hold a whole cell, flush the lot */
__skb_pull
(
skb
,
skb
->
len
);
return
NULL
;
}
}
}
}
return
NULL
;
}
static
struct
sk_buff
*
udsl_decode_aal5
(
struct
udsl_vcc_data
*
ctx
,
struct
sk_buff
*
skb
)
{
uint
crc
=
0xffffffff
;
uint
length
,
pdu_crc
,
pdu_length
;
vdbg
(
"udsl_decode_aal5 (0x%p, 0x%p) called"
,
ctx
,
skb
);
if
(
skb
->
len
&&
(
skb
->
len
%
48
))
return
NULL
;
length
=
(
skb
->
tail
[
-
6
]
<<
8
)
+
skb
->
tail
[
-
5
];
pdu_crc
=
(
skb
->
tail
[
-
4
]
<<
24
)
+
(
skb
->
tail
[
-
3
]
<<
16
)
+
(
skb
->
tail
[
-
2
]
<<
8
)
+
skb
->
tail
[
-
1
];
pdu_length
=
((
length
+
47
+
8
)
/
48
)
*
48
;
vdbg
(
"udsl_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d"
,
skb
->
len
,
length
,
pdu_crc
,
pdu_length
);
/* is skb long enough ? */
if
(
skb
->
len
<
pdu_length
)
{
atomic_inc
(
&
ctx
->
vcc
->
stats
->
rx_err
);
return
NULL
;
}
/* is skb too long ? */
if
(
skb
->
len
>
pdu_length
)
{
dbg
(
"udsl_decode_aal5: Warning: readjusting illegal size %d -> %d"
,
skb
->
len
,
pdu_length
);
/* buffer is too long. we can try to recover
* if we discard the first part of the skb.
* the crc will decide whether this was ok
*/
skb_pull
(
skb
,
skb
->
len
-
pdu_length
);
}
crc
=
~
crc32_be
(
crc
,
skb
->
data
,
pdu_length
-
4
);
/* check crc */
if
(
pdu_crc
!=
crc
)
{
dbg
(
"udsl_decode_aal5: crc check failed!"
);
atomic_inc
(
&
ctx
->
vcc
->
stats
->
rx_err
);
return
NULL
;
}
/* pdu is ok */
skb_trim
(
skb
,
length
);
/* update stats */
vcc
=
vcc_data
->
vcc
;
atomic_inc
(
&
ctx
->
vcc
->
stats
->
rx
);
vdbg
(
"udsl_decode_aal5 returns pdu 0x%p with length %d"
,
skb
,
skb
->
len
);
if
(
!
vcc_data
->
skb
&&
!
(
vcc_data
->
skb
=
dev_alloc_skb
(
vcc_data
->
max_pdu
)))
{
return
skb
;
dbg
(
"udsl_extract_cells: no memory for skb (vcc: 0x%p)!"
,
vcc
);
if
(
pti
)
atomic_inc
(
&
vcc
->
stats
->
rx_err
);
continue
;
}
}
}
...
@@ -406,7 +317,7 @@ static struct sk_buff *udsl_decode_aal5 (struct udsl_vcc_data *ctx, struct sk_bu
...
@@ -406,7 +317,7 @@ static struct sk_buff *udsl_decode_aal5 (struct udsl_vcc_data *ctx, struct sk_bu
** encode **
** encode **
*************/
*************/
static
const
unsigned
char
zeros
[
ATM_CELL_PAYLOAD
];
static
const
unsigned
char
zeros
[
ATM_CELL_PAYLOAD
];
static
void
udsl_groom_skb
(
struct
atm_vcc
*
vcc
,
struct
sk_buff
*
skb
)
static
void
udsl_groom_skb
(
struct
atm_vcc
*
vcc
,
struct
sk_buff
*
skb
)
{
{
...
@@ -421,7 +332,7 @@ static void udsl_groom_skb (struct atm_vcc *vcc, struct sk_buff *skb)
...
@@ -421,7 +332,7 @@ static void udsl_groom_skb (struct atm_vcc *vcc, struct sk_buff *skb)
ctrl
->
cell_header
[
3
]
=
vcc
->
vci
<<
4
;
ctrl
->
cell_header
[
3
]
=
vcc
->
vci
<<
4
;
ctrl
->
cell_header
[
4
]
=
0xec
;
ctrl
->
cell_header
[
4
]
=
0xec
;
ctrl
->
num_cells
=
(
skb
->
len
+
ATM_AAL5_TRAILER
+
ATM_CELL_PAYLOAD
-
1
)
/
ATM_CELL_PAYLOAD
;
ctrl
->
num_cells
=
UDSL_NUM_CELLS
(
skb
->
len
)
;
ctrl
->
num_entire
=
skb
->
len
/
ATM_CELL_PAYLOAD
;
ctrl
->
num_entire
=
skb
->
len
/
ATM_CELL_PAYLOAD
;
zero_padding
=
ctrl
->
num_cells
*
ATM_CELL_PAYLOAD
-
skb
->
len
-
ATM_AAL5_TRAILER
;
zero_padding
=
ctrl
->
num_cells
*
ATM_CELL_PAYLOAD
-
skb
->
len
-
ATM_AAL5_TRAILER
;
...
@@ -490,8 +401,7 @@ static unsigned int udsl_write_cells (unsigned int howmany, struct sk_buff *skb,
...
@@ -490,8 +401,7 @@ static unsigned int udsl_write_cells (unsigned int howmany, struct sk_buff *skb,
memset
(
target
,
0
,
ATM_CELL_PAYLOAD
-
ATM_AAL5_TRAILER
);
memset
(
target
,
0
,
ATM_CELL_PAYLOAD
-
ATM_AAL5_TRAILER
);
target
+=
ATM_CELL_PAYLOAD
-
ATM_AAL5_TRAILER
;
target
+=
ATM_CELL_PAYLOAD
-
ATM_AAL5_TRAILER
;
if
(
--
ctrl
->
num_cells
)
BUG_ON
(
--
ctrl
->
num_cells
);
BUG
();
}
}
memcpy
(
target
,
ctrl
->
aal5_trailer
,
ATM_AAL5_TRAILER
);
memcpy
(
target
,
ctrl
->
aal5_trailer
,
ATM_AAL5_TRAILER
);
...
@@ -511,145 +421,87 @@ static unsigned int udsl_write_cells (unsigned int howmany, struct sk_buff *skb,
...
@@ -511,145 +421,87 @@ static unsigned int udsl_write_cells (unsigned int howmany, struct sk_buff *skb,
static
void
udsl_complete_receive
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
)
static
void
udsl_complete_receive
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
)
{
{
struct
udsl_receive_buffer
*
buf
;
struct
udsl_instance_data
*
instance
;
struct
udsl_instance_data
*
instance
;
struct
udsl_receiver
*
rcv
;
struct
udsl_receiver
*
rcv
;
unsigned
long
flags
;
unsigned
long
flags
;
if
(
!
urb
||
!
(
rcv
=
urb
->
context
)
||
!
(
instance
=
rcv
->
instance
)
)
{
if
(
!
urb
||
!
(
rcv
=
urb
->
context
))
{
dbg
(
"udsl_complete_receive: bad urb!"
);
dbg
(
"udsl_complete_receive: bad urb!"
);
return
;
return
;
}
}
vdbg
(
"udsl_complete_receive entered (urb 0x%p, status %d)"
,
urb
,
urb
->
status
);
instance
=
rcv
->
instance
;
buf
=
rcv
->
buffer
;
buf
->
filled_cells
=
urb
->
actual_length
/
ATM_CELL_SIZE
;
vdbg
(
"udsl_complete_receive: urb 0x%p, status %d, actual_length %d, filled_cells %u, rcv 0x%p, buf 0x%p"
,
urb
,
urb
->
status
,
urb
->
actual_length
,
buf
->
filled_cells
,
rcv
,
buf
);
BUG_ON
(
buf
->
filled_cells
>
UDSL_RCV_BUF_SIZE
);
/* may not be in_interrupt() */
/* may not be in_interrupt() */
spin_lock_irqsave
(
&
instance
->
completed_receivers_lock
,
flags
);
spin_lock_irqsave
(
&
instance
->
receive_lock
,
flags
);
list_add_tail
(
&
rcv
->
list
,
&
instance
->
completed_receivers
);
list_add
(
&
rcv
->
list
,
&
instance
->
spare_receivers
);
tasklet_schedule
(
&
instance
->
receive_tasklet
);
list_add_tail
(
&
buf
->
list
,
&
instance
->
filled_receive_buffers
);
spin_unlock_irqrestore
(
&
instance
->
completed_receivers_lock
,
flags
);
if
(
likely
(
!
urb
->
status
))
tasklet_schedule
(
&
instance
->
receive_tasklet
);
spin_unlock_irqrestore
(
&
instance
->
receive_lock
,
flags
);
}
}
static
void
udsl_process_receive
(
unsigned
long
data
)
static
void
udsl_process_receive
(
unsigned
long
data
)
{
{
struct
udsl_receive_buffer
*
buf
;
struct
udsl_instance_data
*
instance
=
(
struct
udsl_instance_data
*
)
data
;
struct
udsl_instance_data
*
instance
=
(
struct
udsl_instance_data
*
)
data
;
struct
udsl_receiver
*
rcv
;
struct
udsl_receiver
*
rcv
;
unsigned
char
*
data_start
;
struct
sk_buff
*
skb
;
struct
urb
*
urb
;
struct
udsl_vcc_data
*
atmsar_vcc
=
NULL
;
struct
sk_buff
*
new
=
NULL
,
*
tmp
=
NULL
;
int
err
;
int
err
;
vdbg
(
"udsl_process_receive entered"
);
made_progress:
while
(
!
list_empty
(
&
instance
->
spare_receive_buffers
))
{
spin_lock_irq
(
&
instance
->
completed_receivers_lock
);
spin_lock_irq
(
&
instance
->
receive_lock
);
while
(
!
list_empty
(
&
instance
->
completed_receivers
))
{
if
(
list_empty
(
&
instance
->
spare_receivers
))
{
rcv
=
list_entry
(
instance
->
completed_receivers
.
next
,
struct
udsl_receiver
,
list
);
spin_unlock_irq
(
&
instance
->
receive_lock
);
list_del
(
&
rcv
->
list
);
spin_unlock_irq
(
&
instance
->
completed_receivers_lock
);
urb
=
rcv
->
urb
;
vdbg
(
"udsl_process_receive: got packet %p with length %d and status %d"
,
urb
,
urb
->
actual_length
,
urb
->
status
);
switch
(
urb
->
status
)
{
case
0
:
vdbg
(
"udsl_process_receive: processing urb with rcv %p, urb %p, skb %p"
,
rcv
,
urb
,
rcv
->
skb
);
/* update the skb structure */
skb
=
rcv
->
skb
;
skb_trim
(
skb
,
0
);
skb_put
(
skb
,
urb
->
actual_length
);
data_start
=
skb
->
data
;
vdbg
(
"skb->len = %d"
,
skb
->
len
);
PACKETDEBUG
(
skb
->
data
,
skb
->
len
);
while
((
new
=
udsl_decode_rawcell
(
instance
,
skb
,
&
atmsar_vcc
)))
{
vdbg
(
"(after cell processing)skb->len = %d"
,
new
->
len
);
tmp
=
new
;
new
=
udsl_decode_aal5
(
atmsar_vcc
,
new
);
/* we can't send NULL skbs upstream, the ATM layer would try to close the vcc... */
if
(
new
)
{
vdbg
(
"(after aal5 decap) skb->len = %d"
,
new
->
len
);
if
(
new
->
len
&&
atm_charge
(
atmsar_vcc
->
vcc
,
new
->
truesize
))
{
PACKETDEBUG
(
new
->
data
,
new
->
len
);
atmsar_vcc
->
vcc
->
push
(
atmsar_vcc
->
vcc
,
new
);
}
else
{
dbg
(
"dropping incoming packet : vcc->sk->rcvbuf = %d, skb->true_size = %d"
,
atmsar_vcc
->
vcc
->
sk
->
rcvbuf
,
new
->
truesize
);
dev_kfree_skb
(
new
);
}
}
else
{
dbg
(
"udsl_decode_aal5 returned NULL!"
);
dev_kfree_skb
(
tmp
);
}
}
/* restore skb */
skb_push
(
skb
,
skb
->
data
-
data_start
);
usb_fill_bulk_urb
(
urb
,
instance
->
usb_dev
,
usb_rcvbulkpipe
(
instance
->
usb_dev
,
UDSL_ENDPOINT_DATA_IN
),
(
unsigned
char
*
)
rcv
->
skb
->
data
,
UDSL_RCV_BUFFER_SIZE
*
ATM_CELL_SIZE
,
udsl_complete_receive
,
rcv
);
if
(
!
(
err
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
)))
break
;
dbg
(
"udsl_process_receive: submission failed (%d)"
,
err
);
/* fall through */
default:
/* error or urb unlinked */
vdbg
(
"udsl_process_receive: adding to spare_receivers"
);
spin_lock_irq
(
&
instance
->
spare_receivers_lock
);
list_add
(
&
rcv
->
list
,
&
instance
->
spare_receivers
);
spin_unlock_irq
(
&
instance
->
spare_receivers_lock
);
break
;
break
;
}
/* switch */
}
rcv
=
list_entry
(
instance
->
spare_receivers
.
next
,
struct
udsl_receiver
,
list
);
spin_lock_irq
(
&
instance
->
completed_receivers_lock
);
list_del
(
&
rcv
->
list
);
}
/* while */
spin_unlock_irq
(
&
instance
->
receive_lock
);
spin_unlock_irq
(
&
instance
->
completed_receivers_lock
);
buf
=
list_entry
(
instance
->
spare_receive_buffers
.
next
,
struct
udsl_receive_buffer
,
list
);
vdbg
(
"udsl_process_receive successful"
);
list_del
(
&
buf
->
list
);
}
rcv
->
buffer
=
buf
;
static
void
udsl_fire_receivers
(
struct
udsl_instance_data
*
instance
)
{
struct
list_head
receivers
,
*
pos
,
*
n
;
INIT_LIST_HEAD
(
&
receivers
);
down
(
&
instance
->
serialize
);
spin_lock_irq
(
&
instance
->
spare_receivers_lock
);
list_splice_init
(
&
instance
->
spare_receivers
,
&
receivers
);
spin_unlock_irq
(
&
instance
->
spare_receivers_lock
);
list_for_each_safe
(
pos
,
n
,
&
receivers
)
{
struct
udsl_receiver
*
rcv
=
list_entry
(
pos
,
struct
udsl_receiver
,
list
);
dbg
(
"udsl_fire_receivers: firing urb %p"
,
rcv
->
urb
);
usb_fill_bulk_urb
(
rcv
->
urb
,
usb_fill_bulk_urb
(
rcv
->
urb
,
instance
->
usb_dev
,
instance
->
usb_dev
,
usb_rcvbulkpipe
(
instance
->
usb_dev
,
UDSL_ENDPOINT_DATA_IN
),
usb_rcvbulkpipe
(
instance
->
usb_dev
,
UDSL_ENDPOINT_DATA_IN
),
(
unsigned
char
*
)
rcv
->
skb
->
data
,
buf
->
base
,
UDSL_RCV_BUF
FER
_SIZE
*
ATM_CELL_SIZE
,
UDSL_RCV_BUF_SIZE
*
ATM_CELL_SIZE
,
udsl_complete_receive
,
udsl_complete_receive
,
rcv
);
rcv
);
if
(
usb_submit_urb
(
rcv
->
urb
,
GFP_KERNEL
)
<
0
)
{
vdbg
(
"udsl_process_receive: sending urb 0x%p, rcv 0x%p, buf 0x%p"
,
rcv
->
urb
,
rcv
,
buf
);
dbg
(
"udsl_fire_receivers: submit failed!"
);
spin_lock_irq
(
&
instance
->
spare_receivers_lock
);
if
((
err
=
usb_submit_urb
(
rcv
->
urb
,
GFP_ATOMIC
))
<
0
)
{
list_move
(
pos
,
&
instance
->
spare_receivers
);
dbg
(
"udsl_process_receive: urb submission failed (%d)!"
,
err
);
spin_unlock_irq
(
&
instance
->
spare_receivers_lock
);
list_add
(
&
buf
->
list
,
&
instance
->
spare_receive_buffers
);
spin_lock_irq
(
&
instance
->
receive_lock
);
list_add
(
&
rcv
->
list
,
&
instance
->
spare_receivers
);
spin_unlock_irq
(
&
instance
->
receive_lock
);
break
;
}
}
}
}
up
(
&
instance
->
serialize
);
spin_lock_irq
(
&
instance
->
receive_lock
);
if
(
list_empty
(
&
instance
->
filled_receive_buffers
))
{
spin_unlock_irq
(
&
instance
->
receive_lock
);
return
;
/* done - no more buffers */
}
buf
=
list_entry
(
instance
->
filled_receive_buffers
.
next
,
struct
udsl_receive_buffer
,
list
);
list_del
(
&
buf
->
list
);
spin_unlock_irq
(
&
instance
->
receive_lock
);
vdbg
(
"udsl_process_receive: processing buf 0x%p"
,
buf
);
udsl_extract_cells
(
instance
,
buf
->
base
,
buf
->
filled_cells
);
list_add
(
&
buf
->
list
,
&
instance
->
spare_receive_buffers
);
goto
made_progress
;
}
}
...
@@ -673,7 +525,7 @@ static void udsl_complete_send (struct urb *urb, struct pt_regs *regs)
...
@@ -673,7 +525,7 @@ static void udsl_complete_send (struct urb *urb, struct pt_regs *regs)
/* may not be in_interrupt() */
/* may not be in_interrupt() */
spin_lock_irqsave
(
&
instance
->
send_lock
,
flags
);
spin_lock_irqsave
(
&
instance
->
send_lock
,
flags
);
list_add
(
&
snd
->
list
,
&
instance
->
spare_senders
);
list_add
(
&
snd
->
list
,
&
instance
->
spare_senders
);
list_add
(
&
snd
->
buffer
->
list
,
&
instance
->
spare_buffers
);
list_add
(
&
snd
->
buffer
->
list
,
&
instance
->
spare_
send_
buffers
);
tasklet_schedule
(
&
instance
->
send_tasklet
);
tasklet_schedule
(
&
instance
->
send_tasklet
);
spin_unlock_irqrestore
(
&
instance
->
send_lock
,
flags
);
spin_unlock_irqrestore
(
&
instance
->
send_lock
,
flags
);
}
}
...
@@ -681,17 +533,17 @@ static void udsl_complete_send (struct urb *urb, struct pt_regs *regs)
...
@@ -681,17 +533,17 @@ static void udsl_complete_send (struct urb *urb, struct pt_regs *regs)
static
void
udsl_process_send
(
unsigned
long
data
)
static
void
udsl_process_send
(
unsigned
long
data
)
{
{
struct
udsl_send_buffer
*
buf
;
struct
udsl_send_buffer
*
buf
;
int
err
;
struct
udsl_instance_data
*
instance
=
(
struct
udsl_instance_data
*
)
data
;
struct
udsl_instance_data
*
instance
=
(
struct
udsl_instance_data
*
)
data
;
unsigned
int
num_written
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
struct
udsl_sender
*
snd
;
struct
udsl_sender
*
snd
;
int
err
;
unsigned
int
num_written
;
made_progress:
made_progress:
spin_lock_irq
(
&
instance
->
send_lock
);
spin_lock_irq
(
&
instance
->
send_lock
);
while
(
!
list_empty
(
&
instance
->
spare_senders
))
{
while
(
!
list_empty
(
&
instance
->
spare_senders
))
{
if
(
!
list_empty
(
&
instance
->
filled_buffers
))
{
if
(
!
list_empty
(
&
instance
->
filled_
send_
buffers
))
{
buf
=
list_entry
(
instance
->
filled_buffers
.
next
,
struct
udsl_send_buffer
,
list
);
buf
=
list_entry
(
instance
->
filled_
send_
buffers
.
next
,
struct
udsl_send_buffer
,
list
);
list_del
(
&
buf
->
list
);
list_del
(
&
buf
->
list
);
}
else
if
((
buf
=
instance
->
current_buffer
))
{
}
else
if
((
buf
=
instance
->
current_buffer
))
{
instance
->
current_buffer
=
NULL
;
instance
->
current_buffer
=
NULL
;
...
@@ -707,7 +559,7 @@ static void udsl_process_send (unsigned long data)
...
@@ -707,7 +559,7 @@ static void udsl_process_send (unsigned long data)
instance
->
usb_dev
,
instance
->
usb_dev
,
usb_sndbulkpipe
(
instance
->
usb_dev
,
UDSL_ENDPOINT_DATA_OUT
),
usb_sndbulkpipe
(
instance
->
usb_dev
,
UDSL_ENDPOINT_DATA_OUT
),
buf
->
base
,
buf
->
base
,
(
UDSL_SND_BUF
FER
_SIZE
-
buf
->
free_cells
)
*
ATM_CELL_SIZE
,
(
UDSL_SND_BUF_SIZE
-
buf
->
free_cells
)
*
ATM_CELL_SIZE
,
udsl_complete_send
,
udsl_complete_send
,
snd
);
snd
);
...
@@ -718,33 +570,32 @@ static void udsl_process_send (unsigned long data)
...
@@ -718,33 +570,32 @@ static void udsl_process_send (unsigned long data)
spin_lock_irq
(
&
instance
->
send_lock
);
spin_lock_irq
(
&
instance
->
send_lock
);
list_add
(
&
snd
->
list
,
&
instance
->
spare_senders
);
list_add
(
&
snd
->
list
,
&
instance
->
spare_senders
);
spin_unlock_irq
(
&
instance
->
send_lock
);
spin_unlock_irq
(
&
instance
->
send_lock
);
list_add
(
&
buf
->
list
,
&
instance
->
filled_buffers
);
list_add
(
&
buf
->
list
,
&
instance
->
filled_
send_
buffers
);
return
;
return
;
/* bail out */
}
}
spin_lock_irq
(
&
instance
->
send_lock
);
spin_lock_irq
(
&
instance
->
send_lock
);
}
/* while */
}
/* while */
spin_unlock_irq
(
&
instance
->
send_lock
);
spin_unlock_irq
(
&
instance
->
send_lock
);
if
(
!
instance
->
current_skb
&&
!
(
instance
->
current_skb
=
skb_dequeue
(
&
instance
->
sndqueue
)))
{
if
(
!
instance
->
current_skb
&&
!
(
instance
->
current_skb
=
skb_dequeue
(
&
instance
->
sndqueue
)))
return
;
/* done - no more skbs */
return
;
/* done - no more skbs */
}
skb
=
instance
->
current_skb
;
skb
=
instance
->
current_skb
;
if
(
!
(
buf
=
instance
->
current_buffer
))
{
if
(
!
(
buf
=
instance
->
current_buffer
))
{
spin_lock_irq
(
&
instance
->
send_lock
);
spin_lock_irq
(
&
instance
->
send_lock
);
if
(
list_empty
(
&
instance
->
spare_buffers
))
{
if
(
list_empty
(
&
instance
->
spare_
send_
buffers
))
{
instance
->
current_buffer
=
NULL
;
instance
->
current_buffer
=
NULL
;
spin_unlock_irq
(
&
instance
->
send_lock
);
spin_unlock_irq
(
&
instance
->
send_lock
);
return
;
/* done - no more buffers */
return
;
/* done - no more buffers */
}
}
buf
=
list_entry
(
instance
->
spare_buffers
.
next
,
struct
udsl_send_buffer
,
list
);
buf
=
list_entry
(
instance
->
spare_
send_
buffers
.
next
,
struct
udsl_send_buffer
,
list
);
list_del
(
&
buf
->
list
);
list_del
(
&
buf
->
list
);
spin_unlock_irq
(
&
instance
->
send_lock
);
spin_unlock_irq
(
&
instance
->
send_lock
);
buf
->
free_start
=
buf
->
base
;
buf
->
free_start
=
buf
->
base
;
buf
->
free_cells
=
UDSL_SND_BUF
FER
_SIZE
;
buf
->
free_cells
=
UDSL_SND_BUF_SIZE
;
instance
->
current_buffer
=
buf
;
instance
->
current_buffer
=
buf
;
}
}
...
@@ -754,7 +605,7 @@ static void udsl_process_send (unsigned long data)
...
@@ -754,7 +605,7 @@ static void udsl_process_send (unsigned long data)
vdbg
(
"udsl_process_send: wrote %u cells from skb 0x%p to buffer 0x%p"
,
num_written
,
skb
,
buf
);
vdbg
(
"udsl_process_send: wrote %u cells from skb 0x%p to buffer 0x%p"
,
num_written
,
skb
,
buf
);
if
(
!
(
buf
->
free_cells
-=
num_written
))
{
if
(
!
(
buf
->
free_cells
-=
num_written
))
{
list_add_tail
(
&
buf
->
list
,
&
instance
->
filled_buffers
);
list_add_tail
(
&
buf
->
list
,
&
instance
->
filled_
send_
buffers
);
instance
->
current_buffer
=
NULL
;
instance
->
current_buffer
=
NULL
;
}
}
...
@@ -766,7 +617,7 @@ static void udsl_process_send (unsigned long data)
...
@@ -766,7 +617,7 @@ static void udsl_process_send (unsigned long data)
if
(
vcc
->
pop
)
if
(
vcc
->
pop
)
vcc
->
pop
(
vcc
,
skb
);
vcc
->
pop
(
vcc
,
skb
);
else
else
kfree_skb
(
skb
);
dev_
kfree_skb
(
skb
);
instance
->
current_skb
=
NULL
;
instance
->
current_skb
=
NULL
;
atomic_inc
(
&
vcc
->
stats
->
tx
);
atomic_inc
(
&
vcc
->
stats
->
tx
);
...
@@ -788,7 +639,7 @@ static void udsl_cancel_send (struct udsl_instance_data *instance, struct atm_vc
...
@@ -788,7 +639,7 @@ static void udsl_cancel_send (struct udsl_instance_data *instance, struct atm_vc
if
(
vcc
->
pop
)
if
(
vcc
->
pop
)
vcc
->
pop
(
vcc
,
skb
);
vcc
->
pop
(
vcc
,
skb
);
else
else
kfree_skb
(
skb
);
dev_
kfree_skb
(
skb
);
}
}
spin_unlock_irq
(
&
instance
->
sndqueue
.
lock
);
spin_unlock_irq
(
&
instance
->
sndqueue
.
lock
);
...
@@ -799,7 +650,7 @@ static void udsl_cancel_send (struct udsl_instance_data *instance, struct atm_vc
...
@@ -799,7 +650,7 @@ static void udsl_cancel_send (struct udsl_instance_data *instance, struct atm_vc
if
(
vcc
->
pop
)
if
(
vcc
->
pop
)
vcc
->
pop
(
vcc
,
skb
);
vcc
->
pop
(
vcc
,
skb
);
else
else
kfree_skb
(
skb
);
dev_
kfree_skb
(
skb
);
}
}
tasklet_enable
(
&
instance
->
send_tasklet
);
tasklet_enable
(
&
instance
->
send_tasklet
);
dbg
(
"udsl_cancel_send done"
);
dbg
(
"udsl_cancel_send done"
);
...
@@ -851,6 +702,7 @@ static void udsl_atm_dev_close (struct atm_dev *dev)
...
@@ -851,6 +702,7 @@ static void udsl_atm_dev_close (struct atm_dev *dev)
dbg
(
"udsl_atm_dev_close: queue has %u elements"
,
instance
->
sndqueue
.
qlen
);
dbg
(
"udsl_atm_dev_close: queue has %u elements"
,
instance
->
sndqueue
.
qlen
);
tasklet_kill
(
&
instance
->
receive_tasklet
);
tasklet_kill
(
&
instance
->
send_tasklet
);
tasklet_kill
(
&
instance
->
send_tasklet
);
kfree
(
instance
);
kfree
(
instance
);
dev
->
dev_data
=
NULL
;
dev
->
dev_data
=
NULL
;
...
@@ -871,8 +723,8 @@ static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page)
...
@@ -871,8 +723,8 @@ static int udsl_atm_proc_read (struct atm_dev *atm_dev, loff_t *pos, char *page)
if
(
!
left
--
)
if
(
!
left
--
)
return
sprintf
(
page
,
"MAC: %02x:%02x:%02x:%02x:%02x:%02x
\n
"
,
return
sprintf
(
page
,
"MAC: %02x:%02x:%02x:%02x:%02x:%02x
\n
"
,
atm_dev
->
esi
[
0
],
atm_dev
->
esi
[
1
],
atm_dev
->
esi
[
2
],
atm_dev
->
esi
[
0
],
atm_dev
->
esi
[
1
],
atm_dev
->
esi
[
2
],
atm_dev
->
esi
[
3
],
atm_dev
->
esi
[
4
],
atm_dev
->
esi
[
5
]);
atm_dev
->
esi
[
3
],
atm_dev
->
esi
[
4
],
atm_dev
->
esi
[
5
]);
if
(
!
left
--
)
if
(
!
left
--
)
return
sprintf
(
page
,
"AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )
\n
"
,
return
sprintf
(
page
,
"AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )
\n
"
,
...
@@ -925,7 +777,7 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
...
@@ -925,7 +777,7 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
return
-
EINVAL
;
return
-
EINVAL
;
/* only support AAL5 */
/* only support AAL5 */
if
(
vcc
->
qos
.
aal
!=
ATM_AAL5
)
if
(
(
vcc
->
qos
.
aal
!=
ATM_AAL5
)
||
(
vcc
->
qos
.
rxtp
.
max_sdu
<
0
)
||
(
vcc
->
qos
.
rxtp
.
max_sdu
>
ATM_MAX_AAL5_PDU
)
)
return
-
EINVAL
;
return
-
EINVAL
;
if
(
!
instance
->
firmware_loaded
)
{
if
(
!
instance
->
firmware_loaded
)
{
...
@@ -949,7 +801,7 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
...
@@ -949,7 +801,7 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
new
->
vcc
=
vcc
;
new
->
vcc
=
vcc
;
new
->
vpi
=
vpi
;
new
->
vpi
=
vpi
;
new
->
vci
=
vci
;
new
->
vci
=
vci
;
new
->
m
tu
=
UDSL_MAX_AAL5_MRU
;
new
->
m
ax_pdu
=
max
(
1
,
UDSL_NUM_CELLS
(
vcc
->
qos
.
rxtp
.
max_sdu
))
*
ATM_CELL_PAYLOAD
;
vcc
->
dev_data
=
new
;
vcc
->
dev_data
=
new
;
vcc
->
vpi
=
vpi
;
vcc
->
vpi
=
vpi
;
...
@@ -965,7 +817,7 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
...
@@ -965,7 +817,7 @@ static int udsl_atm_open (struct atm_vcc *vcc, short vpi, int vci)
up
(
&
instance
->
serialize
);
up
(
&
instance
->
serialize
);
udsl_fire_receivers
(
instance
);
tasklet_schedule
(
&
instance
->
receive_tasklet
);
dbg
(
"udsl_atm_open: allocated vcc data 0x%p (max_pdu: %u)"
,
new
,
new
->
max_pdu
);
dbg
(
"udsl_atm_open: allocated vcc data 0x%p (max_pdu: %u)"
,
new
,
new
->
max_pdu
);
...
@@ -994,9 +846,9 @@ static void udsl_atm_close (struct atm_vcc *vcc)
...
@@ -994,9 +846,9 @@ static void udsl_atm_close (struct atm_vcc *vcc)
list_del
(
&
vcc_data
->
list
);
list_del
(
&
vcc_data
->
list
);
tasklet_enable
(
&
instance
->
receive_tasklet
);
tasklet_enable
(
&
instance
->
receive_tasklet
);
if
(
vcc_data
->
reasBuffer
)
if
(
vcc_data
->
skb
)
kfree_skb
(
vcc_data
->
reasBuffer
);
dev_kfree_skb
(
vcc_data
->
skb
);
vcc_data
->
reasBuffer
=
NULL
;
vcc_data
->
skb
=
NULL
;
kfree
(
vcc_data
);
kfree
(
vcc_data
);
vcc
->
dev_data
=
NULL
;
vcc
->
dev_data
=
NULL
;
...
@@ -1041,7 +893,9 @@ static int udsl_set_alternate (struct udsl_instance_data *instance)
...
@@ -1041,7 +893,9 @@ static int udsl_set_alternate (struct udsl_instance_data *instance)
instance
->
firmware_loaded
=
1
;
instance
->
firmware_loaded
=
1
;
}
}
up
(
&
instance
->
serialize
);
up
(
&
instance
->
serialize
);
udsl_fire_receivers
(
instance
);
tasklet_schedule
(
&
instance
->
receive_tasklet
);
return
0
;
return
0
;
}
}
...
@@ -1057,10 +911,10 @@ static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *
...
@@ -1057,10 +911,10 @@ static int udsl_usb_ioctl (struct usb_interface *intf, unsigned int code, void *
}
}
switch
(
code
)
{
switch
(
code
)
{
case
UDSL_IOCTL_
START
:
case
UDSL_IOCTL_
LINE_UP
:
instance
->
atm_dev
->
signal
=
ATM_PHY_SIG_FOUND
;
instance
->
atm_dev
->
signal
=
ATM_PHY_SIG_FOUND
;
return
udsl_set_alternate
(
instance
);
return
udsl_set_alternate
(
instance
);
case
UDSL_IOCTL_
STOP
:
case
UDSL_IOCTL_
LINE_DOWN
:
instance
->
atm_dev
->
signal
=
ATM_PHY_SIG_LOST
;
instance
->
atm_dev
->
signal
=
ATM_PHY_SIG_LOST
;
return
0
;
return
0
;
default:
default:
...
@@ -1101,31 +955,25 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
...
@@ -1101,31 +955,25 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
INIT_LIST_HEAD
(
&
instance
->
vcc_list
);
INIT_LIST_HEAD
(
&
instance
->
vcc_list
);
spin_lock_init
(
&
instance
->
spare_receivers
_lock
);
spin_lock_init
(
&
instance
->
receive
_lock
);
INIT_LIST_HEAD
(
&
instance
->
spare_receivers
);
INIT_LIST_HEAD
(
&
instance
->
spare_receivers
);
INIT_LIST_HEAD
(
&
instance
->
filled_receive_buffers
);
spin_lock_init
(
&
instance
->
completed_receivers_lock
);
INIT_LIST_HEAD
(
&
instance
->
completed_receivers
);
tasklet_init
(
&
instance
->
receive_tasklet
,
udsl_process_receive
,
(
unsigned
long
)
instance
);
tasklet_init
(
&
instance
->
receive_tasklet
,
udsl_process_receive
,
(
unsigned
long
)
instance
);
INIT_LIST_HEAD
(
&
instance
->
spare_receive_buffers
);
skb_queue_head_init
(
&
instance
->
sndqueue
);
skb_queue_head_init
(
&
instance
->
sndqueue
);
spin_lock_init
(
&
instance
->
send_lock
);
spin_lock_init
(
&
instance
->
send_lock
);
INIT_LIST_HEAD
(
&
instance
->
spare_senders
);
INIT_LIST_HEAD
(
&
instance
->
spare_senders
);
INIT_LIST_HEAD
(
&
instance
->
spare_buffers
);
INIT_LIST_HEAD
(
&
instance
->
spare_
send_
buffers
);
tasklet_init
(
&
instance
->
send_tasklet
,
udsl_process_send
,
(
unsigned
long
)
instance
);
tasklet_init
(
&
instance
->
send_tasklet
,
udsl_process_send
,
(
unsigned
long
)
instance
);
INIT_LIST_HEAD
(
&
instance
->
filled_buffers
);
INIT_LIST_HEAD
(
&
instance
->
filled_
send_
buffers
);
/* receive init */
/* receive init */
for
(
i
=
0
;
i
<
UDSL_NUMBER_RCV_URBS
;
i
++
)
{
for
(
i
=
0
;
i
<
UDSL_NUM_RCV_URBS
;
i
++
)
{
struct
udsl_receiver
*
rcv
=
&
(
instance
->
all_receivers
[
i
]);
struct
udsl_receiver
*
rcv
=
&
(
instance
->
receivers
[
i
]);
if
(
!
(
rcv
->
skb
=
dev_alloc_skb
(
UDSL_RCV_BUFFER_SIZE
*
ATM_CELL_SIZE
)))
{
dbg
(
"udsl_usb_probe: no memory for skb %d!"
,
i
);
goto
fail
;
}
if
(
!
(
rcv
->
urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
)))
{
if
(
!
(
rcv
->
urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
)))
{
dbg
(
"udsl_usb_probe: no memory for receive urb %d!"
,
i
);
dbg
(
"udsl_usb_probe: no memory for receive urb %d!"
,
i
);
...
@@ -1135,13 +983,21 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
...
@@ -1135,13 +983,21 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
rcv
->
instance
=
instance
;
rcv
->
instance
=
instance
;
list_add
(
&
rcv
->
list
,
&
instance
->
spare_receivers
);
list_add
(
&
rcv
->
list
,
&
instance
->
spare_receivers
);
}
for
(
i
=
0
;
i
<
UDSL_NUM_RCV_BUFS
;
i
++
)
{
struct
udsl_receive_buffer
*
buf
=
&
(
instance
->
receive_buffers
[
i
]);
dbg
(
"udsl_usb_probe: skb->truesize = %d (asked for %d)"
,
rcv
->
skb
->
truesize
,
UDSL_RCV_BUF_SIZE
*
ATM_CELL_SIZE
);
if
(
!
(
buf
->
base
=
kmalloc
(
UDSL_RCV_BUF_SIZE
*
ATM_CELL_SIZE
,
GFP_KERNEL
)))
{
dbg
(
"udsl_usb_probe: no memory for receive buffer %d!"
,
i
);
goto
fail
;
}
list_add
(
&
buf
->
list
,
&
instance
->
spare_receive_buffers
);
}
}
/* send init */
/* send init */
for
(
i
=
0
;
i
<
UDSL_NUM
BER
_SND_URBS
;
i
++
)
{
for
(
i
=
0
;
i
<
UDSL_NUM_SND_URBS
;
i
++
)
{
struct
udsl_sender
*
snd
=
&
(
instance
->
all_senders
[
i
]);
struct
udsl_sender
*
snd
=
&
(
instance
->
senders
[
i
]);
if
(
!
(
snd
->
urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
)))
{
if
(
!
(
snd
->
urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
)))
{
dbg
(
"udsl_usb_probe: no memory for send urb %d!"
,
i
);
dbg
(
"udsl_usb_probe: no memory for send urb %d!"
,
i
);
...
@@ -1153,18 +1009,19 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
...
@@ -1153,18 +1009,19 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
list_add
(
&
snd
->
list
,
&
instance
->
spare_senders
);
list_add
(
&
snd
->
list
,
&
instance
->
spare_senders
);
}
}
for
(
i
=
0
;
i
<
UDSL_NUM
BER
_SND_BUFS
;
i
++
)
{
for
(
i
=
0
;
i
<
UDSL_NUM_SND_BUFS
;
i
++
)
{
struct
udsl_send_buffer
*
buf
=
&
(
instance
->
all_buffers
[
i
]);
struct
udsl_send_buffer
*
buf
=
&
(
instance
->
send_buffers
[
i
]);
if
(
!
(
buf
->
base
=
kmalloc
(
UDSL_SND_BUFFER_SIZE
*
ATM_CELL_SIZE
,
GFP_KERNEL
)))
{
if
(
!
(
buf
->
base
=
kmalloc
(
UDSL_SND_BUF_SIZE
*
ATM_CELL_SIZE
,
GFP_KERNEL
)))
{
dbg
(
"udsl_usb_probe: no memory for send buffer %d!"
,
i
);
dbg
(
"udsl_usb_probe: no memory for send buffer %d!"
,
i
);
dbg
(
"udsl_usb_probe: no memory for send buffer %d!"
,
i
);
goto
fail
;
goto
fail
;
}
}
list_add
(
&
buf
->
list
,
&
instance
->
spare_buffers
);
list_add
(
&
buf
->
list
,
&
instance
->
spare_
send_
buffers
);
}
}
/*
atm
init */
/*
ATM
init */
if
(
!
(
instance
->
atm_dev
=
atm_dev_register
(
udsl_driver_name
,
&
udsl_atm_devops
,
-
1
,
0
)))
{
if
(
!
(
instance
->
atm_dev
=
atm_dev_register
(
udsl_driver_name
,
&
udsl_atm_devops
,
-
1
,
0
)))
{
dbg
(
"udsl_usb_probe: failed to register ATM device!"
);
dbg
(
"udsl_usb_probe: failed to register ATM device!"
);
goto
fail
;
goto
fail
;
...
@@ -1174,14 +1031,14 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
...
@@ -1174,14 +1031,14 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
instance
->
atm_dev
->
ci_range
.
vci_bits
=
ATM_CI_MAX
;
instance
->
atm_dev
->
ci_range
.
vci_bits
=
ATM_CI_MAX
;
instance
->
atm_dev
->
signal
=
ATM_PHY_SIG_UNKNOWN
;
instance
->
atm_dev
->
signal
=
ATM_PHY_SIG_UNKNOWN
;
/* t
mp init atm
device, set to 128kbit */
/* t
emp init ATM
device, set to 128kbit */
instance
->
atm_dev
->
link_rate
=
128
*
1000
/
424
;
instance
->
atm_dev
->
link_rate
=
128
*
1000
/
424
;
/* set MAC address, it is stored in the serial number */
/* set MAC address, it is stored in the serial number */
memset
(
instance
->
atm_dev
->
esi
,
0
,
sizeof
(
instance
->
atm_dev
->
esi
));
memset
(
instance
->
atm_dev
->
esi
,
0
,
sizeof
(
instance
->
atm_dev
->
esi
));
if
(
usb_string
(
dev
,
dev
->
descriptor
.
iSerialNumber
,
mac_str
,
sizeof
(
mac_str
))
==
12
)
if
(
usb_string
(
dev
,
dev
->
descriptor
.
iSerialNumber
,
mac_str
,
sizeof
(
mac_str
))
==
12
)
for
(
i
=
0
;
i
<
6
;
i
++
)
for
(
i
=
0
;
i
<
6
;
i
++
)
instance
->
atm_dev
->
esi
[
i
]
=
(
hex2int
(
mac_str
[
i
*
2
])
*
16
)
+
(
hex2int
(
mac_str
[
i
*
2
+
1
]));
instance
->
atm_dev
->
esi
[
i
]
=
(
hex2int
(
mac_str
[
i
*
2
])
*
16
)
+
(
hex2int
(
mac_str
[
i
*
2
+
1
]));
/* device description */
/* device description */
buf
=
instance
->
description
;
buf
=
instance
->
description
;
...
@@ -1215,20 +1072,17 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
...
@@ -1215,20 +1072,17 @@ static int udsl_usb_probe (struct usb_interface *intf, const struct usb_device_i
return
0
;
return
0
;
fail:
fail:
for
(
i
=
0
;
i
<
UDSL_NUM
BER
_SND_BUFS
;
i
++
)
for
(
i
=
0
;
i
<
UDSL_NUM_SND_BUFS
;
i
++
)
kfree
(
instance
->
all_buffers
[
i
].
base
);
kfree
(
instance
->
send_buffers
[
i
].
base
);
for
(
i
=
0
;
i
<
UDSL_NUM
BER
_SND_URBS
;
i
++
)
for
(
i
=
0
;
i
<
UDSL_NUM_SND_URBS
;
i
++
)
usb_free_urb
(
instance
->
all_senders
[
i
].
urb
);
usb_free_urb
(
instance
->
senders
[
i
].
urb
);
for
(
i
=
0
;
i
<
UDSL_NUM
BER_RCV_URBS
;
i
++
)
{
for
(
i
=
0
;
i
<
UDSL_NUM
_RCV_BUFS
;
i
++
)
struct
udsl_receiver
*
rcv
=
&
(
instance
->
all_receivers
[
i
]
);
kfree
(
instance
->
receive_buffers
[
i
].
base
);
usb_free_urb
(
rcv
->
urb
);
for
(
i
=
0
;
i
<
UDSL_NUM_RCV_URBS
;
i
++
)
usb_free_urb
(
instance
->
receivers
[
i
].
urb
);
if
(
rcv
->
skb
)
kfree_skb
(
rcv
->
skb
);
}
kfree
(
instance
);
kfree
(
instance
);
...
@@ -1239,7 +1093,7 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
...
@@ -1239,7 +1093,7 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
{
{
struct
udsl_instance_data
*
instance
=
usb_get_intfdata
(
intf
);
struct
udsl_instance_data
*
instance
=
usb_get_intfdata
(
intf
);
struct
list_head
*
pos
;
struct
list_head
*
pos
;
unsigned
int
count
=
0
;
unsigned
int
count
;
int
result
,
i
;
int
result
,
i
;
dbg
(
"udsl_usb_disconnect entered"
);
dbg
(
"udsl_usb_disconnect entered"
);
...
@@ -1251,38 +1105,25 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
...
@@ -1251,38 +1105,25 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
return
;
return
;
}
}
tasklet_disable
(
&
instance
->
receive_tasklet
);
/* receive finalize */
/* receive finalize */
down
(
&
instance
->
serialize
);
/* vs udsl_fire_receivers */
tasklet_disable
(
&
instance
->
receive_tasklet
);
/* no need to take the spinlock */
list_for_each
(
pos
,
&
instance
->
spare_receivers
)
if
(
++
count
>
UDSL_NUMBER_RCV_URBS
)
panic
(
__FILE__
": memory corruption detected at line %d!
\n
"
,
__LINE__
);
INIT_LIST_HEAD
(
&
instance
->
spare_receivers
);
up
(
&
instance
->
serialize
);
dbg
(
"udsl_usb_disconnect: flushed %u spare receivers"
,
count
);
count
=
UDSL_NUMBER_RCV_URBS
-
count
;
for
(
i
=
0
;
i
<
UDSL_NUM
BER
_RCV_URBS
;
i
++
)
for
(
i
=
0
;
i
<
UDSL_NUM_RCV_URBS
;
i
++
)
if
((
result
=
usb_unlink_urb
(
instance
->
all_receivers
[
i
].
urb
))
<
0
)
if
((
result
=
usb_unlink_urb
(
instance
->
receivers
[
i
].
urb
))
<
0
)
dbg
(
"udsl_usb_disconnect: usb_unlink_urb on receive urb %d returned %d"
,
i
,
result
);
dbg
(
"udsl_usb_disconnect: usb_unlink_urb on receive urb %d returned %d"
,
i
,
result
);
/* wait for completion handlers to finish */
/* wait for completion handlers to finish */
do
{
do
{
unsigned
int
completed
=
0
;
count
=
0
;
spin_lock_irq
(
&
instance
->
receive_lock
);
spin_lock_irq
(
&
instance
->
completed_receivers_lock
);
list_for_each
(
pos
,
&
instance
->
spare_receivers
)
list_for_each
(
pos
,
&
instance
->
completed_receivers
)
if
(
++
count
>
UDSL_NUM_RCV_URBS
)
if
(
++
completed
>
count
)
panic
(
__FILE__
": memory corruption detected at line %d!
\n
"
,
__LINE__
);
panic
(
__FILE__
": memory corruption detected at line %d!
\n
"
,
__LINE__
);
spin_unlock_irq
(
&
instance
->
completed_receivers
_lock
);
spin_unlock_irq
(
&
instance
->
receive
_lock
);
dbg
(
"udsl_usb_disconnect: found %u
completed receivers"
,
completed
);
dbg
(
"udsl_usb_disconnect: found %u
spare receivers"
,
count
);
if
(
co
mpleted
==
count
)
if
(
co
unt
==
UDSL_NUM_RCV_URBS
)
break
;
break
;
set_current_state
(
TASK_RUNNING
);
set_current_state
(
TASK_RUNNING
);
...
@@ -1290,37 +1131,36 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
...
@@ -1290,37 +1131,36 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
}
while
(
1
);
}
while
(
1
);
/* no need to take the spinlock */
/* no need to take the spinlock */
INIT_LIST_HEAD
(
&
instance
->
completed_receivers
);
INIT_LIST_HEAD
(
&
instance
->
filled_receive_buffers
);
INIT_LIST_HEAD
(
&
instance
->
spare_receive_buffers
);
tasklet_enable
(
&
instance
->
receive_tasklet
);
tasklet_enable
(
&
instance
->
receive_tasklet
);
tasklet_kill
(
&
instance
->
receive_tasklet
);
for
(
i
=
0
;
i
<
UDSL_NUM
BER_RCV_URBS
;
i
++
)
{
for
(
i
=
0
;
i
<
UDSL_NUM
_RCV_URBS
;
i
++
)
struct
udsl_receiver
*
rcv
=
&
(
instance
->
all_receivers
[
i
]
);
usb_free_urb
(
instance
->
receivers
[
i
].
urb
);
usb_free_urb
(
rcv
->
urb
);
for
(
i
=
0
;
i
<
UDSL_NUM_RCV_BUFS
;
i
++
)
kfree_skb
(
rcv
->
skb
);
kfree
(
instance
->
receive_buffers
[
i
].
base
);
}
/* send finalize */
/* send finalize */
tasklet_disable
(
&
instance
->
send_tasklet
);
tasklet_disable
(
&
instance
->
send_tasklet
);
for
(
i
=
0
;
i
<
UDSL_NUM
BER
_SND_URBS
;
i
++
)
for
(
i
=
0
;
i
<
UDSL_NUM_SND_URBS
;
i
++
)
if
((
result
=
usb_unlink_urb
(
instance
->
all_senders
[
i
].
urb
))
<
0
)
if
((
result
=
usb_unlink_urb
(
instance
->
senders
[
i
].
urb
))
<
0
)
dbg
(
"udsl_usb_disconnect: usb_unlink_urb on send urb %d returned %d"
,
i
,
result
);
dbg
(
"udsl_usb_disconnect: usb_unlink_urb on send urb %d returned %d"
,
i
,
result
);
/* wait for completion handlers to finish */
/* wait for completion handlers to finish */
do
{
do
{
count
=
0
;
count
=
0
;
spin_lock
(
&
instance
->
send_lock
);
spin_lock
_irq
(
&
instance
->
send_lock
);
list_for_each
(
pos
,
&
instance
->
spare_senders
)
list_for_each
(
pos
,
&
instance
->
spare_senders
)
if
(
++
count
>
UDSL_NUM
BER
_SND_URBS
)
if
(
++
count
>
UDSL_NUM_SND_URBS
)
panic
(
__FILE__
": memory corruption detected at line %d!
\n
"
,
__LINE__
);
panic
(
__FILE__
": memory corruption detected at line %d!
\n
"
,
__LINE__
);
spin_unlock
(
&
instance
->
send_lock
);
spin_unlock
_irq
(
&
instance
->
send_lock
);
dbg
(
"udsl_usb_disconnect: found %u spare senders"
,
count
);
dbg
(
"udsl_usb_disconnect: found %u spare senders"
,
count
);
if
(
count
==
UDSL_NUM
BER
_SND_URBS
)
if
(
count
==
UDSL_NUM_SND_URBS
)
break
;
break
;
set_current_state
(
TASK_RUNNING
);
set_current_state
(
TASK_RUNNING
);
...
@@ -1329,22 +1169,22 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
...
@@ -1329,22 +1169,22 @@ static void udsl_usb_disconnect (struct usb_interface *intf)
/* no need to take the spinlock */
/* no need to take the spinlock */
INIT_LIST_HEAD
(
&
instance
->
spare_senders
);
INIT_LIST_HEAD
(
&
instance
->
spare_senders
);
INIT_LIST_HEAD
(
&
instance
->
spare_buffers
);
INIT_LIST_HEAD
(
&
instance
->
spare_
send_
buffers
);
instance
->
current_buffer
=
NULL
;
instance
->
current_buffer
=
NULL
;
tasklet_enable
(
&
instance
->
send_tasklet
);
tasklet_enable
(
&
instance
->
send_tasklet
);
for
(
i
=
0
;
i
<
UDSL_NUM
BER
_SND_URBS
;
i
++
)
for
(
i
=
0
;
i
<
UDSL_NUM_SND_URBS
;
i
++
)
usb_free_urb
(
instance
->
all_senders
[
i
].
urb
);
usb_free_urb
(
instance
->
senders
[
i
].
urb
);
for
(
i
=
0
;
i
<
UDSL_NUM
BER
_SND_BUFS
;
i
++
)
for
(
i
=
0
;
i
<
UDSL_NUM_SND_BUFS
;
i
++
)
kfree
(
instance
->
all_buffers
[
i
].
base
);
kfree
(
instance
->
send_buffers
[
i
].
base
);
wmb
();
wmb
();
instance
->
usb_dev
=
NULL
;
instance
->
usb_dev
=
NULL
;
/*
atm
finalize */
/*
ATM
finalize */
shutdown_atm_dev
(
instance
->
atm_dev
);
/* frees instance */
shutdown_atm_dev
(
instance
->
atm_dev
);
/* frees instance
, kills tasklets
*/
}
}
...
@@ -1392,10 +1232,10 @@ static int udsl_print_packet (const unsigned char *data, int len)
...
@@ -1392,10 +1232,10 @@ static int udsl_print_packet (const unsigned char *data, int len)
int
i
=
0
,
j
=
0
;
int
i
=
0
,
j
=
0
;
for
(
i
=
0
;
i
<
len
;)
{
for
(
i
=
0
;
i
<
len
;)
{
buffer
[
0
]
=
'\0'
;
buffer
[
0
]
=
'\0'
;
sprintf
(
buffer
,
"%.3d :"
,
i
);
sprintf
(
buffer
,
"%.3d :"
,
i
);
for
(
j
=
0
;
(
j
<
16
)
&&
(
i
<
len
);
j
++
,
i
++
)
{
for
(
j
=
0
;
(
j
<
16
)
&&
(
i
<
len
);
j
++
,
i
++
)
{
sprintf
(
buffer
,
"%s %2.2x"
,
buffer
,
data
[
i
]);
sprintf
(
buffer
,
"%s %2.2x"
,
buffer
,
data
[
i
]);
}
}
dbg
(
"%s"
,
buffer
);
dbg
(
"%s"
,
buffer
);
}
}
...
...
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