diff options
Diffstat (limited to 'drivers/char/tpm/tpm_atmel.c')
-rw-r--r-- | drivers/char/tpm/tpm_atmel.c | 146 |
1 files changed, 80 insertions, 66 deletions
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c index c0d64914595f..8cb42e84723c 100644 --- a/drivers/char/tpm/tpm_atmel.c +++ b/drivers/char/tpm/tpm_atmel.c | |||
@@ -40,7 +40,7 @@ enum tpm_atmel_read_status { | |||
40 | ATML_STATUS_READY = 0x08 | 40 | ATML_STATUS_READY = 0x08 |
41 | }; | 41 | }; |
42 | 42 | ||
43 | static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count) | 43 | static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count) |
44 | { | 44 | { |
45 | u8 status, *hdr = buf; | 45 | u8 status, *hdr = buf; |
46 | u32 size; | 46 | u32 size; |
@@ -54,7 +54,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count) | |||
54 | for (i = 0; i < 6; i++) { | 54 | for (i = 0; i < 6; i++) { |
55 | status = inb(chip->vendor->base + 1); | 55 | status = inb(chip->vendor->base + 1); |
56 | if ((status & ATML_STATUS_DATA_AVAIL) == 0) { | 56 | if ((status & ATML_STATUS_DATA_AVAIL) == 0) { |
57 | dev_err(&chip->pci_dev->dev, | 57 | dev_err(chip->dev, |
58 | "error reading header\n"); | 58 | "error reading header\n"); |
59 | return -EIO; | 59 | return -EIO; |
60 | } | 60 | } |
@@ -66,12 +66,12 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count) | |||
66 | size = be32_to_cpu(*native_size); | 66 | size = be32_to_cpu(*native_size); |
67 | 67 | ||
68 | if (count < size) { | 68 | if (count < size) { |
69 | dev_err(&chip->pci_dev->dev, | 69 | dev_err(chip->dev, |
70 | "Recv size(%d) less than available space\n", size); | 70 | "Recv size(%d) less than available space\n", size); |
71 | for (; i < size; i++) { /* clear the waiting data anyway */ | 71 | for (; i < size; i++) { /* clear the waiting data anyway */ |
72 | status = inb(chip->vendor->base + 1); | 72 | status = inb(chip->vendor->base + 1); |
73 | if ((status & ATML_STATUS_DATA_AVAIL) == 0) { | 73 | if ((status & ATML_STATUS_DATA_AVAIL) == 0) { |
74 | dev_err(&chip->pci_dev->dev, | 74 | dev_err(chip->dev, |
75 | "error reading data\n"); | 75 | "error reading data\n"); |
76 | return -EIO; | 76 | return -EIO; |
77 | } | 77 | } |
@@ -83,7 +83,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count) | |||
83 | for (; i < size; i++) { | 83 | for (; i < size; i++) { |
84 | status = inb(chip->vendor->base + 1); | 84 | status = inb(chip->vendor->base + 1); |
85 | if ((status & ATML_STATUS_DATA_AVAIL) == 0) { | 85 | if ((status & ATML_STATUS_DATA_AVAIL) == 0) { |
86 | dev_err(&chip->pci_dev->dev, | 86 | dev_err(chip->dev, |
87 | "error reading data\n"); | 87 | "error reading data\n"); |
88 | return -EIO; | 88 | return -EIO; |
89 | } | 89 | } |
@@ -93,20 +93,20 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count) | |||
93 | /* make sure data available is gone */ | 93 | /* make sure data available is gone */ |
94 | status = inb(chip->vendor->base + 1); | 94 | status = inb(chip->vendor->base + 1); |
95 | if (status & ATML_STATUS_DATA_AVAIL) { | 95 | if (status & ATML_STATUS_DATA_AVAIL) { |
96 | dev_err(&chip->pci_dev->dev, "data available is stuck\n"); | 96 | dev_err(chip->dev, "data available is stuck\n"); |
97 | return -EIO; | 97 | return -EIO; |
98 | } | 98 | } |
99 | 99 | ||
100 | return size; | 100 | return size; |
101 | } | 101 | } |
102 | 102 | ||
103 | static int tpm_atml_send(struct tpm_chip *chip, u8 * buf, size_t count) | 103 | static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count) |
104 | { | 104 | { |
105 | int i; | 105 | int i; |
106 | 106 | ||
107 | dev_dbg(&chip->pci_dev->dev, "tpm_atml_send: "); | 107 | dev_dbg(chip->dev, "tpm_atml_send:\n"); |
108 | for (i = 0; i < count; i++) { | 108 | for (i = 0; i < count; i++) { |
109 | dev_dbg(&chip->pci_dev->dev, "0x%x(%d) ", buf[i], buf[i]); | 109 | dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]); |
110 | outb(buf[i], chip->vendor->base); | 110 | outb(buf[i], chip->vendor->base); |
111 | } | 111 | } |
112 | 112 | ||
@@ -118,6 +118,11 @@ static void tpm_atml_cancel(struct tpm_chip *chip) | |||
118 | outb(ATML_STATUS_ABORT, chip->vendor->base + 1); | 118 | outb(ATML_STATUS_ABORT, chip->vendor->base + 1); |
119 | } | 119 | } |
120 | 120 | ||
121 | static u8 tpm_atml_status(struct tpm_chip *chip) | ||
122 | { | ||
123 | return inb(chip->vendor->base + 1); | ||
124 | } | ||
125 | |||
121 | static struct file_operations atmel_ops = { | 126 | static struct file_operations atmel_ops = { |
122 | .owner = THIS_MODULE, | 127 | .owner = THIS_MODULE, |
123 | .llseek = no_llseek, | 128 | .llseek = no_llseek, |
@@ -137,7 +142,7 @@ static struct attribute* atmel_attrs[] = { | |||
137 | &dev_attr_pcrs.attr, | 142 | &dev_attr_pcrs.attr, |
138 | &dev_attr_caps.attr, | 143 | &dev_attr_caps.attr, |
139 | &dev_attr_cancel.attr, | 144 | &dev_attr_cancel.attr, |
140 | 0, | 145 | NULL, |
141 | }; | 146 | }; |
142 | 147 | ||
143 | static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs }; | 148 | static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs }; |
@@ -146,6 +151,7 @@ static struct tpm_vendor_specific tpm_atmel = { | |||
146 | .recv = tpm_atml_recv, | 151 | .recv = tpm_atml_recv, |
147 | .send = tpm_atml_send, | 152 | .send = tpm_atml_send, |
148 | .cancel = tpm_atml_cancel, | 153 | .cancel = tpm_atml_cancel, |
154 | .status = tpm_atml_status, | ||
149 | .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL, | 155 | .req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL, |
150 | .req_complete_val = ATML_STATUS_DATA_AVAIL, | 156 | .req_complete_val = ATML_STATUS_DATA_AVAIL, |
151 | .req_canceled = ATML_STATUS_READY, | 157 | .req_canceled = ATML_STATUS_READY, |
@@ -153,86 +159,94 @@ static struct tpm_vendor_specific tpm_atmel = { | |||
153 | .miscdev = { .fops = &atmel_ops, }, | 159 | .miscdev = { .fops = &atmel_ops, }, |
154 | }; | 160 | }; |
155 | 161 | ||
156 | static int __devinit tpm_atml_init(struct pci_dev *pci_dev, | 162 | static struct platform_device *pdev; |
157 | const struct pci_device_id *pci_id) | 163 | |
164 | static void __devexit tpm_atml_remove(struct device *dev) | ||
165 | { | ||
166 | struct tpm_chip *chip = dev_get_drvdata(dev); | ||
167 | if (chip) { | ||
168 | release_region(chip->vendor->base, 2); | ||
169 | tpm_remove_hardware(chip->dev); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | static struct device_driver atml_drv = { | ||
174 | .name = "tpm_atmel", | ||
175 | .bus = &platform_bus_type, | ||
176 | .owner = THIS_MODULE, | ||
177 | .suspend = tpm_pm_suspend, | ||
178 | .resume = tpm_pm_resume, | ||
179 | }; | ||
180 | |||
181 | static int __init init_atmel(void) | ||
158 | { | 182 | { |
159 | u8 version[4]; | ||
160 | int rc = 0; | 183 | int rc = 0; |
161 | int lo, hi; | 184 | int lo, hi; |
162 | 185 | ||
163 | if (pci_enable_device(pci_dev)) | 186 | driver_register(&atml_drv); |
164 | return -EIO; | ||
165 | 187 | ||
166 | lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); | 188 | lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO); |
167 | hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); | 189 | hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI); |
168 | 190 | ||
169 | tpm_atmel.base = (hi<<8)|lo; | 191 | tpm_atmel.base = (hi<<8)|lo; |
170 | dev_dbg( &pci_dev->dev, "Operating with base: 0x%x\n", tpm_atmel.base); | ||
171 | 192 | ||
172 | /* verify that it is an Atmel part */ | 193 | /* verify that it is an Atmel part */ |
173 | if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T' | 194 | if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T' |
174 | || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') { | 195 | || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') { |
175 | rc = -ENODEV; | 196 | return -ENODEV; |
176 | goto out_err; | ||
177 | } | 197 | } |
178 | 198 | ||
179 | /* query chip for its version number */ | 199 | /* verify chip version number is 1.1 */ |
180 | if ((version[0] = tpm_read_index(TPM_ADDR, 0x00)) != 0xFF) { | 200 | if ( (tpm_read_index(TPM_ADDR, 0x00) != 0x01) || |
181 | version[1] = tpm_read_index(TPM_ADDR, 0x01); | 201 | (tpm_read_index(TPM_ADDR, 0x01) != 0x01 )) |
182 | version[2] = tpm_read_index(TPM_ADDR, 0x02); | 202 | return -ENODEV; |
183 | version[3] = tpm_read_index(TPM_ADDR, 0x03); | 203 | |
184 | } else { | 204 | pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL); |
185 | dev_info(&pci_dev->dev, "version query failed\n"); | 205 | if ( !pdev ) |
186 | rc = -ENODEV; | 206 | return -ENOMEM; |
187 | goto out_err; | 207 | |
208 | pdev->name = "tpm_atmel0"; | ||
209 | pdev->id = -1; | ||
210 | pdev->num_resources = 0; | ||
211 | pdev->dev.release = tpm_atml_remove; | ||
212 | pdev->dev.driver = &atml_drv; | ||
213 | |||
214 | if ((rc = platform_device_register(pdev)) < 0) { | ||
215 | kfree(pdev); | ||
216 | pdev = NULL; | ||
217 | return rc; | ||
188 | } | 218 | } |
189 | 219 | ||
190 | if ((rc = tpm_register_hardware(pci_dev, &tpm_atmel)) < 0) | 220 | if (request_region(tpm_atmel.base, 2, "tpm_atmel0") == NULL ) { |
191 | goto out_err; | 221 | platform_device_unregister(pdev); |
222 | kfree(pdev); | ||
223 | pdev = NULL; | ||
224 | return -EBUSY; | ||
225 | } | ||
192 | 226 | ||
193 | dev_info(&pci_dev->dev, | 227 | if ((rc = tpm_register_hardware(&pdev->dev, &tpm_atmel)) < 0) { |
194 | "Atmel TPM version %d.%d.%d.%d\n", version[0], version[1], | 228 | release_region(tpm_atmel.base, 2); |
195 | version[2], version[3]); | 229 | platform_device_unregister(pdev); |
230 | kfree(pdev); | ||
231 | pdev = NULL; | ||
232 | return rc; | ||
233 | } | ||
196 | 234 | ||
235 | dev_info(&pdev->dev, "Atmel TPM 1.1, Base Address: 0x%x\n", | ||
236 | tpm_atmel.base); | ||
197 | return 0; | 237 | return 0; |
198 | out_err: | ||
199 | pci_disable_device(pci_dev); | ||
200 | return rc; | ||
201 | } | ||
202 | |||
203 | static struct pci_device_id tpm_pci_tbl[] __devinitdata = { | ||
204 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0)}, | ||
205 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12)}, | ||
206 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)}, | ||
207 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)}, | ||
208 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)}, | ||
209 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)}, | ||
210 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)}, | ||
211 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)}, | ||
212 | {PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)}, | ||
213 | {PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)}, | ||
214 | {0,} | ||
215 | }; | ||
216 | |||
217 | MODULE_DEVICE_TABLE(pci, tpm_pci_tbl); | ||
218 | |||
219 | static struct pci_driver atmel_pci_driver = { | ||
220 | .name = "tpm_atmel", | ||
221 | .id_table = tpm_pci_tbl, | ||
222 | .probe = tpm_atml_init, | ||
223 | .remove = __devexit_p(tpm_remove), | ||
224 | .suspend = tpm_pm_suspend, | ||
225 | .resume = tpm_pm_resume, | ||
226 | }; | ||
227 | |||
228 | static int __init init_atmel(void) | ||
229 | { | ||
230 | return pci_register_driver(&atmel_pci_driver); | ||
231 | } | 238 | } |
232 | 239 | ||
233 | static void __exit cleanup_atmel(void) | 240 | static void __exit cleanup_atmel(void) |
234 | { | 241 | { |
235 | pci_unregister_driver(&atmel_pci_driver); | 242 | if (pdev) { |
243 | tpm_atml_remove(&pdev->dev); | ||
244 | platform_device_unregister(pdev); | ||
245 | kfree(pdev); | ||
246 | pdev = NULL; | ||
247 | } | ||
248 | |||
249 | driver_unregister(&atml_drv); | ||
236 | } | 250 | } |
237 | 251 | ||
238 | module_init(init_atmel); | 252 | module_init(init_atmel); |