Blame view

drivers/dio/dio.c 8.25 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
  /* Code to support devices on the DIO and DIO-II bus
   * Copyright (C) 05/1998 Peter Maydell <pmaydell@chiark.greenend.org.uk>
   * Copyright (C) 2004 Jochen Friedrich <jochen@scram.de>
   * 
   * This code has basically these routines at the moment:
   * int dio_find(u_int deviceid)
   *    Search the list of DIO devices and return the select code
   *    of the next unconfigured device found that matches the given device ID.
   *    Note that the deviceid parameter should be the encoded ID.
   *    This means that framebuffers should pass it as 
   *    DIO_ENCODE_ID(DIO_ID_FBUFFER,DIO_ID2_TOPCAT)
   *    (or whatever); everybody else just uses DIO_ID_FOOBAR.
   * unsigned long dio_scodetophysaddr(int scode)
   *    Return the physical address corresponding to the given select code.
   * int dio_scodetoipl(int scode)
   *    Every DIO card has a fixed interrupt priority level. This function 
   *    returns it, whatever it is.
   * const char *dio_scodetoname(int scode)
   *    Return a character string describing this board [might be "" if 
   *    not CONFIG_DIO_CONSTANTS]
   * void dio_config_board(int scode)     mark board as configured in the list
   * void dio_unconfig_board(int scode)   mark board as no longer configured
   *
   * This file is based on the way the Amiga port handles Zorro II cards, 
   * although we aren't so complicated...
   */
  #include <linux/module.h>
  #include <linux/string.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/dio.h>
  #include <linux/slab.h>                         /* kmalloc() */
7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
35
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
  #include <asm/io.h>                             /* readb() */
  
  struct dio_bus dio_bus = {
  	.resources = {
  		/* DIO range */
  		{ .name = "DIO mem", .start = 0x00600000, .end = 0x007fffff },
  		/* DIO-II range */
  		{ .name = "DIO-II mem", .start = 0x01000000, .end = 0x1fffffff }
  	},
  	.name = "DIO bus"
  };
  
  /* not a real config option yet! */
  #define CONFIG_DIO_CONSTANTS
  
  #ifdef CONFIG_DIO_CONSTANTS
  /* We associate each numeric ID with an appropriate descriptive string
   * using a constant array of these structs.
   * FIXME: we should be able to arrange to throw away most of the strings
   * using the initdata stuff. Then we wouldn't need to worry about 
   * carrying them around...
   * I think we do this by copying them into newly kmalloc()ed memory and 
   * marking the names[] array as .initdata ?
   */
  struct dioname
  {
          int id;
          const char *name;
  };
  
  /* useful macro */
  #define DIONAME(x) { DIO_ID_##x, DIO_DESC_##x }
  #define DIOFBNAME(x) { DIO_ENCODE_ID( DIO_ID_FBUFFER, DIO_ID2_##x), DIO_DESC2_##x }
  
  static struct dioname names[] = 
  {
          DIONAME(DCA0), DIONAME(DCA0REM), DIONAME(DCA1), DIONAME(DCA1REM),
          DIONAME(DCM), DIONAME(DCMREM),
          DIONAME(LAN),
          DIONAME(FHPIB), DIONAME(NHPIB),
          DIONAME(SCSI0), DIONAME(SCSI1), DIONAME(SCSI2), DIONAME(SCSI3),
          DIONAME(FBUFFER),
          DIONAME(PARALLEL), DIONAME(VME), DIONAME(DCL), DIONAME(DCLREM),
          DIONAME(MISC0), DIONAME(MISC1), DIONAME(MISC2), DIONAME(MISC3),
          DIONAME(MISC4), DIONAME(MISC5), DIONAME(MISC6), DIONAME(MISC7),
          DIONAME(MISC8), DIONAME(MISC9), DIONAME(MISC10), DIONAME(MISC11), 
          DIONAME(MISC12), DIONAME(MISC13),
          DIOFBNAME(GATORBOX), DIOFBNAME(TOPCAT), DIOFBNAME(RENAISSANCE),
          DIOFBNAME(LRCATSEYE), DIOFBNAME(HRCCATSEYE), DIOFBNAME(HRMCATSEYE),
          DIOFBNAME(DAVINCI), DIOFBNAME(XXXCATSEYE), DIOFBNAME(HYPERION),
          DIOFBNAME(XGENESIS), DIOFBNAME(TIGER), DIOFBNAME(YGENESIS)   
  };
  
  #undef DIONAME
  #undef DIOFBNAME
