diff options
author | Al Viro <viro@ftp.linux.org.uk> | 2008-01-13 09:17:35 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2008-01-18 14:44:33 -0500 |
commit | b665982409fd5e4d3f1b71591d2f6badf9d2ee99 (patch) | |
tree | 00f16223e91563bd99cb4a42178f62e693aa2030 /drivers/net/3c515.c | |
parent | c15561f0e5615607e2b5524c4b3af64d20cd6e28 (diff) |
3c574, 3c515 bitfields abuse
wn3_config is shared by these cards; the way we deal with it is both bad C
(union abuse) and broken on big-endian. For 3c515 it's less serious (ISA
cards are quite rare outside of little-endian boxen), but 3c574 is a pcmcia
one and that'd better be endian-independent... Fix is the same in both
cases.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/3c515.c')
-rw-r--r-- | drivers/net/3c515.c | 60 |
1 files changed, 31 insertions, 29 deletions
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index 275e7510ebaf..684bab781015 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c | |||
@@ -243,14 +243,16 @@ enum eeprom_offset { | |||
243 | enum Window3 { /* Window 3: MAC/config bits. */ | 243 | enum Window3 { /* Window 3: MAC/config bits. */ |
244 | Wn3_Config = 0, Wn3_MAC_Ctrl = 6, Wn3_Options = 8, | 244 | Wn3_Config = 0, Wn3_MAC_Ctrl = 6, Wn3_Options = 8, |
245 | }; | 245 | }; |
246 | union wn3_config { | 246 | enum wn3_config { |
247 | int i; | 247 | Ram_size = 7, |
248 | struct w3_config_fields { | 248 | Ram_width = 8, |
249 | unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2; | 249 | Ram_speed = 0x30, |
250 | int pad8:8; | 250 | Rom_size = 0xc0, |
251 | unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1; | 251 | Ram_split_shift = 16, |
252 | int pad24:7; | 252 | Ram_split = 3 << Ram_split_shift, |
253 | } u; | 253 | Xcvr_shift = 20, |
254 | Xcvr = 7 << Xcvr_shift, | ||
255 | Autoselect = 0x1000000, | ||
254 | }; | 256 | }; |
255 | 257 | ||
256 | enum Window4 { | 258 | enum Window4 { |
@@ -614,7 +616,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, | |||
614 | /* Read the station address from the EEPROM. */ | 616 | /* Read the station address from the EEPROM. */ |
615 | EL3WINDOW(0); | 617 | EL3WINDOW(0); |
616 | for (i = 0; i < 0x18; i++) { | 618 | for (i = 0; i < 0x18; i++) { |
617 | short *phys_addr = (short *) dev->dev_addr; | 619 | __be16 *phys_addr = (__be16 *) dev->dev_addr; |
618 | int timer; | 620 | int timer; |
619 | outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd); | 621 | outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd); |
620 | /* Pause for at least 162 us. for the read to take place. */ | 622 | /* Pause for at least 162 us. for the read to take place. */ |
@@ -646,22 +648,22 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, | |||
646 | 648 | ||
647 | { | 649 | { |
648 | char *ram_split[] = { "5:3", "3:1", "1:1", "3:5" }; | 650 | char *ram_split[] = { "5:3", "3:1", "1:1", "3:5" }; |
649 | union wn3_config config; | 651 | __u32 config; |
650 | EL3WINDOW(3); | 652 | EL3WINDOW(3); |
651 | vp->available_media = inw(ioaddr + Wn3_Options); | 653 | vp->available_media = inw(ioaddr + Wn3_Options); |
652 | config.i = inl(ioaddr + Wn3_Config); | 654 | config = inl(ioaddr + Wn3_Config); |
653 | if (corkscrew_debug > 1) | 655 | if (corkscrew_debug > 1) |
654 | printk(KERN_INFO " Internal config register is %4.4x, transceivers %#x.\n", | 656 | printk(KERN_INFO " Internal config register is %4.4x, transceivers %#x.\n", |
655 | config.i, inw(ioaddr + Wn3_Options)); | 657 | config, inw(ioaddr + Wn3_Options)); |
656 | printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", | 658 | printk(KERN_INFO " %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", |
657 | 8 << config.u.ram_size, | 659 | 8 << config & Ram_size, |
658 | config.u.ram_width ? "word" : "byte", | 660 | config & Ram_width ? "word" : "byte", |
659 | ram_split[config.u.ram_split], | 661 | ram_split[(config & Ram_split) >> Ram_split_shift], |
660 | config.u.autoselect ? "autoselect/" : "", | 662 | config & Autoselect ? "autoselect/" : "", |
661 | media_tbl[config.u.xcvr].name); | 663 | media_tbl[(config & Xcvr) >> Xcvr_shift].name); |
662 | dev->if_port = config.u.xcvr; | 664 | vp->default_media = (config & Xcvr) >> Xcvr_shift; |
663 | vp->default_media = config.u.xcvr; | 665 | vp->autoselect = config & Autoselect ? 1 : 0; |
664 | vp->autoselect = config.u.autoselect; | 666 | dev->if_port = vp->default_media; |
665 | } | 667 | } |
666 | if (vp->media_override != 7) { | 668 | if (vp->media_override != 7) { |
667 | printk(KERN_INFO " Media override to transceiver type %d (%s).\n", | 669 | printk(KERN_INFO " Media override to transceiver type %d (%s).\n", |
@@ -694,14 +696,14 @@ static int corkscrew_open(struct net_device *dev) | |||
694 | { | 696 | { |
695 | int ioaddr = dev->base_addr; | 697 | int ioaddr = dev->base_addr; |
696 | struct corkscrew_private *vp = netdev_priv(dev); | 698 | struct corkscrew_private *vp = netdev_priv(dev); |
697 | union wn3_config config; | 699 | __u32 config; |
698 | int i; | 700 | int i; |
699 | 701 | ||
700 | /* Before initializing select the active media port. */ | 702 | /* Before initializing select the active media port. */ |
701 | EL3WINDOW(3); | 703 | EL3WINDOW(3); |
702 | if (vp->full_duplex) | 704 | if (vp->full_duplex) |
703 | outb(0x20, ioaddr + Wn3_MAC_Ctrl); /* Set the full-duplex bit. */ | 705 | outb(0x20, ioaddr + Wn3_MAC_Ctrl); /* Set the full-duplex bit. */ |
704 | config.i = inl(ioaddr + Wn3_Config); | 706 | config = inl(ioaddr + Wn3_Config); |
705 | 707 | ||
706 | if (vp->media_override != 7) { | 708 | if (vp->media_override != 7) { |
707 | if (corkscrew_debug > 1) | 709 | if (corkscrew_debug > 1) |
@@ -727,12 +729,12 @@ static int corkscrew_open(struct net_device *dev) | |||
727 | } else | 729 | } else |
728 | dev->if_port = vp->default_media; | 730 | dev->if_port = vp->default_media; |
729 | 731 | ||
730 | config.u.xcvr = dev->if_port; | 732 | config = (config & ~Xcvr) | (dev->if_port << Xcvr_shift); |
731 | outl(config.i, ioaddr + Wn3_Config); | 733 | outl(config, ioaddr + Wn3_Config); |
732 | 734 | ||
733 | if (corkscrew_debug > 1) { | 735 | if (corkscrew_debug > 1) { |
734 | printk("%s: corkscrew_open() InternalConfig %8.8x.\n", | 736 | printk("%s: corkscrew_open() InternalConfig %8.8x.\n", |
735 | dev->name, config.i); | 737 | dev->name, config); |
736 | } | 738 | } |
737 | 739 | ||
738 | outw(TxReset, ioaddr + EL3_CMD); | 740 | outw(TxReset, ioaddr + EL3_CMD); |
@@ -901,7 +903,7 @@ static void corkscrew_timer(unsigned long data) | |||
901 | ok = 1; | 903 | ok = 1; |
902 | } | 904 | } |
903 | if (!ok) { | 905 | if (!ok) { |
904 | union wn3_config config; | 906 | __u32 config; |
905 | 907 | ||
906 | do { | 908 | do { |
907 | dev->if_port = | 909 | dev->if_port = |
@@ -928,9 +930,9 @@ static void corkscrew_timer(unsigned long data) | |||
928 | ioaddr + Wn4_Media); | 930 | ioaddr + Wn4_Media); |
929 | 931 | ||
930 | EL3WINDOW(3); | 932 | EL3WINDOW(3); |
931 | config.i = inl(ioaddr + Wn3_Config); | 933 | config = inl(ioaddr + Wn3_Config); |
932 | config.u.xcvr = dev->if_port; | 934 | config = (config & ~Xcvr) | (dev->if_port << Xcvr_shift); |
933 | outl(config.i, ioaddr + Wn3_Config); | 935 | outl(config, ioaddr + Wn3_Config); |
934 | 936 | ||
935 | outw(dev->if_port == 3 ? StartCoax : StopCoax, | 937 | outw(dev->if_port == 3 ? StartCoax : StopCoax, |
936 | ioaddr + EL3_CMD); | 938 | ioaddr + EL3_CMD); |