diff options
Diffstat (limited to 'drivers/net/ethernet/8390')
-rw-r--r-- | drivers/net/ethernet/8390/Kconfig | 14 | ||||
-rw-r--r-- | drivers/net/ethernet/8390/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/8390/mcf8390.c | 480 |
3 files changed, 495 insertions, 0 deletions
diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig index 2e538676924d..e1219e037c04 100644 --- a/drivers/net/ethernet/8390/Kconfig +++ b/drivers/net/ethernet/8390/Kconfig | |||
@@ -162,6 +162,20 @@ config MAC8390 | |||
162 | and read the Ethernet-HOWTO, available from | 162 | and read the Ethernet-HOWTO, available from |
163 | <http://www.tldp.org/docs.html#howto>. | 163 | <http://www.tldp.org/docs.html#howto>. |
164 | 164 | ||
165 | config MCF8390 | ||
166 | tristate "ColdFire NS8390 based Ethernet support" | ||
167 | depends on COLDFIRE | ||
168 | select CRC32 | ||
169 | ---help--- | ||
170 | This driver is for Ethernet devices using an NS8390-compatible | ||
171 | chipset on many common ColdFire CPU based boards. Many of the older | ||
172 | Freescale dev boards use this, and some other common boards like | ||
173 | some SnapGear routers do as well. | ||
174 | |||
175 | If you have one of these boards and want to use the network interface | ||
176 | on them then choose Y. To compile this driver as a module, choose M | ||
177 | here, the module will be called mcf8390. | ||
178 | |||
165 | config NE2000 | 179 | config NE2000 |
166 | tristate "NE2000/NE1000 support" | 180 | tristate "NE2000/NE1000 support" |
167 | depends on (ISA || (Q40 && m) || M32R || MACH_TX49XX) | 181 | depends on (ISA || (Q40 && m) || M32R || MACH_TX49XX) |
diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile index d13790b7fd27..f43038babf86 100644 --- a/drivers/net/ethernet/8390/Makefile +++ b/drivers/net/ethernet/8390/Makefile | |||
@@ -14,6 +14,7 @@ obj-$(CONFIG_HPLAN_PLUS) += hp-plus.o 8390p.o | |||
14 | obj-$(CONFIG_HPLAN) += hp.o 8390p.o | 14 | obj-$(CONFIG_HPLAN) += hp.o 8390p.o |
15 | obj-$(CONFIG_HYDRA) += hydra.o 8390.o | 15 | obj-$(CONFIG_HYDRA) += hydra.o 8390.o |
16 | obj-$(CONFIG_LNE390) += lne390.o 8390.o | 16 | obj-$(CONFIG_LNE390) += lne390.o 8390.o |
17 | obj-$(CONFIG_MCF8390) += mcf8390.o 8390.o | ||
17 | obj-$(CONFIG_NE2000) += ne.o 8390p.o | 18 | obj-$(CONFIG_NE2000) += ne.o 8390p.o |
18 | obj-$(CONFIG_NE2_MCA) += ne2.o 8390p.o | 19 | obj-$(CONFIG_NE2_MCA) += ne2.o 8390p.o |
19 | obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o | 20 | obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o |
diff --git a/drivers/net/ethernet/8390/mcf8390.c b/drivers/net/ethernet/8390/mcf8390.c new file mode 100644 index 000000000000..230efd6fa5d5 --- /dev/null +++ b/drivers/net/ethernet/8390/mcf8390.c | |||
@@ -0,0 +1,480 @@ | |||
1 | /* | ||
2 | * Support for ColdFire CPU based boards using a NS8390 Ethernet device. | ||
3 | * | ||
4 | * Derived from the many other 8390 drivers. | ||
5 | * | ||
6 | * (C) Copyright 2012, Greg Ungerer <gerg@uclinux.org> | ||
7 | * | ||
8 | * This file is subject to the terms and conditions of the GNU General Public | ||
9 | * License. See the file COPYING in the main directory of the Linux | ||
10 | * distribution for more details. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/errno.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/netdevice.h> | ||
19 | #include <linux/etherdevice.h> | ||
20 | #include <linux/jiffies.h> | ||
21 | #include <linux/io.h> | ||
22 | #include <asm/mcf8390.h> | ||
23 | |||
24 | static const char version[] = | ||
25 | "mcf8390.c: (15-06-2012) Greg Ungerer <gerg@uclinux.org>"; | ||
26 | |||
27 | #define NE_CMD 0x00 | ||
28 | #define NE_DATAPORT 0x10 /* NatSemi-defined port window offset */ | ||
29 | #define NE_RESET 0x1f /* Issue a read to reset ,a write to clear */ | ||
30 | #define NE_EN0_ISR 0x07 | ||
31 | #define NE_EN0_DCFG 0x0e | ||
32 | #define NE_EN0_RSARLO 0x08 | ||
33 | #define NE_EN0_RSARHI 0x09 | ||
34 | #define NE_EN0_RCNTLO 0x0a | ||
35 | #define NE_EN0_RXCR 0x0c | ||
36 | #define NE_EN0_TXCR 0x0d | ||
37 | #define NE_EN0_RCNTHI 0x0b | ||
38 | #define NE_EN0_IMR 0x0f | ||
39 | |||
40 | #define NESM_START_PG 0x40 /* First page of TX buffer */ | ||
41 | #define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ | ||
42 | |||
43 | #ifdef NE2000_ODDOFFSET | ||
44 | /* | ||
45 | * A lot of the ColdFire boards use a separate address region for odd offset | ||
46 | * register addresses. The following functions convert and map as required. | ||
47 | * Note that the data port accesses are treated a little differently, and | ||
48 | * always accessed via the insX/outsX functions. | ||
49 | */ | ||
50 | static inline u32 NE_PTR(u32 addr) | ||
51 | { | ||
52 | if (addr & 1) | ||
53 | return addr - 1 + NE2000_ODDOFFSET; | ||
54 | return addr; | ||
55 | } | ||
56 | |||
57 | static inline u32 NE_DATA_PTR(u32 addr) | ||
58 | { | ||
59 | return addr; | ||
60 | } | ||
61 | |||
62 | void ei_outb(u32 val, u32 addr) | ||
63 | { | ||
64 | NE2000_BYTE *rp; | ||
65 | |||
66 | rp = (NE2000_BYTE *) NE_PTR(addr); | ||
67 | *rp = RSWAP(val); | ||
68 | } | ||
69 | |||
70 | #define ei_inb ei_inb | ||
71 | u8 ei_inb(u32 addr) | ||
72 | { | ||
73 | NE2000_BYTE *rp, val; | ||
74 | |||
75 | rp = (NE2000_BYTE *) NE_PTR(addr); | ||
76 | val = *rp; | ||
77 | return (u8) (RSWAP(val) & 0xff); | ||
78 | } | ||
79 | |||
80 | void ei_insb(u32 addr, void *vbuf, int len) | ||
81 | { | ||
82 | NE2000_BYTE *rp, val; | ||
83 | u8 *buf; | ||
84 | |||
85 | buf = (u8 *) vbuf; | ||
86 | rp = (NE2000_BYTE *) NE_DATA_PTR(addr); | ||
87 | for (; (len > 0); len--) { | ||
88 | val = *rp; | ||
89 | *buf++ = RSWAP(val); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | void ei_insw(u32 addr, void *vbuf, int len) | ||
94 | { | ||
95 | volatile u16 *rp; | ||
96 | u16 w, *buf; | ||
97 | |||
98 | buf = (u16 *) vbuf; | ||
99 | rp = (volatile u16 *) NE_DATA_PTR(addr); | ||
100 | for (; (len > 0); len--) { | ||
101 | w = *rp; | ||
102 | *buf++ = BSWAP(w); | ||
103 | } | ||
104 | } | ||
105 | |||
106 | void ei_outsb(u32 addr, const void *vbuf, int len) | ||
107 | { | ||
108 | NE2000_BYTE *rp, val; | ||
109 | u8 *buf; | ||
110 | |||
111 | buf = (u8 *) vbuf; | ||
112 | rp = (NE2000_BYTE *) NE_DATA_PTR(addr); | ||
113 | for (; (len > 0); len--) { | ||
114 | val = *buf++; | ||
115 | *rp = RSWAP(val); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | void ei_outsw(u32 addr, const void *vbuf, int len) | ||
120 | { | ||
121 | volatile u16 *rp; | ||
122 | u16 w, *buf; | ||
123 | |||
124 | buf = (u16 *) vbuf; | ||
125 | rp = (volatile u16 *) NE_DATA_PTR(addr); | ||
126 | for (; (len > 0); len--) { | ||
127 | w = *buf++; | ||
128 | *rp = BSWAP(w); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | #else /* !NE2000_ODDOFFSET */ | ||
133 | |||
134 | #define ei_inb inb | ||
135 | #define ei_outb outb | ||
136 | #define ei_insb insb | ||
137 | #define ei_insw insw | ||
138 | #define ei_outsb outsb | ||
139 | #define ei_outsw outsw | ||
140 | |||
141 | #endif /* !NE2000_ODDOFFSET */ | ||
142 | |||
143 | #define ei_inb_p ei_inb | ||
144 | #define ei_outb_p ei_outb | ||
145 | |||
146 | #include "lib8390.c" | ||
147 | |||
148 | /* | ||
149 | * Hard reset the card. This used to pause for the same period that a | ||
150 | * 8390 reset command required, but that shouldn't be necessary. | ||
151 | */ | ||
152 | static void mcf8390_reset_8390(struct net_device *dev) | ||
153 | { | ||
154 | unsigned long reset_start_time = jiffies; | ||
155 | u32 addr = dev->base_addr; | ||
156 | |||
157 | if (ei_debug > 1) | ||
158 | netdev_dbg(dev, "resetting the 8390 t=%ld...\n", jiffies); | ||
159 | |||
160 | ei_outb(ei_inb(addr + NE_RESET), addr + NE_RESET); | ||
161 | |||
162 | ei_status.txing = 0; | ||
163 | ei_status.dmaing = 0; | ||
164 | |||
165 | /* This check _should_not_ be necessary, omit eventually. */ | ||
166 | while ((ei_inb(addr + NE_EN0_ISR) & ENISR_RESET) == 0) { | ||
167 | if (time_after(jiffies, reset_start_time + 2 * HZ / 100)) { | ||
168 | netdev_warn(dev, "%s: did not complete\n", __func__); | ||
169 | break; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | ei_outb(ENISR_RESET, addr + NE_EN0_ISR); | ||
174 | } | ||
175 | |||
176 | /* | ||
177 | * This *shouldn't* happen. | ||
178 | * If it does, it's the last thing you'll see | ||
179 | */ | ||
180 | static void mcf8390_dmaing_err(const char *func, struct net_device *dev, | ||
181 | struct ei_device *ei_local) | ||
182 | { | ||
183 | netdev_err(dev, "%s: DMAing conflict [DMAstat:%d][irqlock:%d]\n", | ||
184 | func, ei_local->dmaing, ei_local->irqlock); | ||
185 | } | ||
186 | |||
187 | /* | ||
188 | * Grab the 8390 specific header. Similar to the block_input routine, but | ||
189 | * we don't need to be concerned with ring wrap as the header will be at | ||
190 | * the start of a page, so we optimize accordingly. | ||
191 | */ | ||
192 | static void mcf8390_get_8390_hdr(struct net_device *dev, | ||
193 | struct e8390_pkt_hdr *hdr, int ring_page) | ||
194 | { | ||
195 | struct ei_device *ei_local = netdev_priv(dev); | ||
196 | u32 addr = dev->base_addr; | ||
197 | |||
198 | if (ei_local->dmaing) { | ||
199 | mcf8390_dmaing_err(__func__, dev, ei_local); | ||
200 | return; | ||
201 | } | ||
202 | |||
203 | ei_local->dmaing |= 0x01; | ||
204 | ei_outb(E8390_NODMA + E8390_PAGE0 + E8390_START, addr + NE_CMD); | ||
205 | ei_outb(ENISR_RDC, addr + NE_EN0_ISR); | ||
206 | ei_outb(sizeof(struct e8390_pkt_hdr), addr + NE_EN0_RCNTLO); | ||
207 | ei_outb(0, addr + NE_EN0_RCNTHI); | ||
208 | ei_outb(0, addr + NE_EN0_RSARLO); /* On page boundary */ | ||
209 | ei_outb(ring_page, addr + NE_EN0_RSARHI); | ||
210 | ei_outb(E8390_RREAD + E8390_START, addr + NE_CMD); | ||
211 | |||
212 | ei_insw(addr + NE_DATAPORT, hdr, sizeof(struct e8390_pkt_hdr) >> 1); | ||
213 | |||
214 | outb(ENISR_RDC, addr + NE_EN0_ISR); /* Ack intr */ | ||
215 | ei_local->dmaing &= ~0x01; | ||
216 | |||
217 | hdr->count = cpu_to_le16(hdr->count); | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * Block input and output, similar to the Crynwr packet driver. | ||
222 | * If you are porting to a new ethercard, look at the packet driver source | ||
223 | * for hints. The NEx000 doesn't share the on-board packet memory -- | ||
224 | * you have to put the packet out through the "remote DMA" dataport | ||
225 | * using z_writeb. | ||
226 | */ | ||
227 | static void mcf8390_block_input(struct net_device *dev, int count, | ||
228 | struct sk_buff *skb, int ring_offset) | ||
229 | { | ||
230 | struct ei_device *ei_local = netdev_priv(dev); | ||
231 | u32 addr = dev->base_addr; | ||
232 | char *buf = skb->data; | ||
233 | |||
234 | if (ei_local->dmaing) { | ||
235 | mcf8390_dmaing_err(__func__, dev, ei_local); | ||
236 | return; | ||
237 | } | ||
238 | |||
239 | ei_local->dmaing |= 0x01; | ||
240 | ei_outb(E8390_NODMA + E8390_PAGE0 + E8390_START, addr + NE_CMD); | ||
241 | ei_outb(ENISR_RDC, addr + NE_EN0_ISR); | ||
242 | ei_outb(count & 0xff, addr + NE_EN0_RCNTLO); | ||
243 | ei_outb(count >> 8, addr + NE_EN0_RCNTHI); | ||
244 | ei_outb(ring_offset & 0xff, addr + NE_EN0_RSARLO); | ||
245 | ei_outb(ring_offset >> 8, addr + NE_EN0_RSARHI); | ||
246 | ei_outb(E8390_RREAD + E8390_START, addr + NE_CMD); | ||
247 | |||
248 | ei_insw(addr + NE_DATAPORT, buf, count >> 1); | ||
249 | if (count & 1) | ||
250 | buf[count - 1] = ei_inb(addr + NE_DATAPORT); | ||
251 | |||
252 | ei_outb(ENISR_RDC, addr + NE_EN0_ISR); /* Ack intr */ | ||
253 | ei_local->dmaing &= ~0x01; | ||
254 | } | ||
255 | |||
256 | static void mcf8390_block_output(struct net_device *dev, int count, | ||
257 | const unsigned char *buf, | ||
258 | const int start_page) | ||
259 | { | ||
260 | struct ei_device *ei_local = netdev_priv(dev); | ||
261 | u32 addr = dev->base_addr; | ||
262 | unsigned long dma_start; | ||
263 | |||
264 | /* Make sure we transfer all bytes if 16bit IO writes */ | ||
265 | if (count & 0x1) | ||
266 | count++; | ||
267 | |||
268 | if (ei_local->dmaing) { | ||
269 | mcf8390_dmaing_err(__func__, dev, ei_local); | ||
270 | return; | ||
271 | } | ||
272 | |||
273 | ei_local->dmaing |= 0x01; | ||
274 | /* We should already be in page 0, but to be safe... */ | ||
275 | ei_outb(E8390_PAGE0 + E8390_START + E8390_NODMA, addr + NE_CMD); | ||
276 | |||
277 | ei_outb(ENISR_RDC, addr + NE_EN0_ISR); | ||
278 | |||
279 | /* Now the normal output. */ | ||
280 | ei_outb(count & 0xff, addr + NE_EN0_RCNTLO); | ||
281 | ei_outb(count >> 8, addr + NE_EN0_RCNTHI); | ||
282 | ei_outb(0x00, addr + NE_EN0_RSARLO); | ||
283 | ei_outb(start_page, addr + NE_EN0_RSARHI); | ||
284 | ei_outb(E8390_RWRITE + E8390_START, addr + NE_CMD); | ||
285 | |||
286 | ei_outsw(addr + NE_DATAPORT, buf, count >> 1); | ||
287 | |||
288 | dma_start = jiffies; | ||
289 | while ((ei_inb(addr + NE_EN0_ISR) & ENISR_RDC) == 0) { | ||
290 | if (time_after(jiffies, dma_start + 2 * HZ / 100)) { /* 20ms */ | ||
291 | netdev_err(dev, "timeout waiting for Tx RDC\n"); | ||
292 | mcf8390_reset_8390(dev); | ||
293 | __NS8390_init(dev, 1); | ||
294 | break; | ||
295 | } | ||
296 | } | ||
297 | |||
298 | ei_outb(ENISR_RDC, addr + NE_EN0_ISR); /* Ack intr */ | ||
299 | ei_local->dmaing &= ~0x01; | ||
300 | } | ||
301 | |||
302 | static const struct net_device_ops mcf8390_netdev_ops = { | ||
303 | .ndo_open = __ei_open, | ||
304 | .ndo_stop = __ei_close, | ||
305 | .ndo_start_xmit = __ei_start_xmit, | ||
306 | .ndo_tx_timeout = __ei_tx_timeout, | ||
307 | .ndo_get_stats = __ei_get_stats, | ||
308 | .ndo_set_rx_mode = __ei_set_multicast_list, | ||
309 | .ndo_validate_addr = eth_validate_addr, | ||
310 | .ndo_set_mac_address = eth_mac_addr, | ||
311 | .ndo_change_mtu = eth_change_mtu, | ||
312 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
313 | .ndo_poll_controller = __ei_poll, | ||
314 | #endif | ||
315 | }; | ||
316 | |||
317 | static int mcf8390_init(struct net_device *dev) | ||
318 | { | ||
319 | static u32 offsets[] = { | ||
320 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, | ||
321 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, | ||
322 | }; | ||
323 | struct ei_device *ei_local = netdev_priv(dev); | ||
324 | unsigned char SA_prom[32]; | ||
325 | u32 addr = dev->base_addr; | ||
326 | int start_page, stop_page; | ||
327 | int i, ret; | ||
328 | |||
329 | mcf8390_reset_8390(dev); | ||
330 | |||
331 | /* | ||
332 | * Read the 16 bytes of station address PROM. | ||
333 | * We must first initialize registers, | ||
334 | * similar to NS8390_init(eifdev, 0). | ||
335 | * We can't reliably read the SAPROM address without this. | ||
336 | * (I learned the hard way!). | ||
337 | */ | ||
338 | { | ||
339 | static const struct { | ||
340 | u32 value; | ||
341 | u32 offset; | ||
342 | } program_seq[] = { | ||
343 | {E8390_NODMA + E8390_PAGE0 + E8390_STOP, NE_CMD}, | ||
344 | /* Select page 0 */ | ||
345 | {0x48, NE_EN0_DCFG}, /* 0x48: Set byte-wide access */ | ||
346 | {0x00, NE_EN0_RCNTLO}, /* Clear the count regs */ | ||
347 | {0x00, NE_EN0_RCNTHI}, | ||
348 | {0x00, NE_EN0_IMR}, /* Mask completion irq */ | ||
349 | {0xFF, NE_EN0_ISR}, | ||
350 | {E8390_RXOFF, NE_EN0_RXCR}, /* 0x20 Set to monitor */ | ||
351 | {E8390_TXOFF, NE_EN0_TXCR}, /* 0x02 and loopback mode */ | ||
352 | {32, NE_EN0_RCNTLO}, | ||
353 | {0x00, NE_EN0_RCNTHI}, | ||
354 | {0x00, NE_EN0_RSARLO}, /* DMA starting at 0x0000 */ | ||
355 | {0x00, NE_EN0_RSARHI}, | ||
356 | {E8390_RREAD + E8390_START, NE_CMD}, | ||
357 | }; | ||
358 | for (i = 0; i < ARRAY_SIZE(program_seq); i++) { | ||
359 | ei_outb(program_seq[i].value, | ||
360 | addr + program_seq[i].offset); | ||
361 | } | ||
362 | } | ||
363 | |||
364 | for (i = 0; i < 16; i++) { | ||
365 | SA_prom[i] = ei_inb(addr + NE_DATAPORT); | ||
366 | ei_inb(addr + NE_DATAPORT); | ||
367 | } | ||
368 | |||
369 | /* We must set the 8390 for word mode. */ | ||
370 | ei_outb(0x49, addr + NE_EN0_DCFG); | ||
371 | start_page = NESM_START_PG; | ||
372 | stop_page = NESM_STOP_PG; | ||
373 | |||
374 | /* Install the Interrupt handler */ | ||
375 | ret = request_irq(dev->irq, __ei_interrupt, 0, dev->name, dev); | ||
376 | if (ret) | ||
377 | return ret; | ||
378 | |||
379 | for (i = 0; i < ETH_ALEN; i++) | ||
380 | dev->dev_addr[i] = SA_prom[i]; | ||
381 | |||
382 | netdev_dbg(dev, "Found ethernet address: %pM\n", dev->dev_addr); | ||
383 | |||
384 | ei_local->name = "mcf8390"; | ||
385 | ei_local->tx_start_page = start_page; | ||
386 | ei_local->stop_page = stop_page; | ||
387 | ei_local->word16 = 1; | ||
388 | ei_local->rx_start_page = start_page + TX_PAGES; | ||
389 | ei_local->reset_8390 = mcf8390_reset_8390; | ||
390 | ei_local->block_input = mcf8390_block_input; | ||
391 | ei_local->block_output = mcf8390_block_output; | ||
392 | ei_local->get_8390_hdr = mcf8390_get_8390_hdr; | ||
393 | ei_local->reg_offset = offsets; | ||
394 | |||
395 | dev->netdev_ops = &mcf8390_netdev_ops; | ||
396 | __NS8390_init(dev, 0); | ||
397 | ret = register_netdev(dev); | ||
398 | if (ret) { | ||
399 | free_irq(dev->irq, dev); | ||
400 | return ret; | ||
401 | } | ||
402 | |||
403 | netdev_info(dev, "addr=0x%08x irq=%d, Ethernet Address %pM\n", | ||
404 | addr, dev->irq, dev->dev_addr); | ||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static int mcf8390_probe(struct platform_device *pdev) | ||
409 | { | ||
410 | struct net_device *dev; | ||
411 | struct ei_device *ei_local; | ||
412 | struct resource *mem, *irq; | ||
413 | resource_size_t msize; | ||
414 | int ret; | ||
415 | |||
416 | irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
417 | if (irq == NULL) { | ||
418 | dev_err(&pdev->dev, "no IRQ specified?\n"); | ||
419 | return -ENXIO; | ||
420 | } | ||
421 | |||
422 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
423 | if (mem == NULL) { | ||
424 | dev_err(&pdev->dev, "no memory address specified?\n"); | ||
425 | return -ENXIO; | ||
426 | } | ||
427 | msize = resource_size(mem); | ||
428 | if (!request_mem_region(mem->start, msize, pdev->name)) | ||
429 | return -EBUSY; | ||
430 | |||
431 | dev = ____alloc_ei_netdev(0); | ||
432 | if (dev == NULL) { | ||
433 | release_mem_region(mem->start, msize); | ||
434 | return -ENOMEM; | ||
435 | } | ||
436 | |||
437 | SET_NETDEV_DEV(dev, &pdev->dev); | ||
438 | platform_set_drvdata(pdev, dev); | ||
439 | ei_local = netdev_priv(dev); | ||
440 | |||
441 | dev->irq = irq->start; | ||
442 | dev->base_addr = mem->start; | ||
443 | |||
444 | ret = mcf8390_init(dev); | ||
445 | if (ret) { | ||
446 | release_mem_region(mem->start, msize); | ||
447 | free_netdev(dev); | ||
448 | return ret; | ||
449 | } | ||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | static int mcf8390_remove(struct platform_device *pdev) | ||
454 | { | ||
455 | struct net_device *dev = platform_get_drvdata(pdev); | ||
456 | struct resource *mem; | ||
457 | |||
458 | unregister_netdev(dev); | ||
459 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
460 | if (mem) | ||
461 | release_mem_region(mem->start, resource_size(mem)); | ||
462 | free_netdev(dev); | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | static struct platform_driver mcf8390_drv = { | ||
467 | .driver = { | ||
468 | .name = "mcf8390", | ||
469 | .owner = THIS_MODULE, | ||
470 | }, | ||
471 | .probe = mcf8390_probe, | ||
472 | .remove = mcf8390_remove, | ||
473 | }; | ||
474 | |||
475 | module_platform_driver(mcf8390_drv); | ||
476 | |||
477 | MODULE_DESCRIPTION("MCF8390 ColdFire NS8390 driver"); | ||
478 | MODULE_AUTHOR("Greg Ungerer <gerg@uclinux.org>"); | ||
479 | MODULE_LICENSE("GPL"); | ||
480 | MODULE_ALIAS("platform:mcf8390"); | ||