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
8f7155ad
Commit
8f7155ad
authored
Mar 03, 2004
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://kernel.bkbits.net/davem/net-2.6
into ppc970.osdl.org:/home/torvalds/v2.5/linux
parents
dbbffa7b
dd2514fe
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
536 additions
and
364 deletions
+536
-364
Documentation/crypto/api-intro.txt
Documentation/crypto/api-intro.txt
+1
-0
crypto/Kconfig
crypto/Kconfig
+10
-0
crypto/Makefile
crypto/Makefile
+1
-0
crypto/arc4.c
crypto/arc4.c
+106
-0
crypto/tcrypt.c
crypto/tcrypt.c
+10
-1
crypto/tcrypt.h
crypto/tcrypt.h
+141
-0
drivers/net/irda/stir4200.c
drivers/net/irda/stir4200.c
+267
-363
No files found.
Documentation/crypto/api-intro.txt
View file @
8f7155ad
...
@@ -186,6 +186,7 @@ Original developers of the crypto algorithms:
...
@@ -186,6 +186,7 @@ Original developers of the crypto algorithms:
Dag Arne Osvik (Serpent)
Dag Arne Osvik (Serpent)
Brian Gladman (AES)
Brian Gladman (AES)
Kartikey Mahendra Bhatt (CAST6)
Kartikey Mahendra Bhatt (CAST6)
Jon Oberheide (ARC4)
SHA1 algorithm contributors:
SHA1 algorithm contributors:
Jean-Francois Dive
Jean-Francois Dive
...
...
crypto/Kconfig
View file @
8f7155ad
...
@@ -140,6 +140,16 @@ config CRYPTO_CAST6
...
@@ -140,6 +140,16 @@ config CRYPTO_CAST6
The CAST6 encryption algorithm (synonymous with CAST-256) is
The CAST6 encryption algorithm (synonymous with CAST-256) is
described in RFC2612.
described in RFC2612.
config CRYPTO_ARC4
tristate "ARC4 cipher algorithm"
depends on CRYPTO
help
ARC4 cipher algorithm.
This is a stream cipher using keys ranging from 8 bits to 2048
bits in length. ARC4 is commonly used in protocols such as WEP
and SSL.
config CRYPTO_DEFLATE
config CRYPTO_DEFLATE
tristate "Deflate compression algorithm"
tristate "Deflate compression algorithm"
depends on CRYPTO
depends on CRYPTO
...
...
crypto/Makefile
View file @
8f7155ad
...
@@ -21,6 +21,7 @@ obj-$(CONFIG_CRYPTO_SERPENT) += serpent.o
...
@@ -21,6 +21,7 @@ obj-$(CONFIG_CRYPTO_SERPENT) += serpent.o
obj-$(CONFIG_CRYPTO_AES)
+=
aes.o
obj-$(CONFIG_CRYPTO_AES)
+=
aes.o
obj-$(CONFIG_CRYPTO_CAST5)
+=
cast5.o
obj-$(CONFIG_CRYPTO_CAST5)
+=
cast5.o
obj-$(CONFIG_CRYPTO_CAST6)
+=
cast6.o
obj-$(CONFIG_CRYPTO_CAST6)
+=
cast6.o
obj-$(CONFIG_CRYPTO_ARC4)
+=
arc4.o
obj-$(CONFIG_CRYPTO_DEFLATE)
+=
deflate.o
obj-$(CONFIG_CRYPTO_DEFLATE)
+=
deflate.o
obj-$(CONFIG_CRYPTO_TEST)
+=
tcrypt.o
obj-$(CONFIG_CRYPTO_TEST)
+=
tcrypt.o
crypto/arc4.c
0 → 100644
View file @
8f7155ad
/*
* Cryptographic API
*
* ARC4 Cipher Algorithm
*
* Jon Oberheide <jon@focalhost.com>
*
* 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 Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/crypto.h>
#define ARC4_MIN_KEY_SIZE 1
#define ARC4_MAX_KEY_SIZE 256
#define ARC4_BLOCK_SIZE 1
struct
arc4_ctx
{
u8
S
[
256
];
u8
x
,
y
;
};
static
int
arc4_set_key
(
void
*
ctx_arg
,
const
u8
*
in_key
,
unsigned
int
key_len
,
u32
*
flags
)
{
struct
arc4_ctx
*
ctx
=
ctx_arg
;
int
i
,
j
=
0
,
k
=
0
;
ctx
->
x
=
1
;
ctx
->
y
=
0
;
for
(
i
=
0
;
i
<
256
;
i
++
)
ctx
->
S
[
i
]
=
i
;
for
(
i
=
0
;
i
<
256
;
i
++
)
{
u8
a
=
ctx
->
S
[
i
];
j
=
(
j
+
in_key
[
k
]
+
a
)
&
0xff
;
ctx
->
S
[
i
]
=
ctx
->
S
[
j
];
ctx
->
S
[
j
]
=
a
;
if
(
++
k
>=
key_len
)
k
=
0
;
}
/* TODO: dump the first 768 bytes generated as recommended
by Ilya Mironov (http://eprint.iacr.org/2002/067/) to
increase the statistical strength of the state table */
return
0
;
}
static
void
arc4_crypt
(
void
*
ctx_arg
,
u8
*
out
,
const
u8
*
in
)
{
struct
arc4_ctx
*
ctx
=
ctx_arg
;
u8
*
const
S
=
ctx
->
S
;
u8
x
=
ctx
->
x
;
u8
y
=
ctx
->
y
;
u8
a
=
S
[
x
];
y
=
(
y
+
a
)
&
0xff
;
u8
b
=
S
[
y
];
S
[
x
]
=
b
;
S
[
y
]
=
a
;
x
=
(
x
+
1
)
&
0xff
;
*
out
++
=
*
in
^
S
[(
a
+
b
)
&
0xff
];
ctx
->
x
=
x
;
ctx
->
y
=
y
;
}
static
struct
crypto_alg
arc4_alg
=
{
.
cra_name
=
"arc4"
,
.
cra_flags
=
CRYPTO_ALG_TYPE_CIPHER
,
.
cra_blocksize
=
ARC4_BLOCK_SIZE
,
.
cra_ctxsize
=
sizeof
(
struct
arc4_ctx
),
.
cra_module
=
THIS_MODULE
,
.
cra_list
=
LIST_HEAD_INIT
(
arc4_alg
.
cra_list
),
.
cra_u
=
{
.
cipher
=
{
.
cia_min_keysize
=
ARC4_MIN_KEY_SIZE
,
.
cia_max_keysize
=
ARC4_MAX_KEY_SIZE
,
.
cia_setkey
=
arc4_set_key
,
.
cia_encrypt
=
arc4_crypt
,
.
cia_decrypt
=
arc4_crypt
}
}
};
static
int
__init
arc4_init
(
void
)
{
return
crypto_register_alg
(
&
arc4_alg
);
}
static
void
__exit
arc4_exit
(
void
)
{
crypto_unregister_alg
(
&
arc4_alg
);
}
module_init
(
arc4_init
);
module_exit
(
arc4_exit
);
MODULE_LICENSE
(
"GPL"
);
MODULE_DESCRIPTION
(
"ARC4 Cipher Algorithm"
);
MODULE_AUTHOR
(
"Jon Oberheide <jon@focalhost.com>"
);
crypto/tcrypt.c
View file @
8f7155ad
...
@@ -61,7 +61,7 @@ static char *tvmem;
...
@@ -61,7 +61,7 @@ static char *tvmem;
static
char
*
check
[]
=
{
static
char
*
check
[]
=
{
"des"
,
"md5"
,
"des3_ede"
,
"rot13"
,
"sha1"
,
"sha256"
,
"blowfish"
,
"des"
,
"md5"
,
"des3_ede"
,
"rot13"
,
"sha1"
,
"sha256"
,
"blowfish"
,
"twofish"
,
"serpent"
,
"sha384"
,
"sha512"
,
"md4"
,
"aes"
,
"cast6"
,
"twofish"
,
"serpent"
,
"sha384"
,
"sha512"
,
"md4"
,
"aes"
,
"cast6"
,
"deflate"
,
NULL
"
arc4"
,
"
deflate"
,
NULL
};
};
static
void
static
void
...
@@ -556,6 +556,10 @@ do_test(void)
...
@@ -556,6 +556,10 @@ do_test(void)
test_cipher
(
"cast6"
,
MODE_ECB
,
ENCRYPT
,
cast6_enc_tv_template
,
CAST6_ENC_TEST_VECTORS
);
test_cipher
(
"cast6"
,
MODE_ECB
,
ENCRYPT
,
cast6_enc_tv_template
,
CAST6_ENC_TEST_VECTORS
);
test_cipher
(
"cast6"
,
MODE_ECB
,
DECRYPT
,
cast6_dec_tv_template
,
CAST6_DEC_TEST_VECTORS
);
test_cipher
(
"cast6"
,
MODE_ECB
,
DECRYPT
,
cast6_dec_tv_template
,
CAST6_DEC_TEST_VECTORS
);
//ARC4
test_cipher
(
"arc4"
,
MODE_ECB
,
ENCRYPT
,
arc4_enc_tv_template
,
ARC4_ENC_TEST_VECTORS
);
test_cipher
(
"arc4x"
,
MODE_ECB
,
DECRYPT
,
arc4_dec_tv_template
,
ARC4_DEC_TEST_VECTORS
);
test_hash
(
"sha384"
,
sha384_tv_template
,
SHA384_TEST_VECTORS
);
test_hash
(
"sha384"
,
sha384_tv_template
,
SHA384_TEST_VECTORS
);
test_hash
(
"sha512"
,
sha512_tv_template
,
SHA512_TEST_VECTORS
);
test_hash
(
"sha512"
,
sha512_tv_template
,
SHA512_TEST_VECTORS
);
test_deflate
();
test_deflate
();
...
@@ -638,6 +642,11 @@ do_test(void)
...
@@ -638,6 +642,11 @@ do_test(void)
test_cipher
(
"cast6"
,
MODE_ECB
,
DECRYPT
,
cast6_dec_tv_template
,
CAST6_DEC_TEST_VECTORS
);
test_cipher
(
"cast6"
,
MODE_ECB
,
DECRYPT
,
cast6_dec_tv_template
,
CAST6_DEC_TEST_VECTORS
);
break
;
break
;
case
16
:
test_cipher
(
"arc4"
,
MODE_ECB
,
ENCRYPT
,
arc4_enc_tv_template
,
ARC4_ENC_TEST_VECTORS
);
test_cipher
(
"arc4"
,
MODE_ECB
,
DECRYPT
,
arc4_dec_tv_template
,
ARC4_DEC_TEST_VECTORS
);
break
;
#ifdef CONFIG_CRYPTO_HMAC
#ifdef CONFIG_CRYPTO_HMAC
case
100
:
case
100
:
test_hmac
(
"md5"
,
hmac_md5_tv_template
,
HMAC_MD5_TEST_VECTORS
);
test_hmac
(
"md5"
,
hmac_md5_tv_template
,
HMAC_MD5_TEST_VECTORS
);
...
...
crypto/tcrypt.h
View file @
8f7155ad
...
@@ -1488,6 +1488,147 @@ struct cipher_testvec cast5_dec_tv_template[] =
...
@@ -1488,6 +1488,147 @@ struct cipher_testvec cast5_dec_tv_template[] =
},
},
};
};
/*
* ARC4 test vectors from OpenSSL
*/
#define ARC4_ENC_TEST_VECTORS 7
#define ARC4_DEC_TEST_VECTORS 7
struct
cipher_testvec
arc4_enc_tv_template
[]
=
{
{
.
key
=
{
0x01
,
0x23
,
0x45
,
0x67
,
0x89
,
0xab
,
0xcd
,
0xef
},
.
klen
=
8
,
.
input
=
{
0x01
,
0x23
,
0x45
,
0x67
,
0x89
,
0xab
,
0xcd
,
0xef
},
.
ilen
=
8
,
.
result
=
{
0x75
,
0xb7
,
0x87
,
0x80
,
0x99
,
0xe0
,
0xc5
,
0x96
},
.
rlen
=
8
,
},
{
.
key
=
{
0x01
,
0x23
,
0x45
,
0x67
,
0x89
,
0xab
,
0xcd
,
0xef
},
.
klen
=
8
,
.
input
=
{
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
},
.
ilen
=
8
,
.
result
=
{
0x74
,
0x94
,
0xc2
,
0xe7
,
0x10
,
0x4b
,
0x08
,
0x79
},
.
rlen
=
8
,
},
{
.
key
=
{
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
},
.
klen
=
8
,
.
input
=
{
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
},
.
ilen
=
8
,
.
result
=
{
0xde
,
0x18
,
0x89
,
0x41
,
0xa3
,
0x37
,
0x5d
,
0x3a
},
.
rlen
=
8
,
},
{
.
key
=
{
0xef
,
0x01
,
0x23
,
0x45
},
.
klen
=
4
,
.
input
=
{
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
},
.
ilen
=
20
,
.
result
=
{
0xd6
,
0xa1
,
0x41
,
0xa7
,
0xec
,
0x3c
,
0x38
,
0xdf
,
0xbd
,
0x61
,
0x5a
,
0x11
,
0x62
,
0xe1
,
0xc7
,
0xba
,
0x36
,
0xb6
,
0x78
,
0x58
},
.
rlen
=
20
,
},
{
.
key
=
{
0x01
,
0x23
,
0x45
,
0x67
,
0x89
,
0xab
,
0xcd
,
0xef
},
.
klen
=
8
,
.
input
=
{
0x12
,
0x34
,
0x56
,
0x78
,
0x9A
,
0xBC
,
0xDE
,
0xF0
,
0x12
,
0x34
,
0x56
,
0x78
,
0x9A
,
0xBC
,
0xDE
,
0xF0
,
0x12
,
0x34
,
0x56
,
0x78
,
0x9A
,
0xBC
,
0xDE
,
0xF0
,
0x12
,
0x34
,
0x56
,
0x78
},
.
ilen
=
28
,
.
result
=
{
0x66
,
0xa0
,
0x94
,
0x9f
,
0x8a
,
0xf7
,
0xd6
,
0x89
,
0x1f
,
0x7f
,
0x83
,
0x2b
,
0xa8
,
0x33
,
0xc0
,
0x0c
,
0x89
,
0x2e
,
0xbe
,
0x30
,
0x14
,
0x3c
,
0xe2
,
0x87
,
0x40
,
0x01
,
0x1e
,
0xcf
},
.
rlen
=
28
,
},
{
.
key
=
{
0xef
,
0x01
,
0x23
,
0x45
},
.
klen
=
4
,
.
input
=
{
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
},
.
ilen
=
10
,
.
result
=
{
0xd6
,
0xa1
,
0x41
,
0xa7
,
0xec
,
0x3c
,
0x38
,
0xdf
,
0xbd
,
0x61
},
.
rlen
=
10
,
},
{
.
key
=
{
0x01
,
0x23
,
0x45
,
0x67
,
0x89
,
0xAB
,
0xCD
,
0xEF
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
},
.
klen
=
16
,
.
input
=
{
0x01
,
0x23
,
0x45
,
0x67
,
0x89
,
0xAB
,
0xCD
,
0xEF
},
.
ilen
=
8
,
.
result
=
{
0x69
,
0x72
,
0x36
,
0x59
,
0x1B
,
0x52
,
0x42
,
0xB1
},
.
rlen
=
8
,
},
};
struct
cipher_testvec
arc4_dec_tv_template
[]
=
{
{
.
key
=
{
0x01
,
0x23
,
0x45
,
0x67
,
0x89
,
0xab
,
0xcd
,
0xef
},
.
klen
=
8
,
.
input
=
{
0x75
,
0xb7
,
0x87
,
0x80
,
0x99
,
0xe0
,
0xc5
,
0x96
},
.
ilen
=
8
,
.
result
=
{
0x01
,
0x23
,
0x45
,
0x67
,
0x89
,
0xab
,
0xcd
,
0xef
},
.
rlen
=
8
,
},
{
.
key
=
{
0x01
,
0x23
,
0x45
,
0x67
,
0x89
,
0xab
,
0xcd
,
0xef
},
.
klen
=
8
,
.
input
=
{
0x74
,
0x94
,
0xc2
,
0xe7
,
0x10
,
0x4b
,
0x08
,
0x79
},
.
ilen
=
8
,
.
result
=
{
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
},
.
rlen
=
8
,
},
{
.
key
=
{
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
},
.
klen
=
8
,
.
input
=
{
0xde
,
0x18
,
0x89
,
0x41
,
0xa3
,
0x37
,
0x5d
,
0x3a
},
.
ilen
=
8
,
.
result
=
{
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
},
.
rlen
=
8
,
},
{
.
key
=
{
0xef
,
0x01
,
0x23
,
0x45
},
.
klen
=
4
,
.
input
=
{
0xd6
,
0xa1
,
0x41
,
0xa7
,
0xec
,
0x3c
,
0x38
,
0xdf
,
0xbd
,
0x61
,
0x5a
,
0x11
,
0x62
,
0xe1
,
0xc7
,
0xba
,
0x36
,
0xb6
,
0x78
,
0x58
},
.
ilen
=
20
,
.
result
=
{
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
},
.
rlen
=
20
,
},
{
.
key
=
{
0x01
,
0x23
,
0x45
,
0x67
,
0x89
,
0xab
,
0xcd
,
0xef
},
.
klen
=
8
,
.
input
=
{
0x66
,
0xa0
,
0x94
,
0x9f
,
0x8a
,
0xf7
,
0xd6
,
0x89
,
0x1f
,
0x7f
,
0x83
,
0x2b
,
0xa8
,
0x33
,
0xc0
,
0x0c
,
0x89
,
0x2e
,
0xbe
,
0x30
,
0x14
,
0x3c
,
0xe2
,
0x87
,
0x40
,
0x01
,
0x1e
,
0xcf
},
.
ilen
=
28
,
.
result
=
{
0x12
,
0x34
,
0x56
,
0x78
,
0x9A
,
0xBC
,
0xDE
,
0xF0
,
0x12
,
0x34
,
0x56
,
0x78
,
0x9A
,
0xBC
,
0xDE
,
0xF0
,
0x12
,
0x34
,
0x56
,
0x78
,
0x9A
,
0xBC
,
0xDE
,
0xF0
,
0x12
,
0x34
,
0x56
,
0x78
},
.
rlen
=
28
,
},
{
.
key
=
{
0xef
,
0x01
,
0x23
,
0x45
},
.
klen
=
4
,
.
input
=
{
0xd6
,
0xa1
,
0x41
,
0xa7
,
0xec
,
0x3c
,
0x38
,
0xdf
,
0xbd
,
0x61
},
.
ilen
=
10
,
.
result
=
{
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
},
.
rlen
=
10
,
},
{
.
key
=
{
0x01
,
0x23
,
0x45
,
0x67
,
0x89
,
0xAB
,
0xCD
,
0xEF
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
},
.
klen
=
16
,
.
input
=
{
0x69
,
0x72
,
0x36
,
0x59
,
0x1B
,
0x52
,
0x42
,
0xB1
},
.
ilen
=
8
,
.
result
=
{
0x01
,
0x23
,
0x45
,
0x67
,
0x89
,
0xAB
,
0xCD
,
0xEF
},
.
rlen
=
8
,
},
};
/*
/*
* Compression stuff.
* Compression stuff.
*/
*/
...
...
drivers/net/irda/stir4200.c
View file @
8f7155ad
...
@@ -49,12 +49,14 @@
...
@@ -49,12 +49,14 @@
#include <linux/suspend.h>
#include <linux/suspend.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/usb.h>
#include <linux/crc32.h>
#include <net/irda/irda.h>
#include <net/irda/irda.h>
#include <net/irda/irlap.h>
#include <net/irda/irlap.h>
#include <net/irda/irda_device.h>
#include <net/irda/irda_device.h>
#include <net/irda/wrapper.h>
#include <net/irda/wrapper.h>
#include <net/irda/crc.h>
#include <net/irda/crc.h>
#include <linux/crc32.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
MODULE_AUTHOR
(
"Stephen Hemminger <shemminger@osdl.org>"
);
MODULE_AUTHOR
(
"Stephen Hemminger <shemminger@osdl.org>"
);
MODULE_DESCRIPTION
(
"IrDA-USB Dongle Driver for SigmaTel STIr4200"
);
MODULE_DESCRIPTION
(
"IrDA-USB Dongle Driver for SigmaTel STIr4200"
);
...
@@ -72,15 +74,11 @@ static int tx_power = 0; /* 0 = highest ... 3 = lowest */
...
@@ -72,15 +74,11 @@ static int tx_power = 0; /* 0 = highest ... 3 = lowest */
module_param
(
tx_power
,
int
,
0
);
module_param
(
tx_power
,
int
,
0
);
MODULE_PARM_DESC
(
tx_power
,
"Set Transmitter power (0-3, 0 is highest power)"
);
MODULE_PARM_DESC
(
tx_power
,
"Set Transmitter power (0-3, 0 is highest power)"
);
static
int
rx_interval
=
5
;
/* milliseconds */
module_param
(
rx_interval
,
int
,
0
);
MODULE_PARM_DESC
(
rx_interval
,
"Receive polling interval (ms)"
);
#define STIR_IRDA_HEADER 4
#define STIR_IRDA_HEADER 4
#define CTRL_TIMEOUT 100
/* milliseconds */
#define CTRL_TIMEOUT 100
/* milliseconds */
#define TRANSMIT_TIMEOUT 200
/* milliseconds */
#define TRANSMIT_TIMEOUT 200
/* milliseconds */
#define STIR_FIFO_SIZE 4096
#define STIR_FIFO_SIZE 4096
#define
NUM_RX_URBS 2
#define
FIFO_REGS_SIZE 3
enum
FirChars
{
enum
FirChars
{
FIR_CE
=
0x7d
,
FIR_CE
=
0x7d
,
...
@@ -167,36 +165,26 @@ enum StirTestMask {
...
@@ -167,36 +165,26 @@ enum StirTestMask {
TEST_TSTOSC
=
0x0F
,
TEST_TSTOSC
=
0x0F
,
};
};
enum
StirState
{
STIR_STATE_RECEIVING
=
0
,
STIR_STATE_TXREADY
,
};
struct
stir_cb
{
struct
stir_cb
{
struct
usb_device
*
usbdev
;
/* init: probe_irda */
struct
usb_device
*
usbdev
;
/* init: probe_irda */
struct
net_device
*
netdev
;
/* network layer */
struct
net_device
*
netdev
;
/* network layer */
struct
irlap_cb
*
irlap
;
/* The link layer we are binded to */
struct
irlap_cb
*
irlap
;
/* The link layer we are binded to */
struct
net_device_stats
stats
;
/* network statistics */
struct
net_device_stats
stats
;
/* network statistics */
struct
qos_info
qos
;
struct
qos_info
qos
;
unsigned
long
state
;
unsigned
speed
;
/* Current speed */
unsigned
speed
;
/* Current speed */
wait_queue_head_t
thr_wait
;
/* transmit thread wakeup */
wait_queue_head_t
thr_wait
;
/* transmit thread wakeup */
struct
completion
thr_exited
;
struct
completion
thr_exited
;
pid_t
thr_pid
;
pid_t
thr_pid
;
unsigned
int
tx_bulkpipe
;
struct
sk_buff
*
tx_pending
;
void
*
tx_data
;
/* wrapped data out */
void
*
io_buf
;
/* transmit/receive buffer */
unsigned
tx_len
;
__u8
*
fifo_status
;
unsigned
tx_newspeed
;
unsigned
tx_mtt
;
unsigned
int
rx_intpipe
;
iobuff_t
rx_buff
;
/* receive unwrap state machine */
iobuff_t
rx_buff
;
/* receive unwrap state machine */
struct
timespec
rx_time
;
struct
timeval
rx_time
;
int
receiving
;
struct
urb
*
rx_urbs
[
NUM_RX_URBS
];
struct
urb
*
rx_urb
;
void
*
rx_data
[
NUM_RX_URBS
];
};
};
...
@@ -209,9 +197,6 @@ static struct usb_device_id dongles[] = {
...
@@ -209,9 +197,6 @@ static struct usb_device_id dongles[] = {
MODULE_DEVICE_TABLE
(
usb
,
dongles
);
MODULE_DEVICE_TABLE
(
usb
,
dongles
);
static
int
fifo_txwait
(
struct
stir_cb
*
stir
,
unsigned
space
);
static
void
stir_usb_receive
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
);
/* Send control message to set dongle register */
/* Send control message to set dongle register */
static
int
write_reg
(
struct
stir_cb
*
stir
,
__u16
reg
,
__u8
value
)
static
int
write_reg
(
struct
stir_cb
*
stir
,
__u16
reg
,
__u8
value
)
{
{
...
@@ -239,6 +224,11 @@ static inline int read_reg(struct stir_cb *stir, __u16 reg,
...
@@ -239,6 +224,11 @@ static inline int read_reg(struct stir_cb *stir, __u16 reg,
MSECS_TO_JIFFIES
(
CTRL_TIMEOUT
));
MSECS_TO_JIFFIES
(
CTRL_TIMEOUT
));
}
}
static
inline
int
isfir
(
u32
speed
)
{
return
(
speed
==
4000000
);
}
/*
/*
* Prepare a FIR IrDA frame for transmission to the USB dongle. The
* Prepare a FIR IrDA frame for transmission to the USB dongle. The
* FIR transmit frame is documented in the datasheet. It consists of
* FIR transmit frame is documented in the datasheet. It consists of
...
@@ -333,8 +323,8 @@ static void fir_eof(struct stir_cb *stir)
...
@@ -333,8 +323,8 @@ static void fir_eof(struct stir_cb *stir)
{
{
iobuff_t
*
rx_buff
=
&
stir
->
rx_buff
;
iobuff_t
*
rx_buff
=
&
stir
->
rx_buff
;
int
len
=
rx_buff
->
len
-
4
;
int
len
=
rx_buff
->
len
-
4
;
struct
sk_buff
*
skb
,
*
nskb
;
__u32
fcs
;
__u32
fcs
;
struct
sk_buff
*
nskb
;
if
(
unlikely
(
len
<=
0
))
{
if
(
unlikely
(
len
<=
0
))
{
pr_debug
(
"%s: short frame len %d
\n
"
,
pr_debug
(
"%s: short frame len %d
\n
"
,
...
@@ -345,41 +335,46 @@ static void fir_eof(struct stir_cb *stir)
...
@@ -345,41 +335,46 @@ static void fir_eof(struct stir_cb *stir)
return
;
return
;
}
}
fcs
=
rx_buff
->
data
[
len
]
|
fcs
=
~
(
crc32_le
(
~
0
,
rx_buff
->
data
,
len
));
rx_buff
->
data
[
len
+
1
]
<<
8
|
if
(
fcs
!=
le32_to_cpu
(
get_unaligned
((
u32
*
)(
rx_buff
->
data
+
len
))))
{
rx_buff
->
data
[
len
+
2
]
<<
16
|
pr_debug
(
"crc error calc 0x%x len %d
\n
"
,
fcs
,
len
);
rx_buff
->
data
[
len
+
3
]
<<
24
;
if
(
unlikely
(
fcs
!=
~
(
crc32_le
(
~
0
,
rx_buff
->
data
,
len
))))
{
pr_debug
(
"%s: crc error
\n
"
,
stir
->
netdev
->
name
);
irda_device_set_media_busy
(
stir
->
netdev
,
TRUE
);
stir
->
stats
.
rx_errors
++
;
stir
->
stats
.
rx_errors
++
;
stir
->
stats
.
rx_crc_errors
++
;
stir
->
stats
.
rx_crc_errors
++
;
return
;
return
;
}
}
/* If can't get new buffer, just drop and reuse */
/* if frame is short then just copy it */
nskb
=
dev_alloc_skb
(
IRDA_SKB_MAX_MTU
);
if
(
len
<
IRDA_RX_COPY_THRESHOLD
)
{
if
(
unlikely
(
!
nskb
))
nskb
=
dev_alloc_skb
(
len
+
1
);
if
(
unlikely
(
!
nskb
))
{
++
stir
->
stats
.
rx_dropped
;
++
stir
->
stats
.
rx_dropped
;
else
{
return
;
struct
sk_buff
*
oskb
=
rx_buff
->
skb
;
}
skb_reserve
(
nskb
,
1
);
skb_reserve
(
nskb
,
1
);
skb
=
nskb
;
memcpy
(
nskb
->
data
,
rx_buff
->
data
,
len
);
}
else
{
nskb
=
dev_alloc_skb
(
rx_buff
->
truesize
);
if
(
unlikely
(
!
nskb
))
{
++
stir
->
stats
.
rx_dropped
;
return
;
}
skb_reserve
(
nskb
,
1
);
skb
=
rx_buff
->
skb
;
rx_buff
->
skb
=
nskb
;
rx_buff
->
head
=
nskb
->
data
;
}
/* Set correct length in socket buffer */
skb_put
(
skb
,
len
);
skb_put
(
oskb
,
len
);
oskb
->
mac
.
raw
=
o
skb
->
data
;
skb
->
mac
.
raw
=
skb
->
data
;
o
skb
->
protocol
=
htons
(
ETH_P_IRDA
);
skb
->
protocol
=
htons
(
ETH_P_IRDA
);
o
skb
->
dev
=
stir
->
netdev
;
skb
->
dev
=
stir
->
netdev
;
netif_rx
(
o
skb
);
netif_rx
(
skb
);
stir
->
stats
.
rx_packets
++
;
stir
->
stats
.
rx_packets
++
;
stir
->
stats
.
rx_bytes
+=
len
;
stir
->
stats
.
rx_bytes
+=
len
;
rx_buff
->
skb
=
nskb
;
rx_buff
->
head
=
nskb
->
data
;
}
rx_buff
->
data
=
rx_buff
->
head
;
rx_buff
->
data
=
rx_buff
->
head
;
rx_buff
->
len
=
0
;
rx_buff
->
len
=
0
;
...
@@ -402,7 +397,6 @@ static void stir_fir_chars(struct stir_cb *stir,
...
@@ -402,7 +397,6 @@ static void stir_fir_chars(struct stir_cb *stir,
continue
;
continue
;
/* Now receiving frame */
/* Now receiving frame */
rx_buff
->
state
=
BEGIN_FRAME
;
rx_buff
->
state
=
BEGIN_FRAME
;
rx_buff
->
in_frame
=
TRUE
;
/* Time to initialize receive buffer */
/* Time to initialize receive buffer */
rx_buff
->
data
=
rx_buff
->
head
;
rx_buff
->
data
=
rx_buff
->
head
;
...
@@ -424,6 +418,7 @@ static void stir_fir_chars(struct stir_cb *stir,
...
@@ -424,6 +418,7 @@ static void stir_fir_chars(struct stir_cb *stir,
if
(
byte
==
FIR_EOF
)
if
(
byte
==
FIR_EOF
)
continue
;
continue
;
rx_buff
->
state
=
INSIDE_FRAME
;
rx_buff
->
state
=
INSIDE_FRAME
;
rx_buff
->
in_frame
=
TRUE
;
/* fall through */
/* fall through */
case
INSIDE_FRAME
:
case
INSIDE_FRAME
:
...
@@ -461,7 +456,6 @@ static void stir_fir_chars(struct stir_cb *stir,
...
@@ -461,7 +456,6 @@ static void stir_fir_chars(struct stir_cb *stir,
error_recovery:
error_recovery:
++
stir
->
stats
.
rx_errors
;
++
stir
->
stats
.
rx_errors
;
irda_device_set_media_busy
(
stir
->
netdev
,
TRUE
);
rx_buff
->
state
=
OUTSIDE_FRAME
;
rx_buff
->
state
=
OUTSIDE_FRAME
;
rx_buff
->
in_frame
=
FALSE
;
rx_buff
->
in_frame
=
FALSE
;
}
}
...
@@ -478,11 +472,6 @@ static void stir_sir_chars(struct stir_cb *stir,
...
@@ -478,11 +472,6 @@ static void stir_sir_chars(struct stir_cb *stir,
&
stir
->
rx_buff
,
bytes
[
i
]);
&
stir
->
rx_buff
,
bytes
[
i
]);
}
}
static
inline
int
isfir
(
u32
speed
)
{
return
(
speed
==
4000000
);
}
static
inline
void
unwrap_chars
(
struct
stir_cb
*
stir
,
static
inline
void
unwrap_chars
(
struct
stir_cb
*
stir
,
const
__u8
*
bytes
,
int
length
)
const
__u8
*
bytes
,
int
length
)
{
{
...
@@ -519,25 +508,31 @@ static int change_speed(struct stir_cb *stir, unsigned speed)
...
@@ -519,25 +508,31 @@ static int change_speed(struct stir_cb *stir, unsigned speed)
int
i
,
err
;
int
i
,
err
;
__u8
mode
;
__u8
mode
;
pr_debug
(
"%s: change speed %d
\n
"
,
stir
->
netdev
->
name
,
speed
);
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
stir_modes
);
++
i
)
{
for
(
i
=
0
;
i
<
ARRAY_SIZE
(
stir_modes
);
++
i
)
{
if
(
speed
==
stir_modes
[
i
].
speed
)
if
(
speed
==
stir_modes
[
i
].
speed
)
goto
found
;
goto
found
;
}
}
ERROR
(
"%s: invalid speed %d
\n
"
,
stir
->
netdev
->
name
,
speed
);
warn
(
"%s: invalid speed %d
"
,
stir
->
netdev
->
name
,
speed
);
return
-
EINVAL
;
return
-
EINVAL
;
found:
found:
pr_debug
(
"%s: speed change from %d to %d
\n
"
,
pr_debug
(
"speed change from %d to %d
\n
"
,
stir
->
speed
,
speed
);
stir
->
netdev
->
name
,
stir
->
speed
,
speed
);
/* sometimes needed to get chip out of stuck state */
err
=
usb_reset_device
(
stir
->
usbdev
);
if
(
err
)
goto
out
;
/* Reset modulator */
err
=
write_reg
(
stir
,
REG_CTRL1
,
CTRL1_SRESET
);
if
(
err
)
goto
out
;
/* Make sure any previous Tx is really finished. This happens
/* Undocumented magic to tweak the DPLL */
* when we answer an incomming request ; the ua:rsp and the
err
=
write_reg
(
stir
,
REG_DPLL
,
0x15
);
* speed change are bundled together, so we need to wait until
if
(
err
)
* the packet we just submitted has been sent. Jean II */
goto
out
;
if
(
fifo_txwait
(
stir
,
0
))
return
-
EIO
;
/* Set clock */
/* Set clock */
err
=
write_reg
(
stir
,
REG_PDCLK
,
stir_modes
[
i
].
pdclk
);
err
=
write_reg
(
stir
,
REG_PDCLK
,
stir_modes
[
i
].
pdclk
);
...
@@ -564,33 +559,13 @@ static int change_speed(struct stir_cb *stir, unsigned speed)
...
@@ -564,33 +559,13 @@ static int change_speed(struct stir_cb *stir, unsigned speed)
goto
out
;
goto
out
;
err
=
write_reg
(
stir
,
REG_CTRL1
,
(
tx_power
&
3
)
<<
1
);
err
=
write_reg
(
stir
,
REG_CTRL1
,
(
tx_power
&
3
)
<<
1
);
out:
stir
->
speed
=
speed
;
return
err
;
}
static
int
stir_reset
(
struct
stir_cb
*
stir
)
{
int
err
;
/* reset state */
stir
->
rx_buff
.
in_frame
=
FALSE
;
stir
->
rx_buff
.
state
=
OUTSIDE_FRAME
;
stir
->
speed
=
-
1
;
/* Undocumented magic to tweak the DPLL */
err
=
write_reg
(
stir
,
REG_DPLL
,
0x15
);
if
(
err
)
if
(
err
)
goto
out
;
goto
out
;
/* Reset sensitivity */
/* Reset sensitivity */
err
=
write_reg
(
stir
,
REG_CTRL2
,
(
rx_sensitivity
&
7
)
<<
5
);
err
=
write_reg
(
stir
,
REG_CTRL2
,
(
rx_sensitivity
&
7
)
<<
5
);
if
(
err
)
goto
out
;
err
=
change_speed
(
stir
,
9600
);
out:
out:
stir
->
speed
=
speed
;
return
err
;
return
err
;
}
}
...
@@ -606,48 +581,62 @@ static int stir_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
...
@@ -606,48 +581,62 @@ static int stir_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
/* the IRDA wrapping routines don't deal with non linear skb */
/* the IRDA wrapping routines don't deal with non linear skb */
SKB_LINEAR_ASSERT
(
skb
);
SKB_LINEAR_ASSERT
(
skb
);
if
(
unlikely
(
skb
->
len
)
==
0
)
/* speed change only */
skb
=
xchg
(
&
stir
->
tx_pending
,
skb
);
stir
->
tx_len
=
0
;
else
if
(
isfir
(
stir
->
speed
))
stir
->
tx_len
=
wrap_fir_skb
(
skb
,
stir
->
tx_data
);
else
stir
->
tx_len
=
wrap_sir_skb
(
skb
,
stir
->
tx_data
);
stir
->
stats
.
tx_packets
++
;
stir
->
stats
.
tx_bytes
+=
skb
->
len
;
stir
->
tx_mtt
=
irda_get_mtt
(
skb
);
stir
->
tx_newspeed
=
irda_get_next_speed
(
skb
);
if
(
!
test_and_set_bit
(
STIR_STATE_TXREADY
,
&
stir
->
state
))
wake_up
(
&
stir
->
thr_wait
);
wake_up
(
&
stir
->
thr_wait
);
/* this should never happen unless stop/wakeup problem */
if
(
unlikely
(
skb
))
{
WARN_ON
(
1
);
dev_kfree_skb
(
skb
);
dev_kfree_skb
(
skb
);
}
return
0
;
return
0
;
}
}
/*
/*
* Wait for the transmit FIFO to have space for next data
* Wait for the transmit FIFO to have space for next data
*
* If space < 0 then wait till FIFO completely drains.
* FYI: can take up to 13 seconds at 2400baud.
*/
*/
static
int
fifo_txwait
(
struct
stir_cb
*
stir
,
unsigned
space
)
static
int
fifo_txwait
(
struct
stir_cb
*
stir
,
int
space
)
{
{
int
err
;
int
err
;
unsigned
count
;
unsigned
long
count
,
status
;
__u8
regs
[
3
];
unsigned
long
timeout
=
jiffies
+
HZ
/
10
;
for
(;;)
{
/* Read FIFO status and count */
/* Read FIFO status and count */
err
=
read_reg
(
stir
,
REG_FIFOCTL
,
regs
,
3
);
for
(;;)
{
if
(
unlikely
(
err
!=
3
))
{
err
=
read_reg
(
stir
,
REG_FIFOCTL
,
stir
->
fifo_status
,
WARNING
(
"%s: FIFO register read error: %d
\n
"
,
FIFO_REGS_SIZE
);
if
(
unlikely
(
err
!=
FIFO_REGS_SIZE
))
{
warn
(
"%s: FIFO register read error: %d"
,
stir
->
netdev
->
name
,
err
);
stir
->
netdev
->
name
,
err
);
return
err
;
return
err
;
}
}
status
=
stir
->
fifo_status
[
0
];
count
=
(
unsigned
)(
stir
->
fifo_status
[
2
]
&
0x1f
)
<<
8
|
stir
->
fifo_status
[
1
];
pr_debug
(
"fifo status 0x%lx count %lu
\n
"
,
status
,
count
);
/* error when receive/transmit fifo gets confused */
if
(
status
&
FIFOCTL_RXERR
)
{
stir
->
stats
.
rx_fifo_errors
++
;
stir
->
stats
.
rx_errors
++
;
break
;
}
if
(
status
&
FIFOCTL_TXERR
)
{
stir
->
stats
.
tx_fifo_errors
++
;
stir
->
stats
.
tx_errors
++
;
break
;
}
/* is fifo receiving already, or empty */
/* is fifo receiving already, or empty */
if
(
!
(
regs
[
0
]
&
FIFOCTL_DIR
)
if
(
!
(
status
&
FIFOCTL_DIR
)
||
(
regs
[
0
]
&
FIFOCTL_EMPTY
))
||
(
status
&
FIFOCTL_EMPTY
))
return
0
;
return
0
;
if
(
signal_pending
(
current
))
if
(
signal_pending
(
current
))
...
@@ -658,40 +647,37 @@ static int fifo_txwait(struct stir_cb *stir, unsigned space)
...
@@ -658,40 +647,37 @@ static int fifo_txwait(struct stir_cb *stir, unsigned space)
||
!
netif_device_present
(
stir
->
netdev
))
||
!
netif_device_present
(
stir
->
netdev
))
return
-
ESHUTDOWN
;
return
-
ESHUTDOWN
;
count
=
(
unsigned
)(
regs
[
2
]
&
0x1f
)
<<
8
|
regs
[
1
];
pr_debug
(
"%s: fifo status 0x%x count %u
\n
"
,
stir
->
netdev
->
name
,
regs
[
0
],
count
);
/* only waiting for some space */
/* only waiting for some space */
if
(
space
&&
STIR_FIFO_SIZE
-
4
>
space
+
count
)
if
(
space
>=
0
&&
STIR_FIFO_SIZE
-
4
>
space
+
count
)
return
0
;
return
0
;
if
(
time_after
(
jiffies
,
timeout
))
{
WARNING
(
"%s: transmit fifo timeout status=0x%x count=%d
\n
"
,
stir
->
netdev
->
name
,
regs
[
0
],
count
);
++
stir
->
stats
.
tx_errors
;
irda_device_set_media_busy
(
stir
->
netdev
,
TRUE
);
return
-
ETIMEDOUT
;
}
/* estimate transfer time for remaining chars */
/* estimate transfer time for remaining chars */
wait_ms
((
count
*
8000
)
/
stir
->
speed
);
wait_ms
((
count
*
8000
)
/
stir
->
speed
);
}
}
err
=
write_reg
(
stir
,
REG_FIFOCTL
,
FIFOCTL_CLR
);
if
(
err
)
return
err
;
err
=
write_reg
(
stir
,
REG_FIFOCTL
,
0
);
if
(
err
)
return
err
;
return
0
;
}
}
/* Wait for turnaround delay before starting transmit. */
/* Wait for turnaround delay before starting transmit. */
static
void
turnaround_delay
(
long
us
,
const
struct
timespec
*
last
)
static
void
turnaround_delay
(
const
struct
stir_cb
*
stir
,
long
us
)
{
{
long
ticks
;
long
ticks
;
struct
time
spec
now
=
CURRENT_TIME
;
struct
time
val
now
;
if
(
us
<=
0
)
if
(
us
<=
0
)
return
;
return
;
us
-=
(
now
.
tv_sec
-
last
->
tv_sec
)
*
USEC_PER_SEC
;
do_gettimeofday
(
&
now
);
us
-=
(
now
.
tv_nsec
-
last
->
tv_nsec
)
/
NSEC_PER_USEC
;
us
-=
(
now
.
tv_sec
-
stir
->
rx_time
.
tv_sec
)
*
USEC_PER_SEC
;
us
-=
now
.
tv_usec
-
stir
->
rx_time
.
tv_usec
;
if
(
us
<
10
)
if
(
us
<
10
)
return
;
return
;
...
@@ -707,77 +693,60 @@ static void turnaround_delay(long us, const struct timespec *last)
...
@@ -707,77 +693,60 @@ static void turnaround_delay(long us, const struct timespec *last)
* Start receiver by submitting a request to the receive pipe.
* Start receiver by submitting a request to the receive pipe.
* If nothing is available it will return after rx_interval.
* If nothing is available it will return after rx_interval.
*/
*/
static
void
receive_start
(
struct
stir_cb
*
stir
)
static
int
receive_start
(
struct
stir_cb
*
stir
)
{
{
int
i
;
/* reset state */
stir
->
receiving
=
1
;
if
(
test_and_set_bit
(
STIR_STATE_RECEIVING
,
&
stir
->
state
))
return
;
if
(
fifo_txwait
(
stir
,
0
))
return
;
for
(
i
=
0
;
i
<
NUM_RX_URBS
;
i
++
)
{
struct
urb
*
urb
=
stir
->
rx_urbs
[
i
];
usb_fill_int_urb
(
urb
,
stir
->
usbdev
,
stir
->
rx_intpipe
,
stir
->
rx_data
[
i
],
STIR_FIFO_SIZE
,
stir_usb_receive
,
stir
,
rx_interval
);
if
(
usb_submit_urb
(
urb
,
GFP_KERNEL
))
urb
->
status
=
-
EINVAL
;
}
if
(
i
==
0
)
{
stir
->
rx_buff
.
in_frame
=
FALSE
;
/* if nothing got queued, then just retry next time */
stir
->
rx_buff
.
state
=
OUTSIDE_FRAME
;
if
(
net_ratelimit
())
WARNING
(
"%s: no receive buffers avaiable
\n
"
,
stir
->
netdev
->
name
);
clear_bit
(
STIR_STATE_RECEIVING
,
&
stir
->
state
)
;
stir
->
rx_urb
->
status
=
0
;
}
return
usb_submit_urb
(
stir
->
rx_urb
,
GFP_KERNEL
);
}
}
/* Stop all pending receive Urb's */
/* Stop all pending receive Urb's */
static
void
receive_stop
(
struct
stir_cb
*
stir
)
static
void
receive_stop
(
struct
stir_cb
*
stir
)
{
{
int
i
;
stir
->
receiving
=
0
;
usb_unlink_urb
(
stir
->
rx_urb
);
for
(
i
=
0
;
i
<
NUM_RX_URBS
;
i
++
)
{
if
(
stir
->
rx_buff
.
in_frame
)
struct
urb
*
urb
=
stir
->
rx_urbs
[
i
];
stir
->
stats
.
collisions
++
;
usb_unlink_urb
(
urb
);
}
}
}
/*
/* Send wrapped data (in tx_data) to device */
* Wrap data in socket buffer and send it.
static
void
stir_send
(
struct
stir_cb
*
stir
)
*/
static
void
stir_send
(
struct
stir_cb
*
stir
,
struct
sk_buff
*
skb
)
{
{
int
rc
;
unsigned
wraplen
;
int
first_frame
=
0
;
if
(
test_and_clear_bit
(
STIR_STATE_RECEIVING
,
&
stir
->
state
))
{
/* if receiving, need to turnaround */
if
(
stir
->
receiving
)
{
receive_stop
(
stir
);
receive_stop
(
stir
);
turnaround_delay
(
stir
,
irda_get_mtt
(
skb
));
first_frame
=
1
;
}
turnaround_delay
(
stir
->
tx_mtt
,
&
stir
->
rx_time
);
if
(
isfir
(
stir
->
speed
))
wraplen
=
wrap_fir_skb
(
skb
,
stir
->
io_buf
);
else
wraplen
=
wrap_sir_skb
(
skb
,
stir
->
io_buf
);
if
(
stir
->
rx_buff
.
in_frame
)
/* check for space available in fifo */
++
stir
->
stats
.
collisions
;
if
(
!
first_frame
)
}
fifo_txwait
(
stir
,
wraplen
);
else
if
(
fifo_txwait
(
stir
,
stir
->
tx_len
))
return
;
/* shutdown or major errors */
stir
->
stats
.
tx_packets
++
;
stir
->
stats
.
tx_bytes
+=
skb
->
len
;
stir
->
netdev
->
trans_start
=
jiffies
;
stir
->
netdev
->
trans_start
=
jiffies
;
pr_debug
(
"send %d (%d)
\n
"
,
skb
->
len
,
wraplen
);
pr_debug
(
"%s: send %d
\n
"
,
stir
->
netdev
->
name
,
stir
->
tx_len
);
if
(
usb_bulk_msg
(
stir
->
usbdev
,
usb_sndbulkpipe
(
stir
->
usbdev
,
1
),
rc
=
usb_bulk_msg
(
stir
->
usbdev
,
stir
->
io_buf
,
wraplen
,
stir
->
tx_bulkpipe
,
NULL
,
MSECS_TO_JIFFIES
(
TRANSMIT_TIMEOUT
)))
stir
->
tx_data
,
stir
->
tx_len
,
NULL
,
MSECS_TO_JIFFIES
(
TRANSMIT_TIMEOUT
));
if
(
unlikely
(
rc
))
{
WARNING
(
"%s: usb bulk message failed %d
\n
"
,
stir
->
netdev
->
name
,
rc
);
stir
->
stats
.
tx_errors
++
;
stir
->
stats
.
tx_errors
++
;
}
}
}
/*
/*
...
@@ -787,7 +756,7 @@ static int stir_transmit_thread(void *arg)
...
@@ -787,7 +756,7 @@ static int stir_transmit_thread(void *arg)
{
{
struct
stir_cb
*
stir
=
arg
;
struct
stir_cb
*
stir
=
arg
;
struct
net_device
*
dev
=
stir
->
netdev
;
struct
net_device
*
dev
=
stir
->
netdev
;
DECLARE_WAITQUEUE
(
wait
,
current
)
;
struct
sk_buff
*
skb
;
daemonize
(
"%s"
,
dev
->
name
);
daemonize
(
"%s"
,
dev
->
name
);
allow_signal
(
SIGTERM
);
allow_signal
(
SIGTERM
);
...
@@ -796,44 +765,58 @@ static int stir_transmit_thread(void *arg)
...
@@ -796,44 +765,58 @@ static int stir_transmit_thread(void *arg)
&&
netif_device_present
(
dev
)
&&
netif_device_present
(
dev
)
&&
!
signal_pending
(
current
))
&&
!
signal_pending
(
current
))
{
{
/*
make swsusp happy with our thread
*/
/*
if suspending, then power off and wait
*/
if
(
current
->
flags
&
PF_FREEZE
)
{
if
(
current
->
flags
&
PF_FREEZE
)
{
if
(
stir
->
receiving
)
receive_stop
(
stir
);
receive_stop
(
stir
);
else
fifo_txwait
(
stir
,
-
1
);
write_reg
(
stir
,
REG_CTRL1
,
CTRL1_TXPWD
|
CTRL1_RXPWD
);
write_reg
(
stir
,
REG_CTRL1
,
CTRL1_TXPWD
|
CTRL1_RXPWD
);
refrigerator
(
PF_IOTHREAD
);
refrigerator
(
PF_IOTHREAD
);
stir_reset
(
stir
);
if
(
change_speed
(
stir
,
stir
->
speed
))
break
;
}
}
/* if something to send? */
/* if something to send? */
if
(
test_and_clear_bit
(
STIR_STATE_TXREADY
,
&
stir
->
state
))
{
skb
=
xchg
(
&
stir
->
tx_pending
,
NULL
);
unsigned
new_speed
=
stir
->
tx_newspeed
;
if
(
skb
)
{
unsigned
new_speed
=
irda_get_next_speed
(
skb
);
netif_wake_queue
(
dev
);
/* Note that we may both send a packet and
if
(
skb
->
len
>
0
)
* change speed in some cases. Jean II */
stir_send
(
stir
,
skb
);
dev_kfree_skb
(
skb
);
if
(
stir
->
tx_len
!=
0
)
if
(
stir
->
speed
!=
new_speed
)
{
stir_send
(
stir
);
if
(
fifo_txwait
(
stir
,
-
1
)
||
change_speed
(
stir
,
new_speed
))
break
;
}
continue
;
}
if
(
stir
->
speed
!=
new_speed
)
/* nothing to send? start receiving */
change_speed
(
stir
,
new_speed
);
if
(
!
stir
->
receiving
&&
irda_device_txqueue_empty
(
dev
))
{
/* Wait otherwise chip gets confused. */
if
(
fifo_txwait
(
stir
,
-
1
))
break
;
netif_wake_queue
(
stir
->
netdev
);
if
(
unlikely
(
receive_start
(
stir
)))
{
if
(
net_ratelimit
())
info
(
"%s: receive usb submit failed"
,
stir
->
netdev
->
name
);
stir
->
receiving
=
0
;
wait_ms
(
10
);
continue
;
continue
;
}
}
}
if
(
irda_device_txqueue_empty
(
dev
))
/* sleep if nothing to send */
receive_start
(
stir
);
wait_event_interruptible
(
stir
->
thr_wait
,
stir
->
tx_pending
);
set_task_state
(
current
,
TASK_INTERRUPTIBLE
);
add_wait_queue
(
&
stir
->
thr_wait
,
&
wait
);
if
(
test_bit
(
STIR_STATE_TXREADY
,
&
stir
->
state
))
__set_task_state
(
current
,
TASK_RUNNING
);
else
schedule_timeout
(
HZ
/
10
);
remove_wait_queue
(
&
stir
->
thr_wait
,
&
wait
);
}
}
complete_and_exit
(
&
stir
->
thr_exited
,
0
);
complete_and_exit
(
&
stir
->
thr_exited
,
0
);
...
@@ -841,48 +824,34 @@ static int stir_transmit_thread(void *arg)
...
@@ -841,48 +824,34 @@ static int stir_transmit_thread(void *arg)
/*
/*
*
Receive wrapped data into rx_data buffer
.
*
USB bulk receive completion callback
.
*
This chip doesn't block until data is available, we just have
*
Wakes up every ms (usb round trip) with wrapped
*
to read the FIFO perodically (ugh)
.
*
data
.
*/
*/
static
void
stir_
usb_receive
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
)
static
void
stir_
rcv_irq
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
)
{
{
struct
stir_cb
*
stir
=
urb
->
context
;
struct
stir_cb
*
stir
=
urb
->
context
;
int
err
;
int
err
;
/* in process of stopping, just drop data */
if
(
!
netif_running
(
stir
->
netdev
))
if
(
!
netif_running
(
stir
->
netdev
))
return
;
return
;
switch
(
urb
->
status
)
{
/* unlink, shutdown, unplug, other nasties */
case
0
:
if
(
urb
->
status
!=
0
)
if
(
urb
->
actual_length
>
0
)
{
return
;
pr_debug
(
"%s: receive %d
\n
"
,
stir
->
netdev
->
name
,
urb
->
actual_length
);
if
(
urb
->
actual_length
>
0
)
{
pr_debug
(
"receive %d
\n
"
,
urb
->
actual_length
);
unwrap_chars
(
stir
,
urb
->
transfer_buffer
,
unwrap_chars
(
stir
,
urb
->
transfer_buffer
,
urb
->
actual_length
);
urb
->
actual_length
);
stir
->
netdev
->
last_rx
=
jiffies
;
stir
->
netdev
->
last_rx
=
jiffies
;
stir
->
rx_time
=
CURRENT_TIME
;
do_gettimeofday
(
&
stir
->
rx_time
);
}
break
;
case
-
ECONNRESET
:
/* killed but pending */
case
-
ENOENT
:
/* killed but not in use */
case
-
ESHUTDOWN
:
/* These are normal errors when URB is cancelled */
stir
->
rx_buff
.
in_frame
=
FALSE
;
stir
->
rx_buff
.
state
=
OUTSIDE_FRAME
;
return
;
default:
WARNING
(
"%s: received status %d
\n
"
,
stir
->
netdev
->
name
,
urb
->
status
);
stir
->
stats
.
rx_errors
++
;
urb
->
status
=
0
;
}
}
/* kernel thread is stopping receiver don't resubmit */
/* kernel thread is stopping receiver don't resubmit */
if
(
!
test_bit
(
STIR_STATE_RECEIVING
,
&
stir
->
state
)
)
if
(
!
stir
->
receiving
)
return
;
return
;
/* resubmit existing urb */
/* resubmit existing urb */
...
@@ -890,14 +859,13 @@ static void stir_usb_receive(struct urb *urb, struct pt_regs *regs)
...
@@ -890,14 +859,13 @@ static void stir_usb_receive(struct urb *urb, struct pt_regs *regs)
/* in case of error, the kernel thread will restart us */
/* in case of error, the kernel thread will restart us */
if
(
err
)
{
if
(
err
)
{
WARNING
(
"%s: usb receive submit error: %d
\n
"
,
warn
(
"%s: usb receive submit error: %d
"
,
stir
->
netdev
->
name
,
err
);
stir
->
netdev
->
name
,
err
);
urb
->
status
=
-
ENOENT
;
stir
->
receiving
=
0
;
wake_up
(
&
stir
->
thr_wait
);
wake_up
(
&
stir
->
thr_wait
);
}
}
}
}
/*
/*
* Function stir_net_open (dev)
* Function stir_net_open (dev)
*
*
...
@@ -906,49 +874,49 @@ static void stir_usb_receive(struct urb *urb, struct pt_regs *regs)
...
@@ -906,49 +874,49 @@ static void stir_usb_receive(struct urb *urb, struct pt_regs *regs)
static
int
stir_net_open
(
struct
net_device
*
netdev
)
static
int
stir_net_open
(
struct
net_device
*
netdev
)
{
{
struct
stir_cb
*
stir
=
netdev
->
priv
;
struct
stir_cb
*
stir
=
netdev
->
priv
;
int
i
,
err
;
int
err
;
char
hwname
[
16
];
char
hwname
[
16
];
err
=
stir_reset
(
stir
);
err
=
usb_clear_halt
(
stir
->
usbdev
,
usb_sndbulkpipe
(
stir
->
usbdev
,
1
));
if
(
err
)
goto
err_out1
;
err
=
usb_clear_halt
(
stir
->
usbdev
,
usb_rcvbulkpipe
(
stir
->
usbdev
,
2
));
if
(
err
)
if
(
err
)
goto
err_out1
;
goto
err_out1
;
err
=
-
ENOMEM
;
err
=
change_speed
(
stir
,
9600
);
if
(
err
)
/* Note: Max SIR frame possible is 4273 */
stir
->
tx_data
=
kmalloc
(
STIR_FIFO_SIZE
,
GFP_KERNEL
);
if
(
!
stir
->
tx_data
)
{
ERROR
(
"%s(), alloc failed for rxbuf!
\n
"
,
__FUNCTION__
);
goto
err_out1
;
goto
err_out1
;
}
err
=
-
ENOMEM
;
/* Initialize for SIR/FIR to copy data directly into skb. */
/* Initialize for SIR/FIR to copy data directly into skb. */
stir
->
receiving
=
0
;
stir
->
rx_buff
.
truesize
=
IRDA_SKB_MAX_MTU
;
stir
->
rx_buff
.
truesize
=
IRDA_SKB_MAX_MTU
;
stir
->
rx_buff
.
skb
=
dev_alloc_skb
(
IRDA_SKB_MAX_MTU
);
stir
->
rx_buff
.
skb
=
dev_alloc_skb
(
IRDA_SKB_MAX_MTU
);
if
(
!
stir
->
rx_buff
.
skb
)
{
if
(
!
stir
->
rx_buff
.
skb
)
ERROR
(
"%s(), dev_alloc_skb() failed for rxbuf!
\n
"
,
goto
err_out1
;
__FUNCTION__
);
goto
err_out2
;
}
skb_reserve
(
stir
->
rx_buff
.
skb
,
1
);
skb_reserve
(
stir
->
rx_buff
.
skb
,
1
);
stir
->
rx_buff
.
head
=
stir
->
rx_buff
.
skb
->
data
;
stir
->
rx_buff
.
head
=
stir
->
rx_buff
.
skb
->
data
;
stir
->
rx_time
=
CURRENT_TIME
;
do_gettimeofday
(
&
stir
->
rx_time
)
;
/* Allocate N receive buffer's and urbs */
stir
->
rx_urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
for
(
i
=
0
;
i
<
NUM_RX_URBS
;
i
++
)
{
if
(
!
stir
->
rx_urb
)
stir
->
rx_urbs
[
i
]
=
usb_alloc_urb
(
0
,
GFP_KERNEL
);
goto
err_out2
;
if
(
!
stir
->
rx_urbs
[
i
]){
ERROR
(
"%s(), usb_alloc_urb failed
\n
"
,
__FUNCTION__
);
goto
err_out3
;
}
stir
->
rx_data
[
i
]
=
kmalloc
(
STIR_FIFO_SIZE
,
GFP_KERNEL
);
stir
->
io_buf
=
kmalloc
(
STIR_FIFO_SIZE
,
GFP_KERNEL
);
if
(
!
stir
->
rx_data
)
{
if
(
!
stir
->
io_buf
)
usb_free_urb
(
stir
->
rx_urbs
[
i
]);
ERROR
(
"%s(), alloc failed for rxbuf!
\n
"
,
__FUNCTION__
);
goto
err_out3
;
goto
err_out3
;
}
}
usb_fill_bulk_urb
(
stir
->
rx_urb
,
stir
->
usbdev
,
usb_rcvbulkpipe
(
stir
->
usbdev
,
2
),
stir
->
io_buf
,
STIR_FIFO_SIZE
,
stir_rcv_irq
,
stir
);
stir
->
fifo_status
=
kmalloc
(
FIFO_REGS_SIZE
,
GFP_KERNEL
);
if
(
!
stir
->
fifo_status
)
goto
err_out4
;
/*
/*
* Now that everything should be initialized properly,
* Now that everything should be initialized properly,
...
@@ -958,8 +926,8 @@ static int stir_net_open(struct net_device *netdev)
...
@@ -958,8 +926,8 @@ static int stir_net_open(struct net_device *netdev)
sprintf
(
hwname
,
"usb#%d"
,
stir
->
usbdev
->
devnum
);
sprintf
(
hwname
,
"usb#%d"
,
stir
->
usbdev
->
devnum
);
stir
->
irlap
=
irlap_open
(
netdev
,
&
stir
->
qos
,
hwname
);
stir
->
irlap
=
irlap_open
(
netdev
,
&
stir
->
qos
,
hwname
);
if
(
!
stir
->
irlap
)
{
if
(
!
stir
->
irlap
)
{
ERROR
(
"%s(): irlap_open failed
\n
"
,
__FUNCTION__
);
err
(
"irlap_open failed"
);
goto
err_out
3
;
goto
err_out
5
;
}
}
/** Start kernel thread for transmit. */
/** Start kernel thread for transmit. */
...
@@ -967,25 +935,24 @@ static int stir_net_open(struct net_device *netdev)
...
@@ -967,25 +935,24 @@ static int stir_net_open(struct net_device *netdev)
CLONE_FS
|
CLONE_FILES
);
CLONE_FS
|
CLONE_FILES
);
if
(
stir
->
thr_pid
<
0
)
{
if
(
stir
->
thr_pid
<
0
)
{
err
=
stir
->
thr_pid
;
err
=
stir
->
thr_pid
;
WARNING
(
"%s: unable to start kernel thread
\n
"
,
err
(
"unable to start kernel thread"
);
stir
->
netdev
->
name
);
goto
err_out6
;
goto
err_out4
;
}
}
netif_start_queue
(
netdev
);
netif_start_queue
(
netdev
);
return
0
;
return
0
;
err_out
4
:
err_out
6
:
irlap_close
(
stir
->
irlap
);
irlap_close
(
stir
->
irlap
);
err_out5:
kfree
(
stir
->
fifo_status
);
err_out4:
kfree
(
stir
->
io_buf
);
err_out3:
err_out3:
while
(
--
i
>=
0
)
{
usb_free_urb
(
stir
->
rx_urb
);
usb_free_urb
(
stir
->
rx_urbs
[
i
]);
kfree
(
stir
->
rx_data
[
i
]);
}
kfree_skb
(
stir
->
rx_buff
.
skb
);
err_out2:
err_out2:
kfree
(
stir
->
tx_data
);
kfree
_skb
(
stir
->
rx_buff
.
skb
);
err_out1:
err_out1:
return
err
;
return
err
;
}
}
...
@@ -999,7 +966,6 @@ static int stir_net_open(struct net_device *netdev)
...
@@ -999,7 +966,6 @@ static int stir_net_open(struct net_device *netdev)
static
int
stir_net_close
(
struct
net_device
*
netdev
)
static
int
stir_net_close
(
struct
net_device
*
netdev
)
{
{
struct
stir_cb
*
stir
=
netdev
->
priv
;
struct
stir_cb
*
stir
=
netdev
->
priv
;
int
i
;
/* Stop transmit processing */
/* Stop transmit processing */
netif_stop_queue
(
netdev
);
netif_stop_queue
(
netdev
);
...
@@ -1007,15 +973,13 @@ static int stir_net_close(struct net_device *netdev)
...
@@ -1007,15 +973,13 @@ static int stir_net_close(struct net_device *netdev)
/* Kill transmit thread */
/* Kill transmit thread */
kill_proc
(
stir
->
thr_pid
,
SIGTERM
,
1
);
kill_proc
(
stir
->
thr_pid
,
SIGTERM
,
1
);
wait_for_completion
(
&
stir
->
thr_exited
);
wait_for_completion
(
&
stir
->
thr_exited
);
kfree
(
stir
->
tx_data
);
kfree
(
stir
->
fifo_status
);
clear_bit
(
STIR_STATE_RECEIVING
,
&
stir
->
state
);
/* Mop up receive urb's */
receive_stop
(
stir
);
usb_unlink_urb
(
stir
->
rx_urb
);
for
(
i
=
0
;
i
<
NUM_RX_URBS
;
i
++
)
{
kfree
(
stir
->
io_buf
);
usb_free_urb
(
stir
->
rx_urbs
[
i
]);
usb_free_urb
(
stir
->
rx_urb
);
kfree
(
stir
->
rx_data
[
i
]);
}
kfree_skb
(
stir
->
rx_buff
.
skb
);
kfree_skb
(
stir
->
rx_buff
.
skb
);
/* Stop and remove instance of IrLAP */
/* Stop and remove instance of IrLAP */
...
@@ -1057,7 +1021,7 @@ static int stir_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
...
@@ -1057,7 +1021,7 @@ static int stir_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
case
SIOCGRECEIVING
:
case
SIOCGRECEIVING
:
/* Only approximately true */
/* Only approximately true */
irq
->
ifr_receiving
=
test_bit
(
STIR_STATE_RECEIVING
,
&
stir
->
state
)
;
irq
->
ifr_receiving
=
stir
->
receiving
;
break
;
break
;
default:
default:
...
@@ -1076,53 +1040,6 @@ static struct net_device_stats *stir_net_get_stats(struct net_device *dev)
...
@@ -1076,53 +1040,6 @@ static struct net_device_stats *stir_net_get_stats(struct net_device *dev)
return
&
stir
->
stats
;
return
&
stir
->
stats
;
}
}
/*
* Parse the various endpoints and find the one we need.
*
* The endpoint are the pipes used to communicate with the USB device.
* The spec defines 2 endpoints of type bulk transfer, one in, and one out.
* These are used to pass frames back and forth with the dongle.
*/
static
int
stir_setup_usb
(
struct
stir_cb
*
stir
,
struct
usb_interface
*
intf
)
{
struct
usb_device
*
usbdev
=
interface_to_usbdev
(
intf
);
const
struct
usb_host_interface
*
interface
=
&
intf
->
altsetting
[
intf
->
act_altsetting
];
const
struct
usb_endpoint_descriptor
*
ep_in
=
NULL
;
const
struct
usb_endpoint_descriptor
*
ep_out
=
NULL
;
int
i
;
if
(
interface
->
desc
.
bNumEndpoints
!=
2
)
{
WARNING
(
"%s: expected two endpoints
\n
"
,
__FUNCTION__
);
return
-
ENODEV
;
}
for
(
i
=
0
;
i
<
interface
->
desc
.
bNumEndpoints
;
i
++
)
{
const
struct
usb_endpoint_descriptor
*
ep
=
&
interface
->
endpoint
[
i
].
desc
;
if
((
ep
->
bmAttributes
&
USB_ENDPOINT_XFERTYPE_MASK
)
==
USB_ENDPOINT_XFER_BULK
)
{
/* We need to find an IN and an OUT */
if
((
ep
->
bEndpointAddress
&
USB_ENDPOINT_DIR_MASK
)
==
USB_DIR_IN
)
ep_in
=
ep
;
else
ep_out
=
ep
;
}
else
WARNING
(
"%s: unknown endpoint type 0x%x
\n
"
,
__FUNCTION__
,
ep
->
bmAttributes
);
}
if
(
!
ep_in
||
!
ep_out
)
return
-
EIO
;
stir
->
tx_bulkpipe
=
usb_sndbulkpipe
(
usbdev
,
ep_out
->
bEndpointAddress
&
USB_ENDPOINT_NUMBER_MASK
);
stir
->
rx_intpipe
=
usb_rcvintpipe
(
usbdev
,
ep_in
->
bEndpointAddress
&
USB_ENDPOINT_NUMBER_MASK
);
return
0
;
}
/*
/*
* This routine is called by the USB subsystem for each new device
* This routine is called by the USB subsystem for each new device
* in the system. We need to check if the device is ours, and in
* in the system. We need to check if the device is ours, and in
...
@@ -1149,9 +1066,9 @@ static int stir_probe(struct usb_interface *intf,
...
@@ -1149,9 +1066,9 @@ static int stir_probe(struct usb_interface *intf,
stir
->
netdev
=
net
;
stir
->
netdev
=
net
;
stir
->
usbdev
=
dev
;
stir
->
usbdev
=
dev
;
ret
=
stir_setup_usb
(
stir
,
intf
);
ret
=
usb_reset_configuration
(
dev
);
if
(
ret
!=
0
)
{
if
(
ret
!=
0
)
{
ERROR
(
"%s(), Bogus endpoints...
\n
"
,
__FUNCTION__
);
err
(
"usb reset configuration failed"
);
goto
err_out2
;
goto
err_out2
;
}
}
...
@@ -1180,10 +1097,6 @@ static int stir_probe(struct usb_interface *intf,
...
@@ -1180,10 +1097,6 @@ static int stir_probe(struct usb_interface *intf,
net
->
get_stats
=
stir_net_get_stats
;
net
->
get_stats
=
stir_net_get_stats
;
net
->
do_ioctl
=
stir_net_ioctl
;
net
->
do_ioctl
=
stir_net_ioctl
;
ret
=
stir_reset
(
stir
);
if
(
ret
)
goto
err_out2
;
ret
=
register_netdev
(
net
);
ret
=
register_netdev
(
net
);
if
(
ret
!=
0
)
if
(
ret
!=
0
)
goto
err_out2
;
goto
err_out2
;
...
@@ -1206,23 +1119,14 @@ static int stir_probe(struct usb_interface *intf,
...
@@ -1206,23 +1119,14 @@ static int stir_probe(struct usb_interface *intf,
static
void
stir_disconnect
(
struct
usb_interface
*
intf
)
static
void
stir_disconnect
(
struct
usb_interface
*
intf
)
{
{
struct
stir_cb
*
stir
=
usb_get_intfdata
(
intf
);
struct
stir_cb
*
stir
=
usb_get_intfdata
(
intf
);
struct
net_device
*
net
;
usb_set_intfdata
(
intf
,
NULL
);
if
(
!
stir
)
if
(
!
stir
)
return
;
return
;
/* Stop transmitter */
unregister_netdev
(
stir
->
netdev
);
net
=
stir
->
netdev
;
free_netdev
(
stir
->
netdev
);
netif_device_detach
(
net
);
/* Remove netdevice */
unregister_netdev
(
net
);
/* No longer attached to USB bus */
usb_set_intfdata
(
intf
,
NULL
);
stir
->
usbdev
=
NULL
;
free_netdev
(
net
);
}
}
...
...
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