]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/i82527.c
CAN driver infrastructure redesign to LinCAN-0.2 version
[lincan.git] / lincan / src / i82527.c
1 /* i82527.c
2  * Linux CAN-bus device driver.
3  * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
4  * Rewritten for new CAN queues by Pavel Pisa - OCERA team member
5  * email:pisa@cmp.felk.cvut.cz
6  * This software is released under the GPL-License.
7  * Version lincan-0.2  9 Jul 2003
8  */
9
10 #define __NO_VERSION__
11 #include <linux/module.h>
12
13 #include <linux/autoconf.h>
14
15 #include <linux/sched.h>
16 #include <linux/fs.h>
17
18 #include "../include/main.h"
19 #include "../include/i82527.h"
20
21 void i82527_irq_rtr_handler(struct chip_t *chip, struct msgobj_t *obj, 
22                             struct rtr_id *rtr_search, unsigned long message_id);
23
24
25 extern int stdmask;
26 extern int extmask;
27 extern int mo15mask;
28
29 /* helper functions for segmented cards read and write configuration and status registers
30    above 0xf offset */
31
32 void i82527_seg_write_reg(const struct chip_t *chip, unsigned char data, unsigned address)
33 {
34         if((address > 0xf) && (chip->flags & CHIP_SEGMENTED))
35                 canobj_write_reg(chip, chip->msgobj[(address>>4)-1],data, address & 0xf);
36         else
37                 can_write_reg(chip, data, address);
38 }
39
40 unsigned i82527_seg_read_reg(const struct chip_t *chip, unsigned address)
41 {
42         if((address > 0xf) && (chip->flags & CHIP_SEGMENTED))
43                 return canobj_read_reg(chip, chip->msgobj[(address>>4)-1], address & 0xf);
44         else
45                 return can_read_reg(chip, address);
46 }
47
48 int i82527_enable_configuration(struct chip_t *chip)
49 {
50         unsigned short flags=0;
51
52         flags = can_read_reg(chip, iCTL) & (iCTL_IE|iCTL_SIE|iCTL_EIE);
53         can_write_reg(chip, flags|iCTL_CCE, iCTL);
54         
55         return 0;
56 }
57
58 int i82527_disable_configuration(struct chip_t *chip)
59 {
60         unsigned short flags=0;
61
62         flags = can_read_reg(chip, iCTL) & (iCTL_IE|iCTL_SIE|iCTL_EIE);
63         can_write_reg(chip, flags, iCTL);
64
65         return 0;
66 }
67
68 int i82527_chip_config(struct chip_t *chip)
69 {
70         can_write_reg(chip,chip->int_cpu_reg,iCPU); // Configure cpu interface
71         can_write_reg(chip,(iCTL_CCE|iCTL_INI),iCTL); // Enable configuration
72         i82527_seg_write_reg(chip,chip->int_clk_reg,iCLK); // Set clock out slew rates 
73         i82527_seg_write_reg(chip,chip->int_bus_reg,iBUS); /* Bus configuration */
74         can_write_reg(chip,0x00,iSTAT); /* Clear error status register */
75
76         /* Check if we can at least read back some arbitrary data from the 
77          * card. If we can not, the card is not properly configured!
78          */
79         canobj_write_reg(chip,chip->msgobj[1],0x25,iMSGDAT1);
80         canobj_write_reg(chip,chip->msgobj[2],0x52,iMSGDAT3);
81         canobj_write_reg(chip,chip->msgobj[10],0xc3,iMSGDAT6);
82         if ( (canobj_read_reg(chip,chip->msgobj[1],iMSGDAT1) != 0x25) ||
83               (canobj_read_reg(chip,chip->msgobj[2],iMSGDAT3) != 0x52) ||
84               (canobj_read_reg(chip,chip->msgobj[10],iMSGDAT6) != 0xc3) ) {
85                 CANMSG("Could not read back from the hardware.\n");
86                 CANMSG("This probably means that your hardware is not correctly configured!\n");
87                 return -1;
88         }
89         else
90                 DEBUGMSG("Could read back, hardware is probably configured correctly\n");
91
92         if (baudrate == 0)
93                 baudrate=1000;
94
95         if (i82527_baud_rate(chip,baudrate*1000,chip->clock,0,75,0)) {
96                 CANMSG("Error configuring baud rate\n");
97                 return -ENODEV;
98         }
99         if (i82527_standard_mask(chip,0x0000,stdmask)) {
100                 CANMSG("Error configuring standard mask\n");
101                 return -ENODEV;
102         }
103         if (i82527_extended_mask(chip,0x00000000,extmask)) {
104                 CANMSG("Error configuring extended mask\n");
105                 return -ENODEV;
106         }
107         if (i82527_message15_mask(chip,0x00000000,mo15mask)) {
108                 CANMSG("Error configuring message 15 mask\n");
109                 return -ENODEV;
110         }
111         if (i82527_clear_objects(chip)) {
112                 CANMSG("Error clearing message objects\n");
113                 return -ENODEV;
114         }
115         if (i82527_config_irqs(chip,0x0a)) {
116                 CANMSG("Error configuring interrupts\n");
117                 return -ENODEV;
118         }
119
120         return 0;
121 }
122
123 /* Set communication parameters.
124  * param rate baud rate in Hz
125  * param clock frequency of i82527 clock in Hz (ISA osc is 14318000)
126  * param sjw synchronization jump width (0-3) prescaled clock cycles
127  * param sampl_pt sample point in % (0-100) sets (TSEG1+2)/(TSEG1+TSEG2+3) ratio
128  * param flags fields BTR1_SAM, OCMODE, OCPOL, OCTP, OCTN, CLK_OFF, CBP
129  */
130 int i82527_baud_rate(struct chip_t *chip, int rate, int clock, int sjw,
131                                                         int sampl_pt, int flags)
132 {
133         int best_error = 1000000000, error;
134         int best_tseg=0, best_brp=0, best_rate=0, brp=0;
135         int tseg=0, tseg1=0, tseg2=0;
136         
137         if (i82527_enable_configuration(chip))
138                 return -ENODEV;
139
140         clock /=2;
141
142         /* tseg even = round down, odd = round up */
143         for (tseg=(0+0+2)*2; tseg<=(MAX_TSEG2+MAX_TSEG1+2)*2+1; tseg++) {
144                 brp = clock/((1+tseg/2)*rate)+tseg%2;
145                 if (brp == 0 || brp > 64)
146                         continue;
147                 error = rate - clock/(brp*(1+tseg/2));
148                 if (error < 0)
149                         error = -error;
150                 if (error <= best_error) {
151                         best_error = error;
152                         best_tseg = tseg/2;
153                         best_brp = brp-1;
154                         best_rate = clock/(brp*(1+tseg/2));
155                 }
156         }
157         if (best_error && (rate/best_error < 10)) {
158                 CANMSG("baud rate %d is not possible with %d Hz clock\n",
159                                                                 rate, 2*clock);
160                 CANMSG("%d bps. brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d\n",
161                                 best_rate, best_brp, best_tseg, tseg1, tseg2);
162                 return -EINVAL;
163         }
164         tseg2 = best_tseg-(sampl_pt*(best_tseg+1))/100;
165         if (tseg2 < 0)
166                 tseg2 = 0;
167         if (tseg2 > MAX_TSEG2)
168                 tseg2 = MAX_TSEG2;
169         
170         tseg1 = best_tseg-tseg2-2;
171         if (tseg1>MAX_TSEG1) {
172                 tseg1 = MAX_TSEG1;
173                 tseg2 = best_tseg-tseg1-2;
174         }
175
176         DEBUGMSG("Setting %d bps.\n", best_rate);
177         DEBUGMSG("brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d, sampl_pt=%d\n",
178                                         best_brp, best_tseg, tseg1, tseg2,
179                                         (100*(best_tseg-tseg2)/(best_tseg+1)));
180                                         
181                                 
182         i82527_seg_write_reg(chip, sjw<<6 | best_brp, iBT0);
183         can_write_reg(chip, ((flags & BTR1_SAM) != 0)<<7 | tseg2<<4 | tseg1,
184                                                                 iBT1);
185         DEBUGMSG("Writing 0x%x to iBT0\n",(sjw<<6 | best_brp));
186         DEBUGMSG("Writing 0x%x to iBT1\n",((flags & BTR1_SAM) != 0)<<7 | 
187                                                         tseg2<<4 | tseg1);
188
189         i82527_disable_configuration(chip);
190
191         return 0;
192 }
193
194 int i82527_standard_mask(struct chip_t *chip, unsigned short code, unsigned short mask)
195 {
196         unsigned char mask0, mask1;
197
198         mask0 = (unsigned char) (mask >> 3);
199         mask1 = (unsigned char) (mask << 5);
200         
201         can_write_reg(chip,mask0,iSGM0);
202         can_write_reg(chip,mask1,iSGM1);
203
204         DEBUGMSG("Setting standard mask to 0x%lx\n",(unsigned long)mask);
205
206         return 0;
207 }
208
209 int i82527_extended_mask(struct chip_t *chip, unsigned long code, unsigned long mask)
210 {
211         unsigned char mask0, mask1, mask2, mask3;
212
213         mask0 = (unsigned char) (mask >> 21);
214         mask1 = (unsigned char) (mask >> 13);
215         mask2 = (unsigned char) (mask >> 5);
216         mask3 = (unsigned char) (mask << 3);
217
218         can_write_reg(chip,mask0,iEGM0);
219         can_write_reg(chip,mask1,iEGM1);
220         can_write_reg(chip,mask2,iEGM2);
221         can_write_reg(chip,mask3,iEGM3);
222
223         DEBUGMSG("Setting extended mask to 0x%lx\n",(unsigned long)mask);
224
225         return 0;
226 }
227
228 int i82527_message15_mask(struct chip_t *chip, unsigned long code, unsigned long mask)
229 {
230         unsigned char mask0, mask1, mask2, mask3;
231
232         mask0 = (unsigned char) (mask >> 21);
233         mask1 = (unsigned char) (mask >> 13);
234         mask2 = (unsigned char) (mask >> 5);
235         mask3 = (unsigned char) (mask << 3);
236
237         can_write_reg(chip,mask0,i15M0);
238         can_write_reg(chip,mask1,i15M1);
239         can_write_reg(chip,mask2,i15M2);
240         can_write_reg(chip,mask3,i15M3);
241
242         DEBUGMSG("Setting message 15 mask to 0x%lx\n",mask);
243
244         return 0;
245
246
247 }
248
249 int i82527_clear_objects(struct chip_t *chip)
250 {
251         int i=0,id=0,data=0;
252         struct msgobj_t *obj;
253
254         DEBUGMSG("Cleared all message objects on chip\n");
255
256         for (i=1; i<=15; i++) {
257                 obj=chip->msgobj[i];
258                 canobj_write_reg(chip,obj,(INTPD_RES|RXIE_RES|TXIE_RES|MVAL_RES),iMSGCTL0);
259                 canobj_write_reg(chip,obj,(NEWD_RES|MLST_RES|TXRQ_RES|RMPD_RES), iMSGCTL1);
260                 for (data=0x07; data<0x0f; data++)
261                         canobj_write_reg(chip,obj,0x00,data);
262                 for (id=2; id<6; id++) {
263                         canobj_write_reg(chip,obj,0x00,id);
264                 }
265                 if (extended==0) {
266                         canobj_write_reg(chip,obj,0x00,iMSGCFG);
267                 }
268                 else {
269                         canobj_write_reg(chip,obj,MCFG_XTD,iMSGCFG);
270                 }
271         }
272         if (extended==0)
273                 DEBUGMSG("All message ID's set to standard\n");
274         else
275                 DEBUGMSG("All message ID's set to extended\n");
276         
277         return 0;
278 }
279
280 int i82527_config_irqs(struct chip_t *chip, short irqs)
281 {
282         can_write_reg(chip,irqs,iCTL);
283         DEBUGMSG("Configured hardware interrupt delivery\n");
284         return 0;
285 }
286
287 int i82527_pre_read_config(struct chip_t *chip, struct msgobj_t *obj)
288 {
289         if (extended) {
290                 canobj_write_reg(chip,obj,MCFG_XTD,iMSGCFG);
291         }
292         else {
293                 canobj_write_reg(chip,obj,0x00,iMSGCFG);
294         }
295         canobj_write_reg(chip,obj,(NEWD_RES|MLST_RES|TXRQ_RES|RMPD_RES), iMSGCTL1);
296         canobj_write_reg(chip,obj,(MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES),iMSGCTL0);
297         
298         return 0;
299 }
300
301 int i82527_pre_write_config(struct chip_t *chip, struct msgobj_t *obj,
302                                                         struct canmsg_t *msg)
303 {
304         int i=0,id0=0,id1=0,id2=0,id3=0;
305
306         canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_RES|CPUU_SET|NEWD_RES),iMSGCTL1);
307         canobj_write_reg(chip,obj,(MVAL_SET|TXIE_SET|RXIE_RES|INTPD_RES),iMSGCTL0);
308         if (extended) {
309                 canobj_write_reg(chip,obj,(msg->length<<4)+(MCFG_DIR|MCFG_XTD),iMSGCFG);
310         }
311         else {
312                 canobj_write_reg(chip,obj,(msg->length<<4)+MCFG_DIR,iMSGCFG);
313         }
314         if (extended) {
315                 id0 = (unsigned char) (msg->id<<3);
316                 id1 = (unsigned char) (msg->id>>5);
317                 id2 = (unsigned char) (msg->id>>13);
318                 id3 = (unsigned char) (msg->id>>21);
319                 canobj_write_reg(chip,obj,id0,iMSGID3);
320                 canobj_write_reg(chip,obj,id1,iMSGID2);
321                 canobj_write_reg(chip,obj,id2,iMSGID1);
322                 canobj_write_reg(chip,obj,id3,iMSGID0);
323         }
324         else {
325                 id1 = (unsigned char) (msg->id<<5);
326                 id0 = (unsigned char) (msg->id>>3);
327                 canobj_write_reg(chip,obj,id1,iMSGID1);
328                 canobj_write_reg(chip,obj,id0,iMSGID0);
329         }
330         canobj_write_reg(chip,obj,0xfa,iMSGCTL1);
331         for (i=0; i<msg->length; i++) {
332                 canobj_write_reg(chip,obj,msg->data[i],iMSGDAT0+i);
333         }
334
335         return 0;
336 }
337
338 int i82527_send_msg(struct chip_t *chip, struct msgobj_t *obj,
339                                                         struct canmsg_t *msg)
340 {
341         if (msg->flags & MSG_RTR) {
342                 canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_RES|CPUU_RES|NEWD_SET),iMSGCTL1);
343         }
344         else {
345                 canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_SET|CPUU_RES|NEWD_SET),iMSGCTL1);
346         }
347
348         return 0;
349 }
350
351 int i82527_check_tx_stat(struct chip_t *chip)
352 {
353         if (can_read_reg(chip,iSTAT) & iSTAT_TXOK) {
354                 can_write_reg(chip,0x0,iSTAT);
355                 return 0;
356         }
357         else {
358                 can_write_reg(chip,0x0,iSTAT);
359                 return 1;
360         }
361 }
362
363 int i82527_remote_request(struct chip_t *chip, struct msgobj_t *obj)
364 {
365         canobj_write_reg(chip,obj,(MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES),iMSGCTL0);
366         canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_SET|MLST_RES|NEWD_RES),iMSGCTL1);
367         
368         return 0;
369 }
370
371 int i82527_set_btregs(struct chip_t *chip, unsigned short btr0,
372                                                         unsigned short btr1)
373 {
374         if (i82527_enable_configuration(chip))
375                 return -ENODEV;
376
377         i82527_seg_write_reg(chip, btr0, iBT0);
378         i82527_seg_write_reg(chip, btr1, iBT1);
379
380         i82527_disable_configuration(chip);
381
382         return 0;
383 }
384
385 int i82527_start_chip(struct chip_t *chip)
386 {
387         unsigned short flags = 0;
388
389         flags = can_read_reg(chip, iCTL) & (iCTL_IE|iCTL_SIE|iCTL_EIE);
390         can_write_reg(chip, flags, iCTL);
391         
392         return 0;
393 }
394
395 int i82527_stop_chip(struct chip_t *chip)
396 {
397         unsigned short flags = 0;
398
399         flags = can_read_reg(chip, iCTL) & (iCTL_IE|iCTL_SIE|iCTL_EIE);
400         can_write_reg(chip, flags|(iCTL_CCE|iCTL_INI), iCTL);
401
402         return 0;
403 }
404
405 inline void i82527_irq_write_handler(struct chip_t *chip, struct msgobj_t *obj)
406 {
407         int cmd;
408
409         canobj_write_reg(chip,obj,(MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),+iMSGCTL0);
410
411         if(obj->tx_slot){
412                 canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
413                 obj->tx_slot=NULL;
414         }
415
416         cmd=canque_test_outslot(obj->qends, &obj->tx_qedge, &obj->tx_slot);
417         if(cmd<0)
418                 return;
419
420         if (chip->chipspecops->pre_write_config(chip, obj, &obj->tx_slot->msg)) {
421                 obj->ret = -1;
422                 canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_PREP);
423                 canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
424                 obj->tx_slot=NULL;
425                 return;
426         }
427         if (chip->chipspecops->send_msg(chip, obj, &obj->tx_slot->msg)) {
428                 obj->ret = -1;
429                 canque_notify_inends(obj->tx_qedge, CANQUEUE_NOTIFY_ERRTX_SEND);
430                 canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot);
431                 obj->tx_slot=NULL;
432                 return;
433         } 
434 }
435
436 inline void i82527_irq_read_handler(struct chip_t *chip, struct msgobj_t *obj,
437                                     unsigned long message_id)
438 {
439         int i=0, tmp=1 ;
440         
441         while (tmp) {
442                 canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES),iMSGCTL1);
443                 canobj_write_reg(chip,obj,(MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES),iMSGCTL0);
444
445                 obj->rx_msg.length =(canobj_read_reg(chip,obj,iMSGCFG) & 0xf0) >> 4;
446                 obj->rx_msg.id = message_id;
447                 for (i=0; i < obj->rx_msg.length; i++)
448                         obj->rx_msg.data[i] = canobj_read_reg(chip,obj,iMSGDAT0+i);
449
450 //FIXME: Add buffer overflow check, currently it's silently over written!
451
452                 canque_filter_msg2edges(obj->qends, &obj->rx_msg);
453
454                 if (!((tmp=canobj_read_reg(chip,obj,iMSGCTL1)) & NEWD_SET)) {
455                         break;
456                 }
457
458                 if (tmp & MLST_SET)
459                         CANMSG("Message lost!\n");
460
461         }
462 }
463
464 irqreturn_t i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
465 {
466         int id0=0, id1=0, id2=0, id3=0;
467
468         unsigned irq_register;
469         unsigned object;
470         struct chip_t *chip=(struct chip_t *)dev_id;
471         struct msgobj_t *obj;
472         unsigned long message_id;
473         struct rtr_id *rtr_search;
474
475         /*put_reg=device->hwspecops->write_register;*/
476         /*get_reg=device->hwspecops->read_register;*/
477
478         irq_register = i82527_seg_read_reg(chip, iIRQ);
479
480         while (irq_register) {
481
482                 if (irq_register == 0x01) {
483                         DEBUGMSG("Status register: 0x%x\n",can_read_reg(chip, iSTAT));
484                         return IRQ_NONE;
485                 }
486                 
487                 if (irq_register == 0x02)
488                         object = 14;
489                 else
490                         object = irq_register-3;
491
492                 obj=chip->msgobj[object];
493
494                 if (canobj_read_reg(chip,obj,iMSGCFG) & MCFG_DIR) {
495                         set_bit(OBJ_TX_REQUEST,&obj->flags);
496                         while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){
497                                 clear_bit(OBJ_TX_REQUEST,&obj->flags);
498
499                                 if(canobj_read_reg(chip,obj,iMSGCTL1)&TXRQ_RES)
500                                         i82527_irq_write_handler(chip, obj); 
501
502                                 clear_bit(OBJ_TX_LOCK,&obj->flags);
503                                 if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break;
504                         }
505                 }
506                 else { 
507
508                         if (extended) {
509                                 id0=canobj_read_reg(chip,obj,iMSGID3);
510                                 id1=canobj_read_reg(chip,obj,iMSGID2)<<8;
511                                 id2=canobj_read_reg(chip,obj,iMSGID1)<<16;
512                                 id3=canobj_read_reg(chip,obj,iMSGID0)<<24;
513                                 message_id=(id0|id1|id2|id3)>>3;
514                         }
515                         else {
516                                 id0=canobj_read_reg(chip,obj,iMSGID1);
517                                 id1=canobj_read_reg(chip,obj,iMSGID0)<<8;
518                                 message_id=(id0|id1)>>5;
519                         }
520
521                         spin_lock(&hardware_p->rtr_lock);
522                         rtr_search=hardware_p->rtr_queue;
523                         while (rtr_search != NULL) {
524                                 if (rtr_search->id == message_id)
525                                         break;
526                                 rtr_search=rtr_search->next;
527                         }
528                         spin_unlock(&hardware_p->rtr_lock);
529                         if ((rtr_search!=NULL) && (rtr_search->id==message_id))
530                                 i82527_irq_rtr_handler(chip, obj, rtr_search, message_id);
531                         else
532                                 i82527_irq_read_handler(chip, obj, message_id); 
533                 }
534
535                 irq_register=i82527_seg_read_reg(chip, iIRQ);
536         }
537         return IRQ_HANDLED;
538 }
539
540 void i82527_irq_rtr_handler(struct chip_t *chip, struct msgobj_t *obj,
541                             struct rtr_id *rtr_search, unsigned long message_id)
542 {
543         short int i=0;
544
545         canobj_write_reg(chip,obj,(MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),iMSGCTL0);
546         canobj_write_reg(chip,obj,(RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES),iMSGCTL1);
547         
548         spin_lock(&hardware_p->rtr_lock);
549
550         rtr_search->rtr_message->id=message_id;
551         rtr_search->rtr_message->length=(canobj_read_reg(chip,obj,iMSGCFG) & 0xf0)>>4;
552         for (i=0; i<rtr_search->rtr_message->length; i++)
553                 rtr_search->rtr_message->data[i]=canobj_read_reg(chip,obj,iMSGDAT0+i);
554         
555         spin_unlock(&hardware_p->rtr_lock);
556
557         if (waitqueue_active(&rtr_search->rtr_wq))
558                 wake_up_interruptible(&rtr_search->rtr_wq);
559 }
560
561 int i82527_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj)
562 {
563          /* dummy lock to prevent preemption fully portable way */
564         spinlock_t dummy_lock;
565         
566         /*  preempt_disable() */
567         spin_lock_init(&dummy_lock);
568         spin_lock(&dummy_lock);
569         
570         set_bit(OBJ_TX_REQUEST,&obj->flags);
571         while(!test_and_set_bit(OBJ_TX_LOCK,&obj->flags)){
572                 clear_bit(OBJ_TX_REQUEST,&obj->flags);
573
574                 if(canobj_read_reg(chip,obj,iMSGCTL1)&TXRQ_RES)
575                         i82527_irq_write_handler(chip, obj);
576         
577                 clear_bit(OBJ_TX_LOCK,&obj->flags);
578                 if(!test_bit(OBJ_TX_REQUEST,&obj->flags)) break;
579         }
580
581         /* preempt_enable(); */
582         spin_unlock(&dummy_lock);
583         return 0;
584 }
585
586 int i82527_register(struct chipspecops_t *chipspecops)
587 {
588         chipspecops->chip_config = i82527_chip_config;
589         chipspecops->baud_rate = i82527_baud_rate;
590         chipspecops->standard_mask = i82527_standard_mask;
591         chipspecops->extended_mask = i82527_extended_mask;
592         chipspecops->message15_mask = i82527_message15_mask;
593         chipspecops->clear_objects = i82527_clear_objects;
594         chipspecops->config_irqs = i82527_config_irqs;
595         chipspecops->pre_read_config = i82527_pre_read_config;
596         chipspecops->pre_write_config = i82527_pre_write_config;
597         chipspecops->send_msg = i82527_send_msg;
598         chipspecops->check_tx_stat = i82527_check_tx_stat;
599         chipspecops->wakeup_tx = i82527_wakeup_tx;
600         chipspecops->remote_request = i82527_remote_request;
601         chipspecops->enable_configuration = i82527_enable_configuration;
602         chipspecops->disable_configuration = i82527_disable_configuration;
603         chipspecops->set_btregs = i82527_set_btregs;
604         chipspecops->start_chip = i82527_start_chip;
605         chipspecops->stop_chip = i82527_stop_chip;
606         chipspecops->irq_handler = i82527_irq_handler;
607         return 0;
608 }