blob: e56b00d774fdfa7152c239fbe4d005e662434468 [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)) {
Felix Helda6627772018-07-27 16:41:32 +0200121 /* The PNP_MSC super IO registers have the IRQ flag set. If no
122 value is assigned in the devicetree, the corresponding
123 PNP_MSC register doesn't get written, which should be printed
124 as warning and not as error. */
125 if (resource->flags & IORESOURCE_IRQ &&
126 (resource->index != PNP_IDX_IRQ0) &&
127 (resource->index != PNP_IDX_IRQ1))
128 printk(BIOS_WARNING, "WARNING: %s %02lx %s size: "
129 "0x%010llx not assigned\n", dev_path(dev),
130 resource->index, resource_type(resource),
131 resource->size);
132 else
133 printk(BIOS_ERR, "ERROR: %s %02lx %s size: 0x%010llx "
134 "not assigned\n", dev_path(dev), resource->index,
135 resource_type(resource), resource->size);
Eric Biederman5cd81732004-03-11 15:01:31 +0000136 return;
137 }
Li-Ta Lo75337f72004-05-07 21:56:48 +0000138
Uwe Hermannd453dd02010-10-18 00:00:57 +0000139 /* Now store the resource. */
Eric Biederman5cd81732004-03-11 15:01:31 +0000140 if (resource->flags & IORESOURCE_IO) {
141 pnp_set_iobase(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000142 } else if (resource->flags & IORESOURCE_DRQ) {
Eric Biederman5cd81732004-03-11 15:01:31 +0000143 pnp_set_drq(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000144 } else if (resource->flags & IORESOURCE_IRQ) {
Eric Biederman5cd81732004-03-11 15:01:31 +0000145 pnp_set_irq(dev, resource->index, resource->base);
Uwe Hermannd453dd02010-10-18 00:00:57 +0000146 } else {
Stefan Reinauerc02b4fc2010-03-22 11:42:32 +0000147 printk(BIOS_ERR, "ERROR: %s %02lx unknown resource type\n",
Uwe Hermannd453dd02010-10-18 00:00:57 +0000148 dev_path(dev), resource->index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000149 return;
150 }
Li-Ta Lo9f0d0f92004-05-10 16:05:16 +0000151 resource->flags |= IORESOURCE_STORED;
Eric Biederman5cd81732004-03-11 15:01:31 +0000152
Eric Biederman03acab62004-10-14 21:25:53 +0000153 report_resource_stored(dev, resource, "");
Eric Biederman5cd81732004-03-11 15:01:31 +0000154}
155
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200156void pnp_set_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000157{
Myles Watsonc25cc112010-05-21 14:33:48 +0000158 struct resource *res;
Eric Biederman5cd81732004-03-11 15:01:31 +0000159
Nico Huberdd4715b2013-06-10 22:08:35 +0200160 pnp_enter_conf_mode(dev);
161
Uwe Hermannd453dd02010-10-18 00:00:57 +0000162 /* Select the logical device (LDN). */
Eric Biederman5cd81732004-03-11 15:01:31 +0000163 pnp_set_logical_device(dev);
164
165 /* Paranoia says I should disable the device here... */
Uwe Hermannd453dd02010-10-18 00:00:57 +0000166 for (res = dev->resource_list; res; res = res->next)
Myles Watsonc25cc112010-05-21 14:33:48 +0000167 pnp_set_resource(dev, res);
Nico Huberdd4715b2013-06-10 22:08:35 +0200168
169 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000170}
171
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200172void pnp_enable_resources(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000173{
Nico Huberdd4715b2013-06-10 22:08:35 +0200174 pnp_enter_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000175 pnp_set_logical_device(dev);
176 pnp_set_enable(dev, 1);
Nico Huberdd4715b2013-06-10 22:08:35 +0200177 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000178}
179
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200180void pnp_enable(struct device *dev)
Eric Biederman5cd81732004-03-11 15:01:31 +0000181{
Li-Ta Lo75337f72004-05-07 21:56:48 +0000182 if (!dev->enabled) {
Nico Huberdd4715b2013-06-10 22:08:35 +0200183 pnp_enter_conf_mode(dev);
Li-Ta Loc6bcedb2004-04-21 16:57:05 +0000184 pnp_set_logical_device(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000185 pnp_set_enable(dev, 0);
Nico Huberdd4715b2013-06-10 22:08:35 +0200186 pnp_exit_conf_mode(dev);
Eric Biederman5cd81732004-03-11 15:01:31 +0000187 }
188}
189
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200190void pnp_alt_enable(struct device *dev)
Nico Huberf898f7b2013-06-10 22:57:12 +0200191{
Nico Huberdd4715b2013-06-10 22:08:35 +0200192 pnp_enter_conf_mode(dev);
Nico Huberf898f7b2013-06-10 22:57:12 +0200193 pnp_set_logical_device(dev);
194 pnp_set_enable(dev, !!dev->enabled);
Nico Huberdd4715b2013-06-10 22:08:35 +0200195 pnp_exit_conf_mode(dev);
Nico Huberf898f7b2013-06-10 22:57:12 +0200196}
197
Eric Biederman5cd81732004-03-11 15:01:31 +0000198struct device_operations pnp_ops = {
199 .read_resources = pnp_read_resources,
200 .set_resources = pnp_set_resources,
201 .enable_resources = pnp_enable_resources,
202 .enable = pnp_enable,
203};
204
Uwe Hermanne4870472010-11-04 23:23:47 +0000205/* PNP chip operations */
Eric Biederman5cd81732004-03-11 15:01:31 +0000206
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200207static void pnp_get_ioresource(struct device *dev, u8 index, u16 mask)
Eric Biederman5cd81732004-03-11 15:01:31 +0000208{
209 struct resource *resource;
Felix Heldf2ec6482018-07-27 02:31:09 +0200210 unsigned int bit;
Li-Ta Lo75337f72004-05-07 21:56:48 +0000211
Felix Heldf2ec6482018-07-27 02:31:09 +0200212 /* If none of the mask bits is set, the resource would occupy the whole
213 IO space leading to IO resource conflicts with the other devices */
Samuel Holland7daac912017-06-06 22:55:01 -0500214 if (!mask) {
Stefan Reinaueraeead272011-01-31 21:16:48 +0000215 printk(BIOS_ERR, "ERROR: device %s index %d has no mask.\n",
216 dev_path(dev), index);
217 return;
218 }
219
Eric Biederman03acab62004-10-14 21:25:53 +0000220 resource = new_resource(dev, index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000221 resource->flags |= IORESOURCE_IO;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000222
Felix Heldf2ec6482018-07-27 02:31:09 +0200223 /* Calculate IO region size which is determined by the first one from
224 the LSB of the mask. */
225 for (bit = 0; bit <= 15 && (mask & (1 << bit)) == 0; ++bit)
226 ;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000227
Felix Heldf2ec6482018-07-27 02:31:09 +0200228 resource->gran = bit;
229 resource->align = bit;
230 resource->size = 1 << bit;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000231
Felix Heldf2ec6482018-07-27 02:31:09 +0200232 /* Calculate IO region address limit which is determined by the first
233 one from the MSB of the mask. */
234 for (bit = 15; bit != 0 && (mask & (1 << bit)) == 0; --bit)
235 ;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000236
Felix Heldf2ec6482018-07-27 02:31:09 +0200237 resource->limit = (1 << (bit + 1)) - 1;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000238
Felix Heldf2ec6482018-07-27 02:31:09 +0200239 /* The block of ones in the mask is expected to be continuous.
240 If there is any zero inbetween the block of ones, it is ignored
241 in the calculation of the resource size and limit. */
242 if (mask != (resource->limit ^ (resource->size - 1)))
243 printk(BIOS_WARNING,
244 "WARNING: mask of device %s index %d is wrong.\n",
245 dev_path(dev), index);
Eric Biederman5cd81732004-03-11 15:01:31 +0000246}
247
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200248static void get_resources(struct device *dev, struct pnp_info *info)
Eric Biederman5cd81732004-03-11 15:01:31 +0000249{
250 struct resource *resource;
251
Uwe Hermanne4870472010-11-04 23:23:47 +0000252 if (info->flags & PNP_IO0)
Samuel Holland7daac912017-06-06 22:55:01 -0500253 pnp_get_ioresource(dev, PNP_IDX_IO0, info->io0);
Uwe Hermanne4870472010-11-04 23:23:47 +0000254 if (info->flags & PNP_IO1)
Samuel Holland7daac912017-06-06 22:55:01 -0500255 pnp_get_ioresource(dev, PNP_IDX_IO1, info->io1);
Uwe Hermanne4870472010-11-04 23:23:47 +0000256 if (info->flags & PNP_IO2)
Samuel Holland7daac912017-06-06 22:55:01 -0500257 pnp_get_ioresource(dev, PNP_IDX_IO2, info->io2);
Uwe Hermanne4870472010-11-04 23:23:47 +0000258 if (info->flags & PNP_IO3)
Samuel Holland7daac912017-06-06 22:55:01 -0500259 pnp_get_ioresource(dev, PNP_IDX_IO3, info->io3);
Uwe Hermanne4870472010-11-04 23:23:47 +0000260
Eric Biederman5cd81732004-03-11 15:01:31 +0000261 if (info->flags & PNP_IRQ0) {
Eric Biederman03acab62004-10-14 21:25:53 +0000262 resource = new_resource(dev, PNP_IDX_IRQ0);
Eric Biederman5cd81732004-03-11 15:01:31 +0000263 resource->size = 1;
264 resource->flags |= IORESOURCE_IRQ;
265 }
266 if (info->flags & PNP_IRQ1) {
Eric Biederman03acab62004-10-14 21:25:53 +0000267 resource = new_resource(dev, PNP_IDX_IRQ1);
Eric Biederman5cd81732004-03-11 15:01:31 +0000268 resource->size = 1;
269 resource->flags |= IORESOURCE_IRQ;
270 }
Uwe Hermanne4870472010-11-04 23:23:47 +0000271
Eric Biederman5cd81732004-03-11 15:01:31 +0000272 if (info->flags & PNP_DRQ0) {
Eric Biederman03acab62004-10-14 21:25:53 +0000273 resource = new_resource(dev, PNP_IDX_DRQ0);
Eric Biederman5cd81732004-03-11 15:01:31 +0000274 resource->size = 1;
275 resource->flags |= IORESOURCE_DRQ;
276 }
277 if (info->flags & PNP_DRQ1) {
Eric Biederman03acab62004-10-14 21:25:53 +0000278 resource = new_resource(dev, PNP_IDX_DRQ1);
Eric Biederman5cd81732004-03-11 15:01:31 +0000279 resource->size = 1;
280 resource->flags |= IORESOURCE_DRQ;
Stefan Reinauerde3206a2010-02-22 06:09:43 +0000281 }
Uwe Hermannd453dd02010-10-18 00:00:57 +0000282
283 /*
284 * These are not IRQs, but set the flag to have the
285 * resource allocator do the right thing.
Stefan Reinauerde3206a2010-02-22 06:09:43 +0000286 */
287 if (info->flags & PNP_EN) {
288 resource = new_resource(dev, PNP_IDX_EN);
289 resource->size = 1;
290 resource->flags |= IORESOURCE_IRQ;
291 }
292 if (info->flags & PNP_MSC0) {
293 resource = new_resource(dev, PNP_IDX_MSC0);
294 resource->size = 1;
295 resource->flags |= IORESOURCE_IRQ;
296 }
297 if (info->flags & PNP_MSC1) {
298 resource = new_resource(dev, PNP_IDX_MSC1);
299 resource->size = 1;
300 resource->flags |= IORESOURCE_IRQ;
301 }
Damien Zammit62c02762015-12-28 23:04:47 +1100302 if (info->flags & PNP_MSC2) {
303 resource = new_resource(dev, PNP_IDX_MSC2);
304 resource->size = 1;
305 resource->flags |= IORESOURCE_IRQ;
306 }
307 if (info->flags & PNP_MSC3) {
308 resource = new_resource(dev, PNP_IDX_MSC3);
309 resource->size = 1;
310 resource->flags |= IORESOURCE_IRQ;
311 }
Stefan Reinauer0108b932013-12-11 11:06:08 -0800312 if (info->flags & PNP_MSC4) {
313 resource = new_resource(dev, PNP_IDX_MSC4);
314 resource->size = 1;
315 resource->flags |= IORESOURCE_IRQ;
316 }
Damien Zammit62c02762015-12-28 23:04:47 +1100317 if (info->flags & PNP_MSC5) {
318 resource = new_resource(dev, PNP_IDX_MSC5);
319 resource->size = 1;
320 resource->flags |= IORESOURCE_IRQ;
321 }
322 if (info->flags & PNP_MSC6) {
323 resource = new_resource(dev, PNP_IDX_MSC6);
324 resource->size = 1;
325 resource->flags |= IORESOURCE_IRQ;
326 }
327 if (info->flags & PNP_MSC7) {
328 resource = new_resource(dev, PNP_IDX_MSC7);
329 resource->size = 1;
330 resource->flags |= IORESOURCE_IRQ;
331 }
332 if (info->flags & PNP_MSC8) {
333 resource = new_resource(dev, PNP_IDX_MSC8);
334 resource->size = 1;
335 resource->flags |= IORESOURCE_IRQ;
336 }
337 if (info->flags & PNP_MSC9) {
338 resource = new_resource(dev, PNP_IDX_MSC9);
339 resource->size = 1;
340 resource->flags |= IORESOURCE_IRQ;
341 }
342 if (info->flags & PNP_MSCA) {
343 resource = new_resource(dev, PNP_IDX_MSCA);
344 resource->size = 1;
345 resource->flags |= IORESOURCE_IRQ;
346 }
347 if (info->flags & PNP_MSCB) {
348 resource = new_resource(dev, PNP_IDX_MSCB);
349 resource->size = 1;
350 resource->flags |= IORESOURCE_IRQ;
351 }
352 if (info->flags & PNP_MSCC) {
353 resource = new_resource(dev, PNP_IDX_MSCC);
354 resource->size = 1;
355 resource->flags |= IORESOURCE_IRQ;
356 }
357 if (info->flags & PNP_MSCD) {
358 resource = new_resource(dev, PNP_IDX_MSCD);
359 resource->size = 1;
360 resource->flags |= IORESOURCE_IRQ;
361 }
362 if (info->flags & PNP_MSCE) {
363 resource = new_resource(dev, PNP_IDX_MSCE);
Stefan Reinauer08ba7d02013-10-31 15:58:50 -0700364 resource->size = 1;
365 resource->flags |= IORESOURCE_IRQ;
366 }
Stefan Reinauer14e22772010-04-27 06:56:47 +0000367}
Eric Biederman5cd81732004-03-11 15:01:31 +0000368
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200369void pnp_enable_devices(struct device *base_dev, struct device_operations *ops,
Uwe Hermannd453dd02010-10-18 00:00:57 +0000370 unsigned int functions, struct pnp_info *info)
Eric Biederman5cd81732004-03-11 15:01:31 +0000371{
372 struct device_path path;
Elyes HAOUASb77cf622018-05-02 21:01:18 +0200373 struct device *dev;
Eric Biederman5cd81732004-03-11 15:01:31 +0000374 int i;
375
Uwe Hermannd453dd02010-10-18 00:00:57 +0000376 path.type = DEVICE_PATH_PNP;
Stefan Reinauer2b34db82009-02-28 20:10:20 +0000377 path.pnp.port = base_dev->path.pnp.port;
Stefan Reinauer14e22772010-04-27 06:56:47 +0000378
Uwe Hermannd453dd02010-10-18 00:00:57 +0000379 /* Setup the ops and resources on the newly allocated devices. */
380 for (i = 0; i < functions; i++) {
Uwe Hermannaa4bedf2007-07-12 13:12:47 +0000381 /* Skip logical devices this Super I/O doesn't have. */
382 if (info[i].function == -1)
383 continue;
384
Stefan Reinauer2b34db82009-02-28 20:10:20 +0000385 path.pnp.device = info[i].function;
Eric Biederman7003ba42004-10-16 06:20:29 +0000386 dev = alloc_find_dev(base_dev->bus, &path);
Stefan Reinauer14e22772010-04-27 06:56:47 +0000387
Uwe Hermannd453dd02010-10-18 00:00:57 +0000388 /* Don't initialize a device multiple times. */
Stefan Reinauer14e22772010-04-27 06:56:47 +0000389 if (dev->ops)
Eric Biederman7003ba42004-10-16 06:20:29 +0000390 continue;
Li-Ta Loc6bcedb2004-04-21 16:57:05 +0000391
Felix Held745e58a2018-07-06 19:38:24 +0200392 /* use LDN-specific ops override from corresponding pnp_info
393 entry if not NULL */
394 if (info[i].ops)
Li-Ta Lo75337f72004-05-07 21:56:48 +0000395 dev->ops = info[i].ops;
Felix Held745e58a2018-07-06 19:38:24 +0200396 /* else use device ops */
397 else
398 dev->ops = ops;
Uwe Hermannd453dd02010-10-18 00:00:57 +0000399
Eric Biederman5cd81732004-03-11 15:01:31 +0000400 get_resources(dev, &info[i]);
Eric Biederman5cd81732004-03-11 15:01:31 +0000401 }
402}