Merge git://git.kernel.org/pub/scm/linux/kernel/git/agk/linux-2.6-dm
[sfrench/cifs-2.6.git] / drivers / net / hamradio / yam.c
index 5407f7486c9c00cdc310962e237284897eac9113..b06691937ce947b980dc73360ed72afa09abd1cd 100644 (file)
@@ -55,6 +55,8 @@
 #include <asm/system.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
 
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/init.h>
 
 #include <linux/yam.h>
-#include "yam9600.h"
-#include "yam1200.h"
 
 /* --------------------------------------------------------------------- */
 
 static const char yam_drvname[] = "yam";
-static char yam_drvinfo[] __initdata = KERN_INFO "YAM driver version 0.8 by F1OAT/F6FBB\n";
+static const char yam_drvinfo[] __initdata = KERN_INFO \
+       "YAM driver version 0.8 by F1OAT/F6FBB\n";
 
 /* --------------------------------------------------------------------- */
 
+#define FIRMWARE_9600  "yam/9600.bin"
+#define FIRMWARE_1200  "yam/1200.bin"
+
 #define YAM_9600       1
 #define YAM_1200       2
 
@@ -115,10 +119,6 @@ struct yam_port {
 
        struct net_device *dev;
 
-       /* Stats section */
-
-       struct net_device_stats stats;
-
        int nb_rxint;
        int nb_mdint;
 
@@ -345,9 +345,51 @@ static int fpga_write(int iobase, unsigned char wrd)
        return 0;
 }
 
-static unsigned char *add_mcs(unsigned char *bits, int bitrate)
+/*
+ * predef should be 0 for loading user defined mcs
+ * predef should be YAM_1200 for loading predef 1200 mcs
+ * predef should be YAM_9600 for loading predef 9600 mcs
+ */
+static unsigned char *add_mcs(unsigned char *bits, int bitrate,
+                             unsigned int predef)
 {
+       const char *fw_name[2] = {FIRMWARE_9600, FIRMWARE_1200};
+       const struct firmware *fw;
+       struct platform_device *pdev;
        struct yam_mcs *p;
+       int err;
+
+       switch (predef) {
+       case 0:
+               fw = NULL;
+               break;
+       case YAM_1200:
+       case YAM_9600:
+               predef--;
+               pdev = platform_device_register_simple("yam", 0, NULL, 0);
+               if (IS_ERR(pdev)) {
+                       printk(KERN_ERR "yam: Failed to register firmware\n");
+                       return NULL;
+               }
+               err = request_firmware(&fw, fw_name[predef], &pdev->dev);
+               platform_device_unregister(pdev);
+               if (err) {
+                       printk(KERN_ERR "Failed to load firmware \"%s\"\n",
+                              fw_name[predef]);
+                       return NULL;
+               }
+               if (fw->size != YAM_FPGA_SIZE) {
+                       printk(KERN_ERR "Bogus length %zu in firmware \"%s\"\n",
+                              fw->size, fw_name[predef]);
+                       release_firmware(fw);
+                       return NULL;
+               }
+               bits = (unsigned char *)fw->data;
+               break;
+       default:
+               printk(KERN_ERR "yam: Invalid predef number %u\n", predef);
+               return NULL;
+       }
 
        /* If it already exists, replace the bit data */
        p = yam_data;
@@ -362,6 +404,7 @@ static unsigned char *add_mcs(unsigned char *bits, int bitrate)
        /* Allocate a new mcs */
        if ((p = kmalloc(sizeof(struct yam_mcs), GFP_KERNEL)) == NULL) {
                printk(KERN_WARNING "YAM: no memory to allocate mcs\n");
+               release_firmware(fw);
                return NULL;
        }
        memcpy(p->bits, bits, YAM_FPGA_SIZE);
@@ -369,6 +412,7 @@ static unsigned char *add_mcs(unsigned char *bits, int bitrate)
        p->next = yam_data;
        yam_data = p;
 
+       release_firmware(fw);
        return p->bits;
 }
 
@@ -386,9 +430,11 @@ static unsigned char *get_mcs(int bitrate)
        /* Load predefined mcs data */
        switch (bitrate) {
        case 1200:
-               return add_mcs(bits_1200, bitrate);
+               /* setting predef as YAM_1200 for loading predef 1200 mcs */
+               return add_mcs(NULL, bitrate, YAM_1200);
        default:
-               return add_mcs(bits_9600, bitrate);
+               /* setting predef as YAM_9600 for loading predef 9600 mcs */
+               return add_mcs(NULL, bitrate, YAM_9600);
        }
 }
 
@@ -507,7 +553,7 @@ static inline void yam_rx_flag(struct net_device *dev, struct yam_port *yp)
                } else {
                        if (!(skb = dev_alloc_skb(pkt_len))) {
                                printk(KERN_WARNING "%s: memory squeeze, dropping packet\n", dev->name);
-                               ++yp->stats.rx_dropped;
+                               ++dev->stats.rx_dropped;
                        } else {
                                unsigned char *cp;
                                cp = skb_put(skb, pkt_len);
@@ -515,7 +561,7 @@ static inline void yam_rx_flag(struct net_device *dev, struct yam_port *yp)
                                memcpy(cp, yp->rx_buf, pkt_len - 1);
                                skb->protocol = ax25_type_trans(skb, dev);
                                netif_rx(skb);
-                               ++yp->stats.rx_packets;
+                               ++dev->stats.rx_packets;
                        }
                }
        }
@@ -677,7 +723,7 @@ static void yam_tx_byte(struct net_device *dev, struct yam_port *yp)
                        yp->tx_count = 1;
                        yp->tx_state = TX_HEAD;
                }
