Krzysztof Halasa | 921a86e | 2010-08-12 23:14:07 +0200 | [diff] [blame] | 1 | /* |
| 2 | * SBE 2T3E3 synchronous serial card driver for Linux |
| 3 | * |
| 4 | * Copyright (C) 2009-2010 Krzysztof Halasa <khc@pm.waw.pl> |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify it |
| 7 | * under the terms of version 2 of the GNU General Public License |
| 8 | * as published by the Free Software Foundation. |
| 9 | * |
| 10 | * This code is based on a driver written by SBE Inc. |
| 11 | */ |
| 12 | |
YAMANE Toshiaki | a17d23d | 2012-10-24 11:52:58 +0900 | [diff] [blame^] | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 14 | |
Krzysztof Halasa | 921a86e | 2010-08-12 23:14:07 +0200 | [diff] [blame] | 15 | #include <linux/module.h> |
| 16 | #include <linux/slab.h> |
| 17 | #include <linux/delay.h> |
| 18 | #include <linux/netdevice.h> |
| 19 | #include <linux/pci.h> |
| 20 | #include <linux/hdlc.h> |
| 21 | #include <linux/if_arp.h> |
| 22 | #include <linux/interrupt.h> |
| 23 | #include "2t3e3.h" |
| 24 | |
| 25 | static void check_leds(unsigned long arg) |
| 26 | { |
| 27 | struct card *card = (struct card *)arg; |
| 28 | struct channel *channel0 = &card->channels[0]; |
| 29 | static int blinker; |
| 30 | |
| 31 | update_led(channel0, ++blinker); |
| 32 | if (has_two_ports(channel0->pdev)) |
| 33 | update_led(&card->channels[1], blinker); |
| 34 | |
| 35 | card->timer.expires = jiffies + HZ / 10; |
| 36 | add_timer(&card->timer); |
| 37 | } |
| 38 | |
| 39 | static void t3e3_remove_channel(struct channel *channel) |
| 40 | { |
| 41 | struct pci_dev *pdev = channel->pdev; |
| 42 | struct net_device *dev = channel->dev; |
| 43 | |
| 44 | /* system hangs if board asserts irq while module is unloaded */ |
| 45 | cpld_stop_intr(channel); |
| 46 | free_irq(dev->irq, dev); |
| 47 | dc_drop_descriptor_list(channel); |
| 48 | unregister_hdlc_device(dev); |
| 49 | free_netdev(dev); |
| 50 | pci_release_regions(pdev); |
| 51 | pci_disable_device(pdev); |
| 52 | pci_set_drvdata(pdev, NULL); |
| 53 | } |
| 54 | |
| 55 | static int __devinit t3e3_init_channel(struct channel *channel, struct pci_dev *pdev, struct card *card) |
| 56 | { |
| 57 | struct net_device *dev; |
| 58 | unsigned int val; |
| 59 | int err; |
| 60 | |
| 61 | err = pci_enable_device(pdev); |
| 62 | if (err) |
| 63 | return err; |
| 64 | |
| 65 | err = pci_request_regions(pdev, "SBE 2T3E3"); |
| 66 | if (err) |
| 67 | goto disable; |
| 68 | |
| 69 | dev = alloc_hdlcdev(channel); |
| 70 | if (!dev) { |
YAMANE Toshiaki | a17d23d | 2012-10-24 11:52:58 +0900 | [diff] [blame^] | 71 | pr_err("Out of memory\n"); |
Alexey Khoroshilov | 4c229df | 2012-09-25 16:56:02 +0400 | [diff] [blame] | 72 | err = -ENOMEM; |
Krzysztof Halasa | 921a86e | 2010-08-12 23:14:07 +0200 | [diff] [blame] | 73 | goto free_regions; |
| 74 | } |
| 75 | |
| 76 | t3e3_sc_init(channel); |
| 77 | dev_to_priv(dev) = channel; |
| 78 | |
| 79 | channel->pdev = pdev; |
| 80 | channel->dev = dev; |
| 81 | channel->card = card; |
| 82 | channel->addr = pci_resource_start(pdev, 0); |
| 83 | if (pdev->subsystem_device == PCI_SUBDEVICE_ID_SBE_2T3E3_P1) |
| 84 | channel->h.slot = 1; |
| 85 | else |
| 86 | channel->h.slot = 0; |
| 87 | |
Alexey Khoroshilov | 4c229df | 2012-09-25 16:56:02 +0400 | [diff] [blame] | 88 | err = setup_device(dev, channel); |
| 89 | if (err) |
| 90 | goto free_dev; |
Krzysztof Halasa | 921a86e | 2010-08-12 23:14:07 +0200 | [diff] [blame] | 91 | |
| 92 | pci_read_config_dword(channel->pdev, 0x40, &val); /* mask sleep mode */ |
| 93 | pci_write_config_dword(channel->pdev, 0x40, val & 0x3FFFFFFF); |
| 94 | |
| 95 | pci_read_config_byte(channel->pdev, PCI_CACHE_LINE_SIZE, &channel->h.cache_size); |
| 96 | pci_read_config_dword(channel->pdev, PCI_COMMAND, &channel->h.command); |
| 97 | t3e3_init(channel); |
| 98 | |
Alexey Khoroshilov | 4c229df | 2012-09-25 16:56:02 +0400 | [diff] [blame] | 99 | err = request_irq(dev->irq, &t3e3_intr, IRQF_SHARED, dev->name, dev); |
| 100 | if (err) { |
YAMANE Toshiaki | a17d23d | 2012-10-24 11:52:58 +0900 | [diff] [blame^] | 101 | netdev_warn(channel->dev, "%s: could not get irq: %d\n", |
| 102 | dev->name, dev->irq); |
Alexey Khoroshilov | 4c229df | 2012-09-25 16:56:02 +0400 | [diff] [blame] | 103 | goto unregister_dev; |
Krzysztof Halasa | 921a86e | 2010-08-12 23:14:07 +0200 | [diff] [blame] | 104 | } |
| 105 | |
| 106 | pci_set_drvdata(pdev, channel); |
| 107 | return 0; |
| 108 | |
Alexey Khoroshilov | 4c229df | 2012-09-25 16:56:02 +0400 | [diff] [blame] | 109 | unregister_dev: |
| 110 | unregister_hdlc_device(dev); |
| 111 | free_dev: |
| 112 | free_netdev(dev); |
Krzysztof Halasa | 921a86e | 2010-08-12 23:14:07 +0200 | [diff] [blame] | 113 | free_regions: |
| 114 | pci_release_regions(pdev); |
| 115 | disable: |
| 116 | pci_disable_device(pdev); |
| 117 | return err; |
| 118 | } |
| 119 | |
| 120 | static void __devexit t3e3_remove_card(struct pci_dev *pdev) |
| 121 | { |
| 122 | struct channel *channel0 = pci_get_drvdata(pdev); |
| 123 | struct card *card = channel0->card; |
| 124 | |
| 125 | del_timer(&card->timer); |
| 126 | if (has_two_ports(channel0->pdev)) { |
| 127 | t3e3_remove_channel(&card->channels[1]); |
| 128 | pci_dev_put(card->channels[1].pdev); |
| 129 | } |
| 130 | t3e3_remove_channel(channel0); |
| 131 | kfree(card); |
| 132 | } |
| 133 | |
| 134 | static int __devinit t3e3_init_card(struct pci_dev *pdev, const struct pci_device_id *ent) |
| 135 | { |
| 136 | /* pdev points to channel #0 */ |
| 137 | struct pci_dev *pdev1 = NULL; |
| 138 | struct card *card; |
| 139 | int channels = 1, err; |
| 140 | |
| 141 | if (has_two_ports(pdev)) { |
| 142 | while ((pdev1 = pci_get_subsys(PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, |
| 143 | PCI_VENDOR_ID_SBE, PCI_SUBDEVICE_ID_SBE_2T3E3_P1, |
| 144 | pdev1))) |
| 145 | if (pdev1->bus == pdev->bus && |
| 146 | pdev1->devfn == pdev->devfn + 8 /* next device on the same bus */) |
| 147 | break; /* found the second channel */ |
| 148 | |
| 149 | if (!pdev1) { |
YAMANE Toshiaki | a17d23d | 2012-10-24 11:52:58 +0900 | [diff] [blame^] | 150 | dev_err(&pdev->dev, "Can't find the second channel\n"); |
Krzysztof Halasa | 921a86e | 2010-08-12 23:14:07 +0200 | [diff] [blame] | 151 | return -EFAULT; |
| 152 | } |
| 153 | channels = 2; |
| 154 | /* holds the reference for pdev1 */ |
| 155 | } |
| 156 | |
| 157 | card = kzalloc(sizeof(struct card) + channels * sizeof(struct channel), GFP_KERNEL); |
| 158 | if (!card) { |
YAMANE Toshiaki | a17d23d | 2012-10-24 11:52:58 +0900 | [diff] [blame^] | 159 | dev_err(&pdev->dev, "Out of memory\n"); |
Krzysztof Halasa | 921a86e | 2010-08-12 23:14:07 +0200 | [diff] [blame] | 160 | return -ENOBUFS; |
| 161 | } |
| 162 | |
| 163 | spin_lock_init(&card->bootrom_lock); |
| 164 | card->bootrom_addr = pci_resource_start(pdev, 0); |
| 165 | |
| 166 | err = t3e3_init_channel(&card->channels[0], pdev, card); |
| 167 | if (err) |
| 168 | goto free_card; |
| 169 | |
| 170 | if (channels == 2) { |
| 171 | err = t3e3_init_channel(&card->channels[1], pdev1, card); |
| 172 | if (err) { |
| 173 | t3e3_remove_channel(&card->channels[0]); |
| 174 | goto free_card; |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | /* start LED timer */ |
| 179 | init_timer(&card->timer); |
| 180 | card->timer.function = check_leds; |
| 181 | card->timer.expires = jiffies + HZ / 10; |
| 182 | card->timer.data = (unsigned long)card; |
| 183 | add_timer(&card->timer); |
| 184 | return 0; |
| 185 | |
| 186 | free_card: |
| 187 | kfree(card); |
| 188 | return err; |
| 189 | } |
| 190 | |
| 191 | static struct pci_device_id t3e3_pci_tbl[] __devinitdata = { |
| 192 | { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, |
| 193 | PCI_VENDOR_ID_SBE, PCI_SUBDEVICE_ID_SBE_T3E3, 0, 0, 0 }, |
| 194 | { PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_21142, |
| 195 | PCI_VENDOR_ID_SBE, PCI_SUBDEVICE_ID_SBE_2T3E3_P0, 0, 0, 0 }, |
| 196 | /* channel 1 will be initialized after channel 0 */ |
| 197 | { 0, } |
| 198 | }; |
| 199 | |
| 200 | static struct pci_driver t3e3_pci_driver = { |
| 201 | .name = "SBE T3E3", |
| 202 | .id_table = t3e3_pci_tbl, |
| 203 | .probe = t3e3_init_card, |
| 204 | .remove = t3e3_remove_card, |
| 205 | }; |
| 206 | |
Devendra Naga | 1cdb9c7 | 2012-07-10 12:10:04 +0530 | [diff] [blame] | 207 | module_pci_driver(t3e3_pci_driver); |
Krzysztof Halasa | 921a86e | 2010-08-12 23:14:07 +0200 | [diff] [blame] | 208 | MODULE_LICENSE("GPL"); |
| 209 | MODULE_DEVICE_TABLE(pci, t3e3_pci_tbl); |