summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@athlon.transmeta.com>2002-02-04 20:24:46 -0800
committerLinus Torvalds <torvalds@athlon.transmeta.com>2002-02-04 20:24:46 -0800
commitaed492fcb972130f11cd62fd8ca0b2af95f54d03 (patch)
treeecd755228f49b188323b4dd257b06fc43fb2f9ae /drivers
parent2ef7e8cef81e6a091de2aebd9d30c273edf6c13c (diff)
v2.4.12.5 -> v2.4.12.6
- Stephen Rothwell: APM idle time handling fixes, docbook update, cleanup - Jeff Garzik: network driver updates - Greg KH: USB updates - Al Viro: UFS update, binfmt_misc rewrite. - Andreas Dilger: /dev/random fixes - David Miller: network/sparc updates
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/char/drm/drm_drv.h20
-rw-r--r--drivers/char/drm/drm_vm.h7
-rw-r--r--drivers/char/drm/ffb_drv.c12
-rw-r--r--drivers/char/random.c205
-rw-r--r--drivers/message/i2o/i2o_core.c8
-rw-r--r--drivers/message/i2o/i2o_pci.c2
-rw-r--r--drivers/message/i2o/i2o_scsi.c8
-rw-r--r--drivers/net/8139cp.c1325
-rw-r--r--drivers/net/8139too.c27
-rw-r--r--drivers/net/Config.in1
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/myri_sbus.c1
-rw-r--r--drivers/net/pcnet32.c6
-rw-r--r--drivers/net/sunbmac.c1
-rw-r--r--drivers/net/sundance.c182
-rw-r--r--drivers/net/sungem.c691
-rw-r--r--drivers/net/sungem.h53
-rw-r--r--drivers/net/sunlance.c1
-rw-r--r--drivers/net/sunqe.c2
-rw-r--r--drivers/net/wireless/airo.c922
-rw-r--r--drivers/net/yellowfin.c11
-rw-r--r--drivers/pci/pci.ids15
-rw-r--r--drivers/scsi/qlogicfc.h5
-rw-r--r--drivers/usb/devices.c4
-rw-r--r--drivers/usb/hiddev.c4
-rw-r--r--drivers/usb/inode.c14
-rw-r--r--drivers/usb/kaweth.c6
-rw-r--r--drivers/usb/scanner.c219
-rw-r--r--drivers/usb/scanner.h69
-rw-r--r--drivers/usb/serial/ftdi_sio.c2
-rw-r--r--drivers/usb/uhci.c4
-rw-r--r--drivers/usb/usb-ohci.c4
-rw-r--r--drivers/usb/usb.c19
-rw-r--r--drivers/usb/usbnet.c2
-rw-r--r--drivers/usb/uss720.c2
-rw-r--r--drivers/video/acornfb.c2
-rw-r--r--drivers/video/amifb.c2
-rw-r--r--drivers/video/aty/atyfb_base.c3
-rw-r--r--drivers/video/aty128fb.c3
-rw-r--r--drivers/video/controlfb.c3
-rw-r--r--drivers/video/cyberfb.c3
-rw-r--r--drivers/video/fm2fb.c3
-rw-r--r--drivers/video/hgafb.c3
-rw-r--r--drivers/video/igafb.c3
-rw-r--r--drivers/video/imsttfb.c3
-rw-r--r--drivers/video/macfb.c2
-rw-r--r--drivers/video/matrox/matroxfb_base.c2
-rw-r--r--drivers/video/platinumfb.c3
-rw-r--r--drivers/video/radeonfb.c3
-rw-r--r--drivers/video/retz3fb.c3
-rw-r--r--drivers/video/riva/fbdev.c3
-rw-r--r--drivers/video/sa1100fb.c3
-rw-r--r--drivers/video/sgivwfb.c3
-rw-r--r--drivers/video/sis/sis_main.c3
-rw-r--r--drivers/video/sstfb.c3
-rw-r--r--drivers/video/tdfxfb.c4
-rw-r--r--drivers/video/tgafb.c2
-rw-r--r--drivers/video/valkyriefb.c3
-rw-r--r--drivers/video/vesafb.c2
-rw-r--r--drivers/video/vfb.c3
-rw-r--r--drivers/video/vga16fb.c2
-rw-r--r--drivers/video/virgefb.c2
63 files changed, 3009 insertions, 922 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index a5279636d77a..c2679823fd2d 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -7,7 +7,7 @@
mod-subdirs := dio mtd sbus video macintosh usb input telephony sgi ide \
- i2o message/fusion scsi md ieee1394 pnp isdn atm \
+ message/i2o message/fusion scsi md ieee1394 pnp isdn atm \
fc4 net/hamradio i2c acpi bluetooth
subdir-y := parport char block net sound misc media cdrom
diff --git a/drivers/char/drm/drm_drv.h b/drivers/char/drm/drm_drv.h
index 9b96d4b93f92..a4ee2537f8fe 100644
--- a/drivers/char/drm/drm_drv.h
+++ b/drivers/char/drm/drm_drv.h
@@ -1047,6 +1047,25 @@ int DRM(unlock)( struct inode *inode, struct file *filp,
atomic_inc( &dev->counts[_DRM_STAT_UNLOCKS] );
+#if __HAVE_KERNEL_CTX_SWITCH
+ /* We no longer really hold it, but if we are the next
+ * agent to request it then we should just be able to
+ * take it immediately and not eat the ioctl.
+ */
+ dev->lock.pid = 0;
+ {
+ __volatile__ unsigned int *plock = &dev->lock.hw_lock->lock;
+ unsigned int old, new, prev, ctx;
+
+ ctx = lock.context;
+ do {
+ old = *plock;
+ new = ctx;
+ prev = cmpxchg(plock, old, new);
+ } while (prev != old);
+ }
+ wake_up_interruptible(&dev->lock.lock_queue);
+#else
DRM(lock_transfer)( dev, &dev->lock.hw_lock->lock,
DRM_KERNEL_CONTEXT );
#if __HAVE_DMA_SCHEDULE
@@ -1061,6 +1080,7 @@ int DRM(unlock)( struct inode *inode, struct file *filp,
DRM_ERROR( "\n" );
}
}
+#endif /* !__HAVE_KERNEL_CTX_SWITCH */
unblock_all_signals();
return 0;
diff --git a/drivers/char/drm/drm_vm.h b/drivers/char/drm/drm_vm.h
index fe68fc97eb64..113a8e94b9cd 100644
--- a/drivers/char/drm/drm_vm.h
+++ b/drivers/char/drm/drm_vm.h
@@ -531,10 +531,17 @@ int DRM(mmap)(struct file *filp, struct vm_area_struct *vma)
vma->vm_flags |= VM_IO; /* not in core dump */
}
offset = DRIVER_GET_REG_OFS();
+#ifdef __sparc__
+ if (io_remap_page_range(vma->vm_start,
+ VM_OFFSET(vma) + offset,
+ vma->vm_end - vma->vm_start,
+ vma->vm_page_prot, 0))
+#else
if (remap_page_range(vma->vm_start,
VM_OFFSET(vma) + offset,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
+#endif
return -EAGAIN;
DRM_DEBUG(" Type = %d; start = 0x%lx, end = 0x%lx,"
" offset = 0x%lx\n",
diff --git a/drivers/char/drm/ffb_drv.c b/drivers/char/drm/ffb_drv.c
index 4048abf0eecb..e73a3e910b93 100644
--- a/drivers/char/drm/ffb_drv.c
+++ b/drivers/char/drm/ffb_drv.c
@@ -1,4 +1,4 @@
-/* $Id: ffb_drv.c,v 1.15 2001/08/09 17:47:51 davem Exp $
+/* $Id: ffb_drv.c,v 1.16 2001/10/18 16:00:24 davem Exp $
* ffb_drv.c: Creator/Creator3D direct rendering driver.
*
* Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -45,16 +45,16 @@ static struct file_operations DRM(fops) = { \
#define DRIVER_PRESETUP() do { \
int _ret; \
_ret = ffb_presetup(dev); \
- if(_ret != 0) return _ret; \
+ if (_ret != 0) return _ret; \
} while(0)
/* Free private structure */
#define DRIVER_PRETAKEDOWN() do { \
- if(dev->dev_private) kfree(dev->dev_private); \
+ if (dev->dev_private) kfree(dev->dev_private); \
} while(0)
#define DRIVER_POSTCLEANUP() do { \
- if(ffb_position != NULL) kfree(ffb_position); \
+ if (ffb_position != NULL) kfree(ffb_position); \
} while(0)
/* We have to free up the rogue hw context state holding error or
@@ -66,7 +66,9 @@ static struct file_operations DRM(fops) = { \
int idx; \
\
idx = context - 1; \
- if (fpriv && fpriv->hw_state[idx] != NULL) { \
+ if (fpriv && \
+ context != DRM_KERNEL_CONTEXT && \
+ fpriv->hw_state[idx] != NULL) { \
kfree(fpriv->hw_state[idx]); \
fpriv->hw_state[idx] = NULL; \
} \
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 40f0cb7deda7..dc87c9db607b 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -164,25 +164,32 @@
* sequence:
*
* echo "Initializing random number generator..."
- * random_seed=/var/run/random-seed
+ * random_seed=/var/run/random-seed
* # Carry a random seed from start-up to start-up
- * # Load and then save 512 bytes, which is the size of the entropy pool
- * if [ -f $random_seed ]; then
+ * # Load and then save the whole entropy pool
+ * if [ -f $random_seed ]; then
* cat $random_seed >/dev/urandom
- * fi
- * dd if=/dev/urandom of=$random_seed count=1
- * chmod 600 $random_seed
+ * else
+ * touch $random_seed
+ * fi
+ * chmod 600 $random_seed
+ * poolfile=/proc/sys/kernel/random/poolsize
+ * [ -r $poolfile ] && bytes=`cat $poolfile` || bytes=512
+ * dd if=/dev/urandom of=$random_seed count=1 bs=bytes
*
* and the following lines in an appropriate script which is run as
* the system is shutdown:
- *
+ *
* # Carry a random seed from shut-down to start-up
- * # Save 512 bytes, which is the size of the entropy pool
+ * # Save the whole entropy pool
* echo "Saving random seed..."
- * random_seed=/var/run/random-seed
- * dd if=/dev/urandom of=$random_seed count=1
- * chmod 600 $random_seed
- *
+ * random_seed=/var/run/random-seed
+ * touch $random_seed
+ * chmod 600 $random_seed
+ * poolfile=/proc/sys/kernel/random/poolsize
+ * [ -r $poolfile ] && bytes=`cat $poolfile` || bytes=512
+ * dd if=/dev/urandom of=$random_seed count=1 bs=bytes
+ *
* For example, on most modern systems using the System V init
* scripts, such code fragments would be found in
* /etc/rc.d/init.d/random. On older Linux systems, the correct script
@@ -272,8 +279,8 @@ static int random_read_wakeup_thresh = 8;
static int random_write_wakeup_thresh = 128;
/*
- * A pool of size POOLWORDS is stirred with a primitive polynomial
- * of degree POOLWORDS over GF(2). The taps for various sizes are
+ * A pool of size .poolwords is stirred with a primitive polynomial
+ * of degree .poolwords over GF(2). The taps for various sizes are
* defined below. They are chosen to be evenly spaced (minimum RMS
* distance from evenly spaced; the numbers in the comments are a
* scaled squared error sum) except for the last tap, which is 1 to
@@ -284,19 +291,17 @@ static struct poolinfo {
int tap1, tap2, tap3, tap4, tap5;
} poolinfo_table[] = {
/* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1 -- 115 */
- { 2048, 1638, 1231, 819, 411, 1 },
+ { 2048, 1638, 1231, 819, 411, 1 },
/* x^1024 + x^817 + x^615 + x^412 + x^204 + x + 1 -- 290 */
- { 1024, 817, 615, 412, 204, 1 },
-
+ { 1024, 817, 615, 412, 204, 1 },
#if 0 /* Alternate polynomial */
/* x^1024 + x^819 + x^616 + x^410 + x^207 + x^2 + 1 -- 115 */
{ 1024, 819, 616, 410, 207, 2 },
#endif
-
+
/* x^512 + x^411 + x^308 + x^208 + x^104 + x + 1 -- 225 */
{ 512, 411, 308, 208, 104, 1 },
-
#if 0 /* Alternates */
/* x^512 + x^409 + x^307 + x^206 + x^102 + x^2 + 1 -- 95 */
{ 512, 409, 307, 206, 102, 2 },
@@ -306,10 +311,9 @@ static struct poolinfo {
/* x^256 + x^205 + x^155 + x^101 + x^52 + x + 1 -- 125 */
{ 256, 205, 155, 101, 52, 1 },
-
+
/* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */
{ 128, 103, 76, 51, 25, 1 },
-
#if 0 /* Alternate polynomial */
/* x^128 + x^103 + x^78 + x^51 + x^27 + x^2 + 1 -- 70 */
{ 128, 103, 78, 51, 27, 2 },
@@ -321,9 +325,12 @@ static struct poolinfo {
/* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */
{ 32, 26, 20, 14, 7, 1 },
- { 0, 0, 0, 0, 0, 0 },
-};
-
+ { 0, 0, 0, 0, 0, 0 },
+};
+
+#define POOLBITS poolwords*32
+#define POOLBYTES poolwords*4
+
/*
* For the purposes of better mixing, we use the CRC-32 polynomial as
* well to make a twisted Generalized Feedback Shift Reigster
@@ -461,6 +468,12 @@ static inline __u32 int_ln_12bits(__u32 word)
}
#endif
+#if 0
+#define DEBUG_ENT(fmt, arg...) printk(KERN_DEBUG "random: " fmt, ## arg)
+#else
+#define DEBUG_ENT(fmt, arg...) do {} while (0)
+#endif
+
/**********************************************************************
*
* OS independent entropy store. Here are the functions which handle
@@ -480,7 +493,7 @@ struct entropy_store {
/*
* Initialize the entropy store. The input argument is the size of
* the random pool.
- *
+ *
* Returns an negative error if there is a problem.
*/
static int create_entropy_store(int size, struct entropy_store **ret_bucket)
@@ -507,12 +520,12 @@ static int create_entropy_store(int size, struct entropy_store **ret_bucket)
memset (r, 0, sizeof(struct entropy_store));
r->poolinfo = *p;
- r->pool = kmalloc(poolwords*4, GFP_KERNEL);
+ r->pool = kmalloc(POOLBYTES, GFP_KERNEL);
if (!r->pool) {
kfree(r);
return -ENOMEM;
}
- memset(r->pool, 0, poolwords*4);
+ memset(r->pool, 0, POOLBYTES);
*ret_bucket = r;
return 0;
}
@@ -524,7 +537,7 @@ static void clear_entropy_store(struct entropy_store *r)
r->entropy_count = 0;
r->input_rotate = 0;
r->extract_count = 0;
- memset(r->pool, 0, r->poolinfo.poolwords*4);
+ memset(r->pool, 0, r->poolinfo.POOLBYTES);
}
static void free_entropy_store(struct entropy_store *r)
@@ -545,18 +558,19 @@ static void free_entropy_store(struct entropy_store *r)
* the entropy is concentrated in the low-order bits.
*/
static void add_entropy_words(struct entropy_store *r, const __u32 *in,
- int num)
+ int nwords)
{
static __u32 const twist_table[8] = {
0, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 };
unsigned i;
int new_rotate;
+ int wordmask = r->poolinfo.poolwords - 1;
__u32 w;
- while (num--) {
+ while (nwords--) {
w = rotate_left(r->input_rotate, *in);
- i = r->add_ptr = (r->add_ptr - 1) & (r->poolinfo.poolwords-1);
+ i = r->add_ptr = (r->add_ptr - 1) & wordmask;
/*
* Normally, we add 7 bits of rotation to the pool.
* At the beginning of the pool, add an extra 7 bits
@@ -569,11 +583,11 @@ static void add_entropy_words(struct entropy_store *r, const __u32 *in,
r->input_rotate = new_rotate & 31;
/* XOR in the various taps */
- w ^= r->pool[(i+r->poolinfo.tap1)&(r->poolinfo.poolwords-1)];
- w ^= r->pool[(i+r->poolinfo.tap2)&(r->poolinfo.poolwords-1)];
- w ^= r->pool[(i+r->poolinfo.tap3)&(r->poolinfo.poolwords-1)];
- w ^= r->pool[(i+r->poolinfo.tap4)&(r->poolinfo.poolwords-1)];
- w ^= r->pool[(i+r->poolinfo.tap5)&(r->poolinfo.poolwords-1)];
+ w ^= r->pool[(i + r->poolinfo.tap1) & wordmask];
+ w ^= r->pool[(i + r->poolinfo.tap2) & wordmask];
+ w ^= r->pool[(i + r->poolinfo.tap3) & wordmask];
+ w ^= r->pool[(i + r->poolinfo.tap4) & wordmask];
+ w ^= r->pool[(i + r->poolinfo.tap5) & wordmask];
w ^= r->pool[i];
r->pool[i] = (w >> 3) ^ twist_table[w & 7];
}
@@ -582,16 +596,22 @@ static void add_entropy_words(struct entropy_store *r, const __u32 *in,
/*
* Credit (or debit) the entropy store with n bits of entropy
*/
-static void credit_entropy_store(struct entropy_store *r, int num)
+static void credit_entropy_store(struct entropy_store *r, int nbits)
{
- int max_entropy = r->poolinfo.poolwords*32;
-
- if (r->entropy_count + num < 0)
+ if (r->entropy_count + nbits < 0) {
+ DEBUG_ENT("negative entropy/overflow (%d+%d)\n",
+ r->entropy_count, nbits);
r->entropy_count = 0;
- else if (r->entropy_count + num > max_entropy)
- r->entropy_count = max_entropy;
- else
- r->entropy_count = r->entropy_count + num;
+ } else if (r->entropy_count + nbits > r->poolinfo.POOLBITS) {
+ r->entropy_count = r->poolinfo.POOLBITS;
+ } else {
+ r->entropy_count += nbits;
+ if (nbits)
+ DEBUG_ENT("%s added %d bits, now %d\n",
+ r == sec_random_state ? "secondary" :
+ r == random_state ? "primary" : "unknown",
+ nbits, r->entropy_count);
+ }
}
/**********************************************************************
@@ -627,6 +647,12 @@ static int __init batch_entropy_init(int size, struct entropy_store *r)
return 0;
}
+/*
+ * Changes to the entropy data is put into a queue rather than being added to
+ * the entropy counts directly. This is presumably to avoid doing heavy
+ * hashing calculations during an interrupt in add_timer_randomness().
+ * Instead, the entropy is only added to the pool once per timer tick.
+ */
void batch_entropy_store(u32 a, u32 b, int num)
{
int new;
@@ -643,32 +669,35 @@ void batch_entropy_store(u32 a, u32 b, int num)
queue_task(&batch_tqueue, &tq_timer);
batch_head = new;
} else {
-#if 0
- printk(KERN_NOTICE "random: batch entropy buffer full\n");
-#endif
+ DEBUG_ENT("batch entropy buffer full\n");
}
}
+/*
+ * Flush out the accumulated entropy operations, adding entropy to the passed
+ * store (normally random_state). If that store has enough entropy, alternate
+ * between randomizing the data of the primary and secondary stores.
+ */
static void batch_entropy_process(void *private_)
{
- int num = 0;
- int max_entropy;
struct entropy_store *r = (struct entropy_store *) private_, *p;
-
+ int max_entropy = r->poolinfo.POOLBITS;
+
if (!batch_max)
return;
- max_entropy = r->poolinfo.poolwords*32;
+ p = r;
while (batch_head != batch_tail) {
+ if (r->entropy_count >= max_entropy) {
+ r = (r == sec_random_state) ? random_state :
+ sec_random_state;
+ max_entropy = r->poolinfo.POOLBITS;
+ }
add_entropy_words(r, batch_entropy_pool + 2*batch_tail, 2);
- p = r;
- if (r->entropy_count > max_entropy && (num & 1))
- r = sec_random_state;
credit_entropy_store(r, batch_entropy_credit[batch_tail]);
batch_tail = (batch_tail+1) & (batch_max-1);
- num++;
}
- if (r->entropy_count >= random_read_wakeup_thresh)
+ if (p->entropy_count >= random_read_wakeup_thresh)
wake_up_interruptible(&random_read_wait);
}
@@ -1204,9 +1233,9 @@ static ssize_t extract_entropy(struct entropy_store *r, void * buf,
/*
* This utility inline function is responsible for transfering entropy
- * from the primary pool to the secondary extraction pool. We pull
- * randomness under two conditions; one is if there isn't enough entropy
- * in the secondary pool. The other is after we have extract 1024 bytes,
+ * from the primary pool to the secondary extraction pool. We pull
+ * randomness under two conditions; one is if there isn't enough entropy
+ * in the secondary pool. The other is after we have extracted 1024 bytes,
* at which point we do a "catastrophic reseeding".
*/
static inline void xfer_secondary_pool(struct entropy_store *r,
@@ -1214,14 +1243,26 @@ static inline void xfer_secondary_pool(struct entropy_store *r,
{
__u32 tmp[TMP_BUF_SIZE];
- if (r->entropy_count < nbytes*8) {
- extract_entropy(random_state, tmp, sizeof(tmp), 0);
- add_entropy_words(r, tmp, TMP_BUF_SIZE);
- credit_entropy_store(r, TMP_BUF_SIZE*8);
+ if (r->entropy_count < nbytes * 8 &&
+ r->entropy_count < r->poolinfo.POOLBITS) {
+ int nwords = min(r->poolinfo.poolwords - r->entropy_count/32,
+ sizeof(tmp) / 4);
+
+ DEBUG_ENT("xfer %d from primary to %s (have %d, need %d)\n",
+ nwords * 32,
+ r == sec_random_state ? "secondary" : "unknown",
+ r->entropy_count, nbytes * 8);
+
+ extract_entropy(random_state, tmp, nwords, 0);
+ add_entropy_words(r, tmp, nwords);
+ credit_entropy_store(r, nwords * 32);
}
if (r->extract_count > 1024) {
+ DEBUG_ENT("reseeding %s with %d from primary\n",
+ r == sec_random_state ? "secondary" : "unknown",
+ sizeof(tmp) * 8);
extract_entropy(random_state, tmp, sizeof(tmp), 0);
- add_entropy_words(r, tmp, TMP_BUF_SIZE);
+ add_entropy_words(r, tmp, sizeof(tmp) / 4);
r->extract_count = 0;
}
}
@@ -1232,9 +1273,12 @@ static inline void xfer_secondary_pool(struct entropy_store *r,
* bits of entropy are left in the pool, but it does not restrict the
* number of bytes that are actually obtained. If the EXTRACT_ENTROPY_USER
* flag is given, then the buf pointer is assumed to be in user space.
- * If the EXTRACT_ENTROPY_SECONDARY flag is given, then this function will
*
- * Note: extract_entropy() assumes that POOLWORDS is a multiple of 16 words.
+ * If the EXTRACT_ENTROPY_SECONDARY flag is given, then we are actually
+ * extracting entropy from the secondary pool, and can refill from the
+ * primary pool if needed.
+ *
+ * Note: extract_entropy() assumes that .poolwords is a multiple of 16 words.
*/
static ssize_t extract_entropy(struct entropy_store *r, void * buf,
size_t nbytes, int flags)
@@ -1244,14 +1288,19 @@ static ssize_t extract_entropy(struct entropy_store *r, void * buf,
__u32 x;
add_timer_randomness(&extract_timer_state, nbytes);
-
+
/* Redundant, but just in case... */
- if (r->entropy_count > r->poolinfo.poolwords)
- r->entropy_count = r->poolinfo.poolwords;
+ if (r->entropy_count > r->poolinfo.POOLBITS)
+ r->entropy_count = r->poolinfo.POOLBITS;
if (flags & EXTRACT_ENTROPY_SECONDARY)
xfer_secondary_pool(r, nbytes);
+ DEBUG_ENT("%s has %d bits, want %d bits\n",
+ r == sec_random_state ? "secondary" :
+ r == random_state ? "primary" : "unknown",
+ r->entropy_count, nbytes * 8);
+
if (r->entropy_count / 8 >= nbytes)
r->entropy_count -= nbytes*8;
else
@@ -1547,9 +1596,7 @@ random_write(struct file * file, const char * buffer,
c -= bytes;
p += bytes;
- /* Convert bytes to words */
- bytes = (bytes + 3) / sizeof(__u32);
- add_entropy_words(random_state, buf, bytes);
+ add_entropy_words(random_state, buf, (bytes + 3) / 4);
}
if (p == buffer) {
return (ssize_t)ret;
@@ -1599,7 +1646,7 @@ random_ioctl(struct inode * inode, struct file * file,
return -EINVAL;
if (size > random_state->poolinfo.poolwords)
size = random_state->poolinfo.poolwords;
- if (copy_to_user(p, random_state->pool, size*sizeof(__u32)))
+ if (copy_to_user(p, random_state->pool, size * 4))
return -EFAULT;
return 0;
case RNDADDENTROPY:
@@ -1716,11 +1763,11 @@ static int proc_do_poolsize(ctl_table *table, int write, struct file *filp,
{
int ret;
- sysctl_poolsize = random_state->poolinfo.poolwords * 4;
+ sysctl_poolsize = random_state->poolinfo.POOLBYTES;
ret = proc_dointvec(table, write, filp, buffer, lenp);
if (ret || !write ||
- (sysctl_poolsize == random_state->poolinfo.poolwords * 4))
+ (sysctl_poolsize == random_state->poolinfo.POOLBYTES))
return ret;
return change_poolsize(sysctl_poolsize);
@@ -1732,7 +1779,7 @@ static int poolsize_strategy(ctl_table *table, int *name, int nlen,
{
int len;
- sysctl_poolsize = random_state->poolinfo.poolwords * 4;
+ sysctl_poolsize = random_state->poolinfo.POOLBYTES;
/*
* We only handle the write case, since the read case gets
@@ -1747,7 +1794,7 @@ static int poolsize_strategy(ctl_table *table, int *name, int nlen,
return -EFAULT;
}
- if (sysctl_poolsize != random_state->poolinfo.poolwords * 4)
+ if (sysctl_poolsize != random_state->poolinfo.POOLBYTES)
return change_poolsize(sysctl_poolsize);
return 0;
@@ -1846,8 +1893,7 @@ static void sysctl_init_random(struct entropy_store *random_state)
{
min_read_thresh = 8;
min_write_thresh = 0;
- max_read_thresh = max_write_thresh =
- random_state->poolinfo.poolwords * 32;
+ max_read_thresh = max_write_thresh = random_state->poolinfo.POOLBITS;
random_table[1].data = &random_state->entropy_count;
}
#endif /* CONFIG_SYSCTL */
@@ -2239,4 +2285,5 @@ EXPORT_SYMBOL(add_mouse_randomness);
EXPORT_SYMBOL(add_interrupt_randomness);
EXPORT_SYMBOL(add_blkdev_randomness);
EXPORT_SYMBOL(batch_entropy_store);
+EXPORT_SYMBOL(generate_random_uuid);
diff --git a/drivers/message/i2o/i2o_core.c b/drivers/message/i2o/i2o_core.c
index d4d0d0e75351..25360fdd2c07 100644
--- a/drivers/message/i2o/i2o_core.c
+++ b/drivers/message/i2o/i2o_core.c
@@ -1924,12 +1924,12 @@ static int i2o_systab_send(struct i2o_controller *iop)
if(iop->status_block->current_mem_size < iop->status_block->desired_mem_size)
{
struct resource *res = &iop->mem_resource;
- res->name = iop->bus.pci.pdev->bus->name;
+ res->name = iop->pdev->bus->name;
res->flags = IORESOURCE_MEM;
res->start = 0;
res->end = 0;
printk("%s: requires private memory resources.\n", iop->name);
- root = pci_find_parent_resource(iop->bus.pci.pdev, res);
+ root = pci_find_parent_resource(iop->pdev, res);
if(root==NULL)
printk("Can't find parent resource!\n");
if(root && allocate_resource(root, res,
@@ -1950,12 +1950,12 @@ static int i2o_systab_send(struct i2o_controller *iop)
if(iop->status_block->current_io_size < iop->status_block->desired_io_size)
{
struct resource *res = &iop->io_resource;
- res->name = iop->bus.pci.pdev->bus->name;
+ res->name = iop->pdev->bus->name;
res->flags = IORESOURCE_IO;
res->start = 0;
res->end = 0;
printk("%s: requires private memory resources.\n", iop->name);
- root = pci_find_parent_resource(iop->bus.pci.pdev, res);
+ root = pci_find_parent_resource(iop->pdev, res);
if(root==NULL)
printk("Can't find parent resource!\n");
if(root && allocate_resource(root, res,
diff --git a/drivers/message/i2o/i2o_pci.c b/drivers/message/i2o/i2o_pci.c
index 64c9ede1606e..056b90fafdd0 100644
--- a/drivers/message/i2o/i2o_pci.c
+++ b/drivers/message/i2o/i2o_pci.c
@@ -162,7 +162,7 @@ int __init i2o_pci_install(struct pci_dev *dev)
c->bus.pci.queue_buggy = 0;
c->bus.pci.dpt = 0;
c->bus.pci.short_req = 0;
- c->bus.pci.pdev = dev;
+ c->pdev = dev;
c->irq_mask = (volatile u32 *)(mem+0x34);
c->post_port = (volatile u32 *)(mem+0x40);
diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
index 7275a7703d8e..93f27fb37aae 100644
--- a/drivers/message/i2o/i2o_scsi.c
+++ b/drivers/message/i2o/i2o_scsi.c
@@ -48,9 +48,9 @@
#include <linux/blk.h>
#include <linux/version.h>
#include <linux/i2o.h>
-#include "../scsi/scsi.h"
-#include "../scsi/hosts.h"
-#include "../scsi/sd.h"
+#include "../../scsi/scsi.h"
+#include "../../scsi/hosts.h"
+#include "../../scsi/sd.h"
#include "i2o_scsi.h"
#define VERSION_STRING "Version 0.0.1"
@@ -909,4 +909,4 @@ MODULE_AUTHOR("Red Hat Software");
static Scsi_Host_Template driver_template = I2OSCSI;
-#include "../scsi/scsi_module.c"
+#include "../../scsi/scsi_module.c"
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
new file mode 100644
index 000000000000..7956265b5970
--- /dev/null
+++ b/drivers/net/8139cp.c
@@ -0,0 +1,1325 @@
+/* 8139cp.c: A Linux PCI Ethernet driver for the RealTek 8139C+ chips. */
+/*
+ Copyright 2001 Jeff Garzik <jgarzik@mandrakesoft.com>
+
+ Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com) [sungem.c]
+ Copyright 2001 Manfred Spraul [natsemi.c]
+ Copyright 1999-2001 by Donald Becker. [natsemi.c]
+ Written 1997-2001 by Donald Becker. [8139too.c]
+ Copyright 1998-2001 by Jes Sorensen, <jes@trained-monkey.org>. [acenic.c]
+
+ This software may be used and distributed according to the terms of
+ the GNU General Public License (GPL), incorporated herein by reference.
+ Drivers based on or derived from this code fall under the GPL and must
+ retain the authorship, copyright and license notice. This file is not
+ a complete program and may only be used when the entire operating
+ system is licensed under the GPL.
+
+ See the file COPYING in this distribution for more information.
+
+ TODO:
+ * dev->tx_timeout
+ * Constants (module parms?) for Rx work limit
+ * support 64-bit PCI DMA
+ * ETHTOOL_[GS]SET, ETHTOOL_GREGS, ETHTOOL_[GS]WOL,
+ ETHTOOL_[GS]MSGLVL, ETHTOOL_NWAY_RST
+ * Complete reset on PciErr
+ * LinkChg and LenChg interrupts
+ * Consider Rx interrupt mitigation using TimerIntr
+ * Implement 8139C+ statistics dump
+ * Support forcing media type with a module parameter,
+ like dl2k.c/sundance.c
+ * Rx checksumming
+ * Tx checksumming
+ * Jumbo frames / dev->change_mtu
+ * Tx abort stops Tx DMA?
+ * Investigate IntrStatus bit 10 purpose and use
+ * Investigate using skb->priority with h/w VLAN priority
+ * Investigate using High Priority Tx Queue with skb->priority
+ * Adjust Rx FIFO threshold and Max Rx DMA burst on Rx FIFO error
+ * Adjust Tx FIFO threshold and Max Tx DMA burst on Tx FIFO error
+
+ */
+
+#define DRV_NAME "8139cp"
+#define DRV_VERSION "0.0.5"
+#define DRV_RELDATE "Oct 19, 2001"
+
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ethtool.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+/* These identify the driver base version and may not be removed. */
+static char version[] __devinitdata =
+KERN_INFO DRV_NAME " 10/100 PCI Ethernet driver v" DRV_VERSION " (" DRV_RELDATE ")\n";
+
+MODULE_AUTHOR("Jeff Garzik <jgarzik@mandrakesoft.com>");
+MODULE_DESCRIPTION("RealTek RTL-8139C+ series 10/100 PCI Ethernet driver");
+MODULE_LICENSE("GPL");
+
+static int debug = -1;
+MODULE_PARM (debug, "i");
+MODULE_PARM_DESC (debug, "8139cp bitmapped message enable number");
+
+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
+ The RTL chips use a 64 element hash table based on the Ethernet CRC. */
+static int multicast_filter_limit = 32;
+MODULE_PARM (multicast_filter_limit, "i");
+MODULE_PARM_DESC (multicast_filter_limit, "8139cp maximum number of filtered multicast addresses");
+
+/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
+#if defined(__alpha__) || defined(__arm__) || defined(__hppa__) \
+ || defined(__sparc_) || defined(__ia64__) \
+ || defined(__sh__) || defined(__mips__)
+static int rx_copybreak = 1518;
+#else
+static int rx_copybreak = 100;
+#endif
+MODULE_PARM (rx_copybreak, "i");
+MODULE_PARM_DESC (rx_copybreak, "8139cp Breakpoint at which Rx packets are copied");
+
+#define PFX DRV_NAME ": "
+
+#define CP_DEF_MSG_ENABLE (NETIF_MSG_DRV | \
+ NETIF_MSG_PROBE | \
+ NETIF_MSG_LINK)
+#define CP_REGS_SIZE (0xff + 1)
+#define CP_RX_RING_SIZE 64
+#define CP_TX_RING_SIZE 64
+#define CP_RING_BYTES \
+ ((sizeof(struct cp_desc) * CP_RX_RING_SIZE) + \
+ (sizeof(struct cp_desc) * CP_TX_RING_SIZE))
+#define NEXT_TX(N) (((N) + 1) & (CP_TX_RING_SIZE - 1))
+#define NEXT_RX(N) (((N) + 1) & (CP_RX_RING_SIZE - 1))
+#define TX_BUFFS_AVAIL(CP) \
+ (((CP)->tx_tail <= (CP)->tx_head) ? \
+ (CP)->tx_tail + (CP_TX_RING_SIZE - 1) - (CP)->tx_head : \
+ (CP)->tx_tail - (CP)->tx_head - 1)
+#define CP_CHIP_VERSION 0x76
+
+#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
+#define RX_OFFSET 2
+
+/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */
+#define RX_FIFO_THRESH 5 /* Rx buffer level before first PCI xfer. */
+#define RX_DMA_BURST 4 /* Maximum PCI burst, '4' is 256 */
+#define TX_DMA_BURST 6 /* Maximum PCI burst, '6' is 1024 */
+#define TX_EARLY_THRESH 256 /* Early Tx threshold, in bytes */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (6*HZ)
+
+
+enum {
+ /* NIC register offsets */
+ MAC0 = 0x00, /* Ethernet hardware address. */
+ MAR0 = 0x08, /* Multicast filter. */
+ TxRingAddr = 0x20, /* 64-bit start addr of Tx ring */
+ HiTxRingAddr = 0x28, /* 64-bit start addr of high priority Tx ring */
+ Cmd = 0x37, /* Command register */
+ IntrMask = 0x3C, /* Interrupt mask */
+ IntrStatus = 0x3E, /* Interrupt status */
+ TxConfig = 0x40, /* Tx configuration */
+ ChipVersion = 0x43, /* 8-bit chip version, inside TxConfig */
+ RxConfig = 0x44, /* Rx configuration */
+ Cfg9346 = 0x50, /* EEPROM select/control; Cfg reg [un]lock */
+ Config1 = 0x52, /* Config1 */
+ Config3 = 0x59, /* Config3 */
+ Config4 = 0x5A, /* Config4 */
+ MultiIntr = 0x5C, /* Multiple interrupt select */
+ Config5 = 0xD8, /* Config5 */
+ TxPoll = 0xD9, /* Tell chip to check Tx descriptors for work */
+ CpCmd = 0xE0, /* C+ Command register (C+ mode only) */
+ RxRingAddr = 0xE4, /* 64-bit start addr of Rx ring */
+ TxThresh = 0xEC, /* Early Tx threshold */
+ OldRxBufAddr = 0x30, /* DMA address of Rx ring buffer (C mode) */
+ OldTSD0 = 0x10, /* DMA address of first Tx desc (C mode) */
+
+ /* Tx and Rx status descriptors */
+ DescOwn = (1 << 31), /* Descriptor is owned by NIC */
+ RingEnd = (1 << 30), /* End of descriptor ring */
+ FirstFrag = (1 << 29), /* First segment of a packet */
+ LastFrag = (1 << 28), /* Final segment of a packet */
+ TxError = (1 << 23), /* Tx error summary */
+ RxError = (1 << 20), /* Rx error summary */
+ IPCS = (1 << 18), /* Calculate IP checksum */
+ UDPCS = (1 << 17), /* Calculate UDP/IP checksum */
+ TCPCS = (1 << 16), /* Calculate TCP/IP checksum */
+ IPFail = (1 << 15), /* IP checksum failed */
+ UDPFail = (1 << 14), /* UDP/IP checksum failed */
+ TCPFail = (1 << 13), /* TCP/IP checksum failed */
+ NormalTxPoll = (1 << 6), /* One or more normal Tx packets to send */
+ PID1 = (1 << 17), /* 2 protocol id bits: 0==non-IP, */
+ PID0 = (1 << 16), /* 1==UDP/IP, 2==TCP/IP, 3==IP */
+ TxFIFOUnder = (1 << 25), /* Tx FIFO underrun */
+ TxOWC = (1 << 22), /* Tx Out-of-window collision */
+ TxLinkFail = (1 << 21), /* Link failed during Tx of packet */
+ TxMaxCol = (1 << 20), /* Tx aborted due to excessive collisions */
+ TxColCntShift = 16, /* Shift, to get 4-bit Tx collision cnt */
+ TxColCntMask = 0x01 | 0x02 | 0x04 | 0x08, /* 4-bit collision count */
+ RxErrFrame = (1 << 27), /* Rx frame alignment error */
+ RxMcast = (1 << 26), /* Rx multicast packet rcv'd */
+ RxErrCRC = (1 << 18), /* Rx CRC error */
+ RxErrRunt = (1 << 19), /* Rx error, packet < 64 bytes */
+ RxErrLong = (1 << 21), /* Rx error, packet > 4096 bytes */
+ RxErrFIFO = (1 << 22), /* Rx error, FIFO overflowed, pkt bad */
+
+ /* RxConfig register */
+ RxCfgFIFOShift = 13, /* Shift, to get Rx FIFO thresh value */
+ RxCfgDMAShift = 8, /* Shift, to get Rx Max DMA value */
+ AcceptErr = 0x20, /* Accept packets with CRC errors */
+ AcceptRunt = 0x10, /* Accept runt (<64 bytes) packets */
+ AcceptBroadcast = 0x08, /* Accept broadcast packets */
+ AcceptMulticast = 0x04, /* Accept multicast packets */
+ AcceptMyPhys = 0x02, /* Accept pkts with our MAC as dest */
+ AcceptAllPhys = 0x01, /* Accept all pkts w/ physical dest */
+
+ /* IntrMask / IntrStatus registers */
+ PciErr = (1 << 15), /* System error on the PCI bus */
+ TimerIntr = (1 << 14), /* Asserted when TCTR reaches TimerInt value */
+ LenChg = (1 << 13), /* Cable length change */
+ SWInt = (1 << 8), /* Software-requested interrupt */
+ TxEmpty = (1 << 7), /* No Tx descriptors available */
+ RxFIFOOvr = (1 << 6), /* Rx FIFO Overflow */
+ LinkChg = (1 << 5), /* Packet underrun, or link change */
+ RxEmpty = (1 << 4), /* No Rx descriptors available */
+ TxErr = (1 << 3), /* Tx error */
+ TxOK = (1 << 2), /* Tx packet sent */
+ RxErr = (1 << 1), /* Rx error */
+ RxOK = (1 << 0), /* Rx packet received */
+ IntrResvd = (1 << 10), /* reserved, according to RealTek engineers,
+ but hardware likes to raise it */
+
+ IntrAll = PciErr | TimerIntr | LenChg | SWInt | TxEmpty |
+ RxFIFOOvr | LinkChg | RxEmpty | TxErr | TxOK |
+ RxErr | RxOK | IntrResvd,
+
+ /* C mode command register */
+ CmdReset = (1 << 4), /* Enable to reset; self-clearing */
+ RxOn = (1 << 3), /* Rx mode enable */
+ TxOn = (1 << 2), /* Tx mode enable */
+
+ /* C+ mode command register */
+ RxChkSum = (1 << 5), /* Rx checksum offload enable */
+ PCIMulRW = (1 << 3), /* Enable PCI read/write multiple */
+ CpRxOn = (1 << 1), /* Rx mode enable */
+ CpTxOn = (1 << 0), /* Tx mode enable */
+
+ /* Cfg9436 EEPROM control register */
+ Cfg9346_Lock = 0x00, /* Lock ConfigX/MII register access */
+ Cfg9346_Unlock = 0xC0, /* Unlock ConfigX/MII register access */
+
+ /* TxConfig register */
+ IFG = (1 << 25) | (1 << 24), /* standard IEEE interframe gap */
+ TxDMAShift = 8, /* DMA burst value (0-7) is shift this many bits */
+
+ /* Early Tx Threshold register */
+ TxThreshMask = 0x3f, /* Mask bits 5-0 */
+ TxThreshMax = 2048, /* Max early Tx threshold */
+
+ /* Config1 register */
+ DriverLoaded = (1 << 5), /* Software marker, driver is loaded */
+ PMEnable = (1 << 0), /* Enable various PM features of chip */
+
+ /* Config3 register */
+ PARMEnable = (1 << 6), /* Enable auto-loading of PHY parms */
+
+ /* Config5 register */
+ PMEStatus = (1 << 0), /* PME status can be reset by PCI RST# */
+};
+
+static const unsigned int cp_intr_mask =
+ PciErr | LinkChg |
+ RxOK | RxErr | RxEmpty | RxFIFOOvr |
+ TxOK | TxErr | TxEmpty;
+
+static const unsigned int cp_rx_config =
+ (RX_FIFO_THRESH << RxCfgFIFOShift) |
+ (RX_DMA_BURST << RxCfgDMAShift);
+
+struct cp_desc {
+ u32 opts1;
+ u32 opts2;
+ u32 addr_lo;
+ u32 addr_hi;
+};
+
+struct ring_info {
+ struct sk_buff *skb;
+ dma_addr_t mapping;
+ unsigned frag;
+};
+
+struct cp_extra_stats {
+ unsigned long rx_frags;
+};
+
+struct cp_private {
+ unsigned tx_head;
+ unsigned tx_tail;
+ unsigned rx_tail;
+
+ void *regs;
+ struct net_device *dev;
+ spinlock_t lock;
+
+ struct cp_desc *rx_ring;
+ struct cp_desc *tx_ring;
+ struct ring_info tx_skb[CP_TX_RING_SIZE];
+ struct ring_info rx_skb[CP_RX_RING_SIZE];
+ unsigned rx_buf_sz;
+ dma_addr_t ring_dma;
+
+ u32 msg_enable;
+
+ struct net_device_stats net_stats;
+ struct cp_extra_stats cp_stats;
+
+ struct pci_dev *pdev;
+ u32 rx_config;
+
+ struct sk_buff *frag_skb;
+ unsigned dropping_frag : 1;
+};
+
+#define cpr8(reg) readb(cp->regs + (reg))
+#define cpr16(reg) readw(cp->regs + (reg))
+#define cpr32(reg) readl(cp->regs + (reg))
+#define cpw8(reg,val) writeb((val), cp->regs + (reg))
+#define cpw16(reg,val) writew((val), cp->regs + (reg))
+#define cpw32(reg,val) writel((val), cp->regs + (reg))
+#define cpw8_f(reg,val) do { \
+ writeb((val), cp->regs + (reg)); \
+ readb(cp->regs + (reg)); \
+ } while (0)
+#define cpw16_f(reg,val) do { \
+ writew((val), cp->regs + (reg)); \
+ readw(cp->regs + (reg)); \
+ } while (0)
+#define cpw32_f(reg,val) do { \
+ writel((val), cp->regs + (reg)); \
+ readl(cp->regs + (reg)); \
+ } while (0)
+
+
+static void __cp_set_rx_mode (struct net_device *dev);
+static void cp_tx (struct cp_private *cp);
+static void cp_clean_rings (struct cp_private *cp);
+
+
+static struct pci_device_id cp_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_REALTEK, PCI_DEVICE_ID_REALTEK_8139,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(pci, cp_pci_tbl);
+
+static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb)
+{
+ skb->protocol = eth_type_trans (skb, cp->dev);
+
+ cp->net_stats.rx_packets++;
+ cp->net_stats.rx_bytes += skb->len;
+ cp->dev->last_rx = jiffies;
+ netif_rx (skb);
+}
+
+static inline void cp_rx_err_acct (struct cp_private *cp, unsigned rx_tail,
+ u32 status, u32 len)
+{
+ if (netif_msg_rx_err (cp))
+ printk (KERN_DEBUG
+ "%s: rx err, slot %d status 0x%x len %d\n",
+ cp->dev->name, rx_tail, status, len);
+ cp->net_stats.rx_errors++;
+ if (status & RxErrFrame)
+ cp->net_stats.rx_frame_errors++;
+ if (status & RxErrCRC)
+ cp->net_stats.rx_crc_errors++;
+ if (status & RxErrRunt)
+ cp->net_stats.rx_length_errors++;
+ if (status & RxErrLong)
+ cp->net_stats.rx_length_errors++;
+ if (status & RxErrFIFO)
+ cp->net_stats.rx_fifo_errors++;
+}
+
+static void cp_rx_frag (struct cp_private *cp, unsigned rx_tail,
+ struct sk_buff *skb, u32 status, u32 len)
+{
+ struct sk_buff *copy_skb, *frag_skb = cp->frag_skb;
+ unsigned orig_len = frag_skb ? frag_skb->len : 0;
+ unsigned target_len = orig_len + len;
+ unsigned first_frag = status & FirstFrag;
+ unsigned last_frag = status & LastFrag;
+
+ if (netif_msg_rx_status (cp))
+ printk (KERN_DEBUG "%s: rx %s%sfrag, slot %d status 0x%x len %d\n",
+ cp->dev->name,
+ cp->dropping_frag ? "dropping " : "",
+ first_frag ? "first " :
+ last_frag ? "last " : "",
+ rx_tail, status, len);
+
+ cp->cp_stats.rx_frags++;
+
+ if (!frag_skb && !first_frag)
+ cp->dropping_frag = 1;
+ if (cp->dropping_frag)
+ goto drop_frag;
+
+ copy_skb = dev_alloc_skb (target_len + RX_OFFSET);
+ if (!copy_skb) {
+ printk(KERN_WARNING "%s: rx slot %d alloc failed\n",
+ cp->dev->name, rx_tail);
+
+ cp->dropping_frag = 1;
+drop_frag:
+ if (frag_skb) {
+ dev_kfree_skb_irq(frag_skb);
+ cp->frag_skb = NULL;
+ }
+ if (last_frag) {
+ cp->net_stats.rx_dropped++;
+ cp->dropping_frag = 0;
+ }
+ return;
+ }
+
+ copy_skb->dev = cp->dev;
+ skb_reserve(copy_skb, RX_OFFSET);
+ skb_put(copy_skb, target_len);
+ if (frag_skb) {
+ memcpy(copy_skb->data, frag_skb->data, orig_len);
+ dev_kfree_skb_irq(frag_skb);
+ }
+ pci_dma_sync_single(cp->pdev, cp->rx_skb[rx_tail].mapping,
+ len, PCI_DMA_FROMDEVICE);
+ memcpy(copy_skb->data + orig_len, skb->data, len);
+
+ copy_skb->ip_summed = CHECKSUM_NONE;
+
+ if (last_frag) {
+ if (status & (RxError | RxErrFIFO)) {
+ cp_rx_err_acct(cp, rx_tail, status, len);
+ dev_kfree_skb_irq(copy_skb);
+ } else
+ cp_rx_skb(cp, copy_skb);
+ cp->frag_skb = NULL;
+ } else {
+ cp->frag_skb = copy_skb;
+ }
+}
+
+static void cp_rx (struct cp_private *cp)
+{
+ unsigned rx_tail = cp->rx_tail;
+ unsigned rx_work = 100;
+
+ while (rx_work--) {
+ u32 status, len;
+ dma_addr_t mapping;
+ struct sk_buff *skb, *copy_skb;
+ unsigned copying_skb, buflen;
+
+ skb = cp->rx_skb[rx_tail].skb;
+ if (!skb)
+ BUG();
+ rmb();
+ status = le32_to_cpu(cp->rx_ring[rx_tail].opts1);
+ if (status & DescOwn)
+ break;
+
+ len = (status & 0x1fff) - 4;
+ mapping = cp->rx_skb[rx_tail].mapping;
+
+ if ((status & (FirstFrag | LastFrag)) != (FirstFrag | LastFrag)) {
+ cp_rx_frag(cp, rx_tail, skb, status, len);
+ goto rx_next;
+ }
+
+ if (status & (RxError | RxErrFIFO)) {
+ cp_rx_err_acct(cp, rx_tail, status, len);
+ goto rx_next;
+ }
+
+ copying_skb = (len <= rx_copybreak);
+
+ if (netif_msg_rx_status(cp))
+ printk(KERN_DEBUG "%s: rx slot %d status 0x%x len %d copying? %d\n",
+ cp->dev->name, rx_tail, status, len,
+ copying_skb);
+
+ buflen = copying_skb ? len : cp->rx_buf_sz;
+ copy_skb = dev_alloc_skb (buflen + RX_OFFSET);
+ if (!copy_skb) {
+ cp->net_stats.rx_dropped++;
+ goto rx_next;
+ }
+
+ skb_reserve(copy_skb, RX_OFFSET);
+ copy_skb->dev = cp->dev;
+
+ if (!copying_skb) {
+ pci_unmap_single(cp->pdev, mapping,
+ buflen, PCI_DMA_FROMDEVICE);
+ skb->ip_summed = CHECKSUM_NONE;
+ skb_trim(skb, len);
+
+ mapping =
+ cp->rx_skb[rx_tail].mapping =
+ pci_map_single(cp->pdev, copy_skb->data,
+ buflen, PCI_DMA_FROMDEVICE);
+ cp->rx_skb[rx_tail].skb = copy_skb;
+ skb_put(copy_skb, buflen);
+ } else {
+ skb_put(copy_skb, len);
+ pci_dma_sync_single(cp->pdev, mapping, len, PCI_DMA_FROMDEVICE);
+ memcpy(copy_skb->data, skb->data, len);
+
+ /* We'll reuse the original ring buffer. */
+ skb = copy_skb;
+ }
+
+ cp_rx_skb(cp, skb);
+
+rx_next:
+ if (rx_tail == (CP_RX_RING_SIZE - 1))
+ cp->rx_ring[rx_tail].opts1 =
+ cpu_to_le32(DescOwn | RingEnd | cp->rx_buf_sz);
+ else
+ cp->rx_ring[rx_tail].opts1 =
+ cpu_to_le32(DescOwn | cp->rx_buf_sz);
+ cp->rx_ring[rx_tail].opts2 = 0;
+ cp->rx_ring[rx_tail].addr_lo = cpu_to_le32(mapping);
+ rx_tail = NEXT_RX(rx_tail);
+ }
+
+ if (!rx_work)
+ printk(KERN_WARNING "%s: rx work limit reached\n", cp->dev->name);
+
+ cp->rx_tail = rx_tail;
+}
+
+static void cp_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+ struct net_device *dev = dev_instance;
+ struct cp_private *cp = dev->priv;
+ u16 status;
+
+ status = cpr16(IntrStatus);
+ if (!status || (status == 0xFFFF))
+ return;
+
+ if (netif_msg_intr(cp))
+ printk(KERN_DEBUG "%s: intr, status %04x cmd %02x cpcmd %04x\n",
+ dev->name, status, cpr8(Cmd), cpr16(CpCmd));
+
+ spin_lock(&cp->lock);
+
+ if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr))
+ cp_rx(cp);
+ if (status & (TxOK | TxErr | TxEmpty | SWInt))
+ cp_tx(cp);
+
+ cpw16_f(IntrStatus, status);
+
+ if (status & PciErr) {
+ u16 pci_status;
+
+ pci_read_config_word(cp->pdev, PCI_STATUS, &pci_status);
+ pci_write_config_word(cp->pdev, PCI_STATUS, pci_status);
+ printk(KERN_ERR "%s: PCI bus error, status=%04x, PCI status=%04x\n",
+ dev->name, status, pci_status);
+ }
+
+ spin_unlock(&cp->lock);
+}
+
+static void cp_tx (struct cp_private *cp)
+{
+ unsigned tx_head = cp->tx_head;
+ unsigned tx_tail = cp->tx_tail;
+
+ while (tx_tail != tx_head) {
+ struct sk_buff *skb;
+ u32 status;
+
+ rmb();
+ status = le32_to_cpu(cp->tx_ring[tx_tail].opts1);
+ if (status & DescOwn)
+ break;
+
+ skb = cp->tx_skb[tx_tail].skb;
+ if (!skb)
+ BUG();
+
+ pci_unmap_single(cp->pdev, cp->tx_skb[tx_tail].mapping,
+ skb->len, PCI_DMA_TODEVICE);
+
+ if (status & LastFrag) {
+ if (status & (TxError | TxFIFOUnder)) {
+ if (netif_msg_tx_err(cp))
+ printk(KERN_DEBUG "%s: tx err, status 0x%x\n",
+ cp->dev->name, status);
+ cp->net_stats.tx_errors++;
+ if (status & TxOWC)
+ cp->net_stats.tx_window_errors++;
+ if (status & TxMaxCol)
+ cp->net_stats.tx_aborted_errors++;
+ if (status & TxLinkFail)
+ cp->net_stats.tx_carrier_errors++;
+ if (status & TxFIFOUnder)
+ cp->net_stats.tx_fifo_errors++;
+ } else {
+ cp->net_stats.collisions +=
+ ((status >> TxColCntShift) & TxColCntMask);
+ cp->net_stats.tx_packets++;
+ cp->net_stats.tx_bytes += skb->len;
+ if (netif_msg_tx_done(cp))
+ printk(KERN_DEBUG "%s: tx done, slot %d\n", cp->dev->name, tx_tail);
+ }
+ dev_kfree_skb_irq(skb);
+ }
+
+ cp->tx_skb[tx_tail].skb = NULL;
+
+ tx_tail = NEXT_TX(tx_tail);
+ }
+
+ cp->tx_tail = tx_tail;
+
+ if (netif_queue_stopped(cp->dev) && (TX_BUFFS_AVAIL(cp) > 1))
+ netif_wake_queue(cp->dev);
+}
+
+static int cp_start_xmit (struct sk_buff *skb, struct net_device *dev)
+{
+ struct cp_private *cp = dev->priv;
+ unsigned entry;
+ u32 eor;
+
+ spin_lock_irq(&cp->lock);
+
+ if (TX_BUFFS_AVAIL(cp) <= (skb_shinfo(skb)->nr_frags + 1)) {
+ netif_stop_queue(dev);
+ spin_unlock_irq(&cp->lock);
+ return 1;
+ }
+
+ entry = cp->tx_head;
+ eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
+ if (skb_shinfo(skb)->nr_frags == 0) {
+ struct cp_desc *txd = &cp->tx_ring[entry];
+ u32 mapping, len;
+
+ len = skb->len;
+ mapping = pci_map_single(cp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+ eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
+#ifdef CP_TX_CHECKSUM
+ txd->opts1 = cpu_to_le32(eor | len | DescOwn | FirstFrag |
+ LastFrag | IPCS | UDPCS | TCPCS);
+#else
+ txd->opts1 = cpu_to_le32(eor | len | DescOwn | FirstFrag |
+ LastFrag);
+#endif
+ txd->opts2 = 0;
+ txd->addr_lo = cpu_to_le32(mapping);
+
+ cp->tx_skb[entry].skb = skb;
+ cp->tx_skb[entry].mapping = mapping;
+ cp->tx_skb[entry].frag = 0;
+ wmb();
+ entry = NEXT_TX(entry);
+ } else {
+ struct cp_desc *txd;
+ u32 first_len, first_mapping;
+ int frag, first_entry = entry;
+
+ /* We must give this initial chunk to the device last.
+ * Otherwise we could race with the device.
+ */
+ first_len = skb->len - skb->data_len;
+ first_mapping = pci_map_single(cp->pdev, skb->data,
+ first_len, PCI_DMA_TODEVICE);
+ cp->tx_skb[entry].skb = skb;
+ cp->tx_skb[entry].mapping = first_mapping;
+ cp->tx_skb[entry].frag = 1;
+ entry = NEXT_TX(entry);
+
+ for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
+ skb_frag_t *this_frag = &skb_shinfo(skb)->frags[frag];
+ u32 len, mapping;
+ u32 ctrl;
+
+ len = this_frag->size;
+ mapping = pci_map_single(cp->pdev,
+ ((void *) page_address(this_frag->page) +
+ this_frag->page_offset),
+ len, PCI_DMA_TODEVICE);
+ eor = (entry == (CP_TX_RING_SIZE - 1)) ? RingEnd : 0;
+#ifdef CP_TX_CHECKSUM
+ ctrl = eor | len | DescOwn | IPCS | UDPCS | TCPCS;
+#else
+ ctrl = eor | len | DescOwn;
+#endif
+ if (frag == skb_shinfo(skb)->nr_frags - 1)
+ ctrl |= LastFrag;
+
+ txd = &cp->tx_ring[entry];
+ txd->opts1 = cpu_to_le32(ctrl);
+ txd->opts2 = 0;
+ txd->addr_lo = cpu_to_le32(mapping);
+
+ cp->tx_skb[entry].skb = skb;
+ cp->tx_skb[entry].mapping = mapping;
+ cp->tx_skb[entry].frag = frag + 2;
+ wmb();
+ entry = NEXT_TX(entry);
+ }
+ txd = &cp->tx_ring[first_entry];
+#ifdef CP_TX_CHECKSUM
+ txd->opts1 = cpu_to_le32(first_len | FirstFrag | DescOwn | IPCS | UDPCS | TCPCS);
+#else
+ txd->opts1 = cpu_to_le32(first_len | FirstFrag | DescOwn);
+#endif
+ txd->opts2 = 0;
+ txd->addr_lo = cpu_to_le32(first_mapping);
+ wmb();
+ }
+ cp->tx_head = entry;
+ if (netif_msg_tx_queued(cp))
+ printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n",
+ dev->name, entry, skb->len);
+ if (TX_BUFFS_AVAIL(cp) < 0)
+ BUG();
+ if (TX_BUFFS_AVAIL(cp) == 0)
+ netif_stop_queue(dev);
+
+ spin_unlock_irq(&cp->lock);
+
+ cpw8(TxPoll, NormalTxPoll);
+ dev->trans_start = jiffies;
+
+ return 0;
+}
+
+/* Set or clear the multicast filter for this adaptor.
+ This routine is not state sensitive and need not be SMP locked. */
+
+static unsigned const ethernet_polynomial = 0x04c11db7U;
+static inline u32 ether_crc (int length, unsigned char *data)
+{
+ int crc = -1;
+
+ while (--length >= 0) {
+ unsigned char current_octet = *data++;
+ int bit;
+ for (bit = 0; bit < 8; bit++, current_octet >>= 1)
+ crc = (crc << 1) ^ ((crc < 0) ^ (current_octet & 1) ?
+ ethernet_polynomial : 0);
+ }
+
+ return crc;
+}
+
+static void __cp_set_rx_mode (struct net_device *dev)
+{
+ struct cp_private *cp = dev->priv;
+ u32 mc_filter[2]; /* Multicast hash filter */
+ int i, rx_mode;
+ u32 tmp;
+
+ /* Note: do not reorder, GCC is clever about common statements. */
+ if (dev->flags & IFF_PROMISC) {
+ /* Unconditionally log net taps. */
+ printk (KERN_NOTICE "%s: Promiscuous mode enabled.\n",
+ dev->name);
+ rx_mode =
+ AcceptBroadcast | AcceptMulticast | AcceptMyPhys |
+ AcceptAllPhys;
+ mc_filter[1] = mc_filter[0] = 0xffffffff;
+ } else if ((dev->mc_count > multicast_filter_limit)
+ || (dev->flags & IFF_ALLMULTI)) {
+ /* Too many to filter perfectly -- accept all multicasts. */
+ rx_mode = AcceptBroadcast | AcceptMulticast | AcceptMyPhys;
+ mc_filter[1] = mc_filter[0] = 0xffffffff;
+ } else {
+ struct dev_mc_list *mclist;
+ rx_mode = AcceptBroadcast | AcceptMyPhys;
+ mc_filter[1] = mc_filter[0] = 0;
+ for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+ i++, mclist = mclist->next) {
+ int bit_nr = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
+
+ mc_filter[bit_nr >> 5] |= cpu_to_le32(1 << (bit_nr & 31));
+ rx_mode |= AcceptMulticast;
+ }
+ }
+
+ /* We can safely update without stopping the chip. */
+ tmp = cp_rx_config | rx_mode;
+ if (cp->rx_config != tmp) {
+ cpw32_f (RxConfig, tmp);
+ cp->rx_config = tmp;
+ }
+ cpw32_f (MAR0 + 0, mc_filter[0]);
+ cpw32_f (MAR0 + 4, mc_filter[1]);
+}
+
+static void cp_set_rx_mode (struct net_device *dev)
+{
+ unsigned long flags;
+ struct cp_private *cp = dev->priv;
+
+ spin_lock_irqsave (&cp->lock, flags);
+ __cp_set_rx_mode(dev);
+ spin_unlock_irqrestore (&cp->lock, flags);
+}
+
+static void __cp_get_stats(struct cp_private *cp)
+{
+ /* XXX implement */
+}
+
+static struct net_device_stats *cp_get_stats(struct net_device *dev)
+{
+ struct cp_private *cp = dev->priv;
+
+ /* The chip only need report frame silently dropped. */
+ spin_lock_irq(&cp->lock);
+ if (netif_running(dev) && netif_device_present(dev))
+ __cp_get_stats(cp);
+ spin_unlock_irq(&cp->lock);
+
+ return &cp->net_stats;
+}
+
+static void cp_stop_hw (struct cp_private *cp)
+{
+ cpw16(IntrMask, 0);
+ cpr16(IntrMask);
+ cpw8(Cmd, 0);
+ cpw16(CpCmd, 0);
+ cpr16(CpCmd);
+ cpw16(IntrStatus, ~(cpr16(IntrStatus)));
+ synchronize_irq();
+ udelay(10);
+
+ cp->rx_tail = 0;
+ cp->tx_head = cp->tx_tail = 0;
+}
+
+static void cp_reset_hw (struct cp_private *cp)
+{
+ unsigned work = 1000;
+
+ cpw8(Cmd, CmdReset);
+
+ while (work--) {
+ if (!(cpr8(Cmd) & CmdReset))
+ return;
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(10);
+ }
+
+ printk(KERN_ERR "%s: hardware reset timeout\n", cp->dev->name);
+}
+
+static void cp_init_hw (struct cp_private *cp)
+{
+ struct net_device *dev = cp->dev;
+
+ cp_reset_hw(cp);
+
+ cpw8_f (Cfg9346, Cfg9346_Unlock);
+
+ /* Restore our idea of the MAC address. */
+ cpw32_f (MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
+ cpw32_f (MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
+
+ cpw8(Cmd, RxOn | TxOn);
+ cpw16(CpCmd, PCIMulRW | CpRxOn | CpTxOn);
+ cpw8(TxThresh, 0x06); /* XXX convert magic num to a constant */
+
+ __cp_set_rx_mode(dev);
+ cpw32_f (TxConfig, IFG | (TX_DMA_BURST << TxDMAShift));
+
+ cpw8(Config1, cpr8(Config1) | DriverLoaded | PMEnable);
+ cpw8(Config3, PARMEnable); /* disables magic packet and WOL */
+ cpw8(Config5, cpr8(Config5) & PMEStatus); /* disables more WOL stuff */
+
+ cpw32_f(HiTxRingAddr, 0);
+ cpw32_f(HiTxRingAddr + 4, 0);
+ cpw32_f(OldRxBufAddr, 0);
+ cpw32_f(OldTSD0, 0);
+ cpw32_f(OldTSD0 + 4, 0);
+ cpw32_f(OldTSD0 + 8, 0);
+ cpw32_f(OldTSD0 + 12, 0);
+
+ cpw32_f(RxRingAddr, cp->ring_dma);
+ cpw32_f(RxRingAddr + 4, 0);
+ cpw32_f(TxRingAddr, cp->ring_dma + (sizeof(struct cp_desc) * CP_RX_RING_SIZE));
+ cpw32_f(TxRingAddr + 4, 0);
+
+ cpw16(MultiIntr, 0);
+
+ cpw16(IntrMask, cp_intr_mask);
+
+ cpw8_f (Cfg9346, Cfg9346_Lock);
+}
+
+static int cp_refill_rx (struct cp_private *cp)
+{
+ unsigned i;
+
+ for (i = 0; i < CP_RX_RING_SIZE; i++) {
+ struct sk_buff *skb;
+
+ skb = dev_alloc_skb(cp->rx_buf_sz + RX_OFFSET);
+ if (!skb)
+ goto err_out;
+
+ skb->dev = cp->dev;
+ skb_reserve(skb, RX_OFFSET);
+ skb_put(skb, cp->rx_buf_sz);
+
+ cp->rx_skb[i].mapping = pci_map_single(cp->pdev,
+ skb->data, cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ cp->rx_skb[i].skb = skb;
+ cp->rx_skb[i].frag = 0;
+
+ if (i == (CP_RX_RING_SIZE - 1))
+ cp->rx_ring[i].opts1 =
+ cpu_to_le32(DescOwn | RingEnd | cp->rx_buf_sz);
+ else
+ cp->rx_ring[i].opts1 =
+ cpu_to_le32(DescOwn | cp->rx_buf_sz);
+ cp->rx_ring[i].opts2 = 0;
+ cp->rx_ring[i].addr_lo = cpu_to_le32(cp->rx_skb[i].mapping);
+ cp->rx_ring[i].addr_hi = 0;
+ }
+
+ return 0;
+
+err_out:
+ cp_clean_rings(cp);
+ return -ENOMEM;
+}
+
+static int cp_init_rings (struct cp_private *cp)
+{
+ memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
+ cp->tx_ring[CP_TX_RING_SIZE - 1].opts1 = cpu_to_le32(RingEnd);
+
+ cp->rx_tail = 0;
+ cp->tx_head = cp->tx_tail = 0;
+
+ return cp_refill_rx (cp);
+}
+
+static int cp_alloc_rings (struct cp_private *cp)
+{
+ cp->rx_ring = pci_alloc_consistent(cp->pdev, CP_RING_BYTES, &cp->ring_dma);
+ if (!cp->rx_ring)
+ return -ENOMEM;
+ cp->tx_ring = &cp->rx_ring[CP_RX_RING_SIZE];
+ return cp_init_rings(cp);
+}
+
+static void cp_clean_rings (struct cp_private *cp)
+{
+ unsigned i;
+
+ memset(cp->rx_ring, 0, sizeof(struct cp_desc) * CP_RX_RING_SIZE);
+ memset(cp->tx_ring, 0, sizeof(struct cp_desc) * CP_TX_RING_SIZE);
+
+ for (i = 0; i < CP_RX_RING_SIZE; i++) {
+ if (cp->rx_skb[i].skb) {
+ pci_unmap_single(cp->pdev, cp->rx_skb[i].mapping,
+ cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(cp->rx_skb[i].skb);
+ }
+ }
+
+ for (i = 0; i < CP_TX_RING_SIZE; i++) {
+ if (cp->tx_skb[i].skb) {
+ struct sk_buff *skb = cp->tx_skb[i].skb;
+ pci_unmap_single(cp->pdev, cp->tx_skb[i].mapping,
+ skb->len, PCI_DMA_TODEVICE);
+ dev_kfree_skb(skb);
+ cp->net_stats.tx_dropped++;
+ }
+ }
+
+ memset(&cp->rx_skb, 0, sizeof(struct ring_info) * CP_RX_RING_SIZE);
+ memset(&cp->tx_skb, 0, sizeof(struct ring_info) * CP_TX_RING_SIZE);
+}
+
+static void cp_free_rings (struct cp_private *cp)
+{
+ cp_clean_rings(cp);
+ pci_free_consistent(cp->pdev, CP_RING_BYTES, cp->rx_ring, cp->ring_dma);
+ cp->rx_ring = NULL;
+ cp->tx_ring = NULL;
+}
+
+static int cp_open (struct net_device *dev)
+{
+ struct cp_private *cp = dev->priv;
+ int rc;
+
+ if (netif_msg_ifup(cp))
+ printk(KERN_DEBUG "%s: enabling interface\n", dev->name);
+
+ cp->rx_buf_sz = (dev->mtu <= 1500 ? PKT_BUF_SZ : dev->mtu + 32);
+
+ rc = cp_alloc_rings(cp);
+ if (rc)
+ return rc;
+
+ cp_init_hw(cp);
+
+ rc = request_irq(dev->irq, cp_interrupt, SA_SHIRQ, dev->name, dev);
+ if (rc)
+ goto err_out_hw;
+
+ netif_start_queue(dev);
+
+ return 0;
+
+err_out_hw:
+ cp_stop_hw(cp);
+ cp_free_rings(cp);
+ return rc;
+}
+
+static int cp_close (struct net_device *dev)
+{
+ struct cp_private *cp = dev->priv;
+
+ if (netif_msg_ifdown(cp))
+ printk(KERN_DEBUG "%s: disabling interface\n", dev->name);
+
+ netif_stop_queue(dev);
+ cp_stop_hw(cp);
+ free_irq(dev->irq, dev);
+ cp_free_rings(cp);
+ return 0;
+}
+
+static int cp_ethtool_ioctl (struct cp_private *cp, void *useraddr)
+{
+ u32 ethcmd;
+
+ /* dev_ioctl() in ../../net/core/dev.c has already checked
+ capable(CAP_NET_ADMIN), so don't bother with that here. */
+
+ if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
+ return -EFAULT;
+
+ switch (ethcmd) {
+
+ case ETHTOOL_GDRVINFO:
+ {
+ struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+ strcpy (info.driver, DRV_NAME);
+ strcpy (info.version, DRV_VERSION);
+ strcpy (info.bus_info, cp->pdev->slot_name);
+ if (copy_to_user (useraddr, &info, sizeof (info)))
+ return -EFAULT;
+ return 0;
+ }
+
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+
+static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+ struct cp_private *cp = dev->priv;
+ int rc = 0;
+
+ switch (cmd) {
+ case SIOCETHTOOL:
+ return cp_ethtool_ioctl(cp, (void *) rq->ifr_data);
+
+ default:
+ rc = -EOPNOTSUPP;
+ break;
+ }
+
+ return rc;
+}
+
+
+
+/* Serial EEPROM section. */
+
+/* EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */
+#define EE_CS 0x08 /* EEPROM chip select. */
+#define EE_DATA_WRITE 0x02 /* EEPROM chip data in. */
+#define EE_WRITE_0 0x00
+#define EE_WRITE_1 0x02
+#define EE_DATA_READ 0x01 /* EEPROM chip data out. */
+#define EE_ENB (0x80 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+ No extra delay is needed with 33Mhz PCI, but 66Mhz may change this.
+ */
+
+#define eeprom_delay() readl(ee_addr)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD (5)
+#define EE_READ_CMD (6)
+#define EE_ERASE_CMD (7)
+
+static int __devinit read_eeprom (void *ioaddr, int location, int addr_len)
+{
+ int i;
+ unsigned retval = 0;
+ void *ee_addr = ioaddr + Cfg9346;
+ int read_cmd = location | (EE_READ_CMD << addr_len);
+
+ writeb (EE_ENB & ~EE_CS, ee_addr);
+ writeb (EE_ENB, ee_addr);
+ eeprom_delay ();
+
+ /* Shift the read command bits out. */
+ for (i = 4 + addr_len; i >= 0; i--) {
+ int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+ writeb (EE_ENB | dataval, ee_addr);
+ eeprom_delay ();
+ writeb (EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay ();
+ }
+ writeb (EE_ENB, ee_addr);
+ eeprom_delay ();
+
+ for (i = 16; i > 0; i--) {
+ writeb (EE_ENB | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay ();
+ retval =
+ (retval << 1) | ((readb (ee_addr) & EE_DATA_READ) ? 1 :
+ 0);
+ writeb (EE_ENB, ee_addr);
+ eeprom_delay ();
+ }
+
+ /* Terminate the EEPROM access. */
+ writeb (~EE_CS, ee_addr);
+ eeprom_delay ();
+
+ return retval;
+}
+
+static int __devinit cp_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct net_device *dev;
+ struct cp_private *cp;
+ int rc;
+ void *regs;
+ long pciaddr;
+ unsigned addr_len, i;
+ u8 pci_rev, cache_size;
+ u16 pci_command;
+
+#ifndef MODULE
+ static int version_printed;
+ if (version_printed++ == 0)
+ printk("%s", version);
+#endif
+
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
+
+ if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
+ pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev < 0x20) {
+ printk(KERN_ERR PFX "pci dev %s (id %04x:%04x rev %02x) is not an 8139C+ compatible chip\n",
+ pdev->slot_name, pdev->vendor, pdev->device, pci_rev);
+ printk(KERN_ERR PFX "Try the \"8139too\" driver instead.\n");
+ return -ENODEV;
+ }
+
+ dev = alloc_etherdev(sizeof(struct cp_private));
+ if (!dev)
+ return -ENOMEM;
+ SET_MODULE_OWNER(dev);
+ cp = dev->priv;
+ cp->pdev = pdev;
+ cp->dev = dev;
+ cp->msg_enable = (debug < 0 ? CP_DEF_MSG_ENABLE : debug);
+ spin_lock_init (&cp->lock);
+
+ rc = pci_enable_device(pdev);
+ if (rc)
+ goto err_out_free;
+
+ rc = pci_request_regions(pdev, DRV_NAME);
+ if (rc)
+ goto err_out_disable;
+
+ if (pdev->irq < 2) {
+ rc = -EIO;
+ printk(KERN_ERR PFX "invalid irq (%d) for pci dev %s\n",
+ pdev->irq, pdev->slot_name);
+ goto err_out_res;
+ }
+ pciaddr = pci_resource_start(pdev, 1);
+ if (!pciaddr) {
+ rc = -EIO;
+ printk(KERN_ERR PFX "no MMIO resource for pci dev %s\n",
+ pdev->slot_name);
+ goto err_out_res;
+ }
+ if (pci_resource_len(pdev, 1) < CP_REGS_SIZE) {
+ rc = -EIO;
+ printk(KERN_ERR PFX "MMIO resource (%lx) too small on pci dev %s\n",
+ pci_resource_len(pdev, 1), pdev->slot_name);
+ goto err_out_res;
+ }
+
+ regs = ioremap_nocache(pciaddr, CP_REGS_SIZE);
+ if (!regs) {
+ rc = -EIO;
+ printk(KERN_ERR PFX "Cannot map PCI MMIO (%lx@%lx) on pci dev %s\n",
+ pci_resource_len(pdev, 1), pciaddr, pdev->slot_name);
+ goto err_out_res;
+ }
+ dev->base_addr = (unsigned long) regs;
+ cp->regs = regs;
+
+ cp_stop_hw(cp);
+
+ /* read MAC address from EEPROM */
+ addr_len = read_eeprom (regs, 0, 8) == 0x8129 ? 8 : 6;
+ for (i = 0; i < 3; i++)
+ ((u16 *) (dev->dev_addr))[i] =
+ le16_to_cpu (read_eeprom (regs, i + 7, addr_len));
+
+ dev->open = cp_open;
+ dev->stop = cp_close;
+ dev->set_multicast_list = cp_set_rx_mode;
+ dev->hard_start_xmit = cp_start_xmit;
+ dev->get_stats = cp_get_stats;
+ dev->do_ioctl = cp_ioctl;
+#if 0
+ dev->tx_timeout = cp_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+#endif
+#ifdef CP_TX_CHECKSUM
+ dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
+#endif
+
+ dev->irq = pdev->irq;
+
+ rc = register_netdev(dev);
+ if (rc)
+ goto err_out_iomap;
+
+ printk (KERN_INFO "%s: %s at 0x%lx, "
+ "%02x:%02x:%02x:%02x:%02x:%02x, "
+ "IRQ %d\n",
+ dev->name,
+ "RTL-8139C+",
+ dev->base_addr,
+ dev->dev_addr[0], dev->dev_addr[1],
+ dev->dev_addr[2], dev->dev_addr[3],
+ dev->dev_addr[4], dev->dev_addr[5],
+ dev->irq);
+
+ pci_set_drvdata(pdev, dev);
+
+ /*
+ * Looks like this is necessary to deal with on all architectures,
+ * even this %$#%$# N440BX Intel based thing doesn't get it right.
+ * Ie. having two NICs in the machine, one will have the cache
+ * line set at boot time, the other will not.
+ */
+ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_size);
+ cache_size <<= 2;
+ if (cache_size != SMP_CACHE_BYTES) {
+ printk(KERN_INFO "%s: PCI cache line size set incorrectly "
+ "(%i bytes) by BIOS/FW, ", dev->name, cache_size);
+ if (cache_size > SMP_CACHE_BYTES)
+ printk("expecting %i\n", SMP_CACHE_BYTES);
+ else {
+ printk("correcting to %i\n", SMP_CACHE_BYTES);
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+ SMP_CACHE_BYTES >> 2);
+ }
+ }
+
+ /* enable busmastering and memory-write-invalidate */
+ pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+ if (!(pci_command & PCI_COMMAND_INVALIDATE)) {
+ pci_command |= PCI_COMMAND_INVALIDATE;
+ pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+ }
+ pci_set_master(pdev);
+
+ return 0;
+
+err_out_iomap:
+ iounmap(regs);
+err_out_res:
+ pci_release_regions(pdev);
+err_out_disable:
+ pci_disable_device(pdev);
+err_out_free:
+ kfree(dev);
+ return rc;
+}
+
+static void __devexit cp_remove_one (struct pci_dev *pdev)
+{
+ struct net_device *dev = pci_get_drvdata(pdev);
+ struct cp_private *cp = dev->priv;
+
+ if (!dev)
+ BUG();
+ unregister_netdev(dev);
+ iounmap(cp->regs);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ kfree(dev);
+}
+
+static struct pci_driver cp_driver = {
+ name: DRV_NAME,
+ id_table: cp_pci_tbl,
+ probe: cp_init_one,
+ remove: cp_remove_one,
+};
+
+static int __init cp_init (void)
+{
+#ifdef MODULE
+ printk("%s", version);
+#endif
+ return pci_module_init (&cp_driver);
+}
+
+static void __exit cp_exit (void)
+{
+ pci_unregister_driver (&cp_driver);
+}
+
+module_init(cp_init);
+module_exit(cp_exit);
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 2a209ce694c7..9621524a3955 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -72,7 +72,7 @@
features of the 8139 chips
Jean-Jacques Michel - bug fix
-
+
Tobias Ringström - Rx interrupt status checking suggestion
Andrew Morton - Clear blocked signals, avoid
@@ -139,7 +139,7 @@ an MMIO register read.
*/
#define DRV_NAME "8139too"
-#define DRV_VERSION "0.9.19"
+#define DRV_VERSION "0.9.20"
#include <linux/config.h>
@@ -258,6 +258,7 @@ typedef enum {
DELTA8139,
ADDTRON8139,
DFE538TX,
+ DFE690TXD,
RTL8129,
} board_t;
@@ -274,6 +275,7 @@ static struct {
{ "Delta Electronics 8139 10/100BaseTX", RTL8139_CAPS },
{ "Addtron Technolgy 8139 10/100BaseTX", RTL8139_CAPS },
{ "D-Link DFE-538TX (RealTek RTL8139)", RTL8139_CAPS },
+ { "D-Link DFE-690TXD (RealTek RTL8139)", RTL8139_CAPS },
{ "RealTek RTL8129", RTL8129_CAPS },
};
@@ -286,6 +288,7 @@ static struct pci_device_id rtl8139_pci_tbl[] __devinitdata = {
{0x1500, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DELTA8139 },
{0x4033, 0x1360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ADDTRON8139 },
{0x1186, 0x1300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE538TX },
+ {0x1186, 0x1340, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DFE690TXD },
#ifdef CONFIG_8139TOO_8129
{0x10ec, 0x8129, PCI_ANY_ID, PCI_ANY_ID, 0, 0, RTL8129 },
@@ -942,6 +945,7 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
int i, addr_len, option;
void *ioaddr;
static int board_idx = -1;
+ u8 pci_rev;
DPRINTK ("ENTER\n");
@@ -961,6 +965,15 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev,
}
#endif
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &pci_rev);
+
+ if (pdev->vendor == PCI_VENDOR_ID_REALTEK &&
+ pdev->device == PCI_DEVICE_ID_REALTEK_8139 && pci_rev >= 0x20) {
+ printk(KERN_INFO PFX "pci dev %s (id %04x:%04x rev %02x) is an enhanced 8139C+ chip\n",
+ pdev->slot_name, pdev->vendor, pdev->device, pci_rev);
+ printk(KERN_INFO PFX "Use the \"8139cp\" driver for improved performance and stability.\n");
+ }
+
i = rtl8139_init_board (pdev, &dev);
if (i < 0) {
DPRINTK ("EXIT, returning %d\n", i);
@@ -1372,7 +1385,7 @@ static void rtl_check_media (struct net_device *dev)
struct rtl8139_private *tp = dev->priv;
DPRINTK("ENTER\n");
-
+
if (tp->phys[0] >= 0) {
u16 mii_reg5 = mdio_read(dev, tp->phys[0], 5);
if (mii_reg5 == 0xffff)
@@ -1421,7 +1434,7 @@ static void rtl8139_hw_start (struct net_device *dev)
RTL_W32 (TxConfig, (TX_DMA_BURST << TxDMAShift));
tp->cur_rx = 0;
-
+
rtl_check_media (dev);
if (tp->chipset >= CH_8139B) {
@@ -1879,7 +1892,7 @@ static void rtl8139_rx_err (u32 rx_status, struct net_device *dev,
{
u8 tmp8;
int tmp_work;
-
+
DPRINTK ("%s: Ethernet frame had errors, status %8.8x.\n",
dev->name, rx_status);
if (rx_status & RxTooLong) {
@@ -1967,7 +1980,7 @@ static void rtl8139_rx_interrupt (struct net_device *dev,
struct sk_buff *skb;
rmb();
-
+
/* read size+status of next frame from DMA ring buffer */
rx_status = le32_to_cpu (*(u32 *) (rx_ring + ring_offset));
rx_size = rx_status >> 16;
@@ -2376,7 +2389,7 @@ static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
}
/* TODO: ETHTOOL_SSET */
-
+
case ETHTOOL_GDRVINFO:
{
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
diff --git a/drivers/net/Config.in b/drivers/net/Config.in
index d13174813b4a..db488cecc753 100644
--- a/drivers/net/Config.in
+++ b/drivers/net/Config.in
@@ -176,6 +176,7 @@ if [ "$CONFIG_NET_ETHERNET" = "y" ]; then
dep_tristate ' PCI NE2000 and clones support (see help)' CONFIG_NE2K_PCI $CONFIG_PCI
dep_tristate ' Novell/Eagle/Microdyne NE3210 EISA support (EXPERIMENTAL)' CONFIG_NE3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
dep_tristate ' Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 $CONFIG_EISA $CONFIG_EXPERIMENTAL
+ dep_tristate ' RealTek RTL-8139 C+ PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_8139CP $CONFIG_PCI $CONFIG_EXPERIMENTAL
dep_tristate ' RealTek RTL-8139 PCI Fast Ethernet Adapter support' CONFIG_8139TOO $CONFIG_PCI
dep_mbool ' Use PIO instead of MMIO' CONFIG_8139TOO_PIO $CONFIG_8139TOO
dep_mbool ' Support for automatic channel equalization (EXPERIMENTAL)' CONFIG_8139TOO_TUNE_TWISTER $CONFIG_8139TOO $CONFIG_EXPERIMENTAL
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 803371cc4ddd..3282201f44ea 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -164,6 +164,7 @@ obj-$(CONFIG_EL3) += 3c509.o
obj-$(CONFIG_3C515) += 3c515.o
obj-$(CONFIG_EEXPRESS) += eexpress.o
obj-$(CONFIG_EEXPRESS_PRO) += eepro.o
+obj-$(CONFIG_8139CP) += 8139cp.o
obj-$(CONFIG_8139TOO) += 8139too.o
obj-$(CONFIG_WAVELAN) += wavelan.o
obj-$(CONFIG_ARLAN) += arlan.o arlan-proc.o
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 7718ed36875b..4ea8280d6d00 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -1153,3 +1153,4 @@ static void __exit myri_sbus_cleanup(void)
module_init(myri_sbus_probe);
module_exit(myri_sbus_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 2356639d600b..f2b17767ef8b 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -53,7 +53,13 @@ static unsigned int pcnet32_portlist[] __initdata = {0x300, 0x320, 0x340, 0x360,
static struct pci_device_id pcnet32_pci_tbl[] __devinitdata = {
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE_HOME, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+/* this id is never reached as the match above occurs first.
+ * However it clearly has significance, so let's not remove it
+ * until we know what that significance is. -jgarzik
+ */
+#if 0
{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0x1014, 0x2000, 0, 0, 0 },
+#endif
{ 0, }
};
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index 3b6cb52b9c07..c9559b0b3d99 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -1301,3 +1301,4 @@ static void __exit bigmac_cleanup(void)
module_init(bigmac_probe);
module_exit(bigmac_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index cf21b0181630..ab376ffedd70 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -25,10 +25,9 @@
/* The user-configurable values.
These may be modified when a driver module is loaded.*/
-
static int debug = 1; /* 1 normal messages, 0 quiet .. 7 verbose. */
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
+static int max_interrupt_work = 30;
static int mtu;
/* Maximum number of multicast addresses to filter (vs. rx-all-multicast).
Typical is a 64 element hash table based on the Ethernet CRC. */
@@ -40,15 +39,20 @@ static int multicast_filter_limit = 32;
need a copy-align. */
static int rx_copybreak;
-/* Used to pass the media type, etc.
- Both 'options[]' and 'full_duplex[]' should exist for driver
- interoperability.
- The media type is usually passed in 'options[]'.
+/* media[] specifies the media type the NIC operates at.
+ autosense Autosensing active media.
+ 10mbps_hd 10Mbps half duplex.
+ 10mbps_fd 10Mbps full duplex.
+ 100mbps_hd 100Mbps half duplex.
+ 100mbps_fd 100Mbps full duplex.
+ 0 Autosensing active media.
+ 1 10Mbps half duplex.
+ 2 10Mbps full duplex.
+ 3 100Mbps half duplex.
+ 4 100Mbps full duplex.
*/
-#define MAX_UNITS 8 /* More are supported, limit only on options */
-static int options[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
-
+#define MAX_UNITS 8
+static char *media[MAX_UNITS];
/* Operational parameters that are set at compile time. */
/* Keep the ring sizes a power of two for compile efficiency.
@@ -65,7 +69,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
/* Operational parameters that usually are not changed. */
/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (2*HZ)
+#define TX_TIMEOUT (4*HZ)
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer.*/
@@ -98,7 +102,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/bitops.h>
#include <asm/io.h>
-
+#include <linux/delay.h>
#include <linux/spinlock.h>
/* These identify the driver base version and may not be removed. */
@@ -114,15 +118,11 @@ MODULE_PARM(max_interrupt_work, "i");
MODULE_PARM(mtu, "i");
MODULE_PARM(debug, "i");
MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(media, "1-" __MODULE_STRING(MAX_UNITS) "s");
MODULE_PARM_DESC(max_interrupt_work, "Sundance Alta maximum events handled per interrupt");
MODULE_PARM_DESC(mtu, "Sundance Alta MTU (all boards)");
MODULE_PARM_DESC(debug, "Sundance Alta debug level (0-5)");
MODULE_PARM_DESC(rx_copybreak, "Sundance Alta copy breakpoint for copy-only-tiny-frames");
-MODULE_PARM_DESC(options, "Sundance Alta: Bits 0-3: media type, bit 17: full duplex");
-MODULE_PARM_DESC(full_duplex, "Sundance Alta full duplex setting(s) (1)");
-
/*
Theory of Operation
@@ -214,9 +214,12 @@ enum chip_capability_flags {CanHaveMII=1, };
#endif
static struct pci_device_id sundance_pci_tbl[] __devinitdata = {
- { 0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { 0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
- { 0, }
+ {0x1186, 0x1002, 0x1186, 0x1002, 0, 0, 0},
+ {0x1186, 0x1002, 0x1186, 0x1003, 0, 0, 1},
+ {0x1186, 0x1002, 0x1186, 0x1012, 0, 0, 2},
+ {0x1186, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+ {0x13F0, 0x0201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+ {0,}
};
MODULE_DEVICE_TABLE(pci, sundance_pci_tbl);
@@ -231,11 +234,19 @@ struct pci_id_info {
int drv_flags; /* Driver use, intended as capability flags. */
};
static struct pci_id_info pci_id_tbl[] = {
- {"OEM Sundance Technology ST201", {0x10021186, 0xffffffff, },
+ {"D-Link DFE-550TX FAST Ethernet Adapter", {0x10021186, 0xffffffff,},
PCI_IOTYPE, 128, CanHaveMII},
- {"Sundance Technology Alta", {0x020113F0, 0xffffffff, },
+ {"D-Link DFE-550FX 100Mbps Fiber-optics Adapter",
+ {0x10031186, 0xffffffff,},
PCI_IOTYPE, 128, CanHaveMII},
- {0,}, /* 0 terminated list. */
+ {"D-Link DFE-580TX 4 port Server Adapter", {0x10121186, 0xffffffff,},
+ PCI_IOTYPE, 128, CanHaveMII},
+ {"D-Link DL10050-based FAST Ethernet Adapter",
+ {0x10021186, 0xffffffff,},
+ PCI_IOTYPE, 128, CanHaveMII},
+ {"Sundance Technology Alta", {0x020113F0, 0xffffffff,},
+ PCI_IOTYPE, 128, CanHaveMII},
+ {0,}, /* 0 terminated list. */
};
/* This driver was written to use PCI memory space, however x86-oriented
@@ -384,9 +395,10 @@ struct netdev_private {
unsigned int tx_full:1; /* The Tx queue is full. */
/* These values are keep track of the transceiver/media in use. */
unsigned int full_duplex:1; /* Full-duplex operation requested. */
- unsigned int duplex_lock:1;
unsigned int medialock:1; /* Do not sense media. */
unsigned int default_port:4; /* Last dev->if_port value. */
+ unsigned int an_enable:1;
+ unsigned int speed;
/* Multicast and receive mode. */
spinlock_t mcastlock; /* SMP lock multicast updates. */
u16 mcast_filter[4];
@@ -428,8 +440,9 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
static int card_idx;
int chip_idx = ent->driver_data;
int irq;
- int i, option = card_idx < MAX_UNITS ? options[card_idx] : 0;
+ int i;
long ioaddr;
+ u16 mii_reg0;
void *ring_space;
dma_addr_t ring_dma;
@@ -489,23 +502,6 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
np->rx_ring = (struct netdev_desc *)ring_space;
np->rx_ring_dma = ring_dma;
- if (dev->mem_start)
- option = dev->mem_start;
-
- /* The lower four bits are the media type. */
- if (option > 0) {
- if (option & 0x200)
- np->full_duplex = 1;
- np->default_port = option & 15;
- if (np->default_port)
- np->medialock = 1;
- }
- if (card_idx < MAX_UNITS && full_duplex[card_idx] > 0)
- np->full_duplex = 1;
-
- if (np->full_duplex)
- np->duplex_lock = 1;
-
/* The chip-specific entries in the device structure. */
dev->open = &netdev_open;
dev->hard_start_xmit = &start_tx;
@@ -548,6 +544,56 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev,
printk(KERN_INFO "%s: No MII transceiver found!, ASIC status %x\n",
dev->name, readl(ioaddr + ASICCtrl));
}
+ /* Parse override configuration */
+ np->an_enable = 1;
+ if (card_idx < MAX_UNITS) {
+ if (media[card_idx] != NULL) {
+ np->an_enable = 0;
+ if (strcmp (media[card_idx], "100mbps_fd") == 0 ||
+ strcmp (media[card_idx], "4") == 0) {
+ np->speed = 100;
+ np->full_duplex = 1;
+ } else if (strcmp (media[card_idx], "100mbps_hd") == 0
+ || strcmp (media[card_idx], "3") == 0) {
+ np->speed = 100;
+ np->full_duplex = 0;
+ } else if (strcmp (media[card_idx], "10mbps_fd") == 0 ||
+ strcmp (media[card_idx], "2") == 0) {
+ np->speed = 10;
+ np->full_duplex = 1;
+ } else if (strcmp (media[card_idx], "10mbps_hd") == 0 ||
+ strcmp (media[card_idx], "1") == 0) {
+ np->speed = 10;
+ np->full_duplex = 0;
+ } else {
+ np->an_enable = 1;
+ }
+ }
+ }
+
+ /* Fibre PHY? */
+ if (readl (ioaddr + ASICCtrl) & 0x80) {
+ /* Default 100Mbps Full */
+ if (np->an_enable) {
+ np->speed = 100;
+ np->full_duplex = 1;
+ np->an_enable = 0;
+ }
+ }
+ /* Reset PHY */
+ mdio_write (dev, np->phys[0], 0, 0x8000);
+ mdelay (300);
+ mdio_write (dev, np->phys[0], 0, 0x1200);
+ /* Force media type */
+ if (!np->an_enable) {
+ mii_reg0 = 0;
+ mii_reg0 |= (np->speed == 100) ? 0x2000 : 0;
+ mii_reg0 |= (np->full_duplex) ? 0x0100 : 0;
+ mdio_write (dev, np->phys[0], 0, mii_reg0);
+ printk (KERN_INFO "Override speed=%d, %s duplex\n",
+ np->speed, np->full_duplex ? "Full" : "Half");
+
+ }
/* Perhaps move the reset here? */
/* Reset the chip to erase previous misconfiguration. */
@@ -714,7 +760,6 @@ static int netdev_open(struct net_device *dev)
if (dev->if_port == 0)
dev->if_port = np->default_port;
- np->full_duplex = np->duplex_lock;
np->mcastlock = (spinlock_t) SPIN_LOCK_UNLOCKED;
set_rx_mode(dev);
@@ -755,9 +800,15 @@ static void check_duplex(struct net_device *dev)
int mii_reg5 = mdio_read(dev, np->phys[0], 5);
int negotiated = mii_reg5 & np->advertising;
int duplex;
-
- if (np->duplex_lock || mii_reg5 == 0xffff)
+
+ /* Force media */
+ if (!np->an_enable || mii_reg5 == 0xffff) {
+ if (np->full_duplex)
+ writew (readw (ioaddr + MACCtrl0) | EnbFullDuplex,
+ ioaddr + MACCtrl0);
return;
+ }
+ /* Autonegotiation */
duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040;
if (np->full_duplex != duplex) {
np->full_duplex = duplex;
@@ -1003,10 +1054,10 @@ static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
/* Abnormal error summary/uncommon events handlers. */
if (intr_status & (IntrDrvRqst | IntrPCIErr | LinkChange | StatsMax))
netdev_error(dev, intr_status);
-
if (--boguscnt < 0) {
get_stats(dev);
- printk(KERN_WARNING "%s: Too much work at interrupt, "
+ if (debug > 1)
+ printk(KERN_WARNING "%s: Too much work at interrupt, "
"status=0x%4.4x / 0x%4.4x.\n",
dev->name, intr_status, readw(ioaddr + IntrClear));
/* Re-enable us in 3.2msec. */
@@ -1132,21 +1183,46 @@ static void netdev_error(struct net_device *dev, int intr_status)
{
long ioaddr = dev->base_addr;
struct netdev_private *np = dev->priv;
+ u16 mii_reg0, mii_reg4, mii_reg5;
+ int speed;
if (intr_status & IntrDrvRqst) {
/* Stop the down counter and turn interrupts back on. */
- printk("%s: Turning interrupts back on.\n", dev->name);
+ if (debug > 1)
+ printk("%s: Turning interrupts back on.\n", dev->name);
writew(0, ioaddr + IntrEnable);
writew(0, ioaddr + DownCounter);
writew(IntrRxDone | IntrRxDMADone | IntrPCIErr | IntrDrvRqst |
IntrTxDone | StatsMax | LinkChange, ioaddr + IntrEnable);
+ /* Ack buggy InRequest */
+ writew (IntrDrvRqst, ioaddr + IntrStatus);
}
if (intr_status & LinkChange) {
- printk(KERN_ERR "%s: Link changed: Autonegotiation advertising"
- " %4.4x partner %4.4x.\n", dev->name,
- mdio_read(dev, np->phys[0], 4),
- mdio_read(dev, np->phys[0], 5));
- check_duplex(dev);
+ if (np->an_enable) {
+ mii_reg4 = mdio_read (dev, np->phys[0], 4);
+ mii_reg5= mdio_read (dev, np->phys[0], 5);
+ mii_reg4 &= mii_reg5;
+ printk (KERN_INFO "%s: Link changed: ", dev->name);
+ if (mii_reg4 & 0x0100)
+ printk ("100Mbps, full duplex\n");
+ else if (mii_reg4 & 0x0080)
+ printk ("100Mbps, half duplex\n");
+ else if (mii_reg4 & 0x0040)
+ printk ("10Mbps, full duplex\n");
+ else if (mii_reg4 & 0x0020)
+ printk ("10Mbps, half duplex\n");
+ else
+ printk ("\n");
+
+ } else {
+ mii_reg0 = mdio_read (dev, np->phys[0], 0);
+ speed = (mii_reg0 & 0x2000) ? 100 : 10;
+ printk (KERN_INFO "%s: Link changed: %dMbps ,",
+ dev->name, speed);
+ printk ("%s duplex.\n", (mii_reg0 & 0x0100) ?
+ "full" : "half");
+ }
+ check_duplex (dev);
}
if (intr_status & StatsMax) {
get_stats(dev);
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 595906033389..88ca3775ef9e 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -1,4 +1,4 @@
-/* $Id: sungem.c,v 1.22 2001/10/09 02:24:33 davem Exp $
+/* $Id: sungem.c,v 1.30 2001/10/17 06:55:10 davem Exp $
* sungem.c: Sun GEM ethernet driver.
*
* Copyright (C) 2000, 2001 David S. Miller (davem@redhat.com)
@@ -36,15 +36,17 @@
#include <asm/pbm.h>
#endif
-#ifdef __powerpc__
+#ifdef CONFIG_ALL_PPC
#include <asm/pci-bridge.h>
#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
#endif
#include "sungem.h"
static char version[] __devinitdata =
- "sungem.c:v0.75 21/Mar/01 David S. Miller (davem@redhat.com)\n";
+ "sungem.c:v0.95 16/Oct/01 David S. Miller (davem@redhat.com)\n";
MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
MODULE_DESCRIPTION("Sun GEM Gbit ethernet driver");
@@ -69,6 +71,9 @@ static struct pci_device_id gem_pci_tbl[] __devinitdata = {
/* These models only differ from the original GEM in
* that their tx/rx fifos are of a different size and
* they only support 10/100 speeds. -DaveM
+ *
+ * Apple's GMAC does support gigabit on machines with
+ * the BCM5400 or 5401 PHYs. -BenH
*/
{ PCI_VENDOR_ID_SUN, PCI_DEVICE_ID_SUN_RIO_GEM,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
@@ -79,14 +84,14 @@ static struct pci_device_id gem_pci_tbl[] __devinitdata = {
MODULE_DEVICE_TABLE(pci, gem_pci_tbl);
-static u16 phy_read(struct gem *gp, int reg)
+static u16 __phy_read(struct gem *gp, int reg, int phy_addr)
{
u32 cmd;
int limit = 10000;
cmd = (1 << 30);
cmd |= (2 << 28);
- cmd |= (gp->mii_phy_addr << 23) & MIF_FRAME_PHYAD;
+ cmd |= (phy_addr << 23) & MIF_FRAME_PHYAD;
cmd |= (reg << 18) & MIF_FRAME_REGAD;
cmd |= (MIF_FRAME_TAMSB);
writel(cmd, gp->regs + MIF_FRAME);
@@ -105,14 +110,19 @@ static u16 phy_read(struct gem *gp, int reg)
return cmd & MIF_FRAME_DATA;
}
-static void phy_write(struct gem *gp, int reg, u16 val)
+static inline u16 phy_read(struct gem *gp, int reg)
+{
+ return __phy_read(gp, reg, gp->mii_phy_addr);
+}
+
+static void __phy_write(struct gem *gp, int reg, u16 val, int phy_addr)
{
u32 cmd;
int limit = 10000;
cmd = (1 << 30);
cmd |= (1 << 28);
- cmd |= (gp->mii_phy_addr << 23) & MIF_FRAME_PHYAD;
+ cmd |= (phy_addr << 23) & MIF_FRAME_PHYAD;
cmd |= (reg << 18) & MIF_FRAME_REGAD;
cmd |= (MIF_FRAME_TAMSB);
cmd |= (val & MIF_FRAME_DATA);
@@ -127,6 +137,11 @@ static void phy_write(struct gem *gp, int reg, u16 val)
}
}
+static inline void phy_write(struct gem *gp, int reg, u16 val)
+{
+ __phy_write(gp, reg, val, gp->mii_phy_addr);
+}
+
static void gem_handle_mif_event(struct gem *gp, u32 reg_val, u32 changed_bits)
{
}
@@ -762,6 +777,10 @@ static void gem_stop(struct gem *gp, unsigned long regs)
int limit;
u32 val;
+ /* Make sure we won't get any more interrupts */
+ writel(0xffffffff, gp->regs + GREG_IMASK);
+
+ /* Reset the chip */
writel(GREG_SWRST_TXRST | GREG_SWRST_RXRST, regs + GREG_SWRST);
limit = STOP_TRIES;
@@ -777,24 +796,73 @@ static void gem_stop(struct gem *gp, unsigned long regs)
printk(KERN_ERR "gem: SW reset is ghetto.\n");
}
+static void gem_start_dma(struct gem *gp)
+{
+ unsigned long val;
+
+ /* We are ready to rock, turn everything on. */
+ val = readl(gp->regs + TXDMA_CFG);
+ writel(val | TXDMA_CFG_ENABLE, gp->regs + TXDMA_CFG);
+ val = readl(gp->regs + RXDMA_CFG);
+ writel(val | RXDMA_CFG_ENABLE, gp->regs + RXDMA_CFG);
+ val = readl(gp->regs + MAC_TXCFG);
+ writel(val | MAC_TXCFG_ENAB, gp->regs + MAC_TXCFG);
+ val = readl(gp->regs + MAC_RXCFG);
+ writel(val | MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
+
+ writel(GREG_STAT_TXDONE, gp->regs + GREG_IMASK);
+
+ writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK);
+
+}
+
+/* Link modes of the BCM5400 PHY */
+static int phy_BCM5400_link_table[8][3] = {
+ { 0, 0, 0 }, /* No link */
+ { 0, 0, 0 }, /* 10BT Half Duplex */
+ { 1, 0, 0 }, /* 10BT Full Duplex */
+ { 0, 1, 0 }, /* 100BT Half Duplex */
+ { 0, 1, 0 }, /* 100BT Half Duplex */
+ { 1, 1, 0 }, /* 100BT Full Duplex*/
+ { 1, 0, 1 }, /* 1000BT */
+ { 1, 0, 1 }, /* 1000BT */
+};
+
/* A link-up condition has occurred, initialize and enable the
* rest of the chip.
*/
static void gem_set_link_modes(struct gem *gp)
{
u32 val;
- int full_duplex, speed;
+ int full_duplex, speed, pause;
full_duplex = 0;
speed = 10;
+ pause = 0;
+
if (gp->phy_type == phy_mii_mdio0 ||
gp->phy_type == phy_mii_mdio1) {
if (gp->lstate == aneg_wait) {
- val = phy_read(gp, PHY_LPA);
- if (val & (PHY_LPA_10FULL | PHY_LPA_100FULL))
- full_duplex = 1;
- if (val & (PHY_LPA_100FULL | PHY_LPA_100HALF))
- speed = 100;
+ if (gp->phy_mod == phymod_bcm5400 ||
+ gp->phy_mod == phymod_bcm5401 ||
+ gp->phy_mod == phymod_bcm5411) {
+ int link_mode;
+ val = phy_read(gp, PHY_BCM5400_AUXSTATUS);
+ link_mode = (val & PHY_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
+ PHY_BCM5400_AUXSTATUS_LINKMODE_SHIFT;
+ full_duplex = phy_BCM5400_link_table[link_mode][0];
+ speed = phy_BCM5400_link_table[link_mode][2] ? 1000
+ : (phy_BCM5400_link_table[link_mode][1] ? 100 : 10);
+ val = phy_read(gp, PHY_LPA);
+ if (val & PHY_LPA_PAUSE)
+ pause = 1;
+ } else {
+ val = phy_read(gp, PHY_LPA);
+ if (val & (PHY_LPA_10FULL | PHY_LPA_100FULL))
+ full_duplex = 1;
+ if (val & (PHY_LPA_100FULL | PHY_LPA_100HALF))
+ speed = 100;
+ }
} else {
val = phy_read(gp, PHY_CTRL);
if (val & PHY_CTRL_FDPLX)
@@ -854,33 +922,24 @@ static void gem_set_link_modes(struct gem *gp)
if (gp->phy_type == phy_serialink ||
gp->phy_type == phy_serdes) {
- u32 pcs_lpa = readl(gp->regs + PCS_MIILP);
+ u32 pcs_lpa = readl(gp->regs + PCS_MIILP);
- val = readl(gp->regs + MAC_MCCFG);
if (pcs_lpa & (PCS_MIIADV_SP | PCS_MIIADV_AP))
- val |= (MAC_MCCFG_SPE | MAC_MCCFG_RPE);
- else
- val &= ~(MAC_MCCFG_SPE | MAC_MCCFG_RPE);
- writel(val, gp->regs + MAC_MCCFG);
+ pause = 1;
+ }
- if (!full_duplex)
- writel(512, gp->regs + MAC_STIME);
- else
- writel(64, gp->regs + MAC_STIME);
- } else {
- /* Set slot-time of 64. */
+ if (!full_duplex)
+ writel(512, gp->regs + MAC_STIME);
+ else
writel(64, gp->regs + MAC_STIME);
- }
+ val = readl(gp->regs + MAC_MCCFG);
+ if (pause)
+ val |= (MAC_MCCFG_SPE | MAC_MCCFG_RPE);
+ else
+ val &= ~(MAC_MCCFG_SPE | MAC_MCCFG_RPE);
+ writel(val, gp->regs + MAC_MCCFG);
- /* We are ready to rock, turn everything on. */
- val = readl(gp->regs + TXDMA_CFG);
- writel(val | TXDMA_CFG_ENABLE, gp->regs + TXDMA_CFG);
- val = readl(gp->regs + RXDMA_CFG);
- writel(val | RXDMA_CFG_ENABLE, gp->regs + RXDMA_CFG);
- val = readl(gp->regs + MAC_TXCFG);
- writel(val | MAC_TXCFG_ENAB, gp->regs + MAC_TXCFG);
- val = readl(gp->regs + MAC_RXCFG);
- writel(val | MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
+ gem_start_dma(gp);
}
static int gem_mdio_link_not_up(struct gem *gp)
@@ -1049,8 +1108,150 @@ static void gem_init_rings(struct gem *gp, int from_irq)
}
}
+static int
+gem_reset_one_mii_phy(struct gem *gp, int phy_addr)
+{
+ u16 val;
+ int limit = 10000;
+
+ val = __phy_read(gp, PHY_CTRL, phy_addr);
+ val &= ~PHY_CTRL_ISO;
+ val |= PHY_CTRL_RST;
+ __phy_write(gp, PHY_CTRL, val, phy_addr);
+
+ udelay(100);
+
+ while (limit--) {
+ val = __phy_read(gp, PHY_CTRL, phy_addr);
+ if ((val & PHY_CTRL_RST) == 0)
+ break;
+ udelay(10);
+ }
+ if ((val & PHY_CTRL_ISO) && limit > 0)
+ __phy_write(gp, PHY_CTRL, val & ~PHY_CTRL_ISO, phy_addr);
+
+ return (limit <= 0);
+}
+
+static void
+gem_init_bcm5400_phy(struct gem *gp)
+{
+ u16 data;
+
+ /* Configure for gigabit full duplex */
+ data = phy_read(gp, PHY_BCM5400_AUXCONTROL);
+ data |= PHY_BCM5400_AUXCONTROL_PWR10BASET;
+ phy_write(gp, PHY_BCM5400_AUXCONTROL, data);
+
+ data = phy_read(gp, PHY_BCM5400_GB_CONTROL);
+ data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+ phy_write(gp, PHY_BCM5400_GB_CONTROL, data);
+
+ mdelay(10);
+
+ /* Reset and configure cascaded 10/100 PHY */
+ gem_reset_one_mii_phy(gp, 0x1f);
+
+ data = __phy_read(gp, PHY_BCM5201_MULTIPHY, 0x1f);
+ data |= PHY_BCM5201_MULTIPHY_SERIALMODE;
+ __phy_write(gp, PHY_BCM5201_MULTIPHY, data, 0x1f);
+
+ data = phy_read(gp, PHY_BCM5400_AUXCONTROL);
+ data &= ~PHY_BCM5400_AUXCONTROL_PWR10BASET;
+ phy_write(gp, PHY_BCM5400_AUXCONTROL, data);
+}
+
+static void
+gem_init_bcm5401_phy(struct gem *gp)
+{
+ u16 data;
+ int rev;
+
+ rev = phy_read(gp, PHY_ID1) & 0x000f;
+ if (rev == 0 || rev == 3) {
+ /* Some revisions of 5401 appear to need this
+ * initialisation sequence to disable, according
+ * to OF, "tap power management"
+ *
+ * WARNING ! OF and Darwin don't agree on the
+ * register addresses. OF seem to interpret the
+ * register numbers below as decimal
+ */
+ phy_write(gp, 0x18, 0x0c20);
+ phy_write(gp, 0x17, 0x0012);
+ phy_write(gp, 0x15, 0x1804);
+ phy_write(gp, 0x17, 0x0013);
+ phy_write(gp, 0x15, 0x1204);
+ phy_write(gp, 0x17, 0x8006);
+ phy_write(gp, 0x15, 0x0132);
+ phy_write(gp, 0x17, 0x8006);
+ phy_write(gp, 0x15, 0x0232);
+ phy_write(gp, 0x17, 0x201f);
+ phy_write(gp, 0x15, 0x0a20);
+ }
+
+ /* Configure for gigabit full duplex */
+ data = phy_read(gp, PHY_BCM5400_GB_CONTROL);
+ data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+ phy_write(gp, PHY_BCM5400_GB_CONTROL, data);
+
+ mdelay(1);
+
+ /* Reset and configure cascaded 10/100 PHY */
+ gem_reset_one_mii_phy(gp, 0x1f);
+
+ data = __phy_read(gp, PHY_BCM5201_MULTIPHY, 0x1f);
+ data |= PHY_BCM5201_MULTIPHY_SERIALMODE;
+ __phy_write(gp, PHY_BCM5201_MULTIPHY, data, 0x1f);
+}
+
+static void
+gem_init_bcm5411_phy(struct gem *gp)
+{
+ u16 data;
+
+ /* Here's some more Apple black magic to setup
+ * some voltage stuffs.
+ */
+ phy_write(gp, 0x1c, 0x8c23);
+ phy_write(gp, 0x1c, 0x8ca3);
+ phy_write(gp, 0x1c, 0x8c23);
+
+ /* Here, Apple seems to want to reset it, do
+ * it as well
+ */
+ phy_write(gp, PHY_CTRL, PHY_CTRL_RST);
+
+ /* Start autoneg */
+ phy_write(gp, PHY_CTRL,
+ (PHY_CTRL_ANENAB | PHY_CTRL_FDPLX |
+ PHY_CTRL_ANRES | PHY_CTRL_SPD2));
+
+ data = phy_read(gp, PHY_BCM5400_GB_CONTROL);
+ data |= PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+ phy_write(gp, PHY_BCM5400_GB_CONTROL, data);
+}
+
static void gem_init_phy(struct gem *gp)
{
+#ifdef CONFIG_ALL_PPC
+ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
+ int i;
+
+ pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gp->of_node, 0, 0);
+ for (i = 0; i < 32; i++) {
+ gp->mii_phy_addr = i;
+ if (phy_read(gp, PHY_CTRL) != 0xffff)
+ break;
+ }
+ if (i == 32) {
+ printk(KERN_WARNING "%s: GMAC PHY not responding !\n",
+ gp->dev->name);
+ return;
+ }
+ }
+#endif /* CONFIG_ALL_PPC */
+
if (gp->pdev->vendor == PCI_VENDOR_ID_SUN &&
gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) {
u32 val;
@@ -1070,27 +1271,59 @@ static void gem_init_phy(struct gem *gp)
if (gp->phy_type == phy_mii_mdio0 ||
gp->phy_type == phy_mii_mdio1) {
- u16 val = phy_read(gp, PHY_CTRL);
- int limit = 10000;
-
+ u32 phy_id;
+ u16 val;
+
/* Take PHY out of isloate mode and reset it. */
- val &= ~PHY_CTRL_ISO;
- val |= PHY_CTRL_RST;
- phy_write(gp, PHY_CTRL, val);
-
- while (limit--) {
- val = phy_read(gp, PHY_CTRL);
- if ((val & PHY_CTRL_RST) == 0)
+ gem_reset_one_mii_phy(gp, gp->mii_phy_addr);
+
+ phy_id = (phy_read(gp, PHY_ID0) << 16 | phy_read(gp, PHY_ID1))
+ & 0xfffffff0;
+ printk(KERN_INFO "%s: MII PHY ID: %x ", gp->dev->name, phy_id);
+ switch(phy_id) {
+ case 0x406210:
+ gp->phy_mod = phymod_bcm5201;
+ printk("BCM 5201\n");
break;
- udelay(10);
- }
+ case 0x4061e0:
+ printk("BCM 5221\n");
+ gp->phy_mod = phymod_bcm5221;
+ break;
+ case 0x206040:
+ printk("BCM 5400\n");
+ gp->phy_mod = phymod_bcm5400;
+ gem_init_bcm5400_phy(gp);
+ break;
+ case 0x206050:
+ printk("BCM 5401\n");
+ gp->phy_mod = phymod_bcm5401;
+ gem_init_bcm5401_phy(gp);
+ break;
+ case 0x206070:
+ printk("BCM 5411\n");
+ gp->phy_mod = phymod_bcm5411;
+ gem_init_bcm5411_phy(gp);
+ break;
+ default:
+ printk("Generic\n");
+ gp->phy_mod = phymod_generic;
+ };
/* Init advertisement and enable autonegotiation. */
+ val = phy_read(gp, PHY_CTRL);
+ val &= ~PHY_CTRL_ANENAB;
+ phy_write(gp, PHY_CTRL, val);
+ udelay(10);
+
phy_write(gp, PHY_ADV,
+ phy_read(gp, PHY_ADV) |
(PHY_ADV_10HALF | PHY_ADV_10FULL |
PHY_ADV_100HALF | PHY_ADV_100FULL));
- val |= (PHY_CTRL_ANRES | PHY_CTRL_ANENAB);
+ val = phy_read(gp, PHY_CTRL);
+ val |= PHY_CTRL_ANENAB;
+ phy_write(gp, PHY_CTRL, val);
+ val |= PHY_CTRL_ANRES;
phy_write(gp, PHY_CTRL, val);
} else {
u32 val;
@@ -1328,20 +1561,186 @@ static void gem_init_mac(struct gem *gp)
writel(0, gp->regs + MAC_MCMASK);
}
+static void
+gem_init_pause_thresholds(struct gem* gp)
+{
+ /* Calculate pause thresholds. Setting the OFF threshold to the
+ * full RX fifo size effectively disables PAUSE generation which
+ * is what we do for 10/100 only GEMs which have FIFOs too small
+ * to make real gains from PAUSE.
+ */
+ if (gp->rx_fifo_sz <= (2 * 1024)) {
+ gp->rx_pause_off = gp->rx_pause_on = gp->rx_fifo_sz;
+ } else {
+ int off = (gp->rx_fifo_sz - (5 * 1024));
+ int on = off - 1024;
+
+ gp->rx_pause_off = off;
+ gp->rx_pause_on = on;
+ }
+
+ {
+ u32 cfg = readl(gp->regs + GREG_BIFCFG);
+
+ /* XXX Why do I do this? -DaveM XXX */
+ cfg |= GREG_BIFCFG_B64DIS;
+ writel(cfg, gp->regs + GREG_BIFCFG);
+
+ cfg = GREG_CFG_IBURST;
+ cfg |= ((31 << 1) & GREG_CFG_TXDMALIM);
+ cfg |= ((31 << 6) & GREG_CFG_RXDMALIM);
+ writel(cfg, gp->regs + GREG_CFG);
+ }
+}
+
+static int gem_check_invariants(struct gem *gp)
+{
+ struct pci_dev *pdev = gp->pdev;
+ u32 mif_cfg;
+
+ /* On Apple's sungem, we can't realy on registers as the chip
+ * was been powered down by the firmware. We do the PHY lookup
+ * when the interface is opened and we configure the driver
+ * with known values.
+ */
+ if (pdev->vendor == PCI_VENDOR_ID_APPLE) {
+ gp->phy_type = phy_mii_mdio0;
+ mif_cfg = readl(gp->regs + MIF_CFG);
+ mif_cfg &= ~MIF_CFG_PSELECT;
+ writel(mif_cfg, gp->regs + MIF_CFG);
+ writel(PCS_DMODE_MGM, gp->regs + PCS_DMODE);
+ writel(MAC_XIFCFG_OE, gp->regs + MAC_XIFCFG);
+ gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64;
+ gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64;
+ gem_init_pause_thresholds(gp);
+ return 0;
+ }
+
+ mif_cfg = readl(gp->regs + MIF_CFG);
+
+ if (pdev->vendor == PCI_VENDOR_ID_SUN &&
+ pdev->device == PCI_DEVICE_ID_SUN_RIO_GEM) {
+ /* One of the MII PHYs _must_ be present
+ * as this chip has no gigabit PHY.
+ */
+ if ((mif_cfg & (MIF_CFG_MDI0 | MIF_CFG_MDI1)) == 0) {
+ printk(KERN_ERR PFX "RIO GEM lacks MII phy, mif_cfg[%08x]\n",
+ mif_cfg);
+ return -1;
+ }
+ }
+
+ /* Determine initial PHY interface type guess. MDIO1 is the
+ * external PHY and thus takes precedence over MDIO0.
+ */
+
+ if (mif_cfg & MIF_CFG_MDI1) {
+ gp->phy_type = phy_mii_mdio1;
+ mif_cfg |= MIF_CFG_PSELECT;
+ writel(mif_cfg, gp->regs + MIF_CFG);
+ } else if (mif_cfg & MIF_CFG_MDI0) {
+ gp->phy_type = phy_mii_mdio0;
+ mif_cfg &= ~MIF_CFG_PSELECT;
+ writel(mif_cfg, gp->regs + MIF_CFG);
+ } else {
+ gp->phy_type = phy_serialink;
+ }
+ if (gp->phy_type == phy_mii_mdio1 ||
+ gp->phy_type == phy_mii_mdio0) {
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ gp->mii_phy_addr = i;
+ if (phy_read(gp, PHY_CTRL) != 0xffff)
+ break;
+ }
+ if (i == 32) {
+ if (pdev->device != PCI_DEVICE_ID_SUN_GEM) {
+ printk(KERN_ERR PFX "RIO MII phy will not respond.\n");
+ return -1;
+ }
+ gp->phy_type = phy_serdes;
+ }
+ }
+
+ /* Fetch the FIFO configurations now too. */
+ gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64;
+ gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64;
+
+ if (pdev->vendor == PCI_VENDOR_ID_SUN) {
+ if (pdev->device == PCI_DEVICE_ID_SUN_GEM) {
+ if (gp->tx_fifo_sz != (9 * 1024) ||
+ gp->rx_fifo_sz != (20 * 1024)) {
+ printk(KERN_ERR PFX "GEM has bogus fifo sizes tx(%d) rx(%d)\n",
+ gp->tx_fifo_sz, gp->rx_fifo_sz);
+ return -1;
+ }
+ } else {
+ if (gp->tx_fifo_sz != (2 * 1024) ||
+ gp->rx_fifo_sz != (2 * 1024)) {
+ printk(KERN_ERR PFX "RIO GEM has bogus fifo sizes tx(%d) rx(%d)\n",
+ gp->tx_fifo_sz, gp->rx_fifo_sz);
+ return -1;
+ }
+ }
+ }
+
+ gem_init_pause_thresholds(gp);
+
+ return 0;
+}
+
static void gem_init_hw(struct gem *gp)
{
+ /* On Apple's gmac, I initialize the PHY only after
+ * setting up the chip. It appears the gigabit PHYs
+ * don't quite like beeing talked to on the GII when
+ * the chip is not running, I suspect it might not
+ * be clocked at that point. --BenH
+ */
+ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
+ gem_check_invariants(gp);
+ gp->hw_running = 1;
+ }
gem_init_phy(gp);
gem_init_dma(gp);
gem_init_mac(gp);
- writel(GREG_STAT_TXDONE, gp->regs + GREG_IMASK);
-
gp->timer_ticks = 0;
gp->lstate = aneg_wait;
gp->link_timer.expires = jiffies + ((12 * HZ) / 10);
add_timer(&gp->link_timer);
}
+#ifdef CONFIG_ALL_PPC
+/* Enable the chip's clock and make sure it's config space is
+ * setup properly. There appear to be no need to restore the
+ * base addresses.
+ */
+static void
+gem_apple_powerup(struct gem* gp)
+{
+ u16 cmd;
+
+ pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 1);
+
+ udelay(100);
+
+ pci_read_config_word(gp->pdev, PCI_COMMAND, &cmd);
+ cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
+ pci_write_config_word(gp->pdev, PCI_COMMAND, cmd);
+ pci_write_config_byte(gp->pdev, PCI_LATENCY_TIMER, 6);
+ pci_write_config_byte(gp->pdev, PCI_CACHE_LINE_SIZE, 8);
+}
+
+/* Turn off the chip's clock */
+static void
+gem_apple_powerdown(struct gem* gp)
+{
+ pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0);
+}
+#endif /* CONFIG_ALL_PPC */
+
static int gem_open(struct net_device *dev)
{
struct gem *gp = dev->priv;
@@ -1349,12 +1748,31 @@ static int gem_open(struct net_device *dev)
del_timer(&gp->link_timer);
+#ifdef CONFIG_ALL_PPC
+ /* First, we need to bring up the chip */
+ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+ gem_apple_powerup(gp);
+#endif /* CONFIG_ALL_PPC */
+
+ /* Reset the chip */
+ gem_stop(gp, regs);
+
+ /* We can now request the interrupt as we know it's masked
+ * on the controller
+ */
if (request_irq(gp->pdev->irq, gem_interrupt,
- SA_SHIRQ, dev->name, (void *)dev))
+ SA_SHIRQ, dev->name, (void *)dev)) {
+#ifdef CONFIG_ALL_PPC
+ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+ gem_apple_powerdown(gp);
+#endif /* CONFIG_ALL_PPC */
return -EAGAIN;
+ }
- gem_stop(gp, regs);
+ /* Allocate & setup ring buffers */
gem_init_rings(gp, 0);
+
+ /* Init & setup chip hardware */
gem_init_hw(gp);
return 0;
@@ -1367,6 +1785,11 @@ static int gem_close(struct net_device *dev)
del_timer(&gp->link_timer);
gem_stop(gp, gp->regs);
gem_clean_rings(gp);
+ gp->hw_running = 0;
+#ifdef CONFIG_ALL_PPC
+ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE)
+ gem_apple_powerdown(gp);
+#endif /* CONFIG_ALL_PPC */
free_irq(gp->pdev->irq, (void *)dev);
return 0;
}
@@ -1376,22 +1799,23 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev)
struct gem *gp = dev->priv;
struct net_device_stats *stats = &gp->net_stats;
- stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR);
- writel(0, gp->regs + MAC_FCSERR);
+ if (gp->hw_running) {
+ stats->rx_crc_errors += readl(gp->regs + MAC_FCSERR);
+ writel(0, gp->regs + MAC_FCSERR);
- stats->rx_frame_errors += readl(gp->regs + MAC_AERR);
- writel(0, gp->regs + MAC_AERR);
+ stats->rx_frame_errors += readl(gp->regs + MAC_AERR);
+ writel(0, gp->regs + MAC_AERR);
- stats->rx_length_errors += readl(gp->regs + MAC_LERR);
- writel(0, gp->regs + MAC_LERR);
-
- stats->tx_aborted_errors += readl(gp->regs + MAC_ECOLL);
- stats->collisions +=
- (readl(gp->regs + MAC_ECOLL) +
- readl(gp->regs + MAC_LCOLL));
- writel(0, gp->regs + MAC_ECOLL);
- writel(0, gp->regs + MAC_LCOLL);
+ stats->rx_length_errors += readl(gp->regs + MAC_LERR);
+ writel(0, gp->regs + MAC_LERR);
+ stats->tx_aborted_errors += readl(gp->regs + MAC_ECOLL);
+ stats->collisions +=
+ (readl(gp->regs + MAC_ECOLL) +
+ readl(gp->regs + MAC_LCOLL));
+ writel(0, gp->regs + MAC_ECOLL);
+ writel(0, gp->regs + MAC_LCOLL);
+ }
return &gp->net_stats;
}
@@ -1399,6 +1823,9 @@ static void gem_set_multicast(struct net_device *dev)
{
struct gem *gp = dev->priv;
+ if (!gp->hw_running)
+ return;
+
netif_stop_queue(dev);
if ((gp->dev->flags & IFF_ALLMULTI) ||
@@ -1489,117 +1916,14 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return -EINVAL;
}
-static int __devinit gem_check_invariants(struct gem *gp)
-{
- struct pci_dev *pdev = gp->pdev;
- u32 mif_cfg = readl(gp->regs + MIF_CFG);
-
- if (pdev->vendor == PCI_VENDOR_ID_SUN &&
- pdev->device == PCI_DEVICE_ID_SUN_RIO_GEM) {
- /* One of the MII PHYs _must_ be present
- * as this chip has no gigabit PHY.
- */
- if ((mif_cfg & (MIF_CFG_MDI0 | MIF_CFG_MDI1)) == 0) {
- printk(KERN_ERR PFX "RIO GEM lacks MII phy, mif_cfg[%08x]\n",
- mif_cfg);
- return -1;
- }
- }
-
- /* Determine initial PHY interface type guess. MDIO1 is the
- * external PHY and thus takes precedence over MDIO0.
- */
- if (mif_cfg & MIF_CFG_MDI1) {
- gp->phy_type = phy_mii_mdio1;
- mif_cfg |= MIF_CFG_PSELECT;
- writel(mif_cfg, gp->regs + MIF_CFG);
- } else if (mif_cfg & MIF_CFG_MDI0) {
- gp->phy_type = phy_mii_mdio0;
- mif_cfg &= ~MIF_CFG_PSELECT;
- writel(mif_cfg, gp->regs + MIF_CFG);
- } else {
- gp->phy_type = phy_serialink;
- }
- if (gp->phy_type == phy_mii_mdio1 ||
- gp->phy_type == phy_mii_mdio0) {
- int i;
-
- for (i = 0; i < 32; i++) {
- gp->mii_phy_addr = i;
- if (phy_read(gp, PHY_CTRL) != 0xffff)
- break;
- }
- if (i == 32) {
- if (pdev->device != PCI_DEVICE_ID_SUN_GEM) {
- printk(KERN_ERR PFX "RIO MII phy will not respond.\n");
- return -1;
- }
- gp->phy_type = phy_serdes;
- }
- }
-
- /* Fetch the FIFO configurations now too. */
- gp->tx_fifo_sz = readl(gp->regs + TXDMA_FSZ) * 64;
- gp->rx_fifo_sz = readl(gp->regs + RXDMA_FSZ) * 64;
-
- if (pdev->vendor == PCI_VENDOR_ID_SUN) {
- if (pdev->device == PCI_DEVICE_ID_SUN_GEM) {
- if (gp->tx_fifo_sz != (9 * 1024) ||
- gp->rx_fifo_sz != (20 * 1024)) {
- printk(KERN_ERR PFX "GEM has bogus fifo sizes tx(%d) rx(%d)\n",
- gp->tx_fifo_sz, gp->rx_fifo_sz);
- return -1;
- }
- } else {
- if (gp->tx_fifo_sz != (2 * 1024) ||
- gp->rx_fifo_sz != (2 * 1024)) {
- printk(KERN_ERR PFX "RIO GEM has bogus fifo sizes tx(%d) rx(%d)\n",
- gp->tx_fifo_sz, gp->rx_fifo_sz);
- return -1;
- }
- }
- }
-
- /* Calculate pause thresholds. Setting the OFF threshold to the
- * full RX fifo size effectively disables PAUSE generation which
- * is what we do for 10/100 only GEMs which have FIFOs too small
- * to make real gains from PAUSE.
- */
- if (gp->rx_fifo_sz <= (2 * 1024)) {
- gp->rx_pause_off = gp->rx_pause_on = gp->rx_fifo_sz;
- } else {
- int off = (gp->rx_fifo_sz - (5 * 1024));
- int on = off - 1024;
-
- gp->rx_pause_off = off;
- gp->rx_pause_on = on;
- }
-
- {
- u32 cfg;
-
- /* XXX Why do I do this? -DaveM XXX */
- cfg = readl(gp->regs + GREG_BIFCFG);
- cfg |= GREG_BIFCFG_B64DIS;
- writel(cfg, gp->regs + GREG_BIFCFG);
-
- cfg = GREG_CFG_IBURST;
- cfg |= ((31 << 1) & GREG_CFG_TXDMALIM);
- cfg |= ((31 << 6) & GREG_CFG_RXDMALIM);
- writel(cfg, gp->regs + GREG_CFG);
- }
-
- return 0;
-}
-
static int __devinit gem_get_device_address(struct gem *gp)
{
-#if defined(__sparc__) || defined(__powerpc__)
+#if defined(__sparc__) || defined(CONFIG_ALL_PPC)
struct net_device *dev = gp->dev;
- struct pci_dev *pdev = gp->pdev;
#endif
#ifdef __sparc__
+ struct pci_dev *pdev = gp->pdev;
struct pcidev_cookie *pcp = pdev->sysdata;
int node = -1;
@@ -1614,12 +1938,10 @@ static int __devinit gem_get_device_address(struct gem *gp)
if (node == -1)
memcpy(dev->dev_addr, idprom->id_ethaddr, 6);
#endif
-#ifdef __powerpc__
- struct device_node *gem_node;
+#ifdef CONFIG_ALL_PPC
unsigned char *addr;
- gem_node = pci_device_to_OF_node(pdev);
- addr = get_property(gem_node, "local-mac-address", NULL);
+ addr = get_property(gp->of_node, "local-mac-address", NULL);
if (addr == NULL) {
printk("\n");
printk(KERN_ERR "%s: can't get mac-address\n", dev->name);
@@ -1642,6 +1964,12 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
if (gem_version_printed++ == 0)
printk(KERN_INFO "%s", version);
+ /* Apple gmac note: during probe, the chip is powered up by
+ * the arch code to allow the code below to work (and to let
+ * the chip be probed on the config space. It won't stay powered
+ * up until the interface is brought up however, so we can't rely
+ * on register configuration done at this point.
+ */
err = pci_enable_device(pdev);
if (err) {
printk(KERN_ERR PFX "Cannot enable MMIO operation, "
@@ -1710,8 +2038,13 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
goto err_out_free_mmio_res;
}
- if (gem_check_invariants(gp))
- goto err_out_iounmap;
+ /* On Apple's, we might not access the hardware at that point */
+ if (pdev->vendor != PCI_VENDOR_ID_APPLE) {
+ gem_stop(gp, gp->regs);
+ if (gem_check_invariants(gp))
+ goto err_out_iounmap;
+ gp->hw_running = 1;
+ }
/* It is guarenteed that the returned buffer will be at least
* PAGE_SIZE aligned.
@@ -1730,6 +2063,9 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ",
dev->name);
+#ifdef CONFIG_ALL_PPC
+ gp->of_node = pci_device_to_OF_node(pdev);
+#endif
if (gem_get_device_address(gp))
goto err_out_iounmap;
@@ -1791,6 +2127,9 @@ static void __devexit gem_remove_one(struct pci_dev *pdev)
iounmap((void *) gp->regs);
release_mem_region(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
+#ifdef CONFIG_ALL_PPC
+ pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0);
+#endif
kfree(dev);
pci_set_drvdata(pdev, NULL);
diff --git a/drivers/net/sungem.h b/drivers/net/sungem.h
index 087a650eb45f..a4a63f21d436 100644
--- a/drivers/net/sungem.h
+++ b/drivers/net/sungem.h
@@ -1,4 +1,4 @@
-/* $Id: sungem.h,v 1.7 2001/04/04 14:49:40 davem Exp $
+/* $Id: sungem.h,v 1.8 2001/10/17 05:55:39 davem Exp $
* sungem.h: Definitions for Sun GEM ethernet driver.
*
* Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -756,9 +756,12 @@
/* MII phy registers */
#define PHY_CTRL 0x00
#define PHY_STAT 0x01
+#define PHY_ID0 0x02
+#define PHY_ID1 0x03
#define PHY_ADV 0x04
#define PHY_LPA 0x05
+#define PHY_CTRL_SPD2 0x0040 /* Gigabit enable? (bcm5411) */
#define PHY_CTRL_FDPLX 0x0100 /* Full duplex */
#define PHY_CTRL_ISO 0x0400 /* Isloate MII from PHY */
#define PHY_CTRL_ANRES 0x0200 /* Auto-negotiation restart */
@@ -778,8 +781,37 @@
#define PHY_LPA_10FULL 0x0040
#define PHY_LPA_100HALF 0x0080
#define PHY_LPA_100FULL 0x0100
+#define PHY_LPA_PAUSE 0x0400
#define PHY_LPA_FAULT 0x2000
+/* More PHY registers (specific to Broadcom models) */
+
+/* MII BCM5201 MULTIPHY interrupt register */
+#define PHY_BCM5201_INTERRUPT 0x1A
+#define PHY_BCM5201_INTERRUPT_INTENABLE 0x4000
+
+#define PHY_BCM5201_AUXMODE2 0x1B
+#define PHY_BCM5201_AUXMODE2_LOWPOWER 0x0008
+
+#define PHY_BCM5201_MULTIPHY 0x1E
+
+/* MII BCM5201 MULTIPHY register bits */
+#define PHY_BCM5201_MULTIPHY_SERIALMODE 0x0002
+#define PHY_BCM5201_MULTIPHY_SUPERISOLATE 0x0008
+
+/* MII BCM5400 1000-BASET Control register */
+#define PHY_BCM5400_GB_CONTROL 0x09
+#define PHY_BCM5400_GB_CONTROL_FULLDUPLEXCAP 0x0200
+
+/* MII BCM5400 AUXCONTROL register */
+#define PHY_BCM5400_AUXCONTROL 0x18
+#define PHY_BCM5400_AUXCONTROL_PWR10BASET 0x0004
+
+/* MII BCM5400 AUXSTATUS register */
+#define PHY_BCM5400_AUXSTATUS 0x19
+#define PHY_BCM5400_AUXSTATUS_LINKMODE_MASK 0x0700
+#define PHY_BCM5400_AUXSTATUS_LINKMODE_SHIFT 8
+
/* When it can, GEM internally caches 4 aligned TX descriptors
* at a time, so that it can use full cacheline DMA reads.
*
@@ -916,9 +948,19 @@ enum gem_phy_type {
phy_serdes,
};
+enum gem_phy_model {
+ phymod_generic,
+ phymod_bcm5201,
+ phymod_bcm5221,
+ phymod_bcm5400,
+ phymod_bcm5401,
+ phymod_bcm5411,
+};
+
enum link_state {
aneg_wait,
force_wait,
+ aneg_up,
};
struct gem {
@@ -927,6 +969,11 @@ struct gem {
int rx_new, rx_old;
int tx_new, tx_old;
+ /* Set when chip is actually in operational state
+ * (ie. not power managed)
+ */
+ int hw_running;
+
struct gem_init_block *init_block;
struct sk_buff *rx_skbs[RX_RING_SIZE];
@@ -935,6 +982,7 @@ struct gem {
struct net_device_stats net_stats;
enum gem_phy_type phy_type;
+ enum gem_phy_model phy_mod;
int tx_fifo_sz;
int rx_fifo_sz;
int rx_pause_off;
@@ -952,6 +1000,9 @@ struct gem {
dma_addr_t gblock_dvma;
struct pci_dev *pdev;
struct net_device *dev;
+#ifdef CONFIG_ALL_PPC
+ struct device_node *of_node;
+#endif
};
#define ALIGNED_RX_SKB_ADDR(addr) \
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index 4c5cbe520875..59b455c8ee03 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -1603,3 +1603,4 @@ static void __exit sparc_lance_cleanup(void)
module_init(sparc_lance_probe);
module_exit(sparc_lance_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index 8dd4ff072f58..30f06d1efc5c 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -1,4 +1,4 @@
-/* $Id: sunqe.c,v 1.51 2001/04/19 22:32:42 davem Exp $
+/* $Id: sunqe.c,v 1.52 2001/10/18 08:18:08 davem Exp $
* sunqe.c: Sparc QuadEthernet 10baseT SBUS card driver.
* Once again I am out to prove that every ethernet
* controller out there can be most efficiently programmed
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 3066566e8199..1b1a4d47e70b 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -14,7 +14,7 @@
Aironet. Major code contributions were received from Javier Achirica
and Jean Tourrilhes <jt@hpl.hp.com>. Code was also integrated from
the Cisco Aironet driver for Linux.
-
+
======================================================================*/
#include <linux/config.h>
@@ -53,7 +53,7 @@ static struct pci_device_id card_ids[] = __devinitdata {
{ 0x14b9, 0x4800, PCI_ANY_ID, PCI_ANY_ID, },
{ 0x14b9, 0x0340, PCI_ANY_ID, PCI_ANY_ID, },
{ 0x14b9, 0x0350, PCI_ANY_ID, PCI_ANY_ID, },
- { 0, }
+ { 0, }
};
MODULE_DEVICE_TABLE(pci, card_ids);
@@ -213,7 +213,7 @@ int maxencrypt /* = 0 */; /* The highest rate that the card can encrypt at.
static int auto_wep /* = 0 */; /* If set, it tries to figure out the wep mode */
static int aux_bap /* = 0 */; /* Checks to see if the aux ports are needed to read
- the bap, needed on some older cards and buses. */
+ the bap, needed on some older cards and buses. */
static int adhoc;
static int proc_uid /* = 0 */;
@@ -341,6 +341,9 @@ static int do8bitIO = 0;
/* The RIDs */
#define RID_CAPABILITIES 0xFF00
+#define RID_APINFO 0xFF01
+#define RID_RADIOINFO 0xFF02
+#define RID_UNKNOWN3 0xFF03
#define RID_RSSI 0xFF04
#define RID_CONFIG 0xFF10
#define RID_SSID 0xFF11
@@ -350,13 +353,25 @@ static int do8bitIO = 0;
#define RID_WEP_TEMP 0xFF15
#define RID_WEP_PERM 0xFF16
#define RID_MODULATION 0xFF17
+#define RID_OPTIONS 0xFF18
#define RID_ACTUALCONFIG 0xFF20 /*readonly*/
+#define RID_FACTORYCONFIG 0xFF21
+#define RID_UNKNOWN22 0xFF22
#define RID_LEAPUSERNAME 0xFF23
#define RID_LEAPPASSWORD 0xFF24
#define RID_STATUS 0xFF50
+#define RID_UNKNOWN52 0xFF52
+#define RID_UNKNOWN54 0xFF54
+#define RID_UNKNOWN55 0xFF55
+#define RID_UNKNOWN56 0xFF56
+#define RID_STATS16 0xFF60
+#define RID_STATS16DELTA 0xFF61
+#define RID_STATS16DELTACLEAR 0xFF62
#define RID_STATS 0xFF68
#define RID_STATSDELTA 0xFF69
#define RID_STATSDELTACLEAR 0xFF6A
+#define RID_UNKNOWN70 0xFF70
+#define RID_UNKNOWN71 0xFF71
#define RID_BSSLISTFIRST 0xFF72
#define RID_BSSLISTNEXT 0xFF73
@@ -563,7 +578,7 @@ typedef struct {
u16 spacer;
u32 vals[100];
} StatsRid;
-
+
typedef struct {
u16 len;
@@ -604,7 +619,7 @@ typedef struct {
#define RADIO_FH 1 /* Frequency hopping radio type */
#define RADIO_DS 2 /* Direct sequence radio type */
#define RADIO_TMA 4 /* Proprietary radio used in old cards (2500) */
- u16 radioType;
+ u16 radioType;
u8 bssid[6]; /* Mac address of the BSS */
u8 zero;
u8 ssidLen;
@@ -653,14 +668,23 @@ typedef struct {
#ifdef CISCO_EXT
#define AIROMAGIC 0xa55a
-#define AIROIOCTL SIOCDEVPRIVATE
+/* Warning : SIOCDEVPRIVATE may disapear during 2.5.X - Jean II */
+#ifdef SIOCIWFIRSTPRIV
+#ifdef SIOCDEVPRIVATE
+#define AIROOLDIOCTL SIOCDEVPRIVATE
+#define AIROOLDIDIFC AIROOLDIOCTL + 1
+#endif /* SIOCDEVPRIVATE */
+#else /* SIOCIWFIRSTPRIV */
+#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
+#endif /* SIOCIWFIRSTPRIV */
+#define AIROIOCTL SIOCIWFIRSTPRIV
#define AIROIDIFC AIROIOCTL + 1
/* Ioctl constants to be used in airo_ioctl.command */
#define AIROGCAP 0 // Capability rid
-#define AIROGCFG 1 // USED A LOT
-#define AIROGSLIST 2 // System ID list
+#define AIROGCFG 1 // USED A LOT
+#define AIROGSLIST 2 // System ID list
#define AIROGVLIST 3 // List of specified AP's
#define AIROGDRVNAM 4 // NOTUSED
#define AIROGEHTENC 5 // NOTUSED
@@ -728,11 +752,12 @@ static unsigned short IN4500( struct airo_info *, u16 register );
static u16 setup_card(struct airo_info*, u8 *mac, ConfigRid *);
static void enable_interrupts(struct airo_info*);
static void disable_interrupts(struct airo_info*);
+static u16 lock_issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap);
-static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
+static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
int whichbap);
-static int fast_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
+static int fast_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen,
int whichbap);
static int bap_write(struct airo_info*, const u16 *pu16Src, int bytelen,
int whichbap);
@@ -740,7 +765,7 @@ static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd);
static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len);
static int PC4500_writerid(struct airo_info*, u16 rid, const void
*pBuf, int len);
-static int do_writerid( struct airo_info*, u16 rid, const void *rid_data,
+static int do_writerid( struct airo_info*, u16 rid, const void *rid_data,
int len );
static u16 transmit_allocate(struct airo_info*, int lenPayload);
static int transmit_802_3_packet(struct airo_info*, u16 TxFid, char
@@ -768,20 +793,18 @@ struct airo_info {
int fids[MAX_FIDS];
int registered;
ConfigRid config;
- u16 authtype; // Used with auto_wep
+ u16 authtype; // Used with auto_wep
char keyindex; // Used with auto wep
char defindex; // Used with auto wep
struct timer_list timer;
struct proc_dir_entry *proc_entry;
struct airo_info *next;
- spinlock_t bap0_lock;
- spinlock_t bap1_lock;
spinlock_t aux_lock;
- spinlock_t cmd_lock;
+ spinlock_t main_lock;
int flags;
#define FLAG_PROMISC IFF_PROMISC
#define FLAG_RADIO_OFF 0x02
- int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
+ int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen,
int whichbap);
int (*header_parse)(struct sk_buff*, unsigned char *);
unsigned short *flash;
@@ -797,7 +820,7 @@ struct airo_info {
#endif /* WIRELESS_EXT */
};
-static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
+static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen,
int whichbap) {
return ai->bap_read(ai, pu16Dst, bytelen, whichbap);
}
@@ -816,12 +839,12 @@ static int readBSSListRid(struct airo_info *ai, int first,
if (first == 1) {
memset(&cmd, 0, sizeof(cmd));
cmd.cmd=CMD_LISTBSS;
- issuecommand(ai, &cmd, &rsp);
+ lock_issuecommand(ai, &cmd, &rsp);
/* Let the command take effect */
set_current_state (TASK_INTERRUPTIBLE);
schedule_timeout (3*HZ);
}
- rc = PC4500_readrid(ai,
+ rc = PC4500_readrid(ai,
first ? RID_BSSLISTFIRST : RID_BSSLISTNEXT,
list, sizeof(*list));
@@ -837,9 +860,9 @@ static int readBSSListRid(struct airo_info *ai, int first,
}
static int readWepKeyRid(struct airo_info*ai, WepKeyRid *wkr, int temp) {
- int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM,
+ int rc = PC4500_readrid(ai, temp ? RID_WEP_TEMP : RID_WEP_PERM,
wkr, sizeof(*wkr));
-
+
wkr->len = le16_to_cpu(wkr->len);
wkr->kindex = le16_to_cpu(wkr->kindex);
wkr->klen = le16_to_cpu(wkr->klen);
@@ -855,7 +878,7 @@ static int writeWepKeyRid(struct airo_info*ai, WepKeyRid *pwkr, int perm) {
wkr.kindex = cpu_to_le16(wkr.kindex);
wkr.klen = cpu_to_le16(wkr.klen);
rc = do_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr));
- if (rc!=SUCCESS) printk(KERN_ERR "airo: WEP_TEMP set %x\n", rc);
+ if (rc!=SUCCESS) printk(KERN_ERR "airo: WEP_TEMP set %x\n", rc);
if (perm) {
rc = do_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr));
if (rc!=SUCCESS) {
@@ -890,7 +913,7 @@ static int writeSsidRid(struct airo_info*ai, SsidRid *pssidr) {
static int readConfigRid(struct airo_info*ai, ConfigRid *cfgr) {
int rc = PC4500_readrid(ai, RID_ACTUALCONFIG, cfgr, sizeof(*cfgr));
u16 *s;
-
+
for(s = &cfgr->len; s <= &cfgr->rtsThres; s++) *s = le16_to_cpu(*s);
for(s = &cfgr->shortRetryLimit; s <= &cfgr->radioType; s++)
@@ -898,16 +921,16 @@ static int readConfigRid(struct airo_info*ai, ConfigRid *cfgr) {
for(s = &cfgr->txPower; s <= &cfgr->radioSpecific; s++)
*s = le16_to_cpu(*s);
-
+
for(s = &cfgr->arlThreshold; s <= &cfgr->autoWake; s++)
*s = le16_to_cpu(*s);
-
+
return rc;
}
static int writeConfigRid(struct airo_info*ai, ConfigRid *pcfgr) {
u16 *s;
ConfigRid cfgr = *pcfgr;
-
+
for(s = &cfgr.len; s <= &cfgr.rtsThres; s++) *s = cpu_to_le16(*s);
for(s = &cfgr.shortRetryLimit; s <= &cfgr.radioType; s++)
@@ -915,10 +938,10 @@ static int writeConfigRid(struct airo_info*ai, ConfigRid *pcfgr) {
for(s = &cfgr.txPower; s <= &cfgr.radioSpecific; s++)
*s = cpu_to_le16(*s);
-
+
for(s = &cfgr.arlThreshold; s <= &cfgr.autoWake; s++)
*s = cpu_to_le16(*s);
-
+
return do_writerid( ai, RID_CONFIG, &cfgr, sizeof(cfgr));
}
static int readStatusRid(struct airo_info*ai, StatusRid *statr) {
@@ -947,7 +970,7 @@ static int writeAPListRid(struct airo_info*ai, APListRid *aplr) {
static int readCapabilityRid(struct airo_info*ai, CapabilityRid *capr) {
int rc = PC4500_readrid(ai, RID_CAPABILITIES, capr, sizeof(*capr));
u16 *s;
-
+
capr->len = le16_to_cpu(capr->len);
capr->prodNum = le16_to_cpu(capr->prodNum);
capr->radioType = le16_to_cpu(capr->radioType);
@@ -976,21 +999,19 @@ static int airo_open(struct net_device *dev) {
static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
s16 len;
- s16 retval = 0;
u16 status;
u32 flags;
- s8 *buffer;
int i,j;
struct airo_info *priv = (struct airo_info*)dev->priv;
u32 *fids = priv->fids;
-
+
if ( skb == NULL ) {
printk( KERN_ERR "airo: skb == NULL!!!\n" );
return 0;
}
-
+
/* Find a vacant FID */
- spin_lock_irqsave(&priv->bap1_lock, flags);
+ spin_lock_irqsave(&priv->main_lock, flags);
for( j = 0, i = -1; j < MAX_FIDS; j++ ) {
if ( !( fids[j] & 0xffff0000 ) ) {
if ( i == -1 ) i = j;
@@ -999,31 +1020,51 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
}
if ( j == MAX_FIDS ) netif_stop_queue(dev);
if ( i == -1 ) {
- retval = -EBUSY;
+ priv->stats.tx_fifo_errors++;
goto tx_done;
}
-
+
len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; /* check min length*/
- buffer = skb->data;
- status = transmit_802_3_packet( priv,
- fids[i],
- skb->data, len );
-
+ status = transmit_802_3_packet( priv, fids[i], skb->data, len );
+
if ( status == SUCCESS ) {
/* Mark fid as used & save length for later */
- fids[i] |= (len << 16);
+ fids[i] |= (len << 16);
dev->trans_start = jiffies;
} else {
- priv->stats.tx_errors++;
+ priv->stats.tx_window_errors++;
}
tx_done:
- spin_unlock_irqrestore(&priv->bap1_lock, flags);
+ spin_unlock_irqrestore(&priv->main_lock, flags);
dev_kfree_skb(skb);
return 0;
}
-static struct net_device_stats *airo_get_stats(struct net_device *dev) {
- return &(((struct airo_info*)dev->priv)->stats);
+struct net_device_stats *airo_get_stats(struct net_device *dev)
+{
+ struct airo_info *local = (struct airo_info*) dev->priv;
+ StatsRid stats_rid;
+ u32 *vals = stats_rid.vals;
+
+ /* Get stats out of the card */
+ readStatsRid(local, &stats_rid, RID_STATS);
+
+ local->stats.rx_packets = vals[43] + vals[44] + vals[45];
+ local->stats.tx_packets = vals[39] + vals[40] + vals[41];
+ local->stats.rx_bytes = vals[92];
+ local->stats.tx_bytes = vals[91];
+ local->stats.rx_errors = vals[0] + vals[2] + vals[3] + vals[4];
+ local->stats.tx_errors = vals[42] + local->stats.tx_fifo_errors;
+ local->stats.multicast = vals[43];
+ local->stats.collisions = vals[89];
+
+ /* detailed rx_errors: */
+ local->stats.rx_length_errors = vals[3];
+ local->stats.rx_crc_errors = vals[4];
+ local->stats.rx_frame_errors = vals[2];
+ local->stats.rx_fifo_errors = vals[0];
+
+ return (&local->stats);
}
static int enable_MAC( struct airo_info *ai, Resp *rsp );
@@ -1033,7 +1074,7 @@ static void airo_set_multicast_list(struct net_device *dev) {
struct airo_info *ai = (struct airo_info*)dev->priv;
Cmd cmd;
Resp rsp;
-
+
/* For some reason this command takes a lot of time (~20 ms) and it's
* run in an interrupt handler, so we'd better be sure we needed it
* before executing it.
@@ -1042,7 +1083,7 @@ static void airo_set_multicast_list(struct net_device *dev) {
memset(&cmd, 0, sizeof(cmd));
cmd.cmd=CMD_SETMODE;
cmd.parm0=(dev->flags&IFF_PROMISC) ? PROMISC : NOPROMISC;
- issuecommand(ai, &cmd, &rsp);
+ lock_issuecommand(ai, &cmd, &rsp);
ai->flags^=IFF_PROMISC;
}
@@ -1073,7 +1114,7 @@ static int airo_change_mtu(struct net_device *dev, int new_mtu)
}
-static int airo_close(struct net_device *dev) {
+static int airo_close(struct net_device *dev) {
struct airo_info *ai = (struct airo_info*)dev->priv;
netif_stop_queue(dev);
@@ -1083,7 +1124,7 @@ static int airo_close(struct net_device *dev) {
static void del_airo_dev( struct net_device *dev );
-void stop_airo_card( struct net_device *dev, int freeres )
+void stop_airo_card( struct net_device *dev, int freeres )
{
struct airo_info *ai = (struct airo_info*)dev->priv;
if (ai->flash)
@@ -1106,32 +1147,35 @@ void stop_airo_card( struct net_device *dev, int freeres )
kfree( dev );
}
-static int add_airo_dev( struct net_device *dev );
+static int add_airo_dev( struct net_device *dev );
struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
{
struct net_device *dev;
struct airo_info *ai;
int i, rc;
-
+
/* Create the network device object. */
dev = alloc_etherdev(sizeof(*ai));
if (!dev) {
printk(KERN_ERR "airo: Couldn't alloc_etherdev\n");
return NULL;
}
+ if (dev_alloc_name(dev, dev->name) < 0) {
+ printk(KERN_ERR "airo: Couldn't get name!\n");
+ goto err_out_free;
+ }
+
ai = dev->priv;
- ai->registered = 1;
+ ai->registered = 0;
ai->dev = dev;
- ai->bap0_lock = SPIN_LOCK_UNLOCKED;
- ai->bap1_lock = SPIN_LOCK_UNLOCKED;
ai->aux_lock = SPIN_LOCK_UNLOCKED;
- ai->cmd_lock = SPIN_LOCK_UNLOCKED;
+ ai->main_lock = SPIN_LOCK_UNLOCKED;
ai->header_parse = dev->hard_header_parse;
rc = add_airo_dev( dev );
if (rc)
goto err_out_free;
-
+
/* The Airo-specific entries in the device structure. */
dev->hard_start_xmit = &airo_start_xmit;
dev->get_stats = &airo_get_stats;
@@ -1146,16 +1190,11 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
dev->stop = &airo_close;
dev->irq = irq;
dev->base_addr = port;
-
- rc = register_netdev(dev);
- if (rc)
- goto err_out_unlink;
-
- rc = request_irq( dev->irq, airo_interrupt,
- SA_SHIRQ | SA_INTERRUPT, dev->name, dev );
+
+ rc = request_irq( dev->irq, airo_interrupt, SA_SHIRQ, dev->name, dev );
if (rc) {
printk(KERN_ERR "airo: register interrupt %d failed, rc %d\n", irq, rc );
- goto err_out_unregister;
+ goto err_out_unlink;
}
if (!is_pcmcia) {
if (!request_region( dev->base_addr, 64, dev->name )) {
@@ -1163,13 +1202,18 @@ struct net_device *init_airo_card( unsigned short irq, int port, int is_pcmcia )
goto err_out_irq;
}
}
-
+
if ( setup_card( ai, dev->dev_addr, &ai->config) != SUCCESS ) {
printk( KERN_ERR "airo: MAC could not be enabled\n" );
rc = -EIO;
goto err_out_res;
}
+ rc = register_netdev(dev);
+ if (rc)
+ goto err_out_res;
+
+ ai->registered = 1;
printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n",
dev->name,
dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
@@ -1189,8 +1233,6 @@ err_out_res:
release_region( dev->base_addr, 64 );
err_out_irq:
free_irq(dev->irq, dev);
-err_out_unregister:
- unregister_netdev(dev);
err_out_unlink:
del_airo_dev(dev);
err_out_free:
@@ -1204,7 +1246,7 @@ int waitbusy (struct airo_info *ai) {
udelay (10);
if (++delay % 20)
OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
- }
+ }
return delay < 10000;
}
@@ -1253,29 +1295,33 @@ static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
u16 status;
u16 fid;
struct airo_info *apriv = (struct airo_info *)dev->priv;
- u16 savedInterrupts;
-
+ u16 savedInterrupts = 0;
+
if (!netif_device_present(dev))
return;
-
- status = IN4500( apriv, EVSTAT );
- if ( !status || status == 0xffff ) return;
-
- if ( status & EV_AWAKE ) {
- OUT4500( apriv, EVACK, EV_AWAKE );
- OUT4500( apriv, EVACK, EV_AWAKE );
- }
-
- savedInterrupts = IN4500( apriv, EVINTEN );
- OUT4500( apriv, EVINTEN, 0 );
-
- if ( status & EV_LINK ) {
- /* The link status has changed, if you want to put a
- monitor hook in, do it here. (Remember that
- interrupts are still disabled!)
- */
- u16 newStatus = IN4500(apriv, LINKSTAT);
- /* Here is what newStatus means: */
+
+ for (;;) {
+ status = IN4500( apriv, EVSTAT );
+ if ( !status || status == 0xffff ) break;
+
+ if ( status & EV_AWAKE ) {
+ OUT4500( apriv, EVACK, EV_AWAKE );
+ OUT4500( apriv, EVACK, EV_AWAKE );
+ }
+
+ if (!savedInterrupts) {
+ savedInterrupts = IN4500( apriv, EVINTEN );
+ OUT4500( apriv, EVINTEN, 0 );
+ }
+
+ if ( status & EV_LINK ) {
+ /* The link status has changed, if you want to put a
+ monitor hook in, do it here. (Remember that
+ interrupts are still disabled!)
+ */
+ u16 newStatus = IN4500(apriv, LINKSTAT);
+ OUT4500( apriv, EVACK, EV_LINK);
+ /* Here is what newStatus means: */
#define NOBEACON 0x8000 /* Loss of sync - missed beacons */
#define MAXRETRIES 0x8001 /* Loss of sync - max retries */
#define MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/
@@ -1304,155 +1350,137 @@ static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
leaving BSS */
#define RC_NOAUTH 9 /* Station requesting (Re)Association is not
Authenticated with the responding station */
- if (newStatus != ASSOCIATED) {
- if (auto_wep && !timer_pending(&apriv->timer)) {
- apriv->timer.expires = RUN_AT(HZ*3);
- add_timer(&apriv->timer);
- }
- }
- }
-
- /* Check to see if there is something to receive */
- if ( status & EV_RX ) {
- struct sk_buff *skb = NULL;
- long flags;
- u16 fc, len, hdrlen = 0;
- struct {
- u16 status, len;
- u8 rssi[2];
- } hdr;
-
- fid = IN4500( apriv, RXFID );
-
- /* Get the packet length */
- spin_lock_irqsave(&apriv->bap0_lock, flags);
- if (dev->type == ARPHRD_IEEE80211) {
- bap_setup (apriv, fid, 4, BAP0);
- bap_read (apriv, (u16*)&hdr, sizeof(hdr), BAP0);
- /* Bad CRC. Ignore packet */
- if (le16_to_cpu(hdr.status) == 2) {
- apriv->stats.rx_crc_errors++;
- apriv->stats.rx_errors++;
- hdr.len = 0;
+ if (newStatus != ASSOCIATED) {
+ if (auto_wep && !timer_pending(&apriv->timer)) {
+ apriv->timer.expires = RUN_AT(HZ*3);
+ add_timer(&apriv->timer);
+ }
}
- } else {
- bap_setup (apriv, fid, 6, BAP0);
- bap_read (apriv, (u16*)&hdr.len, 4, BAP0);
- }
- len = le16_to_cpu(hdr.len);
-
- if (len > 2312) {
- apriv->stats.rx_length_errors++;
- apriv->stats.rx_errors++;
- printk( KERN_ERR
- "airo: Bad size %d\n", len );
- len = 0;
}
- if (len) {
+
+ /* Check to see if there is something to receive */
+ if ( status & EV_RX ) {
+ struct sk_buff *skb = NULL;
+ u16 fc, len, hdrlen = 0;
+ struct {
+ u16 status, len;
+ u8 rssi[2];
+ } hdr;
+
+ fid = IN4500( apriv, RXFID );
+
+ /* Get the packet length */
if (dev->type == ARPHRD_IEEE80211) {
- bap_setup (apriv, fid, 0x14, BAP0);
- bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0);
- if ((le16_to_cpu(fc) & 0x300) == 0x300)
- hdrlen = 30;
- else
- hdrlen = 24;
- } else
- hdrlen = 12;
+ bap_setup (apriv, fid, 4, BAP0);
+ bap_read (apriv, (u16*)&hdr, sizeof(hdr), BAP0);
+ /* Bad CRC. Ignore packet */
+ if (le16_to_cpu(hdr.status) & 2)
+ hdr.len = 0;
+ } else {
+ bap_setup (apriv, fid, 6, BAP0);
+ bap_read (apriv, (u16*)&hdr.len, 4, BAP0);
+ }
+ len = le16_to_cpu(hdr.len);
- skb = dev_alloc_skb( len + hdrlen + 2 );
- if ( !skb ) {
- apriv->stats.rx_dropped++;
+ if (len > 2312) {
+ printk( KERN_ERR "airo: Bad size %d\n", len );
len = 0;
}
- }
- if (len) {
- u16 *buffer;
- buffer = (u16*)skb_put (skb, len + hdrlen);
- if (dev->type == ARPHRD_IEEE80211) {
- u16 gap, tmpbuf[4];
- buffer[0] = fc;
- bap_read (apriv, buffer + 1, hdrlen - 2, BAP0);
- if (hdrlen == 24)
- bap_read (apriv, tmpbuf, 6, BAP0);
-
- bap_read (apriv, &gap, sizeof(gap), BAP0);
- gap = le16_to_cpu(gap);
- if (gap && gap <= 8)
- bap_read (apriv, tmpbuf, gap, BAP0);
-
- bap_read (apriv, buffer + hdrlen/2, len, BAP0);
- } else {
- bap_setup (apriv, fid, 0x38, BAP0);
- bap_read (apriv, buffer,len + hdrlen,BAP0);
+ if (len) {
+ if (dev->type == ARPHRD_IEEE80211) {
+ bap_setup (apriv, fid, 0x14, BAP0);
+ bap_read (apriv, (u16*)&fc, sizeof(fc), BAP0);
+ if ((le16_to_cpu(fc) & 0x300) == 0x300)
+ hdrlen = 30;
+ else
+ hdrlen = 24;
+ } else
+ hdrlen = 12;
+
+ skb = dev_alloc_skb( len + hdrlen + 2 );
+ if ( !skb ) {
+ apriv->stats.rx_dropped++;
+ len = 0;
+ }
}
+ if (len) {
+ u16 *buffer;
+ buffer = (u16*)skb_put (skb, len + hdrlen);
+ if (dev->type == ARPHRD_IEEE80211) {
+ u16 gap, tmpbuf[4];
+ buffer[0] = fc;
+ bap_read (apriv, buffer + 1, hdrlen - 2, BAP0);
+ if (hdrlen == 24)
+ bap_read (apriv, tmpbuf, 6, BAP0);
+
+ bap_read (apriv, &gap, sizeof(gap), BAP0);
+ gap = le16_to_cpu(gap);
+ if (gap && gap <= 8)
+ bap_read (apriv, tmpbuf, gap, BAP0);
+
+ bap_read (apriv, buffer + hdrlen/2, len, BAP0);
+ } else {
+ bap_setup (apriv, fid, 0x38, BAP0);
+ bap_read (apriv, buffer,len + hdrlen,BAP0);
+ }
+ OUT4500( apriv, EVACK, EV_RX);
#ifdef WIRELESS_SPY
- if (apriv->spy_number > 0) {
- int i;
- char *sa;
-
- sa = (char*)buffer + ((dev->type == ARPHRD_IEEE80211) ? 10 : 6);
-
- for (i=0; i<apriv->spy_number; i++)
- if (!memcmp(sa,apriv->spy_address[i],6))
- {
- apriv->spy_stat[i].qual = hdr.rssi[0];
- if (apriv->rssi)
- apriv->spy_stat[i].level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
- else
- apriv->spy_stat[i].level = (hdr.rssi[1] + 321) / 2;
- apriv->spy_stat[i].noise = 0;
- apriv->spy_stat[i].updated = 3;
- break;
- }
- }
+ if (apriv->spy_number > 0) {
+ int i;
+ char *sa;
+
+ sa = (char*)buffer + ((dev->type == ARPHRD_IEEE80211) ? 10 : 6);
+
+ for (i=0; i<apriv->spy_number; i++)
+ if (!memcmp(sa,apriv->spy_address[i],6))
+ {
+ apriv->spy_stat[i].qual = hdr.rssi[0];
+ if (apriv->rssi)
+ apriv->spy_stat[i].level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm;
+ else
+ apriv->spy_stat[i].level = (hdr.rssi[1] + 321) / 2;
+ apriv->spy_stat[i].noise = 0;
+ apriv->spy_stat[i].updated = 3;
+ break;
+ }
+ }
#endif /* WIRELESS_SPY */
- apriv->stats.rx_packets++;
- apriv->stats.rx_bytes += len + hdrlen;
- dev->last_rx = jiffies;
- skb->dev = dev;
- skb->ip_summed = CHECKSUM_NONE;
- if (dev->type == ARPHRD_IEEE80211) {
- skb->mac.raw = skb->data;
- skb_pull (skb, hdrlen);
- skb->pkt_type = PACKET_OTHERHOST;
- skb->protocol = htons(ETH_P_802_2);
- } else
- skb->protocol = eth_type_trans( skb, dev );
+ dev->last_rx = jiffies;
+ skb->dev = dev;
+ skb->ip_summed = CHECKSUM_NONE;
+ if (dev->type == ARPHRD_IEEE80211) {
+ skb->mac.raw = skb->data;
+ skb_pull (skb, hdrlen);
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = htons(ETH_P_802_2);
+ } else
+ skb->protocol = eth_type_trans(skb,dev);
- netif_rx( skb );
+ netif_rx( skb );
+ } else
+ OUT4500( apriv, EVACK, EV_RX);
}
- spin_unlock_irqrestore(&apriv->bap0_lock, flags);
- }
- /* Check to see if a packet has been transmitted */
- if ( status & ( EV_TX|EV_TXEXC ) ) {
- int i;
- int len = 0;
- int full = 1;
- int index = -1;
-
- fid = IN4500(apriv, TXCOMPLFID);
-
- for( i = 0; i < MAX_FIDS; i++ ) {
- if (!(apriv->fids[i] & 0xffff0000)) full = 0;
- if ( ( apriv->fids[i] & 0xffff ) == fid ) {
- len = apriv->fids[i] >> 16;
- index = i;
- /* Set up to be used again */
- apriv->fids[i] &= 0xffff;
+ /* Check to see if a packet has been transmitted */
+ if ( status & ( EV_TX|EV_TXEXC ) ) {
+ int i;
+ int len = 0;
+ int index = -1;
+
+ fid = IN4500(apriv, TXCOMPLFID);
+
+ for( i = 0; i < MAX_FIDS; i++ ) {
+ if ( ( apriv->fids[i] & 0xffff ) == fid ) {
+ len = apriv->fids[i] >> 16;
+ index = i;
+ /* Set up to be used again */
+ apriv->fids[i] &= 0xffff;
+ }
}
- }
- if (full) netif_wake_queue(dev);
- if (index==-1) {
- printk( KERN_ERR
- "airo: Unallocated FID was used to xmit\n" );
- }
- if ( status & EV_TX ) {
- apriv->stats.tx_packets++;
- if(index!=-1)
- apriv->stats.tx_bytes += len;
- } else {
- if (bap_setup(apriv, fid, 0x0004, BAP1) == SUCCESS) {
+ if (index != -1) netif_wake_queue(dev);
+ if ((status & EV_TXEXC) &&
+ (bap_setup(apriv, fid, 4, BAP1) == SUCCESS)) {
+
u16 status;
bap_read(apriv, &status, 2, BAP1);
if (le16_to_cpu(status) & 2)
@@ -1462,18 +1490,24 @@ static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
if (le16_to_cpu(status) & 0x10)
apriv->stats.tx_carrier_errors++;
}
- apriv->stats.tx_errors++;
+ OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC));
+ if (index==-1) {
+ printk( KERN_ERR "airo: Unallocated FID was used to xmit\n" );
+ }
}
+ if ( status & ~STATUS_INTS )
+ OUT4500( apriv, EVACK, status & ~STATUS_INTS);
+
+ if ( status & ~STATUS_INTS & ~IGNORE_INTS )
+ printk( KERN_WARNING "airo: Got weird status %x\n",
+ status & ~STATUS_INTS & ~IGNORE_INTS );
}
- if ( status & ~STATUS_INTS & ~IGNORE_INTS )
- printk( KERN_WARNING
- "airo: Got weird status %x\n",
- status & ~STATUS_INTS & ~IGNORE_INTS );
- OUT4500( apriv, EVACK, status & STATUS_INTS );
- OUT4500( apriv, EVINTEN, savedInterrupts );
-
+
+ if (savedInterrupts)
+ OUT4500( apriv, EVINTEN, savedInterrupts );
+
/* done.. */
- return;
+ return;
}
/*
@@ -1496,7 +1530,7 @@ static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) {
static u16 IN4500( struct airo_info *ai, u16 reg ) {
unsigned short rc;
-
+
if ( !do8bitIO )
rc = inw( ai->dev->base_addr + reg );
else {
@@ -1512,7 +1546,7 @@ static int enable_MAC( struct airo_info *ai, Resp *rsp ) {
if (ai->flags&FLAG_RADIO_OFF) return SUCCESS;
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = MAC_ENABLE;
- return issuecommand(ai, &cmd, rsp);
+ return lock_issuecommand(ai, &cmd, rsp);
}
static void disable_MAC( struct airo_info *ai ) {
@@ -1521,7 +1555,7 @@ static void disable_MAC( struct airo_info *ai ) {
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = MAC_DISABLE; // disable in case already enabled
- issuecommand(ai, &cmd, &rsp);
+ lock_issuecommand(ai, &cmd, &rsp);
}
static void enable_interrupts( struct airo_info *ai ) {
@@ -1538,10 +1572,10 @@ static void disable_interrupts( struct airo_info *ai ) {
OUT4500( ai, EVINTEN, 0 );
}
-static u16 setup_card(struct airo_info *ai, u8 *mac,
+static u16 setup_card(struct airo_info *ai, u8 *mac,
ConfigRid *config)
{
- Cmd cmd;
+ Cmd cmd;
Resp rsp;
ConfigRid cfg;
int status;
@@ -1560,18 +1594,18 @@ static u16 setup_card(struct airo_info *ai, u8 *mac,
/* The NOP is the first step in getting the card going */
cmd.cmd = NOP;
cmd.parm0 = cmd.parm1 = cmd.parm2 = 0;
- if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
+ if ( lock_issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
return ERROR;
}
memset(&cmd, 0, sizeof(cmd));
cmd.cmd = MAC_DISABLE; // disable in case already enabled
- if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
+ if ( lock_issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
return ERROR;
}
-
+
// Let's figure out if we need to use the AUX port
cmd.cmd = CMD_ENABLEAUX;
- if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
+ if (lock_issuecommand(ai, &cmd, &rsp) != SUCCESS) {
printk(KERN_ERR "airo: Error checking for AUX port\n");
return ERROR;
}
@@ -1586,7 +1620,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac,
cfg = *config;
} else {
tdsRssiRid rssi_rid;
-
+
// general configuration (read/modify/write)
status = readConfigRid(ai, &cfg);
if ( status != SUCCESS ) return ERROR;
@@ -1606,23 +1640,23 @@ static u16 setup_card(struct airo_info *ai, u8 *mac,
if ((status == SUCCESS) && (cap_rid.softCap & 8))
cfg.rmode |= RXMODE_NORMALIZED_RSSI;
else
- printk(KERN_WARNING "airo: unknown received signal level\n");
+ printk(KERN_WARNING "airo: unknown received signal level scale\n");
}
cfg.opmode = adhoc ? MODE_STA_IBSS : MODE_STA_ESS;
-
+
/* Save off the MAC */
for( i = 0; i < 6; i++ ) {
mac[i] = cfg.macAddr[i];
}
- /* Check to see if there are any insmod configured
+ /* Check to see if there are any insmod configured
rates to add */
if ( rates ) {
int i = 0;
if ( rates[0] ) memset(cfg.rates,0,sizeof(cfg.rates));
for( i = 0; i < 8 && rates[i]; i++ ) {
cfg.rates[i] = rates[i];
- }
+ }
}
if ( basic_rate > 0 ) {
int i;
@@ -1637,27 +1671,27 @@ static u16 setup_card(struct airo_info *ai, u8 *mac,
cfg.authType = ai->authtype;
*config = cfg;
}
-
+
/* Setup the SSIDs if present */
if ( ssids[0] ) {
int i = 0;
for( i = 0; i < 3 && ssids[i]; i++ ) {
mySsid.ssids[i].len = strlen(ssids[i]);
- if ( mySsid.ssids[i].len > 32 )
+ if ( mySsid.ssids[i].len > 32 )
mySsid.ssids[i].len = 32;
memcpy(mySsid.ssids[i].ssid, ssids[i],
mySsid.ssids[i].len);
mySsid.ssids[i].len = mySsid.ssids[i].len;
}
}
-
+
status = writeConfigRid(ai, &cfg);
if ( status != SUCCESS ) return ERROR;
-
+
/* Set up the SSID list */
status = writeSsidRid(ai, &mySsid);
if ( status != SUCCESS ) return ERROR;
-
+
/* Grab the initial wep key, we gotta save it for auto_wep */
rc = readWepKeyRid(ai, &wkr, 1);
if (rc == SUCCESS) do {
@@ -1667,7 +1701,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac,
}
rc = readWepKeyRid(ai, &wkr, 0);
} while(lastindex != wkr.kindex);
-
+
if (auto_wep && !timer_pending(&ai->timer)) {
ai->timer.expires = RUN_AT(HZ*3);
add_timer(&ai->timer);
@@ -1675,49 +1709,49 @@ static u16 setup_card(struct airo_info *ai, u8 *mac,
return SUCCESS;
}
+static u16 lock_issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
+ int rc;
+ long flags;
+
+ spin_lock_irqsave(&ai->main_lock, flags);
+ rc = issuecommand(ai, pCmd, pRsp);
+ spin_unlock_irqrestore(&ai->main_lock, flags);
+ return rc;
+}
+
static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
// Im really paranoid about letting it run forever!
- int max_tries = 600000;
- int rc = SUCCESS;
- long flags;
+ int max_tries = 600000;
- spin_lock_irqsave(&ai->cmd_lock, flags);
OUT4500(ai, PARAM0, pCmd->parm0);
OUT4500(ai, PARAM1, pCmd->parm1);
OUT4500(ai, PARAM2, pCmd->parm2);
OUT4500(ai, COMMAND, pCmd->cmd);
while ( max_tries-- &&
(IN4500(ai, EVSTAT) & EV_CMD) == 0) {
- if ( IN4500(ai, COMMAND) == pCmd->cmd) {
+ if ( IN4500(ai, COMMAND) == pCmd->cmd) {
// PC4500 didn't notice command, try again
OUT4500(ai, COMMAND, pCmd->cmd);
}
- if (!(max_tries & 255) && !in_interrupt()) {
- set_current_state(TASK_RUNNING);
- schedule();
- }
}
if ( max_tries == -1 ) {
- printk( KERN_ERR
+ printk( KERN_ERR
"airo: Max tries exceeded when issueing command\n" );
- rc = ERROR;
- goto done;
+ return ERROR;
}
// command completed
pRsp->status = IN4500(ai, STATUS);
pRsp->rsp0 = IN4500(ai, RESP0);
pRsp->rsp1 = IN4500(ai, RESP1);
pRsp->rsp2 = IN4500(ai, RESP2);
-
+
// clear stuck command busy if necessary
if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
}
// acknowledge processing the status/response
OUT4500(ai, EVACK, EV_CMD);
- done:
- spin_unlock_irqrestore(&ai->cmd_lock, flags);
- return rc;
+ return SUCCESS;
}
/* Sets up the bap to start exchange data. whichbap should
@@ -1727,7 +1761,7 @@ static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap )
{
int timeout = 50;
int max_tries = 3;
-
+
OUT4500(ai, SELECT0+whichbap, rid);
OUT4500(ai, OFFSET0+whichbap, offset);
while (1) {
@@ -1735,19 +1769,19 @@ static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap )
if (status & BAP_BUSY) {
/* This isn't really a timeout, but its kinda
close */
- if (timeout--) {
+ if (timeout--) {
continue;
}
} else if ( status & BAP_ERR ) {
/* invalid rid or offset */
- printk( KERN_ERR "airo: BAP error %x %d\n",
+ printk( KERN_ERR "airo: BAP error %x %d\n",
status, whichbap );
return ERROR;
} else if (status & BAP_DONE) { // success
return SUCCESS;
}
if ( !(max_tries--) ) {
- printk( KERN_ERR
+ printk( KERN_ERR
"airo: BAP setup error too many retries\n" );
return ERROR;
}
@@ -1776,7 +1810,7 @@ static u16 aux_setup(struct airo_info *ai, u16 page,
/* requires call to bap_setup() first */
static int aux_bap_read(struct airo_info *ai, u16 *pu16Dst,
- int bytelen, int whichbap)
+ int bytelen, int whichbap)
{
u16 len;
u16 page;
@@ -1795,11 +1829,11 @@ static int aux_bap_read(struct airo_info *ai, u16 *pu16Dst,
for (i=0; i<words;) {
int count;
count = (len>>1) < (words-i) ? (len>>1) : (words-i);
- if ( !do8bitIO )
- insw( ai->dev->base_addr+DATA0+whichbap,
+ if ( !do8bitIO )
+ insw( ai->dev->base_addr+DATA0+whichbap,
pu16Dst+i,count );
else
- insb( ai->dev->base_addr+DATA0+whichbap,
+ insb( ai->dev->base_addr+DATA0+whichbap,
pu16Dst+i, count << 1 );
i += count;
if (i<words) {
@@ -1812,11 +1846,11 @@ static int aux_bap_read(struct airo_info *ai, u16 *pu16Dst,
/* requires call to bap_setup() first */
-static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst,
+static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst,
int bytelen, int whichbap)
{
bytelen = (bytelen + 1) & (~1); // round up to even value
- if ( !do8bitIO )
+ if ( !do8bitIO )
insw( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen>>1 );
else
insb( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen );
@@ -1824,12 +1858,12 @@ static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst,
}
/* requires call to bap_setup() first */
-static int bap_write(struct airo_info *ai, const u16 *pu16Src,
+static int bap_write(struct airo_info *ai, const u16 *pu16Src,
int bytelen, int whichbap)
{
bytelen = (bytelen + 1) & (~1); // round up to even value
- if ( !do8bitIO )
- outsw( ai->dev->base_addr+DATA0+whichbap,
+ if ( !do8bitIO )
+ outsw( ai->dev->base_addr+DATA0+whichbap,
pu16Src, bytelen>>1 );
else
outsb( ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen );
@@ -1861,7 +1895,7 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len)
long flags;
int rc = SUCCESS;
- spin_lock_irqsave(&ai->bap1_lock, flags);
+ spin_lock_irqsave(&ai->main_lock, flags);
if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != SUCCESS) {
rc = status;
goto done;
@@ -1873,10 +1907,10 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len)
// read the rid length field
bap_read(ai, pBuf, 2, BAP1);
// length for remaining part of rid
- len = min_t(unsigned int, len, le16_to_cpu(*(u16*)pBuf)) - 2;
-
+ len = min(len, (int)le16_to_cpu(*(u16*)pBuf)) - 2;
+
if ( len <= 2 ) {
- printk( KERN_ERR
+ printk( KERN_ERR
"airo: Rid %x has a length of %d which is too short\n",
(int)rid,
(int)len );
@@ -1884,26 +1918,22 @@ static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len)
goto done;
}
// read remainder of the rid
- if (bap_setup(ai, rid, 2, BAP1) != SUCCESS) {
- rc = ERROR;
- goto done;
- }
rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1);
done:
- spin_unlock_irqrestore(&ai->bap1_lock, flags);
+ spin_unlock_irqrestore(&ai->main_lock, flags);
return rc;
}
/* Note, that we are using BAP1 which is also used by transmit, so
* make sure this isnt called when a transmit is happening */
-static int PC4500_writerid(struct airo_info *ai, u16 rid,
+static int PC4500_writerid(struct airo_info *ai, u16 rid,
const void *pBuf, int len)
{
u16 status;
long flags;
int rc = SUCCESS;
- spin_lock_irqsave(&ai->bap1_lock, flags);
+ spin_lock_irqsave(&ai->main_lock, flags);
// --- first access so that we can write the rid data
if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) {
rc = status;
@@ -1918,7 +1948,7 @@ static int PC4500_writerid(struct airo_info *ai, u16 rid,
// ---now commit the rid data
rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
done:
- spin_unlock_irqrestore(&ai->bap1_lock, flags);
+ spin_unlock_irqrestore(&ai->main_lock, flags);
return rc;
}
@@ -1934,7 +1964,7 @@ static u16 transmit_allocate(struct airo_info *ai, int lenPayload)
cmd.cmd = CMD_ALLOCATETX;
cmd.parm0 = lenPayload;
- if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return 0;
+ if (lock_issuecommand(ai, &cmd, &rsp) != SUCCESS) return 0;
if ( (rsp.status & 0xFF00) != 0) return 0;
/* wait for the allocate event/indication
* It makes me kind of nervous that this can just sit here and spin,
@@ -1943,7 +1973,7 @@ static u16 transmit_allocate(struct airo_info *ai, int lenPayload)
// get the allocated fid and acknowledge
txFid = IN4500(ai, TXALLOCFID);
OUT4500(ai, EVACK, EV_ALLOC);
-
+
/* The CARD is pretty cool since it converts the ethernet packet
* into 802.11. Also note that we don't release the FID since we
* will be using the same one over and over again. */
@@ -1951,13 +1981,13 @@ static u16 transmit_allocate(struct airo_info *ai, int lenPayload)
* releasing the fid. */
txControl = cpu_to_le16(TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3
| TXCTL_ETHERNET | TXCTL_NORELEASE);
- spin_lock_irqsave(&ai->bap1_lock, flags);
+ spin_lock_irqsave(&ai->main_lock, flags);
if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS) {
- spin_unlock_irqrestore(&ai->bap1_lock, flags);
+ spin_unlock_irqrestore(&ai->main_lock, flags);
return ERROR;
}
bap_write(ai, &txControl, sizeof(txControl), BAP1);
- spin_unlock_irqrestore(&ai->bap1_lock, flags);
+ spin_unlock_irqrestore(&ai->main_lock, flags);
return txFid;
}
@@ -1965,18 +1995,18 @@ static u16 transmit_allocate(struct airo_info *ai, int lenPayload)
/* In general BAP1 is dedicated to transmiting packets. However,
since we need a BAP when accessing RIDs, we also use BAP1 for that.
Make sure the BAP1 spinlock is held when this is called. */
-static int transmit_802_3_packet(struct airo_info *ai, u16 txFid,
+static int transmit_802_3_packet(struct airo_info *ai, u16 txFid,
char *pPacket, int len)
{
u16 payloadLen;
Cmd cmd;
Resp rsp;
-
+
if (len < 12) {
printk( KERN_WARNING "Short packet %d\n", len );
return ERROR;
}
-
+
// packet is destination[6], source[6], payload[len-12]
// write the payload length and dst/src/payload
if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR;
@@ -2106,7 +2136,7 @@ static int setup_proc_entry( struct net_device *dev,
entry->gid = proc_gid;
entry->data = dev;
SETPROC_OPS(entry, proc_statsdelta_ops);
-
+
/* Setup the Stats */
entry = create_proc_entry("Stats",
S_IFREG | (S_IRUGO&proc_perm),
@@ -2115,7 +2145,7 @@ static int setup_proc_entry( struct net_device *dev,
entry->gid = proc_gid;
entry->data = dev;
SETPROC_OPS(entry, proc_stats_ops);
-
+
/* Setup the Status */
entry = create_proc_entry("Status",
S_IFREG | (S_IRUGO&proc_perm),
@@ -2124,7 +2154,7 @@ static int setup_proc_entry( struct net_device *dev,
entry->gid = proc_gid;
entry->data = dev;
SETPROC_OPS(entry, proc_status_ops);
-
+
/* Setup the Config */
entry = create_proc_entry("Config",
S_IFREG | proc_perm,
@@ -2208,9 +2238,9 @@ static ssize_t proc_read( struct file *file,
int i;
int pos;
struct proc_data *priv = (struct proc_data*)file->private_data;
-
+
if( !priv->rbuffer ) return -EINVAL;
-
+
pos = *offset;
for( i = 0; i+pos < priv->readlen && i < len; i++ ) {
if (put_user( priv->rbuffer[i+pos], buffer+i ))
@@ -2227,18 +2257,18 @@ static ssize_t proc_read( struct file *file,
static ssize_t proc_write( struct file *file,
const char *buffer,
size_t len,
- loff_t *offset )
+ loff_t *offset )
{
int i;
int pos;
struct proc_data *priv = (struct proc_data*)file->private_data;
-
+
if ( !priv->wbuffer ) {
return -EINVAL;
}
-
+
pos = *offset;
-
+
for( i = 0; i + pos < priv->maxwritelen &&
i < len; i++ ) {
if (get_user( priv->wbuffer[i+pos], buffer + i ))
@@ -2257,11 +2287,11 @@ static int proc_status_open( struct inode *inode, struct file *file ) {
CapabilityRid cap_rid;
StatusRid status_rid;
int i;
-
+
MOD_INC_USE_COUNT;
-
+
dp = inode->u.generic_ip;
-
+
if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2270,10 +2300,10 @@ static int proc_status_open( struct inode *inode, struct file *file ) {
kfree (file->private_data);
return -ENOMEM;
}
-
+
readStatusRid(apriv, &status_rid);
readCapabilityRid(apriv, &cap_rid);
-
+
i = sprintf(data->rbuffer, "Status: %s%s%s%s%s%s%s%s%s\n",
status_rid.mode & 1 ? "CFG ": "",
status_rid.mode & 2 ? "ACT ": "",
@@ -2319,7 +2349,7 @@ static int proc_status_open( struct inode *inode, struct file *file ) {
}
static int proc_stats_rid_open(struct inode*, struct file*, u16);
-static int proc_statsdelta_open( struct inode *inode,
+static int proc_statsdelta_open( struct inode *inode,
struct file *file ) {
if (file->f_mode&FMODE_WRITE) {
return proc_stats_rid_open(inode, file, RID_STATSDELTACLEAR);
@@ -2331,7 +2361,7 @@ static int proc_stats_open( struct inode *inode, struct file *file ) {
return proc_stats_rid_open(inode, file, RID_STATS);
}
-static int proc_stats_rid_open( struct inode *inode,
+static int proc_stats_rid_open( struct inode *inode,
struct file *file,
u16 rid ) {
struct proc_data *data;
@@ -2342,10 +2372,10 @@ static int proc_stats_rid_open( struct inode *inode,
int i, j;
int *vals = stats.vals;
MOD_INC_USE_COUNT;
-
-
+
+
dp = inode->u.generic_ip;
-
+
if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2354,11 +2384,11 @@ static int proc_stats_rid_open( struct inode *inode,
kfree (file->private_data);
return -ENOMEM;
}
-
+
readStatsRid(apriv, &stats, rid);
-
+
j = 0;
- for(i=0; (int)statsLabels[i]!=-1 &&
+ for(i=0; (int)statsLabels[i]!=-1 &&
i*4<stats.len; i++){
if (!statsLabels[i]) continue;
if (j+strlen(statsLabels[i])+16>4096) {
@@ -2411,10 +2441,10 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
Resp rsp;
char *line;
int need_reset = 0;
-
+
if ( !data->writelen ) return;
dp = (struct proc_dir_entry *) inode->u.generic_ip;
-
+
disable_MAC(ai);
readConfigRid(ai, &config);
@@ -2442,7 +2472,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
need_reset = 1;
}
}
-
+
/*** Radio status */
else if (!strncmp(line,"Radio: ", 7)) {
line += 7;
@@ -2455,15 +2485,15 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
/*** NodeName processing */
else if ( !strncmp( line, "NodeName: ", 10 ) ) {
int j;
-
+
line += 10;
memset( config.nodeName, 0, 16 );
/* Do the name, assume a space between the mode and node name */
for( j = 0; j < 16 && line[j] != '\n'; j++ ) {
config.nodeName[j] = line[j];
}
- }
-
+ }
+
/*** PowerMode processing */
else if ( !strncmp( line, "PowerMode: ", 11 ) ) {
line += 11;
@@ -2473,11 +2503,11 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
config.powerSaveMode = POWERSAVE_PSP;
} else {
config.powerSaveMode = POWERSAVE_CAM;
- }
+ }
} else if ( !strncmp( line, "DataRates: ", 11 ) ) {
- int v, i = 0, k = 0; /* i is index into line,
+ int v, i = 0, k = 0; /* i is index into line,
k is index to rates */
-
+
line += 11;
while((v = get_dec_u16(line, &i, 3))!=-1) {
config.rates[k++] = (u8)v;
@@ -2488,7 +2518,7 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
int v, i = 0;
line += 9;
v = get_dec_u16(line, &i, i+3);
- if ( v != -1 )
+ if ( v != -1 )
config.channelSet = (u16)v;
} else if ( !strncmp( line, "XmitPower: ", 11 ) ) {
int v, i = 0;
@@ -2510,50 +2540,50 @@ static void proc_config_on_close( struct inode *inode, struct file *file ) {
}
} else if ( !strncmp( line, "LongRetryLimit: ", 16 ) ) {
int v, i = 0;
-
+
line += 16;
v = get_dec_u16(line, &i, 3);
v = (v<0) ? 0 : ((v>255) ? 255 : v);
config.longRetryLimit = (u16)v;
} else if ( !strncmp( line, "ShortRetryLimit: ", 17 ) ) {
int v, i = 0;
-
+
line += 17;
v = get_dec_u16(line, &i, 3);
v = (v<0) ? 0 : ((v>255) ? 255 : v);
config.shortRetryLimit = (u16)v;
} else if ( !strncmp( line, "RTSThreshold: ", 14 ) ) {
int v, i = 0;
-
+
line += 14;
v = get_dec_u16(line, &i, 4);
v = (v<0) ? 0 : ((v>2312) ? 2312 : v);
config.rtsThres = (u16)v;
} else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) {
int v, i = 0;
-
+
line += 16;
v = get_dec_u16(line, &i, 5);
v = (v<0) ? 0 : v;
config.txLifetime = (u16)v;
} else if ( !strncmp( line, "RXMSDULifetime: ", 16 ) ) {
int v, i = 0;
-
+
line += 16;
v = get_dec_u16(line, &i, 5);
v = (v<0) ? 0 : v;
config.rxLifetime = (u16)v;
} else if ( !strncmp( line, "TXDiversity: ", 13 ) ) {
- config.txDiversity =
+ config.txDiversity =
(line[13]=='l') ? 1 :
((line[13]=='r')? 2: 3);
} else if ( !strncmp( line, "RXDiversity: ", 13 ) ) {
- config.rxDiversity =
+ config.rxDiversity =
(line[13]=='l') ? 1 :
((line[13]=='r')? 2: 3);
} else if ( !strncmp( line, "FragThreshold: ", 15 ) ) {
int v, i = 0;
-
+
line += 15;
v = get_dec_u16(line, &i, 4);
v = (v<256) ? 256 : ((v>2312) ? 2312 : v);
@@ -2605,11 +2635,11 @@ static int proc_config_open( struct inode *inode, struct file *file ) {
struct airo_info *ai = (struct airo_info*)dev->priv;
ConfigRid config;
int i;
-
+
MOD_INC_USE_COUNT;
-
+
dp = (struct proc_dir_entry *) inode->u.generic_ip;
-
+
if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2626,10 +2656,10 @@ static int proc_config_open( struct inode *inode, struct file *file ) {
memset( data->wbuffer, 0, 2048 );
data->maxwritelen = 2048;
data->on_close = proc_config_on_close;
-
+
readConfigRid(ai, &config);
-
- i = sprintf( data->rbuffer,
+
+ i = sprintf( data->rbuffer,
"Mode: %s\n"
"Radio: %s\n"
"NodeName: %-16s\n"
@@ -2637,9 +2667,9 @@ static int proc_config_open( struct inode *inode, struct file *file ) {
"DataRates: %d %d %d %d %d %d %d %d\n"
"Channel: %d\n"
"XmitPower: %d\n",
- config.opmode == 0 ? "adhoc" :
+ config.opmode == 0 ? "adhoc" :
config.opmode == 1 ? "ESS" :
- config.opmode == 2 ? "AP" :
+ config.opmode == 2 ? "AP" :
config.opmode == 3 ? "AP RPTR" : "Error",
ai->flags&FLAG_RADIO_OFF ? "off" : "on",
config.nodeName,
@@ -2700,11 +2730,11 @@ static void proc_SSID_on_close( struct inode *inode, struct file *file ) {
SsidRid SSID_rid;
int i;
int offset = 0;
-
+
if ( !data->writelen ) return;
-
+
memset( &SSID_rid, 0, sizeof( SSID_rid ) );
-
+
for( i = 0; i < 3; i++ ) {
int j;
for( j = 0; j+offset < data->writelen && j < 32 &&
@@ -2714,7 +2744,7 @@ static void proc_SSID_on_close( struct inode *inode, struct file *file ) {
if ( j == 0 ) break;
SSID_rid.ssids[i].len = j;
offset += j;
- while( data->wbuffer[offset] != '\n' &&
+ while( data->wbuffer[offset] != '\n' &&
offset < data->writelen ) offset++;
offset++;
}
@@ -2735,12 +2765,12 @@ static void proc_APList_on_close( struct inode *inode, struct file *file ) {
struct airo_info *ai = (struct airo_info*)dev->priv;
APListRid APList_rid;
int i;
-
+
if ( !data->writelen ) return;
-
+
memset( &APList_rid, 0, sizeof(APList_rid) );
APList_rid.len = sizeof(APList_rid);
-
+
for( i = 0; i < 4 && data->writelen >= (i+1)*6*3; i++ ) {
int j;
for( j = 0; j < 6*3 && data->wbuffer[j+i*6*3]; j++ ) {
@@ -2764,7 +2794,7 @@ static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data,
int len ) {
int rc;
Resp rsp;
-
+
disable_MAC(ai);
rc = PC4500_writerid(ai, rid, rid_data, len);
enable_MAC(ai, &rsp);
@@ -2816,7 +2846,7 @@ static int set_wep_key(struct airo_info *ai, u16 index,
memcpy( wkr.mac, macaddr, 6 );
printk(KERN_INFO "Setting key %d\n", index);
}
-
+
writeWepKeyRid(ai, &wkr, perm);
return 0;
}
@@ -2832,11 +2862,11 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
int j = 0;
memset(key, 0, sizeof(key));
-
+
dp = (struct proc_dir_entry *) inode->u.generic_ip;
data = (struct proc_data *)file->private_data;
if ( !data->writelen ) return;
-
+
if (data->wbuffer[0] >= '0' && data->wbuffer[0] <= '3' &&
(data->wbuffer[1] == ' ' || data->wbuffer[1] == '\n')) {
index = data->wbuffer[0] - '0';
@@ -2873,11 +2903,11 @@ static int proc_wepkey_open( struct inode *inode, struct file *file ) {
u16 lastindex;
int j=0;
int rc;
-
+
MOD_INC_USE_COUNT;
-
+
dp = (struct proc_dir_entry *) inode->u.generic_ip;
-
+
if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2897,7 +2927,7 @@ static int proc_wepkey_open( struct inode *inode, struct file *file ) {
}
memset( data->wbuffer, 0, 80 );
data->on_close = proc_wepkey_on_close;
-
+
ptr = data->rbuffer;
strcpy(ptr, "No wep keys\n");
rc = readWepKeyRid(ai, &wkr, 1);
@@ -2927,9 +2957,9 @@ static int proc_SSID_open( struct inode *inode, struct file *file ) {
SsidRid SSID_rid;
MOD_INC_USE_COUNT;
-
+
dp = (struct proc_dir_entry *) inode->u.generic_ip;
-
+
if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2947,16 +2977,16 @@ static int proc_SSID_open( struct inode *inode, struct file *file ) {
}
memset( data->wbuffer, 0, 33*3 );
data->on_close = proc_SSID_on_close;
-
+
readSsidRid(ai, &SSID_rid);
ptr = data->rbuffer;
for( i = 0; i < 3; i++ ) {
int j;
if ( !SSID_rid.ssids[i].len ) break;
- for( j = 0; j < 32 &&
- j < SSID_rid.ssids[i].len &&
+ for( j = 0; j < 32 &&
+ j < SSID_rid.ssids[i].len &&
SSID_rid.ssids[i].ssid[j]; j++ ) {
- *ptr++ = SSID_rid.ssids[i].ssid[j];
+ *ptr++ = SSID_rid.ssids[i].ssid[j];
}
*ptr++ = '\n';
}
@@ -2975,9 +3005,9 @@ static int proc_APList_open( struct inode *inode, struct file *file ) {
APListRid APList_rid;
MOD_INC_USE_COUNT;
-
+
dp = (struct proc_dir_entry *) inode->u.generic_ip;
-
+
if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
memset(file->private_data, 0, sizeof(struct proc_data));
@@ -2995,7 +3025,7 @@ static int proc_APList_open( struct inode *inode, struct file *file ) {
}
memset( data->wbuffer, 0, data->maxwritelen );
data->on_close = proc_APList_on_close;
-
+
readAPListRid(ai, &APList_rid);
ptr = data->rbuffer;
for( i = 0; i < 4; i++ ) {
@@ -3027,11 +3057,11 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
int rc;
/* If doLoseSync is not 1, we won't do a Lose Sync */
int doLoseSync = -1;
-
+
MOD_INC_USE_COUNT;
-
+
dp = (struct proc_dir_entry *) inode->u.generic_ip;
-
+
if ((file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
return -ENOMEM;
memset(file->private_data, 0, sizeof(struct proc_data));
@@ -3044,15 +3074,15 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
data->maxwritelen = 0;
data->wbuffer = 0;
data->on_close = 0;
-
+
if (file->f_mode & FMODE_WRITE) {
if (!(file->f_mode & FMODE_READ)) {
Cmd cmd;
Resp rsp;
-
+
memset(&cmd, 0, sizeof(cmd));
cmd.cmd=CMD_LISTBSS;
- issuecommand(ai, &cmd, &rsp);
+ lock_issuecommand(ai, &cmd, &rsp);
data->readlen = 0;
return 0;
}
@@ -3087,7 +3117,7 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) {
return 0;
}
-static int proc_close( struct inode *inode, struct file *file )
+static int proc_close( struct inode *inode, struct file *file )
{
struct proc_data *data = (struct proc_data *)file->private_data;
if ( data->on_close != NULL ) data->on_close( inode, file );
@@ -3112,7 +3142,7 @@ static void timer_func( u_long data ) {
struct net_device *dev = (struct net_device*)data;
struct airo_info *apriv = (struct airo_info *)dev->priv;
u16 linkstat = IN4500(apriv, LINKSTAT);
-
+
if (linkstat != 0x400 ) {
/* We don't have a link so try changing the authtype */
ConfigRid config = apriv->config;
@@ -3158,13 +3188,13 @@ static int add_airo_dev( struct net_device *dev ) {
if ( auto_wep ) {
struct airo_info *apriv=dev->priv;
struct timer_list *timer = &apriv->timer;
-
+
timer->function = timer_func;
timer->data = (u_long)dev;
init_timer(timer);
apriv->authtype = AUTH_SHAREDKEY;
}
-
+
node->dev = dev;
node->next = airo_devices;
airo_devices = node;
@@ -3177,14 +3207,14 @@ static void del_airo_dev( struct net_device *dev ) {
while( *p && ( (*p)->dev != dev ) )
p = &(*p)->next;
if ( *p && (*p)->dev == dev )
- *p = (*p)->next;
+ *p = (*p)->next;
}
#ifdef CONFIG_PCI
-static int __devinit airo_pci_probe(struct pci_dev *pdev,
+static int __devinit airo_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *pent)
{
- pdev->driver_data = init_airo_card(pdev->irq,
+ pdev->driver_data = init_airo_card(pdev->irq,
pdev->resource[2].start, 0);
if (!pdev->driver_data) {
return -ENODEV;
@@ -3201,21 +3231,21 @@ static void __devexit airo_pci_remove(struct pci_dev *pdev)
static int __init airo_init_module( void )
{
int i, rc = 0, have_isa_dev = 0;
-
+
airo_entry = create_proc_entry("aironet",
S_IFDIR | airo_perm,
proc_root_driver);
airo_entry->uid = proc_uid;
airo_entry->gid = proc_gid;
-
+
for( i = 0; i < 4 && io[i] && irq[i]; i++ ) {
- printk( KERN_INFO
+ printk( KERN_INFO
"airo: Trying to configure ISA adapter at irq=%d io=0x%x\n",
irq[i], io[i] );
if (init_airo_card( irq[i], io[i], 0 ))
have_isa_dev = 1;
}
-
+
#ifdef CONFIG_PCI
printk( KERN_INFO "airo: Probing for PCI adapters\n" );
rc = pci_module_init(&airo_driver);
@@ -3274,7 +3304,11 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
StatusRid status_rid; /* Card status info */
#ifdef CISCO_EXT
- if (cmd != SIOCGIWPRIV && cmd != AIROIOCTL && cmd != AIROIDIFC)
+ if (cmd != SIOCGIWPRIV && cmd != AIROIOCTL && cmd != AIROIDIFC
+#ifdef AIROOLDIOCTL
+ && cmd != AIROOLDIOCTL && cmd != AIROOLDIDIFC
+#endif
+ )
#endif /* CISCO_EXT */
{
/* If the command read some stuff, we better get it out of
@@ -3851,7 +3885,7 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
/* Hum... Should put the right values there */
range.max_qual.qual = 10;
- range.max_qual.level = 0;
+ range.max_qual.level = 0x100 - 120; /* -120 dBm */
range.max_qual.noise = 0;
range.sensitivity = 65535;
@@ -3908,7 +3942,7 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
range.txpower_capa = IW_TXPOW_MWATT;
#endif /* WIRELESS_EXT > 9 */
#if WIRELESS_EXT > 10
- range.we_version_source = 11;
+ range.we_version_source = 12;
range.we_version_compiled = WIRELESS_EXT;
range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
range.retry_flags = IW_RETRY_LIMIT;
@@ -3918,6 +3952,17 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
range.min_r_time = 1024;
range.max_r_time = 65535 * 1024;
#endif /* WIRELESS_EXT > 10 */
+#if WIRELESS_EXT > 11
+ /* Experimental measurements - boundary 11/5.5 Mb/s */
+ /* Note : with or without the (local->rssi), results
+ * are somewhat different. - Jean II */
+ range.avg_qual.qual = 6;
+ if (local->rssi)
+ range.avg_qual.level = 186; /* -70 dBm */
+ else
+ range.avg_qual.level = 176; /* -80 dBm */
+ range.avg_qual.noise = 0;
+#endif /* WIRELESS_EXT > 11 */
if (copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range)))
rc = -EFAULT;
@@ -3943,7 +3988,7 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
}
break;
- case SIOCSIWPOWER:
+ case SIOCSIWPOWER:
if (wrq->u.power.disabled) {
if ((config.rmode & 0xFF) >= RXMODE_RFMON) {
rc = -EINVAL;
@@ -4022,7 +4067,7 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (BSSList.index == 0xffff) break;
}
if (!i) {
- for (i = 0;
+ for (i = 0;
i < min(IW_MAX_AP, 4) &&
(status_rid.bssid[i][0]
& status_rid.bssid[i][1]
@@ -4037,7 +4082,7 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
| status_rid.bssid[i][4]
| status_rid.bssid[i][5]);
i++) {
- memcpy(s[i].sa_data,
+ memcpy(s[i].sa_data,
status_rid.bssid[i], 6);
s[i].sa_family = ARPHRD_ETHER;
}
@@ -4050,7 +4095,7 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
rc = -EFAULT;
}
wrq->u.data.length = i;
- if (copy_to_user(wrq->u.data.pointer, &s,
+ if (copy_to_user(wrq->u.data.pointer, &s,
sizeof(struct sockaddr)*i))
rc = -EFAULT;
}
@@ -4134,6 +4179,9 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
#ifdef CISCO_EXT
case AIROIDIFC:
+#ifdef AIROOLDIDIFC
+ case AIROOLDIDIFC:
+#endif
{
int val = AIROMAGIC;
aironet_ioctl com;
@@ -4143,9 +4191,12 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
rc = -EFAULT;
}
break;
-
+
case AIROIOCTL:
- /* Get the command struct and hand it off for evaluation by
+#ifdef AIROOLDIOCTL
+ case AIROOLDIOCTL:
+#endif
+ /* Get the command struct and hand it off for evaluation by
* the proper subfunction
*/
{
@@ -4209,8 +4260,6 @@ static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
* TODO :
* o Check if work in Ad-Hoc mode (otherwise, use SPY, as in wvlan_cs)
* o Find the noise level
- * o Convert values to dBm
- * o Fill out discard.misc with something interesting
*
* Jean
*/
@@ -4219,7 +4268,7 @@ struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
struct airo_info *local = (struct airo_info*) dev->priv;
StatusRid status_rid;
StatsRid stats_rid;
- int *vals = stats_rid.vals;
+ u32 *vals = stats_rid.vals;
/* Get stats out of the card */
readStatusRid(local, &status_rid);
@@ -4241,21 +4290,28 @@ struct iw_statistics *airo_get_wireless_stats(struct net_device *dev)
* specific problems */
local->wstats.discard.nwid = vals[56] + vals[57] + vals[58];/* SSID Mismatch */
local->wstats.discard.code = vals[6];/* RxWepErr */
- local->wstats.discard.misc = vals[1] + vals[2] + vals[3] + vals[4] + vals[30] + vals[32];
+#if WIRELESS_EXT > 11
+ local->wstats.discard.fragment = vals[30];
+ local->wstats.discard.retries = vals[10];
+ local->wstats.discard.misc = vals[1] + vals[32];
+ local->wstats.miss.beacon = vals[34];
+#else /* WIRELESS_EXT > 11 */
+ local->wstats.discard.misc = vals[1] + vals[30] + vals[32];
+#endif /* WIRELESS_EXT > 11 */
return (&local->wstats);
}
#endif /* WIRELESS_EXT */
#ifdef CISCO_EXT
/*
- * This just translates from driver IOCTL codes to the command codes to
- * feed to the radio's host interface. Things can be added/deleted
- * as needed. This represents the READ side of control I/O to
+ * This just translates from driver IOCTL codes to the command codes to
+ * feed to the radio's host interface. Things can be added/deleted
+ * as needed. This represents the READ side of control I/O to
* the card
*/
static int readrids(struct net_device *dev, aironet_ioctl *comp) {
unsigned short ridcode;
- unsigned char iobuf[2048];
+ unsigned char iobuf[2048];
switch(comp->command)
{
@@ -4279,18 +4335,18 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
case AIROGSTATSD32: ridcode = RID_STATSDELTA; break;
case AIROGSTATSC32: ridcode = RID_STATS; break;
default:
- return -EINVAL;
+ return -EINVAL;
break;
}
PC4500_readrid((struct airo_info *)dev->priv,ridcode,iobuf,sizeof(iobuf));
/* get the count of bytes in the rid docs say 1st 2 bytes is it.
- * then return it to the user
+ * then return it to the user
* 9/22/2000 Honor user given length
*/
if (copy_to_user(comp->data, iobuf,
- min_t(unsigned int, comp->len, sizeof(iobuf))))
+ min((int)comp->len, (int)sizeof(iobuf))))
return -EFAULT;
return 0;
}
@@ -4303,7 +4359,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
int ridcode;
Resp rsp;
static int (* writer)(struct airo_info *, u16 rid, const void *, int);
- unsigned char iobuf[2048];
+ unsigned char iobuf[2048];
/* Only super-user can write RIDs */
if (!capable(CAP_NET_ADMIN))
@@ -4324,7 +4380,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
case AIROPWEPKEY: ridcode = RID_WEP_TEMP; writer = PC4500_writerid;
break;
- /* this is not really a rid but a command given to the card
+ /* this is not really a rid but a command given to the card
* same with MAC off
*/
case AIROPMACON:
@@ -4332,7 +4388,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
return -EIO;
return 0;
- /*
+ /*
* Evidently this code in the airo driver does not get a symbol
* as disable_MAC. it's probably so short the compiler does not gen one.
*/
@@ -4350,7 +4406,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
PC4500_readrid(dev->priv,ridcode,iobuf,sizeof(iobuf));
if (copy_to_user(comp->data, iobuf,
- min_t(unsigned int, comp->len, sizeof(iobuf))))
+ min((int)comp->len, (int)sizeof(iobuf))))
return -EFAULT;
return 0;
@@ -4372,7 +4428,7 @@ static int writerids(struct net_device *dev, aironet_ioctl *comp) {
*****************************************************************************
*/
-/*
+/*
* Flash command switch table
*/
@@ -4435,10 +4491,10 @@ int flashcard(struct net_device *dev, aironet_ioctl *comp) {
#define FLASH_COMMAND 0x7e7e
-/*
+/*
* STEP 1)
- * Disable MAC and do soft reset on
- * card.
+ * Disable MAC and do soft reset on
+ * card.
*/
int cmdreset(struct airo_info *ai) {
@@ -4448,7 +4504,7 @@ int cmdreset(struct airo_info *ai) {
printk(KERN_INFO "Waitbusy hang before RESET\n");
return -EBUSY;
}
-
+
OUT4500(ai,COMMAND,CMD_SOFTRESET);
set_current_state (TASK_UNINTERRUPTIBLE);
@@ -4462,7 +4518,7 @@ int cmdreset(struct airo_info *ai) {
}
/* STEP 2)
- * Put the card in legendary flash
+ * Put the card in legendary flash
* mode
*/
@@ -4473,7 +4529,7 @@ int setflashmode (struct airo_info *ai) {
OUT4500(ai, COMMAND,0x10);
set_current_state (TASK_UNINTERRUPTIBLE);
schedule_timeout (HZ/2); /* 500ms delay */
-
+
if(!waitbusy(ai)) {
printk(KERN_INFO "Waitbusy hang after setflash mode\n");
return -EIO;
@@ -4481,8 +4537,8 @@ int setflashmode (struct airo_info *ai) {
return 0;
}
-/* Put character to SWS0 wait for dwelltime
- * x 50us for echo .
+/* Put character to SWS0 wait for dwelltime
+ * x 50us for echo .
*/
int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
@@ -4493,7 +4549,7 @@ int flashpchar(struct airo_info *ai,int byte,int dwelltime) {
if(dwelltime == 0 )
dwelltime = 200;
-
+
waittime=dwelltime;
/* Wait for busy bit d15 to go false indicating buffer empty */
@@ -4531,7 +4587,7 @@ int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){
do {
rchar = IN4500(ai,SWS1);
-
+
if(dwelltime && !(0x8000 & rchar)){
dwelltime -= 10;
mdelay(10);
@@ -4551,9 +4607,9 @@ int flashgchar(struct airo_info *ai,int matchbyte,int dwelltime){
return -EIO;
}
-/*
- * Transfer 32k of firmware data from user buffer to our buffer and
- * send to the card
+/*
+ * Transfer 32k of firmware data from user buffer to our buffer and
+ * send to the card
*/
int flashputbuf(struct airo_info *ai){
@@ -4566,7 +4622,7 @@ int flashputbuf(struct airo_info *ai){
for(nwords=0;nwords != FLASHSIZE / 2;nwords++){
OUT4500(ai,AUXDATA,ai->flash[nwords] & 0xffff);
}
-
+
OUT4500(ai,SWS0,0x8000);
return 0;
@@ -4628,7 +4684,7 @@ int flashrestart(struct airo_info *ai,struct net_device *dev){
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- POSSIBILITY OF SUCH DAMAGE.
+ POSSIBILITY OF SUCH DAMAGE.
*/
module_init(airo_init_module);
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 0f955e76db72..e169ad56faf8 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -38,10 +38,13 @@
* Fix three endian-ness bugs
* Support dual function SYM53C885E ethernet chip
+ LK1.1.5 (val@nmt.edu):
+ * Fix forced full-duplex bug I introduced
+
*/
#define DRV_NAME "yellowfin"
-#define DRV_VERSION "1.05+LK1.1.3"
+#define DRV_VERSION "1.05+LK1.1.5"
#define DRV_RELDATE "May 10, 2001"
#define PFX DRV_NAME ": "
@@ -256,7 +259,7 @@ enum pci_id_flags_bits {
};
enum capability_flags {
HasMII=1, FullTxStatus=2, IsGigabit=4, HasMulticastBug=8, FullRxStatus=16,
- HasMACAddrBug=32, /* Only on early revs. */
+ HasMACAddrBug=32, DontUseEeprom=64, /* Only on early revs. */
};
/* The PCI I/O space extent. */
#define YELLOWFIN_SIZE 0x100
@@ -282,7 +285,7 @@ static struct pci_id_info pci_id_tbl[] = {
PCI_IOTYPE, YELLOWFIN_SIZE,
FullTxStatus | IsGigabit | HasMulticastBug | HasMACAddrBug},
{"Symbios SYM83C885", { 0x07011000, 0xffffffff},
- PCI_IOTYPE, YELLOWFIN_SIZE, HasMII | IsGigabit | FullTxStatus },
+ PCI_IOTYPE, YELLOWFIN_SIZE, HasMII | DontUseEeprom },
{0,},
};
@@ -453,7 +456,7 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev,
#endif
irq = pdev->irq;
- if (drv_flags & IsGigabit)
+ if (drv_flags & DontUseEeprom)
for (i = 0; i < 6; i++)
dev->dev_addr[i] = inb(ioaddr + StnAddr + i);
else {
diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids
index b566eb0e03a1..6ebf1c22d089 100644
--- a/drivers/pci/pci.ids
+++ b/drivers/pci/pci.ids
@@ -106,9 +106,16 @@
0012 53c895a
0020 53c1010 Ultra3 SCSI Adapter
0021 53c1010 66MHz Ultra3 SCSI Adapter
+ 0030 53c1030
+ 0040 53c1035
008f 53c875J
1092 8000 FirePort 40 SCSI Controller
1092 8760 FirePort 40 Dual SCSI Host Adapter
+ 0621 FC909
+ 0622 FC929
+ 0623 FC929 LAN
+ 0624 FC919
+ 0625 FC919 LAN
0701 83C885
0702 Yellowfin G-NIC gigabit ethernet
1318 0000 PEI100X
@@ -2085,6 +2092,7 @@
110a Siemens Nixdorf AG
0002 Pirahna 2-port
0005 Tulip controller, power management, switch extender
+ 2102 DSCC4 WAN adapter
4942 FPGA I-Bus Tracer for MBD
6120 SZB6120
110b Chromatic Research Inc.
@@ -2310,7 +2318,7 @@
1148 5841 FDDI SK-5841 (SK-NET FDDI-FP64)
1148 5843 FDDI SK-5843 (SK-NET FDDI-LP64)
1148 5844 FDDI SK-5844 (SK-NET FDDI-LP64 DAS)
- 4200 Token ring adaptor
+ 4200 Token Ring adapter
4300 Gigabit Ethernet
1148 9821 SK-9821 (1000Base-T single link)
1148 9822 SK-9822 (1000Base-T dual link)
@@ -4080,6 +4088,7 @@
14e4 0007 NetXtreme BCM5701 1000BaseSX
14e4 0008 NetXtreme BCM5701 1000BaseTX
14e4 8008 NetXtreme BCM5701 1000BaseTX
+ 5820 BCM5820 Crypto Accelerator
14e5 Pixelfusion Ltd
14e6 SHINING Technology Inc
14e7 3CX
@@ -4823,7 +4832,7 @@
0e11 b0c6 Embedded NC3120 with Wake on LAN
0e11 b0c7 Embedded NC3121
0e11 b0d7 NC3121 with Wake on LAN
- 0e11 b0dd NC3131
+ 0e11 b0dd NC3131 (82558B)
0e11 b0de NC3132
0e11 b0e1 NC3133
0e11 b144 NC3123 (82559)
@@ -4891,6 +4900,8 @@
1a21 82840 840 (Carmel) Chipset Host Bridge (Hub A)
1a23 82840 840 (Carmel) Chipset AGP Bridge
1a24 82840 840 (Carmel) Chipset PCI Bridge (Hub B)
+ 1a30 82845 845 (Brookdale) Chipset Host Bridge
+ 1a31 82845 845 (Brookdale) Chipset AGP Bridge
2410 82801AA ISA Bridge (LPC)
2411 82801AA IDE
2412 82801AA USB
diff --git a/drivers/scsi/qlogicfc.h b/drivers/scsi/qlogicfc.h
index 10539d3db8fc..8128e99132b6 100644
--- a/drivers/scsi/qlogicfc.h
+++ b/drivers/scsi/qlogicfc.h
@@ -62,13 +62,8 @@
* determined for each queue request anew.
*/
-#if BITS_PER_LONG > 32
#define DATASEGS_PER_COMMAND 2
#define DATASEGS_PER_CONT 5
-#else
-#define DATASEGS_PER_COMMAND 3
-#define DATASEGS_PER_CONT 7
-#endif
#define QLOGICFC_REQ_QUEUE_LEN 127 /* must be power of two - 1 */
#define QLOGICFC_MAX_SG(ql) (DATASEGS_PER_COMMAND + (((ql) > 0) ? DATASEGS_PER_CONT*((ql) - 1) : 0))
diff --git a/drivers/usb/devices.c b/drivers/usb/devices.c
index ef4db5c5db78..e3071c87491e 100644
--- a/drivers/usb/devices.c
+++ b/drivers/usb/devices.c
@@ -488,7 +488,7 @@ static ssize_t usb_device_read(struct file *file, char *buf, size_t nbytes, loff
return -EFAULT;
/* enumerate busses */
- read_lock_irq (&usb_bus_list_lock);
+ down (&usb_bus_list_lock);
for (buslist = usb_bus_list.next; buslist != &usb_bus_list; buslist = buslist->next) {
/* print devices for this bus */
bus = list_entry(buslist, struct usb_bus, bus_list);
@@ -498,7 +498,7 @@ static ssize_t usb_device_read(struct file *file, char *buf, size_t nbytes, loff
return ret;
total_written += ret;
}
- read_unlock_irq (&usb_bus_list_lock);
+ up (&usb_bus_list_lock);
return total_written;
}
diff --git a/drivers/usb/hiddev.c b/drivers/usb/hiddev.c
index a461ce679f60..982f366fe41a 100644
--- a/drivers/usb/hiddev.c
+++ b/drivers/usb/hiddev.c
@@ -264,7 +264,7 @@ static ssize_t hiddev_read(struct file * file, char * buffer, size_t count,
if (list->head == list->tail) {
add_wait_queue(&list->hiddev->wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
while (list->head == list->tail) {
@@ -284,7 +284,7 @@ static ssize_t hiddev_read(struct file * file, char * buffer, size_t count,
schedule();
}
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
remove_wait_queue(&list->hiddev->wait, &wait);
}
diff --git a/drivers/usb/inode.c b/drivers/usb/inode.c
index 59c03519dc07..0c348ed80ff3 100644
--- a/drivers/usb/inode.c
+++ b/drivers/usb/inode.c
@@ -260,15 +260,15 @@ static struct usb_bus *usbdevfs_findbus(int busnr)
struct list_head *list;
struct usb_bus *bus;
- read_lock_irq (&usb_bus_list_lock);
+ down (&usb_bus_list_lock);
for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) {
bus = list_entry(list, struct usb_bus, bus_list);
if (bus->busnum == busnr) {
- read_unlock_irq (&usb_bus_list_lock);
+ up (&usb_bus_list_lock);
return bus;
}
}
- read_unlock_irq (&usb_bus_list_lock);
+ up (&usb_bus_list_lock);
return NULL;
}
@@ -416,7 +416,7 @@ static int usbdevfs_root_readdir(struct file *filp, void *dirent, filldir_t fill
if (i < 2+NRSPECIAL)
return 0;
i -= 2+NRSPECIAL;
- read_lock_irq (&usb_bus_list_lock);
+ down (&usb_bus_list_lock);
for (list = usb_bus_list.next; list != &usb_bus_list; list = list->next) {
if (i > 0) {
i--;
@@ -428,7 +428,7 @@ static int usbdevfs_root_readdir(struct file *filp, void *dirent, filldir_t fill
break;
filp->f_pos++;
}
- read_unlock_irq (&usb_bus_list_lock);
+ up (&usb_bus_list_lock);
return 0;
}
}
@@ -639,13 +639,13 @@ struct super_block *usbdevfs_read_super(struct super_block *s, void *data, int s
list_add_tail(&inode->u.usbdev_i.slist, &s->u.usbdevfs_sb.ilist);
list_add_tail(&inode->u.usbdev_i.dlist, &special[i].inodes);
}
- read_lock_irq (&usb_bus_list_lock);
+ down (&usb_bus_list_lock);
for (blist = usb_bus_list.next; blist != &usb_bus_list; blist = blist->next) {
bus = list_entry(blist, struct usb_bus, bus_list);
new_bus_inode(bus, s);
recurse_new_dev_inode(bus->root_hub, s);
}
- read_unlock_irq (&usb_bus_list_lock);
+ up (&usb_bus_list_lock);
return s;
out_no_root:
diff --git a/drivers/usb/kaweth.c b/drivers/usb/kaweth.c
index 050b4f0fbe02..8a4432065435 100644
--- a/drivers/usb/kaweth.c
+++ b/drivers/usb/kaweth.c
@@ -969,14 +969,14 @@ static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
init_waitqueue_head(&awd.wqh);
awd.done = 0;
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&awd.wqh, &wait);
urb->context = &awd;
status = usb_submit_urb(urb);
if (status) {
// something went wrong
usb_free_urb(urb);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
remove_wait_queue(&awd.wqh, &wait);
return status;
}
@@ -984,7 +984,7 @@ static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
while (timeout && !awd.done)
timeout = schedule_timeout(timeout);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
remove_wait_queue(&awd.wqh, &wait);
if (!timeout) {
diff --git a/drivers/usb/scanner.c b/drivers/usb/scanner.c
index 0fff71177e86..ed98f11f4063 100644
--- a/drivers/usb/scanner.c
+++ b/drivers/usb/scanner.c
@@ -1,9 +1,9 @@
/* -*- linux-c -*- */
/*
- * Driver for USB Scanners (linux-2.4.0)
+ * Driver for USB Scanners (linux-2.4.12)
*
- * Copyright (C) 1999, 2000 David E. Nelson
+ * Copyright (C) 1999, 2000, 2001 David E. Nelson
*
* Portions may be copyright Brad Keryan and Michael Gee.
*
@@ -226,13 +226,59 @@
* read_timeout. Thanks to Mark W. Webb <markwebb@adelphia.net> for
* reporting this bug.
* - Added Epson Perfection 1640SU and 1640SU Photo. Thanks to
- * Jean-Luc <f5ibh@db0bm.ampr.org>.
+ * Jean-Luc <f5ibh@db0bm.ampr.org> and Manuel
+ * Pelayo <Manuel.Pelayo@sesips.org>. Reported to work fine by Manuel.
*
- * 0.4.6 08/16/2001 Yves Duret <yduret@mandrakesoft.com>
- * - added devfs support (from printer.c)
- *
- * TODO
+ * 0.4.6 9/27/2001
+ * - Added IOCTL's to report back scanner USB ID's. Thanks to
+ * Karl Heinz <khk@lynx.phpwebhosting.com>
+ * - Added Umax Astra 2100U ID's. Thanks to Ron
+ * Wellsted <ron@wellsted.org.uk>.
+ * and Manuel Pelayo <Manuel.Pelayo@sesips.org>.
+ * - Added HP 3400 ID's. Thanks to Harald Hannelius <harald@iki.fi>
+ * and Bertrik Sikken <bertrik@zonnet.nl>. Reported to work at
+ * htpp://home.zonnet.nl/bertrik/hp3300c/hp3300c.htm.
+ * - Added Minolta Dimage Scan Dual II ID's. Thanks to Jose Paulo
+ * Moitinho de Almeida <moitinho@civil.ist.utl.pt>
+ * - Confirmed addition for SnapScan E20. Thanks to Steffen Hübner
+ * <hueb_s@gmx.de>.
+ * - Added Lifetec LT9385 ID's. Thanks to Van Bruwaene Kris
+ * <krvbr@yahoo.co.uk>
+ * - Added Agfa SnapScan e26 ID's. Reported to work with SANE
+ * 1.0.5. Thanks to Falk Sauer <falk@mgnkatze.franken.de>.
+ * - Added HP 4300 ID's. Thanks to Stefan Schlosser
+ * <castla@grmmbl.org>.
+ * - Added Relisis Episode ID's. Thanks to Manfred
+ * Morgner <odb-devel@gmx.net>.
+ * - Added many Acer ID's. Thanks to Oliver
+ * Schwartz <Oliver.Schwartz@gmx.de>.
+ * - Added Snapscan e40 ID's. Thanks to Oliver
+ * Schwartz <Oliver.Schwartz@gmx.de>.
+ * - Thanks to Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de>
+ * for helping with races.
+ * - Added Epson Perfection 1650 ID's. Thanks to Karl Heinz
+ * Kremer <khk@khk.net>.
+ * - Added Epson Perfection 2450 ID's (aka GT-9700 for the Japanese
+ * market). Thanks to Karl Heinz Kremer <khk@khk.net>.
+ * - Added Mustek 600 USB ID's. Thanks to Marcus
+ * Alanen <maalanen@ra.abo.fi>.
+ * - Added Acer ScanPrisa 1240UT ID's. Thanks to Morgan
+ * Collins <sirmorcant@morcant.org>.
+ * - Incorporated devfs patches!! Thanks to Tom Rini
+ * <trini@kernel.crashing.org>, Pavel Roskin <proski@gnu.org>,
+ * Greg KH <greg@kroah.com>, Yves Duret <yduret@mandrakesoft.com>,
+ * Flavio Stanchina <flavio.stanchina@tin.it>.
+ * - Removed Minolta ScanImage II. This scanner uses USB SCSI. Thanks
+ * to Oliver Neukum <Oliver.Neukum@lrz.uni-muenchen.de> for pointing
+ * this out.
+ * - Added additional SMP locking. Thanks to David Brownell and
+ * Oliver Neukum for their help.
+ * - Added version reporting - reports for both module load and modinfo
+ * - Started path to hopefully straighten/clean out ioctl()'s.
+ * - Users are now notified to consult the Documentation/usb/scanner.txt
+ * for common error messages rather than the maintainer.
*
+ * TODO
* - Performance
* - Select/poll methods
* - More testing
@@ -266,7 +312,6 @@
*/
#include "scanner.h"
-
static void
irq_scanner(struct urb *urb)
{
@@ -276,19 +321,23 @@ irq_scanner(struct urb *urb)
* all I want to do with it -- or somebody else for that matter.
*/
- struct scn_usb_data *scn = urb->context;
- unsigned char *data = &scn->button;
+ struct scn_usb_data *scn;
+ unsigned char *data;
+ scn = urb->context;
+ down(&(scn->sem));
+ data = &scn->button;
data += 0; /* Keep gcc from complaining about unused var */
if (urb->status) {
+ up(&(scn->sem));
return;
}
dbg("irq_scanner(%d): data:%x", scn->scn_minor, *data);
+ up(&(scn->sem));
return;
}
-
static int
open_scanner(struct inode * inode, struct file * file)
{
@@ -299,22 +348,28 @@ open_scanner(struct inode * inode, struct file * file)
int err=0;
- lock_kernel();
+ MOD_INC_USE_COUNT;
+
+ down(&scn_mutex);
scn_minor = USB_SCN_MINOR(inode);
dbg("open_scanner: scn_minor:%d", scn_minor);
if (!p_scn_table[scn_minor]) {
+ up(&scn_mutex);
err("open_scanner(%d): Unable to access minor data", scn_minor);
- err = -ENODEV;
- goto out_error;
+ return -ENODEV;
}
scn = p_scn_table[scn_minor];
dev = scn->scn_dev;
+ down(&(scn->sem)); /* Now protect the scn_usb_data structure */
+
+ up(&scn_mutex); /* Now handled by the above */
+
if (!dev) {
err("open_scanner(%d): Scanner device not present", scn_minor);
err = -ENODEV;
@@ -337,13 +392,15 @@ open_scanner(struct inode * inode, struct file * file)
scn->isopen = 1;
- file->private_data = scn; /* Used by the read and write metheds */
+ file->private_data = scn; /* Used by the read and write methods */
- MOD_INC_USE_COUNT;
out_error:
- unlock_kernel();
+ up(&(scn->sem)); /* Wake up any possible contending processes */
+
+ if (err)
+ MOD_DEC_USE_COUNT;
return err;
}
@@ -364,12 +421,17 @@ close_scanner(struct inode * inode, struct file * file)
return -ENODEV;
}
- scn = p_scn_table[scn_minor];
+ down(&scn_mutex);
+ scn = p_scn_table[scn_minor];
+ down(&(scn->sem));
scn->isopen = 0;
file->private_data = NULL;
+ up(&scn_mutex);
+ up(&(scn->sem));
+
MOD_DEC_USE_COUNT;
return 0;
@@ -395,6 +457,8 @@ write_scanner(struct file * file, const char * buffer,
scn = file->private_data;
+ down(&(scn->sem));
+
scn_minor = scn->scn_minor;
obuf = scn->obuf;
@@ -403,12 +467,10 @@ write_scanner(struct file * file, const char * buffer,
file->f_dentry->d_inode->i_atime = CURRENT_TIME;
- down(&(scn->gen_lock));
-
while (count > 0) {
if (signal_pending(current)) {
- ret = -EINTR;
+ ret = -ERESTARTSYS;
break;
}
@@ -427,7 +489,7 @@ write_scanner(struct file * file, const char * buffer,
ret = result;
break;
} else if (result < 0) { /* We should not get any I/O errors */
- warn("write_scanner(%d): funky result: %d. Please notify the maintainer.", scn_minor, result);
+ warn("write_scanner(%d): funky result: %d. Consult Documentataion/usb/scanner.txt.", scn_minor, result);
ret = -EIO;
break;
}
@@ -457,7 +519,7 @@ write_scanner(struct file * file, const char * buffer,
break;
}
}
- up(&(scn->gen_lock));
+ up(&(scn->sem));
mdelay(5); /* This seems to help with SANE queries */
return ret ? ret : bytes_written;
}
@@ -483,6 +545,8 @@ read_scanner(struct file * file, char * buffer,
scn = file->private_data;
+ down(&(scn->sem));
+
scn_minor = scn->scn_minor;
ibuf = scn->ibuf;
@@ -496,11 +560,9 @@ read_scanner(struct file * file, char * buffer,
atime of
the device
node */
- down(&(scn->gen_lock));
-
while (count > 0) {
if (signal_pending(current)) {
- ret = -EINTR;
+ ret = -ERESTARTSYS;
break;
}
@@ -545,7 +607,7 @@ read_scanner(struct file * file, char * buffer,
ret = result;
break;
} else if ((result < 0) && (result != USB_ST_DATAUNDERRUN)) {
- warn("read_scanner(%d): funky result:%d. Please notify the maintainer.", scn_minor, (int)result);
+ warn("read_scanner(%d): funky result:%d. Consult Documentation/usb/scanner.txt.", scn_minor, (int)result);
ret = -EIO;
break;
}
@@ -577,20 +639,16 @@ read_scanner(struct file * file, char * buffer,
break;
}
}
- up(&(scn->gen_lock));
-
+ up(&(scn->sem));
return ret ? ret : bytes_read;
}
-#ifdef SCN_IOCTL
static int
ioctl_scanner(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct usb_device *dev;
- int result;
-
kdev_t scn_minor;
scn_minor = USB_SCN_MINOR(inode);
@@ -604,12 +662,15 @@ ioctl_scanner(struct inode *inode, struct file *file,
switch (cmd)
{
- case IOCTL_SCANNER_VENDOR :
+ case SCANNER_IOCTL_VENDOR :
return (put_user(dev->descriptor.idVendor, (unsigned int *) arg));
- case IOCTL_SCANNER_PRODUCT :
+ case SCANNER_IOCTL_PRODUCT :
return (put_user(dev->descriptor.idProduct, (unsigned int *) arg));
+#ifdef PV8630
case PV8630_IOCTL_INREQUEST :
{
+ int result;
+
struct {
__u8 data;
__u8 request;
@@ -637,6 +698,8 @@ ioctl_scanner(struct inode *inode, struct file *file,
}
case PV8630_IOCTL_OUTREQUEST :
{
+ int result;
+
struct {
__u8 request;
__u16 value;
@@ -658,20 +721,59 @@ ioctl_scanner(struct inode *inode, struct file *file,
return result;
}
+#endif /* PV8630 */
+ case SCANNER_IOCTL_CTRLMSG:
+ {
+ struct ctrlmsg_ioctl {
+ devrequest req;
+ void *data;
+ } cmsg;
+ int pipe, nb, ret;
+ unsigned char buf[64];
+
+ if (copy_from_user(&cmsg, (void *)arg, sizeof(cmsg)))
+ return -EFAULT;
+
+ nb = le16_to_cpup(&cmsg.req.length);
+
+ if (nb > sizeof(buf))
+ return -EINVAL;
+
+ if ((cmsg.req.requesttype & 0x80) == 0) {
+ pipe = usb_sndctrlpipe(dev, 0);
+ if (nb > 0 && copy_from_user(buf, cmsg.data, nb))
+ return -EFAULT;
+ } else {
+ pipe = usb_rcvctrlpipe(dev, 0);
+ }
+
+ ret = usb_control_msg(dev, pipe, cmsg.req.request,
+ cmsg.req.requesttype,
+ le16_to_cpup(&cmsg.req.value),
+ le16_to_cpup(&cmsg.req.index),
+ buf, nb, HZ);
+
+ if (ret < 0) {
+ err("ioctl_scanner(%d): control_msg returned %d\n", scn_minor, ret);
+ return -EIO;
+ }
+
+ if (nb > 0 && (cmsg.req.requesttype & 0x80) && copy_to_user(cmsg.data, buf, nb))
+ return -EFAULT;
+
+ return 0;
+ }
default:
return -ENOTTY;
}
return 0;
}
-#endif /* SCN_IOCTL */
static struct
file_operations usb_scanner_fops = {
read: read_scanner,
write: write_scanner,
-#ifdef SCN_IOCTL
ioctl: ioctl_scanner,
-#endif /* SCN_IOCTL */
open: open_scanner,
release: close_scanner,
};
@@ -691,6 +793,7 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum,
char valid_device = 0;
char have_bulk_in, have_bulk_out, have_intr;
+ char name[10];
if (vendor != -1 && product != -1) {
info("probe_scanner: User specified USB scanner -- Vendor:Product - %x:%x", vendor, product);
@@ -791,7 +894,7 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum,
dbg("probe_scanner: intr_ep:%d", have_intr);
continue;
}
- info("probe_scanner: Undetected endpoint. Notify the maintainer.");
+ info("probe_scanner: Undetected endpoint -- consult Documentation/usb/scanner.txt.");
return NULL; /* Shouldn't ever get here unless we have something weird */
}
@@ -815,7 +918,7 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum,
}
break;
default:
- info("probe_scanner: Endpoint determination failed. Notify the maintainer.");
+ info("probe_scanner: Endpoint determination failed -- consult Documentation/usb/scanner.txt");
return NULL;
}
@@ -825,6 +928,8 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum,
* with it. The problem with this is that we are counting on the fact
* that the user will sequentially add device nodes for the scanner
* devices. */
+
+ down(&scn_mutex);
for (scn_minor = 0; scn_minor < SCN_MAX_MNR; scn_minor++) {
if (!p_scn_table[scn_minor])
@@ -844,8 +949,10 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum,
return NULL;
}
memset (scn, 0, sizeof(struct scn_usb_data));
- dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn);
+ init_MUTEX(&(scn->sem)); /* Initializes to unlocked */
+
+ dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn);
/* Ok, if we detected an interrupt EP, setup a handler for it */
if (have_intr) {
@@ -859,6 +966,7 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum,
if (usb_submit_urb(&scn->scn_irq)) {
err("probe_scanner(%d): Unable to allocate INT URB.", scn_minor);
kfree(scn);
+ up(&scn_mutex);
return NULL;
}
}
@@ -868,6 +976,7 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum,
if (!(scn->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {
err("probe_scanner(%d): Not enough memory for the output buffer.", scn_minor);
kfree(scn);
+ up(&scn_mutex);
return NULL;
}
dbg("probe_scanner(%d): obuf address:%p", scn_minor, scn->obuf);
@@ -876,6 +985,7 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum,
err("probe_scanner(%d): Not enough memory for the input buffer.", scn_minor);
kfree(scn->obuf);
kfree(scn);
+ up(&scn_mutex);
return NULL;
}
dbg("probe_scanner(%d): ibuf address:%p", scn_minor, scn->ibuf);
@@ -908,15 +1018,17 @@ probe_scanner(struct usb_device *dev, unsigned int ifnum,
scn->scn_minor = scn_minor;
scn->isopen = 0;
- init_MUTEX(&(scn->gen_lock));
-
- /* if we have devfs, create with perms=660 */
- scn->devfs = devfs_register(usb_devfs_handle, "scanner",
- DEVFS_FL_DEFAULT, USB_MAJOR,
- SCN_BASE_MNR + scn_minor,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
- S_IWGRP, &usb_scanner_fops, NULL);
+ sprintf(name, "scanner%d", scn->scn_minor);
+
+ scn->devfs = devfs_register(usb_devfs_handle, name,
+ DEVFS_FL_DEFAULT, USB_MAJOR,
+ SCN_BASE_MNR + scn->scn_minor,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
+ S_IWGRP | S_IROTH | S_IWOTH, &usb_scanner_fops, NULL);
+ if (scn->devfs == NULL)
+ dbg("scanner%d: device node registration failed", scn_minor);
+ up(&scn_mutex);
return p_scn_table[scn_minor] = scn;
}
@@ -926,6 +1038,9 @@ disconnect_scanner(struct usb_device *dev, void *ptr)
{
struct scn_usb_data *scn = (struct scn_usb_data *) ptr;
+ down (&scn_mutex);
+ down (&(scn->sem));
+
if(scn->intr_ep) {
dbg("disconnect_scanner(%d): Unlinking IRQ URB", scn->scn_minor);
usb_unlink_urb(&scn->scn_irq);
@@ -933,17 +1048,17 @@ disconnect_scanner(struct usb_device *dev, void *ptr)
usb_driver_release_interface(&scanner_driver,
&scn->scn_dev->actconfig->interface[scn->ifnum]);
- devfs_unregister (scn->devfs);
-
kfree(scn->ibuf);
kfree(scn->obuf);
dbg("disconnect_scanner: De-allocating minor:%d", scn->scn_minor);
+ devfs_unregister(scn->devfs);
p_scn_table[scn->scn_minor] = NULL;
+ up (&(scn->sem));
kfree (scn);
+ up (&scn_mutex);
}
-
static struct
usb_driver scanner_driver = {
name: "usbscanner",
@@ -968,7 +1083,7 @@ usb_scanner_init (void)
if (usb_register(&scanner_driver) < 0)
return -1;
- info("USB Scanner support registered.");
+ info(DRIVER_VERSION ":" DRIVER_DESC);
return 0;
}
diff --git a/drivers/usb/scanner.h b/drivers/usb/scanner.h
index 50dea437173f..ca10402fbb81 100644
--- a/drivers/usb/scanner.h
+++ b/drivers/usb/scanner.h
@@ -1,12 +1,10 @@
/*
- * Driver for USB Scanners (linux-2.4.0)
+ * Driver for USB Scanners (linux-2.4.12)
*
- * Copyright (C) 1999, 2000 David E. Nelson
+ * Copyright (C) 1999, 2000, 2001 David E. Nelson
*
* David E. Nelson (dnelson@jump.net)
*
- * 08/16/2001 added devfs support Yves Duret <yduret@mandrakesoft.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
@@ -37,12 +35,21 @@
// #define DEBUG
+/* Enable this to support the older ioctl interfaces scanners that
+ * a PV8630 Scanner-On-Chip. The prefered method is the
+ * SCANNER_IOCTL_CTRLMSG ioctl.
+ */
+// #define PV8630
+
+#define DRIVER_VERSION "0.4.6"
+#define DRIVER_DESC "USB Scanner Driver"
+
#include <linux/usb.h>
static __s32 vendor=-1, product=-1, read_timeout=0;
MODULE_AUTHOR("David E. Nelson, dnelson@jump.net, http://www.jump.net/~dnelson");
-MODULE_DESCRIPTION("USB Scanner Driver");
+MODULE_DESCRIPTION(DRIVER_DESC" "DRIVER_VERSION);
MODULE_LICENSE("GPL");
MODULE_PARM(vendor, "i");
@@ -55,10 +62,6 @@ MODULE_PARM(read_timeout, "i");
MODULE_PARM_DESC(read_timeout, "User specified read timeout in seconds");
-/* Enable to activate the ioctl interface. This is mainly meant for */
-/* development purposes until an ioctl number is officially registered */
-#define SCN_IOCTL
-
/* WARNING: These DATA_DUMP's can produce a lot of data. Caveat Emptor. */
// #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */
// #define WR_DATA_DUMP /* DEBUG does not have to be defined. */
@@ -69,26 +72,42 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x04a5, 0x2040) }, /* Prisa AcerScan 620U (!) */
{ USB_DEVICE(0x04a5, 0x20c0) }, /* Prisa AcerScan 1240UT */
{ USB_DEVICE(0x04a5, 0x2022) }, /* Vuego Scan Brisa 340U */
+ { USB_DEVICE(0x04a5, 0x1a20) }, /* Unknown - Oliver Schwartz */
+ { USB_DEVICE(0x04a5, 0x1a2a) }, /* Unknown - Oliver Schwartz */
+ { USB_DEVICE(0x04a5, 0x207e) }, /* Prisa 640BU */
+ { USB_DEVICE(0x04a5, 0x20be) }, /* Unknown - Oliver Schwartz */
+ { USB_DEVICE(0x04a5, 0x20c0) }, /* Unknown - Oliver Schwartz */
+ { USB_DEVICE(0x04a5, 0x20de) }, /* S2W 3300U */
+ { USB_DEVICE(0x04a5, 0x20b0) }, /* Unknown - Oliver Schwartz */
+ { USB_DEVICE(0x04a5, 0x20fe) }, /* Unknown - Oliver Schwartz */
/* Agfa */
{ USB_DEVICE(0x06bd, 0x0001) }, /* SnapScan 1212U */
{ USB_DEVICE(0x06bd, 0x0002) }, /* SnapScan 1236U */
{ USB_DEVICE(0x06bd, 0x2061) }, /* Another SnapScan 1212U (?)*/
{ USB_DEVICE(0x06bd, 0x0100) }, /* SnapScan Touch */
+ { USB_DEVICE(0x06bd, 0x2091) }, /* SnapScan e20 */
+ { USB_DEVICE(0x06bd, 0x2097) }, /* SnapScan e26 */
+ { USB_DEVICE(0x06bd, 0x208d) }, /* Snapscan e40 */
/* Colorado -- See Primax/Colorado below */
/* Epson -- See Seiko/Epson below */
/* Genius */
{ USB_DEVICE(0x0458, 0x2001) }, /* ColorPage-Vivid Pro */
/* Hewlett Packard */
{ USB_DEVICE(0x03f0, 0x0205) }, /* 3300C */
+ { USB_DEVICE(0x03f0, 0x0405) }, /* 3400C */
{ USB_DEVICE(0x03f0, 0x0101) }, /* 4100C */
{ USB_DEVICE(0x03f0, 0x0105) }, /* 4200C */
+ { USB_DEVICE(0x03f0, 0x0305) }, /* 4300C */
{ USB_DEVICE(0x03f0, 0x0102) }, /* PhotoSmart S20 */
{ USB_DEVICE(0x03f0, 0x0401) }, /* 5200C */
// { USB_DEVICE(0x03f0, 0x0701) }, /* 5300C - NOT SUPPORTED - see http://www.neatech.nl/oss/HP5300C/ */
{ USB_DEVICE(0x03f0, 0x0201) }, /* 6200C */
{ USB_DEVICE(0x03f0, 0x0601) }, /* 6300C */
+ { USB_DEVICE(0x03f0, 0x605) }, /* 2200C */
/* iVina */
- { USB_DEVICE(0x0638, 0x0268) }, /* 1200U */
+ { USB_DEVICE(0x0638, 0x0268) }, /* 1200U */
+ /* Lifetec */
+ { USB_DEVICE(0x05d8, 0x4002) }, /* Lifetec LT9385 */
/* Microtek -- No longer supported - Enable SCSI and USB Microtek in kernel config */
// { USB_DEVICE(0x05da, 0x0099) }, /* ScanMaker X6 - X6U */
// { USB_DEVICE(0x05da, 0x0094) }, /* Phantom 336CX - C3 */
@@ -97,10 +116,13 @@ static struct usb_device_id scanner_device_ids [] = {
// { USB_DEVICE(0x05da, 0x00a3) }, /* ScanMaker V6USL */
// { USB_DEVICE(0x05da, 0x80a3) }, /* ScanMaker V6USL #2 */
// { USB_DEVICE(0x05da, 0x80ac) }, /* ScanMaker V6UL - SpicyU */
+ /* Minolta */
+ // { USB_DEVICE(0x0638,0x026a) }, /* Minolta Dimage Scan Dual II */
/* Mustek */
{ USB_DEVICE(0x055f, 0x0001) }, /* 1200 CU */
{ USB_DEVICE(0x0400, 0x1000) }, /* BearPaw 1200 */
{ USB_DEVICE(0x055f, 0x0002) }, /* 600 CU */
+ { USB_DEVICE(0x055f, 0x0873) }, /* 600 USB */
{ USB_DEVICE(0x055f, 0x0003) }, /* 1200 USB */
{ USB_DEVICE(0x055f, 0x0006) }, /* 1200 UB */
{ USB_DEVICE(0x0400, 0x1001) }, /* BearPaw 2400 */
@@ -116,9 +138,11 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x0461, 0x0303) }, /* G2E-300 #2 */
{ USB_DEVICE(0x0461, 0x0383) }, /* G2E-600 */
{ USB_DEVICE(0x0461, 0x0340) }, /* Colorado USB 9600 */
- { USB_DEVICE(0x0461, 0x0360) }, /* Colorado USB 19200 */
+ // { USB_DEVICE(0x0461, 0x0360) }, /* Colorado USB 19200 - undetected endpoint */
{ USB_DEVICE(0x0461, 0x0341) }, /* Colorado 600u */
{ USB_DEVICE(0x0461, 0x0361) }, /* Colorado 1200u */
+ /* Relisis */
+ // { USB_DEVICE(0x0475, 0x0103) }, /* Episode - undetected endpoint */
/* Seiko/Epson Corp. */
{ USB_DEVICE(0x04b8, 0x0101) }, /* Perfection 636U and 636Photo */
{ USB_DEVICE(0x04b8, 0x0103) }, /* Perfection 610 */
@@ -129,9 +153,12 @@ static struct usb_device_id scanner_device_ids [] = {
{ USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */
{ USB_DEVICE(0x04b8, 0x010c) }, /* Perfection 640U */
{ USB_DEVICE(0x04b8, 0x010e) }, /* Expression 1680 */
+ { USB_DEVICE(0x04b8, 0x0110) }, /* Perfection 1650 */
+ { USB_DEVICE(0x04b8, 0x0112) }, /* Perfection 2450 - GT-9700 for the Japanese mkt */
/* Umax */
{ USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */
{ USB_DEVICE(0x1606, 0x0030) }, /* Astra 2000U */
+ { USB_DEVICE(0x1606, 0x0130) }, /* Astra 2100U */
{ USB_DEVICE(0x1606, 0x0230) }, /* Astra 2200U */
/* Visioneer */
{ USB_DEVICE(0x04a7, 0x0221) }, /* OneTouch 5300 USB */
@@ -167,16 +194,24 @@ MODULE_DEVICE_TABLE (usb, scanner_device_ids);
/* FIXME: These are NOT registered ioctls()'s */
+#ifdef PV8630
#define PV8630_IOCTL_INREQUEST 69
#define PV8630_IOCTL_OUTREQUEST 70
+#endif /* PV8630 */
+
+
+/* read vendor and product IDs from the scanner */
+#define SCANNER_IOCTL_VENDOR _IOR('U', 0x20, int)
+#define SCANNER_IOCTL_PRODUCT _IOR('U', 0x21, int)
+/* send/recv a control message to the scanner */
+#define SCANNER_IOCTL_CTRLMSG _IOWR('U', 0x22, devrequest )
-/* read vendor and product IDs */
-#define IOCTL_SCANNER_VENDOR _IOR('u', 0xa0, int)
-#define IOCTL_SCANNER_PRODUCT _IOR('u', 0xa1, int)
#define SCN_MAX_MNR 16 /* We're allocated 16 minors */
#define SCN_BASE_MNR 48 /* USB Scanners start at minor 48 */
+static DECLARE_MUTEX (scn_mutex); /* Initializes to unlocked */
+
struct scn_usb_data {
struct usb_device *scn_dev;
devfs_handle_t devfs; /* devfs device */
@@ -189,12 +224,12 @@ struct scn_usb_data {
char *obuf, *ibuf; /* transfer buffers */
char bulk_in_ep, bulk_out_ep, intr_ep; /* Endpoint assignments */
wait_queue_head_t rd_wait_q; /* read timeouts */
- struct semaphore gen_lock; /* lock to prevent concurrent reads or writes */
+ struct semaphore sem; /* lock to prevent concurrent reads or writes */
unsigned int rd_nak_timeout; /* Seconds to wait before read() timeout. */
};
+extern devfs_handle_t usb_devfs_handle;
+
static struct scn_usb_data *p_scn_table[SCN_MAX_MNR] = { NULL, /* ... */};
static struct usb_driver scanner_driver;
-
-extern devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 640ca9e0e947..d62521c764f1 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -454,7 +454,7 @@ static int ftdi_sio_write (struct usb_serial_port *port, int from_user,
while (port->write_urb->status == -EINPROGRESS) {
dbg(__FUNCTION__ " write in progress - retrying");
if (signal_pending(current)) {
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
remove_wait_queue(&port->write_wait, &wait);
rc = -ERESTARTSYS;
goto err;
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index af8f012665b6..88b087622dee 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -1684,8 +1684,8 @@ static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb)
/* Control and Isochronous ignore the toggle, so this */
/* is safe for all types */
if (!(td->status & TD_CTRL_ACTIVE) &&
- uhci_actual_length(td->status) < uhci_expected_length(td->info) ||
- tmp == head) {
+ (uhci_actual_length(td->status) < uhci_expected_length(td->info) ||
+ tmp == head)) {
usb_settoggle(urb->dev, uhci_endpoint(td->info),
uhci_packetout(td->info),
uhci_toggle(td->info) ^ 1);
diff --git a/drivers/usb/usb-ohci.c b/drivers/usb/usb-ohci.c
index 15d6ba0a9f2b..eff3386b94bf 100644
--- a/drivers/usb/usb-ohci.c
+++ b/drivers/usb/usb-ohci.c
@@ -779,7 +779,7 @@ static int sohci_unlink_urb (urb_t * urb)
set_current_state(TASK_UNINTERRUPTIBLE);
while (timeout && (urb->status == USB_ST_URB_PENDING))
timeout = schedule_timeout (timeout);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
remove_wait_queue (&unlink_wakeup, &wait);
if (urb->status == USB_ST_URB_PENDING) {
err ("unlink URB timeout");
@@ -884,7 +884,7 @@ static int sohci_free_dev (struct usb_device * usb_dev)
set_current_state(TASK_UNINTERRUPTIBLE);
while (timeout && dev->ed_cnt)
timeout = schedule_timeout (timeout);
- current->state = TASK_RUNNING;
+ set_current_state(TASK_RUNNING);
remove_wait_queue (&freedev_wakeup, &wait);
if (dev->ed_cnt) {
err ("free device %d timeout", usb_dev->devnum);
diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c
index 1be3080b1550..c580b6082e07 100644
--- a/drivers/usb/usb.c
+++ b/drivers/usb/usb.c
@@ -60,7 +60,7 @@ static void usb_check_support(struct usb_device *);
*/
LIST_HEAD(usb_driver_list);
LIST_HEAD(usb_bus_list);
-rwlock_t usb_bus_list_lock = RW_LOCK_UNLOCKED;
+struct semaphore usb_bus_list_lock;
devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */
@@ -112,7 +112,7 @@ void usb_scan_devices(void)
{
struct list_head *tmp;
- read_lock_irq (&usb_bus_list_lock);
+ down (&usb_bus_list_lock);
tmp = usb_bus_list.next;
while (tmp != &usb_bus_list) {
struct usb_bus *bus = list_entry(tmp,struct usb_bus, bus_list);
@@ -120,7 +120,7 @@ void usb_scan_devices(void)
tmp = tmp->next;
usb_check_support(bus->root_hub);
}
- read_unlock_irq (&usb_bus_list_lock);
+ up (&usb_bus_list_lock);
}
/*
@@ -182,7 +182,7 @@ void usb_deregister(struct usb_driver *driver)
*/
list_del(&driver->driver_list);
- read_lock_irq (&usb_bus_list_lock);
+ down (&usb_bus_list_lock);
tmp = usb_bus_list.next;
while (tmp != &usb_bus_list) {
struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list);
@@ -190,7 +190,7 @@ void usb_deregister(struct usb_driver *driver)
tmp = tmp->next;
usb_drivers_purge(driver, bus->root_hub);
}
- read_unlock_irq (&usb_bus_list_lock);
+ up (&usb_bus_list_lock);
}
struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
@@ -421,7 +421,7 @@ void usb_register_bus(struct usb_bus *bus)
{
int busnum;
- write_lock_irq (&usb_bus_list_lock);
+ down (&usb_bus_list_lock);
busnum = find_next_zero_bit(busmap.busmap, USB_MAXBUS, 1);
if (busnum < USB_MAXBUS) {
set_bit(busnum, busmap.busmap);
@@ -433,7 +433,7 @@ void usb_register_bus(struct usb_bus *bus)
/* Add it to the list of buses */
list_add(&bus->bus_list, &usb_bus_list);
- write_unlock_irq (&usb_bus_list_lock);
+ up (&usb_bus_list_lock);
usbdevfs_add_bus(bus);
@@ -455,9 +455,9 @@ void usb_deregister_bus(struct usb_bus *bus)
* controller code, as well as having it call this when cleaning
* itself up
*/
- write_lock_irq (&usb_bus_list_lock);
+ down (&usb_bus_list_lock);
list_del(&bus->bus_list);
- write_unlock_irq (&usb_bus_list_lock);
+ up (&usb_bus_list_lock);
usbdevfs_remove_bus(bus);
@@ -2332,6 +2332,7 @@ struct list_head *usb_bus_get_list(void)
*/
static int __init usb_init(void)
{
+ init_MUTEX(&usb_bus_list_lock);
usb_major_init();
usbdevfs_init();
usb_hub_init();
diff --git a/drivers/usb/usbnet.c b/drivers/usb/usbnet.c
index 6981f543fe9c..2e101acb2fc5 100644
--- a/drivers/usb/usbnet.c
+++ b/drivers/usb/usbnet.c
@@ -1056,7 +1056,7 @@ static int usbnet_stop (struct net_device *net)
while (skb_queue_len (&dev->rxq)
&& skb_queue_len (&dev->txq)
&& skb_queue_len (&dev->done)) {
- current->state = TASK_UNINTERRUPTIBLE;
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout (UNLINK_TIMEOUT_JIFFIES);
dbg ("waited for %d urb completions", temp);
}
diff --git a/drivers/usb/uss720.c b/drivers/usb/uss720.c
index a7c5e1ef619f..98067c866654 100644
--- a/drivers/usb/uss720.c
+++ b/drivers/usb/uss720.c
@@ -159,7 +159,7 @@ static int change_mode(struct parport *pp, int m)
if (time_after_eq (jiffies, expire))
/* The FIFO is stuck. */
return -EBUSY;
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout((HZ + 99) / 100);
if (signal_pending (current))
break;
diff --git a/drivers/video/acornfb.c b/drivers/video/acornfb.c
index 9020a278f301..f102c975729f 100644
--- a/drivers/video/acornfb.c
+++ b/drivers/video/acornfb.c
@@ -1528,7 +1528,7 @@ acornfb_setup(char *options)
acornfb_init_fbinfo();
- for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
+ while (opt = strsep(&options, ",")) {
if (!*opt)
continue;
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index 34f04ad26797..fb30cde0f2fa 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -1192,7 +1192,7 @@ int __init amifb_setup(char *options)
if (!options || !*options)
return 0;
- for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!strcmp(this_opt, "inverse")) {
amifb_inverse = 1;
fb_invert_cmaps();
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index a08ca4280784..e8b9f5a47ccd 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -2521,8 +2521,7 @@ int __init atyfb_setup(char *options)
if (!options || !*options)
return 0;
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!strncmp(this_opt, "font:", 5)) {
char *p;
int i;
diff --git a/drivers/video/aty128fb.c b/drivers/video/aty128fb.c
index 17504fbf50d8..849cbd83b389 100644
--- a/drivers/video/aty128fb.c
+++ b/drivers/video/aty128fb.c
@@ -1613,8 +1613,7 @@ aty128fb_setup(char *options)
if (!options || !*options)
return 0;
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!strncmp(this_opt, "font:", 5)) {
char *p;
int i;
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index 52ca30f5a42a..15c6116aeaa1 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -1423,8 +1423,7 @@ void __init control_setup(char *options)
if (!options || !*options)
return;
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!strncmp(this_opt, "font:", 5)) {
char *p;
int i;
diff --git a/drivers/video/cyberfb.c b/drivers/video/cyberfb.c
index d248381ec27e..ff9b6cef54bd 100644
--- a/drivers/video/cyberfb.c
+++ b/drivers/video/cyberfb.c
@@ -1022,8 +1022,7 @@ int __init cyberfb_setup(char *options)
return 0;
}
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!strcmp(this_opt, "inverse")) {
Cyberfb_inverse = 1;
fb_invert_cmaps();
diff --git a/drivers/video/fm2fb.c b/drivers/video/fm2fb.c
index 2bbc75c55e6c..6eaff519139b 100644
--- a/drivers/video/fm2fb.c
+++ b/drivers/video/fm2fb.c
@@ -430,8 +430,7 @@ int __init fm2fb_setup(char *options)
if (!options || !*options)
return 0;
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!strncmp(this_opt, "pal", 3))
fm2fb_mode = FM2FB_MODE_PAL;
else if (!strncmp(this_opt, "ntsc", 4))
diff --git a/drivers/video/hgafb.c b/drivers/video/hgafb.c
index 7056ec6b0ffc..c0c2d1361622 100644
--- a/drivers/video/hgafb.c
+++ b/drivers/video/hgafb.c
@@ -795,8 +795,7 @@ int __init hgafb_setup(char *options)
if (!options || !*options)
return 0;
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!strncmp(this_opt, "font:", 5))
strcpy(fb_info.fontname, this_opt+5);
}
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index 1ef224e28e49..7379dfbbc1d6 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -773,8 +773,7 @@ int __init igafb_setup(char *options)
if (!options || !*options)
return 0;
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!strncmp(this_opt, "font:", 5)) {
char *p;
int i;
diff --git a/drivers/video/imsttfb.c b/drivers/video/imsttfb.c
index 8748b44b0d5d..315ff4fd620f 100644
--- a/drivers/video/imsttfb.c
+++ b/drivers/video/imsttfb.c
@@ -1977,8 +1977,7 @@ imsttfb_setup(char *options)
if (!options || !*options)
return 0;
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!strncmp(this_opt, "font:", 5)) {
char *p;
int i;
diff --git a/drivers/video/macfb.c b/drivers/video/macfb.c
index f36c0ac2afe9..5588d8acb184 100644
--- a/drivers/video/macfb.c
+++ b/drivers/video/macfb.c
@@ -848,7 +848,7 @@ void __init macfb_setup(char *options, int *ints)
if (!options || !*options)
return;
- for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!*this_opt) continue;
if (! strcmp(this_opt, "inverse"))
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index feb79a4caea0..3e4a7c6e4a0e 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -2355,7 +2355,7 @@ int __init matroxfb_setup(char *options) {
if (!options || !*options)
return 0;
- for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!*this_opt) continue;
dprintk("matroxfb_setup: option %s\n", this_opt);
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index 8a7208ffa072..f8b6a9cf96fe 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -841,8 +841,7 @@ int __init platinum_setup(char *options)
if (!options || !*options)
return 0;
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!strncmp(this_opt, "font:", 5)) {
char *p;
int i;
diff --git a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c
index 764c439c61c5..f5b6438c8baa 100644
--- a/drivers/video/radeonfb.c
+++ b/drivers/video/radeonfb.c
@@ -537,8 +537,7 @@ int __init radeonfb_setup (char *options)
if (!options || !*options)
return 0;
- for (this_opt = strtok (options, ","); this_opt;
- this_opt = strtok (NULL, ",")) {
+ while (this_opt = strsep (&options, ",")) {
if (!strncmp (this_opt, "font:", 5)) {
char *p;
int i;
diff --git a/drivers/video/retz3fb.c b/drivers/video/retz3fb.c
index 5d93506ccb49..afb7db1999b4 100644
--- a/drivers/video/retz3fb.c
+++ b/drivers/video/retz3fb.c
@@ -1348,8 +1348,7 @@ int __init retz3fb_setup(char *options)
if (!options || !*options)
return 0;
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")){
+ while (this_opt = strsep(&options, ",")) {
if (!strcmp(this_opt, "inverse")) {
z3fb_inverse = 1;
fb_invert_cmaps();
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index cebcfabb887d..f62ccf6760c0 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -2045,8 +2045,7 @@ int __init rivafb_setup(char *options)
if (!options || !*options)
return 0;
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!strncmp(this_opt, "font:", 5)) {
char *p;
int i;
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index a9fff2b8879e..22628fed57d3 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -2299,8 +2299,7 @@ int __init sa1100fb_setup(char *options)
if (!options || !*options)
return 0;
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!strncmp(this_opt, "bpp:", 4))
current_par.max_bpp =
diff --git a/drivers/video/sgivwfb.c b/drivers/video/sgivwfb.c
index bf8d17e5409e..c9c1fe6581e3 100644
--- a/drivers/video/sgivwfb.c
+++ b/drivers/video/sgivwfb.c
@@ -862,8 +862,7 @@ int __init sgivwfb_setup(char *options)
if (!options || !*options)
return 0;
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!strncmp(this_opt, "font:", 5))
strcpy(fb_info.fontname, this_opt+5);
}
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index 4483b2c70c3d..280264b6c7f4 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -1726,8 +1726,7 @@ int sisfb_setup(char *options)
if (!options || !*options)
return 0;
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!*this_opt)
continue;
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c
index 0cea53fd63b6..0b717f44bc5e 100644
--- a/drivers/video/sstfb.c
+++ b/drivers/video/sstfb.c
@@ -1697,8 +1697,7 @@ int __init sstfb_setup(char *options)
if (!options || !*options)
return 0;
- for(this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!*this_opt) continue;
f_ddprintk("option %s\n", this_opt);
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c
index ad32b3398645..32b66b5a4bc0 100644
--- a/drivers/video/tdfxfb.c
+++ b/drivers/video/tdfxfb.c
@@ -2086,9 +2086,7 @@ void tdfxfb_setup(char *options,
if(!options || !*options)
return;
- for(this_opt = strtok(options, ",");
- this_opt;
- this_opt = strtok(NULL, ",")) {
+ while(this_opt = strsep(&options, ",")) {
if(!strcmp(this_opt, "inverse")) {
inverse = 1;
fb_invert_cmaps();
diff --git a/drivers/video/tgafb.c b/drivers/video/tgafb.c
index 75b8f1e6252e..35a77b8abdec 100644
--- a/drivers/video/tgafb.c
+++ b/drivers/video/tgafb.c
@@ -889,7 +889,7 @@ int __init tgafb_setup(char *options) {
int i;
if (options && *options) {
- for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!*this_opt) { continue; }
if (!strncmp(this_opt, "font:", 5)) {
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
index f24988799181..09307d62231a 100644
--- a/drivers/video/valkyriefb.c
+++ b/drivers/video/valkyriefb.c
@@ -801,8 +801,7 @@ int __init valkyriefb_setup(char *options)
if (!options || !*options)
return 0;
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!strncmp(this_opt, "font:", 5)) {
char *p;
int i;
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index 761e4343dfbe..0ff02e09926e 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -457,7 +457,7 @@ int __init vesafb_setup(char *options)
if (!options || !*options)
return 0;
- for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!*this_opt) continue;
if (! strcmp(this_opt, "inverse"))
diff --git a/drivers/video/vfb.c b/drivers/video/vfb.c
index 7e8c5e94981a..78edbfcdd51c 100644
--- a/drivers/video/vfb.c
+++ b/drivers/video/vfb.c
@@ -382,8 +382,7 @@ int __init vfb_setup(char *options)
if (!options || !*options)
return 0;
- for (this_opt = strtok(options, ","); this_opt;
- this_opt = strtok(NULL, ",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!strncmp(this_opt, "font:", 5))
strcpy(fb_info.fontname, this_opt+5);
}
diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c
index 85701ecfebdc..196c05d5e0bc 100644
--- a/drivers/video/vga16fb.c
+++ b/drivers/video/vga16fb.c
@@ -692,7 +692,7 @@ int vga16fb_setup(char *options)
if (!options || !*options)
return 0;
- for(this_opt=strtok(options,","); this_opt; this_opt=strtok(NULL,",")) {
+ while (this_opt = strsep(&options, ",")) {
if (!*this_opt) continue;
if (!strncmp(this_opt, "font:", 5))
diff --git a/drivers/video/virgefb.c b/drivers/video/virgefb.c
index 41c9537568ac..a5a81486a214 100644
--- a/drivers/video/virgefb.c
+++ b/drivers/video/virgefb.c
@@ -1085,7 +1085,7 @@ int __init virgefb_setup(char *options)
if (!options || !*options)
return 0;
- for (this_opt = strtok(options, ","); this_opt; this_opt = strtok(NULL, ","))
+ while (this_opt = strsep(&options, ",")) {
if (!strcmp(this_opt, "inverse")) {
Cyberfb_inverse = 1;
fb_invert_cmaps();