diff options
author | Dan Williams <dcbw@redhat.com> | 2009-01-24 09:04:12 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-01-29 16:01:38 -0500 |
commit | f55d4517ebdd6de627d42a24baefaeb689978087 (patch) | |
tree | 78451db08c876d5d536d0f6a15a3e3bef0a7cfca /drivers/net/wireless/airo.c | |
parent | 0d21044effa10044930419c6f837f75191229c3a (diff) |
airo: clean up and clarify interrupt-time task handling
Split each specific interrupt-time task out into its own function to
make airo_interrupt() actually readable.
Signed-off-by: Dan Williams <dcbw@redhat.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/airo.c')
-rw-r--r-- | drivers/net/wireless/airo.c | 613 |
1 files changed, 327 insertions, 286 deletions
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 2ff588bb0a7c..a192c4472e02 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c | |||
@@ -981,6 +981,14 @@ typedef struct { | |||
981 | dma_addr_t host_addr; | 981 | dma_addr_t host_addr; |
982 | } TxFid; | 982 | } TxFid; |
983 | 983 | ||
984 | struct rx_hdr { | ||
985 | __le16 status, len; | ||
986 | u8 rssi[2]; | ||
987 | u8 rate; | ||
988 | u8 freq; | ||
989 | __le16 tmp[4]; | ||
990 | } __attribute__ ((packed)); | ||
991 | |||
984 | typedef struct { | 992 | typedef struct { |
985 | unsigned int ctl: 15; | 993 | unsigned int ctl: 15; |
986 | unsigned int rdy: 1; | 994 | unsigned int rdy: 1; |
@@ -3123,314 +3131,354 @@ static int header_len(__le16 ctl) | |||
3123 | return 24; | 3131 | return 24; |
3124 | } | 3132 | } |
3125 | 3133 | ||
3126 | static irqreturn_t airo_interrupt(int irq, void *dev_id) | 3134 | static void airo_handle_cisco_mic(struct airo_info *ai) |
3127 | { | 3135 | { |
3128 | struct net_device *dev = dev_id; | 3136 | if (test_bit(FLAG_MIC_CAPABLE, &ai->flags)) { |
3137 | set_bit(JOB_MIC, &ai->jobs); | ||
3138 | wake_up_interruptible(&ai->thr_wait); | ||
3139 | } | ||
3140 | } | ||
3141 | |||
3142 | /* Airo Status codes */ | ||
3143 | #define STAT_NOBEACON 0x8000 /* Loss of sync - missed beacons */ | ||
3144 | #define STAT_MAXRETRIES 0x8001 /* Loss of sync - max retries */ | ||
3145 | #define STAT_MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/ | ||
3146 | #define STAT_FORCELOSS 0x8003 /* Loss of sync - host request */ | ||
3147 | #define STAT_TSFSYNC 0x8004 /* Loss of sync - TSF synchronization */ | ||
3148 | #define STAT_DEAUTH 0x8100 /* low byte is 802.11 reason code */ | ||
3149 | #define STAT_DISASSOC 0x8200 /* low byte is 802.11 reason code */ | ||
3150 | #define STAT_ASSOC_FAIL 0x8400 /* low byte is 802.11 reason code */ | ||
3151 | #define STAT_AUTH_FAIL 0x0300 /* low byte is 802.11 reason code */ | ||
3152 | #define STAT_ASSOC 0x0400 /* Associated */ | ||
3153 | #define STAT_REASSOC 0x0600 /* Reassociated? Only on firmware >= 5.30.17 */ | ||
3154 | |||
3155 | static void airo_print_status(const char *devname, u16 status) | ||
3156 | { | ||
3157 | u8 reason = status & 0xFF; | ||
3158 | |||
3159 | switch (status) { | ||
3160 | case STAT_NOBEACON: | ||
3161 | airo_print_dbg(devname, "link lost (missed beacons)"); | ||
3162 | break; | ||
3163 | case STAT_MAXRETRIES: | ||
3164 | case STAT_MAXARL: | ||
3165 | airo_print_dbg(devname, "link lost (max retries)"); | ||
3166 | break; | ||
3167 | case STAT_FORCELOSS: | ||
3168 | airo_print_dbg(devname, "link lost (local choice)"); | ||
3169 | break; | ||
3170 | case STAT_TSFSYNC: | ||
3171 | airo_print_dbg(devname, "link lost (TSF sync lost)"); | ||
3172 | break; | ||
3173 | case STAT_DEAUTH: | ||
3174 | airo_print_dbg(devname, "deauthenticated (reason: %d)", reason); | ||
3175 | break; | ||
3176 | case STAT_DISASSOC: | ||
3177 | airo_print_dbg(devname, "disassociated (reason: %d)", reason); | ||
3178 | break; | ||
3179 | case STAT_ASSOC_FAIL: | ||
3180 | airo_print_dbg(devname, "association failed (reason: %d)", | ||
3181 | reason); | ||
3182 | break; | ||
3183 | case STAT_AUTH_FAIL: | ||
3184 | airo_print_dbg(devname, "authentication failed (reason: %d)", | ||
3185 | reason); | ||
3186 | break; | ||
3187 | default: | ||
3188 | break; | ||
3189 | } | ||
3190 | } | ||
3191 | |||
3192 | static void airo_handle_link(struct airo_info *ai) | ||
3193 | { | ||
3194 | union iwreq_data wrqu; | ||
3195 | int scan_forceloss = 0; | ||
3129 | u16 status; | 3196 | u16 status; |
3130 | u16 fid; | ||
3131 | struct airo_info *apriv = dev->ml_priv; | ||
3132 | u16 savedInterrupts = 0; | ||
3133 | int handled = 0; | ||
3134 | 3197 | ||
3135 | if (!netif_device_present(dev)) | 3198 | /* Get new status and acknowledge the link change */ |
3136 | return IRQ_NONE; | 3199 | status = le16_to_cpu(IN4500(ai, LINKSTAT)); |
3200 | OUT4500(ai, EVACK, EV_LINK); | ||
3137 | 3201 | ||
3138 | for (;;) { | 3202 | if ((status == STAT_FORCELOSS) && (ai->scan_timeout > 0)) |
3139 | status = IN4500( apriv, EVSTAT ); | 3203 | scan_forceloss = 1; |
3140 | if ( !(status & STATUS_INTS) || status == 0xffff ) break; | ||
3141 | 3204 | ||
3142 | handled = 1; | 3205 | airo_print_status(ai->dev->name, status); |
3143 | 3206 | ||
3144 | if ( status & EV_AWAKE ) { | 3207 | if ((status == STAT_ASSOC) || (status == STAT_REASSOC)) { |
3145 | OUT4500( apriv, EVACK, EV_AWAKE ); | 3208 | if (auto_wep) |
3146 | OUT4500( apriv, EVACK, EV_AWAKE ); | 3209 | ai->expires = 0; |
3147 | } | 3210 | if (ai->list_bss_task) |
3211 | wake_up_process(ai->list_bss_task); | ||
3212 | set_bit(FLAG_UPDATE_UNI, &ai->flags); | ||
3213 | set_bit(FLAG_UPDATE_MULTI, &ai->flags); | ||
3148 | 3214 | ||
3149 | if (!savedInterrupts) { | 3215 | if (down_trylock(&ai->sem) != 0) { |
3150 | savedInterrupts = IN4500( apriv, EVINTEN ); | 3216 | set_bit(JOB_EVENT, &ai->jobs); |
3151 | OUT4500( apriv, EVINTEN, 0 ); | 3217 | wake_up_interruptible(&ai->thr_wait); |
3218 | } else | ||
3219 | airo_send_event(ai->dev); | ||
3220 | } else if (!scan_forceloss) { | ||
3221 | if (auto_wep && !ai->expires) { | ||
3222 | ai->expires = RUN_AT(3*HZ); | ||
3223 | wake_up_interruptible(&ai->thr_wait); | ||
3152 | } | 3224 | } |
3153 | 3225 | ||
3154 | if ( status & EV_MIC ) { | 3226 | /* Send event to user space */ |
3155 | OUT4500( apriv, EVACK, EV_MIC ); | 3227 | memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); |
3156 | if (test_bit(FLAG_MIC_CAPABLE, &apriv->flags)) { | 3228 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; |
3157 | set_bit(JOB_MIC, &apriv->jobs); | 3229 | wireless_send_event(ai->dev, SIOCGIWAP, &wrqu, NULL); |
3158 | wake_up_interruptible(&apriv->thr_wait); | 3230 | } |
3159 | } | 3231 | } |
3160 | } | ||
3161 | if ( status & EV_LINK ) { | ||
3162 | union iwreq_data wrqu; | ||
3163 | int scan_forceloss = 0; | ||
3164 | /* The link status has changed, if you want to put a | ||
3165 | monitor hook in, do it here. (Remember that | ||
3166 | interrupts are still disabled!) | ||
3167 | */ | ||
3168 | u16 newStatus = IN4500(apriv, LINKSTAT); | ||
3169 | OUT4500( apriv, EVACK, EV_LINK); | ||
3170 | /* Here is what newStatus means: */ | ||
3171 | #define NOBEACON 0x8000 /* Loss of sync - missed beacons */ | ||
3172 | #define MAXRETRIES 0x8001 /* Loss of sync - max retries */ | ||
3173 | #define MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/ | ||
3174 | #define FORCELOSS 0x8003 /* Loss of sync - host request */ | ||
3175 | #define TSFSYNC 0x8004 /* Loss of sync - TSF synchronization */ | ||
3176 | #define DEAUTH 0x8100 /* Deauthentication (low byte is reason code) */ | ||
3177 | #define DISASS 0x8200 /* Disassociation (low byte is reason code) */ | ||
3178 | #define ASSFAIL 0x8400 /* Association failure (low byte is reason | ||
3179 | code) */ | ||
3180 | #define AUTHFAIL 0x0300 /* Authentication failure (low byte is reason | ||
3181 | code) */ | ||
3182 | #define ASSOCIATED 0x0400 /* Associated */ | ||
3183 | #define REASSOCIATED 0x0600 /* Reassociated? Only on firmware >= 5.30.17 */ | ||
3184 | #define RC_RESERVED 0 /* Reserved return code */ | ||
3185 | #define RC_NOREASON 1 /* Unspecified reason */ | ||
3186 | #define RC_AUTHINV 2 /* Previous authentication invalid */ | ||
3187 | #define RC_DEAUTH 3 /* Deauthenticated because sending station is | ||
3188 | leaving */ | ||
3189 | #define RC_NOACT 4 /* Disassociated due to inactivity */ | ||
3190 | #define RC_MAXLOAD 5 /* Disassociated because AP is unable to handle | ||
3191 | all currently associated stations */ | ||
3192 | #define RC_BADCLASS2 6 /* Class 2 frame received from | ||
3193 | non-Authenticated station */ | ||
3194 | #define RC_BADCLASS3 7 /* Class 3 frame received from | ||
3195 | non-Associated station */ | ||
3196 | #define RC_STATLEAVE 8 /* Disassociated because sending station is | ||
3197 | leaving BSS */ | ||
3198 | #define RC_NOAUTH 9 /* Station requesting (Re)Association is not | ||
3199 | Authenticated with the responding station */ | ||
3200 | if (newStatus == FORCELOSS && apriv->scan_timeout > 0) | ||
3201 | scan_forceloss = 1; | ||
3202 | if(newStatus == ASSOCIATED || newStatus == REASSOCIATED) { | ||
3203 | if (auto_wep) | ||
3204 | apriv->expires = 0; | ||
3205 | if (apriv->list_bss_task) | ||
3206 | wake_up_process(apriv->list_bss_task); | ||
3207 | set_bit(FLAG_UPDATE_UNI, &apriv->flags); | ||
3208 | set_bit(FLAG_UPDATE_MULTI, &apriv->flags); | ||
3209 | |||
3210 | if (down_trylock(&apriv->sem) != 0) { | ||
3211 | set_bit(JOB_EVENT, &apriv->jobs); | ||
3212 | wake_up_interruptible(&apriv->thr_wait); | ||
3213 | } else | ||
3214 | airo_send_event(dev); | ||
3215 | } else if (!scan_forceloss) { | ||
3216 | if (auto_wep && !apriv->expires) { | ||
3217 | apriv->expires = RUN_AT(3*HZ); | ||
3218 | wake_up_interruptible(&apriv->thr_wait); | ||
3219 | } | ||
3220 | 3232 | ||
3221 | /* Send event to user space */ | 3233 | static void airo_handle_rx(struct airo_info *ai) |
3222 | memset(wrqu.ap_addr.sa_data, '\0', ETH_ALEN); | 3234 | { |
3223 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | 3235 | struct sk_buff *skb = NULL; |
3224 | wireless_send_event(dev, SIOCGIWAP, &wrqu,NULL); | 3236 | __le16 fc, v, *buffer, tmpbuf[4]; |
3225 | } | 3237 | u16 len, hdrlen = 0, gap, fid; |
3226 | } | 3238 | struct rx_hdr hdr; |
3239 | int success = 0; | ||
3227 | 3240 | ||
3228 | /* Check to see if there is something to receive */ | 3241 | if (test_bit(FLAG_MPI, &ai->flags)) { |
3229 | if ( status & EV_RX ) { | 3242 | if (test_bit(FLAG_802_11, &ai->flags)) |
3230 | struct sk_buff *skb = NULL; | 3243 | mpi_receive_802_11(ai); |
3231 | __le16 fc, v; | 3244 | else |
3232 | u16 len, hdrlen = 0; | 3245 | mpi_receive_802_3(ai); |
3233 | #pragma pack(1) | 3246 | OUT4500(ai, EVACK, EV_RX); |
3234 | struct { | 3247 | return; |
3235 | __le16 status, len; | 3248 | } |
3236 | u8 rssi[2]; | ||
3237 | u8 rate; | ||
3238 | u8 freq; | ||
3239 | __le16 tmp[4]; | ||
3240 | } hdr; | ||
3241 | #pragma pack() | ||
3242 | u16 gap; | ||
3243 | __le16 tmpbuf[4]; | ||
3244 | __le16 *buffer; | ||
3245 | |||
3246 | if (test_bit(FLAG_MPI,&apriv->flags)) { | ||
3247 | if (test_bit(FLAG_802_11, &apriv->flags)) | ||
3248 | mpi_receive_802_11(apriv); | ||
3249 | else | ||
3250 | mpi_receive_802_3(apriv); | ||
3251 | OUT4500(apriv, EVACK, EV_RX); | ||
3252 | goto exitrx; | ||
3253 | } | ||
3254 | 3249 | ||
3255 | fid = IN4500( apriv, RXFID ); | 3250 | fid = IN4500(ai, RXFID); |
3256 | |||
3257 | /* Get the packet length */ | ||
3258 | if (test_bit(FLAG_802_11, &apriv->flags)) { | ||
3259 | bap_setup (apriv, fid, 4, BAP0); | ||
3260 | bap_read (apriv, (__le16*)&hdr, sizeof(hdr), BAP0); | ||
3261 | /* Bad CRC. Ignore packet */ | ||
3262 | if (le16_to_cpu(hdr.status) & 2) | ||
3263 | hdr.len = 0; | ||
3264 | if (apriv->wifidev == NULL) | ||
3265 | hdr.len = 0; | ||
3266 | } else { | ||
3267 | bap_setup (apriv, fid, 0x36, BAP0); | ||
3268 | bap_read (apriv, &hdr.len, 2, BAP0); | ||
3269 | } | ||
3270 | len = le16_to_cpu(hdr.len); | ||
3271 | 3251 | ||
3272 | if (len > AIRO_DEF_MTU) { | 3252 | /* Get the packet length */ |
3273 | airo_print_err(apriv->dev->name, "Bad size %d", len); | 3253 | if (test_bit(FLAG_802_11, &ai->flags)) { |
3274 | goto badrx; | 3254 | bap_setup (ai, fid, 4, BAP0); |
3275 | } | 3255 | bap_read (ai, (__le16*)&hdr, sizeof(hdr), BAP0); |
3276 | if (len == 0) | 3256 | /* Bad CRC. Ignore packet */ |
3277 | goto badrx; | 3257 | if (le16_to_cpu(hdr.status) & 2) |
3258 | hdr.len = 0; | ||
3259 | if (ai->wifidev == NULL) | ||
3260 | hdr.len = 0; | ||
3261 | } else { | ||
3262 | bap_setup(ai, fid, 0x36, BAP0); | ||
3263 | bap_read(ai, &hdr.len, 2, BAP0); | ||
3264 | } | ||
3265 | len = le16_to_cpu(hdr.len); | ||
3278 | 3266 | ||
3279 | if (test_bit(FLAG_802_11, &apriv->flags)) { | 3267 | if (len > AIRO_DEF_MTU) { |
3280 | bap_read (apriv, &fc, sizeof(fc), BAP0); | 3268 | airo_print_err(ai->dev->name, "Bad size %d", len); |
3281 | hdrlen = header_len(fc); | 3269 | goto done; |
3282 | } else | 3270 | } |
3283 | hdrlen = ETH_ALEN * 2; | 3271 | if (len == 0) |
3272 | goto done; | ||
3284 | 3273 | ||
3285 | skb = dev_alloc_skb( len + hdrlen + 2 + 2 ); | 3274 | if (test_bit(FLAG_802_11, &ai->flags)) { |
3286 | if ( !skb ) { | 3275 | bap_read(ai, &fc, sizeof (fc), BAP0); |
3287 | dev->stats.rx_dropped++; | 3276 | hdrlen = header_len(fc); |
3288 | goto badrx; | 3277 | } else |
3289 | } | 3278 | hdrlen = ETH_ALEN * 2; |
3290 | skb_reserve(skb, 2); /* This way the IP header is aligned */ | 3279 | |
3291 | buffer = (__le16*)skb_put (skb, len + hdrlen); | 3280 | skb = dev_alloc_skb(len + hdrlen + 2 + 2); |
3292 | if (test_bit(FLAG_802_11, &apriv->flags)) { | 3281 | if (!skb) { |
3293 | buffer[0] = fc; | 3282 | ai->dev->stats.rx_dropped++; |
3294 | bap_read (apriv, buffer + 1, hdrlen - 2, BAP0); | 3283 | goto done; |
3295 | if (hdrlen == 24) | 3284 | } |
3296 | bap_read (apriv, tmpbuf, 6, BAP0); | 3285 | |
3297 | 3286 | skb_reserve(skb, 2); /* This way the IP header is aligned */ | |
3298 | bap_read (apriv, &v, sizeof(v), BAP0); | 3287 | buffer = (__le16 *) skb_put(skb, len + hdrlen); |
3299 | gap = le16_to_cpu(v); | 3288 | if (test_bit(FLAG_802_11, &ai->flags)) { |
3300 | if (gap) { | 3289 | buffer[0] = fc; |
3301 | if (gap <= 8) { | 3290 | bap_read(ai, buffer + 1, hdrlen - 2, BAP0); |
3302 | bap_read (apriv, tmpbuf, gap, BAP0); | 3291 | if (hdrlen == 24) |
3303 | } else { | 3292 | bap_read(ai, tmpbuf, 6, BAP0); |
3304 | airo_print_err(apriv->dev->name, "gaplen too " | 3293 | |
3305 | "big. Problems will follow..."); | 3294 | bap_read(ai, &v, sizeof(v), BAP0); |
3306 | } | 3295 | gap = le16_to_cpu(v); |
3307 | } | 3296 | if (gap) { |
3308 | bap_read (apriv, buffer + hdrlen/2, len, BAP0); | 3297 | if (gap <= 8) { |
3298 | bap_read(ai, tmpbuf, gap, BAP0); | ||
3309 | } else { | 3299 | } else { |
3310 | MICBuffer micbuf; | 3300 | airo_print_err(ai->dev->name, "gaplen too " |
3311 | bap_read (apriv, buffer, ETH_ALEN*2, BAP0); | 3301 | "big. Problems will follow..."); |
3312 | if (apriv->micstats.enabled) { | 3302 | } |
3313 | bap_read (apriv,(__le16*)&micbuf,sizeof(micbuf),BAP0); | 3303 | } |
3314 | if (ntohs(micbuf.typelen) > 0x05DC) | 3304 | bap_read(ai, buffer + hdrlen/2, len, BAP0); |
3315 | bap_setup (apriv, fid, 0x44, BAP0); | 3305 | } else { |
3316 | else { | 3306 | MICBuffer micbuf; |
3317 | if (len <= sizeof(micbuf)) | 3307 | |
3318 | goto badmic; | 3308 | bap_read(ai, buffer, ETH_ALEN * 2, BAP0); |
3319 | 3309 | if (ai->micstats.enabled) { | |
3320 | len -= sizeof(micbuf); | 3310 | bap_read(ai, (__le16 *) &micbuf, sizeof (micbuf), BAP0); |
3321 | skb_trim (skb, len + hdrlen); | 3311 | if (ntohs(micbuf.typelen) > 0x05DC) |
3322 | } | 3312 | bap_setup(ai, fid, 0x44, BAP0); |
3323 | } | 3313 | else { |
3324 | bap_read(apriv,buffer+ETH_ALEN,len,BAP0); | 3314 | if (len <= sizeof (micbuf)) { |
3325 | if (decapsulate(apriv,&micbuf,(etherHead*)buffer,len)) { | 3315 | dev_kfree_skb_irq(skb); |
3326 | badmic: | 3316 | goto done; |
3327 | dev_kfree_skb_irq (skb); | ||
3328 | badrx: | ||
3329 | OUT4500( apriv, EVACK, EV_RX); | ||
3330 | goto exitrx; | ||
3331 | } | 3317 | } |
3318 | |||
3319 | len -= sizeof(micbuf); | ||
3320 | skb_trim(skb, len + hdrlen); | ||
3332 | } | 3321 | } |
3322 | } | ||
3323 | |||
3324 | bap_read(ai, buffer + ETH_ALEN, len, BAP0); | ||
3325 | if (decapsulate(ai, &micbuf, (etherHead*) buffer, len)) | ||
3326 | dev_kfree_skb_irq (skb); | ||
3327 | else | ||
3328 | success = 1; | ||
3329 | } | ||
3330 | |||
3333 | #ifdef WIRELESS_SPY | 3331 | #ifdef WIRELESS_SPY |
3334 | if (apriv->spy_data.spy_number > 0) { | 3332 | if (success && (ai->spy_data.spy_number > 0)) { |
3335 | char *sa; | 3333 | char *sa; |
3336 | struct iw_quality wstats; | 3334 | struct iw_quality wstats; |
3337 | /* Prepare spy data : addr + qual */ | 3335 | |
3338 | if (!test_bit(FLAG_802_11, &apriv->flags)) { | 3336 | /* Prepare spy data : addr + qual */ |
3339 | sa = (char*)buffer + 6; | 3337 | if (!test_bit(FLAG_802_11, &ai->flags)) { |
3340 | bap_setup (apriv, fid, 8, BAP0); | 3338 | sa = (char *) buffer + 6; |
3341 | bap_read (apriv, (__le16*)hdr.rssi, 2, BAP0); | 3339 | bap_setup(ai, fid, 8, BAP0); |
3342 | } else | 3340 | bap_read(ai, (__le16 *) hdr.rssi, 2, BAP0); |
3343 | sa = (char*)buffer + 10; | 3341 | } else |
3344 | wstats.qual = hdr.rssi[0]; | 3342 | sa = (char *) buffer + 10; |
3345 | if (apriv->rssi) | 3343 | wstats.qual = hdr.rssi[0]; |
3346 | wstats.level = 0x100 - apriv->rssi[hdr.rssi[1]].rssidBm; | 3344 | if (ai->rssi) |
3347 | else | 3345 | wstats.level = 0x100 - ai->rssi[hdr.rssi[1]].rssidBm; |
3348 | wstats.level = (hdr.rssi[1] + 321) / 2; | 3346 | else |
3349 | wstats.noise = apriv->wstats.qual.noise; | 3347 | wstats.level = (hdr.rssi[1] + 321) / 2; |
3350 | wstats.updated = IW_QUAL_LEVEL_UPDATED | 3348 | wstats.noise = ai->wstats.qual.noise; |
3351 | | IW_QUAL_QUAL_UPDATED | 3349 | wstats.updated = IW_QUAL_LEVEL_UPDATED |
3352 | | IW_QUAL_DBM; | 3350 | | IW_QUAL_QUAL_UPDATED |
3353 | /* Update spy records */ | 3351 | | IW_QUAL_DBM; |
3354 | wireless_spy_update(dev, sa, &wstats); | 3352 | /* Update spy records */ |
3355 | } | 3353 | wireless_spy_update(ai->dev, sa, &wstats); |
3354 | } | ||
3356 | #endif /* WIRELESS_SPY */ | 3355 | #endif /* WIRELESS_SPY */ |
3357 | OUT4500( apriv, EVACK, EV_RX); | ||
3358 | 3356 | ||
3359 | if (test_bit(FLAG_802_11, &apriv->flags)) { | 3357 | done: |
3360 | skb_reset_mac_header(skb); | 3358 | OUT4500(ai, EVACK, EV_RX); |
3361 | skb->pkt_type = PACKET_OTHERHOST; | 3359 | |
3362 | skb->dev = apriv->wifidev; | 3360 | if (success) { |
3363 | skb->protocol = htons(ETH_P_802_2); | 3361 | if (test_bit(FLAG_802_11, &ai->flags)) { |
3364 | } else | 3362 | skb_reset_mac_header(skb); |
3365 | skb->protocol = eth_type_trans(skb,dev); | 3363 | skb->pkt_type = PACKET_OTHERHOST; |
3366 | skb->ip_summed = CHECKSUM_NONE; | 3364 | skb->dev = ai->wifidev; |
3365 | skb->protocol = htons(ETH_P_802_2); | ||
3366 | } else | ||
3367 | skb->protocol = eth_type_trans(skb, ai->dev); | ||
3368 | skb->ip_summed = CHECKSUM_NONE; | ||
3369 | |||
3370 | netif_rx(skb); | ||
3371 | } | ||
3372 | } | ||
3373 | |||
3374 | static void airo_handle_tx(struct airo_info *ai, u16 status) | ||
3375 | { | ||
3376 | int i, len = 0, index = -1; | ||
3377 | u16 fid; | ||
3367 | 3378 | ||
3368 | netif_rx( skb ); | 3379 | if (test_bit(FLAG_MPI, &ai->flags)) { |
3380 | unsigned long flags; | ||
3381 | |||
3382 | if (status & EV_TXEXC) | ||
3383 | get_tx_error(ai, -1); | ||
3384 | |||
3385 | spin_lock_irqsave(&ai->aux_lock, flags); | ||
3386 | if (!skb_queue_empty(&ai->txq)) { | ||
3387 | spin_unlock_irqrestore(&ai->aux_lock,flags); | ||
3388 | mpi_send_packet(ai->dev); | ||
3389 | } else { | ||
3390 | clear_bit(FLAG_PENDING_XMIT, &ai->flags); | ||
3391 | spin_unlock_irqrestore(&ai->aux_lock,flags); | ||
3392 | netif_wake_queue(ai->dev); | ||
3369 | } | 3393 | } |
3370 | exitrx: | 3394 | OUT4500(ai, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC)); |
3395 | return; | ||
3396 | } | ||
3371 | 3397 | ||
3372 | /* Check to see if a packet has been transmitted */ | 3398 | fid = IN4500(ai, TXCOMPLFID); |
3373 | if ( status & ( EV_TX|EV_TXCPY|EV_TXEXC ) ) { | 3399 | |
3374 | int i; | 3400 | for(i = 0; i < MAX_FIDS; i++) { |
3375 | int len = 0; | 3401 | if ((ai->fids[i] & 0xffff) == fid) { |
3376 | int index = -1; | 3402 | len = ai->fids[i] >> 16; |
3377 | 3403 | index = i; | |
3378 | if (test_bit(FLAG_MPI,&apriv->flags)) { | 3404 | } |
3379 | unsigned long flags; | 3405 | } |
3380 | |||
3381 | if (status & EV_TXEXC) | ||
3382 | get_tx_error(apriv, -1); | ||
3383 | spin_lock_irqsave(&apriv->aux_lock, flags); | ||
3384 | if (!skb_queue_empty(&apriv->txq)) { | ||
3385 | spin_unlock_irqrestore(&apriv->aux_lock,flags); | ||
3386 | mpi_send_packet (dev); | ||
3387 | } else { | ||
3388 | clear_bit(FLAG_PENDING_XMIT, &apriv->flags); | ||
3389 | spin_unlock_irqrestore(&apriv->aux_lock,flags); | ||
3390 | netif_wake_queue (dev); | ||
3391 | } | ||
3392 | OUT4500( apriv, EVACK, | ||
3393 | status & (EV_TX|EV_TXCPY|EV_TXEXC)); | ||
3394 | goto exittx; | ||
3395 | } | ||
3396 | 3406 | ||
3397 | fid = IN4500(apriv, TXCOMPLFID); | 3407 | if (index != -1) { |
3408 | if (status & EV_TXEXC) | ||
3409 | get_tx_error(ai, index); | ||
3398 | 3410 | ||
3399 | for( i = 0; i < MAX_FIDS; i++ ) { | 3411 | OUT4500(ai, EVACK, status & (EV_TX | EV_TXEXC)); |
3400 | if ( ( apriv->fids[i] & 0xffff ) == fid ) { | 3412 | |
3401 | len = apriv->fids[i] >> 16; | 3413 | /* Set up to be used again */ |
3402 | index = i; | 3414 | ai->fids[index] &= 0xffff; |
3403 | } | 3415 | if (index < MAX_FIDS / 2) { |
3404 | } | 3416 | if (!test_bit(FLAG_PENDING_XMIT, &ai->flags)) |
3405 | if (index != -1) { | 3417 | netif_wake_queue(ai->dev); |
3406 | if (status & EV_TXEXC) | 3418 | } else { |
3407 | get_tx_error(apriv, index); | 3419 | if (!test_bit(FLAG_PENDING_XMIT11, &ai->flags)) |
3408 | OUT4500( apriv, EVACK, status & (EV_TX | EV_TXEXC)); | 3420 | netif_wake_queue(ai->wifidev); |
3409 | /* Set up to be used again */ | ||
3410 | apriv->fids[index] &= 0xffff; | ||
3411 | if (index < MAX_FIDS / 2) { | ||
3412 | if (!test_bit(FLAG_PENDING_XMIT, &apriv->flags)) | ||
3413 | netif_wake_queue(dev); | ||
3414 | } else { | ||
3415 | if (!test_bit(FLAG_PENDING_XMIT11, &apriv->flags)) | ||
3416 | netif_wake_queue(apriv->wifidev); | ||
3417 | } | ||
3418 | } else { | ||
3419 | OUT4500( apriv, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC)); | ||
3420 | airo_print_err(apriv->dev->name, "Unallocated FID was " | ||
3421 | "used to xmit" ); | ||
3422 | } | ||
3423 | } | 3421 | } |
3424 | exittx: | 3422 | } else { |
3425 | if ( status & ~STATUS_INTS & ~IGNORE_INTS ) | 3423 | OUT4500(ai, EVACK, status & (EV_TX | EV_TXCPY | EV_TXEXC)); |
3426 | airo_print_warn(apriv->dev->name, "Got weird status %x", | 3424 | airo_print_err(ai->dev->name, "Unallocated FID was used to xmit"); |
3425 | } | ||
3426 | } | ||
3427 | |||
3428 | static irqreturn_t airo_interrupt(int irq, void *dev_id) | ||
3429 | { | ||
3430 | struct net_device *dev = dev_id; | ||
3431 | u16 status, savedInterrupts = 0; | ||
3432 | struct airo_info *ai = dev->ml_priv; | ||
3433 | int handled = 0; | ||
3434 | |||
3435 | if (!netif_device_present(dev)) | ||
3436 | return IRQ_NONE; | ||
3437 | |||
3438 | for (;;) { | ||
3439 | status = IN4500(ai, EVSTAT); | ||
3440 | if (!(status & STATUS_INTS) || (status == 0xffff)) | ||
3441 | break; | ||
3442 | |||
3443 | handled = 1; | ||
3444 | |||
3445 | if (status & EV_AWAKE) { | ||
3446 | OUT4500(ai, EVACK, EV_AWAKE); | ||
3447 | OUT4500(ai, EVACK, EV_AWAKE); | ||
3448 | } | ||
3449 | |||
3450 | if (!savedInterrupts) { | ||
3451 | savedInterrupts = IN4500(ai, EVINTEN); | ||
3452 | OUT4500(ai, EVINTEN, 0); | ||
3453 | } | ||
3454 | |||
3455 | if (status & EV_MIC) { | ||
3456 | OUT4500(ai, EVACK, EV_MIC); | ||
3457 | airo_handle_cisco_mic(ai); | ||
3458 | } | ||
3459 | |||
3460 | if (status & EV_LINK) { | ||
3461 | /* Link status changed */ | ||
3462 | airo_handle_link(ai); | ||
3463 | } | ||
3464 | |||
3465 | /* Check to see if there is something to receive */ | ||
3466 | if (status & EV_RX) | ||
3467 | airo_handle_rx(ai); | ||
3468 | |||
3469 | /* Check to see if a packet has been transmitted */ | ||
3470 | if (status & (EV_TX | EV_TXCPY | EV_TXEXC)) | ||
3471 | airo_handle_tx(ai, status); | ||
3472 | |||
3473 | if ( status & ~STATUS_INTS & ~IGNORE_INTS ) { | ||
3474 | airo_print_warn(ai->dev->name, "Got weird status %x", | ||
3427 | status & ~STATUS_INTS & ~IGNORE_INTS ); | 3475 | status & ~STATUS_INTS & ~IGNORE_INTS ); |
3476 | } | ||
3428 | } | 3477 | } |
3429 | 3478 | ||
3430 | if (savedInterrupts) | 3479 | if (savedInterrupts) |
3431 | OUT4500( apriv, EVINTEN, savedInterrupts ); | 3480 | OUT4500(ai, EVINTEN, savedInterrupts); |
3432 | 3481 | ||
3433 | /* done.. */ | ||
3434 | return IRQ_RETVAL(handled); | 3482 | return IRQ_RETVAL(handled); |
3435 | } | 3483 | } |
3436 | 3484 | ||
@@ -3609,18 +3657,10 @@ static void mpi_receive_802_11(struct airo_info *ai) | |||
3609 | struct sk_buff *skb = NULL; | 3657 | struct sk_buff *skb = NULL; |
3610 | u16 len, hdrlen = 0; | 3658 | u16 len, hdrlen = 0; |
3611 | __le16 fc; | 3659 | __le16 fc; |
3612 | #pragma pack(1) | 3660 | struct rx_hdr hdr; |
3613 | struct { | ||
3614 | __le16 status, len; | ||
3615 | u8 rssi[2]; | ||
3616 | u8 rate; | ||
3617 | u8 freq; | ||
3618 | __le16 tmp[4]; | ||
3619 | } hdr; | ||
3620 | #pragma pack() | ||
3621 | u16 gap; | 3661 | u16 gap; |
3622 | u16 *buffer; | 3662 | u16 *buffer; |
3623 | char *ptr = ai->rxfids[0].virtual_host_addr+4; | 3663 | char *ptr = ai->rxfids[0].virtual_host_addr + 4; |
3624 | 3664 | ||
3625 | memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd)); | 3665 | memcpy_fromio(&rxd, ai->rxfids[0].card_ram_off, sizeof(rxd)); |
3626 | memcpy ((char *)&hdr, ptr, sizeof(hdr)); | 3666 | memcpy ((char *)&hdr, ptr, sizeof(hdr)); |
@@ -3687,6 +3727,7 @@ static void mpi_receive_802_11(struct airo_info *ai) | |||
3687 | skb->protocol = htons(ETH_P_802_2); | 3727 | skb->protocol = htons(ETH_P_802_2); |
3688 | skb->ip_summed = CHECKSUM_NONE; | 3728 | skb->ip_summed = CHECKSUM_NONE; |
3689 | netif_rx( skb ); | 3729 | netif_rx( skb ); |
3730 | |||
3690 | badrx: | 3731 | badrx: |
3691 | if (rxd.valid == 0) { | 3732 | if (rxd.valid == 0) { |
3692 | rxd.valid = 1; | 3733 | rxd.valid = 1; |