627f192d1   Geert Uytterhoeven   dio: Fix buffer o...
91
92
  static const char unknowndioname[]
  	= "unknown DIO board, please email linux-m68k@lists.linux-m68k.org";
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
94
95
96
97
  
  static const char *dio_getname(int id)
  {
          /* return pointer to a constant string describing the board with given ID */
  	unsigned int i;
0a8320b04   Alejandro Martinez Ruiz   dio: ARRAY_SIZE()...
98
  	for (i = 0; i < ARRAY_SIZE(names); i++)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
                  if (names[i].id == id) 
                          return names[i].name;
  
          return unknowndioname;
  }
  
  #else
  
  static char dio_no_name[] = { 0 };
  #define dio_getname(_id)	(dio_no_name)
  
  #endif /* CONFIG_DIO_CONSTANTS */
  
  int __init dio_find(int deviceid)
  {
  	/* Called to find a DIO device before the full bus scan has run.
  	 * Only used by the console driver.
  	 */
  	int scode, id;
  	u_char prid, secid, i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
  
  	for (scode = 0; scode < DIO_SCMAX; scode++) {
  		void *va;
  		unsigned long pa;
  
                  if (DIO_SCINHOLE(scode))
                          continue;
  
                  pa = dio_scodetophysaddr(scode);
  
  		if (!pa)
  			continue;
  
  		if (scode < DIOII_SCBASE)
  			va = (void *)(pa + DIO_VIRADDRBASE);
  		else
  			va = ioremap(pa, PAGE_SIZE);
c02205e9f   Al Viro   dio: use probe_ke...
136
                  if (probe_kernel_read(&i, (unsigned char *)va + DIO_IDOFF, 1)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
140
  			if (scode >= DIOII_SCBASE)
  				iounmap(va);
                          continue;             /* no board present at that select code */
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  		prid = DIO_ID(va);
  
                  if (DIO_NEEDSSECID(prid)) {
                          secid = DIO_SECID(va);
                          id = DIO_ENCODE_ID(prid, secid);
                  } else
  			id = prid;
  
  		if (id == deviceid) {
  			if (scode >= DIOII_SCBASE)
  				iounmap(va);
  			return scode;
  		}
  	}
  
  	return -1;
  }
  
  /* This is the function that scans the DIO space and works out what
   * hardware is actually present.
   */
  static int __init dio_init(void)
  {
  	int scode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
  	int i;
  	struct dio_dev *dev;
2e4c77bea   Geert Uytterhoeven   m68k: dio - Kill ...
167
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
170
171
172
173
174
175
176
  
  	if (!MACH_IS_HP300)
  		return 0;
  
          printk(KERN_INFO "Scanning for DIO devices...
  ");
  
  	/* Initialize the DIO bus */ 
  	INIT_LIST_HEAD(&dio_bus.devices);
9591463af   Kay Sievers   dio: struct devic...
177
  	dev_set_name(&dio_bus.dev, "dio");
2e4c77bea   Geert Uytterhoeven   m68k: dio - Kill ...
178
179
180
181
182
183
  	error = device_register(&dio_bus.dev);
  	if (error) {
  		pr_err("DIO: Error registering dio_bus
  ");
  		return error;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
  
  	/* Request all resources */
  	dio_bus.num_resources = (hp300_model == HP_320 ? 1 : 2);
  	for (i = 0; i < dio_bus.num_resources; i++)
  		request_resource(&iomem_resource, &dio_bus.resources[i]);
  
  	/* Register all devices */
          for (scode = 0; scode < DIO_SCMAX; ++scode)
          {
                  u_char prid, secid = 0;        /* primary, secondary ID bytes */
                  u_char *va;
  		unsigned long pa;
                  
                  if (DIO_SCINHOLE(scode))
                          continue;
  
  		pa = dio_scodetophysaddr(scode);
  
  		if (!pa)
  			continue;
  
  		if (scode < DIOII_SCBASE)
  			va = (void *)(pa + DIO_VIRADDRBASE);
  		else
  			va = ioremap(pa, PAGE_SIZE);
c02205e9f   Al Viro   dio: use probe_ke...
209
                  if (probe_kernel_read(&i, (unsigned char *)va + DIO_IDOFF, 1)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
210
211
212
213
  			if (scode >= DIOII_SCBASE)
  				iounmap(va);
                          continue;              /* no board present at that select code */
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
                  /* Found a board, allocate it an entry in the list */
e66860cbd   Deepak Saxena   [PATCH] drivers/d...
215
  		dev = kzalloc(sizeof(struct dio_dev), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
  		if (!dev)
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
220
221
222
223
  		dev->bus = &dio_bus;
  		dev->dev.parent = &dio_bus.dev;
  		dev->dev.bus = &dio_bus_type;
  		dev->scode = scode;
  		dev->resource.start = pa;
  		dev->resource.end = pa + DIO_SIZE(scode, va);
9591463af   Kay Sievers   dio: struct devic...
224
  		dev_set_name(&dev->dev, "%02x", scode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
  
                  /* read the ID byte(s) and encode if necessary. */
  		prid = DIO_ID(va);
  
                  if (DIO_NEEDSSECID(prid)) {
                          secid = DIO_SECID(va);
                          dev->id = DIO_ENCODE_ID(prid, secid);
                  } else
                          dev->id = prid;
  
                  dev->ipl = DIO_IPL(va);
                  strcpy(dev->name,dio_getname(dev->id));
                  printk(KERN_INFO "select code %3d: ipl %d: ID %02X", dev->scode, dev->ipl, prid);
                  if (DIO_NEEDSSECID(prid))
                          printk(":%02X", secid);
                  printk(": %s
  ", dev->name);
  
  		if (scode >= DIOII_SCBASE)
  			iounmap(va);
2e4c77bea   Geert Uytterhoeven   m68k: dio - Kill ...
245
246
247
248
249
250
251
252
253
254
255
  		error = device_register(&dev->dev);
  		if (error) {
  			pr_err("DIO: Error registering device %s
  ",
  			       dev->name);
  			continue;
  		}
  		error = dio_create_sysfs_dev_files(dev);
  		if (error)
  			dev_err(&dev->dev, "Error creating sysfs files
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
          }
  	return 0;
  }
  
  subsys_initcall(dio_init);
  
  /* Bear in mind that this is called in the very early stages of initialisation
   * in order to get the address of the serial port for the console...
   */
  unsigned long dio_scodetophysaddr(int scode)
  {
          if (scode >= DIOII_SCBASE) {
                  return (DIOII_BASE + (scode - 132) * DIOII_DEVSIZE);
          } else if (scode > DIO_SCMAX || scode < 0)
                  return 0;
          else if (DIO_SCINHOLE(scode))
                  return 0;
  
          return (DIO_BASE + scode * DIO_DEVSIZE);
  }