-               ++yp->stats.tx_packets;
+               ++dev->stats.tx_packets;
                break;
        case TX_TAIL:
                if (--yp->tx_count <= 0) {
@@ -716,7 +762,7 @@ static irqreturn_t yam_interrupt(int irq, void *dev_id)
                        handled = 1;
 
                        if (lsr & LSR_OE)
-                               ++yp->stats.rx_fifo_errors;
+                               ++dev->stats.rx_fifo_errors;
 
                        yp->dcd = (msr & RX_DCD) ? 1 : 0;
 
@@ -778,16 +824,16 @@ static int yam_seq_show(struct seq_file *seq, void *v)
        seq_printf(seq, "  TxTail   %u\n", yp->txtail);
        seq_printf(seq, "  SlotTime %u\n", yp->slot);
        seq_printf(seq, "  Persist  %u\n", yp->pers);
-       seq_printf(seq, "  TxFrames %lu\n", yp->stats.tx_packets);
-       seq_printf(seq, "  RxFrames %lu\n", yp->stats.rx_packets);
+       seq_printf(seq, "  TxFrames %lu\n", dev->stats.tx_packets);
+       seq_printf(seq, "  RxFrames %lu\n", dev->stats.rx_packets);
        seq_printf(seq, "  TxInt    %u\n", yp->nb_mdint);
        seq_printf(seq, "  RxInt    %u\n", yp->nb_rxint);
-       seq_printf(seq, "  RxOver   %lu\n", yp->stats.rx_fifo_errors);
+       seq_printf(seq, "  RxOver   %lu\n", dev->stats.rx_fifo_errors);
        seq_printf(seq, "\n");
        return 0;
 }
 
-static struct seq_operations yam_seqops = {
+static const struct seq_operations yam_seqops = {
        .start = yam_seq_start,
        .next = yam_seq_next,
        .stop = yam_seq_stop,
@@ -810,26 +856,6 @@ static const struct file_operations yam_info_fops = {
 #endif
 
 
-/* --------------------------------------------------------------------- */
-
-static struct net_device_stats *yam_get_stats(struct net_device *dev)
-{
-       struct yam_port *yp;
-
-       if (!dev)
-               return NULL;
-
-       yp = netdev_priv(dev);
-       if (yp->magic != YAM_MAGIC)
-               return NULL;
-
-       /* 
-        * Get the current statistics.  This may be called with the
-        * card open or closed. 
-        */
-       return &yp->stats;
-}
-
 /* --------------------------------------------------------------------- */
 
 static int yam_open(struct net_device *dev)
@@ -877,10 +903,10 @@ static int yam_open(struct net_device *dev)
 
        /* Reset overruns for all ports - FPGA programming makes overruns */
        for (i = 0; i < NR_PORTS; i++) {
-               struct net_device *dev = yam_devs[i];
-               struct yam_port *yp = netdev_priv(dev);
-               inb(LSR(dev->base_addr));
-               yp->stats.rx_fifo_errors = 0;
+               struct net_device *yam_dev = yam_devs[i];
+
+               inb(LSR(yam_dev->base_addr));
+               yam_dev->stats.rx_fifo_errors = 0;
        }
 
        printk(KERN_INFO "%s at iobase 0x%lx irq %u uart %s\n", dev->name, dev->base_addr, dev->irq,
@@ -959,7 +985,8 @@ static int yam_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                        kfree(ym);
                        return -EINVAL;
                }
-               add_mcs(ym->bits, ym->bitrate);
+               /* setting predef as 0 for loading userdefined mcs data */
+               add_mcs(ym->bits, ym->bitrate, 0);
                kfree(ym);
                break;
 
@@ -1068,6 +1095,14 @@ static int yam_set_mac_address(struct net_device *dev, void *addr)
 
 /* --------------------------------------------------------------------- */
 
+static const struct net_device_ops yam_netdev_ops = {
+       .ndo_open            = yam_open,
+       .ndo_stop            = yam_close,
+       .ndo_start_xmit      = yam_send_packet,
+       .ndo_do_ioctl        = yam_ioctl,
+       .ndo_set_mac_address = yam_set_mac_address,
+};
+
 static void yam_setup(struct net_device *dev)
 {
        struct yam_port *yp = netdev_priv(dev);
@@ -1088,18 +1123,11 @@ static void yam_setup(struct net_device *dev)
        dev->base_addr = yp->iobase;
        dev->irq = yp->irq;
 
-       dev->open = yam_open;
-       dev->stop = yam_close;
-       dev->do_ioctl = yam_ioctl;
-       dev->hard_start_xmit = yam_send_packet;
-       dev->get_stats = yam_get_stats;
-
        skb_queue_head_init(&yp->send_queue);
 
+       dev->netdev_ops = &yam_netdev_ops;
        dev->header_ops = &ax25_header_ops;
 
-       dev->set_mac_address = yam_set_mac_address;
-
        dev->type = ARPHRD_AX25;
        dev->hard_header_len = AX25_MAX_HEADER_LEN;
        dev->mtu = AX25_MTU;
@@ -1181,6 +1209,8 @@ static void __exit yam_cleanup_driver(void)
 MODULE_AUTHOR("Frederic Rible F1OAT frible@teaser.fr");
 MODULE_DESCRIPTION("Yam amateur radio modem driver");
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(FIRMWARE_1200);
+MODULE_FIRMWARE(FIRMWARE_9600);
 
 module_init(yam_init_driver);
 module_exit(yam_cleanup_driver);