diff options
Diffstat (limited to 'drivers/scsi/aic7xxx/aic7770_osm.c')
-rw-r--r-- | drivers/scsi/aic7xxx/aic7770_osm.c | 189 |
1 files changed, 64 insertions, 125 deletions
diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c index 682ca0b32b44..d4ed5e9f830a 100644 --- a/drivers/scsi/aic7xxx/aic7770_osm.c +++ b/drivers/scsi/aic7xxx/aic7770_osm.c | |||
@@ -44,88 +44,46 @@ | |||
44 | #include <linux/device.h> | 44 | #include <linux/device.h> |
45 | #include <linux/eisa.h> | 45 | #include <linux/eisa.h> |
46 | 46 | ||
47 | #define EISA_MFCTR_CHAR0(ID) (char)(((ID>>26) & 0x1F) | '@') /* Bits 26-30 */ | ||
48 | #define EISA_MFCTR_CHAR1(ID) (char)(((ID>>21) & 0x1F) | '@') /* Bits 21-25 */ | ||
49 | #define EISA_MFCTR_CHAR2(ID) (char)(((ID>>16) & 0x1F) | '@') /* Bits 16-20 */ | ||
50 | #define EISA_PRODUCT_ID(ID) (short)((ID>>4) & 0xFFF) /* Bits 4-15 */ | ||
51 | #define EISA_REVISION_ID(ID) (uint8_t)(ID & 0x0F) /* Bits 0-3 */ | ||
52 | |||
53 | static int aic7770_eisa_dev_probe(struct device *dev); | ||
54 | static int aic7770_eisa_dev_remove(struct device *dev); | ||
55 | static struct eisa_driver aic7770_driver = { | ||
56 | .driver = { | ||
57 | .name = "aic7xxx", | ||
58 | .probe = aic7770_eisa_dev_probe, | ||
59 | .remove = aic7770_eisa_dev_remove, | ||
60 | } | ||
61 | }; | ||
62 | |||
63 | typedef struct device *aic7770_dev_t; | ||
64 | |||
65 | static int aic7770_linux_config(struct aic7770_identity *entry, | ||
66 | aic7770_dev_t dev, u_int eisaBase); | ||
67 | |||
68 | int | 47 | int |
69 | ahc_linux_eisa_init(void) | 48 | aic7770_map_registers(struct ahc_softc *ahc, u_int port) |
70 | { | 49 | { |
71 | struct eisa_device_id *eid; | ||
72 | struct aic7770_identity *id; | ||
73 | int i; | ||
74 | |||
75 | if (aic7xxx_probe_eisa_vl == 0) | ||
76 | return -ENODEV; | ||
77 | |||
78 | /* | 50 | /* |
79 | * Linux requires the EISA IDs to be specified in | 51 | * Lock out other contenders for our i/o space. |
80 | * the EISA ID string format. Perform the conversion | ||
81 | * and setup a table with a NUL terminal entry. | ||
82 | */ | 52 | */ |
83 | aic7770_driver.id_table = malloc(sizeof(struct eisa_device_id) * | 53 | if (request_region(port, AHC_EISA_IOSIZE, "aic7xxx") == 0) |
84 | (ahc_num_aic7770_devs + 1), | 54 | return (ENOMEM); |
85 | M_DEVBUF, M_NOWAIT); | 55 | ahc->tag = BUS_SPACE_PIO; |
86 | if (aic7770_driver.id_table == NULL) | 56 | ahc->bsh.ioport = port; |
87 | return -ENOMEM; | 57 | return (0); |
88 | |||
89 | for (eid = (struct eisa_device_id *)aic7770_driver.id_table, | ||
90 | id = aic7770_ident_table, i = 0; | ||
91 | i < ahc_num_aic7770_devs; eid++, id++, i++) { | ||
92 | |||
93 | sprintf(eid->sig, "%c%c%c%03X%01X", | ||
94 | EISA_MFCTR_CHAR0(id->full_id), | ||
95 | EISA_MFCTR_CHAR1(id->full_id), | ||
96 | EISA_MFCTR_CHAR2(id->full_id), | ||
97 | EISA_PRODUCT_ID(id->full_id), | ||
98 | EISA_REVISION_ID(id->full_id)); | ||
99 | eid->driver_data = i; | ||
100 | } | ||
101 | eid->sig[0] = 0; | ||
102 | |||
103 | return eisa_driver_register(&aic7770_driver); | ||
104 | } | 58 | } |
105 | 59 | ||
106 | void | 60 | int |
107 | ahc_linux_eisa_exit(void) | 61 | aic7770_map_int(struct ahc_softc *ahc, u_int irq) |
108 | { | 62 | { |
109 | if(aic7xxx_probe_eisa_vl != 0 && aic7770_driver.id_table != NULL) { | 63 | int error; |
110 | eisa_driver_unregister(&aic7770_driver); | 64 | int shared; |
111 | free(aic7770_driver.id_table, M_DEVBUF); | 65 | |
112 | } | 66 | shared = 0; |
67 | if ((ahc->flags & AHC_EDGE_INTERRUPT) == 0) | ||
68 | shared = SA_SHIRQ; | ||
69 | |||
70 | error = request_irq(irq, ahc_linux_isr, shared, "aic7xxx", ahc); | ||
71 | if (error == 0) | ||
72 | ahc->platform_data->irq = irq; | ||
73 | |||
74 | return (-error); | ||
113 | } | 75 | } |
114 | 76 | ||
115 | static int | 77 | static int |
116 | aic7770_linux_config(struct aic7770_identity *entry, aic7770_dev_t dev, | 78 | aic7770_probe(struct device *dev) |
117 | u_int eisaBase) | ||
118 | { | 79 | { |
80 | struct eisa_device *edev = to_eisa_device(dev); | ||
81 | u_int eisaBase = edev->base_addr+AHC_EISA_SLOT_OFFSET; | ||
119 | struct ahc_softc *ahc; | 82 | struct ahc_softc *ahc; |
120 | char buf[80]; | 83 | char buf[80]; |
121 | char *name; | 84 | char *name; |
122 | int error; | 85 | int error; |
123 | 86 | ||
124 | /* | ||
125 | * Allocate a softc for this card and | ||
126 | * set it up for attachment by our | ||
127 | * common detect routine. | ||
128 | */ | ||
129 | sprintf(buf, "ahc_eisa:%d", eisaBase >> 12); | 87 | sprintf(buf, "ahc_eisa:%d", eisaBase >> 12); |
130 | name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); | 88 | name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); |
131 | if (name == NULL) | 89 | if (name == NULL) |
@@ -134,81 +92,62 @@ aic7770_linux_config(struct aic7770_identity *entry, aic7770_dev_t dev, | |||
134 | ahc = ahc_alloc(&aic7xxx_driver_template, name); | 92 | ahc = ahc_alloc(&aic7xxx_driver_template, name); |
135 | if (ahc == NULL) | 93 | if (ahc == NULL) |
136 | return (ENOMEM); | 94 | return (ENOMEM); |
137 | error = aic7770_config(ahc, entry, eisaBase); | 95 | error = aic7770_config(ahc, aic7770_ident_table + edev->id.driver_data, |
96 | eisaBase); | ||
138 | if (error != 0) { | 97 | if (error != 0) { |
139 | ahc->bsh.ioport = 0; | 98 | ahc->bsh.ioport = 0; |
140 | ahc_free(ahc); | 99 | ahc_free(ahc); |
141 | return (error); | 100 | return (error); |
142 | } | 101 | } |
143 | 102 | ||
144 | dev->driver_data = (void *)ahc; | 103 | dev_set_drvdata(dev, ahc); |
104 | |||
145 | if (aic7xxx_detect_complete) | 105 | if (aic7xxx_detect_complete) |
146 | error = ahc_linux_register_host(ahc, &aic7xxx_driver_template); | 106 | error = ahc_linux_register_host(ahc, &aic7xxx_driver_template); |
147 | return (error); | 107 | return (error); |
148 | } | 108 | } |
149 | 109 | ||
150 | int | 110 | static int |
151 | aic7770_map_registers(struct ahc_softc *ahc, u_int port) | 111 | aic7770_remove(struct device *dev) |
152 | { | ||
153 | /* | ||
154 | * Lock out other contenders for our i/o space. | ||
155 | */ | ||
156 | if (request_region(port, AHC_EISA_IOSIZE, "aic7xxx") == 0) | ||
157 | return (ENOMEM); | ||
158 | ahc->tag = BUS_SPACE_PIO; | ||
159 | ahc->bsh.ioport = port; | ||
160 | return (0); | ||
161 | } | ||
162 | |||
163 | int | ||
164 | aic7770_map_int(struct ahc_softc *ahc, u_int irq) | ||
165 | { | 112 | { |
166 | int error; | 113 | struct ahc_softc *ahc = dev_get_drvdata(dev); |
167 | int shared; | 114 | u_long s; |
168 | 115 | ||
169 | shared = 0; | 116 | ahc_lock(ahc, &s); |
170 | if ((ahc->flags & AHC_EDGE_INTERRUPT) == 0) | 117 | ahc_intr_enable(ahc, FALSE); |
171 | shared = SA_SHIRQ; | 118 | ahc_unlock(ahc, &s); |
172 | 119 | ||
173 | error = request_irq(irq, ahc_linux_isr, shared, "aic7xxx", ahc); | 120 | ahc_free(ahc); |
174 | if (error == 0) | 121 | return 0; |
175 | ahc->platform_data->irq = irq; | ||
176 | |||
177 | return (-error); | ||
178 | } | 122 | } |
179 | 123 | ||
180 | static int | 124 | static struct eisa_device_id aic7770_ids[] = { |
181 | aic7770_eisa_dev_probe(struct device *dev) | 125 | { "ADP7771", 0 }, /* AHA 274x */ |
126 | { "ADP7756", 1 }, /* AHA 284x BIOS enabled */ | ||
127 | { "ADP7757", 2 }, /* AHA 284x BIOS disabled */ | ||
128 | { "ADP7782", 3 }, /* AHA 274x Olivetti OEM */ | ||
129 | { "ADP7783", 4 }, /* AHA 274x Olivetti OEM (Differential) */ | ||
130 | { "ADP7770", 5 }, /* AIC7770 generic */ | ||
131 | { "" } | ||
132 | }; | ||
133 | |||
134 | static struct eisa_driver aic7770_driver = { | ||
135 | .id_table = aic7770_ids, | ||
136 | .driver = { | ||
137 | .name = "aic7xxx", | ||
138 | .probe = aic7770_probe, | ||
139 | .remove = aic7770_remove, | ||
140 | } | ||
141 | }; | ||
142 | |||
143 | int | ||
144 | ahc_linux_eisa_init(void) | ||
182 | { | 145 | { |
183 | struct eisa_device *edev; | 146 | return eisa_driver_register(&aic7770_driver); |
184 | |||
185 | edev = to_eisa_device(dev); | ||
186 | return (aic7770_linux_config(aic7770_ident_table + edev->id.driver_data, | ||
187 | dev, edev->base_addr+AHC_EISA_SLOT_OFFSET)); | ||
188 | } | 147 | } |
189 | 148 | ||
190 | static int | 149 | void |
191 | aic7770_eisa_dev_remove(struct device *dev) | 150 | ahc_linux_eisa_exit(void) |
192 | { | 151 | { |
193 | struct ahc_softc *ahc; | 152 | eisa_driver_unregister(&aic7770_driver); |
194 | u_long l; | ||
195 | |||
196 | /* | ||
197 | * We should be able to just perform | ||
198 | * the free directly, but check our | ||
199 | * list for extra sanity. | ||
200 | */ | ||
201 | ahc_list_lock(&l); | ||
202 | ahc = ahc_find_softc((struct ahc_softc *)dev->driver_data); | ||
203 | if (ahc != NULL) { | ||
204 | u_long s; | ||
205 | |||
206 | ahc_lock(ahc, &s); | ||
207 | ahc_intr_enable(ahc, FALSE); | ||
208 | ahc_unlock(ahc, &s); | ||
209 | ahc_free(ahc); | ||
210 | } | ||
211 | ahc_list_unlock(&l); | ||
212 | |||
213 | return (0); | ||
214 | } | 153 | } |