blob: 28a45d0692e1774eb9a3a4b0f358f461a9c9efb6 [file] [log] [blame]
Uwe Hermannb80dbf02007-04-22 19:08:13 +00001/*
Stefan Reinauer7e61e452008-01-18 10:35:56 +00002 * This file is part of the coreboot project.
Uwe Hermannb80dbf02007-04-22 19:08:13 +00003 *
Uwe Hermannb80dbf02007-04-22 19:08:13 +00004 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
Uwe Hermannb80dbf02007-04-22 19:08:13 +000012 */
Eric Biederman5cd81732004-03-11 15:01:31 +000013
14#include <console/console.h>
15#include <stdlib.h>
16#include <stdint.h>
Eric Biederman5cd81732004-03-11 15:01:31 +000017#include <arch/io.h>
18#include <device/device.h>
19#include <device/pnp.h>
20
Nico Huberdd4715b2013-06-10 22:08:35 +020021/* PNP config mode wrappers */
22
Elyes HAOUASb77cf622018-05-02 21:01:18 +020023void pnp_enter_conf_mode(struct device *dev)
Nico Huberdd4715b2013-06-10 22:08:35 +020024{
25 if (dev->ops->ops_pnp_mode)
26 dev->ops->ops_pnp_mode->enter_conf_mode(dev);
27}
28
Elyes HAOUASb77cf622018-05-02 21:01:18 +020029void pnp_exit_conf_mode(struct device *dev)
Nico Huberdd4715b2013-06-10 22:08:35 +020030{
31 if (dev->ops->ops_pnp_mode)
32 dev->ops->ops_pnp_mode->exit_conf_mode(dev);
33}
34
Eric Biederman5cd81732004-03-11 15:01:31 +000035/* PNP fundamental operations */
36
Elyes HAOUASb77cf622018-05-02 21:01:18 +020037void pnp_write_config(struct device *dev, u8 reg, u8 value)
Eric Biederman5cd81732004-03-11 15:01:31 +000038{
Stefan Reinauer2b34db82009-02-28 20:10:20 +000039 outb(reg, dev->path.pnp.port);
40 outb(value, dev->path.pnp.port + 1);
Eric Biederman5cd81732004-03-11 15:01:31 +000041}
42
Elyes HAOUASb77cf622018-05-02 21:01:18 +020043u8 pnp_read_config(struct device *dev, u8 reg)
Eric Biederman5cd81732004-03-11 15:01:31 +000044{
Stefan Reinauer2b34db82009-02-28 20:10:20 +000045 outb(reg, dev->path.pnp.port);
46 return inb(dev->path.pnp.port + 1);
Eric Biederman5cd81732004-03-11 15:01:31 +000047}
48
Elyes HAOUASb77cf622018-05-02 21:01:18 +020049void pnp_set_logical_device(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +000050{
Stefan Reinauer2b34db82009-02-28 20:10:20 +000051 pnp_write_config(dev, 0x07, dev->path.pnp.device & 0xff);
Eric Biederman5cd81732004-03-11 15:01:31 +000052}
53
Elyes HAOUASb77cf622018-05-02 21:01:18 +020054void pnp_set_enable(struct device *dev, int enable)
Eric Biederman5cd81732004-03-11 15:01:31 +000055{
Uwe Hermannd453dd02010-10-18 00:00:57 +000056 u8 tmp, bitpos;
Rudolf Marek623df672008-02-18 20:32:46 +000057
58 tmp = pnp_read_config(dev, 0x30);
Uwe Hermannd453dd02010-10-18 00:00:57 +000059
60 /* Handle virtual devices, which share the same LDN register. */
Stefan Reinauer2b34db82009-02-28 20:10:20 +000061 bitpos = (dev->path.pnp.device >> 8) & 0x7;
Rudolf Marek623df672008-02-18 20:32:46 +000062
Uwe Hermannd453dd02010-10-18 00:00:57 +000063 if (enable)
Rudolf Marek623df672008-02-18 20:32:46 +000064 tmp |= (1 << bitpos);
Uwe Hermannd453dd02010-10-18 00:00:57 +000065 else
Rudolf Marek623df672008-02-18 20:32:46 +000066 tmp &= ~(1 << bitpos);
Uwe Hermannd453dd02010-10-18 00:00:57 +000067
Rudolf Marek623df672008-02-18 20:32:46 +000068 pnp_write_config(dev, 0x30, tmp);
Eric Biederman5cd81732004-03-11 15:01:31 +000069}
70
Elyes HAOUASb77cf622018-05-02 21:01:18 +020071int pnp_read_enable(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +000072{
Uwe Hermannd453dd02010-10-18 00:00:57 +000073 u8 tmp, bitpos;
74
Rudolf Marek623df672008-02-18 20:32:46 +000075 tmp = pnp_read_config(dev, 0x30);
Uwe Hermannd453dd02010-10-18 00:00:57 +000076
77 /* Handle virtual devices, which share the same LDN register. */
Stefan Reinauer2b34db82009-02-28 20:10:20 +000078 bitpos = (dev->path.pnp.device >> 8) & 0x7;
Uwe Hermannd453dd02010-10-18 00:00:57 +000079
Rudolf Marekb05d4bb2008-02-19 20:30:25 +000080 return !!(tmp & (1 << bitpos));
Eric Biederman5cd81732004-03-11 15:01:31 +000081}
82
Elyes HAOUASb77cf622018-05-02 21:01:18 +020083void pnp_set_iobase(struct device *dev, u8 index, u16 iobase)
Eric Biederman5cd81732004-03-11 15:01:31 +000084{
Uwe Hermannd453dd02010-10-18 00:00:57 +000085 /* Index == 0x60 or 0x62. */
Eric Biederman5cd81732004-03-11 15:01:31 +000086 pnp_write_config(dev, index + 0, (iobase >> 8) & 0xff);
87 pnp_write_config(dev, index + 1, iobase & 0xff);
88}
89
Elyes HAOUASb77cf622018-05-02 21:01:18 +020090void pnp_set_irq(struct device *dev, u8 index, u8 irq)
Eric Biederman5cd81732004-03-11 15:01:31 +000091{
Uwe Hermannd453dd02010-10-18 00:00:57 +000092 /* Index == 0x70 or 0x72. */
Eric Biederman5cd81732004-03-11 15:01:31 +000093 pnp_write_config(dev, index, irq);
94}
95
Elyes HAOUASb77cf622018-05-02 21:01:18 +020096void pnp_set_drq(struct device *dev, u8 index, u8 drq)
Eric Biederman5cd81732004-03-11 15:01:31 +000097{
Uwe Hermannd453dd02010-10-18 00:00:57 +000098 /* Index == 0x74. */
Eric Biederman5cd81732004-03-11 15:01:31 +000099 pnp_write_config(dev, index, drq & 0xff);
100}
101
102/* PNP device operations */
103
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200104void pnp_read_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000105{
106 return;
107}
108
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200109static void pnp_set_resource(struct device *dev, struct resource *resource)
Eric Biederman5cd81732004-03-11 15:01:31 +0000110{
111 if (!(resource->flags & IORESOURCE_ASSIGNED)) {
Elyes HAOUAS495bb662019-09-23 13:15:41 +0200112 /* The PNP_MSC Super IO registers have the IRQ flag set. If no
Felix Helda6627772018-07-27 16:41:32 +0200113 value is assigned in the devicetree, the corresponding
114 PNP_MSC register doesn't get written, which should be printed
115 as warning and not as error. */
116 if (resource->flags & IORESOURCE_IRQ &&
117 (resource->index != PNP_IDX_IRQ0) &&
118 (resource->index != PNP_IDX_IRQ1))
119 printk(BIOS_WARNING, "WARNING: %s %02lx %s size: "
120 "0x%010llx not assigned\n", dev_path(dev),
121 resource->index, resource_type(resource),
122 resource->size);
123 else
124 printk(BIOS_ERR, "ERROR: %s %02lx %s size: 0x%010llx "
125 "not assigned\n", dev_path(dev), resource->index,
126 resource_type(resource), resource->size);
Eric Biederman5cd81732004-03-11 15:01:31 +0000127 return;
128 }
Li-Ta Lo75337f72004-05-07 21:56:48 +0000129
Uwe Hermannd453dd02010-10-18 00:00:57 +0000130 /* Now store the resource. */
Eric Biederman5cd81732004-03-11 15:01:31 +0000131 if (resource->flags & IORESOURCE_IO) {
132 pnp_set_iobase(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000133 } else if (resource->flags & IORESOURCE_DRQ) {
Eric Biederman5cd81732004-03-11 15:01:31 +0000134 pnp_set_drq(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000135 } else if (resource->flags & IORESOURCE_IRQ) {
Eric Biederman5cd81732004-03-11 15:01:31 +0000136 pnp_set_irq(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000137 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000138 printk(BIOS_ERR, "ERROR: %s %02lx unknown resource type\n",
Uwe Hermannd453dd02010-10-18 00:00:57 +0000139 dev_path(dev), resource->index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000140 return;
141 }
Li-Ta Lo9f0d0f92004-05-10 16:05:16 +0000142 resource->flags |= IORESOURCE_STORED;
Eric Biederman5cd81732004-03-11 15:01:31 +0000143
Eric Biederman03acab62004-10-14 21:25:53 +0000144 report_resource_stored(dev, resource, "");
Eric Biederman5cd81732004-03-11 15:01:31 +0000145}
146
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200147void pnp_set_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000148{
Myles Watsonc25cc112010-05-21 14:33:48 +0000149 struct resource *res;
Eric Biederman5cd81732004-03-11 15:01:31 +0000150
Nico Huberdd4715b2013-06-10 22:08:35 +0200151 pnp_enter_conf_mode(dev);
152
Uwe Hermannd453dd02010-10-18 00:00:57 +0000153 /* Select the logical device (LDN). */
Eric Biederman5cd81732004-03-11 15:01:31 +0000154 pnp_set_logical_device(dev);
155
156 /* Paranoia says I should disable the device here... */
Uwe Hermannd453dd02010-10-18 00:00:57 +0000157 for (res = dev->resource_list; res; res = res->next)
Myles Watsonc25cc112010-05-21 14:33:48 +0000158 pnp_set_resource(dev, res);
Nico Huberdd4715b2013-06-10 22:08:35 +0200159
160 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000161}
162
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200163void pnp_enable_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000164{
Nico Huberdd4715b2013-06-10 22:08:35 +0200165 pnp_enter_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000166 pnp_set_logical_device(dev);
167 pnp_set_enable(dev, 1);
Nico Huberdd4715b2013-06-10 22:08:35 +0200168 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000169}
170
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200171void pnp_enable(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000172{
Li-Ta Lo75337f72004-05-07 21:56:48 +0000173 if (!dev->enabled) {
Nico Huberdd4715b2013-06-10 22:08:35 +0200174 pnp_enter_conf_mode(dev);
Li-Ta Loc6bcedb2004-04-21 16:57:05 +0000175 pnp_set_logical_device(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000176 pnp_set_enable(dev, 0);
Nico Huberdd4715b2013-06-10 22:08:35 +0200177 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000178 }
179}
180
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200181void pnp_alt_enable(struct device *dev)
Nico Huberf898f7b2013-06-10 22:57:12 +0200182{
Nico Huberdd4715b2013-06-10 22:08:35 +0200183 pnp_enter_conf_mode(dev);
Nico Huberf898f7b2013-06-10 22:57:12 +0200184 pnp_set_logical_device(dev);
185 pnp_set_enable(dev, !!dev->enabled);
Nico Huberdd4715b2013-06-10 22:08:35 +0200186 pnp_exit_conf_mode(dev);
Nico Huberf898f7b2013-06-10 22:57:12 +0200187}
188
Eric Biederman5cd81732004-03-11 15:01:31 +0000189struct device_operations pnp_ops = {
190 .read_resources = pnp_read_resources,
191 .set_resources = pnp_set_resources,
192 .enable_resources = pnp_enable_resources,
193 .enable = pnp_enable,
194};
195
Uwe Hermanne4870472010-11-04 23:23:47 +0000196/* PNP chip operations */
Eric Biederman5cd81732004-03-11 15:01:31 +0000197
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200198static void pnp_get_ioresource(struct device *dev, u8 index, u16 mask)
Eric Biederman5cd81732004-03-11 15:01:31 +0000199{
200 struct resource *resource;
Felix Heldf2ec6482018-07-27 02:31:09 +0200201 unsigned int bit;
Li-Ta Lo75337f72004-05-07 21:56:48 +0000202
Felix Heldf2ec6482018-07-27 02:31:09 +0200203 /* If none of the mask bits is set, the resource would occupy the whole
204 IO space leading to IO resource conflicts with the other devices */
Samuel Holland7daac912017-06-06 22:55:01 -0500205 if (!mask) {
Stefan Reinaueraeead272011-01-31 21:16:48 +0000206 printk(BIOS_ERR, "ERROR: device %s index %d has no mask.\n",
207 dev_path(dev), index);
208 return;
209 }
210
Eric Biederman03acab62004-10-14 21:25:53 +0000211 resource = new_resource(dev, index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000212 resource->flags |= IORESOURCE_IO;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000213
Felix Heldf2ec6482018-07-27 02:31:09 +0200214 /* Calculate IO region size which is determined by the first one from
215 the LSB of the mask. */
216 for (bit = 0; bit <= 15 && (mask & (1 << bit)) == 0; ++bit)
217 ;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000218
Felix Heldf2ec6482018-07-27 02:31:09 +0200219 resource->gran = bit;
220 resource->align = bit;
221 resource->size = 1 << bit;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000222
Felix Heldf2ec6482018-07-27 02:31:09 +0200223 /* Calculate IO region address limit which is determined by the first
224 one from the MSB of the mask. */
225 for (bit = 15; bit != 0 && (mask & (1 << bit)) == 0; --bit)
226 ;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000227
Felix Heldf2ec6482018-07-27 02:31:09 +0200228 resource->limit = (1 << (bit + 1)) - 1;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000229
Felix Heldf2ec6482018-07-27 02:31:09 +0200230 /* The block of ones in the mask is expected to be continuous.
231 If there is any zero inbetween the block of ones, it is ignored
232 in the calculation of the resource size and limit. */
233 if (mask != (resource->limit ^ (resource->size - 1)))
234 printk(BIOS_WARNING,
235 "WARNING: mask of device %s index %d is wrong.\n",
236 dev_path(dev), index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000237}
238
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200239static void get_resources(struct device *dev, struct pnp_info *info)
Eric Biederman5cd81732004-03-11 15:01:31 +0000240{
241 struct resource *resource;
242
Uwe Hermanne4870472010-11-04 23:23:47 +0000243 if (info->flags & PNP_IO0)
Samuel Holland7daac912017-06-06 22:55:01 -0500244 pnp_get_ioresource(dev, PNP_IDX_IO0, info->io0);
Uwe Hermanne4870472010-11-04 23:23:47 +0000245 if (info->flags & PNP_IO1)
Samuel Holland7daac912017-06-06 22:55:01 -0500246 pnp_get_ioresource(dev, PNP_IDX_IO1, info->io1);
Uwe Hermanne4870472010-11-04 23:23:47 +0000247 if (info->flags & PNP_IO2)
Samuel Holland7daac912017-06-06 22:55:01 -0500248 pnp_get_ioresource(dev, PNP_IDX_IO2, info->io2);
Uwe Hermanne4870472010-11-04 23:23:47 +0000249 if (info->flags & PNP_IO3)
Samuel Holland7daac912017-06-06 22:55:01 -0500250 pnp_get_ioresource(dev, PNP_IDX_IO3, info->io3);
Uwe Hermanne4870472010-11-04 23:23:47 +0000251
Eric Biederman5cd81732004-03-11 15:01:31 +0000252 if (info->flags & PNP_IRQ0) {
Eric Biederman03acab62004-10-14 21:25:53 +0000253 resource = new_resource(dev, PNP_IDX_IRQ0);
Eric Biederman5cd81732004-03-11 15:01:31 +0000254 resource->size = 1;
255 resource->flags |= IORESOURCE_IRQ;
256 }
257 if (info->flags & PNP_IRQ1) {
Eric Biederman03acab62004-10-14 21:25:53 +0000258 resource = new_resource(dev, PNP_IDX_IRQ1);
Eric Biederman5cd81732004-03-11 15:01:31 +0000259 resource->size = 1;
260 resource->flags |= IORESOURCE_IRQ;
261 }
Uwe Hermanne4870472010-11-04 23:23:47 +0000262
Eric Biederman5cd81732004-03-11 15:01:31 +0000263 if (info->flags & PNP_DRQ0) {
Eric Biederman03acab62004-10-14 21:25:53 +0000264 resource = new_resource(dev, PNP_IDX_DRQ0);
Eric Biederman5cd81732004-03-11 15:01:31 +0000265 resource->size = 1;
266 resource->flags |= IORESOURCE_DRQ;
267 }
268 if (info->flags & PNP_DRQ1) {
Eric Biederman03acab62004-10-14 21:25:53 +0000269 resource = new_resource(dev, PNP_IDX_DRQ1);
Eric Biederman5cd81732004-03-11 15:01:31 +0000270 resource->size = 1;
271 resource->flags |= IORESOURCE_DRQ;
Stefan Reinauerde3206a2010-02-22 06:09:43 +0000272 }
Uwe Hermannd453dd02010-10-18 00:00:57 +0000273
274 /*
275 * These are not IRQs, but set the flag to have the
276 * resource allocator do the right thing.
Stefan Reinauerde3206a2010-02-22 06:09:43 +0000277 */
278 if (info->flags & PNP_EN) {
279 resource = new_resource(dev, PNP_IDX_EN);
280 resource->size = 1;
281 resource->flags |= IORESOURCE_IRQ;
282 }
283 if (info->flags & PNP_MSC0) {
284 resource = new_resource(dev, PNP_IDX_MSC0);
285 resource->size = 1;
286 resource->flags |= IORESOURCE_IRQ;
287 }
288 if (info->flags & PNP_MSC1) {
289 resource = new_resource(dev, PNP_IDX_MSC1);
290 resource->size = 1;
291 resource->flags |= IORESOURCE_IRQ;
292 }
Damien Zammit62c02762015-12-28 23:04:47 +1100293 if (info->flags & PNP_MSC2) {
294 resource = new_resource(dev, PNP_IDX_MSC2);
295 resource->size = 1;
296 resource->flags |= IORESOURCE_IRQ;
297 }
298 if (info->flags & PNP_MSC3) {
299 resource = new_resource(dev, PNP_IDX_MSC3);
300 resource->size = 1;
301 resource->flags |= IORESOURCE_IRQ;
302 }
Stefan Reinauer0108b932013-12-11 11:06:08 -0800303 if (info->flags & PNP_MSC4) {
304 resource = new_resource(dev, PNP_IDX_MSC4);
305 resource->size = 1;
306 resource->flags |= IORESOURCE_IRQ;
307 }
Damien Zammit62c02762015-12-28 23:04:47 +1100308 if (info->flags & PNP_MSC5) {
309 resource = new_resource(dev, PNP_IDX_MSC5);
310 resource->size = 1;
311 resource->flags |= IORESOURCE_IRQ;
312 }
313 if (info->flags & PNP_MSC6) {
314 resource = new_resource(dev, PNP_IDX_MSC6);
315 resource->size = 1;
316 resource->flags |= IORESOURCE_IRQ;
317 }
318 if (info->flags & PNP_MSC7) {
319 resource = new_resource(dev, PNP_IDX_MSC7);
320 resource->size = 1;
321 resource->flags |= IORESOURCE_IRQ;
322 }
323 if (info->flags & PNP_MSC8) {
324 resource = new_resource(dev, PNP_IDX_MSC8);
325 resource->size = 1;
326 resource->flags |= IORESOURCE_IRQ;
327 }
328 if (info->flags & PNP_MSC9) {
329 resource = new_resource(dev, PNP_IDX_MSC9);
330 resource->size = 1;
331 resource->flags |= IORESOURCE_IRQ;
332 }
333 if (info->flags & PNP_MSCA) {
334 resource = new_resource(dev, PNP_IDX_MSCA);
335 resource->size = 1;
336 resource->flags |= IORESOURCE_IRQ;
337 }
338 if (info->flags & PNP_MSCB) {
339 resource = new_resource(dev, PNP_IDX_MSCB);
340 resource->size = 1;
341 resource->flags |= IORESOURCE_IRQ;
342 }
343 if (info->flags & PNP_MSCC) {
344 resource = new_resource(dev, PNP_IDX_MSCC);
345 resource->size = 1;
346 resource->flags |= IORESOURCE_IRQ;
347 }
348 if (info->flags & PNP_MSCD) {
349 resource = new_resource(dev, PNP_IDX_MSCD);
350 resource->size = 1;
351 resource->flags |= IORESOURCE_IRQ;
352 }
353 if (info->flags & PNP_MSCE) {
354 resource = new_resource(dev, PNP_IDX_MSCE);
Stefan Reinauer08ba7d02013-10-31 15:58:50 -0700355 resource->size = 1;
356 resource->flags |= IORESOURCE_IRQ;
357 }
Stefan Reinauer14e22772010-04-27 06:56:47 +0000358}
Eric Biederman5cd81732004-03-11 15:01:31 +0000359
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200360void pnp_enable_devices(struct device *base_dev, struct device_operations *ops,
Uwe Hermannd453dd02010-10-18 00:00:57 +0000361 unsigned int functions, struct pnp_info *info)
Eric Biederman5cd81732004-03-11 15:01:31 +0000362{
363 struct device_path path;
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200364 struct device *dev;
Eric Biederman5cd81732004-03-11 15:01:31 +0000365 int i;
366
Uwe Hermannd453dd02010-10-18 00:00:57 +0000367 path.type = DEVICE_PATH_PNP;
Stefan Reinauer2b34db82009-02-28 20:10:20 +0000368 path.pnp.port = base_dev->path.pnp.port;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000369
Uwe Hermannd453dd02010-10-18 00:00:57 +0000370 /* Setup the ops and resources on the newly allocated devices. */
371 for (i = 0; i < functions; i++) {
Uwe Hermannaa4bedf2007-07-12 13:12:47 +0000372 /* Skip logical devices this Super I/O doesn't have. */
373 if (info[i].function == -1)
374 continue;
375
Stefan Reinauer2b34db82009-02-28 20:10:20 +0000376 path.pnp.device = info[i].function;
Eric Biederman7003ba42004-10-16 06:20:29 +0000377 dev = alloc_find_dev(base_dev->bus, &path);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000378
Uwe Hermannd453dd02010-10-18 00:00:57 +0000379 /* Don't initialize a device multiple times. */
Stefan Reinauer14e22772010-04-27 06:56:47 +0000380 if (dev->ops)
Eric Biederman7003ba42004-10-16 06:20:29 +0000381 continue;
Li-Ta Loc6bcedb2004-04-21 16:57:05 +0000382
Felix Held745e58a2018-07-06 19:38:24 +0200383 /* use LDN-specific ops override from corresponding pnp_info
384 entry if not NULL */
385 if (info[i].ops)
Li-Ta Lo75337f72004-05-07 21:56:48 +0000386 dev->ops = info[i].ops;
Felix Held745e58a2018-07-06 19:38:24 +0200387 /* else use device ops */
388 else
389 dev->ops = ops;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000390
Eric Biederman5cd81732004-03-11 15:01:31 +0000391 get_resources(dev, &info[i]);
Eric Biederman5cd81732004-03-11 15:01:31 +0000392 }
393}