]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/char/pcmcia/ipwireless/hardware.c
libata: Avoid overflow in ata_tf_read_block() when tf->hba_lbal > 127
[linux-2.6-omap-h63xx.git] / drivers / char / pcmcia / ipwireless / hardware.c
index 0ccbbc1f593ab3edd7e07a9c0c95a8378108d1bf..4c1820cad71230045624f002368c6c03efbd0061 100644 (file)
 static void ipw_send_setup_packet(struct ipw_hardware *hw);
 static void handle_received_SETUP_packet(struct ipw_hardware *ipw,
                                         unsigned int address,
-                                        unsigned char *data, int len,
+                                        const unsigned char *data, int len,
                                         int is_last);
 static void ipwireless_setup_timer(unsigned long data);
 static void handle_received_CTRL_packet(struct ipw_hardware *hw,
-               unsigned int channel_idx, unsigned char *data, int len);
+               unsigned int channel_idx, const unsigned char *data, int len);
 
 /*#define TIMING_DIAGNOSTICS*/
 
@@ -79,8 +79,7 @@ static void report_timing(void)
                timing_stats.last_report_time = jiffies;
                if (!first)
                        printk(KERN_INFO IPWIRELESS_PCCARD_NAME
-                              ": %u us elapsed - read %lu bytes in %u us, "
-                              "wrote %lu bytes in %u us\n",
+                              ": %u us elapsed - read %lu bytes in %u us, wrote %lu bytes in %u us\n",
                               jiffies_to_usecs(since),
                               timing_stats.read_bytes,
                               jiffies_to_usecs(timing_stats.read_time),
@@ -133,29 +132,17 @@ enum {
 #define NL_FOLLOWING_PACKET_HEADER_SIZE    1
 
 struct nl_first_packet_header {
-#if defined(__BIG_ENDIAN_BITFIELD)
-       unsigned char packet_rank:2;
-       unsigned char address:3;
-       unsigned char protocol:3;
-#else
        unsigned char protocol:3;
        unsigned char address:3;
        unsigned char packet_rank:2;
-#endif
        unsigned char length_lsb;
        unsigned char length_msb;
 };
 
 struct nl_packet_header {
-#if defined(__BIG_ENDIAN_BITFIELD)
-       unsigned char packet_rank:2;
-       unsigned char address:3;
-       unsigned char protocol:3;
-#else
        unsigned char protocol:3;
        unsigned char address:3;
        unsigned char packet_rank:2;
-#endif
 };
 
 /* Value of 'packet_rank' above */
@@ -383,19 +370,44 @@ static void dump_data_bytes(const char *type, const unsigned char *data,
                        length < DUMP_MAX_BYTES ? length : DUMP_MAX_BYTES);
 }
 
-static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data,
+static void swap_packet_bitfield_to_le(unsigned char *data)
+{
+#ifdef __BIG_ENDIAN_BITFIELD
+       unsigned char tmp = *data, ret = 0;
+
+       /*
+        * transform bits from aa.bbb.ccc to ccc.bbb.aa
+        */
+       ret |= tmp & 0xc0 >> 6;
+       ret |= tmp & 0x38 >> 1;
+       ret |= tmp & 0x07 << 5;
+       *data = ret & 0xff;
+#endif
+}
+
+static void swap_packet_bitfield_from_le(unsigned char *data)
+{
+#ifdef __BIG_ENDIAN_BITFIELD
+       unsigned char tmp = *data, ret = 0;
+
+       /*
+        * transform bits from ccc.bbb.aa to aa.bbb.ccc
+        */
+       ret |= tmp & 0xe0 >> 5;
+       ret |= tmp & 0x1c << 1;
+       ret |= tmp & 0x03 << 6;
+       *data = ret & 0xff;
+#endif
+}
+
+static void do_send_fragment(struct ipw_hardware *hw, unsigned char *data,
                            unsigned length)
 {
        unsigned i;
        unsigned long flags;
 
        start_timing();
-
-       if (length == 0)
-               return 0;
-
-       if (length > hw->ll_mtu)
-               return -1;
+       BUG_ON(length > hw->ll_mtu);
 
        if (ipwireless_debug)
                dump_data_bytes("send", data, length);
@@ -403,6 +415,7 @@ static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data,
        spin_lock_irqsave(&hw->lock, flags);
 
        hw->tx_ready = 0;
+       swap_packet_bitfield_to_le(data);
 
        if (hw->hw_version == HW_VERSION_1) {
                outw((unsigned short) length, hw->base_port + IODWR);
@@ -440,11 +453,9 @@ static int do_send_fragment(struct ipw_hardware *hw, const unsigned char *data,
        spin_unlock_irqrestore(&hw->lock, flags);
 
        end_write_timing(length);
-
-       return 0;
 }
 
-static int do_send_packet(struct ipw_hardware *hw, struct ipw_tx_packet *packet)
+static void do_send_packet(struct ipw_hardware *hw, struct ipw_tx_packet *packet)
 {
        unsigned short fragment_data_len;
        unsigned short data_left = packet->length - packet->offset;
@@ -459,6 +470,10 @@ static int do_send_packet(struct ipw_hardware *hw, struct ipw_tx_packet *packet)
        if (data_left < fragment_data_len)
                fragment_data_len = data_left;
 
+       /*
+        * hdr_first is now in machine bitfield order, which will be swapped
+        * to le just before it goes to hw
+        */
        pkt.hdr_first.protocol = packet->protocol;
        pkt.hdr_first.address = packet->dest_addr;
        pkt.hdr_first.packet_rank = 0;
@@ -500,8 +515,6 @@ static int do_send_packet(struct ipw_hardware *hw, struct ipw_tx_packet *packet)
                                        packet->length);
                kfree(packet);
        }
-
-       return 0;
 }
 
 static void ipw_setup_hardware(struct ipw_hardware *hw)
@@ -550,11 +563,12 @@ static struct ipw_rx_packet *pool_allocate(struct ipw_hardware *hw,
                if (!list_empty(&hw->rx_pool)) {
                        packet = list_first_entry(&hw->rx_pool,
                                        struct ipw_rx_packet, queue);
-                       list_del(&packet->queue);
                        hw->rx_pool_size--;
                        spin_unlock_irqrestore(&hw->lock, flags);
+                       list_del(&packet->queue);
                } else {
-                       static int min_capacity = 256;
+                       const int min_capacity =
+                               ipwireless_ppp_mru(hw->network) + 2;
                        int new_capacity;
 
                        spin_unlock_irqrestore(&hw->lock, flags);
@@ -597,13 +611,15 @@ static void pool_free(struct ipw_hardware *hw, struct ipw_rx_packet *packet)
                kfree(packet);
        else {
                hw->rx_pool_size++;
-               list_add_tail(&packet->queue, &hw->rx_pool);
+               list_add(&packet->queue, &hw->rx_pool);
        }
 }
 
 static void queue_received_packet(struct ipw_hardware *hw,
-                                 unsigned int protocol, unsigned int address,
-                                 unsigned char *data, int length, int is_last)
+                                 unsigned int protocol,
+                                 unsigned int address,
+                                 const unsigned char *data, int length,
+                                 int is_last)
 {
        unsigned int channel_idx = address - 1;
        struct ipw_rx_packet *packet = NULL;
@@ -747,10 +763,10 @@ static void ipw_receive_data_work(struct work_struct *work_rx)
 
 static void handle_received_CTRL_packet(struct ipw_hardware *hw,
                                        unsigned int channel_idx,
-                                       unsigned char *data, int len)
+                                       const unsigned char *data, int len)
 {
-       struct ipw_control_packet_body *body =
-               (struct ipw_control_packet_body *) data;
+       const struct ipw_control_packet_body *body =
+               (const struct ipw_control_packet_body *) data;
        unsigned int changed_mask;
 
        if (len != sizeof(struct ipw_control_packet_body)) {
@@ -792,13 +808,13 @@ static void handle_received_CTRL_packet(struct ipw_hardware *hw,
 }
 
 static void handle_received_packet(struct ipw_hardware *hw,
-                                  union nl_packet *packet,
+                                  const union nl_packet *packet,
                                   unsigned short len)
 {
        unsigned int protocol = packet->hdr.protocol;
        unsigned int address = packet->hdr.address;
        unsigned int header_length;
-       unsigned char *data;
+       const unsigned char *data;
        unsigned int data_len;
        int is_last = packet->hdr.packet_rank & NL_LAST_PACKET;
 
@@ -846,8 +862,7 @@ static void do_receive_packet(struct ipw_hardware *hw)
                len = inw(hw->base_port + IODRR);
                if (len > hw->ll_mtu) {
                        printk(KERN_INFO IPWIRELESS_PCCARD_NAME
-                              ": received a packet of %u bytes - "
-                              "longer than the MTU!\n", len);
+                              ": received a packet of %u bytes - longer than the MTU!\n", len);
                        outw(DCR_RXDONE | DCR_RXRESET, hw->base_port + IODCR);
                        return;
                }
@@ -863,8 +878,7 @@ static void do_receive_packet(struct ipw_hardware *hw)
                len = inw(hw->base_port);
                if (len > hw->ll_mtu) {
                        printk(KERN_INFO IPWIRELESS_PCCARD_NAME
-                              ": received a packet of %u bytes - "
-                              "longer than the MTU!\n", len);
+                              ": received a packet of %u bytes - longer than the MTU!\n", len);
                        writew(MEMRX_PCINTACKK,
                                &hw->memory_info_regs->memreg_pc_interrupt_ack);
                        return;
@@ -886,6 +900,8 @@ static void do_receive_packet(struct ipw_hardware *hw)
 
        acknowledge_data_read(hw);
 
+       swap_packet_bitfield_from_le(pkt);
+
        if (ipwireless_debug)
                dump_data_bytes("recv", pkt, len);
 
@@ -1180,8 +1196,7 @@ static irqreturn_t ipwireless_handle_v2_v3_interrupt(int irq,
                                        ": spurious interrupt - new_tx mode\n");
                        else {
                                printk(KERN_WARNING IPWIRELESS_PCCARD_NAME
-                                       ": no valid memreg_tx value - "
-                                       "switching to the old memreg_tx\n");
+                                       ": no valid memreg_tx value - switching to the old memreg_tx\n");
                                hw->memreg_tx =
                                        &hw->memory_info_regs->memreg_tx_old;
                                try_mem_tx_old = 1;
@@ -1276,7 +1291,7 @@ static void *alloc_ctrl_packet(int header_size,
 }
 
 int ipwireless_send_packet(struct ipw_hardware *hw, unsigned int channel_idx,
-                           unsigned char *data, unsigned int length,
+                           const unsigned char *data, unsigned int length,
                            void (*callback) (void *cb, unsigned int length),
                            void *callback_data)
 {
@@ -1487,8 +1502,7 @@ static void handle_setup_get_version_rsp(struct ipw_hardware *hw,
        if (vers_no == TL_SETUP_VERSION)
                __handle_setup_get_version_rsp(hw);
        else
-               printk(KERN_ERR
-                               IPWIRELESS_PCCARD_NAME
+               printk(KERN_ERR IPWIRELESS_PCCARD_NAME
                                ": invalid hardware version no %u\n",
                                (unsigned int) vers_no);
 }
@@ -1511,10 +1525,10 @@ static void ipw_send_setup_packet(struct ipw_hardware *hw)
 
 static void handle_received_SETUP_packet(struct ipw_hardware *hw,
                                         unsigned int address,
-                                        unsigned char *data, int len,
+                                        const unsigned char *data, int len,
                                         int is_last)
 {
-       union ipw_setup_rx_msg *rx_msg = (union ipw_setup_rx_msg *) data;
+       const union ipw_setup_rx_msg *rx_msg = (const union ipw_setup_rx_msg *) data;
 
        if (address != ADDR_SETUP_PROT) {
                printk(KERN_INFO IPWIRELESS_PCCARD_NAME