blob: 09a27487b3e0d1a570975341d7a1a9945ab046b6 [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 *
4 * Copyright (C) 2004 Linux Networx
5 * (Written by Eric Biederman <ebiederman@lnxi.com> for Linux Networx)
6 * Copyright (C) 2004 Li-Ta Lo <ollie@lanl.gov>
7 * Copyright (C) 2005 Tyan
8 * (Written by Yinghai Lu <yhlu@tyan.com> for Tyan)
Nico Huberdd4715b2013-06-10 22:08:35 +02009 * Copyright (C) 2013 Nico Huber <nico.h@gmx.de>
Felix Heldf2ec6482018-07-27 02:31:09 +020010 * Copyright (C) 2018 Felix Held <felix-coreboot@felixheld.de>
Uwe Hermannb80dbf02007-04-22 19:08:13 +000011 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; version 2 of the License.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
Uwe Hermannb80dbf02007-04-22 19:08:13 +000020 */
Eric Biederman5cd81732004-03-11 15:01:31 +000021
22#include <console/console.h>
23#include <stdlib.h>
24#include <stdint.h>
Eric Biederman5cd81732004-03-11 15:01:31 +000025#include <string.h>
26#include <arch/io.h>
27#include <device/device.h>
28#include <device/pnp.h>
29
Nico Huberdd4715b2013-06-10 22:08:35 +020030/* PNP config mode wrappers */
31
Elyes HAOUASb77cf622018-05-02 21:01:18 +020032void pnp_enter_conf_mode(struct device *dev)
Nico Huberdd4715b2013-06-10 22:08:35 +020033{
34 if (dev->ops->ops_pnp_mode)
35 dev->ops->ops_pnp_mode->enter_conf_mode(dev);
36}
37
Elyes HAOUASb77cf622018-05-02 21:01:18 +020038void pnp_exit_conf_mode(struct device *dev)
Nico Huberdd4715b2013-06-10 22:08:35 +020039{
40 if (dev->ops->ops_pnp_mode)
41 dev->ops->ops_pnp_mode->exit_conf_mode(dev);
42}
43
Eric Biederman5cd81732004-03-11 15:01:31 +000044/* PNP fundamental operations */
45
Elyes HAOUASb77cf622018-05-02 21:01:18 +020046void pnp_write_config(struct device *dev, u8 reg, u8 value)
Eric Biederman5cd81732004-03-11 15:01:31 +000047{
Stefan Reinauer2b34db82009-02-28 20:10:20 +000048 outb(reg, dev->path.pnp.port);
49 outb(value, dev->path.pnp.port + 1);
Eric Biederman5cd81732004-03-11 15:01:31 +000050}
51
Elyes HAOUASb77cf622018-05-02 21:01:18 +020052u8 pnp_read_config(struct device *dev, u8 reg)
Eric Biederman5cd81732004-03-11 15:01:31 +000053{
Stefan Reinauer2b34db82009-02-28 20:10:20 +000054 outb(reg, dev->path.pnp.port);
55 return inb(dev->path.pnp.port + 1);
Eric Biederman5cd81732004-03-11 15:01:31 +000056}
57
Elyes HAOUASb77cf622018-05-02 21:01:18 +020058void pnp_set_logical_device(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +000059{
Stefan Reinauer2b34db82009-02-28 20:10:20 +000060 pnp_write_config(dev, 0x07, dev->path.pnp.device & 0xff);
Eric Biederman5cd81732004-03-11 15:01:31 +000061}
62
Elyes HAOUASb77cf622018-05-02 21:01:18 +020063void pnp_set_enable(struct device *dev, int enable)
Eric Biederman5cd81732004-03-11 15:01:31 +000064{
Uwe Hermannd453dd02010-10-18 00:00:57 +000065 u8 tmp, bitpos;
Rudolf Marek623df672008-02-18 20:32:46 +000066
67 tmp = pnp_read_config(dev, 0x30);
Uwe Hermannd453dd02010-10-18 00:00:57 +000068
69 /* Handle virtual devices, which share the same LDN register. */
Stefan Reinauer2b34db82009-02-28 20:10:20 +000070 bitpos = (dev->path.pnp.device >> 8) & 0x7;
Rudolf Marek623df672008-02-18 20:32:46 +000071
Uwe Hermannd453dd02010-10-18 00:00:57 +000072 if (enable)
Rudolf Marek623df672008-02-18 20:32:46 +000073 tmp |= (1 << bitpos);
Uwe Hermannd453dd02010-10-18 00:00:57 +000074 else
Rudolf Marek623df672008-02-18 20:32:46 +000075 tmp &= ~(1 << bitpos);
Uwe Hermannd453dd02010-10-18 00:00:57 +000076
Rudolf Marek623df672008-02-18 20:32:46 +000077 pnp_write_config(dev, 0x30, tmp);
Eric Biederman5cd81732004-03-11 15:01:31 +000078}
79
Elyes HAOUASb77cf622018-05-02 21:01:18 +020080int pnp_read_enable(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +000081{
Uwe Hermannd453dd02010-10-18 00:00:57 +000082 u8 tmp, bitpos;
83
Rudolf Marek623df672008-02-18 20:32:46 +000084 tmp = pnp_read_config(dev, 0x30);
Uwe Hermannd453dd02010-10-18 00:00:57 +000085
86 /* Handle virtual devices, which share the same LDN register. */
Stefan Reinauer2b34db82009-02-28 20:10:20 +000087 bitpos = (dev->path.pnp.device >> 8) & 0x7;
Uwe Hermannd453dd02010-10-18 00:00:57 +000088
Rudolf Marekb05d4bb2008-02-19 20:30:25 +000089 return !!(tmp & (1 << bitpos));
Eric Biederman5cd81732004-03-11 15:01:31 +000090}
91
Elyes HAOUASb77cf622018-05-02 21:01:18 +020092void pnp_set_iobase(struct device *dev, u8 index, u16 iobase)
Eric Biederman5cd81732004-03-11 15:01:31 +000093{
Uwe Hermannd453dd02010-10-18 00:00:57 +000094 /* Index == 0x60 or 0x62. */
Eric Biederman5cd81732004-03-11 15:01:31 +000095 pnp_write_config(dev, index + 0, (iobase >> 8) & 0xff);
96 pnp_write_config(dev, index + 1, iobase & 0xff);
97}
98
Elyes HAOUASb77cf622018-05-02 21:01:18 +020099void pnp_set_irq(struct device *dev, u8 index, u8 irq)
Eric Biederman5cd81732004-03-11 15:01:31 +0000100{
Uwe Hermannd453dd02010-10-18 00:00:57 +0000101 /* Index == 0x70 or 0x72. */
Eric Biederman5cd81732004-03-11 15:01:31 +0000102 pnp_write_config(dev, index, irq);
103}
104
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200105void pnp_set_drq(struct device *dev, u8 index, u8 drq)
Eric Biederman5cd81732004-03-11 15:01:31 +0000106{
Uwe Hermannd453dd02010-10-18 00:00:57 +0000107 /* Index == 0x74. */
Eric Biederman5cd81732004-03-11 15:01:31 +0000108 pnp_write_config(dev, index, drq & 0xff);
109}
110
111/* PNP device operations */
112
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200113void pnp_read_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000114{
115 return;
116}
117
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200118static void pnp_set_resource(struct device *dev, struct resource *resource)
Eric Biederman5cd81732004-03-11 15:01:31 +0000119{
120 if (!(resource->flags & IORESOURCE_ASSIGNED)) {
Patrick Georgi51615092012-03-11 19:31:03 +0100121 printk(BIOS_ERR, "ERROR: %s %02lx %s size: 0x%010llx "
Uwe Hermannd453dd02010-10-18 00:00:57 +0000122 "not assigned\n", dev_path(dev), resource->index,
123 resource_type(resource), resource->size);
Eric Biederman5cd81732004-03-11 15:01:31 +0000124 return;
125 }
Li-Ta Lo75337f72004-05-07 21:56:48 +0000126
Uwe Hermannd453dd02010-10-18 00:00:57 +0000127 /* Now store the resource. */
Eric Biederman5cd81732004-03-11 15:01:31 +0000128 if (resource->flags & IORESOURCE_IO) {
129 pnp_set_iobase(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000130 } else if (resource->flags & IORESOURCE_DRQ) {
Eric Biederman5cd81732004-03-11 15:01:31 +0000131 pnp_set_drq(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000132 } else if (resource->flags & IORESOURCE_IRQ) {
Eric Biederman5cd81732004-03-11 15:01:31 +0000133 pnp_set_irq(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000134 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000135 printk(BIOS_ERR, "ERROR: %s %02lx unknown resource type\n",
Uwe Hermannd453dd02010-10-18 00:00:57 +0000136 dev_path(dev), resource->index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000137 return;
138 }
Li-Ta Lo9f0d0f92004-05-10 16:05:16 +0000139 resource->flags |= IORESOURCE_STORED;
Eric Biederman5cd81732004-03-11 15:01:31 +0000140
Eric Biederman03acab62004-10-14 21:25:53 +0000141 report_resource_stored(dev, resource, "");
Eric Biederman5cd81732004-03-11 15:01:31 +0000142}
143
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200144void pnp_set_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000145{
Myles Watsonc25cc112010-05-21 14:33:48 +0000146 struct resource *res;
Eric Biederman5cd81732004-03-11 15:01:31 +0000147
Nico Huberdd4715b2013-06-10 22:08:35 +0200148 pnp_enter_conf_mode(dev);
149
Uwe Hermannd453dd02010-10-18 00:00:57 +0000150 /* Select the logical device (LDN). */
Eric Biederman5cd81732004-03-11 15:01:31 +0000151 pnp_set_logical_device(dev);
152
153 /* Paranoia says I should disable the device here... */
Uwe Hermannd453dd02010-10-18 00:00:57 +0000154 for (res = dev->resource_list; res; res = res->next)
Myles Watsonc25cc112010-05-21 14:33:48 +0000155 pnp_set_resource(dev, res);
Nico Huberdd4715b2013-06-10 22:08:35 +0200156
157 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000158}
159
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200160void pnp_enable_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000161{
Nico Huberdd4715b2013-06-10 22:08:35 +0200162 pnp_enter_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000163 pnp_set_logical_device(dev);
164 pnp_set_enable(dev, 1);
Nico Huberdd4715b2013-06-10 22:08:35 +0200165 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000166}
167
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200168void pnp_enable(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000169{
Li-Ta Lo75337f72004-05-07 21:56:48 +0000170 if (!dev->enabled) {
Nico Huberdd4715b2013-06-10 22:08:35 +0200171 pnp_enter_conf_mode(dev);
Li-Ta Loc6bcedb2004-04-21 16:57:05 +0000172 pnp_set_logical_device(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000173 pnp_set_enable(dev, 0);
Nico Huberdd4715b2013-06-10 22:08:35 +0200174 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000175 }
176}
177
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200178void pnp_alt_enable(struct device *dev)
Nico Huberf898f7b2013-06-10 22:57:12 +0200179{
Nico Huberdd4715b2013-06-10 22:08:35 +0200180 pnp_enter_conf_mode(dev);
Nico Huberf898f7b2013-06-10 22:57:12 +0200181 pnp_set_logical_device(dev);
182 pnp_set_enable(dev, !!dev->enabled);
Nico Huberdd4715b2013-06-10 22:08:35 +0200183 pnp_exit_conf_mode(dev);
Nico Huberf898f7b2013-06-10 22:57:12 +0200184}
185
Eric Biederman5cd81732004-03-11 15:01:31 +0000186struct device_operations pnp_ops = {
187 .read_resources = pnp_read_resources,
188 .set_resources = pnp_set_resources,
189 .enable_resources = pnp_enable_resources,
190 .enable = pnp_enable,
191};
192
Uwe Hermanne4870472010-11-04 23:23:47 +0000193/* PNP chip operations */
Eric Biederman5cd81732004-03-11 15:01:31 +0000194
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200195static void pnp_get_ioresource(struct device *dev, u8 index, u16 mask)
Eric Biederman5cd81732004-03-11 15:01:31 +0000196{
197 struct resource *resource;
Felix Heldf2ec6482018-07-27 02:31:09 +0200198 unsigned int bit;
Li-Ta Lo75337f72004-05-07 21:56:48 +0000199
Felix Heldf2ec6482018-07-27 02:31:09 +0200200 /* If none of the mask bits is set, the resource would occupy the whole
201 IO space leading to IO resource conflicts with the other devices */
Samuel Holland7daac912017-06-06 22:55:01 -0500202 if (!mask) {
Stefan Reinaueraeead272011-01-31 21:16:48 +0000203 printk(BIOS_ERR, "ERROR: device %s index %d has no mask.\n",
204 dev_path(dev), index);
205 return;
206 }
207
Eric Biederman03acab62004-10-14 21:25:53 +0000208 resource = new_resource(dev, index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000209 resource->flags |= IORESOURCE_IO;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000210
Felix Heldf2ec6482018-07-27 02:31:09 +0200211 /* Calculate IO region size which is determined by the first one from
212 the LSB of the mask. */
213 for (bit = 0; bit <= 15 && (mask & (1 << bit)) == 0; ++bit)
214 ;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000215
Felix Heldf2ec6482018-07-27 02:31:09 +0200216 resource->gran = bit;
217 resource->align = bit;
218 resource->size = 1 << bit;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000219
Felix Heldf2ec6482018-07-27 02:31:09 +0200220 /* Calculate IO region address limit which is determined by the first
221 one from the MSB of the mask. */
222 for (bit = 15; bit != 0 && (mask & (1 << bit)) == 0; --bit)
223 ;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000224
Felix Heldf2ec6482018-07-27 02:31:09 +0200225 resource->limit = (1 << (bit + 1)) - 1;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000226
Felix Heldf2ec6482018-07-27 02:31:09 +0200227 /* The block of ones in the mask is expected to be continuous.
228 If there is any zero inbetween the block of ones, it is ignored
229 in the calculation of the resource size and limit. */
230 if (mask != (resource->limit ^ (resource->size - 1)))
231 printk(BIOS_WARNING,
232 "WARNING: mask of device %s index %d is wrong.\n",
233 dev_path(dev), index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000234}
235
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200236static void get_resources(struct device *dev, struct pnp_info *info)
Eric Biederman5cd81732004-03-11 15:01:31 +0000237{
238 struct resource *resource;
239
Uwe Hermanne4870472010-11-04 23:23:47 +0000240 if (info->flags & PNP_IO0)
Samuel Holland7daac912017-06-06 22:55:01 -0500241 pnp_get_ioresource(dev, PNP_IDX_IO0, info->io0);
Uwe Hermanne4870472010-11-04 23:23:47 +0000242 if (info->flags & PNP_IO1)
Samuel Holland7daac912017-06-06 22:55:01 -0500243 pnp_get_ioresource(dev, PNP_IDX_IO1, info->io1);
Uwe Hermanne4870472010-11-04 23:23:47 +0000244 if (info->flags & PNP_IO2)
Samuel Holland7daac912017-06-06 22:55:01 -0500245 pnp_get_ioresource(dev, PNP_IDX_IO2, info->io2);
Uwe Hermanne4870472010-11-04 23:23:47 +0000246 if (info->flags & PNP_IO3)
Samuel Holland7daac912017-06-06 22:55:01 -0500247 pnp_get_ioresource(dev, PNP_IDX_IO3, info->io3);
Uwe Hermanne4870472010-11-04 23:23:47 +0000248
Eric Biederman5cd81732004-03-11 15:01:31 +0000249 if (info->flags & PNP_IRQ0) {
Eric Biederman03acab62004-10-14 21:25:53 +0000250 resource = new_resource(dev, PNP_IDX_IRQ0);
Eric Biederman5cd81732004-03-11 15:01:31 +0000251 resource->size = 1;
252 resource->flags |= IORESOURCE_IRQ;
253 }
254 if (info->flags & PNP_IRQ1) {
Eric Biederman03acab62004-10-14 21:25:53 +0000255 resource = new_resource(dev, PNP_IDX_IRQ1);
Eric Biederman5cd81732004-03-11 15:01:31 +0000256 resource->size = 1;
257 resource->flags |= IORESOURCE_IRQ;
258 }
Uwe Hermanne4870472010-11-04 23:23:47 +0000259
Eric Biederman5cd81732004-03-11 15:01:31 +0000260 if (info->flags & PNP_DRQ0) {
Eric Biederman03acab62004-10-14 21:25:53 +0000261 resource = new_resource(dev, PNP_IDX_DRQ0);
Eric Biederman5cd81732004-03-11 15:01:31 +0000262 resource->size = 1;
263 resource->flags |= IORESOURCE_DRQ;
264 }
265 if (info->flags & PNP_DRQ1) {
Eric Biederman03acab62004-10-14 21:25:53 +0000266 resource = new_resource(dev, PNP_IDX_DRQ1);
Eric Biederman5cd81732004-03-11 15:01:31 +0000267 resource->size = 1;
268 resource->flags |= IORESOURCE_DRQ;
Stefan Reinauerde3206a2010-02-22 06:09:43 +0000269 }
Uwe Hermannd453dd02010-10-18 00:00:57 +0000270
271 /*
272 * These are not IRQs, but set the flag to have the
273 * resource allocator do the right thing.
Stefan Reinauerde3206a2010-02-22 06:09:43 +0000274 */
275 if (info->flags & PNP_EN) {
276 resource = new_resource(dev, PNP_IDX_EN);
277 resource->size = 1;
278 resource->flags |= IORESOURCE_IRQ;
279 }
280 if (info->flags & PNP_MSC0) {
281 resource = new_resource(dev, PNP_IDX_MSC0);
282 resource->size = 1;
283 resource->flags |= IORESOURCE_IRQ;
284 }
285 if (info->flags & PNP_MSC1) {
286 resource = new_resource(dev, PNP_IDX_MSC1);
287 resource->size = 1;
288 resource->flags |= IORESOURCE_IRQ;
289 }
Damien Zammit62c02762015-12-28 23:04:47 +1100290 if (info->flags & PNP_MSC2) {
291 resource = new_resource(dev, PNP_IDX_MSC2);
292 resource->size = 1;
293 resource->flags |= IORESOURCE_IRQ;
294 }
295 if (info->flags & PNP_MSC3) {
296 resource = new_resource(dev, PNP_IDX_MSC3);
297 resource->size = 1;
298 resource->flags |= IORESOURCE_IRQ;
299 }
Stefan Reinauer0108b932013-12-11 11:06:08 -0800300 if (info->flags & PNP_MSC4) {
301 resource = new_resource(dev, PNP_IDX_MSC4);
302 resource->size = 1;
303 resource->flags |= IORESOURCE_IRQ;
304 }
Damien Zammit62c02762015-12-28 23:04:47 +1100305 if (info->flags & PNP_MSC5) {
306 resource = new_resource(dev, PNP_IDX_MSC5);
307 resource->size = 1;
308 resource->flags |= IORESOURCE_IRQ;
309 }
310 if (info->flags & PNP_MSC6) {
311 resource = new_resource(dev, PNP_IDX_MSC6);
312 resource->size = 1;
313 resource->flags |= IORESOURCE_IRQ;
314 }
315 if (info->flags & PNP_MSC7) {
316 resource = new_resource(dev, PNP_IDX_MSC7);
317 resource->size = 1;
318 resource->flags |= IORESOURCE_IRQ;
319 }
320 if (info->flags & PNP_MSC8) {
321 resource = new_resource(dev, PNP_IDX_MSC8);
322 resource->size = 1;
323 resource->flags |= IORESOURCE_IRQ;
324 }
325 if (info->flags & PNP_MSC9) {
326 resource = new_resource(dev, PNP_IDX_MSC9);
327 resource->size = 1;
328 resource->flags |= IORESOURCE_IRQ;
329 }
330 if (info->flags & PNP_MSCA) {
331 resource = new_resource(dev, PNP_IDX_MSCA);
332 resource->size = 1;
333 resource->flags |= IORESOURCE_IRQ;
334 }
335 if (info->flags & PNP_MSCB) {
336 resource = new_resource(dev, PNP_IDX_MSCB);
337 resource->size = 1;
338 resource->flags |= IORESOURCE_IRQ;
339 }
340 if (info->flags & PNP_MSCC) {
341 resource = new_resource(dev, PNP_IDX_MSCC);
342 resource->size = 1;
343 resource->flags |= IORESOURCE_IRQ;
344 }
345 if (info->flags & PNP_MSCD) {
346 resource = new_resource(dev, PNP_IDX_MSCD);
347 resource->size = 1;
348 resource->flags |= IORESOURCE_IRQ;
349 }
350 if (info->flags & PNP_MSCE) {
351 resource = new_resource(dev, PNP_IDX_MSCE);
Stefan Reinauer08ba7d02013-10-31 15:58:50 -0700352 resource->size = 1;
353 resource->flags |= IORESOURCE_IRQ;
354 }
Stefan Reinauer14e22772010-04-27 06:56:47 +0000355}
Eric Biederman5cd81732004-03-11 15:01:31 +0000356
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200357void pnp_enable_devices(struct device *base_dev, struct device_operations *ops,
Uwe Hermannd453dd02010-10-18 00:00:57 +0000358 unsigned int functions, struct pnp_info *info)
Eric Biederman5cd81732004-03-11 15:01:31 +0000359{
360 struct device_path path;
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200361 struct device *dev;
Eric Biederman5cd81732004-03-11 15:01:31 +0000362 int i;
363
Uwe Hermannd453dd02010-10-18 00:00:57 +0000364 path.type = DEVICE_PATH_PNP;
Stefan Reinauer2b34db82009-02-28 20:10:20 +0000365 path.pnp.port = base_dev->path.pnp.port;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000366
Uwe Hermannd453dd02010-10-18 00:00:57 +0000367 /* Setup the ops and resources on the newly allocated devices. */
368 for (i = 0; i < functions; i++) {
Uwe Hermannaa4bedf2007-07-12 13:12:47 +0000369 /* Skip logical devices this Super I/O doesn't have. */
370 if (info[i].function == -1)
371 continue;
372
Stefan Reinauer2b34db82009-02-28 20:10:20 +0000373 path.pnp.device = info[i].function;
Eric Biederman7003ba42004-10-16 06:20:29 +0000374 dev = alloc_find_dev(base_dev->bus, &path);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000375
Uwe Hermannd453dd02010-10-18 00:00:57 +0000376 /* Don't initialize a device multiple times. */
Stefan Reinauer14e22772010-04-27 06:56:47 +0000377 if (dev->ops)
Eric Biederman7003ba42004-10-16 06:20:29 +0000378 continue;
Li-Ta Loc6bcedb2004-04-21 16:57:05 +0000379
Felix Held745e58a2018-07-06 19:38:24 +0200380 /* use LDN-specific ops override from corresponding pnp_info
381 entry if not NULL */
382 if (info[i].ops)
Li-Ta Lo75337f72004-05-07 21:56:48 +0000383 dev->ops = info[i].ops;
Felix Held745e58a2018-07-06 19:38:24 +0200384 /* else use device ops */
385 else
386 dev->ops = ops;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000387
Eric Biederman5cd81732004-03-11 15:01:31 +0000388 get_resources(dev, &info[i]);
Eric Biederman5cd81732004-03-11 15:01:31 +0000389 }
390}