n$m]58w
return; 9-a2L JI
} 6Y>,e;R
k;K>
,$F
switch (data->state) { >Oi2gPA
case BCM203X_LOAD_MINIDRV: 1fO2)$Y
memcpy(data->buffer, "#", 1); liCCc;&B;
Ft"&NtXeZZ
usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), Z}LOy^TL
data->buffer, 1, bcm203x_complete, data); L.TgJv43
J:~[j
data->state = BCM203X_SELECT_MEMORY; 2{sD*8&`
<(#xOe
/* use workqueue to have a small delay */ qUEd
E`B
schedule_work(&data->work); gc,J2B]61
break; j:v~MrQ7|
j h1 bn
case BCM203X_SELECT_MEMORY: KB%j! ?
usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP), B~V<n&<
data->buffer, 32, bcm203x_complete, data, 1); "5o;z@(
&e HM#as
data->state = BCM203X_CHECK_MEMORY; ')P2O\YS
cYq']$]
if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) Yhc6P%{Z^
BT_ERR("Can't submit URB"); h7de9Rt
break; 2<y}91N:
`Ct'/h{
case BCM203X_CHECK_MEMORY: <4l.s
if (data->buffer[0] != '#') { W2F+^
BT_ERR("Memory select failed"); C;d|\[7Z
data->state = BCM203X_ERROR; !7mvyc!'!
break; V5e \%
} e9z$+h
vDK:v$g
data->state = BCM203X_LOAD_FIRMWARE; =9;[C:p0-
>+Sv9S
case BCM203X_LOAD_FIRMWARE: 5eiZs
if (data->fw_sent == data->fw_size) { ^Txu~r0@
usb_fill_int_urb(urb, udev, usb_rcvintpipe(udev, BCM203X_IN_EP), {2}tPT[a(
data->buffer, 32, bcm203x_complete, data, 1); 9:9N)cNvfX
n=<NFkeX
data->state = BCM203X_CHECK_FIRMWARE; vi[#?;pkF
} else { ||{T5E-.F
len = min_t(uint, data->fw_size - data->fw_sent, 4096); y+
6`|
h_
A6?qIy
usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), AkYupP2]v
data->fw_data + data->fw_sent, len, bcm203x_complete, data); xQNw&'|UU
*<`7|BH 3
data->fw_sent += len; vHs>ba$"
} iwG>]:K3
86;+r'3p.
if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0) u"`5
BT_ERR("Can't submit URB"); N`,7 FI}
break; =F'l's^j
4c5^7";P
case BCM203X_CHECK_FIRMWARE: ONjC(7
if (data->buffer[0] != '.') { @!z$Sp=
BT_ERR("Firmware loading failed"); k%EWkM)?
data->state = BCM203X_ERROR; -:)DX++
break; J-t=1
} wb(*7 &eP:
A|p@\3P*A
data->state = BCM203X_RESET; c&E*KfOG
break; @wd!&%yzO
} `FZ(#GDF
} jGO9n
O{lIs_1.Z
static void bcm203x_work(struct work_struct *work) =8$|_
{ QRsqPh&-
struct bcm203x_data *data = r+imn&FK8
container_of(work, struct bcm203x_data, work); -vyIOH,
!7A"vTs
if (atomic_read(&data->shutdown)) 8q_1(& O
return; Si#"Wn?|
ljNzYg~-
if (usb_submit_urb(data->urb, GFP_KERNEL) < 0) IV)^;i
BT_ERR("Can't submit URB"); I#i?**
} J}x>~?W
AkxH
static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id *id) ^7i^ \w0
{ 8!Wfd)4=,F
const struct firmware *firmware; Iv'RLM
struct usb_device *udev = interface_to_usbdev(intf); 0L!er%GM
struct bcm203x_data *data; Qy4X#wgD
int size; gJ]Cq/gC
17e=GL
BT_DBG("intf %p id %p", intf, id); xCR;
K]!
\\Y,?x_0T
if (intf->cur_altsetting->desc.bInterfaceNumber != 0) zt7_r`#z
return -ENODEV; Bj;\mUsk
?RZq =5Um&
data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL); @''&nRC1
if (!data) { 3CA|5A.Pa
BT_ERR("Can't allocate memory for data structure"); f&6w;T=
return -ENOMEM; ]b}B~jD
} Gh2#-~|cB
;l$9gD>R
data->udev = udev; *6NO-T; -
data->state = BCM203X_LOAD_MINIDRV; EYA/CI
x}v1X`6b
data->urb = usb_alloc_urb(0, GFP_KERNEL); *y)4D[
z-
if (!data->urb) { %p<$|'
BT_ERR("Can't allocate URB"); d/l,C4p
return -ENOMEM; L30>|g
} :lgHL3yl
\BLp-B1s
if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) { `Ac:f5a
BT_ERR("Mini driver request failed"); LEWa6'0rq
usb_free_urb(data->urb); 0Xp
nbB~~I
return -EIO; cN62M=**
} 6hp{,8|D"m
xcHen/4X
BT_DBG("minidrv data %p size %zu", firmware->data, firmware->size); ,Qat
XFtOmY
size = max_t(uint, firmware->size, 4096); a@Mq J=<L
U?^OD
data->buffer = kmalloc(size, GFP_KERNEL); ;?0_Q3IML
if (!data->buffer) { Q6u{@$(/N
BT_ERR("Can't allocate memory for mini driver"); p`\3if'
release_firmware(firmware); g8KY`MBnC&
usb_free_urb(data->urb); nlaG<L#
return -ENOMEM; 6*sw,sU[y
} w %;hl#s
7LG+$LEz
memcpy(data->buffer, firmware->data, firmware->size); 9e]'OKL+
zkd3Z$Ce
usb_fill_bulk_urb(data->urb, udev, usb_sndbulkpipe(udev, BCM203X_OUT_EP), r)Or\HL
data->buffer, firmware->size, bcm203x_complete, data); <]~ZPk[
;8BA~,4l
release_firmware(firmware); Hc M~
\N? 7WQ
if (request_firmware(&firmware, "BCM2033-FW.bin", &udev->dev) < 0) { CF\R<rF<VS
BT_ERR("Firmware request failed"); "2%>M
usb_free_urb(data->urb); &&&9
kfree(data->buffer); .xEJaID\N
return -EIO; )9MrdVNv
}
O)O Uy
>'N!dM.+9
BT_DBG("firmware data %p size %zu", firmware->data, firmware->size); s_xV-C#q@
y86))
data->fw_data = kmemdup(firmware->data, firmware->size, GFP_KERNEL); ("OAPr\2dw
if (!data->fw_data) { Ey'J]KVW
BT_ERR("Can't allocate memory for firmware image"); EA6t36|TX
release_firmware(firmware); -]/7hN*v
usb_free_urb(data->urb); w(Gz({l+
kfree(data->buffer); jM]d'E?ZLA
return -ENOMEM; #K|0laul
} &-=K:;x
*o!l/>4g
data->fw_size = firmware->size; $6#
lTYN~
data->fw_sent = 0; vGMJ ^q
-3` "E%9
release_firmware(firmware); _|X7
n~
{M[~E|@D
INIT_WORK(&data->work, bcm203x_work); R5~gH6K|
.9OFryo
usb_set_intfdata(intf, data); #sZIDn J#
0Qp[\ia
/* use workqueue to have a small delay */ Rjq a_hxrS
schedule_work(&data->work); ./7v",#*.'
J,(7.+`~#
return 0; }a ^|L"
} 5KJ%]B(H2
BRa{\R^I
static void bcm203x_disconnect(struct usb_interface *intf) /=TH08
{ 'y.JcS!|
struct bcm203x_data *data = usb_get_intfdata(intf); %l]Rh/VPn?
>fH*XP>(
BT_DBG("intf %p", intf); +;dXDZ2
};r|}v !~_
atomic_inc(&data->shutdown); 'B`#:tX^N
cancel_work_sync(&data->work); 5,R`@&K3D
> ws!5q
usb_kill_urb(data->urb); ZE
rdt:w
AWT"Y4Ie
usb_set_intfdata(intf, NULL); O |WbFf
hg8Be6G<
usb_free_urb(data->urb); NI.`mc6Xd
kfree(data->fw_data); RLHYw@-j@
kfree(data->buffer); +ubnx{VC
} @\jQoaLT$_
krjN7&
static struct usb_driver bcm203x_driver = { Xu#:Fe}:
.name = "bcm203x", /zT`Y=1
.probe = bcm203x_probe, "r. .
.disconnect = bcm203x_disconnect, :6D0j
.id_table = bcm203x_table, 8teJ*sz